Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(transformer): add deepUnmock to hoist method list #1372

Merged
merged 3 commits into from
Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import hello from './disable-automock'

jest.disableAutomock()

test('original implementation', () => {
// now we have the original implementation,
// even if we set the automocking in a jest configuration
expect(hello()).toBe('hi!')
})
3 changes: 3 additions & 0 deletions e2e/__cases__/hoisting/disable-automock/disable-automock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function() {
return 'hi!'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
jest.enableAutomock()

import hello from './enable-automock'

test('original implementation', () => {
// now we have the mocked implementation,
// @ts-ignore
expect(hello._isMockFunction).toBeTruthy()
})
3 changes: 3 additions & 0 deletions e2e/__cases__/hoisting/enable-automock/enable-automock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function() {
return 'hi!'
}
21 changes: 0 additions & 21 deletions e2e/__cases__/hoisting/hello.spec.ts

This file was deleted.

13 changes: 13 additions & 0 deletions e2e/__cases__/hoisting/mock-unmock/mock-unmock.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import hello from './mock-unmock'

jest.mock('./mock-unmock')

const original = jest.requireActual('./mock-unmock').default
it('should have been mocked', () => {
const msg = hello()
expect(hello).not.toBe(original)
expect(msg).toBeUndefined()
expect(hello).toHaveProperty('mock')
expect(require('foo')).toBe('bar')
jest.mock('foo', () => 'bar', { virtual: true })
})
722 changes: 540 additions & 182 deletions e2e/__tests__/__snapshots__/hoisting.test.ts.snap

Large diffs are not rendered by default.

39 changes: 36 additions & 3 deletions e2e/__tests__/hoisting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,47 @@ import { allValidPackageSets } from '../__helpers__/templates'
import { configureTestCase } from '../__helpers__/test-case'

describe('Hoisting jest.mock() & jest.unmock()', () => {
const testCase = configureTestCase('hoisting', { writeIo: true })
const testCase = configureTestCase('hoisting/mock-unmock', {
writeIo: true,
})

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()
expect(result.status).toBe(0)
expect(result).toMatchSnapshot('output-mockUnmock')
expect(result.ioFor('mock-unmock.spec.ts')).toMatchSnapshot('io-mockUnmock')
})
})
})

describe('Hoisting jest.enableAutomock()', () => {
const testCase = configureTestCase('hoisting/enable-automock', { writeIo: true })

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()
expect(result.status).toBe(0)
expect(result).toMatchSnapshot('output-enableAutomock')
expect(result.ioFor('enable-automock.spec.ts')).toMatchSnapshot('io-enableAutomock')
})
})
})

describe('Hoisting jest.disableAutomock()', () => {
const testCase = configureTestCase('hoisting/disable-automock', {
writeIo: true,
jestConfig: {
automock: true,
}
})

testCase.runWithTemplates(allValidPackageSets, 0, (runTest, { testLabel }) => {
it(testLabel, () => {
const result = runTest()
expect(result.status).toBe(0)
expect(result).toMatchSnapshot('output')
expect(result.ioFor('hello.spec.ts')).toMatchSnapshot('io')
expect(result).toMatchSnapshot('output-disableAutomock')
expect(result.ioFor('disable-automock.spec.ts')).toMatchSnapshot('io-disableAutomock')
})
})
})
20 changes: 19 additions & 1 deletion src/transformers/hoist-jest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,19 @@ jest.enableAutomock()
jest.disableAutomock()
jest.mock('./foo')
jest.mock('./foo/bar', () => 'bar')
jest.unmock('./bar/foo').dontMock('./bar/bar')
jest.deepUnmock('./foo')
jest.mock('./foo').mock('./bar')
const func = () => {
const bar = 'bar'
console.log(bar)
jest.unmock('./foo')
jest.mock('./bar')
jest.mock('./bar/foo', () => 'foo')
jest.unmock('./foo/bar')
jest.unmock('./bar/foo').dontMock('./bar/bar')
jest.deepUnmock('./bar')
jest.mock('./foo').mock('./bar')
}
const func2 = () => {
const bar = 'bar'
Expand All @@ -25,6 +31,9 @@ const func2 = () => {
jest.unmock('./foo/bar')
jest.mock('./bar/foo', () => 'foo')
jest.unmock('./foo')
jest.unmock('./bar/foo').dontMock('./bar/bar')
jest.deepUnmock('./bar')
jest.mock('./foo').mock('./bar')
}
`
const logger = testing.createLoggerMock()
Expand All @@ -41,30 +50,39 @@ describe('hoisting', () => {
expect(typeof hoist.factory).toBe('function')
})

it('should hoist jest mock() and unmock() statements', () => {
it('should hoist jest.mock(), unmock(), disableAutomock() and enableAutomock()', () => {
const out = transpile(CODE_WITH_HOISTING)
expect(out.outputText).toMatchInlineSnapshot(`
"jest.enableAutomock();
jest.disableAutomock();
jest.mock('./foo');
jest.mock('./foo/bar', function () { return 'bar'; });
jest.deepUnmock('./foo');
jest.mock('./foo').mock('./bar');
var foo = 'foo';
console.log(foo);
jest.unmock('./bar/foo').dontMock('./bar/bar');
var func = function () {
jest.unmock('./foo');
jest.mock('./bar');
jest.mock('./bar/foo', function () { return 'foo'; });
jest.unmock('./foo/bar');
jest.deepUnmock('./bar');
jest.mock('./foo').mock('./bar');
var bar = 'bar';
console.log(bar);
jest.unmock('./bar/foo').dontMock('./bar/bar');
};
var func2 = function () {
jest.mock('./bar');
jest.unmock('./foo/bar');
jest.mock('./bar/foo', function () { return 'foo'; });
jest.unmock('./foo');
jest.deepUnmock('./bar');
jest.mock('./foo').mock('./bar');
var bar = 'bar';
console.log(bar);
jest.unmock('./bar/foo').dontMock('./bar/bar');
};
"
`)
Expand Down
22 changes: 12 additions & 10 deletions src/transformers/hoist-jest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { ConfigSet } from '../config/config-set'
/**
* What methods of `jest` should we hoist
*/
const HOIST_METHODS = ['mock', 'unmock', 'enableAutomock', 'disableAutomock']
const HOIST_METHODS = ['mock', 'unmock', 'enableAutomock', 'disableAutomock', 'deepUnmock']

/**
* @internal
Expand All @@ -41,20 +41,22 @@ export function factory(cs: ConfigSet) {
*/
const ts = cs.compilerModule

function shouldHoistExpression(expression: Node): boolean {
return (
ts.isCallExpression(expression) &&
ts.isPropertyAccessExpression(expression.expression) &&
HOIST_METHODS.includes(expression.expression.name.text) &&
((ts.isIdentifier(expression.expression.expression) && expression.expression.expression.text === 'jest') ||
shouldHoistExpression(expression.expression.expression))
)
}

/**
* Checks whether given node is a statement that we need to hoist
* @param node The node to test
*/
function shouldHoistNode(node: Node): node is ExpressionStatement {
return (
ts.isExpressionStatement(node) &&
ts.isCallExpression(node.expression) &&
ts.isPropertyAccessExpression(node.expression.expression) &&
ts.isIdentifier(node.expression.expression.expression) &&
node.expression.expression.expression.text === 'jest' &&
ts.isIdentifier(node.expression.expression.name) &&
HOIST_METHODS.includes(node.expression.expression.name.text)
)
return ts.isExpressionStatement(node) && shouldHoistExpression(node.expression)
}

/**
Expand Down