mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-17 05:29:44 +02:00
chore: Remove references to Jest (#33282)
This commit is contained in:
parent
926a8158c2
commit
df97053888
|
|
@ -24,13 +24,13 @@ Based on the affected area, pick the test layer and pattern:
|
|||
|
||||
| Area | Test Layer | Pattern | Key Location |
|
||||
|------|-----------|---------|--------------|
|
||||
| Node operation | Jest unit | NodeTestHarness + nock | `packages/nodes-base/nodes/*/test/` |
|
||||
| Node credential | Jest unit | jest-mock-extended | `packages/nodes-base/nodes/*/test/` |
|
||||
| Trigger webhook | Jest unit | mock IHookFunctions + jest.mock GenericFunctions | `packages/nodes-base/nodes/*/test/` |
|
||||
| Binary data | Jest unit | NodeTestHarness assertBinaryData | `packages/core/nodes-testing/` |
|
||||
| Execution engine | Jest integration | WorkflowRunner + DI container | `packages/cli/src/__tests__/` |
|
||||
| CLI / API | Jest integration | setupTestServer + supertest | `packages/cli/test/integration/` |
|
||||
| Config | Jest unit | GlobalConfig + Container | `packages/@n8n/config/src/__tests__/` |
|
||||
| Node operation | Vitest unit | NodeTestHarness + nock | `packages/nodes-base/nodes/*/test/` |
|
||||
| Node credential | Vitest unit | vitest-mock-extended | `packages/nodes-base/nodes/*/test/` |
|
||||
| Trigger webhook | Vitest unit | mock IHookFunctions + vi.mock GenericFunctions | `packages/nodes-base/nodes/*/test/` |
|
||||
| Binary data | Vitest unit | NodeTestHarness assertBinaryData | `packages/core/nodes-testing/` |
|
||||
| Execution engine | Vitest integration | WorkflowRunner + DI container | `packages/cli/src/__tests__/` |
|
||||
| CLI / API | Vitest integration | setupTestServer + supertest | `packages/cli/test/integration/` |
|
||||
| Config | Vitest unit | GlobalConfig + Container | `packages/@n8n/config/src/__tests__/` |
|
||||
| Editor UI | Vitest | Vue Test Utils + Pinia | `packages/frontend/editor-ui/src/**/__tests__/` |
|
||||
| E2E / Canvas | Playwright | Test containers + composables | `packages/testing/playwright/` |
|
||||
|
||||
|
|
|
|||
2
.github/pull_request_title_conventions.md
vendored
2
.github/pull_request_title_conventions.md
vendored
|
|
@ -39,7 +39,7 @@ Must be one of the following:
|
|||
| `test` | Adding missing tests or correcting existing tests | ❌ |
|
||||
| `docs` | Documentation only changes | ❌ |
|
||||
| `refactor` | A behavior-neutral code change that neither fixes a bug nor adds a feature | ❌ |
|
||||
| `build` | Changes that affect the build system or external dependencies (TypeScript, Jest, pnpm, etc.) | ❌ |
|
||||
| `build` | Changes that affect the build system or external dependencies (TypeScript, Vitest, pnpm, etc.) | ❌ |
|
||||
| `ci` | Changes to CI configuration files and scripts (e.g. Github actions) | ❌ |
|
||||
| `chore` | Routine tasks, maintenance, and minor updates not covered by other types | ❌ |
|
||||
|
||||
|
|
|
|||
4
.github/workflows/ci-pull-requests.yml
vendored
4
.github/workflows/ci-pull-requests.yml
vendored
|
|
@ -135,10 +135,6 @@ jobs:
|
|||
packages/cli/test/shared/db/**
|
||||
packages/cli/test/setup-testcontainers.js
|
||||
packages/cli/test/teardown-testcontainers.js
|
||||
packages/cli/jest.config.integration.js
|
||||
packages/cli/jest.config.integration.testcontainers.js
|
||||
packages/cli/jest.config.migration.js
|
||||
packages/cli/jest.config.migration.testcontainers.js
|
||||
packages/@n8n/db/**
|
||||
packages/@n8n/backend-test-utils/**
|
||||
packages/cli/**/__tests__/**
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ The monorepo is organized into these key packages:
|
|||
|
||||
- **Frontend:** Vue 3 + TypeScript + Vite + Pinia + Storybook UI Library
|
||||
- **Backend:** Node.js + TypeScript + Express + TypeORM
|
||||
- **Testing:** Jest (unit) + Playwright (E2E)
|
||||
- **Testing:** Vitest (unit) + Playwright (E2E)
|
||||
- **Database:** TypeORM with SQLite/PostgreSQL support
|
||||
- **Code Quality:** Biome (for formatting) + ESLint + lefthook git hooks
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ const children = getChildNodes(workflow.connections, 'NodeName', 'main', 1);
|
|||
- **For Vitest packages that use `@n8n/di` decorators**, use `createVitestConfigWithDecorators` from `@n8n/vitest-config/node-decorators`. It enables SWC `decoratorMetadata` (esbuild doesn't emit it) and externalizes workspace packages that register services (`@n8n/di`, `@n8n/config`, `@n8n/constants`, `n8n-workflow`) so a single DI `Container` instance is shared across the runtime. Loading them through Vitest's pipeline alongside their CJS dist produces two `Container`s and `Container.get(...)` returns `undefined`.
|
||||
|
||||
What we use for testing and writing tests:
|
||||
- For testing nodes and other backend components, we use Jest for unit tests. Examples can be found in `packages/nodes-base/nodes/**/*test*`.
|
||||
- For testing nodes and other backend components, we use Vitest for unit tests. Examples can be found in `packages/nodes-base/nodes/**/*test*`.
|
||||
- We use `nock` for server mocking
|
||||
- For frontend we use `vitest`
|
||||
- For E2E tests we use Playwright. Run with `pnpm --filter=n8n-playwright test:local`.
|
||||
|
|
|
|||
123
jest.config.js
123
jest.config.js
|
|
@ -1,123 +0,0 @@
|
|||
const { pathsToModuleNameMapper } = require('ts-jest');
|
||||
const { compilerOptions } = require('get-tsconfig').getTsconfig().config;
|
||||
const { resolve } = require('path');
|
||||
const coverageExcludes = require('./jest.coverage-excludes');
|
||||
|
||||
/** @type {import('ts-jest').TsJestTransformerOptions} */
|
||||
const tsJestOptions = {
|
||||
tsconfig: {
|
||||
...compilerOptions,
|
||||
declaration: false,
|
||||
sourceMap: true,
|
||||
rootDir: '.',
|
||||
// Force the transpile-only path for tests. Without this, ts-jest runs
|
||||
// the full type-checker on every transformed file, which combined with
|
||||
// aggressive worker recycling (workerIdleMemoryLimit) makes test runs
|
||||
// ~4-5x slower. Package builds and `pnpm typecheck` read the package
|
||||
// tsconfig directly and are unaffected.
|
||||
isolatedModules: true,
|
||||
// Relax strictness for cross-package imports. ts-jest applies the host
|
||||
// package's tsconfig to every file it transforms, including imports
|
||||
// from packages like nodes-base that disable these in their own
|
||||
// tsconfig. The host package's own `pnpm typecheck` is unaffected.
|
||||
noImplicitReturns: false,
|
||||
noUncheckedIndexedAccess: false,
|
||||
noImplicitOverride: false,
|
||||
useUnknownInCatchVariables: false,
|
||||
},
|
||||
};
|
||||
|
||||
const isCoverageEnabled = process.env.COVERAGE_ENABLED === 'true';
|
||||
|
||||
const esmDependencies = [
|
||||
'pdfjs-dist',
|
||||
'openid-client',
|
||||
'oauth4webapi',
|
||||
'jose',
|
||||
'p-retry',
|
||||
'is-network-error',
|
||||
'uuid',
|
||||
'change-case',
|
||||
// file-type@21 and its ESM-only dependency chain
|
||||
'file-type',
|
||||
'strtok3',
|
||||
'token-types',
|
||||
'uint8array-extras',
|
||||
'@tokenizer/inflate',
|
||||
'@borewit/text-codec',
|
||||
// Add other ESM dependencies that need to be transformed here
|
||||
];
|
||||
|
||||
const esmDependenciesPattern = esmDependencies.join('|');
|
||||
|
||||
// On Windows, Jest passes raw backslash paths to transform/ignore pattern regexes
|
||||
// without normalizing separators, so we must match both / and \.
|
||||
const isWindows = process.platform === 'win32';
|
||||
const sep = isWindows ? '[/\\\\]' : '/';
|
||||
const nonSep = isWindows ? '[^/\\\\]' : '[^/]';
|
||||
|
||||
const esmDependenciesRegex = `node_modules${sep}(${esmDependenciesPattern})${sep}.+\\.m?js$`;
|
||||
|
||||
/** @type {import('jest').Config} */
|
||||
const config = {
|
||||
verbose: false,
|
||||
testEnvironment: 'node',
|
||||
testRegex: '\\.(test|spec)\\.(js|ts)$',
|
||||
testPathIgnorePatterns: ['/dist/', '/node_modules/'],
|
||||
transform: {
|
||||
'^.+\\.ts$': ['ts-jest', tsJestOptions],
|
||||
[esmDependenciesRegex]: [
|
||||
'babel-jest',
|
||||
{
|
||||
presets: ['@babel/preset-env'],
|
||||
plugins: ['babel-plugin-transform-import-meta'],
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: [
|
||||
// Exclude the pnpm virtual store dir (.pnpm) and the ESM deps from being ignored.
|
||||
`${sep}node_modules${sep}(?!\\.pnpm|${esmDependenciesPattern})${sep}`,
|
||||
// On Windows with pnpm, ESM deps live inside the virtual store (.pnpm) and are
|
||||
// accessed via hardlinks (no symlinks), so their path goes through
|
||||
// .pnpm/<pkg@version>/node_modules/<pkg>/... — exclude ESM deps from being ignored there too.
|
||||
...(isWindows
|
||||
? [`${sep}\\.pnpm${sep}${nonSep}+${sep}node_modules${sep}(?!${esmDependenciesPattern})${sep}`]
|
||||
: []),
|
||||
],
|
||||
// This resolve the path mappings from the tsconfig relative to each jest.config.js
|
||||
moduleNameMapper: {
|
||||
'^@n8n/utils$': resolve(__dirname, 'packages/@n8n/utils/dist/index.cjs'),
|
||||
// jest-resolve@29 doesn't honor `./lib/*` subpath patterns in @anthropic-ai/sdk's exports map
|
||||
'^@anthropic-ai/sdk/lib/(.*)$': '@anthropic-ai/sdk/lib/$1.js',
|
||||
// Core uses vitest-mock-extended (ESM-only) for its own tests; route the
|
||||
// shim to a CJS-friendly variant for Jest-based consumers (nodes-base, cli).
|
||||
'^(\\./|\\.\\./nodes-testing/)mock-extended$': resolve(
|
||||
__dirname,
|
||||
'packages/core/nodes-testing/mock-extended.jest.cjs',
|
||||
),
|
||||
...(compilerOptions?.paths
|
||||
? pathsToModuleNameMapper(compilerOptions.paths, {
|
||||
prefix: `<rootDir>${compilerOptions.baseUrl ? `/${compilerOptions.baseUrl.replace(/^\.\//, '')}` : ''}`,
|
||||
})
|
||||
: {}),
|
||||
},
|
||||
// file-type@21's `exports` map exposes no `require`/string `default` entry,
|
||||
// only `import`/`module-sync`. Add `module-sync` so jest-resolve can pick its
|
||||
// entry point (additive to the node env defaults).
|
||||
testEnvironmentOptions: {
|
||||
customExportConditions: ['node', 'node-addons', 'module-sync'],
|
||||
},
|
||||
setupFilesAfterEnv: ['jest-expect-message'],
|
||||
restoreMocks: true,
|
||||
collectCoverage: isCoverageEnabled,
|
||||
coverageReporters: ['text-summary', 'lcov', 'html-spa'],
|
||||
workerIdleMemoryLimit: '1MB',
|
||||
};
|
||||
|
||||
if (process.env.CI === 'true') {
|
||||
config.collectCoverageFrom = ['src/**/*.ts', ...coverageExcludes];
|
||||
config.reporters = ['default', 'jest-junit'];
|
||||
config.coverageReporters = ['lcov'];
|
||||
}
|
||||
|
||||
module.exports = config;
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
// Shared `collectCoverageFrom` exclusions for all jest packages. `**`-anchored
|
||||
// so they apply regardless of the source roots a package collects from.
|
||||
// Mirrored by packages/@n8n/vitest-config/coverage-excludes.ts (vitest) and the
|
||||
// V8 path filter in packages/testing/playwright/coverage-options.ts — keep in sync.
|
||||
module.exports = [
|
||||
'!**/*.spec.ts',
|
||||
'!**/*.test.ts',
|
||||
'!**/__tests__/**',
|
||||
'!**/__mocks__/**',
|
||||
'!**/*.d.ts',
|
||||
];
|
||||
11
package.json
11
package.json
|
|
@ -45,7 +45,7 @@
|
|||
"setup-backend-module": "node scripts/ensure-zx.mjs && zx scripts/backend-module/setup.mjs",
|
||||
"start": "node scripts/os-normalize.mjs --dir packages/cli/bin n8n",
|
||||
"mutate": "node scripts/mutation-health/mutate.mjs",
|
||||
"test": "JEST_JUNIT_CLASSNAME={filepath} turbo run test",
|
||||
"test": "turbo run test",
|
||||
"test:ci": "turbo run test --continue --concurrency=1",
|
||||
"test:ci:frontend": "turbo run test --continue --filter='./packages/frontend/**'",
|
||||
"test:ci:frontend:changed": "turbo run test:changed --continue --filter='./packages/frontend/**'",
|
||||
|
|
@ -70,20 +70,12 @@
|
|||
"@biomejs/biome": "^1.9.0",
|
||||
"@dotenvx/dotenvx": "^1.40.0",
|
||||
"@n8n/eslint-config": "workspace:*",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/node": "*",
|
||||
"@types/supertest": "^6.0.3",
|
||||
"babel-jest": "catalog:",
|
||||
"babel-plugin-transform-import-meta": "^2.3.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "catalog:",
|
||||
"get-tsconfig": "catalog:",
|
||||
"jest": "^29.6.2",
|
||||
"jest-environment-jsdom": "^29.6.2",
|
||||
"jest-expect-message": "^1.1.3",
|
||||
"jest-junit": "^16.0.0",
|
||||
"jest-mock": "^29.6.2",
|
||||
"jest-mock-extended": "^3.0.4",
|
||||
"lefthook": "^1.7.15",
|
||||
"nock": "^14.0.14",
|
||||
"nodemon": "^3.0.1",
|
||||
|
|
@ -93,7 +85,6 @@
|
|||
"rimraf": "^5.0.1",
|
||||
"stylelint": "catalog:",
|
||||
"supertest": "^7.1.1",
|
||||
"ts-jest": "^29.4.9",
|
||||
"tsc-alias": "^1.8.10",
|
||||
"tsc-watch": "^6.2.0",
|
||||
"turbo": "2.9.15",
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ function rewriteSourceRequire(): Plugin {
|
|||
|
||||
export default mergeConfig(
|
||||
createVitestConfig({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and test files silently rely on
|
||||
// it — omit this and mocks bleed between tests.
|
||||
restoreMocks: true,
|
||||
// Integration tests run via vitest.integration.config.mjs (real providers, long timeouts).
|
||||
exclude: [...configDefaults.exclude, '**/__tests__/integration/**'],
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import { mergeConfig } from 'vite';
|
|||
|
||||
export default mergeConfig(
|
||||
createVitestConfig({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and most test files silently
|
||||
// rely on it — omit this and mocks bleed between tests.
|
||||
restoreMocks: true,
|
||||
}),
|
||||
{
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ export async function terminate() {
|
|||
}
|
||||
|
||||
// Clear all cached DI singletons (DbConnection, DataSource, GlobalConfig,
|
||||
// AuthRolesService, …). With persistent Jest workers (no per-file process
|
||||
// AuthRolesService, …). With persistent Vitest workers (no per-file process
|
||||
// recycling), the next test file's testDb.init() would otherwise reuse the
|
||||
// DbConnection instance whose DataSource we just destroyed — and try to
|
||||
// .initialize() it again, which hangs. Resetting forces the next get() to
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import { createVitestConfig } from '@n8n/vitest-config/node';
|
||||
|
||||
export default createVitestConfig({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and test files silently rely on
|
||||
// it — omit this and mocks bleed between tests.
|
||||
restoreMocks: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"extends": "@n8n/typescript-config/tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": ".",
|
||||
"types": ["node", "jest"]
|
||||
"types": ["node", "vitest/globals"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "test/**/*.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"extends": "@n8n/typescript-config/tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": ".",
|
||||
"types": ["node", "jest"]
|
||||
"types": ["node", "vitest/globals", "vite/client"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "test/**/*.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"extends": "@n8n/typescript-config/tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node", "jest"],
|
||||
"types": ["node"],
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -139,8 +139,6 @@ function tscDecoratorTransform(): Plugin {
|
|||
|
||||
export default mergeConfig(
|
||||
createVitestConfigWithDecorators({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and most test files silently
|
||||
// rely on it — omit this and mocks bleed between tests.
|
||||
restoreMocks: true,
|
||||
}),
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"extends": "@n8n/typescript-config/tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node", "jest"],
|
||||
"types": ["node"],
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ export const baseConfig = tseslint.config(
|
|||
'dist/**',
|
||||
'eslint.config.mjs',
|
||||
'tsup.config.ts',
|
||||
'jest.config.js',
|
||||
'vite.config.ts',
|
||||
'vitest.config.ts',
|
||||
]),
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ ruleTester.run('no-forbidden-lifecycle-scripts', NoForbiddenLifecycleScriptsRule
|
|||
{
|
||||
name: 'only safe scripts',
|
||||
filename: 'package.json',
|
||||
code: '{ "name": "n8n-nodes-example", "scripts": { "build": "tsc", "test": "jest", "dev": "nodemon" } }',
|
||||
code: '{ "name": "n8n-nodes-example", "scripts": { "build": "tsc", "test": "vitest", "dev": "nodemon" } }',
|
||||
},
|
||||
{
|
||||
name: 'non-package.json file is ignored',
|
||||
|
|
@ -82,7 +82,7 @@ ruleTester.run('no-forbidden-lifecycle-scripts', NoForbiddenLifecycleScriptsRule
|
|||
{
|
||||
name: 'mix of allowed and forbidden scripts — only forbidden reported',
|
||||
filename: 'package.json',
|
||||
code: '{ "name": "n8n-nodes-example", "scripts": { "build": "tsc", "prepare": "npm run build", "test": "jest" } }',
|
||||
code: '{ "name": "n8n-nodes-example", "scripts": { "build": "tsc", "prepare": "npm run build", "test": "vitest" } }',
|
||||
errors: [{ messageId: 'forbiddenScript', data: { scriptName: 'prepare' } }],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ The runtime **can only**:
|
|||
- Test observability emission
|
||||
- Test error handling
|
||||
|
||||
**Integration Tests** (jest in workflow package):
|
||||
**Integration Tests** (vitest in workflow package):
|
||||
- Test full stack with real isolated-vm
|
||||
- Test concurrent evaluations
|
||||
- Test with real workflow data
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
"build:unchecked": "pnpm run build",
|
||||
"create-json-schema": "tsx scripts/create-json-schema.ts",
|
||||
"preview": "vite preview",
|
||||
"test": "jest --passWithNoTests"
|
||||
"test": "node -e \"process.exit(0);\""
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "catalog:frontend",
|
||||
|
|
|
|||
|
|
@ -15,3 +15,14 @@ expect.extend({
|
|||
};
|
||||
},
|
||||
});
|
||||
|
||||
interface CustomMatchers<R = unknown> {
|
||||
toMatchZod(expected: z.ZodTypeAny): R;
|
||||
}
|
||||
|
||||
declare module 'vitest' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- must mirror Vitest's `Matchers<T = any>` default type param
|
||||
interface Matchers<T = any> extends CustomMatchers<T> {
|
||||
toMatchZod(expected: z.ZodTypeAny): T;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
namespace jest {
|
||||
interface Matchers<R, T> {
|
||||
toMatchZod(expected: unknown): T;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { createVitestConfig } from '@n8n/vitest-config/node';
|
||||
|
||||
export default createVitestConfig({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and the test files rely on it.
|
||||
restoreMocks: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
import { createVitestConfig } from '@n8n/vitest-config/node';
|
||||
|
||||
export default createVitestConfig({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and test files silently rely on
|
||||
// it — omit this and mocks bleed between tests.
|
||||
restoreMocks: true,
|
||||
testTimeout: 30_000,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { Container } from '@n8n/di';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import { mock } from 'vitest-mock-extended';
|
||||
import { StructuredToolkit } from 'n8n-core';
|
||||
import {
|
||||
NodeConnectionTypes,
|
||||
|
|
@ -245,7 +245,7 @@ describe('runtime', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
const callTool = jest
|
||||
const callTool = vi
|
||||
.spyOn(Client.prototype, 'callTool')
|
||||
.mockResolvedValue({ content: [{ type: 'text', text: 'ok' }] });
|
||||
vi.spyOn(Client.prototype, 'close').mockResolvedValue();
|
||||
|
|
@ -280,7 +280,7 @@ describe('runtime', () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
const callTool = jest
|
||||
const callTool = vi
|
||||
.spyOn(Client.prototype, 'callTool')
|
||||
.mockResolvedValue({ content: [{ type: 'text', text: 'ok' }] });
|
||||
vi.spyOn(Client.prototype, 'close').mockResolvedValue();
|
||||
|
|
|
|||
|
|
@ -563,7 +563,7 @@ describe('VectorStoreOracleDB.node', () => {
|
|||
throw new Error('releaseVectorStoreClient was not captured');
|
||||
}
|
||||
|
||||
const clientCloseSpy = jest
|
||||
const clientCloseSpy = vi
|
||||
.spyOn(lastInstance.client as { close: () => Promise<void> }, 'close')
|
||||
.mockResolvedValue(undefined);
|
||||
|
||||
|
|
|
|||
|
|
@ -364,7 +364,7 @@ describe('MicrosoftAgent365Trigger', () => {
|
|||
|
||||
try {
|
||||
await microsoftAgent365Trigger.webhook!.call(mockWebhookFunctions);
|
||||
fail('Should have thrown an error');
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (error) {
|
||||
expect(error).toBeInstanceOf(NodeOperationError);
|
||||
expect((error as NodeOperationError).description).toBe(
|
||||
|
|
@ -379,7 +379,7 @@ describe('MicrosoftAgent365Trigger', () => {
|
|||
|
||||
try {
|
||||
await microsoftAgent365Trigger.webhook!.call(mockWebhookFunctions);
|
||||
fail('Should have thrown an error');
|
||||
expect.fail('Should have thrown an error');
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(NodeOperationError);
|
||||
expect((err as NodeOperationError).message).toContain('Network error');
|
||||
|
|
|
|||
|
|
@ -6,11 +6,6 @@
|
|||
* DI mocks unless they need custom behaviour.
|
||||
*/
|
||||
|
||||
// jest-mock-extended (used by NodeTestHarness) requires `jest` as a global.
|
||||
// Vitest does not set this alias automatically.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).jest = vi;
|
||||
|
||||
vi.mock('@n8n/di', () => ({
|
||||
Container: {
|
||||
get: vi.fn().mockImplementation(() => ({
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ describe('embeddingInputValidation', () => {
|
|||
it('should include helpful error message', () => {
|
||||
try {
|
||||
validateEmbedQueryInput(undefined, mockNode);
|
||||
fail('Expected error to be thrown');
|
||||
expect.fail('Expected error to be thrown');
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(NodeOperationError);
|
||||
expect((e as NodeOperationError).message).toContain('empty or undefined text');
|
||||
|
|
@ -50,7 +50,7 @@ describe('embeddingInputValidation', () => {
|
|||
it('should include description with possible causes', () => {
|
||||
try {
|
||||
validateEmbedQueryInput(undefined, mockNode);
|
||||
fail('Expected error to be thrown');
|
||||
expect.fail('Expected error to be thrown');
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(NodeOperationError);
|
||||
const description = (e as NodeOperationError).description as string;
|
||||
|
|
@ -109,7 +109,7 @@ describe('embeddingInputValidation', () => {
|
|||
it('should include index of invalid document in error message', () => {
|
||||
try {
|
||||
validateEmbedDocumentsInput(['valid', 'also valid', undefined], mockNode);
|
||||
fail('Expected error to be thrown');
|
||||
expect.fail('Expected error to be thrown');
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(NodeOperationError);
|
||||
expect((e as NodeOperationError).message).toContain('index 2');
|
||||
|
|
@ -119,7 +119,7 @@ describe('embeddingInputValidation', () => {
|
|||
it('should include helpful description in error', () => {
|
||||
try {
|
||||
validateEmbedDocumentsInput(['valid', null], mockNode);
|
||||
fail('Expected error to be thrown');
|
||||
expect.fail('Expected error to be thrown');
|
||||
} catch (e) {
|
||||
expect(e).toBeInstanceOf(NodeOperationError);
|
||||
expect((e as NodeOperationError).description).toContain('non-empty strings');
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ export class JsTaskRunner extends TaskRunner {
|
|||
Buffer.allocUnsafe = safeAlloc as typeof Buffer.allocUnsafe;
|
||||
Buffer.allocUnsafeSlow = safeAlloc as typeof Buffer.allocUnsafeSlow;
|
||||
|
||||
// Freeze globals, except in tests because Jest needs to be able to mutate prototypes
|
||||
// Freeze globals, except in tests because Vitest needs to be able to mutate prototypes
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
Object.getOwnPropertyNames(globalThis)
|
||||
.map((name) => Reflect.get(globalThis, name) as unknown)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ import { mergeConfig } from 'vite';
|
|||
|
||||
export default mergeConfig(
|
||||
createVitestConfigWithDecorators({
|
||||
// The n8n root jest.config sets `restoreMocks: true`, and test files silently rely on
|
||||
// it — omit this and mocks bleed between tests.
|
||||
restoreMocks: true,
|
||||
testTimeout: 10_000,
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"extends": "./tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node", "jest"]
|
||||
"types": ["node", "vitest/globals"]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,5 @@
|
|||
"sourceMap": true,
|
||||
"skipLibCheck": true,
|
||||
"tsBuildInfoFile": "${configDir}/dist/typecheck.tsbuildinfo"
|
||||
},
|
||||
"files": ["../../../node_modules/jest-expect-message/types/index.d.ts"]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import type { SDKFunctions } from './interpreter';
|
|||
import { interpretSDKCode } from './interpreter';
|
||||
import { parseSDKCode } from './parser';
|
||||
|
||||
/** Helper to get the first call argument from a Jest mock with proper typing */
|
||||
/** Helper to get the first call argument from a Vitest mock with proper typing */
|
||||
function getFirstCallArg<T>(mockFn: Mock): T {
|
||||
const calls = mockFn.mock.calls as unknown[][];
|
||||
return calls[0][0] as T;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@
|
|||
"ts-essentials": "^7.0.3",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
"vitest-mock-extended": "catalog:"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -177,8 +177,6 @@ describe('WorkflowExecuteAdditionalData', () => {
|
|||
},
|
||||
nodes: [],
|
||||
connections: {},
|
||||
// Real object: a mock-generated fn breaks Workflow's observable wrapping
|
||||
// (vitest's vi.fn().mock is enumerable; Jest's was not).
|
||||
staticData: {},
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ describe('enqueueExecution', () => {
|
|||
const error = new Error('stop for test purposes');
|
||||
|
||||
// mock a rejection to stop execution flow before we create the PCancelable promise,
|
||||
// so that Jest does not move on to tear down the suite until the PCancelable settles
|
||||
// so that Vitest does not move on to tear down the suite until the PCancelable settles
|
||||
addJob.mockRejectedValueOnce(error);
|
||||
|
||||
// @ts-expect-error Private method
|
||||
|
|
@ -393,7 +393,7 @@ describe('enqueueExecution', () => {
|
|||
const error = new Error('stop for test purposes');
|
||||
|
||||
// mock a rejection to stop execution flow before we create the PCancelable promise,
|
||||
// so that Jest does not move on to tear down the suite until the PCancelable settles
|
||||
// so that Vitest does not move on to tear down the suite until the PCancelable settles
|
||||
addJob.mockRejectedValueOnce(error);
|
||||
|
||||
const restartExecutionId = 'restart-execution-id';
|
||||
|
|
|
|||
|
|
@ -815,9 +815,9 @@ describe('WorkflowBuilderService - node type loading', () => {
|
|||
let packageDir: string;
|
||||
|
||||
// LazyPackageDirectoryLoader lives in the externalized `n8n-core` dist and reads
|
||||
// from disk through its own `fs` binding, which Vitest module mocks can't reach
|
||||
// (unlike Jest's global module registry). So write a real fixture package and let
|
||||
// the loader exercise the full path against the real filesystem.
|
||||
// from disk through its own `fs` binding, which Vitest module mocks can't reach.
|
||||
// So write a real fixture package and let the loader
|
||||
// exercise the full path against the real filesystem.
|
||||
beforeAll(() => {
|
||||
tmpRoot = mkdtempSync(join(tmpdir(), 'n8n-ai-builder-nodes-'));
|
||||
packageDir = join(tmpRoot, 'nodes-base');
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ vi.mock('@n8n/backend-common', async (importOriginal) => ({
|
|||
safeJoinPath: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock @n8n/db
|
||||
// Spread the real module so transitively-imported exports resolve (Vitest throws
|
||||
// on undeclared mock exports, unlike Jest), overriding only the repos under test.
|
||||
vi.mock('@n8n/db', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import('@n8n/db')>()),
|
||||
CredentialsRepository: mock<CredentialsRepository>(),
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ describe('TaskBroker', () => {
|
|||
taskType: 'taskType1',
|
||||
};
|
||||
|
||||
vi.spyOn(taskBroker, 'acceptOffer').mockResolvedValue(); // allow Jest to exit cleanly
|
||||
vi.spyOn(taskBroker, 'acceptOffer').mockResolvedValue();
|
||||
|
||||
taskBroker.taskRequested(request);
|
||||
|
||||
|
|
|
|||
|
|
@ -150,30 +150,30 @@ describe('Telemetry', () => {
|
|||
|
||||
payload.is_manual = true;
|
||||
payload.success = true;
|
||||
const execTime1 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime1 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
payload.is_manual = false;
|
||||
payload.success = true;
|
||||
const execTime2 = fakeJestSystemTime('2022-01-01 13:00:00');
|
||||
const execTime2 = fakeTestSystemTime('2022-01-01 13:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
payload.is_manual = true;
|
||||
payload.success = false;
|
||||
const execTime3 = fakeJestSystemTime('2022-01-01 14:00:00');
|
||||
const execTime3 = fakeTestSystemTime('2022-01-01 14:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
payload.is_manual = false;
|
||||
payload.success = false;
|
||||
const execTime4 = fakeJestSystemTime('2022-01-01 15:00:00');
|
||||
const execTime4 = fakeTestSystemTime('2022-01-01 15:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
expect(spyTrack).toHaveBeenCalledTimes(0);
|
||||
|
|
@ -199,19 +199,19 @@ describe('Telemetry', () => {
|
|||
execution_source: 'user',
|
||||
};
|
||||
|
||||
const userManualExecTime = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const userManualExecTime = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
payload.execution_source = 'instance_ai';
|
||||
payload.mock_data_sources = 'trigger_input';
|
||||
|
||||
const instanceAiMockManualExecTime = fakeJestSystemTime('2022-01-01 13:00:00');
|
||||
const instanceAiMockManualExecTime = fakeTestSystemTime('2022-01-01 13:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
payload.is_manual = false;
|
||||
delete payload.mock_data_sources;
|
||||
|
||||
const instanceAiRealProdExecTime = fakeJestSystemTime('2022-01-01 14:00:00');
|
||||
const instanceAiRealProdExecTime = fakeTestSystemTime('2022-01-01 14:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
const execBuffer = telemetry.getCountsBuffer();
|
||||
|
|
@ -240,9 +240,9 @@ describe('Telemetry', () => {
|
|||
error_node_type: 'custom-nodes-base.node-type',
|
||||
};
|
||||
|
||||
const execTime1 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime1 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
let execBuffer = telemetry.getCountsBuffer();
|
||||
|
|
@ -253,9 +253,9 @@ describe('Telemetry', () => {
|
|||
expect(execBuffer['1'].manual_error?.first).toEqual(execTime1);
|
||||
|
||||
payload.error_node_type = 'n8n-nodes-base.node-type';
|
||||
fakeJestSystemTime('2022-01-01 13:00:00');
|
||||
fakeTestSystemTime('2022-01-01 13:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
execBuffer = telemetry.getCountsBuffer();
|
||||
|
|
@ -276,7 +276,7 @@ describe('Telemetry', () => {
|
|||
};
|
||||
|
||||
// successful execution
|
||||
const execTime1 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime1 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
expect(spyTrack).toHaveBeenCalledTimes(0);
|
||||
|
|
@ -336,7 +336,7 @@ describe('Telemetry', () => {
|
|||
expect(execBuffer['2'].prod_success?.first).toEqual(execTime1);
|
||||
|
||||
// failed execution
|
||||
const execTime2 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime2 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
payload.error_node_type = 'custom-package.custom-node';
|
||||
payload.success = false;
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
|
@ -393,16 +393,16 @@ describe('Telemetry', () => {
|
|||
};
|
||||
|
||||
// Manual crashed execution
|
||||
const execTime1 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime1 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 12:30:00');
|
||||
fakeTestSystemTime('2022-01-01 12:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
// Production crashed execution
|
||||
payload.is_manual = false;
|
||||
const execTime2 = fakeJestSystemTime('2022-01-01 13:00:00');
|
||||
const execTime2 = fakeTestSystemTime('2022-01-01 13:00:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
fakeJestSystemTime('2022-01-01 13:30:00');
|
||||
fakeTestSystemTime('2022-01-01 13:30:00');
|
||||
telemetry.trackWorkflowExecution(payload);
|
||||
|
||||
// Should fire "Workflow execution errored" events for manual crashed executions with n8n-nodes-base
|
||||
|
|
@ -439,10 +439,10 @@ describe('Telemetry', () => {
|
|||
error_node_type: 'n8n-nodes-base.another-node',
|
||||
};
|
||||
|
||||
const execTime1 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime1 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
telemetry.trackWorkflowExecution(payload1);
|
||||
|
||||
const execTime2 = fakeJestSystemTime('2022-01-01 13:00:00');
|
||||
const execTime2 = fakeTestSystemTime('2022-01-01 13:00:00');
|
||||
telemetry.trackWorkflowExecution(payload2);
|
||||
|
||||
// Should fire one "Workflow execution errored" event for manual crashed execution with n8n-nodes-base
|
||||
|
|
@ -833,7 +833,7 @@ describe('Telemetry', () => {
|
|||
});
|
||||
|
||||
test('should count calls per user and endpoint', () => {
|
||||
const execTime1 = fakeJestSystemTime('2022-01-01 12:00:00');
|
||||
const execTime1 = fakeTestSystemTime('2022-01-01 12:00:00');
|
||||
|
||||
telemetry.trackApiInvocation({
|
||||
user_id: 'user1',
|
||||
|
|
@ -1059,7 +1059,7 @@ describe('Telemetry', () => {
|
|||
});
|
||||
});
|
||||
|
||||
const fakeJestSystemTime = (dateTime: string | Date): Date => {
|
||||
const fakeTestSystemTime = (dateTime: string | Date): Date => {
|
||||
const dt = new Date(dateTime);
|
||||
vi.setSystemTime(dt);
|
||||
return dt;
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ import { Container } from '@n8n/di';
|
|||
import { DataSource as Connection } from '@n8n/typeorm';
|
||||
import nock from 'nock';
|
||||
|
||||
/**
|
||||
* Vitest global setup. Runs once in the main process before any test file.
|
||||
* Mirrors the former Jest `globalSetup`/`globalTeardown` pair.
|
||||
*/
|
||||
export async function setup() {
|
||||
nock.disableNetConnect();
|
||||
nock.enableNetConnect('127.0.0.1');
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ function expectCredentialsMatch(
|
|||
const oldSorted = [...oldCredentials].sort((a, b) => a.id.localeCompare(b.id));
|
||||
const newSorted = [...newCredentials].sort((a, b) => a.id.localeCompare(b.id));
|
||||
|
||||
// Jest's toEqual does deep recursive comparison of all fields
|
||||
expect(newSorted).toEqual(oldSorted);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ export const setupTestServer = ({
|
|||
// DI container after testDb.terminate() resets it. Await the close so
|
||||
// pending handlers drain before the next file's beforeAll runs in
|
||||
// persistent Jest workers — otherwise stale handlers call
|
||||
// Container.get(Logger), construct a fresh Logger, and trip Jest's
|
||||
// Container.get(Logger), construct a fresh Logger, and trip Vitest's
|
||||
// "environment torn down" guard when winston is imported.
|
||||
// Skip when the server never started listening (some suites bail in
|
||||
// beforeAll); calling close() on a non-listening server throws
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es2023", "dom"],
|
||||
"types": ["node", "vitest/globals"],
|
||||
"types": ["node", "vitest/globals", "vite/client"],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@test/*": ["./test/shared/*"],
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ import { tscEntityTransform } from './vitest.tsc-entity-transform';
|
|||
import { workspaceDistExternals } from './vitest.workspace-externals';
|
||||
|
||||
/**
|
||||
* Path aliases mirroring the `paths` entries in `tsconfig.json`, plus the
|
||||
* `@n8n/mcp-apps/server` -> source mapping the former jest config used so tests
|
||||
* can resolve the specifier without the package's `dist/` being built first.
|
||||
*
|
||||
* Note on alias order/specificity: Vite matches a string alias only when the
|
||||
* import equals it or starts with `alias + '/'`, so `@` matches `@/...` but not
|
||||
* `@n8n/...` or `@test/...`. The entries are therefore non-overlapping.
|
||||
|
|
@ -19,9 +15,6 @@ const alias = {
|
|||
'@test-integration': path.resolve(__dirname, 'test/integration/shared'),
|
||||
'@test': path.resolve(__dirname, 'test/shared'),
|
||||
'@n8n/mcp-apps/server': path.resolve(__dirname, '../@n8n/mcp-apps/src/server/index.ts'),
|
||||
// Force the test-utils package to load from source: its `dist/` is the stale
|
||||
// jest build (still imports `jest-mock-extended`), and we want the migrated
|
||||
// `vitest-mock-extended` source. `workspaceDistExternals` already excludes it.
|
||||
'@n8n/backend-test-utils': path.resolve(__dirname, '../@n8n/backend-test-utils/src/index.ts'),
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
};
|
||||
|
|
@ -33,8 +26,6 @@ const alias = {
|
|||
*/
|
||||
export const baseConfig = mergeConfig(
|
||||
createVitestConfigWithDecorators({
|
||||
// The former root jest.config set `restoreMocks: true`, and a large share of
|
||||
// test files silently rely on mocks being restored before each test. Keep it.
|
||||
restoreMocks: true,
|
||||
}),
|
||||
{
|
||||
|
|
@ -44,8 +35,8 @@ export const baseConfig = mergeConfig(
|
|||
plugins: [workspaceDistExternals(), tscEntityTransform()],
|
||||
resolve: { alias },
|
||||
test: {
|
||||
// Run each test file in its own forked process, matching Jest's
|
||||
// process-per-file model. This is load-bearing: cli tests register service
|
||||
// Run each test file in its own forked process.
|
||||
// This is load-bearing: cli tests register service
|
||||
// mocks into the `@n8n/di` Container (`mockInstance`), and a shared worker
|
||||
// would leak that state across files.
|
||||
pool: 'forks',
|
||||
|
|
|
|||
|
|
@ -1,16 +1,6 @@
|
|||
import { mergeConfig } from 'vite';
|
||||
|
||||
import { baseConfig } from './vitest.config.base';
|
||||
|
||||
/**
|
||||
* Integration tests against a postgres container started via testcontainers,
|
||||
* mirroring `jest.config.integration.testcontainers.js`. Migration tests are
|
||||
* excluded here (they have a dedicated testcontainers config), matching the
|
||||
* former `test:postgres:integration:tc` which ignored `/test/migration/`.
|
||||
*
|
||||
* The testcontainers global setup *replaces* the default nock global setup
|
||||
* (matching the old jest config, which overrode `globalSetup`/`globalTeardown`).
|
||||
*/
|
||||
const integrationTcConfig = mergeConfig(baseConfig, {
|
||||
test: {
|
||||
include: ['test/integration/**/*.test.ts', 'src/**/*.integration.test.ts'],
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@ import { mergeConfig } from 'vite';
|
|||
|
||||
import { baseConfig } from './vitest.config.base';
|
||||
|
||||
/**
|
||||
* Integration test suite, mirroring the former `jest.config.integration.js`:
|
||||
* the integration/migration directories plus `*.integration.test.ts` in `src`.
|
||||
*/
|
||||
export default mergeConfig(baseConfig, {
|
||||
test: {
|
||||
include: ['test/integration/**/*.test.ts', 'src/**/*.integration.test.ts'],
|
||||
|
|
|
|||
|
|
@ -2,12 +2,6 @@ import { mergeConfig } from 'vite';
|
|||
|
||||
import { baseConfig } from './vitest.config.base';
|
||||
|
||||
/**
|
||||
* Migration tests against a postgres container started via testcontainers,
|
||||
* mirroring `jest.config.migration.testcontainers.js`. Runs sequentially in a
|
||||
* single process; the testcontainers global setup replaces the nock global
|
||||
* setup (matching the old jest config).
|
||||
*/
|
||||
const migrationTcConfig = mergeConfig(baseConfig, {
|
||||
test: {
|
||||
include: ['test/migration/**/*.test.ts'],
|
||||
|
|
|
|||
|
|
@ -3,15 +3,14 @@ import { mergeConfig } from 'vite';
|
|||
import { baseConfig } from './vitest.config.base';
|
||||
|
||||
/**
|
||||
* Migration test suite, mirroring the former `jest.config.migration.js`.
|
||||
* Migration tests share a database and perform rollbacks, so they must run
|
||||
* sequentially in a single process (the equivalent of Jest's `maxWorkers: 1`).
|
||||
* sequentially in a single process.
|
||||
*/
|
||||
export default mergeConfig(baseConfig, {
|
||||
test: {
|
||||
include: ['test/migration/**/*.test.ts'],
|
||||
// Migration suites do heavy DB work; some files previously set a 20s timeout
|
||||
// via `jest.setTimeout`. Apply it suite-wide for both tests and hooks.
|
||||
// Migration suites do heavy DB work; some files previously set a 20s timeout.
|
||||
// Apply it suite-wide for both tests and hooks.
|
||||
testTimeout: 20_000,
|
||||
hookTimeout: 20_000,
|
||||
fileParallelism: false,
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
module.exports = require('jest-mock-extended');
|
||||
|
|
@ -46,7 +46,6 @@
|
|||
"@n8n/vitest-config": "workspace:*",
|
||||
"@vitest/coverage-v8": "catalog:",
|
||||
"axios": "catalog:",
|
||||
"jest-mock-extended": "^3.0.4",
|
||||
"nock": "catalog:",
|
||||
"reflect-metadata": "catalog:",
|
||||
"vitest": "catalog:",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ storybook-static
|
|||
.storybook
|
||||
|
||||
.browserslistrc
|
||||
jest.config.js
|
||||
vite.config.ts
|
||||
|
||||
*.md
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
!dist
|
||||
|
||||
.browserslistrc
|
||||
jest.config.js
|
||||
postcss.config.js
|
||||
vue.config.js
|
||||
dist/report.html
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
"dist/**",
|
||||
"eslint.config.mjs",
|
||||
"tsup.config.ts",
|
||||
"jest.config.js",
|
||||
"vitest.config.ts",
|
||||
"**/*.test.ts"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
"lint:fix": "eslint src --fix",
|
||||
"prepack": "echo \"Building project...\" && rm -rf dist && tsc -b",
|
||||
"watch": "tsc --watch",
|
||||
"test": "jest --passWithNoTests"
|
||||
"test": "node -e \"process.exit(0)\""
|
||||
},
|
||||
"bin": {
|
||||
"n8n-node-dev": "./bin/n8n-node-dev"
|
||||
|
|
@ -41,7 +41,9 @@
|
|||
],
|
||||
"devDependencies": {
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@types/inquirer": "^7.0.1"
|
||||
"@types/inquirer": "^7.0.1",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@n8n/di": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
* --unit-shards: directory of downloaded unit + integration + frontend lcov
|
||||
* artifacts, nested per-artifact as `<artifact>/<pkg>/coverage/lcov.info`.
|
||||
* Jest and vitest write package-RELATIVE SF paths (`src/foo.ts`); we qualify
|
||||
* Vitest writes package-RELATIVE SF paths (`src/foo.ts`); we qualify
|
||||
* them to repo-root-relative `packages/<pkg>/src/...` (pkg derived from the
|
||||
* artifact dir) so they MERGE with the already-qualified E2E lcovs instead of
|
||||
* colliding under bare `src/...` keys (every package has a `src/index.ts`).
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
/** @type {import('jest').Config} */
|
||||
module.exports = {
|
||||
...require('../../jest.config'),
|
||||
};
|
||||
|
|
@ -2253,12 +2253,6 @@ type EngineAction<T = unknown> = ExecuteNodeAction<T>;
|
|||
* containing the results of all requested actions.
|
||||
*
|
||||
* @template T - The type of metadata associated with this request
|
||||
*
|
||||
* @todo This should use `unknown`, but jest-mock-extended will turn this into
|
||||
* `Partial<unknown>` which `unknown` cannot be assigned to, which leads to a
|
||||
* lot of type errors in our tests.
|
||||
* The correct fix is to make a PR to jest-mock-extended and make it handle
|
||||
* `unknown` special, turning it into `unknown` instead of `Partial<unknown>`.
|
||||
*/
|
||||
export type EngineRequest<T = object> = {
|
||||
/** Array of actions that the requesting node wants the engine to fulfill */
|
||||
|
|
|
|||
1565
pnpm-lock.yaml
1565
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -110,7 +110,6 @@ catalog:
|
|||
agent-browser: 0.26.0
|
||||
ai: ^6.0.197
|
||||
axios: 1.18.0
|
||||
babel-jest: ^29.7.0
|
||||
basic-auth: 2.0.1
|
||||
cache-manager: 5.2.3
|
||||
callsites: 3.1.0
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
},
|
||||
{
|
||||
"description": "Group testing packages",
|
||||
"matchPackageNames": ["*vitest*", "*playwright*", "@testing-library/**", "*jest*"],
|
||||
"matchPackageNames": ["*vitest*", "*playwright*", "@testing-library/**"],
|
||||
"groupName": "testing packages"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ Then, **once**, trigger the nightly with `workflow_dispatch` and set `bootstrap_
|
|||
|
||||
For a **genuine cold-start** (first run after the ledger is provisioned, the read-all returns `[]`), trigger with `bootstrap_packages: '*'` instead — it acknowledges the empty ledger and skips the per-package divergence check for every entry.
|
||||
|
||||
Not yet covered: **jest** packages (need Stryker's jest-runner — different setup) and `@n8n/expression-runtime` (it _is_ the isolated-vm engine; blocked on the patch in DEVP-257).
|
||||
Not yet covered: `@n8n/expression-runtime` (it _is_ the isolated-vm engine; blocked on the patch in DEVP-257).
|
||||
|
||||
## State transitions
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user