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 all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
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
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
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);
});
14 changes: 14 additions & 0 deletions e2e/test-environment/DocblockPragmasEnvironment.js
@@ -0,0 +1,14 @@
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.

'use strict';

const JSDOMEnvironment = require('jest-environment-jsdom');

class TestEnvironment extends JSDOMEnvironment {
constructor(config, context) {
super(config, context);
this.global.myCustomPragma = context.docblockPragmas['my-custom-pragma'];
}
}

module.exports = TestEnvironment;
4 changes: 2 additions & 2 deletions e2e/test-environment/EsmDefaultEnvironment.js
Expand Up @@ -11,8 +11,8 @@ 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';
}
}
Expand Down
10 changes: 10 additions & 0 deletions e2e/test-environment/__tests__/docblockPragmas.test.js
@@ -0,0 +1,10 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* @jest-environment ./DocblockPragmasEnvironment.js
* @my-custom-pragma pragma-value
*/

test('docblock pragmas', () => {
expect(myCustomPragma).toEqual('pragma-value'); // eslint-disable-line no-undef
});
14 changes: 8 additions & 6 deletions packages/jest-environment/src/index.ts
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
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