Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass docblock pragmas to TestEnvironment constructor. #8320

Merged
merged 7 commits into from
Apr 13, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### Features

- `[expect]` Improve report when matcher fails, part 15 ([#8281](https://github.com/facebook/jest/pull/8281))
- `[jest-runner]` Pass docblock pragmas to TestEnvironment constructor ([#8320](https://github.com/facebook/jest/pull/8320))

### Fixes

Expand Down
12 changes: 10 additions & 2 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,8 @@ test('use jsdom in this test file', () => {

You can create your own module that will be used for setting up the test environment. The module must export a class with `setup`, `teardown` and `runScript` methods. You can also pass variables from this module to your test suites by assigning them to `this.global` object – this will make them available in your test suites as global variables.

Any docblock pragmas in test files will be passed to the environment constructor and can be used for per-test configuration. If the pragma does not have a value, it will be present in the object with it's value set to an empty string. If the pragma is not present, it will not be present in the object.

_Note: TestEnvironment is sandboxed. Each test suite will trigger setup/teardown in their own TestEnvironment._

Example:
Expand All @@ -870,15 +872,21 @@ Example:
const NodeEnvironment = require('jest-environment-node');

class CustomEnvironment extends NodeEnvironment {
constructor(config, context) {
constructor(config, {testPath, docblockPragmas}) {
super(config, context);
this.testPath = context.testPath;
this.testPath = testPath;
this.docblockPragmas = docblockPragmas;
}

async setup() {
await super.setup();
await someSetupTasks(this.testPath);
this.global.someGlobalObject = createGlobalObject();

// Will trigger if docblock contains @my-custom-pragma my-pragma-value
if (this.docblockPragmas['my-custom-pragma'] === 'my-pragma-value') {
// ...
}
}

async teardown() {
Expand Down
2 changes: 1 addition & 1 deletion e2e/__tests__/testEnvironment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ it('respects testEnvironment docblock', () => {
const {json: result} = runWithJson('test-environment');

expect(result.success).toBe(true);
expect(result.numTotalTests).toBe(2);
expect(result.numTotalTests).toBe(3);
});
5 changes: 3 additions & 2 deletions e2e/test-environment/EsmDefaultEnvironment.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ exports.__esModule = true;
const NodeEnvironment = require('jest-environment-node');

class Env extends NodeEnvironment {
constructor(...args) {
super(...args);
constructor(config, options) {
super(config, options);
this.global.property = 'value';
this.global.myCustomPragma = options.docblockPragmas['my-custom-pragma'];
}
}

Expand Down
5 changes: 5 additions & 0 deletions e2e/test-environment/__tests__/esmDefault.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
* LICENSE file in the root directory of this source tree.
*
* @jest-environment ./EsmDefaultEnvironment.js
* @my-custom-pragma pragma-value
*/
'use strict';

test('access env', () => {
expect(property).toBe('value'); // eslint-disable-line no-undef
});

test('docblock pragmas', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would prefer a distinct test file and Environment impl to separate concerns - this one tests ESM default export support and I wouldn't want docblock pragmas to fail as well if that breaks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

expect(myCustomPragma).toEqual('pragma-value'); // eslint-disable-line no-undef
});
14 changes: 8 additions & 6 deletions packages/jest-environment/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ import {JestFakeTimers as FakeTimers} from '@jest/fake-timers';
type JestMockFn = typeof jestMock.fn;
type JestMockSpyOn = typeof jestMock.spyOn;

export type EnvironmentContext = {
console?: Console;
testPath?: Config.Path;
};
// In Jest 25, remove `Partial` since it's incorrect. The properties are always
// passed, or not. The context itself is optional, not properties within it.
export type EnvironmentContext = Partial<{
console: Console;
docblockPragmas: {[key: string]: string | Array<string>};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the docblock types exported from anywhere? Maybe not worth the dep

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn’t think it was worth the dependency.

testPath: Config.Path;
}>;

// TODO: type this better: https://nodejs.org/api/modules.html#modules_the_module_wrapper
type ModuleWrapper = (...args: Array<unknown>) => unknown;

export declare class JestEnvironment {
constructor(config: Config.ProjectConfig);
constructor(config: Config.ProjectConfig, context: EnvironmentContext);
constructor(config: Config.ProjectConfig, context?: EnvironmentContext);
global: Global.Global;
fakeTimers: FakeTimers<unknown> | null;
moduleMocker: ModuleMocker | null;
Expand Down
5 changes: 3 additions & 2 deletions packages/jest-runner/src/runTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ async function runTestInternal(
context?: TestRunnerContext,
): Promise<RunTestInternalResult> {
const testSource = fs.readFileSync(path, 'utf8');
const parsedDocblock = docblock.parse(docblock.extract(testSource));
const customEnvironment = parsedDocblock['jest-environment'];
const docblockPragmas = docblock.parse(docblock.extract(testSource));
const customEnvironment = docblockPragmas['jest-environment'];

let testEnvironment = config.testEnvironment;

Expand Down Expand Up @@ -144,6 +144,7 @@ async function runTestInternal(

const environment = new TestEnvironment(config, {
console: testConsole,
docblockPragmas,
testPath: path,
});
const leakDetector = config.detectLeaks
Expand Down