mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 02:21:13 +00:00
ci: Playwright project organization (#17905)
This commit is contained in:
@@ -1,143 +1,42 @@
|
||||
/* eslint-disable import-x/no-default-export */
|
||||
import { currentsReporter } from '@currents/playwright';
|
||||
import type { Project } from '@playwright/test';
|
||||
import { defineConfig } from '@playwright/test';
|
||||
import os from 'os';
|
||||
|
||||
import currentsConfig from './currents.config';
|
||||
import { getProjects } from './playwright-projects';
|
||||
import { getPortFromUrl } from './utils/url-helper';
|
||||
|
||||
// Type definitions for container configurations
|
||||
interface ContainerConfig {
|
||||
postgres?: boolean;
|
||||
queueMode?: {
|
||||
mains: number;
|
||||
workers: number;
|
||||
};
|
||||
env?: Record<string, string>;
|
||||
}
|
||||
const IS_CI = !!process.env.CI;
|
||||
|
||||
interface ContainerConfigEntry {
|
||||
name: string;
|
||||
config: ContainerConfig;
|
||||
}
|
||||
const MACBOOK_WINDOW_SIZE = { width: 1536, height: 960 };
|
||||
|
||||
/*
|
||||
* Mode-based Test Configuration
|
||||
*
|
||||
* Usage examples:
|
||||
*
|
||||
* 1. Run only mode:standard tests:
|
||||
* npx playwright test --project="mode:standard*"
|
||||
*
|
||||
* 2. Run only parallel tests for all modes:
|
||||
* npx playwright test --project="*Parallel"
|
||||
*
|
||||
* 3. Run a specific mode's sequential tests:
|
||||
* npx playwright test --project="mode:multi-main - Sequential"
|
||||
*
|
||||
* Test tagging examples:
|
||||
*
|
||||
* // Runs on all modes
|
||||
* test('basic functionality', async ({ page }) => { ... });
|
||||
*
|
||||
* // Only runs on multi-main mode
|
||||
* test('multi-main specific @mode:multi-main', async ({ page }) => { ... });
|
||||
*
|
||||
* // Only runs on postgres mode, and in sequential execution
|
||||
* test('database reset test @mode:postgres @db:reset', async ({ page }) => { ... });
|
||||
*
|
||||
* // Runs on all modes, but in sequential execution
|
||||
* test('another reset test @db:reset', async ({ page }) => { ... });
|
||||
*/
|
||||
|
||||
// Container configurations
|
||||
const containerConfigs: ContainerConfigEntry[] = [
|
||||
{ name: 'mode:standard', config: {} },
|
||||
{ name: 'mode:postgres', config: { postgres: true } },
|
||||
{ name: 'mode:queue', config: { queueMode: { mains: 1, workers: 1 } } },
|
||||
{ name: 'mode:multi-main', config: { queueMode: { mains: 2, workers: 1 } } },
|
||||
];
|
||||
|
||||
// Workflow tests are run in a separate project, since they are not run in parallel with the other tests
|
||||
const workflowProject: Project = {
|
||||
name: 'mode:workflows',
|
||||
testDir: './test-workflows',
|
||||
testMatch: 'workflow-tests.spec.ts',
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
fullyParallel: true,
|
||||
};
|
||||
|
||||
// Parallel tests can run fully parallel on a worker
|
||||
// Sequential tests can run on a single worker, since the need a DB reset
|
||||
// Chaos tests can run on a single worker, since they can destroy containers etc, these need to be isolate from DB tests since they are destructive
|
||||
function createProjectTrio(name: string, containerConfig: ContainerConfig): Project[] {
|
||||
const modeTag = `@${name}`;
|
||||
|
||||
// Parse custom env vars from command line
|
||||
const customEnv = process.env.N8N_TEST_ENV ? JSON.parse(process.env.N8N_TEST_ENV) : {};
|
||||
|
||||
// Merge custom env vars into container config
|
||||
const mergedConfig = {
|
||||
...containerConfig,
|
||||
env: {
|
||||
...containerConfig.env,
|
||||
...customEnv,
|
||||
},
|
||||
};
|
||||
|
||||
// Only add dependencies when using external URL (i.e., using containers)
|
||||
// This is to stop DB reset tests from running in parallel with other tests when more than 1 worker is used
|
||||
const shouldAddDependencies = process.env.N8N_BASE_URL;
|
||||
|
||||
return [
|
||||
{
|
||||
name: `${name} - Parallel`,
|
||||
grep: new RegExp(
|
||||
`${modeTag}(?!.*(@db:reset|@chaostest))|^(?!.*(@mode:|@db:reset|@chaostest))`,
|
||||
),
|
||||
testIgnore: '*examples*',
|
||||
fullyParallel: true,
|
||||
use: { containerConfig: mergedConfig },
|
||||
},
|
||||
{
|
||||
name: `${name} - Sequential`,
|
||||
grep: new RegExp(`${modeTag}.*@db:reset|@db:reset(?!.*@mode:)`),
|
||||
fullyParallel: false,
|
||||
testIgnore: '*examples*',
|
||||
workers: 1,
|
||||
...(shouldAddDependencies && { dependencies: [`${name} - Parallel`] }),
|
||||
use: { containerConfig: mergedConfig },
|
||||
},
|
||||
{
|
||||
name: `${name} - Chaos`,
|
||||
grep: new RegExp(`${modeTag}.*@chaostest`),
|
||||
testIgnore: '*examples*',
|
||||
fullyParallel: false,
|
||||
workers: 1,
|
||||
use: { containerConfig: mergedConfig },
|
||||
timeout: 120000,
|
||||
},
|
||||
];
|
||||
}
|
||||
// Calculate workers based on environment
|
||||
// The amount of workers to run, limited to 6 as higher causes instability in the local server
|
||||
// Use half the CPUs in local, full in CI (CI has no other processes so we can use more)
|
||||
const CPU_COUNT = os.cpus().length;
|
||||
const LOCAL_WORKERS = Math.min(6, Math.floor(CPU_COUNT / 2));
|
||||
const CI_WORKERS = CPU_COUNT;
|
||||
const WORKERS = IS_CI ? CI_WORKERS : LOCAL_WORKERS;
|
||||
|
||||
export default defineConfig({
|
||||
globalSetup: './global-setup.ts',
|
||||
testDir: './tests',
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 2 : 8,
|
||||
forbidOnly: IS_CI,
|
||||
retries: IS_CI ? 2 : 0,
|
||||
workers: WORKERS,
|
||||
timeout: 60000,
|
||||
|
||||
reporter: process.env.CI
|
||||
? [
|
||||
['list'],
|
||||
['github'],
|
||||
['junit', { outputFile: process.env.PLAYWRIGHT_JUNIT_OUTPUT_NAME ?? 'results.xml' }],
|
||||
['html', { open: 'never' }],
|
||||
['json', { outputFile: 'test-results.json' }],
|
||||
['blob'],
|
||||
currentsReporter(currentsConfig),
|
||||
]
|
||||
: [['html']],
|
||||
projects: getProjects(),
|
||||
|
||||
// We use this if an n8n url is passed in. If the server is already running, we reuse it.
|
||||
webServer: process.env.N8N_BASE_URL
|
||||
? {
|
||||
command: `cd .. && N8N_PORT=${getPortFromUrl(process.env.N8N_BASE_URL)} N8N_USER_FOLDER=/${os.tmpdir()}/n8n-main-$(date +%s) E2E_TESTS=true pnpm start`,
|
||||
url: `${process.env.N8N_BASE_URL}/favicon.ico`,
|
||||
timeout: 20000,
|
||||
reuseExistingServer: true,
|
||||
}
|
||||
: undefined,
|
||||
|
||||
use: {
|
||||
trace: 'on',
|
||||
@@ -145,18 +44,19 @@ export default defineConfig({
|
||||
screenshot: 'on',
|
||||
testIdAttribute: 'data-test-id',
|
||||
headless: process.env.SHOW_BROWSER !== 'true',
|
||||
viewport: { width: 1536, height: 960 },
|
||||
actionTimeout: 30000,
|
||||
viewport: MACBOOK_WINDOW_SIZE,
|
||||
actionTimeout: 20000, // TODO: We might need to make this dynamic for container tests if we have low resource containers etc
|
||||
navigationTimeout: 10000,
|
||||
channel: 'chromium',
|
||||
},
|
||||
|
||||
projects: process.env.N8N_BASE_URL
|
||||
? containerConfigs
|
||||
.filter(({ name }) => name === 'mode:standard')
|
||||
.flatMap(({ name, config }) => createProjectTrio(name, config))
|
||||
.concat([workflowProject])
|
||||
: containerConfigs
|
||||
.flatMap(({ name, config }) => createProjectTrio(name, config))
|
||||
.concat([workflowProject]),
|
||||
reporter: IS_CI
|
||||
? [
|
||||
['list'],
|
||||
['github'],
|
||||
['junit', { outputFile: process.env.PLAYWRIGHT_JUNIT_OUTPUT_NAME ?? 'results.xml' }],
|
||||
['html', { open: 'never' }],
|
||||
['json', { outputFile: 'test-results.json' }],
|
||||
currentsReporter(currentsConfig),
|
||||
]
|
||||
: [['html']],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user