Skip to content

Commit f24c3cd

Browse files
authored
Migrate testing suite to Vitest (#1242)
1 parent a316560 commit f24c3cd

File tree

9 files changed

+129
-130
lines changed

9 files changed

+129
-130
lines changed

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
"@rollup/plugin-typescript": "^11.1.6",
2929
"@types/expect": "^24.3.0",
3030
"@types/lodash": "^4.14.144",
31-
"@types/mocha": "^10.0.0",
3231
"@types/node": "^18.7.14",
3332
"@typescript-eslint/eslint-plugin": "^7.1.1",
3433
"@typescript-eslint/parser": "^7.1.1",
@@ -39,11 +38,11 @@
3938
"is-url": "^1.2.4",
4039
"is-uuid": "^1.0.2",
4140
"lodash": "^4.17.15",
42-
"mocha": "^10.0.0",
4341
"np": "^10.0.0",
4442
"prettier": "^3.2.5",
4543
"rollup": "^4.12.1",
46-
"typescript": "^4.8.3"
44+
"typescript": "^4.8.3",
45+
"vitest": "^1.6.0"
4746
},
4847
"scripts": {
4948
"build": "rm -rf ./{dist} && rollup --config ./rollup.config.js",
@@ -55,9 +54,9 @@
5554
"lint:eslint": "eslint '{src,test}/*.{js,ts}'",
5655
"lint:prettier": "prettier --list-different '**/*.{js,json,ts}'",
5756
"release": "npm run build && npm run lint && np",
58-
"test": "npm run build && npm run test:types && npm run test:mocha",
59-
"test:mocha": "mocha --require ./test/register.cjs --require source-map-support/register ./test/index.ts",
57+
"test": "npm run build && npm run test:types && npm run test:vitest",
6058
"test:types": "tsc --noEmit && tsc --project ./test/tsconfig.json --noEmit",
59+
"test:vitest": "vitest run",
6160
"watch": "npm run build -- --watch"
6261
},
6362
"keywords": [

test/api/assert.ts renamed to test/api/assert.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { throws, doesNotThrow } from 'assert'
2+
import { describe, it } from 'vitest'
23
import { assert, string, StructError } from '../../src'
34

45
describe('assert', () => {

test/api/create.ts renamed to test/api/create.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { strictEqual, deepEqual, deepStrictEqual, throws } from 'assert'
2+
import { describe, it } from 'vitest'
23
import {
34
type,
45
optional,

test/api/is.ts renamed to test/api/is.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { strictEqual } from 'assert'
2+
import { describe, it } from 'vitest'
23
import { is, string } from '../../src'
34

45
describe('is', () => {

test/api/mask.ts renamed to test/api/mask.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { deepStrictEqual, throws } from 'assert'
2+
import { describe, it } from 'vitest'
23
import {
34
mask,
45
object,

test/api/validate.ts renamed to test/api/validate.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { deepStrictEqual, strictEqual } from 'assert'
2+
import { describe, it } from 'vitest'
23
import {
34
validate,
45
string,

test/index.test.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import assert, { CallTracker } from 'assert'
2+
import fs from 'fs'
3+
import { pick } from 'lodash'
4+
import { basename, extname, resolve } from 'path'
5+
import { describe, it } from 'vitest'
6+
import {
7+
any,
8+
assert as assertValue,
9+
Context,
10+
create as createValue,
11+
deprecated,
12+
StructError,
13+
} from '../src'
14+
15+
describe('superstruct', () => {
16+
describe('validation', () => {
17+
const kindsDir = resolve(__dirname, 'validation')
18+
const kinds = fs
19+
.readdirSync(kindsDir)
20+
.filter((t) => t[0] !== '.')
21+
.map((t) => basename(t, extname(t)))
22+
23+
for (const kind of kinds) {
24+
describe(kind, async () => {
25+
const testsDir = resolve(kindsDir, kind)
26+
const tests = fs
27+
.readdirSync(testsDir)
28+
.filter((t) => t[0] !== '.')
29+
.map((t) => basename(t, extname(t)))
30+
31+
for (const name of tests) {
32+
const module = await import(resolve(testsDir, name))
33+
const { Struct, data, create, only, skip, output, failures } = module
34+
const run = only ? it.only : skip ? it.skip : it
35+
run(name, () => {
36+
let actual
37+
let err
38+
39+
try {
40+
if (create) {
41+
actual = createValue(data, Struct)
42+
} else {
43+
assertValue(data, Struct)
44+
actual = data
45+
}
46+
} catch (e) {
47+
if (!(e instanceof StructError)) {
48+
throw e
49+
}
50+
51+
err = e
52+
}
53+
54+
if ('output' in module) {
55+
if (err) {
56+
throw new Error(
57+
`Expected "${name}" fixture not to throw an error but it did:\n\n${err}`
58+
)
59+
}
60+
61+
assert.deepStrictEqual(actual, output)
62+
} else if ('failures' in module) {
63+
if (!err) {
64+
throw new Error(
65+
`Expected "${name}" fixture to throw an error but it did not.`
66+
)
67+
}
68+
69+
const props = ['type', 'path', 'refinement', 'value', 'branch']
70+
const actualFailures = err
71+
.failures()
72+
.map((failure) => pick(failure, ...props))
73+
74+
assert.deepStrictEqual(actualFailures, failures)
75+
assert.deepStrictEqual(pick(err, ...props), failures[0])
76+
} else {
77+
throw new Error(
78+
`The "${name}" fixture did not define an \`output\` or \`failures\` export.`
79+
)
80+
}
81+
})
82+
}
83+
})
84+
}
85+
})
86+
87+
describe('deprecated', () => {
88+
it('does not log deprecated type if value is undefined', () => {
89+
const tracker = new CallTracker()
90+
const logSpy = buildSpyWithZeroCalls(tracker)
91+
assertValue(undefined, deprecated(any(), logSpy))
92+
tracker.verify()
93+
})
94+
95+
it('logs deprecated type to passed function if value is present', () => {
96+
const tracker = new CallTracker()
97+
const fakeLog = (value: unknown, ctx: Context) => {}
98+
const logSpy = tracker.calls(fakeLog, 1)
99+
assertValue('present', deprecated(any(), logSpy))
100+
tracker.verify()
101+
})
102+
})
103+
})
104+
105+
/**
106+
* This emulates `tracker.calls(0)`.
107+
*
108+
* `CallTracker.calls` doesn't support passing `0`, therefore we expect it
109+
* to be called once which is our call in this test. This proves that
110+
* the following action didn't call it.
111+
*/
112+
function buildSpyWithZeroCalls(tracker: CallTracker) {
113+
const logSpy = tracker.calls(1)
114+
logSpy()
115+
return logSpy
116+
}

test/index.ts

Lines changed: 0 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,5 @@
1-
import assert, { CallTracker } from 'assert'
2-
import fs from 'fs'
3-
import { pick } from 'lodash'
4-
import { basename, extname, resolve } from 'path'
5-
import {
6-
any,
7-
assert as assertValue,
8-
Context,
9-
create as createValue,
10-
deprecated,
11-
StructError,
12-
} from '../src'
13-
14-
describe('superstruct', () => {
15-
describe('api', () => {
16-
require('./api/assert')
17-
require('./api/create')
18-
require('./api/is')
19-
require('./api/mask')
20-
require('./api/validate')
21-
})
22-
23-
describe('validation', () => {
24-
const kindsDir = resolve(__dirname, 'validation')
25-
const kinds = fs
26-
.readdirSync(kindsDir)
27-
.filter((t) => t[0] !== '.')
28-
.map((t) => basename(t, extname(t)))
29-
30-
for (const kind of kinds) {
31-
describe(kind, () => {
32-
const testsDir = resolve(kindsDir, kind)
33-
const tests = fs
34-
.readdirSync(testsDir)
35-
.filter((t) => t[0] !== '.')
36-
.map((t) => basename(t, extname(t)))
37-
38-
for (const name of tests) {
39-
const module = require(resolve(testsDir, name))
40-
const { Struct, data, create, only, skip, output, failures } = module
41-
const run = only ? it.only : skip ? it.skip : it
42-
run(name, () => {
43-
let actual
44-
let err
45-
46-
try {
47-
if (create) {
48-
actual = createValue(data, Struct)
49-
} else {
50-
assertValue(data, Struct)
51-
actual = data
52-
}
53-
} catch (e) {
54-
if (!(e instanceof StructError)) {
55-
throw e
56-
}
57-
58-
err = e
59-
}
60-
61-
if ('output' in module) {
62-
if (err) {
63-
throw new Error(
64-
`Expected "${name}" fixture not to throw an error but it did:\n\n${err}`
65-
)
66-
}
67-
68-
assert.deepStrictEqual(actual, output)
69-
} else if ('failures' in module) {
70-
if (!err) {
71-
throw new Error(
72-
`Expected "${name}" fixture to throw an error but it did not.`
73-
)
74-
}
75-
76-
const props = ['type', 'path', 'refinement', 'value', 'branch']
77-
const actualFailures = err
78-
.failures()
79-
.map((failure) => pick(failure, ...props))
80-
81-
assert.deepStrictEqual(actualFailures, failures)
82-
assert.deepStrictEqual(pick(err, ...props), failures[0])
83-
} else {
84-
throw new Error(
85-
`The "${name}" fixture did not define an \`output\` or \`failures\` export.`
86-
)
87-
}
88-
})
89-
}
90-
})
91-
}
92-
})
93-
94-
describe('deprecated', () => {
95-
it('does not log deprecated type if value is undefined', () => {
96-
const tracker = new CallTracker()
97-
const logSpy = buildSpyWithZeroCalls(tracker)
98-
assertValue(undefined, deprecated(any(), logSpy))
99-
tracker.verify()
100-
})
101-
102-
it('logs deprecated type to passed function if value is present', () => {
103-
const tracker = new CallTracker()
104-
const fakeLog = (value: unknown, ctx: Context) => {}
105-
const logSpy = tracker.calls(fakeLog, 1)
106-
assertValue('present', deprecated(any(), logSpy))
107-
tracker.verify()
108-
})
109-
})
110-
})
111-
1121
/**
1132
* A helper for testing type signatures.
1143
*/
1154

1165
export function test<T>(fn: (x: unknown) => T) {}
117-
118-
/**
119-
* This emulates `tracker.calls(0)`.
120-
*
121-
* `CallTracker.calls` doesn't support passing `0`, therefore we expect it
122-
* to be called once which is our call in this test. This proves that
123-
* the following action didn't call it.
124-
*/
125-
function buildSpyWithZeroCalls(tracker: CallTracker) {
126-
const logSpy = tracker.calls(1)
127-
logSpy()
128-
return logSpy
129-
}

test/tsconfig.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
22
"extends": "../tsconfig.json",
3-
"include": ["./**/*.ts"]
3+
"include": ["./**/*.ts"],
4+
"compilerOptions": {
5+
"skipLibCheck": true
6+
}
47
}

0 commit comments

Comments
 (0)