Skip to content

Commit

Permalink
Fix @babel/register test mocks
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Dec 1, 2021
1 parent c2c4554 commit c7bd3a6
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 48 deletions.
3 changes: 3 additions & 0 deletions packages/babel-register/src/nodeWrapper.ts
Expand Up @@ -13,6 +13,9 @@ const internalModuleCache = Object.create(null);

Module._cache = internalModuleCache;
const node = require("./node");

// NOTE: This Module._cache set is intercepted by the beforeEach hook in
// packages/babel-register/test/index.js to install dependencies mocks.
Module._cache = globalModuleCache;

// Add source-map-support to global cache as it's stateful
Expand Down
22 changes: 19 additions & 3 deletions packages/babel-register/test/cache.js
@@ -1,13 +1,13 @@
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { createRequire } from "module";
import { createRequire, Module } from "module";

const require = createRequire(import.meta.url);

const testCacheFilename = path.join(
path.dirname(fileURLToPath(import.meta.url)),
".babel",
".cache.babel",
);
const oldBabelDisableCacheValue = process.env.BABEL_DISABLE_CACHE;

Expand Down Expand Up @@ -35,14 +35,30 @@ function resetCache() {
process.env.BABEL_DISABLE_CACHE = oldBabelDisableCacheValue;
}

const OLD_JEST_MOCKS = !!jest.doMock;

