mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
test: Migrate UI tests from Cypress -> Playwright (no-changelog) (#18201)
This commit is contained in:
66
packages/testing/playwright/pages/AIAssistantPage.ts
Normal file
66
packages/testing/playwright/pages/AIAssistantPage.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class AIAssistantPage extends BasePage {
|
||||
getAskAssistantFloatingButton() {
|
||||
return this.page.getByTestId('ask-assistant-floating-button');
|
||||
}
|
||||
|
||||
getAskAssistantCanvasActionButton() {
|
||||
return this.page.getByTestId('ask-assistant-canvas-action-button');
|
||||
}
|
||||
|
||||
getAskAssistantChat() {
|
||||
return this.page.getByTestId('ask-assistant-chat');
|
||||
}
|
||||
|
||||
getPlaceholderMessage() {
|
||||
return this.page.getByTestId('placeholder-message');
|
||||
}
|
||||
|
||||
getChatInput() {
|
||||
return this.page.getByTestId('chat-input');
|
||||
}
|
||||
|
||||
getSendMessageButton() {
|
||||
return this.page.getByTestId('send-message-button');
|
||||
}
|
||||
|
||||
getCloseChatButton() {
|
||||
return this.page.getByTestId('close-chat-button');
|
||||
}
|
||||
|
||||
getAskAssistantSidebarResizer() {
|
||||
return this.page
|
||||
.getByTestId('ask-assistant-sidebar')
|
||||
.locator('[class*="_resizer"][data-dir="left"]')
|
||||
.first();
|
||||
}
|
||||
|
||||
getNodeErrorViewAssistantButton() {
|
||||
return this.page.getByTestId('node-error-view-ask-assistant-button').locator('button').first();
|
||||
}
|
||||
|
||||
getChatMessagesAll() {
|
||||
return this.page.locator('[data-test-id^="chat-message"]');
|
||||
}
|
||||
|
||||
getChatMessagesAssistant() {
|
||||
return this.page.getByTestId('chat-message-assistant');
|
||||
}
|
||||
|
||||
getChatMessagesUser() {
|
||||
return this.page.getByTestId('chat-message-user');
|
||||
}
|
||||
|
||||
getChatMessagesSystem() {
|
||||
return this.page.getByTestId('chat-message-system');
|
||||
}
|
||||
|
||||
getQuickReplyButtons() {
|
||||
return this.page.getByTestId('quick-replies').locator('button');
|
||||
}
|
||||
|
||||
getNewAssistantSessionModal() {
|
||||
return this.page.getByTestId('new-assistant-session-modal');
|
||||
}
|
||||
}
|
||||
15
packages/testing/playwright/pages/BecomeCreatorCTAPage.ts
Normal file
15
packages/testing/playwright/pages/BecomeCreatorCTAPage.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class BecomeCreatorCTAPage extends BasePage {
|
||||
getBecomeTemplateCreatorCta() {
|
||||
return this.page.getByTestId('become-template-creator-cta');
|
||||
}
|
||||
|
||||
getCloseBecomeTemplateCreatorCtaButton() {
|
||||
return this.page.getByTestId('close-become-template-creator-cta');
|
||||
}
|
||||
|
||||
async closeBecomeTemplateCreatorCta() {
|
||||
await this.getCloseBecomeTemplateCreatorCtaButton().click();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import { BasePage } from './BasePage';
|
||||
import { resolveFromRoot } from '../utils/path-helper';
|
||||
@@ -8,6 +9,10 @@ export class CanvasPage extends BasePage {
|
||||
return this.page.getByRole('button', { name: 'Save' });
|
||||
}
|
||||
|
||||
workflowSaveButton(): Locator {
|
||||
return this.page.getByTestId('workflow-save-button');
|
||||
}
|
||||
|
||||
canvasAddButton(): Locator {
|
||||
return this.page.getByTestId('canvas-add-button');
|
||||
}
|
||||
@@ -132,7 +137,6 @@ export class CanvasPage extends BasePage {
|
||||
async clickExecutionsTab(): Promise<void> {
|
||||
await this.page.getByRole('radio', { name: 'Executions' }).click();
|
||||
}
|
||||
|
||||
async setWorkflowName(name: string): Promise<void> {
|
||||
await this.clickByTestId('inline-edit-preview');
|
||||
await this.fillByTestId('inline-edit-input', name);
|
||||
@@ -161,7 +165,6 @@ export class CanvasPage extends BasePage {
|
||||
getWorkflowTags() {
|
||||
return this.page.getByTestId('workflow-tags').locator('.el-tag');
|
||||
}
|
||||
|
||||
async activateWorkflow() {
|
||||
const responsePromise = this.page.waitForResponse(
|
||||
(response) =>
|
||||
@@ -170,4 +173,90 @@ export class CanvasPage extends BasePage {
|
||||
await this.page.getByTestId('workflow-activate-switch').click();
|
||||
await responsePromise;
|
||||
}
|
||||
|
||||
async clickZoomToFitButton(): Promise<void> {
|
||||
await this.clickByTestId('zoom-to-fit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get node issues for a specific node
|
||||
*/
|
||||
getNodeIssuesByName(nodeName: string) {
|
||||
return this.nodeByName(nodeName).getByTestId('node-issues');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tags to the workflow
|
||||
* @param count - The number of tags to add
|
||||
* @returns An array of tag names
|
||||
*/
|
||||
async addTags(count: number = 1): Promise<string[]> {
|
||||
const tags: string[] = [];
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const tag = `tag-${nanoid(8)}-${i}`;
|
||||
tags.push(tag);
|
||||
|
||||
if (i === 0) {
|
||||
await this.clickByText('Add tag');
|
||||
} else {
|
||||
await this.page
|
||||
.getByTestId('tags-dropdown')
|
||||
.getByText(tags[i - 1])
|
||||
.click();
|
||||
}
|
||||
|
||||
await this.page.getByRole('combobox').first().fill(tag);
|
||||
await this.page.getByRole('combobox').first().press('Enter');
|
||||
}
|
||||
|
||||
await this.page.click('body');
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
// Production Checklist methods
|
||||
getProductionChecklistButton(): Locator {
|
||||
return this.page.getByTestId('suggested-action-count');
|
||||
}
|
||||
|
||||
getProductionChecklistPopover(): Locator {
|
||||
return this.page.locator('[data-reka-popper-content-wrapper=""]').filter({ hasText: /./ });
|
||||
}
|
||||
|
||||
getProductionChecklistActionItem(text?: string): Locator {
|
||||
const items = this.page.getByTestId('suggested-action-item');
|
||||
if (text) {
|
||||
return items.getByText(text);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
getProductionChecklistIgnoreAllButton(): Locator {
|
||||
return this.page.getByTestId('suggested-action-ignore-all');
|
||||
}
|
||||
|
||||
getErrorActionItem(): Locator {
|
||||
return this.getProductionChecklistActionItem('Set up error notifications');
|
||||
}
|
||||
|
||||
getTimeSavedActionItem(): Locator {
|
||||
return this.getProductionChecklistActionItem('Track time saved');
|
||||
}
|
||||
|
||||
getEvaluationsActionItem(): Locator {
|
||||
return this.getProductionChecklistActionItem('Test reliability of AI steps');
|
||||
}
|
||||
|
||||
async clickProductionChecklistButton(): Promise<void> {
|
||||
await this.getProductionChecklistButton().click();
|
||||
}
|
||||
|
||||
async clickProductionChecklistIgnoreAll(): Promise<void> {
|
||||
await this.getProductionChecklistIgnoreAllButton().click();
|
||||
}
|
||||
|
||||
async clickProductionChecklistAction(actionText: string): Promise<void> {
|
||||
await this.getProductionChecklistActionItem(actionText).click();
|
||||
}
|
||||
}
|
||||
|
||||
15
packages/testing/playwright/pages/IframePage.ts
Normal file
15
packages/testing/playwright/pages/IframePage.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class IframePage extends BasePage {
|
||||
getIframe() {
|
||||
return this.page.locator('iframe');
|
||||
}
|
||||
|
||||
getIframeBySrc(src: string) {
|
||||
return this.page.locator(`iframe[src="${src}"]`);
|
||||
}
|
||||
|
||||
async waitForIframeRequest(url: string) {
|
||||
await this.page.waitForResponse(url);
|
||||
}
|
||||
}
|
||||
@@ -35,4 +35,16 @@ export class NodeDisplayViewPage extends BasePage {
|
||||
async close() {
|
||||
await this.clickBackToCanvasButton();
|
||||
}
|
||||
|
||||
async execute() {
|
||||
await this.clickByTestId('node-execute-button');
|
||||
}
|
||||
|
||||
getOutputPanel() {
|
||||
return this.page.getByTestId('output-panel');
|
||||
}
|
||||
|
||||
getParameterExpressionPreviewValue() {
|
||||
return this.page.getByTestId('parameter-expression-preview-value');
|
||||
}
|
||||
}
|
||||
|
||||
15
packages/testing/playwright/pages/SettingsPage.ts
Normal file
15
packages/testing/playwright/pages/SettingsPage.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class SettingsPage extends BasePage {
|
||||
getMenuItems() {
|
||||
return this.page.getByTestId('menu-item');
|
||||
}
|
||||
|
||||
getMenuItem(id: string) {
|
||||
return this.page.getByTestId('menu-item').getByTestId(id);
|
||||
}
|
||||
|
||||
async goToSettings() {
|
||||
await this.page.goto('/settings');
|
||||
}
|
||||
}
|
||||
35
packages/testing/playwright/pages/VersionsPage.ts
Normal file
35
packages/testing/playwright/pages/VersionsPage.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class VersionsPage extends BasePage {
|
||||
getVersionUpdatesPanelOpenButton() {
|
||||
return this.page.getByTestId('version-update-next-versions-link');
|
||||
}
|
||||
|
||||
getVersionUpdatesPanel() {
|
||||
return this.page.getByTestId('version-updates-panel');
|
||||
}
|
||||
|
||||
getVersionUpdatesPanelCloseButton() {
|
||||
return this.getVersionUpdatesPanel().getByRole('button', { name: 'Close' });
|
||||
}
|
||||
|
||||
getVersionCard() {
|
||||
return this.page.getByTestId('version-card');
|
||||
}
|
||||
|
||||
getWhatsNewMenuItem() {
|
||||
return this.page.getByTestId('menu-item').getByTestId('whats-new');
|
||||
}
|
||||
|
||||
async openWhatsNewMenu() {
|
||||
await this.getWhatsNewMenuItem().click();
|
||||
}
|
||||
|
||||
async openVersionUpdatesPanel() {
|
||||
await this.getVersionUpdatesPanelOpenButton().click();
|
||||
}
|
||||
|
||||
async closeVersionUpdatesPanel() {
|
||||
await this.getVersionUpdatesPanelCloseButton().click();
|
||||
}
|
||||
}
|
||||
31
packages/testing/playwright/pages/WorkflowActivationModal.ts
Normal file
31
packages/testing/playwright/pages/WorkflowActivationModal.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class WorkflowActivationModal extends BasePage {
|
||||
getModal(): Locator {
|
||||
return this.page.getByTestId('activation-modal');
|
||||
}
|
||||
|
||||
getDontShowAgainCheckbox(): Locator {
|
||||
return this.getModal().getByText("Don't show again");
|
||||
}
|
||||
|
||||
getGotItButton(): Locator {
|
||||
return this.getModal().getByRole('button', { name: 'Got it' });
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
await this.getDontShowAgainCheckbox().click();
|
||||
|
||||
await this.getGotItButton().click();
|
||||
}
|
||||
|
||||
async clickDontShowAgain(): Promise<void> {
|
||||
await this.getDontShowAgainCheckbox().click();
|
||||
}
|
||||
|
||||
async clickGotIt(): Promise<void> {
|
||||
await this.getGotItButton().click();
|
||||
}
|
||||
}
|
||||
39
packages/testing/playwright/pages/WorkflowSettingsModal.ts
Normal file
39
packages/testing/playwright/pages/WorkflowSettingsModal.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
|
||||
import { BasePage } from './BasePage';
|
||||
|
||||
export class WorkflowSettingsModal extends BasePage {
|
||||
getModal(): Locator {
|
||||
return this.page.getByTestId('workflow-settings-dialog');
|
||||
}
|
||||
|
||||
getWorkflowMenu(): Locator {
|
||||
return this.page.getByTestId('workflow-menu');
|
||||
}
|
||||
|
||||
getSettingsMenuItem(): Locator {
|
||||
return this.page.getByTestId('workflow-menu-item-settings');
|
||||
}
|
||||
|
||||
getErrorWorkflowField(): Locator {
|
||||
return this.page.getByTestId('workflow-settings-error-workflow');
|
||||
}
|
||||
|
||||
getSaveButton(): Locator {
|
||||
return this.page.getByRole('button', { name: 'Save' });
|
||||
}
|
||||
|
||||
async open(): Promise<void> {
|
||||
await this.getWorkflowMenu().click();
|
||||
await this.getSettingsMenuItem().click();
|
||||
}
|
||||
|
||||
async clickSave(): Promise<void> {
|
||||
await this.getSaveButton().click();
|
||||
}
|
||||
|
||||
async selectErrorWorkflow(workflowName: string): Promise<void> {
|
||||
await this.getErrorWorkflowField().click();
|
||||
await this.page.getByRole('option', { name: workflowName }).first().click();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
import { AIAssistantPage } from './AIAssistantPage';
|
||||
import { BecomeCreatorCTAPage } from './BecomeCreatorCTAPage';
|
||||
import { CanvasPage } from './CanvasPage';
|
||||
import { CredentialsPage } from './CredentialsPage';
|
||||
import { ExecutionsPage } from './ExecutionsPage';
|
||||
import { IframePage } from './IframePage';
|
||||
import { NodeDisplayViewPage } from './NodeDisplayViewPage';
|
||||
import { NotificationsPage } from './NotificationsPage';
|
||||
import { ProjectSettingsPage } from './ProjectSettingsPage';
|
||||
import { SettingsPage } from './SettingsPage';
|
||||
import { SidebarPage } from './SidebarPage';
|
||||
import { VersionsPage } from './VersionsPage';
|
||||
import { WorkflowActivationModal } from './WorkflowActivationModal';
|
||||
import { WorkflowSettingsModal } from './WorkflowSettingsModal';
|
||||
import { WorkflowSharingModal } from './WorkflowSharingModal';
|
||||
import { WorkflowsPage } from './WorkflowsPage';
|
||||
import { CanvasComposer } from '../composables/CanvasComposer';
|
||||
@@ -18,18 +25,28 @@ export class n8nPage {
|
||||
readonly page: Page;
|
||||
|
||||
// Pages
|
||||
readonly aiAssistant: AIAssistantPage;
|
||||
readonly becomeCreatorCTA: BecomeCreatorCTAPage;
|
||||
readonly canvas: CanvasPage;
|
||||
|
||||
readonly iframe: IframePage;
|
||||
readonly ndv: NodeDisplayViewPage;
|
||||
readonly projectSettings: ProjectSettingsPage;
|
||||
readonly settings: SettingsPage;
|
||||
readonly versions: VersionsPage;
|
||||
readonly workflows: WorkflowsPage;
|
||||
readonly notifications: NotificationsPage;
|
||||
readonly credentials: CredentialsPage;
|
||||
readonly executions: ExecutionsPage;
|
||||
readonly sideBar: SidebarPage;
|
||||
|
||||
// Modals
|
||||
readonly workflowActivationModal: WorkflowActivationModal;
|
||||
readonly workflowSettingsModal: WorkflowSettingsModal;
|
||||
readonly workflowSharingModal: WorkflowSharingModal;
|
||||
|
||||
// Composables
|
||||
readonly workflowComposer: WorkflowComposer;
|
||||
readonly workflowSharingModal: WorkflowSharingModal;
|
||||
readonly projectComposer: ProjectComposer;
|
||||
readonly canvasComposer: CanvasComposer;
|
||||
|
||||
@@ -37,9 +54,15 @@ export class n8nPage {
|
||||
this.page = page;
|
||||
|
||||
// Pages
|
||||
this.aiAssistant = new AIAssistantPage(page);
|
||||
this.becomeCreatorCTA = new BecomeCreatorCTAPage(page);
|
||||
this.canvas = new CanvasPage(page);
|
||||
|
||||
this.iframe = new IframePage(page);
|
||||
this.ndv = new NodeDisplayViewPage(page);
|
||||
this.projectSettings = new ProjectSettingsPage(page);
|
||||
this.settings = new SettingsPage(page);
|
||||
this.versions = new VersionsPage(page);
|
||||
this.workflows = new WorkflowsPage(page);
|
||||
this.notifications = new NotificationsPage(page);
|
||||
this.credentials = new CredentialsPage(page);
|
||||
@@ -47,6 +70,10 @@ export class n8nPage {
|
||||
this.sideBar = new SidebarPage(page);
|
||||
this.workflowSharingModal = new WorkflowSharingModal(page);
|
||||
|
||||
// Modals
|
||||
this.workflowActivationModal = new WorkflowActivationModal(page);
|
||||
this.workflowSettingsModal = new WorkflowSettingsModal(page);
|
||||
|
||||
// Composables
|
||||
this.workflowComposer = new WorkflowComposer(this);
|
||||
this.projectComposer = new ProjectComposer(this);
|
||||
|
||||
Reference in New Issue
Block a user