mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 04:34:06 -08:00
test: Address flaky setup e2e (no-changelog) (#6085)
* test: Add /setup intercept for `skipSetup` command (no-changelog) * Drop all tables for e2e reset, intercept account setup request * Fix linting issues * Allow to skip setup account request intercept and linting fixes * Make sure variables are loaded * Use PATCH for enabling of e2e features * Do not exclude migration table from truncation * Add user sign-up intercept
This commit is contained in:
parent
700cc39cbc
commit
e88232ede2
|
@ -11,7 +11,7 @@ module.exports = defineConfig({
|
||||||
},
|
},
|
||||||
defaultCommandTimeout: 10000,
|
defaultCommandTimeout: 10000,
|
||||||
requestTimeout: 12000,
|
requestTimeout: 12000,
|
||||||
numTestsKeptInMemory: 0,
|
numTestsKeptInMemory: 2,
|
||||||
experimentalMemoryManagement: true,
|
experimentalMemoryManagement: true,
|
||||||
e2e: {
|
e2e: {
|
||||||
baseUrl: BASE_URL,
|
baseUrl: BASE_URL,
|
||||||
|
@ -35,8 +35,13 @@ module.exports = defineConfig({
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'enable-feature': (feature) =>
|
'set-feature': ({ feature, enabled }) => {
|
||||||
fetch(BASE_URL + `/e2e/enable-feature/${feature}`, { method: 'POST' }),
|
return fetch(BASE_URL + `/e2e/feature/${feature}`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
body: JSON.stringify({ enabled }),
|
||||||
|
headers: { 'Content-Type': 'application/json' }
|
||||||
|
})
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,6 +16,7 @@ describe('Variables', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the unlicensed action box when the feature is disabled', () => {
|
it('should show the unlicensed action box when the feature is disabled', () => {
|
||||||
|
cy.disableFeature('feat:variables');
|
||||||
cy.signin({ email, password });
|
cy.signin({ email, password });
|
||||||
cy.visit(variablesPage.url);
|
cy.visit(variablesPage.url);
|
||||||
|
|
||||||
|
@ -30,7 +31,10 @@ describe('Variables', () => {
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.signin({ email, password });
|
cy.signin({ email, password });
|
||||||
|
cy.intercept('GET', '/rest/variables').as('loadVariables');
|
||||||
|
|
||||||
cy.visit(variablesPage.url);
|
cy.visit(variablesPage.url);
|
||||||
|
cy.wait(['@loadVariables', '@loadSettings']);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show the licensed action box when the feature is enabled', () => {
|
it('should show the licensed action box when the feature is enabled', () => {
|
||||||
|
|
|
@ -84,11 +84,12 @@ describe('Default owner', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to setup instance and migrate workflows and credentials', () => {
|
it('should be able to setup instance and migrate workflows and credentials', () => {
|
||||||
cy.setup({ email, firstName, lastName, password });
|
cy.setup({ email, firstName, lastName, password }, true);
|
||||||
|
|
||||||
messageBox.getters.content().should('contain.text', '1 existing workflow and 1 credential');
|
messageBox.getters.content().should('contain.text', '1 existing workflow and 1 credential');
|
||||||
|
|
||||||
messageBox.actions.confirm();
|
messageBox.actions.confirm();
|
||||||
|
cy.wait('@setupRequest');
|
||||||
cy.url().should('include', settingsUsersPage.url);
|
cy.url().should('include', settingsUsersPage.url);
|
||||||
settingsSidebar.actions.back();
|
settingsSidebar.actions.back();
|
||||||
|
|
||||||
|
|
|
@ -105,18 +105,22 @@ Cypress.Commands.add('signup', ({ firstName, lastName, password, url }) => {
|
||||||
|
|
||||||
signupPage.getters.form().within(() => {
|
signupPage.getters.form().within(() => {
|
||||||
cy.url().then((url) => {
|
cy.url().then((url) => {
|
||||||
|
cy.intercept('/rest/users/*').as('userSignup')
|
||||||
signupPage.getters.firstName().type(firstName);
|
signupPage.getters.firstName().type(firstName);
|
||||||
signupPage.getters.lastName().type(lastName);
|
signupPage.getters.lastName().type(lastName);
|
||||||
signupPage.getters.password().type(password);
|
signupPage.getters.password().type(password);
|
||||||
signupPage.getters.submit().click();
|
signupPage.getters.submit().click();
|
||||||
|
cy.wait('@userSignup');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('setup', ({ email, firstName, lastName, password }) => {
|
Cypress.Commands.add('setup', ({ email, firstName, lastName, password }, skipIntercept = false) => {
|
||||||
const signupPage = new SignupPage();
|
const signupPage = new SignupPage();
|
||||||
|
|
||||||
|
cy.intercept('GET', signupPage.url).as('setupPage');
|
||||||
cy.visit(signupPage.url);
|
cy.visit(signupPage.url);
|
||||||
|
cy.wait('@setupPage');
|
||||||
|
|
||||||
signupPage.getters.form().within(() => {
|
signupPage.getters.form().within(() => {
|
||||||
cy.url().then((url) => {
|
cy.url().then((url) => {
|
||||||
|
@ -125,7 +129,13 @@ Cypress.Commands.add('setup', ({ email, firstName, lastName, password }) => {
|
||||||
signupPage.getters.firstName().type(firstName);
|
signupPage.getters.firstName().type(firstName);
|
||||||
signupPage.getters.lastName().type(lastName);
|
signupPage.getters.lastName().type(lastName);
|
||||||
signupPage.getters.password().type(password);
|
signupPage.getters.password().type(password);
|
||||||
|
|
||||||
|
cy.intercept('POST', '/rest/owner/setup').as('setupRequest');
|
||||||
signupPage.getters.submit().click();
|
signupPage.getters.submit().click();
|
||||||
|
|
||||||
|
if(!skipIntercept) {
|
||||||
|
cy.wait('@setupRequest');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cy.log('User already signed up');
|
cy.log('User already signed up');
|
||||||
}
|
}
|
||||||
|
@ -168,7 +178,9 @@ Cypress.Commands.add('skipSetup', () => {
|
||||||
const workflowPage = new WorkflowPage();
|
const workflowPage = new WorkflowPage();
|
||||||
const Confirmation = new MessageBox();
|
const Confirmation = new MessageBox();
|
||||||
|
|
||||||
|
cy.intercept('GET', signupPage.url).as('setupPage');
|
||||||
cy.visit(signupPage.url);
|
cy.visit(signupPage.url);
|
||||||
|
cy.wait('@setupPage');
|
||||||
|
|
||||||
signupPage.getters.form().within(() => {
|
signupPage.getters.form().within(() => {
|
||||||
cy.url().then((url) => {
|
cy.url().then((url) => {
|
||||||
|
@ -199,7 +211,11 @@ Cypress.Commands.add('setupOwner', (payload) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('enableFeature', (feature) => {
|
Cypress.Commands.add('enableFeature', (feature) => {
|
||||||
cy.task('enable-feature', feature);
|
cy.task('set-feature', { feature, enabled: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
Cypress.Commands.add('disableFeature', (feature) => {
|
||||||
|
cy.task('set-feature', { feature, enabled: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
Cypress.Commands.add('grantBrowserPermissions', (...permissions: string[]) => {
|
Cypress.Commands.add('grantBrowserPermissions', (...permissions: string[]) => {
|
||||||
|
|
|
@ -36,13 +36,14 @@ declare global {
|
||||||
signin(payload: SigninPayload): void;
|
signin(payload: SigninPayload): void;
|
||||||
signout(): void;
|
signout(): void;
|
||||||
signup(payload: SignupPayload): void;
|
signup(payload: SignupPayload): void;
|
||||||
setup(payload: SetupPayload): void;
|
setup(payload: SetupPayload, skipIntercept?: boolean): void;
|
||||||
setupOwner(payload: SetupPayload): void;
|
setupOwner(payload: SetupPayload): void;
|
||||||
inviteUsers(payload: InviteUsersPayload): void;
|
inviteUsers(payload: InviteUsersPayload): void;
|
||||||
interceptREST(method: string, url: string): Chainable<Interception>;
|
interceptREST(method: string, url: string): Chainable<Interception>;
|
||||||
skipSetup(): void;
|
skipSetup(): void;
|
||||||
resetAll(): void;
|
resetAll(): void;
|
||||||
enableFeature(feature: string): void;
|
enableFeature(feature: string): void;
|
||||||
|
disableFeature(feature: string): void;
|
||||||
waitForLoad(waitForIntercepts?: boolean): void;
|
waitForLoad(waitForIntercepts?: boolean): void;
|
||||||
grantBrowserPermissions(...permissions: string[]): void;
|
grantBrowserPermissions(...permissions: string[]): void;
|
||||||
readClipboard(): Chainable<string>;
|
readClipboard(): Chainable<string>;
|
||||||
|
|
|
@ -36,33 +36,30 @@ type Feature = keyof typeof enabledFeatures;
|
||||||
|
|
||||||
Container.get(License).isFeatureEnabled = (feature: Feature) => enabledFeatures[feature] ?? false;
|
Container.get(License).isFeatureEnabled = (feature: Feature) => enabledFeatures[feature] ?? false;
|
||||||
|
|
||||||
const tablesToTruncate = [
|
const tablesNotToTruncate = ['sqlite_sequence'];
|
||||||
'auth_identity',
|
|
||||||
'auth_provider_sync_history',
|
|
||||||
'event_destinations',
|
|
||||||
'shared_workflow',
|
|
||||||
'shared_credentials',
|
|
||||||
'webhook_entity',
|
|
||||||
'workflows_tags',
|
|
||||||
'credentials_entity',
|
|
||||||
'tag_entity',
|
|
||||||
'workflow_statistics',
|
|
||||||
'workflow_entity',
|
|
||||||
'execution_entity',
|
|
||||||
'settings',
|
|
||||||
'installed_packages',
|
|
||||||
'installed_nodes',
|
|
||||||
'user',
|
|
||||||
'role',
|
|
||||||
];
|
|
||||||
|
|
||||||
const truncateAll = async () => {
|
const truncateAll = async () => {
|
||||||
const connection = Db.getConnection();
|
const connection = Db.getConnection();
|
||||||
for (const table of tablesToTruncate) {
|
const allTables: Array<{ name: string }> = await connection.query(
|
||||||
|
"SELECT name FROM sqlite_master WHERE type='table';",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Disable foreign key constraint checks
|
||||||
|
await connection.query('PRAGMA foreign_keys = OFF;');
|
||||||
|
|
||||||
|
for (const { name: table } of allTables) {
|
||||||
|
try {
|
||||||
|
if (tablesNotToTruncate.includes(table)) continue;
|
||||||
await connection.query(
|
await connection.query(
|
||||||
`DELETE FROM ${table}; DELETE FROM sqlite_sequence WHERE name=${table};`,
|
`DELETE FROM ${table}; DELETE FROM sqlite_sequence WHERE name=${table};`,
|
||||||
);
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Dropping Table for E2E Reset error: ', error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-enable foreign key constraint checks
|
||||||
|
await connection.query('PRAGMA foreign_keys = ON;');
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupUserManagement = async () => {
|
const setupUserManagement = async () => {
|
||||||
|
@ -139,8 +136,14 @@ e2eController.post('/db/setup-owner', bodyParser.json(), async (req, res) => {
|
||||||
res.writeHead(204).end();
|
res.writeHead(204).end();
|
||||||
});
|
});
|
||||||
|
|
||||||
e2eController.post('/enable-feature/:feature', async (req: Request<{ feature: Feature }>, res) => {
|
e2eController.patch(
|
||||||
|
'/feature/:feature',
|
||||||
|
bodyParser.json(),
|
||||||
|
async (req: Request<{ feature: Feature }>, res) => {
|
||||||
const { feature } = req.params;
|
const { feature } = req.params;
|
||||||
enabledFeatures[feature] = true;
|
const { enabled } = req.body;
|
||||||
|
|
||||||
|
enabledFeatures[feature] = enabled === undefined || enabled === true;
|
||||||
res.writeHead(204).end();
|
res.writeHead(204).end();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in a new issue