Skip to content

Commit

Permalink
test sync callbacks, add docu and type test
Browse files Browse the repository at this point in the history
  • Loading branch information
CircleCI committed Dec 19, 2022
1 parent 4045eb7 commit 36c138e
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 72 deletions.
14 changes: 13 additions & 1 deletion docs/JestObjectAPI.md
Expand Up @@ -575,13 +575,25 @@ const otherCopyOfMyModule = require('myModule');
```js
let myModule;
await jest.isolateModulesAsync(async () => {
constmyModule = require('myModule');
myModule = await import('myModule');
// do async stuff here
});

const otherCopyOfMyModule = require('myModule');
```

`jest.isolateModulesAsync()` can also run synchronous callbacks:

```js
let myModule;
await jest.isolateModulesAsync(() => {
myModule = require('myModule');
// do sync stuff here
});

const otherCopyOfMyModule = require('myModule');
```

## Mock Functions

### `jest.fn(implementation?)`
Expand Down
Expand Up @@ -343,110 +343,220 @@ describe('isolateModules', () => {
});

describe('isolateModulesAsync', () => {
it('keeps its registry isolated from global one', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
exports.increment();
expect(exports.getState()).toBe(2);
describe('with sync callback', () => {
it('keeps its registry isolated from global one', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
exports.increment();
expect(exports.getState()).toBe(2);

await runtime.isolateModulesAsync(() => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});

await runtime.isolateModulesAsync(async () => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
expect(exports.getState()).toBe(2);
});

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(2);
});
it('resets all modules after the block', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
await runtime.isolateModulesAsync(() => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
exports.increment();
expect(exports.getState()).toBe(2);
});

it('resets all modules after the block', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
await runtime.isolateModulesAsync(async () => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
exports.increment();
expect(exports.getState()).toBe(2);
});

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});
it('resets module after failing', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
await expect(
runtime.isolateModulesAsync(() => {
throw new Error('Error from isolated module');
}),
).rejects.toThrow('Error from isolated module');

await runtime.isolateModulesAsync(() => {
expect(true).toBe(true);
});
});

it('resets module after failing', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
it('cannot nest isolateModulesAsync blocks', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
await expect(async () => {
await runtime.isolateModulesAsync(async () => {
await runtime.isolateModulesAsync(() => {});
});
}).rejects.toThrow(
'isolateModulesAsync cannot be nested inside another isolateModulesAsync or isolateModules.',
);
});
await expect(
runtime.isolateModulesAsync(async () => {
throw new Error('Error from isolated module');
}),
).rejects.toThrow('Error from isolated module');

await runtime.isolateModulesAsync(async () => {
expect(true).toBe(true);
it('can call resetModules within a isolateModules block', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
await runtime.isolateModulesAsync(() => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);

exports.increment();
runtime.resetModules();

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});
});

it('cannot nest isolateModulesAsync blocks', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
await expect(async () => {
describe('with async callback', () => {
it('keeps its registry isolated from global one', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
exports.increment();
expect(exports.getState()).toBe(2);

await runtime.isolateModulesAsync(async () => {
await runtime.isolateModulesAsync(() => Promise.resolve());
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});
}).rejects.toThrow(
'isolateModulesAsync cannot be nested inside another isolateModulesAsync or isolateModules.',
);
});

it('can call resetModules within a isolateModules block', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(2);
});
let exports;
await runtime.isolateModulesAsync(async () => {

it('resets all modules after the block', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
await runtime.isolateModulesAsync(async () => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
exports.increment();
expect(exports.getState()).toBe(2);
});

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});

exports.increment();
runtime.resetModules();
it('resets module after failing', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
await expect(
runtime.isolateModulesAsync(async () => {
throw new Error('Error from isolated module');
}),
).rejects.toThrow('Error from isolated module');

await runtime.isolateModulesAsync(async () => {
expect(true).toBe(true);
});
});

it('cannot nest isolateModulesAsync blocks', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
await expect(async () => {
await runtime.isolateModulesAsync(async () => {
await runtime.isolateModulesAsync(() => Promise.resolve());
});
}).rejects.toThrow(
'isolateModulesAsync cannot be nested inside another isolateModulesAsync or isolateModules.',
);
});

it('can call resetModules within a isolateModules block', async () => {
const runtime = await createRuntime(__filename, {
moduleNameMapper,
});
let exports;
await runtime.isolateModulesAsync(async () => {
exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);

exports.increment();
runtime.resetModules();

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});

exports = runtime.requireModuleOrMock(
runtime.__mockRootPath,
'ModuleWithState',
);
expect(exports.getState()).toBe(1);
});

describe('can use isolateModulesAsync from a beforeEach block', () => {
Expand Down
7 changes: 2 additions & 5 deletions packages/jest-runtime/src/index.ts
Expand Up @@ -1141,7 +1141,7 @@ export default class Runtime {
}
}

async isolateModulesAsync(fn: () => Promise<void>): Promise<void> {
async isolateModulesAsync(fn: () => Promise<void> | void): Promise<void> {
if (this._isolatedModuleRegistry || this._isolatedMockRegistry) {
throw new Error(
'isolateModulesAsync cannot be nested inside another isolateModulesAsync or isolateModules.',
Expand Down Expand Up @@ -2180,9 +2180,6 @@ export default class Runtime {
this.isolateModules(fn);
return jestObject;
};
const isolateModulesAsync = async (fn: () => Promise<void>) => {
await this.isolateModulesAsync(fn);
};
const fn = this._moduleMocker.fn.bind(this._moduleMocker);
const spyOn = this._moduleMocker.spyOn.bind(this._moduleMocker);
const mocked =
Expand Down Expand Up @@ -2248,7 +2245,7 @@ export default class Runtime {
getTimerCount: () => _getFakeTimers().getTimerCount(),
isMockFunction: this._moduleMocker.isMockFunction,
isolateModules,
isolateModulesAsync,
isolateModulesAsync: this.isolateModulesAsync,
mock,
mocked,
now: () => _getFakeTimers().now(),
Expand Down
1 change: 1 addition & 0 deletions packages/jest-types/__typetests__/jest.test.ts
Expand Up @@ -99,6 +99,7 @@ expectType<typeof jest>(jest.isolateModules(() => {}));
expectError(jest.isolateModules());

expectType<Promise<void>>(jest.isolateModulesAsync(async () => {}));
expectType<Promise<void>>(jest.isolateModulesAsync(() => {}));
expectError(jest.isolateModulesAsync());

expectType<typeof jest>(jest.mock('moduleName'));
Expand Down

0 comments on commit 36c138e

Please sign in to comment.