describe("@babel/register - caching", () => {
describe("cache", () => {
let load, get, setDirty, save;
let consoleWarnSpy;

if (!OLD_JEST_MOCKS) {
let oldModuleCache;
beforeAll(() => {
oldModuleCache = Module._cache;
});
afterAll(() => {
Module._cache = oldModuleCache;
});
}

beforeEach(() => {
// Since lib/cache is a singleton we need to fully reload it
jest.resetModules(require);
if (OLD_JEST_MOCKS) {
jest.resetModules();
} else {
Module._cache = {};
}
const cache = require("../lib/cache.js");

load = cache.load;
Expand Down
1 change: 1 addition & 0 deletions packages/babel-register/test/fixtures/package.json
@@ -0,0 +1 @@
{ "type": "commonjs" }
132 changes: 90 additions & 42 deletions packages/babel-register/test/index.js
@@ -1,47 +1,19 @@
import { createRequire } from "module";
import { createRequire, Module } from "module";
import path from "path";
import fs from "fs";
import child from "child_process";
import { fileURLToPath } from "url";

const dirname = path.dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);

let currentHook;
let currentOptions;
let sourceMapSupport = false;

const registerFile = require.resolve("../lib/index");
const testCacheFilename = path.join(__dirname, ".babel");
const testCacheFilename = path.join(dirname, ".index.babel");
const testFile = require.resolve("./fixtures/babelrc/es2015");
const testFileContent = fs.readFileSync(testFile);
const sourceMapTestFile = require.resolve("./fixtures/source-map/index");
const sourceMapNestedTestFile = require.resolve(
"./fixtures/source-map/foo/bar",
);
const internalModulesTestFile = require.resolve(
"./fixtures/internal-modules/index",
);

jest.mock("pirates", () => {
return {
addHook(hook, opts) {
currentHook = hook;
currentOptions = opts;

return () => {
currentHook = null;
currentOptions = null;
};
},
};
});

jest.mock("source-map-support", () => {
return {
install() {
sourceMapSupport = true;
},
};
});
const piratesPath = require.resolve("pirates");
const smsPath = require.resolve("source-map-support");

const defaultOptions = {
exts: [".js", ".jsx", ".es6", ".es", ".mjs", ".cjs"],
Expand All @@ -60,7 +32,31 @@ function resetCache() {
process.env.BABEL_CACHE_PATH = null;
}

const OLD_JEST_MOCKS = !!jest.doMock;

describe("@babel/register", function () {
let currentHook, currentOptions, sourceMapSupport;

const mocks = {
["pirates"]: {
addHook(hook, opts) {
currentHook = hook;
currentOptions = opts;

return () => {
currentHook = null;
currentOptions = null;
};
},
},

["source-map-support"]: {
install() {
sourceMapSupport = true;
},
},
};

let babelRegister;

function setupRegister(config = { babelrc: false }) {
Expand All @@ -83,6 +79,12 @@ describe("@babel/register", function () {
cleanCache();
}

beforeEach(() => {
currentHook = null;
currentOptions = null;
sourceMapSupport = false;
});

afterEach(async () => {
// @babel/register saves the cache on process.nextTick.
// We need to wait for at least one tick so that when jest
Expand All @@ -91,16 +93,60 @@ describe("@babel/register", function () {
await new Promise(setImmediate);

revertRegister();
currentHook = null;
currentOptions = null;
sourceMapSupport = false;
jest.resetModules();
});

afterAll(() => {
resetCache();
});

if (OLD_JEST_MOCKS) {
jest.doMock("pirates", () => mocks["pirates"]);
jest.doMock("source-map-support", () => mocks["source-map-support"]);

afterEach(() => {
jest.resetModules();
});
} else {
let originalRequireCacheDescriptor;
beforeAll(() => {
originalRequireCacheDescriptor = Object.getOwnPropertyDescriptor(
Module,
"_cache",
);
});

beforeEach(() => {
const isEmptyObj = obj =>
Object.getPrototypeOf(obj) === null && Object.keys(obj).length === 0;

// This setter intercepts the Module._cache assignment in
// packages/babel-register/src/nodeWrapper.js to install in the
// internal isolated cache.
const emptyInitialCache = {};
Object.defineProperty(Module, "_cache", {
get: () => emptyInitialCache,
set(value) {
expect(isEmptyObj(value)).toBe(true);

Object.defineProperty(Module, "_cache", {
value,
enumerable: originalRequireCacheDescriptor.enumerable,
configurable: originalRequireCacheDescriptor.configurable,
writable: originalRequireCacheDescriptor.writable,
});
value[piratesPath] = { exports: mocks["pirates"] };
value[smsPath] = { exports: mocks["source-map-support"] };
},
enumerable: originalRequireCacheDescriptor.enumerable,
configurable: originalRequireCacheDescriptor.configurable,
});
});

afterAll(() => {
Object.defineProperty(Module, "_cache", originalRequireCacheDescriptor);
});
}

test("registers hook correctly", () => {
setupRegister();

Expand Down Expand Up @@ -160,11 +206,11 @@ describe("@babel/register", function () {
const output = await spawnNodeAsync([
"-r",
registerFile,
sourceMapTestFile,
require.resolve("./fixtures/source-map/index"),
]);
const sourceMap = JSON.parse(output);
expect(sourceMap.map.sourceRoot + sourceMap.map.sources[0]).toBe(
sourceMapNestedTestFile,
require.resolve("./fixtures/source-map/foo/bar"),
);
});

Expand Down Expand Up @@ -195,14 +241,16 @@ describe("@babel/register", function () {
// Need a clean environment without `convert-source-map`
// already in the require cache, so we spawn a separate process

const output = await spawnNodeAsync([internalModulesTestFile]);
const output = await spawnNodeAsync([
require.resolve("./fixtures/internal-modules/index.js"),
]);
const { convertSourceMap } = JSON.parse(output);
expect(convertSourceMap).toMatch("/* transformed */");
});
});

function spawnNodeAsync(args) {
const spawn = child.spawn(process.execPath, args, { cwd: __dirname });
const spawn = child.spawn(process.execPath, args, { cwd: dirname });

let output = "";
let callback;
Expand Down
3 changes: 0 additions & 3 deletions test/jest-light-runner/src/global-setup.js
Expand Up @@ -24,7 +24,4 @@ globalThis.afterEach = circus.afterEach;
globalThis.jest = {
fn: mock.fn,
spyOn: mock.spyOn,
resetModules: require => {
for (const k of Object.keys(require.cache)) delete require.cache[k];
},
};

0 comments on commit c7bd3a6

Please sign in to comment.