Skip to content

Commit

Permalink
Merge master to fix CI
Browse files Browse the repository at this point in the history
  • Loading branch information
ivov committed Jun 10, 2024
2 parents 304b700 + ae00b44 commit 162e298
Show file tree
Hide file tree
Showing 183 changed files with 1,244 additions and 762 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/e2e-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
git fetch origin pull/${{ inputs.pr_number }}/head
git checkout FETCH_HEAD
- uses: pnpm/action-setup@v2.4.0
- uses: pnpm/action-setup@v4.0.0

- name: Install dependencies
run: pnpm install --frozen-lockfile
Expand All @@ -103,6 +103,7 @@ jobs:
VUE_APP_MAX_PINNED_DATA_SIZE: 16384

- name: Cypress install
working-directory: cypress
run: pnpm cypress:install

- name: Cache build artifacts
Expand Down Expand Up @@ -138,7 +139,7 @@ jobs:
git fetch origin pull/${{ inputs.pr_number }}/head
git checkout FETCH_HEAD
- uses: pnpm/action-setup@v2.4.0
- uses: pnpm/action-setup@v4.0.0

- name: Restore cached pnpm modules
uses: actions/cache/[email protected]
Expand All @@ -155,6 +156,7 @@ jobs:
- name: Cypress run
uses: cypress-io/[email protected]
with:
working-directory: cypress
install: false
start: pnpm start
wait-on: 'http://localhost:5678'
Expand All @@ -165,7 +167,7 @@ jobs:
# in the same parent workflow
ci-build-id: ${{ needs.prepare.outputs.uuid }}
spec: '/__w/n8n/n8n/cypress/${{ inputs.spec }}'
config-file: /__w/n8n/n8n/cypress.config.js
config-file: /__w/n8n/n8n/cypress/cypress.config.js
env:
NODE_OPTIONS: --dns-result-order=ipv4first
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ nodelinter.config.json
packages/**/.turbo
.turbo
*.tsbuildinfo
cypress/videos/*
cypress/screenshots/*
cypress/downloads/*
*.swp
CHANGELOG-*.md
*.mdx
Expand Down
24 changes: 24 additions & 0 deletions cypress/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const sharedOptions = require('@n8n_io/eslint-config/shared');

/**
* @type {import('@types/eslint').ESLint.ConfigData}
*/
module.exports = {
extends: ['@n8n_io/eslint-config/base'],

...sharedOptions(__dirname),

rules: {
// TODO: remove these rules
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-return': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/promise-function-async': 'off',
'n8n-local-rules/no-uncaught-json-parse': 'off',
},
};
3 changes: 3 additions & 0 deletions cypress/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
videos/
screenshots/
downloads/
4 changes: 4 additions & 0 deletions cypress/augmentation.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module 'cypress-otp' {
// eslint-disable-next-line import/no-default-export
export default function generateOTPToken(secret: string): string;
}
2 changes: 1 addition & 1 deletion cypress/composables/becomeTemplateCreatorCta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const getCloseBecomeTemplateCreatorCtaButton = () =>
//#region Actions

