Skip to content

Commit

Permalink
fix(transformer): add deepUnmock to hoist method list (#1372)
Browse files Browse the repository at this point in the history
* fix(transformers): add deepUnmock to hoist methods

* fix(transformers): add deepUnmock to hoist methods
  • Loading branch information
ahnpnl committed Feb 5, 2020
1 parent 23f676c commit 0fbbc00
Show file tree
Hide file tree
Showing 11 changed files with 644 additions and 217 deletions.
@@ -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
@@ -0,0 +1,3 @@
export default function() {
return 'hi!'
}
@@ -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
@@ -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
@@ -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 })
})
File renamed without changes.
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
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
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
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

0 comments on commit 0fbbc00

Please sign in to comment.