test: Migrate Cypress E2E tests to Playwright (#18970)

This commit is contained in:
shortstacked
2025-09-02 10:16:32 +01:00
committed by GitHub
parent d183652c0d
commit 38de3ee8a4
17 changed files with 423 additions and 374 deletions

View File

@@ -1,49 +0,0 @@
import { errorToast, successToast } from '../pages/notifications';
const INVALID_NAMES = [
'https://n8n.io',
'http://n8n.io',
'www.n8n.io',
'n8n.io',
'n8n.бг',
'n8n.io/home',
'n8n.io/home?send=true',
'<a href="#">Jack</a>',
'<script>alert("Hello")</script>',
];
const VALID_NAMES = [
['a', 'a'],
['alice', 'alice'],
['Robert', 'Downey Jr.'],
['Mia', 'Mia-Downey'],
['Mark', "O'neil"],
['Thomas', 'Müler'],
['ßáçøñ', 'ßáçøñ'],
['أحمد', 'فلسطين'],
['Милорад', 'Филиповић'],
];
describe('Personal Settings', () => {
it('should allow to change first and last name', () => {
cy.visit('/settings/personal');
VALID_NAMES.forEach((name) => {
cy.getByTestId('personal-data-form').find('input[name="firstName"]').clear().type(name[0]);
cy.getByTestId('personal-data-form').find('input[name="lastName"]').clear().type(name[1]);
cy.getByTestId('save-settings-button').click();
successToast().should('contain', 'Personal details updated');
successToast().find('.el-notification__closeBtn').click();
});
});
// eslint-disable-next-line n8n-local-rules/no-skipped-tests
it('not allow malicious values for personal data', () => {
cy.visit('/settings/personal');
INVALID_NAMES.forEach((name) => {
cy.getByTestId('personal-data-form').find('input[name="firstName"]').clear().type(name);
cy.getByTestId('personal-data-form').find('input[name="lastName"]').clear().type(name);
cy.getByTestId('save-settings-button').click();
errorToast().should('contain', 'Potentially malicious string');
errorToast().find('.el-notification__closeBtn').click();
});
});
});

View File

@@ -1,47 +0,0 @@
import { getCredentialSaveButton } from '../composables/modals/credential-modal';
import { CredentialsPage, CredentialsModal } from '../pages';
const credentialsPage = new CredentialsPage();
const credentialsModal = new CredentialsModal();
describe('Credentials', () => {
it('create and connect with Google OAuth2', () => {
// Open credentials page
cy.visit(credentialsPage.url, {
onBeforeLoad(win) {
cy.stub(win, 'open').as('windowOpen');
},
});
// Add a new Google OAuth2 credential
credentialsPage.getters.emptyListCreateCredentialButton().click();
credentialsModal.getters.newCredentialTypeOption('Google OAuth2 API').click();
credentialsModal.getters.newCredentialTypeButton().click();
// Fill in the key/secret and save
credentialsModal.actions.fillField('clientId', 'test-key');
credentialsModal.actions.fillField('clientSecret', 'test-secret');
credentialsModal.actions.save();
// Connect to Google
credentialsModal.getters.oauthConnectButton().click();
cy.get('@windowOpen').should(
'have.been.calledOnceWith',
Cypress.sinon.match(
'https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&prompt=consent&client_id=test-key&redirect_uri=http%3A%2F%2Flocalhost%3A5678%2Frest%2Foauth2-credential%2Fcallback&response_type=code',
),
'OAuth Authorization',
'scrollbars=no,resizable=yes,status=no,titlebar=noe,location=no,toolbar=no,menubar=no,width=500,height=700',
);
// Emulate successful save using BroadcastChannel
cy.window().then(() => {
const channel = new BroadcastChannel('oauth-callback');
channel.postMessage('success');
});
// Check that the credential was saved and connected successfully
getCredentialSaveButton().should('contain.text', 'Saved');
credentialsModal.getters.oauthConnectSuccessBanner().should('be.visible');
});
});

View File

@@ -1,48 +0,0 @@
import { openNodeCreator, searchBar } from '../composables/nodeCreator';
import { addNodeToCanvas, navigateToNewWorkflowPage } from '../composables/workflow';
describe('RAG callout experiment', () => {
describe('NDV callout', () => {
it('should show callout and open template on click', () => {
cy.intercept('workflows/templates/rag-starter-template?fromJson=true');
navigateToNewWorkflowPage();
addNodeToCanvas('Zep Vector Store', true, true, 'Add documents to vector store');
cy.contains('Tip: Get a feel for vector stores in n8n with our').should('exist');
let openedUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open').callsFake((url) => {
openedUrl = url;
});
});
cy.contains('RAG starter template').click();
cy.then(() => cy.visit(openedUrl));
cy.url().should('include', '/workflows/templates/rag-starter-template?fromJson=true');
});
});
describe('search callout', () => {
it('should show callout and open template on click', () => {
cy.intercept('workflows/templates/rag-starter-template?fromJson=true');
navigateToNewWorkflowPage();
openNodeCreator();
searchBar().type('rag');
let openedUrl = '';
cy.window().then((win) => {
cy.stub(win, 'open').callsFake((url) => {
openedUrl = url;
});
});
cy.contains('RAG starter template').should('exist').click();
cy.then(() => cy.visit(openedUrl));
cy.url().should('include', '/workflows/templates/rag-starter-template?fromJson=true');
});
});
});

View File

