Skip to content

Commit 6700522

Browse files
committed
feat(cli): ads a simple config:init helper + tests
1 parent 48ab7bb commit 6700522

6 files changed

Lines changed: 446 additions & 26 deletions

File tree

cli.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env node
22

3-
require('./dist/cli')
3+
require('./dist/cli').processArgv()

docs/user/config.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,19 @@ All options have default values which should fit most of the projects.
8989
- [**`diagnostics`**: Diagnostics related configuration.](config/diagnostics)
9090
- [**`babelConfig`**: Babel(Jest) related configuration.](config/babelConfig)
9191
- [**`stringifyContentPathRegex`**: Configure which file(s) will become a module returning its content.](config/stringifyContentPathRegex)
92+
93+
### Upgrading
94+
95+
You can use the `config:migrate` tool of TSJest CLI if you're coming from an older version to help you migrate your Jest configuration.
96+
97+
<div class="row"><div class="col-md-6" markdown="block">
98+
If you're using `jest.config.json`:
99+
```sh
100+
node ./node_modules/.bin/ts-jest config:migrate jest.config.js
101+
```
102+
</div><div class="col-md-6" markdown="block">
103+
If you're using `jest` config property of `package.json`:
104+
```sh
105+
node ./node_modules/.bin/ts-jest config:migrate package.json
106+
```
107+
</div></div>

