chore: Migrate @n8n/json-schema-to-zod from Jest to Vitest (#28411)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matsu 2026-04-20 16:07:50 +03:00 committed by GitHub
parent 9dd3e59acb
commit 9f71e12e5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 137 additions and 103 deletions

View file

@ -1,5 +0,0 @@
/** @type {import('jest').Config} */
module.exports = {
...require('../../../jest.config'),
setupFilesAfterEnv: ['<rootDir>/test/extend-expect.ts'],
};

View file

@ -28,9 +28,9 @@
"build:esm": "tsc -p tsconfig.esm.json && node postesm.cjs",
"build": "rimraf ./dist && pnpm run build:types && pnpm run build:cjs && pnpm run build:esm",
"dry": "pnpm run build && pnpm pub --dry-run",
"test": "jest",
"test:unit": "jest",
"test:watch": "jest --watch"
"test": "vitest run",
"test:unit": "vitest run",
"test:dev": "vitest --silent=false"
},
"keywords": [
"zod",
@ -65,6 +65,10 @@
"devDependencies": {
"@n8n/typescript-config": "workspace:*",
"@types/json-schema": "^7.0.15",
"zod": "catalog:"
"zod": "catalog:",
"@n8n/vitest-config": "workspace:*",
"@vitest/coverage-v8": "catalog:",
"vitest": "catalog:",
"vitest-mock-extended": "catalog:"
}
}

View file