@@ -1,46 +0,0 @@
import * as workflow from '../composables/workflow';
import { EDIT_FIELDS_SET_NODE_NAME, LOOP_OVER_ITEMS_NODE_NAME } from '../constants';
import { NodeCreator } from '../pages/features/node-creator';
import { NDV } from '../pages/ndv';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
const nodeCreatorFeature = new NodeCreator();
const WorkflowPage = new WorkflowPageClass();
const NDVModal = new NDV();
describe('CAT-726 Node connectors not rendered when nodes inserted on the canvas', () => {
beforeEach(() => {
WorkflowPage.actions.visit();
});
it('should correctly append a No Op node when Loop Over Items node is added (from add button)', () => {
nodeCreatorFeature.actions.openNodeCreator();
nodeCreatorFeature.getters.searchBar().find('input').type(EDIT_FIELDS_SET_NODE_NAME);
nodeCreatorFeature.getters.getCreatorItem(EDIT_FIELDS_SET_NODE_NAME).click();
NDVModal.actions.close();
workflow.executeWorkflowAndWait();
cy.getByTestId('edge-label').realHover();
cy.getByTestId('add-connection-button').realClick();
nodeCreatorFeature.getters.searchBar().find('input').type(LOOP_OVER_ITEMS_NODE_NAME);
nodeCreatorFeature.getters.getCreatorItem(LOOP_OVER_ITEMS_NODE_NAME).click();
NDVModal.actions.close();
WorkflowPage.getters.canvasNodes().should('have.length', 4);
WorkflowPage.getters.nodeConnections().should('have.length', 4);
WorkflowPage.getters
.getConnectionBetweenNodes(LOOP_OVER_ITEMS_NODE_NAME, 'Replace Me')
.should('exist')
.should('be.visible');
WorkflowPage.getters
.getConnectionBetweenNodes(LOOP_OVER_ITEMS_NODE_NAME, EDIT_FIELDS_SET_NODE_NAME)
.should('exist')
.should('be.visible');
WorkflowPage.getters
.getConnectionBetweenNodes('Replace Me', LOOP_OVER_ITEMS_NODE_NAME)
.should('exist')
.should('be.visible');
});
});

View File

@@ -1,57 +0,0 @@
import {
getManualChatMessages,
getManualChatModal,
sendManualChatMessage,
} from '../composables/modals/chat-modal';
import { clickExecuteNode } from '../composables/ndv';
import {
clickZoomToFit,
openNode,
navigateToNewWorkflowPage,
openContextMenu,
clickContextMenuAction,
clickClearExecutionDataButton,
} from '../composables/workflow';
import { clearNotifications } from '../pages/notifications';
describe('AI-812-partial-execs-broken-when-using-chat-trigger', () => {
beforeEach(() => {
navigateToNewWorkflowPage();
cy.createFixtureWorkflow('Test_chat_partial_execution.json');
clearNotifications();
clickZoomToFit();
openContextMenu('Edit Fields');
clickContextMenuAction('deselect_all');
});
// Check if the full execution still behaves as expected after the partial execution tests
afterEach(() => {
clearNotifications();
clickClearExecutionDataButton();
sendManualChatMessage('Test Full Execution');
getManualChatMessages().should('have.length', 4);
getManualChatMessages().should('contain', 'Set 3 with chatInput: Test Full Execution');
});
it('should do partial execution when using chat trigger and clicking NDV execute node', () => {
openNode('Edit Fields1');
clickExecuteNode();
getManualChatModal().should('exist');
sendManualChatMessage('Test Partial Execution');
getManualChatMessages().should('have.length', 2);
getManualChatMessages().should('contain', 'Test Partial Execution');
getManualChatMessages().should('contain', 'Set 2 with chatInput: Test Partial Execution');
});
it('should do partial execution when using chat trigger and context-menu execute node', () => {
openContextMenu('Edit Fields');
clickContextMenuAction('execute');
getManualChatModal().should('exist');
sendManualChatMessage('Test Partial Execution');
getManualChatMessages().should('have.length', 2);
getManualChatMessages().should('contain', 'Test Partial Execution');
getManualChatMessages().should('contain', 'Set 1 with chatInput: Test Partial Execution');
});
});

View File

@@ -1,127 +0,0 @@
{
"nodes": [
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "0c345346-8cef-415c-aa1a-3d3941bb4035",
"name": "text",
"value": "=Set 1 with chatInput: {{ $json.chatInput }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
0
],
"id": "b1584b5b-c17c-4fd9-9b75-dd61f2c4c20d",
"name": "Edit Fields"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "9a7bd7af-c3fb-4984-b15a-2f805b66ed02",
"name": "text",
"value": "=Set 2 with chatInput: {{ $('When chat message received').item.json.chatInput }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
440,
0
],
"id": "e9e02219-4b6b-48d1-8d3d-2c850362abf2",
"name": "Edit Fields1"
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"typeVersion": 1.1,
"position": [
0,
0
],
"id": "c2dd390e-1360-4d6f-a922-4d295246a886",
"name": "When chat message received",
"webhookId": "28da48d8-cef1-4364-b4d6-429212d2e3f6"
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "9a7bd7af-c3fb-4984-b15a-2f805b66ed02",
"name": "text",
"value": "=Set 3 with chatInput: {{ $('When chat message received').item.json.chatInput }}",
"type": "string"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
660,
0
],
"id": "766dba66-a4da-4d84-ad80-ca5579ce91e5",
"name": "Edit Fields2"
}
],
"connections": {
"Edit Fields": {
"main": [
[
{
"node": "Edit Fields1",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields1": {
"main": [
[
{
"node": "Edit Fields2",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "27cc9b56542ad45b38725555722c50a1c3fee1670bbb67980558314ee08517c4"
}
}