src/cli/cli.spec.ts

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
import { testing } from 'bs-logger'
2+
import * as _fs from 'fs'
3+
import { normalize, resolve } from 'path'
4+
5+
import { mocked } from '../__helpers__/mocks'
6+
import { rootLogger as _rootLogger } from '../util/logger'
7+
8+
import { processArgv } from '.'
9+
10+
// === helpers ================================================================
11+
jest.mock('../util/logger')
12+
jest.mock('fs')
13+
const fs = mocked(_fs)
14+
const rootLogger = _rootLogger as testing.LoggerMock
15+
16+
const mockWriteStream = () => {
17+
return {
18+
written: [] as string[],
19+
write(text: string) {
20+
this.written.push(text)
21+
},
22+
clear() {
23+
this.written = []
24+
},
25+
}
26+
}
27+
28+
const mockObject = <T, M>(obj: T, newProps: M): T & M & { mockRestore: () => T } => {
29+
const backup: any = Object.create(null)
30+
31+
Object.keys(newProps).forEach(key => {
32+
const desc = (backup[key] = Object.getOwnPropertyDescriptor(obj, key))
33+
const newDesc: any = { ...desc }
34+
if (newDesc.get) {
35+
newDesc.get = () => (newProps as any)[key]
36+
} else {
37+
newDesc.value = (newProps as any)[key]
38+
}
39+
Object.defineProperty(obj, key, newDesc)
40+
})
41+
if ((obj as any).mockRestore) backup.mockRestore = Object.getOwnPropertyDescriptor(obj, 'mockRestore')
42+
return Object.defineProperty(obj, 'mockRestore', {
43+
value() {
44+
Object.keys(backup).forEach(key => {
45+
Object.defineProperty(obj, key, backup[key])
46+
})
47+
return obj
48+
},
49+
configurable: true,
50+
})
51+
}
52+
53+
let lastExitCode: number | undefined
54+
55+
const runCli = async (
56+
...args: any[]
57+
): Promise<{ stdout: string; stderr: string; exitCode: number | undefined; log: string }> => {
58+
mockedProcess.stderr.clear()
59+
mockedProcess.stdout.clear()
60+
rootLogger.target.clear()
61+
mockedProcess.argv.splice(2, mockedProcess.argv.length - 2, ...args)
62+
lastExitCode = undefined
63+
await processArgv()
64+
return {
65+
exitCode: lastExitCode,
66+
stdout: mockedProcess.stdout.written.join('\n'),
67+
stderr: mockedProcess.stderr.written.join('\n'),
68+
log: rootLogger.target.lines.join('\n'),
69+
}
70+
}
71+
72+
let mockedProcess: any
73+
const FAKE_CWD = normalize('/foo/bar')
74+
const FAKE_PKG = normalize(`${FAKE_CWD}/package.json`)
75+
fs.existsSync.mockImplementation(f => f === FAKE_PKG)
76+
fs.readFileSync.mockImplementation(f => {
77+
if (f === FAKE_PKG) return JSON.stringify({ name: 'mock', version: '0.0.0-mock.0' })
78+
throw new Error('ENOENT')
79+
})
80+
81+
// === test ===================================================================
82+
83+
beforeEach(() => {
84+
// jest.resetModules()
85+
lastExitCode = undefined
86+
mockedProcess = mockObject(process, {
87+
cwd: () => FAKE_CWD,
88+
argv: ['node', resolve(__dirname, '..', '..', 'cli.js')],
89+
stderr: mockWriteStream(),
90+
stdout: mockWriteStream(),
91+
exit: (exitCode = 0) => {
92+
lastExitCode = exitCode
93+
},
94+
})
95+
fs.writeFileSync.mockClear()
96+
fs.existsSync.mockClear()
97+
fs.readFileSync.mockClear()
98+
rootLogger.target.clear()
99+
})
100+
afterEach(() => {
101+
mockedProcess.mockRestore()
102+
mockedProcess = undefined
103+
})
104+
105+
describe('cli', async () => {
106+
it('should output usage', async () => {
107+
expect.assertions(2)
108+
await expect(runCli()).resolves.toMatchInlineSnapshot(`
109+
Object {
110+
"exitCode": 0,
111+
"log": "",
112+
"stderr": "",
113+
"stdout": "
114+
Usage:
115+
ts-jest command [options] [...args]
116+
117+
Commands:
118+
config:init Creates initial Jest configuration
119+
config:migrate Migrates a given Jest configuration
120+
help [command] Show this help, or help about a command
121+
122+
Example:
123+
ts-jest help config:migrate
124+
",
125+
}
126+
`)
127+
await expect(runCli('hello:motto')).resolves.toMatchInlineSnapshot(`
128+
Object {
129+
"exitCode": 0,
130+
"log": "",
131+
"stderr": "",
132+
"stdout": "
133+
Usage:
134+
ts-jest command [options] [...args]
135+
136+
Commands:
137+
config:init Creates initial Jest configuration
138+
config:migrate Migrates a given Jest configuration
139+
help [command] Show this help, or help about a command
140+
141+
Example:
142+
ts-jest help config:migrate
143+
",
144+
}
145+
`)
146+
})
147+
})
148+
149+
describe('config', async () => {
150+
// briefly tested, see header comment in `config/init.ts`
151+
describe('init', async () => {
152+
const noOption = ['config:init']
153+
const fullOptions = [
154+
...noOption,
155+
'--babel',
156+
'--tsconfig',
157+
'tsconfig.test.json',
158+
'--jsdom',
159+
'--no-jest-preset',
160+
'--allow-js',
161+
]
162+
it('should create a jest.config.json (without options)', async () => {
163+
expect.assertions(2)
164+
const res = await runCli(...noOption)
165+
expect(res).toEqual({
166+
exitCode: 0,
167+
log: '',
168+
stderr: `
169+
Jest configuration written to "${normalize('/foo/bar/jest.config.js')}".
170+
`,
171+
stdout: '',
172+
})
173+
expect(fs.writeFileSync.mock.calls).toEqual([
174+
[
175+
normalize('/foo/bar/jest.config.js'),
176+
`module.exports = {
177+
preset: 'ts-jest',
178+
testEnvironment: 'node',
179+
};`,
180+
],
181+
])
182+
})
183+
it('should create a jest.config.foo.json (with all options set)', async () => {
184+
expect.assertions(2)
185+
const res = await runCli(...fullOptions, 'jest.config.foo.js')
186+
expect(res).toEqual({
187+
exitCode: 0,
188+
log: '',
189+
stderr: `
190+
Jest configuration written to "${normalize('/foo/bar/jest.config.foo.js')}".
191+
`,
192+
stdout: '',
193+
})
194+
expect(fs.writeFileSync.mock.calls).toEqual([
195+
[
196+
normalize('/foo/bar/jest.config.foo.js'),
197+
`const tsJest = require('ts-jest').createJestPreset({ allowJs: true });
198+
199+
module.exports = {
200+
...tsJest,
201+
globals: {
202+
'ts-jest': {
203+
tsconfig: 'tsconfig.test.json',
204+
babelConfig: true,
205+
},
206+
},
207+
};`,
208+
],
209+
])
210+
})
211+
it('should update package.json (without options)', async () => {
212+
expect.assertions(2)
213+
const res = await runCli(...noOption, 'package.json')
214+
expect(res).toEqual({
215+
exitCode: 0,
216+
log: '',
217+
stderr: `
218+
Jest configuration written to "${normalize('/foo/bar/package.json')}".
219+
`,
220+
stdout: '',
221+
})
222+
expect(fs.writeFileSync.mock.calls).toEqual([
223+
[
224+
normalize('/foo/bar/package.json'),
225+
`{
226+
"name": "mock",
227+
"version": "0.0.0-mock.0",
228+
"jest": {
229+
"preset": "ts-jest",
230+
"testEnvironment": "node"
231+
}
232+
}`,
233+
],
234+
])
235+
})
236+
it('should update package.json (with all options set)', async () => {
237+
expect.assertions(2)
238+
const res = await runCli(...fullOptions, 'package.json')
239+
expect(res).toEqual({
240+
exitCode: 0,
241+
log: `[level:20] creating jest presets handling JavaScript files
242+
`,
243+
stderr: `
244+
Jest configuration written to "${normalize('/foo/bar/package.json')}".
245+
`,
246+
stdout: '',
247+
})
248+
expect(fs.writeFileSync.mock.calls).toEqual([
249+
[
250+
normalize('/foo/bar/package.json'),
251+
`{
252+
"name": "mock",
253+
"version": "0.0.0-mock.0",
254+
"jest": {
255+
"transform": {
256+
"^.+\\\\.[tj]sx?$": "ts-jest"
257+
},
258+
"testMatch": [
259+
"**/__tests__/**/*.js?(x)",
260+
"**/?(*.)+(spec|test).js?(x)",
261+
"**/__tests__/**/*.ts?(x)",
262+
"**/?(*.)+(spec|test).ts?(x)"
263+
],
264+
"moduleFileExtensions": [
265+
"js",
266+
"json",
267+
"jsx",
268+
"node",
269+
"ts",
270+
"tsx"
271+
],
272+
"globals": {
273+
"ts-jest": {
274+
"tsconfig": "tsconfig.test.json",
275+
"babelConfig": true
276+
}
277+
}
278+
}
279+
}`,
280+
],
281+
])
282+
})
283+
})
284+
})

0 commit comments

Comments
 (0)