test: migrate jest->vitest

This commit is contained in:
2026-01-26 11:30:01 +02:00
parent bd53564d3e
commit c597738d64
7 changed files with 832 additions and 2776 deletions

View File

@@ -1,187 +0,0 @@
/*
* For a detailed explanation regarding each configuration property and type check, visit:
* https://jestjs.io/docs/configuration
*/
export default {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/private/var/folders/q9/0mns8fgd00b4t5j5lq2wh2yh0000gn/T/jest_dx",
// Automatically clear mock calls and instances between every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// Indicates which provider should be used to instrument code for coverage
coverageProvider: 'v8',
// A list of reporter names that Jest uses when writing coverage reports
coverageReporters: ['json-summary', 'json', 'text', 'lcov', 'clover'],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "jsx",
// "ts",
// "tsx",
// "json",
// "node"
// ],
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
preset: 'ts-jest',
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state between every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state between every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// The number of seconds after which a test is considered as slow and reported as such in the results.
// slowTestThreshold: 5,
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
// testEnvironment: "jest-environment-node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
testPathIgnorePatterns: ['/node_modules/', '/_old/'],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jest-circus/runner",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/",
// "\\.pnp\\.[^\\/]+$"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
verbose: true,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
}

View File

@@ -18,20 +18,18 @@
"build": "tsc -p tsconfig.build.json && cp package.json README.md build",
"dev": "tsc --watch",
"cmd": "ts-node src/sample.ts",
"test": "jest",
"test": "vitest run",
"docs:build": "cd docs && pnpm build",
"docs:watch": "cd docs && pnpm start",
"docs:deploy": "pnpm docs:build && gh-pages -d docs"
},
"devDependencies": {
"@types/jest": "^30.0.0",
"@types/node": "^25.0.10",
"gh-pages": "^6.3.0",
"jest": "^30.2.0",
"prettier": "^3.8.1",
"ts-jest": "^29.4.6",
"ts-node": "^10.9.2",
"typescript": "^5.9.3"
"typescript": "^5.9.3",
"vitest": "^3.0.0"
},
"dependencies": {
"zod": "^4.3.6"

3328
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
import { vi } from 'vitest'
import { MassargCommand } from '../src/command'
import { massarg } from '../src/index'
@@ -13,26 +14,26 @@ describe('sub command', () => {
test('add', () => {
const command = massarg(opts)
expect(command.command).toBeInstanceOf(Function)
expect(command.command({ name: 'test2', description: 'test2', run: jest.fn() })).toBeInstanceOf(
expect(command.command({ name: 'test2', description: 'test2', run: vi.fn() })).toBeInstanceOf(
MassargCommand,
)
})
test('add duplicate', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts)
.command({ name: 'test2', description: 'test2', run: jest.fn() })
.command({ name: 'test2', description: 'test2', run: jest.fn() }),
.command({ name: 'test2', description: 'test2', run: vi.fn() })
.command({ name: 'test2', description: 'test2', run: vi.fn() }),
).toThrow('Command "test2" already exists')
error.mockRestore()
})
test('validate', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts).command({
name: 'test2',
description: 123 as any,
run: jest.fn(),
run: vi.fn(),
}),
).toThrow('Invalid input: expected string, received number')
error.mockRestore()
@@ -56,7 +57,7 @@ describe('getArgs', () => {
test('stops after command', () => {
expect(
massarg(opts)
.command({ name: 'test', description: 'test', run: jest.fn() })
.command({ name: 'test', description: 'test', run: vi.fn() })
.getArgs(['test', '--test', 'test']),
).toEqual({ extra: ['--test', 'test'] })
})
@@ -130,7 +131,7 @@ describe('getArgs', () => {
.command({
name: 'test3',
description: 'test3',
run: jest.fn(),
run: vi.fn(),
})
.option({
name: 'test',
@@ -147,7 +148,7 @@ describe('getArgs', () => {
.command({
name: 'test3',
description: 'test3',
run: jest.fn(),
run: vi.fn(),
})
.option({
name: 'test',
@@ -161,7 +162,7 @@ describe('getArgs', () => {
describe('parse', () => {
test('runs command', () => {
const fn = jest.fn()
const fn = vi.fn()
const command = massarg(opts).command({
name: 'test',
description: 'test',
@@ -172,7 +173,7 @@ describe('parse', () => {
expect(fn).toHaveBeenCalled()
})
test('runs main', () => {
const fn = jest.fn()
const fn = vi.fn()
const command = massarg(opts)
.main(fn)
.flag({ name: 'test', description: 'test', aliases: [] })
@@ -183,7 +184,7 @@ describe('parse', () => {
expect(fn).toHaveBeenCalledWith({}, command)
})
test('runs main with args', () => {
const fn = jest.fn()
const fn = vi.fn()
const command = massarg(opts)
.option({ name: 'test', description: 'test', aliases: [] })
.main(fn)
@@ -204,7 +205,7 @@ describe('parse', () => {
describe('main', () => {
test('add', () => {
const fn = jest.fn()
const fn = vi.fn()
const command = massarg(opts)
expect(command.main).toBeInstanceOf(Function)
expect(command.main(fn)).toBeInstanceOf(MassargCommand)
@@ -212,12 +213,12 @@ describe('main', () => {
})
describe('onError', () => {
let mockExit: jest.SpyInstance
let mockConsoleError: jest.SpyInstance
let mockExit: ReturnType<typeof vi.spyOn>
let mockConsoleError: ReturnType<typeof vi.spyOn>
beforeEach(() => {
mockExit = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never)
mockConsoleError = jest.spyOn(console, 'error').mockImplementation(() => {})
mockExit = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never)
mockConsoleError = vi.spyOn(console, 'error').mockImplementation(() => {})
})
afterEach(() => {
@@ -226,7 +227,7 @@ describe('onError', () => {
})
test('add handler', () => {
const handler = jest.fn()
const handler = vi.fn()
const command = massarg(opts)
expect(command.onError).toBeInstanceOf(Function)
expect(command.onError(handler)).toBeInstanceOf(MassargCommand)
@@ -246,7 +247,7 @@ describe('onError', () => {
})
test('custom error handler is called', () => {
const handler = jest.fn()
const handler = vi.fn()
const command = massarg(opts)
.onError(handler)
.option({
@@ -263,7 +264,7 @@ describe('onError', () => {
})
test('custom error handler overrides default', () => {
const handler = jest.fn()
const handler = vi.fn()
const command = massarg(opts)
.onError(handler)
.option({
@@ -279,7 +280,7 @@ describe('onError', () => {
})
test('error handler catches errors from run function', () => {
const handler = jest.fn()
const handler = vi.fn()
const command = massarg(opts)
.onError(handler)
.main(() => {
@@ -293,7 +294,7 @@ describe('onError', () => {
})
test('error handler propagates to subcommands', () => {
const handler = jest.fn()
const handler = vi.fn()
const command = massarg(opts)
.onError(handler)
.command({

View File

@@ -1,3 +1,4 @@
import { vi } from 'vitest'
import { defaultHelpConfig } from '../src/help'
import { massarg } from '../src/index'
@@ -38,8 +39,8 @@ test('prints help from command', () => {
const command = massarg(opts).help({
bindCommand: true,
})
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const log = vi.spyOn(console, 'log').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
command.parse(['help'])
expect(log).toHaveBeenCalled()
log.mockRestore()
@@ -74,13 +75,13 @@ describe('prints help from option', () => {
const command = massarg(opts).help({
bindOption: true,
})
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
const log = vi.spyOn(console, 'log').mockImplementation(() => { })
command.parse(['--help'])
expect(log).toHaveBeenCalled()
})
test('when main command', () => {
const mainCmd = jest.fn()
const mainCmd = vi.fn()
const command2 = massarg(opts)
.help({
bindOption: true,
@@ -101,7 +102,7 @@ describe('prints help from option', () => {
.help({
bindOption: true,
})
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
const log = vi.spyOn(console, 'log').mockImplementation(() => { })
command.parse(['--help'])
expect(log).toHaveBeenCalled()
})
@@ -113,7 +114,7 @@ test('help string', () => {
})
test('print help', () => {
const log = jest.spyOn(console, 'log').mockImplementation(() => { })
const log = vi.spyOn(console, 'log').mockImplementation(() => { })
const command = massarg(opts)
command.printHelp()
expect(log).toHaveBeenCalled()

View File

@@ -1,3 +1,4 @@
import { vi } from 'vitest'
import { MassargCommand } from '../src/command'
import { massarg } from '../src/index'
@@ -14,7 +15,7 @@ describe('option', () => {
).toBeInstanceOf(MassargCommand)
})
test('validate', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts).option({
name: 'test2',
@@ -26,7 +27,7 @@ describe('option', () => {
error.mockRestore()
})
test('add duplicate', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts)
.option({
@@ -61,7 +62,7 @@ describe('option', () => {
expect(command.getArgs(['123'])).toHaveProperty('def', '123')
})
test('add 2 defaults', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts)
.option({
@@ -91,7 +92,7 @@ describe('option', () => {
expect(command.getArgs(['--test2', 'test'])).toHaveProperty('test', 'test')
})
test('required', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
const command = massarg(opts).option({
name: 'test2',
description: 'test2',
@@ -112,7 +113,7 @@ describe('flag', () => {
)
})
test('add duplicate', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts)
.flag({ name: 'test2', description: 'test2', aliases: [] })
@@ -121,7 +122,7 @@ describe('flag', () => {
error.mockRestore()
})
test('validate', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
expect(() =>
massarg(opts).flag({
name: 'test2',
@@ -133,7 +134,7 @@ describe('flag', () => {
})
describe('negation', () => {
test('no negation', () => {
const error = jest.spyOn(console, 'error').mockImplementation(() => { })
const error = vi.spyOn(console, 'error').mockImplementation(() => { })
const command = massarg(opts).flag({ name: 'test2', description: 'test2', aliases: [] })
expect(() => command.getArgs(['--no-test2'])).toThrow(
'test2: Option test2 cannot be negated (received: "--no-test2")',

12
vitest.config.ts Normal file
View File

@@ -0,0 +1,12 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
include: ['test/**/*.test.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'json-summary', 'lcov', 'clover'],
},
},
})