Upgrading nextJS from 7.0.2 to the latest version of next 8.0.4 break tests that rely on mocking Date.now(). These tests are written in files that do not import nextjs
Clone sample repo: https://github.com/ssylvia/next-test-date-mock
NextJS Update Breaks Date Mocks
Steps to reproduce:
yarn installyarn test --no-cache.yarn test --no-cache.Date mock no longer worksTest that fails
Source method (src/utils/index.ts)
export const getCurrentTime = () => {
const time = Date.now();
return time;
};
Test (src/utils/index.ts)
test("getCurrentTime", () => {
jest.spyOn(Date, "now").mockImplementation(() => 0);
expect(getCurrentTime()).toBe(0);
});
Date.now() should continue to be mocked
If applicable, add screenshots to help explain your problem.
I've bisected the repo and identified 55e89e759a1a81a2815cbcc53359197dbcb41779 as the offending commit, more precisely the addition of the following line in packages/next/build/babel/preset.ts:
line 54:
corejs: 2,
breaks the test.
If the above line is removed from that file on origin/canary of next.js the test passes - however I'm not sure from the documentation whether that line is necessary.
@nataliemarleny Is this happening to you too even in the latest canary ? I didn't manage to reproduce this.
I haven't tested this in the latest canary, but on latest master we're seeing this bug as well.
The issue seems to be how the transpiler is setup as noted, where Date mocks are being circumvented by @babel/runtime-corejs2, e.g.
Date.now = () => 1;
test('should return the same value for date when mocked', () => {
const value = Date.now();
expect(value).toEqual(Date.now());
expect(value).toEqual(Date.now());
});
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
Date.now = function () {
return 1;
};
test('should return the same value for date when mocked', function () {
var value = (0, _now.default)();
expect(value).toEqual((0, _now.default)());
expect(value).toEqual((0, _now.default)());
});
Installing latest canary, seeing a slightly different but still troublesome transpile:
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
var _now = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/date/now"));
Date.now = function () {
return 1;
};
test('should return the same value for date when mocked', function () {
var value = (0, _now["default"])();
expect(value).toEqual((0, _now["default"])());
expect(value).toEqual((0, _now["default"])());
});
@mherodev Can you share your .babelrc please ? a very simple reproduction can work too 馃檹
Here's a simplified version of my babel.config.js that I was able to repro with:
module.exports = {
presets: [['next/babel', { 'preset-env': { modules: 'commonjs' } }]],
}
And here are all of my relevant babel packages from package.json:
"@babel/cli": "^7.2.3",
"@babel/core": "^7.0.0",
"@babel/node": "^7.0.0",
"@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"next": "^8.1.0",
@mherodev Why do you have babel packages installed ?, also is that your real babel config ? you should not use commonjs modules for the app.
It's been awhile, but I expect the babel packages were required to transpile our custom server. We also have a number of babel plugins that I assume require them as dependencies up the chain, e.g.
"babel-eslint": "^10.0.1",
"babel-jest": "^24.8.0",
"babel-plugin-emotion": "^10.0.13",
"babel-plugin-inline-react-svg": "^1.1.0",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-transform-define": "^1.3.1",
As for commonjs, it's used exclusively for testing, and removing it doesn't resolve this issue. Our actual config has it used under the env prop:
env: {
test: {
presets: [['next/babel', { 'preset-env': { modules: 'commonjs' } }]],
},
},
Removing corejs does fix the issue, I think it shouldn't introduce other issues, at least not in test mode:
{
"env": {
"development": {
"presets": ["next/babel"]
},
"production": {
"presets": ["next/babel"]
},
"test": {
"presets": [
[
"next/babel",
{
"preset-env": {
"modules": "commonjs"
},
"transform-runtime": {
"corejs": false
}
}
]
]
}
}
}
Great, we'll use this work-around!
I ran into this problem also today with latest versions of all related libs.
The bug seems be that Date and global.Date get treated differently.
Date.now = jest.spyOn(global.Date, 'now').mockImplementation(() => 5);
console.log(global.Date.now()); // returns 5 as expected
console.log(Date.now()); // returns 1570401251960 (mock had no affect)
I changed my babel.config.js to
module.exports = function (api) {
return {
// other config omitted
presets: [
'@babel/plugin-transform-runtime',
{
// CoreJS breaks Jest mocks for some reason
corejs: api.env('jest') ? false : 2,
helpers: true,
regenerator: true
}
]
}
}
and this seems to fixed it.
We can't really resolve this issue on the Next.js side as disabling corejs would cause the environment to be different between next build and testing.
Most helpful comment
Removing
corejsdoes fix the issue, I think it shouldn't introduce other issues, at least not in test mode: