ci: Test container enhancements (#17008)

This commit is contained in:
shortstacked
2025-07-10 11:50:03 +01:00
committed by GitHub
parent 2294c3d71b
commit be3e75dbee
23 changed files with 408 additions and 154 deletions

View File

@@ -19,7 +19,7 @@ export class ProjectComposer {
const projectNameUnique = projectName ?? `Project ${Date.now()}`;
await this.n8n.projectSettings.fillProjectName(projectNameUnique);
await this.n8n.projectSettings.clickSaveButton();
const projectId = await this.extractProjectIdFromPage('projects', 'settings');
const projectId = this.extractProjectIdFromPage('projects', 'settings');
return { projectName: projectNameUnique, projectId };
}
@@ -50,7 +50,7 @@ export class ProjectComposer {
return match?.[1] ?? '';
}
async extractProjectIdFromPage(beforeWord: string, afterWord: string): Promise<string> {
extractProjectIdFromPage(beforeWord: string, afterWord: string): string {
return this.extractIdFromUrl(this.n8n.page.url(), beforeWord, afterWord);
}
}

View File

@@ -1,4 +1,4 @@
/* eslint-disable import/no-extraneous-dependencies */
/* eslint-disable import-x/no-extraneous-dependencies */
import type { FrontendSettings } from '@n8n/api-types';
import type { BrowserContext, Route } from '@playwright/test';
import cloneDeep from 'lodash/cloneDeep';

View File

@@ -1,21 +1,10 @@
const sharedOptions = require('@n8n/eslint-config/shared');
/**
* @type {import('@types/eslint').ESLint.ConfigData}
*/
module.exports = {
extends: ['@n8n/eslint-config/base', 'plugin:playwright/recommended'],
...sharedOptions(__dirname),
plugins: ['playwright'],
env: {
node: true,
},
import { defineConfig, globalIgnores } from 'eslint/config';
import { baseConfig } from '@n8n/eslint-config/base';
import playwrightPlugin from 'eslint-plugin-playwright';
export default defineConfig(baseConfig, playwrightPlugin.configs['flat/recommended'], {
ignores: ['playwright-report/**'],
rules: {
// TODO: remove these rules
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unsafe-argument': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
@@ -28,9 +17,9 @@ module.exports = {
'n8n-local-rules/no-uncaught-json-parse': 'off',
'playwright/expect-expect': 'warn',
'playwright/max-nested-describe': 'warn',
'playwright/no-conditional-in-test': 'warn',
'playwright/no-conditional-in-test': 'error',
'playwright/no-skipped-test': 'warn',
'import/no-extraneous-dependencies': [
'import-x/no-extraneous-dependencies': [
'error',
{
devDependencies: ['**/tests/**', '**/e2e/**', '**/playwright/**'],
@@ -38,4 +27,4 @@ module.exports = {
},
],
},
};
});

View File

@@ -2,6 +2,7 @@ import { test as base, expect, type TestInfo } from '@playwright/test';
import type { N8NStack } from 'n8n-containers/n8n-test-container-creation';
import { createN8NStack } from 'n8n-containers/n8n-test-container-creation';
import { ContainerTestHelpers } from 'n8n-containers/n8n-test-container-helpers';
import { setTimeout as wait } from 'node:timers/promises';
import { setupDefaultInterceptors } from '../config/intercepts';
import { n8nPage } from '../pages/n8nPage';
@@ -28,6 +29,7 @@ interface ContainerConfig {
mains: number;
workers: number;
};
env?: Record<string, string>;
}
/**
@@ -40,6 +42,11 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({
containerConfig: [
async ({}, use, testInfo: TestInfo) => {
const config = (testInfo.project.use?.containerConfig as ContainerConfig) || {};
config.env = {
...config.env,
E2E_TESTS: 'true',
};
await use(config);
},
{ scope: 'worker' },
@@ -60,7 +67,7 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({
const container = await createN8NStack(containerConfig);
// TODO: Remove this once we have a better way to wait for the container to be ready (e.g. healthcheck)
await new Promise((resolve) => setTimeout(resolve, 5000));
await wait(3000);
console.log(`Container URL: ${container.baseUrl}`);

View File

@@ -39,5 +39,5 @@ async function globalSetup() {
console.log('🏁 Global setup completed');
}
// eslint-disable-next-line import/no-default-export
// eslint-disable-next-line import-x/no-default-export
export default globalSetup;

View File

@@ -18,6 +18,7 @@
"devDependencies": {
"@currents/playwright": "1.14.1",
"@playwright/test": "1.53.0",
"@types/lodash": "catalog:",
"eslint-plugin-playwright": "2.2.0",
"n8n-containers": "workspace:*"
}

View File

@@ -11,17 +11,17 @@ export class ExecutionsPage extends BasePage {
await this.clickButtonByName('Copy to editor');
}
async getExecutionItems(): Promise<Locator> {
getExecutionItems(): Locator {
return this.page.locator('div.execution-card');
}
async getLastExecutionItem(): Promise<Locator> {
const executionItems = await this.getExecutionItems();
getLastExecutionItem(): Locator {
const executionItems = this.getExecutionItems();
return executionItems.nth(0);
}
async clickLastExecutionItem(): Promise<void> {
const executionItem = await this.getLastExecutionItem();
const executionItem = this.getLastExecutionItem();
await executionItem.click();
}

View File

@@ -13,6 +13,7 @@ import { CanvasComposer } from '../composables/CanvasComposer';
import { ProjectComposer } from '../composables/ProjectComposer';
import { WorkflowComposer } from '../composables/WorkflowComposer';
// eslint-disable-next-line @typescript-eslint/naming-convention
export class n8nPage {
readonly page: Page;

View File

@@ -1,4 +1,4 @@
/* eslint-disable import/no-default-export */
/* eslint-disable import-x/no-default-export */
import type { Project } from '@playwright/test';
import { defineConfig } from '@playwright/test';

View File

@@ -1,5 +1,6 @@
// services/api-helper.ts
import type { APIRequestContext } from '@playwright/test';
import { setTimeout as wait } from 'node:timers/promises';
import type { UserCredentials } from '../config/test-users';
import {
@@ -115,7 +116,7 @@ export class ApiHelpers {
throw new TestError(errorText);
}
// Adding small delay to ensure database is reset
await new Promise((resolve) => setTimeout(resolve, 1000));
await wait(1000);
}
async signin(role: UserRole, memberIndex: number = 0): Promise<LoginResponseData> {