Skip to content

Commit

Permalink
feat: directly writes to stdio so jest does not swallow
Browse files Browse the repository at this point in the history
  • Loading branch information
huafu committed Aug 21, 2018
1 parent 95e84ad commit 6a7f01f
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 105 deletions.
55 changes: 0 additions & 55 deletions src/__helpers__/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,58 +9,3 @@ export function spied<T>(
): T extends (...args: any[]) => any ? jest.SpyInstance<T> : jest.Mocked<T> {
return val as any
}

export function mockThese(
map:
| string[]
| {
[k: string]: () => any
},
) {
const isArray = Array.isArray(map)
const items: string[] = isArray ? (map as string[]) : Object.keys(map)
items.forEach(item => {
const val = isArray ? () => item : (map as any)[item]
jest.doMock(item, val, { virtual: true })
})
}

export function spyThese<T extends object, K extends keyof T>(
object: T,
implementations: { [key in K]: T[K] | any | undefined },
): { [key in K]: jest.SpyInstance<T[K]> } & {
mockRestore: () => void
mockReset: () => void
mockClear: () => void
} {
const keys = Object.keys(implementations) as K[]
const res = keys.reduce(
(map, key) => {
const actual = object[key] as any
const spy = (map[key] = jest.spyOn(object, key as K))
if (implementations[key]) {
const impl = implementations[key] as (...args: any[]) => any
if (impl.length && /\W\$super\W/.test(impl.toString())) {
spy.mockImplementation(function(this: T, ...args: any[]) {
return impl.call(this, () => actual.apply(this, args), ...args)
})
} else {
spy.mockImplementation(impl)
}
}
return map
},
{} as any,
)
// utility to restore/reset/clear all
res.mockRestore = () => {
keys.forEach(key => res[key].mockRestore())
}
res.mockReset = () => {
keys.forEach(key => res[key].mockReset())
}
res.mockClear = () => {
keys.forEach(key => res[key].mockClear())
}
return res
}
22 changes: 11 additions & 11 deletions src/lib/__snapshots__/backports.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.__TRANSFORM_HTML__" set to false should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.__TRANSFORM_HTML__\\" is deprecated, use \\"[jest-config].globals.ts-jest.stringifyContentPathRegex\\" instead."`;
exports[`backportJestConfig with "globals.__TRANSFORM_HTML__" set to false should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.__TRANSFORM_HTML__\\" is deprecated, use \\"[jest-config].globals.ts-jest.stringifyContentPathRegex\\" instead."`;

exports[`backportJestConfig with "globals.__TRANSFORM_HTML__" set to true should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -36,7 +36,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.__TRANSFORM_HTML__" set to true should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.__TRANSFORM_HTML__\\" is deprecated, use \\"[jest-config].globals.ts-jest.stringifyContentPathRegex\\" instead."`;
exports[`backportJestConfig with "globals.__TRANSFORM_HTML__" set to true should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.__TRANSFORM_HTML__\\" is deprecated, use \\"[jest-config].globals.ts-jest.stringifyContentPathRegex\\" instead."`;

exports[`backportJestConfig with "globals.__TS_CONFIG__" set to { foo: 'bar' } should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -60,7 +60,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.__TS_CONFIG__" set to { foo: 'bar' } should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.__TS_CONFIG__\\" is deprecated, use \\"[jest-config].globals.ts-jest.tsConfig\\" instead."`;
exports[`backportJestConfig with "globals.__TS_CONFIG__" set to { foo: 'bar' } should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.__TS_CONFIG__\\" is deprecated, use \\"[jest-config].globals.ts-jest.tsConfig\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to '\\\\.spec\\\\.ts$' should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -84,7 +84,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to '\\\\.spec\\\\.ts$' should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.ts-jest.enableTsDiagnostics\\" is deprecated, use \\"[jest-config].globals.ts-jest.diagnostics\\" instead."`;
exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to '\\\\.spec\\\\.ts$' should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.ts-jest.enableTsDiagnostics\\" is deprecated, use \\"[jest-config].globals.ts-jest.diagnostics\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to false should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -106,7 +106,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to false should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.ts-jest.enableTsDiagnostics\\" is deprecated, use \\"[jest-config].globals.ts-jest.diagnostics\\" instead."`;
exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to false should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.ts-jest.enableTsDiagnostics\\" is deprecated, use \\"[jest-config].globals.ts-jest.diagnostics\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to true should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -128,7 +128,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to true should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.ts-jest.enableTsDiagnostics\\" is deprecated, use \\"[jest-config].globals.ts-jest.diagnostics\\" instead."`;
exports[`backportJestConfig with "globals.ts-jest.enableTsDiagnostics" set to true should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.ts-jest.enableTsDiagnostics\\" is deprecated, use \\"[jest-config].globals.ts-jest.diagnostics\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.skipBabel" set to false should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -150,7 +150,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.ts-jest.skipBabel" set to false should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.ts-jest.skipBabel\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead."`;
exports[`backportJestConfig with "globals.ts-jest.skipBabel" set to false should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.ts-jest.skipBabel\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.skipBabel" set to true should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -170,7 +170,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.ts-jest.skipBabel" set to true should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.ts-jest.skipBabel\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead."`;
exports[`backportJestConfig with "globals.ts-jest.skipBabel" set to true should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.ts-jest.skipBabel\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.tsConfigFile" set to 'tsconfig.build.json' should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -192,7 +192,7 @@ Object {
}
`;

exports[`backportJestConfig with "globals.ts-jest.tsConfigFile" set to 'tsconfig.build.json' should wran the user 1`] = `"ts-jest: \\"[jest-config].globals.ts-jest.tsConfigFile\\" is deprecated, use \\"[jest-config].globals.ts-jest.tsConfig\\" instead."`;
exports[`backportJestConfig with "globals.ts-jest.tsConfigFile" set to 'tsconfig.build.json' should wran the user 1`] = `"warn ts-jest: \\"[jest-config].globals.ts-jest.tsConfigFile\\" is deprecated, use \\"[jest-config].globals.ts-jest.tsConfig\\" instead."`;

exports[`backportJestConfig with "globals.ts-jest.useBabelrc" set to false should have changed the config correctly: before 1`] = `
Object {
Expand All @@ -215,7 +215,7 @@ Object {
`;

exports[`backportJestConfig with "globals.ts-jest.useBabelrc" set to false should wran the user 1`] = `
"ts-jest: \\"[jest-config].globals.ts-jest.useBabelrc\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead.
"warn ts-jest: \\"[jest-config].globals.ts-jest.useBabelrc\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead.
↳ See \`babel-jest\` related issue: https://github.com/facebook/jest/issues/3845"
`;

Expand All @@ -240,6 +240,6 @@ Object {
`;

exports[`backportJestConfig with "globals.ts-jest.useBabelrc" set to true should wran the user 1`] = `
"ts-jest: \\"[jest-config].globals.ts-jest.useBabelrc\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead.
"warn ts-jest: \\"[jest-config].globals.ts-jest.useBabelrc\\" is deprecated, use \\"[jest-config].globals.ts-jest.babelConfig\\" instead.
↳ See \`babel-jest\` related issue: https://github.com/facebook/jest/issues/3845"
`;
15 changes: 7 additions & 8 deletions src/lib/backports.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { backportJestConfig } from './backports'
import { spyThese } from '../__helpers__/mocks'
import set from 'lodash.set'
import { inspect } from 'util'
import { __setup } from './debug'

const consoleSpies = spyThese(console, {
warn: () => undefined,
})
afterEach(() => {
consoleSpies.mockReset()
const logger = jest.fn()
__setup({ logger })
beforeEach(() => {
logger.mockClear()
})

describe('backportJestConfig', () => {
Expand All @@ -21,8 +20,8 @@ describe('backportJestConfig', () => {
describe(`with "${oldPath}" set to ${inspect(val)}`, () => {
it(`should wran the user`, () => {
backportJestConfig(original)
expect(consoleSpies.warn).toHaveBeenCalledTimes(1)
expect(consoleSpies.warn.mock.calls[0].join(' ')).toMatchSnapshot()
expect(logger).toHaveBeenCalledTimes(1)
expect(logger.mock.calls[0].join(' ')).toMatchSnapshot()
}) // should warn the user
it(`should have changed the config correctly`, () => {
expect(original).toMatchSnapshot('before')
Expand Down
60 changes: 39 additions & 21 deletions src/lib/debug.spec.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,77 @@
import { spyThese } from '../__helpers__/mocks'
import { debug, wrapWithDebug, __setup } from './debug'
import { debug, wrapWithDebug, __setup, warn } from './debug'

const consoleSpies = spyThese(console, {
log: () => void 0,
warn: () => void 0,
})
const stdoutSpy = jest.spyOn(process.stdout, 'write')
const stderrSpy = jest.spyOn(process.stderr, 'write')

beforeEach(() => {
delete process.env.TS_JEST_DEBUG
consoleSpies.mockClear()
stderrSpy.mockClear()
stdoutSpy.mockClear()
})
afterAll(() => {
stderrSpy.mockRestore()
stdoutSpy.mockRestore()
})

describe('debug', () => {
it('should log when TS_JEST_DEBUG is truthy', () => {
it('should log to stdout when TS_JEST_DEBUG is truthy', () => {
process.env.TS_JEST_DEBUG = '1'
__setup()
debug('foo')
expect(consoleSpies.log).toHaveBeenCalledTimes(1)
expect(consoleSpies.log).toHaveBeenCalledWith('ts-jest:', 'foo')
expect(stdoutSpy).toHaveBeenCalledTimes(1)
expect(stdoutSpy).toHaveBeenCalledWith('ts-jest: foo\n')
})
it('should NOT log when TS_JEST_DEBUG is falsy', () => {
it('should NOT log to stdout when TS_JEST_DEBUG is falsy', () => {
process.env.TS_JEST_DEBUG = ''
__setup()
debug('foo')
expect(consoleSpies.log).not.toHaveBeenCalled()
expect(stdoutSpy).not.toHaveBeenCalled()
})
it('should NOT log when TS_JEST_DEBUG is not set', () => {
it('should NOT log to stdout when TS_JEST_DEBUG is not set', () => {
delete process.env.TS_JEST_DEBUG
__setup()
debug('foo')
expect(consoleSpies.log).not.toHaveBeenCalled()
expect(stdoutSpy).not.toHaveBeenCalled()
})
})
describe('warn', () => {
it('should log to stderr when TS_JEST_DEBUG is truthy', () => {
process.env.TS_JEST_DEBUG = '1'
__setup()
warn('foo')
expect(stderrSpy).toHaveBeenCalledTimes(1)
expect(stderrSpy).toHaveBeenCalledWith('ts-jest: foo\n')
})
it('should log to stderr even when TS_JEST_DEBUG is falsy', () => {
delete process.env.TS_JEST_DEBUG
__setup()
warn('foo')
expect(stderrSpy).toHaveBeenCalledTimes(1)
expect(stderrSpy).toHaveBeenCalledWith('ts-jest: foo\n')
})
})

describe('wrapWithDebug', () => {
const subject = (val: string) => `hello ${val}`
const wrapAndCall = (val: string) => wrapWithDebug('foo', subject)(val)

it('should log when TS_JEST_DEBUG is truthy', () => {
it('should log to stdout when TS_JEST_DEBUG is truthy', () => {
process.env.TS_JEST_DEBUG = '1'
__setup()
expect(wrapAndCall('bar')).toBe('hello bar')
expect(consoleSpies.log).toHaveBeenCalledTimes(1)
expect(consoleSpies.log).toHaveBeenCalledWith('ts-jest:', 'foo')
expect(stdoutSpy).toHaveBeenCalledTimes(1)
expect(stdoutSpy).toHaveBeenCalledWith('ts-jest: foo\n')
})
it('should NOT log when TS_JEST_DEBUG is falsy', () => {
it('should NOT log to stdout when TS_JEST_DEBUG is falsy', () => {
process.env.TS_JEST_DEBUG = ''
__setup()
expect(wrapAndCall('bar')).toBe('hello bar')
expect(consoleSpies.log).not.toHaveBeenCalled()
expect(stdoutSpy).not.toHaveBeenCalled()
})
it('should NOT log when TS_JEST_DEBUG is not set', () => {
it('should NOT log to stdout when TS_JEST_DEBUG is not set', () => {
delete process.env.TS_JEST_DEBUG
__setup()
expect(wrapAndCall('bar')).toBe('hello bar')
expect(consoleSpies.log).not.toHaveBeenCalled()
expect(stdoutSpy).not.toHaveBeenCalled()
})
})
17 changes: 14 additions & 3 deletions src/lib/debug.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { format } from 'util'

export let DEBUG_MODE!: boolean

export let debug!: typeof console.log
Expand All @@ -8,13 +10,22 @@ export let wrapWithDebug!: <T extends (...args: any[]) => any>(
func: T,
) => T

type LogKind = 'log' | 'warn' | 'debug' | 'info'
type LogKind = 'log' | 'warn'
type Logger = (kind: LogKind, ...args: any[]) => void

export let LOG_PREFIX = 'ts-jest:'

export const defaultLogger: Logger = (kind: LogKind, ...args: any[]) => {
console[kind](...args)
export const defaultLogger: Logger = (
kind: LogKind,
msg: string = '',
...args: any[]
) => {
// we use stderr/stdout dirrectly so that the log won't be swallowed by jest
if (kind === 'warn') {
process.stderr.write(format(msg, ...args) + '\n')
} else if (kind) {
process.stdout.write(format(msg, ...args) + '\n')
}
}

interface SetupOptions {
Expand Down
Loading

0 comments on commit 6a7f01f

Please sign in to comment.