export const interceptCtaRequestWithResponse = (becomeCreator: boolean) => {
return cy.intercept('GET', `/rest/cta/become-creator`, {
return cy.intercept('GET', '/rest/cta/become-creator', {
body: becomeCreator,
});
};
Expand Down
2 changes: 1 addition & 1 deletion cypress/composables/modals/credential-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function closeCredentialModal() {
getCredentialModalCloseButton().click();
}

export function setCredentialValues(values: Record<string, any>, save = true) {
export function setCredentialValues(values: Record<string, string>, save = true) {
Object.entries(values).forEach(([key, value]) => {
setCredentialConnectionParameterInputByName(key, value);
});
Expand Down
4 changes: 2 additions & 2 deletions cypress/composables/ndv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Getters
*/

import { getVisibleSelect } from "../utils";
import { getVisibleSelect } from '../utils';

export function getCredentialSelect(eq = 0) {
return cy.getByTestId('node-credentials-select').eq(eq);
Expand Down Expand Up @@ -75,7 +75,7 @@ export function setParameterInputByName(name: string, value: string) {
}

export function toggleParameterCheckboxInputByName(name: string) {
getParameterInputByName(name).find('input[type="checkbox"]').realClick()
getParameterInputByName(name).find('input[type="checkbox"]').realClick();
}

export function setParameterSelectByContent(name: string, content: string) {
Expand Down
2 changes: 1 addition & 1 deletion cypress/composables/setup-workflow-credentials-button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
* Getters
*/

export const getSetupWorkflowCredentialsButton = () => cy.get(`button:contains("Set up template")`);
export const getSetupWorkflowCredentialsButton = () => cy.get('button:contains("Set up template")');
2 changes: 1 addition & 1 deletion cypress/composables/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function getNodeByName(name: string) {
export function disableNode(name: string) {
const target = getNodeByName(name);
target.rightclick(name ? 'center' : 'topLeft', { force: true });
cy.getByTestId(`context-menu-item-toggle_activation`).click();
cy.getByTestId('context-menu-item-toggle_activation').click();
}

export function getConnectionBySourceAndTarget(source: string, target: string) {
Expand Down
6 changes: 6 additions & 0 deletions cypress.config.js → cypress/cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ module.exports = defineConfig({
screenshotOnRunFailure: true,
experimentalInteractiveRunEvents: true,
experimentalSessionAndOrigin: true,
specPattern: 'e2e/**/*.ts',
supportFile: 'support/e2e.ts',
fixturesFolder: 'fixtures',
downloadsFolder: 'downloads',
screenshotsFolder: 'screenshots',
videosFolder: 'videos',
},
env: {
MAX_PINNED_DATA_SIZE: process.env.VUE_APP_MAX_PINNED_DATA_SIZE
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/1-workflows.cy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { v4 as uuid } from 'uuid';
import { WorkflowsPage as WorkflowsPageClass } from '../pages/workflows';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import { v4 as uuid } from 'uuid';

const WorkflowsPage = new WorkflowsPageClass();
const WorkflowPage = new WorkflowPageClass();
Expand Down
16 changes: 10 additions & 6 deletions cypress/e2e/10-undo-redo.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { CODE_NODE_NAME, SET_NODE_NAME, EDIT_FIELDS_SET_NODE_NAME } from './../constants';
import { SCHEDULE_TRIGGER_NODE_NAME } from '../constants';
import {
SCHEDULE_TRIGGER_NODE_NAME,
CODE_NODE_NAME,
SET_NODE_NAME,
EDIT_FIELDS_SET_NODE_NAME,
} from '../constants';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import { MessageBox as MessageBoxClass } from '../pages/modals/message-box';
import { NDV } from '../pages/ndv';
Expand Down Expand Up @@ -338,8 +342,8 @@ describe('Undo/Redo', () => {
WorkflowPage.getters.nodeConnections().should('have.length', 1);
cy.get(WorkflowPage.getters.getEndpointSelector('input', 'Switch')).should('have.length', 1);
cy.get(WorkflowPage.getters.getEndpointSelector('input', 'Switch'))
.should('have.css', 'left', `637px`)
.should('have.css', 'top', `501px`);
.should('have.css', 'left', '637px')
.should('have.css', 'top', '501px');

cy.fixture('Test_workflow_form_switch.json').then((data) => {
cy.get('body').paste(JSON.stringify(data));
Expand All @@ -353,8 +357,8 @@ describe('Undo/Redo', () => {
WorkflowPage.getters.nodeConnections().should('have.length', 1);
cy.get(WorkflowPage.getters.getEndpointSelector('input', 'Switch')).should('have.length', 1);
cy.get(WorkflowPage.getters.getEndpointSelector('input', 'Switch'))
.should('have.css', 'left', `637px`)
.should('have.css', 'top', `501px`);
.should('have.css', 'left', '637px')
.should('have.css', 'top', '501px');
});

it('should not undo/redo when NDV or a modal is open', () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/11-inline-expression-editor.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('Inline expression editor', () => {
beforeEach(() => {
WorkflowPage.actions.visit();
WorkflowPage.actions.addInitialNodeToCanvas('Schedule');
cy.on('uncaught:exception', (err) => err.name !== 'ExpressionError');
cy.on('uncaught:exception', (error) => error.name !== 'ExpressionError');
});

describe('Static data', () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/12-canvas-actions.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import {
MANUAL_TRIGGER_NODE_NAME,
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
Expand All @@ -7,7 +8,6 @@ import {
IF_NODE_NAME,
HTTP_REQUEST_NODE_NAME,
} from './../constants';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';

const WorkflowPage = new WorkflowPageClass();
describe('Canvas Actions', () => {
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/12-canvas.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import { NDV, WorkflowExecutionsTab } from '../pages';
import {
MANUAL_TRIGGER_NODE_NAME,
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
Expand All @@ -7,8 +9,6 @@ import {
SWITCH_NODE_NAME,
MERGE_NODE_NAME,
} from './../constants';
import { WorkflowPage as WorkflowPageClass } from '../pages/workflow';
import { NDV, WorkflowExecutionsTab } from '../pages';

const WorkflowPage = new WorkflowPageClass();
const ExecutionsTab = new WorkflowExecutionsTab();
Expand Down Expand Up @@ -258,7 +258,7 @@ describe('Canvas Node Manipulation and Navigation', () => {

WorkflowPage.actions.pinchToZoom(1, 'zoomOut');
// Zoom in 1x + Zoom out 1x should reset to default (=1)
WorkflowPage.getters.nodeView().should('have.css', 'transform', `matrix(1, 0, 0, 1, 0, 0)`);
WorkflowPage.getters.nodeView().should('have.css', 'transform', 'matrix(1, 0, 0, 1, 0, 0)');

WorkflowPage.actions.pinchToZoom(1, 'zoomOut');
WorkflowPage.getters
Expand Down
9 changes: 4 additions & 5 deletions cypress/e2e/13-pinning.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ describe('Data pinning', () => {

ndv.actions.pastePinnedData([
{
test: '1'.repeat(Cypress.env('MAX_PINNED_DATA_SIZE')),
test: '1'.repeat(Cypress.env('MAX_PINNED_DATA_SIZE') as number),
},
]);
workflowPage.getters
Expand All @@ -151,10 +151,8 @@ describe('Data pinning', () => {
ndv.getters.pinDataButton().should('not.exist');
ndv.getters.editPinnedDataButton().should('be.visible');

ndv.actions.setPinnedData('[ { "name": "First item", "code": 2dsa }]')
workflowPage.getters
.errorToast()
.should('contain', 'Unable to save due to invalid JSON');
ndv.actions.setPinnedData('[ { "name": "First item", "code": 2dsa }]');
workflowPage.getters.errorToast().should('contain', 'Unable to save due to invalid JSON');
});

it('Should be able to reference paired items in a node located before pinned data', () => {
Expand All @@ -168,6 +166,7 @@ describe('Data pinning', () => {
ndv.actions.close();

workflowPage.actions.addNodeToCanvas(EDIT_FIELDS_SET_NODE_NAME, true, true);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
setExpressionOnStringValueInSet(`{{ $('${HTTP_REQUEST_NODE_NAME}').item`);

const output = '[Object: {"json": {"http": 123}, "pairedItem": {"item": 0}}]';
Expand Down
2 changes: 1 addition & 1 deletion cypress/e2e/14-data-transformation-expressions.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import { WorkflowPage, NDV } from '../pages';
import { getVisibleSelect } from '../utils';

const wf = new WorkflowPage();
const ndv = new NDV();
Expand Down
6 changes: 3 additions & 3 deletions cypress/e2e/14-mapping.cy.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { WorkflowPage, NDV } from '../pages';
import { getVisibleSelect } from '../utils';
import {
MANUAL_TRIGGER_NODE_NAME,
MANUAL_TRIGGER_NODE_DISPLAY_NAME,
SCHEDULE_TRIGGER_NODE_NAME,
} from './../constants';
import { WorkflowPage, NDV } from '../pages';
import { getVisibleSelect } from '../utils';

const workflowPage = new WorkflowPage();
const ndv = new NDV();
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('Data mapping', () => {
});

it('maps expressions from previous nodes', () => {
cy.createFixtureWorkflow('Test_workflow_3.json', `My test workflow`);
cy.createFixtureWorkflow('Test_workflow_3.json', 'My test workflow');
workflowPage.actions.zoomToFit();
workflowPage.actions.openNode('Set1');

Expand Down
45 changes: 25 additions & 20 deletions cypress/e2e/15-scheduler-node.cy.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { WorkflowPage, WorkflowsPage, NDV } from '../pages';
import { BACKEND_BASE_URL } from '../constants';
import { getVisibleSelect } from '../utils';
import type { ExecutionResponse } from '../types';

const workflowsPage = new WorkflowsPage();
const workflowPage = new WorkflowPage();
const ndv = new NDV();

describe('Schedule Trigger node', async () => {
describe('Schedule Trigger node', () => {
beforeEach(() => {
workflowPage.actions.visit();
});
Expand Down Expand Up @@ -37,30 +38,34 @@ describe('Schedule Trigger node', async () => {
const workflowId = url.split('/').pop();

cy.wait(1200);
cy.request('GET', `${BACKEND_BASE_URL}/rest/executions`).then((response) => {
expect(response.status).to.eq(200);
expect(workflowId).to.not.be.undefined;
expect(response.body.data.results.length).to.be.greaterThan(0);
const matchingExecutions = response.body.data.results.filter(
(execution: any) => execution.workflowId === workflowId,
);
expect(matchingExecutions).to.have.length(1);

cy.wait(1200);
cy.request('GET', `${BACKEND_BASE_URL}/rest/executions`).then((response) => {
cy.request<ExecutionResponse>('GET', `${BACKEND_BASE_URL}/rest/executions`).then(
(response) => {
expect(response.status).to.eq(200);
expect(workflowId).to.not.be.undefined;
expect(response.body.data.results.length).to.be.greaterThan(0);
const matchingExecutions = response.body.data.results.filter(
(execution: any) => execution.workflowId === workflowId,
(execution) => execution.workflowId === workflowId,
);
expect(matchingExecutions).to.have.length(2);
expect(matchingExecutions).to.have.length(1);

cy.wait(1200);
cy.request<ExecutionResponse>('GET', `${BACKEND_BASE_URL}/rest/executions`).then(
(response1) => {
expect(response1.status).to.eq(200);
expect(response1.body.data.results.length).to.be.greaterThan(0);
const matchingExecutions1 = response1.body.data.results.filter(
(execution: any) => execution.workflowId === workflowId,
);
expect(matchingExecutions1).to.have.length(2);

workflowPage.actions.activateWorkflow();
workflowPage.getters.activatorSwitch().should('not.have.class', 'is-checked');
cy.visit(workflowsPage.url);
workflowsPage.actions.deleteWorkFlow('Schedule Trigger Workflow');
});
});
workflowPage.actions.activateWorkflow();
workflowPage.getters.activatorSwitch().should('not.have.class', 'is-checked');
cy.visit(workflowsPage.url);
workflowsPage.actions.deleteWorkFlow('Schedule Trigger Workflow');
},
);
},
);
});
});
});
Loading

0 comments on commit 162e298

Please sign in to comment.