Skip to content

Commit

Permalink
fix: write snapshots to disk even if FS is mocked (jestjs#7080)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimenB authored and captain-yossarian committed Jul 18, 2019
1 parent 90046f0 commit 92b2430
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
- `[jest-runtime]` Fix `requireActual` on node_modules with mock present ([#7404](https://github.com/facebook/jest/pull/7404))
- `[jest-resolve]` Fix `isBuiltinModule` to support versions of node without `module.builtinModules` ([#7565](https://github.com/facebook/jest/pull/7565))
- `[babel-jest]` Set `cwd` to be resilient to it changing during the runtime of the tests ([#7574](https://github.com/facebook/jest/pull/7574))
- `[jest-snapshot]` Write and read snapshots from disk even if `fs` is mocked ([#7080](https://github.com/facebook/jest/pull/7080))

### Chore & Maintenance

Expand Down
9 changes: 9 additions & 0 deletions e2e/__tests__/__snapshots__/snapshot-mock-fs.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`store snapshot even if fs is mocked 1`] = `
"Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 1 written, 1 total
Time: <<REPLACED>>
Ran all test suites."
`;
40 changes: 40 additions & 0 deletions e2e/__tests__/snapshot-mock-fs.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
'use strict';

const rimraf = require('rimraf');
const path = require('path');
const {extractSummary} = require('../Utils');
const runJest = require('../runJest');

const DIR = path.resolve(__dirname, '../snapshot-mock-fs');
const snapshotDir = path.resolve(DIR, '__tests__/__snapshots__');
const snapshotFile = path.resolve(snapshotDir, 'snapshot.test.js.snap');

beforeEach(() => rimraf.sync(snapshotDir));
afterAll(() => rimraf.sync(snapshotDir));

test('store snapshot even if fs is mocked', () => {
const {json, status, stderr} = runJest.json(DIR, ['--ci=false']);

expect(status).toBe(0);
expect(json.numTotalTests).toBe(1);
expect(json.numPassedTests).toBe(1);

expect(stderr).toMatch('1 snapshot written from 1 test suite.');
expect(extractSummary(stderr).summary).toMatchSnapshot();

// $FlowFixMe dynamic require
const content = require(snapshotFile);
expect(content['snapshot 1']).toBe(`
Object {
"foo": "bar",
}
`);
});
19 changes: 19 additions & 0 deletions e2e/snapshot-mock-fs/__tests__/snapshot.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+jsinfra
*/
'use strict';

const fs = require('fs');

fs.writeFileSync = jest.fn();

test('snapshot', () => {
const thing = {foo: 'bar'};

expect(thing).toMatchSnapshot();
});
5 changes: 5 additions & 0 deletions e2e/snapshot-mock-fs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"jest": {
"testEnvironment": "node"
}
}
16 changes: 16 additions & 0 deletions packages/jest-util/src/installCommonGlobals.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import type {ConfigGlobals} from 'types/Config';
import type {Global} from 'types/Global';

import fs from 'fs';
import createProcessObject from './createProcessObject';
import deepCyclicCopy from './deepCyclicCopy';

Expand All @@ -31,6 +32,21 @@ export default function(globalObject: Global, globals: ConfigGlobals) {
value: globalObject.Date.now.bind(globalObject.Date),
writable: false,
},
[symbol.for('jest-native-read-file')]: {
enumerable: false,
value: fs.readFileSync.bind(fs),
writable: false,
},
[symbol.for('jest-native-write-file')]: {
enumerable: false,
value: fs.writeFileSync.bind(fs),
writable: false,
},
[symbol.for('jest-native-exists-file')]: {
enumerable: false,
value: fs.existsSync.bind(fs),
writable: false,
},
'jest-symbol-do-not-touch': {
enumerable: false,
value: symbol,
Expand Down
59 changes: 59 additions & 0 deletions scripts/babel-plugin-jest-native-globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ module.exports = ({template}) => {
const nowDeclaration = template(`
var jestNow = global[Symbol.for('jest-native-now')] || global.Date.now;
`);
const fsReadFileDeclaration = template(`
var jestReadFile = global[Symbol.for('jest-native-read-file')] || fs.readFileSync;
`);
const fsWriteFileDeclaration = template(`
var jestWriteFile = global[Symbol.for('jest-native-write-file')] || fs.writeFileSync;
`);
const fsExistsFileDeclaration = template(`
var jestExistsFile = global[Symbol.for('jest-native-exists-file')] || fs.existsSync;
`);

return {
name: 'jest-native-globals',
Expand Down Expand Up @@ -57,6 +66,56 @@ module.exports = ({template}) => {

path.parentPath.replaceWithSourceString('jestNow');
}
if (
path.node.name === 'fs' &&
path.parent.property &&
['readFileSync', 'writeFileSync', 'existsSync'].includes(
path.parent.property.name
)
) {
if (
!state.jestInjectedRead &&
path.parent.property.name === 'readFileSync'
) {
state.jestInjectedRead = true;
path
.findParent(p => p.isProgram())
.unshiftContainer('body', fsReadFileDeclaration());
path
.findParent(p => p.isProgram())
.unshiftContainer('body', symbolDeclaration());

path.parentPath.replaceWithSourceString('jestReadFile');
}
if (
!state.jestInjectedWrite &&
path.parent.property.name === 'writeFileSync'
) {
state.jestInjectedWrite = true;
path
.findParent(p => p.isProgram())
.unshiftContainer('body', fsWriteFileDeclaration());
path
.findParent(p => p.isProgram())
.unshiftContainer('body', symbolDeclaration());

path.parentPath.replaceWithSourceString('jestWriteFile');
}
if (
!state.jestInjectedExists &&
path.parent.property.name === 'existsSync'
) {
state.jestInjectedExists = true;
path
.findParent(p => p.isProgram())
.unshiftContainer('body', fsExistsFileDeclaration());
path
.findParent(p => p.isProgram())
.unshiftContainer('body', symbolDeclaration());

path.parentPath.replaceWithSourceString('jestExistsFile');
}
}
},
},
};
Expand Down

0 comments on commit 92b2430

Please sign in to comment.