Skip to content

Commit ded6db6

Browse files
authored
test: Migrate cypress batch to playwright (#19854)
1 parent 2d79909 commit ded6db6

File tree

16 files changed

+635
-263
lines changed

16 files changed

+635
-263
lines changed

cypress/e2e/group2/27-two-factor-authentication.cy.ts

Lines changed: 0 additions & 128 deletions
This file was deleted.

cypress/e2e/group4/44-routing.cy.ts

Lines changed: 0 additions & 116 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { expect } from '@playwright/test';
2+
import { authenticator } from 'otplib';
3+
4+
import type { n8nPage } from '../pages/n8nPage';
5+
6+
export class MfaComposer {
7+
constructor(private readonly n8n: n8nPage) {}
8+
9+
/**
10+
* Enable MFA for a user using predefined secret
11+
* @param email - User email
12+
* @param password - User password
13+
* @param mfaSecret - Known MFA secret to use for token generation
14+
*/
15+
async enableMfa(email: string, password: string, mfaSecret: string): Promise<void> {
16+
await this.n8n.signIn.loginWithEmailAndPassword(email, password, true);
17+
await this.n8n.settings.goToPersonalSettings();
18+
19+
await this.n8n.settings.clickEnableMfa();
20+
21+
await this.n8n.mfaSetupModal.getModalContainer().waitFor({ state: 'visible' });
22+
23+
await this.n8n.mfaSetupModal.clickCopySecretToClipboard();
24+
25+
const token = authenticator.generate(mfaSecret);
26+
await this.n8n.mfaSetupModal.fillToken(token);
27+
await expect(this.n8n.mfaSetupModal.getDownloadRecoveryCodesButton()).toBeVisible();
28+
await this.n8n.mfaSetupModal.clickDownloadRecoveryCodes();
29+
await this.n8n.mfaSetupModal.clickSave();
30+
await this.n8n.mfaSetupModal.waitForHidden();
31+
}
32+
33+
/**
34+
* Login with MFA code
35+
* @param email - User email
36+
* @param password - User password
37+
* @param mfaSecret - Known MFA secret for token generation
38+
*/
39+
async loginWithMfaCode(email: string, password: string, mfaSecret: string): Promise<void> {
40+
await this.n8n.signIn.fillEmail(email);
41+
await this.n8n.signIn.fillPassword(password);
42+
await this.n8n.signIn.clickSubmit();
43+
44+
await expect(this.n8n.mfaLogin.getForm()).toBeVisible();
45+
const loginMfaCode = authenticator.generate(mfaSecret);
46+
await this.n8n.mfaLogin.submitMfaCode(loginMfaCode);
47+
await expect(this.n8n.page).toHaveURL(/workflows/);
48+
}
49+
50+
/**
51+
* Login with MFA recovery code
52+
* @param email - User email
53+
* @param password - User password
54+
* @param recoveryCode - Known recovery code
55+
*/
56+
async loginWithMfaRecoveryCode(
57+
email: string,
58+
password: string,
59+
recoveryCode: string,
60+
): Promise<void> {
61+
await this.n8n.signIn.fillEmail(email);
62+
await this.n8n.signIn.fillPassword(password);
63+
await this.n8n.signIn.clickSubmit();
64+
65+
await expect(this.n8n.mfaLogin.getForm()).toBeVisible();
66+
await this.n8n.mfaLogin.submitMfaRecoveryCode(recoveryCode);
67+
await expect(this.n8n.page).toHaveURL(/workflows/);
68+
}
69+
}

packages/testing/playwright/config/test-users.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ export interface UserCredentials {
55
password: string;
66
firstName: string;
77
lastName: string;
8+
mfaEnabled?: boolean;
9+
mfaSecret?: string;
10+
mfaRecoveryCodes?: string[];
811
}
912

1013
// Simple name generators
@@ -58,6 +61,9 @@ export const INSTANCE_OWNER_CREDENTIALS: UserCredentials = {
5861
password: DEFAULT_USER_PASSWORD,
5962
firstName: randFirstName(),
6063
lastName: randLastName(),
64+
mfaEnabled: false,
65+
mfaSecret: 'KVKFKRCPNZQUYMLXOVYDSQKJKZDTSRLD',
66+
mfaRecoveryCodes: ['d04ea17f-e8b2-4afa-a9aa-57a2c735b30e'],
6167
};
6268

6369
export const INSTANCE_ADMIN_CREDENTIALS: UserCredentials = {

packages/testing/playwright/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"n8n-workflow": "workspace:*",
3737
"flatted": "catalog:",
3838
"nanoid": "catalog:",
39+
"otplib": "^12.0.1",
3940
"tsx": "catalog:",
4041
"mockserver-client": "^5.15.0",
4142
"zod": "catalog:"

packages/testing/playwright/pages/CanvasPage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CredentialModal } from './components/CredentialModal';
88
import { FocusPanel } from './components/FocusPanel';
99
import { LogsPanel } from './components/LogsPanel';
1010
import { NodeCreator } from './components/NodeCreator';
11+
import { SaveChangesModal } from './components/SaveChangesModal';
1112
import { StickyComponent } from './components/StickyComponent';
1213

1314
export class CanvasPage extends BasePage {
@@ -16,6 +17,7 @@ export class CanvasPage extends BasePage {
1617
readonly focusPanel = new FocusPanel(this.page.getByTestId('focus-panel'));
1718
readonly credentialModal = new CredentialModal(this.page.getByTestId('editCredential-modal'));
1819
readonly nodeCreator = new NodeCreator(this.page);
20+
readonly saveChangesModal = new SaveChangesModal(this.page.locator('.el-overlay'));
1921

2022
saveWorkflowButton(): Locator {
2123
return this.page.getByRole('button', { name: 'Save' });

0 commit comments

Comments
 (0)