@ -1,7 +1,8 @@
import { expect, type MatcherState } from 'vitest';
import type { z } from 'zod';
expect.extend({
toMatchZod(this: jest.MatcherContext, actual: z.ZodTypeAny, expected: z.ZodTypeAny) {
toMatchZod(this: MatcherState, actual: z.ZodTypeAny, expected: z.ZodTypeAny) {
const actualSerialized = JSON.stringify(actual._def, null, 2);
const expectedSerialized = JSON.stringify(expected._def, null, 2);
const pass = this.equals(actualSerialized, expectedSerialized);

View file

@ -1,6 +1,6 @@
/* eslint-disable n8n-local-rules/no-skipped-tests */
import type { JSONSchema7 } from 'json-schema';
import { z, ZodError } from 'zod';
import { z } from 'zod';
import { parseObject } from '../../src/parsers/parse-object';
@ -432,24 +432,26 @@ describe('parseObject', () => {
},
});
expect(run(result, { b: 'hello', x: true })).toEqual({
expect(run(result, { b: 'hello', x: true })).toMatchObject({
success: false,
error: new ZodError([
{
code: 'invalid_type',
expected: 'string',
received: 'undefined',
path: ['a'],
message: 'Required',
},
{
code: 'invalid_type',
expected: 'number',
received: 'string',
path: ['b'],
message: 'Expected number, received string',
},
]),
error: expect.objectContaining({
issues: [
{
code: 'invalid_type',
expected: 'string',
received: 'undefined',
path: ['a'],
message: 'Required',
},
{
code: 'invalid_type',
expected: 'number',
received: 'string',
path: ['b'],
message: 'Expected number, received string',
},
],
}),
});
});
@ -474,31 +476,33 @@ describe('parseObject', () => {
expect(result).toMatchZod(expected);
expect(run(result, { b: 'hello', x: 'true' })).toEqual({
expect(run(result, { b: 'hello', x: 'true' })).toMatchObject({
success: false,
error: new ZodError([
{
code: 'invalid_type',
expected: 'string',
received: 'undefined',
path: ['a'],
message: 'Required',
},
{
code: 'invalid_type',
expected: 'number',
received: 'string',
path: ['b'],
message: 'Expected number, received string',
},
{
code: 'invalid_type',
expected: 'boolean',
received: 'string',
path: ['x'],
message: 'Expected boolean, received string',
},
]),
error: expect.objectContaining({
issues: [
{
code: 'invalid_type',
expected: 'string',
received: 'undefined',
path: ['a'],
message: 'Required',
},
{
code: 'invalid_type',
expected: 'number',
received: 'string',
path: ['b'],
message: 'Expected number, received string',
},
{
code: 'invalid_type',
expected: 'boolean',
received: 'string',
path: ['x'],
message: 'Expected boolean, received string',
},
],
}),
});
});
@ -549,17 +553,19 @@ describe('parseObject', () => {
data: { a: 'a', b: 2, '.': [] },
});
expect(run(result, { a: 'a', b: 2, '.': '[]' })).toEqual({
expect(run(result, { a: 'a', b: 2, '.': '[]' })).toMatchObject({
success: false,
error: new ZodError([
{
code: 'invalid_type',
expected: 'array',
received: 'string',
path: ['.'],
message: 'Expected array, received string',
},
]),
error: expect.objectContaining({
issues: [
{
code: 'invalid_type',
expected: 'array',
received: 'string',
path: ['.'],
message: 'Expected array, received string',
},
],
}),
});
});
@ -713,28 +719,30 @@ describe('parseObject', () => {
expect(result).toMatchZod(expected);
expect(run(result, { x: true, '.': [], ',': [] })).toEqual({
expect(run(result, { x: true, '.': [], ',': [] })).toMatchObject({
success: false,
error: new ZodError([
{
path: [','],
code: 'custom',
message: 'Invalid input: Key matching regex /,/ must match schema',
params: {
issues: [
{
code: 'too_small',
minimum: 1,
type: 'array',
inclusive: true,
exact: false,
message: 'Array must contain at least 1 element(s)',
path: [],
},
],
error: expect.objectContaining({
issues: [
{
path: [','],
code: 'custom',
message: 'Invalid input: Key matching regex /,/ must match schema',
params: {
issues: [
{
code: 'too_small',
minimum: 1,
type: 'array',
inclusive: true,
exact: false,
message: 'Array must contain at least 1 element(s)',
path: [],
},
],
},
},
},
]),
],
}),
});
});
@ -818,28 +826,30 @@ describe('parseObject', () => {
data: { '.': [] },
});
expect(run(result, { ',': [] })).toEqual({
expect(run(result, { ',': [] })).toMatchObject({
success: false,
error: new ZodError([
{
path: [','],
code: 'custom',
message: 'Invalid input: Key matching regex /,/ must match schema',
params: {
issues: [
{
code: 'too_small',
minimum: 1,
type: 'array',
inclusive: true,
exact: false,
message: 'Array must contain at least 1 element(s)',
path: [],
},
],
error: expect.objectContaining({
issues: [
{
path: [','],
code: 'custom',
message: 'Invalid input: Key matching regex /,/ must match schema',
params: {
issues: [
{
code: 'too_small',
minimum: 1,
type: 'array',
inclusive: true,
exact: false,
message: 'Array must contain at least 1 element(s)',
path: [],
},
],
},
},
},
]),
],
}),
});
expect(result).toMatchZod(expected);

View file

@ -6,7 +6,8 @@
"strict": true,
"noEmit": true,
"skipLibCheck": true,
"esModuleInterop": true
"esModuleInterop": true,
"types": ["vitest/globals"]
},
"include": ["src/**/*.ts", "test/**/*.ts"]
}

View file

@ -0,0 +1,11 @@
import { defineConfig, mergeConfig } from 'vitest/config';
import { vitestConfig } from '@n8n/vitest-config/node';
export default mergeConfig(
defineConfig({
test: {
setupFiles: ['./test/extend-expect.ts'],
},
}),
vitestConfig,
);

View file

@ -1675,9 +1675,21 @@ importers:
'@n8n/typescript-config':
specifier: workspace:*
version: link:../typescript-config
'@n8n/vitest-config':
specifier: workspace:*
version: link:../vitest-config
'@types/json-schema':
specifier: ^7.0.15
version: 7.0.15
'@vitest/coverage-v8':
specifier: 'catalog:'
version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
vitest:
specifier: 'catalog:'
version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(@vitest/browser-playwright@4.0.16)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3))
vitest-mock-extended:
specifier: 'catalog:'
version: 3.1.0(typescript@6.0.2)(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@20.19.21)(jsdom@23.0.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(vite@8.0.2(@types/node@20.19.21)(esbuild@0.25.10)(jiti@2.6.1)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.16.1)(tsx@4.19.3)(yaml@2.8.3)))
zod:
specifier: 3.25.67
version: 3.25.67