test(core): Run only expression tests once per engine in the workflow package (no-changelog) (#40242)

This commit is contained in:
Mike Repeć 2026-10-06 13:07:49 +00:00 committed by GitHub
parent 62fd028089
commit 2b685c33b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 18 deletions

View File

@ -1,9 +1,36 @@
import { Expression } from '../src/expression';
// Only runs when N8N_EXPRESSION_ENGINE is set to 'vm' or 'quickjs'.
// The engine projects (vitest.config.ts) run the tests that evaluate
// expressions once per engine and set N8N_EXPRESSION_ENGINE; the default
// project runs everything else once and sets it to ''.
const engine = (process.env.N8N_EXPRESSION_ENGINE || undefined) as
| 'vm'
| 'legacy'
| 'quickjs'
| undefined;
// A test that evaluates an expression outside the engine projects would pass
// against one engine only, so it fails here until it is added to ENGINE_TESTS.
// With no engine initialised every entry point (resolveSimpleParameterValue,
// resolveWithoutWorkflow) ends in the legacy evaluator, so that is the guard.
// vi.mock is hoisted above every other statement, so the factory reads the
// environment itself instead of the `engine` constant below.
vi.mock('../src/expression-evaluator-proxy', async (importOriginal) => {
const original = await importOriginal<typeof import('../src/expression-evaluator-proxy')>();
if (process.env.N8N_EXPRESSION_ENGINE) return original;
return {
...original,
evaluateExpression: () => {
throw new Error(
`${expect.getState().testPath} evaluates an expression. Add it to ENGINE_TESTS in vitest.config.ts so it runs once per engine.`,
);
},
};
});
// Initializes the expression evaluator once per vitest worker before all tests,
// and disposes it after.
const engine = process.env.N8N_EXPRESSION_ENGINE as 'vm' | 'quickjs' | undefined;
if (engine === 'vm' || engine === 'quickjs') {
beforeAll(async () => {
await Expression.initExpressionEngine({

View File

@ -1,11 +1,43 @@
import { defineConfig } from 'vitest/config';
import { createBaseInlineConfig } from '@n8n/vitest-config/node';
// Tests that evaluate expressions, so their outcome depends on the engine.
// Only these run once per engine project; everything else runs once in the
// default project. A test outside this list that evaluates an expression fails
// there (see test/setup-vm-evaluator.ts), so the list cannot drift silently.
const ENGINE_TESTS = [
'test/expression.test.ts',
'test/expression-array-proxy-semantics.test.ts',
'test/expression-compatibility.test.ts',
'test/expression-engine-start-failure.test.ts',
'test/expression-item-accessor-engine-parity.test.ts',
'test/expression-items-engine-parity.test.ts',
'test/expression-nested-data.test.ts',
'test/expression-vm-errors.test.ts',
'test/expression-with-isolate.test.ts',
'test/ExpressionExtensions/*.test.ts',
'test/native-evaluation-fuzz.test.ts',
'test/native-evaluation-parity.test.ts',
'test/webhook-description-fields.test.ts',
'test/workflow.test.ts',
'test/workflow-data-proxy.test.ts',
'test/workflow-expression.test.ts',
];
const { reporters, outputFile, ...sharedTestConfig } = createBaseInlineConfig({
include: ['test/**/*.test.ts'],
setupFiles: ['./test/setup-vm-evaluator.ts'],
});
const engineProject = (engine: 'vm' | 'legacy' | 'quickjs') => ({
test: {
...sharedTestConfig,
include: ENGINE_TESTS,
name: `${engine}-engine`,
env: { N8N_EXPRESSION_ENGINE: engine },
},
});
export default defineConfig({
test: {
reporters,
@ -14,24 +46,16 @@ export default defineConfig({
{
test: {
...sharedTestConfig,
name: 'vm-engine',
env: { N8N_EXPRESSION_ENGINE: 'vm' },
},
},
{
test: {
...sharedTestConfig,
name: 'legacy-engine',
env: { N8N_EXPRESSION_ENGINE: 'legacy' },
},
},
{
test: {
...sharedTestConfig,
name: 'quickjs-engine',
env: { N8N_EXPRESSION_ENGINE: 'quickjs' },
exclude: [...(sharedTestConfig.exclude ?? []), ...ENGINE_TESTS],
name: 'default',
// Explicitly no engine, so a shell N8N_EXPRESSION_ENGINE cannot turn
// this project into a fourth engine run and disable the guard.
env: { N8N_EXPRESSION_ENGINE: '' },
},
},
engineProject('vm'),
engineProject('legacy'),
engineProject('quickjs'),
],
},
});