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

Test cannot change process environment #9264

Closed
tsondergaard opened this issue Dec 5, 2019 · 5 comments
Closed

Test cannot change process environment #9264

tsondergaard opened this issue Dec 5, 2019 · 5 comments

Comments

@tsondergaard
Copy link

🐛 Bug Report

It is not possible for a test to set the process environment as node_modules/jest-util/build/installCommonGlobals.js runs node_modules/jest-util/build/createProcessObject.js createProcessEnv() which replaces the real process.env with a fake one. This means that tests cannot communicate with binary/native modules via the environment.

My specific use case is, in a nodejs jest test, a need to set KRB5_CONFIG in the real process environment prior to interacting with the native library MIT krb5 via https://www.npmjs.com/package/gssapi.js.

To Reproduce

Rather than my use case, which requires a third-party binary node module, I will just provide a repro case that uses standard node modules. This example require a system with a bash shell, where it will write output: bar to standard output.

const child = require("child_process");

process.env.foo = "bar";
child.exec("echo -n $foo", (err, stdout, stderr) => {
    console.log(`output: ${stdout}`);
});

If this code is instead moved into a jest test it will just write output: to standard output as the foo variable will only have been set in the jest fake process.env, not in the real (OS level) process environment, so it is not inherited by the process that we start.

In this repro case you can of course just pass the env explicitly as an option to child_process.exec(), but that is besides the point. The point is that process.env changes do not update the real system/OS-level process environment, which prevents communication via the process environment to binary modules.

@tsondergaard tsondergaard changed the title test cannot change process environment Test cannot change process environment Dec 5, 2019
@StringEpsilon
Copy link
Contributor

StringEpsilon commented Feb 27, 2022

Related: #5118

@SimenB
Copy link
Member

SimenB commented Feb 27, 2022

I don't think we're gonna change this as it'll break isolation between tests (and if tests run in different order they might behave differently). When spawning subprocesses (or threads) I think it makes more sense to pass an explicit env anyways.

The point is that process.env changes do not update the real system/OS-level process environment

That doesn't happen anyway, all you're changing in node is the process-local snapshot taken when node spawned

@lazytype
Copy link

lazytype commented Feb 27, 2022

@SimenB Could you expose APIs to change the process environment in specific ways that ensure isolation between tests? For example, expose a function call jest.setTimeZone that:
a) can only be called in a beforeEach or beforeAll and will throw otherwise
b) automatically restore the time zone during the afterEach/afterAll phase

Right now, it's impossible to test that code correctly deals with various time zones such as those that observe Daylight Savings Time without hacks such as #9856 (comment)

@SimenB
Copy link
Member

SimenB commented Feb 27, 2022

The problem is Date only reading the default from env (AFAIK). Unfortunately, I think that'll only be fixed by Temporal: https://tc39.es/proposal-temporal/docs/#Temporal-TimeZone.

If you're stuck with legacy Date, what you could do is write a custom test environment that sent the real process.env through. You'd then opt out of the test isolation, but that might be a tradeoff that's worth it to you.

Another option is to create a test env that allows you to set timezone through config. Jest 28 (currently in alpha) allows you to set config per test file via docblock.

// timeZoneEnvironment.js
const {TestEnvironment} = require('jest-environment-node');

module.exports = class TimeZoneEnv extends TestEnvironment {
  constructor(config, context) {
    super(config, context);

    const timeZoneFromOptions =
      config.projectConfig.testEnvironmentOptions.timezone;

    if (timeZoneFromOptions) {
      process.env.TZ = timeZoneFromOptions;
    }
  }
};
// cairo.test.js
/**
 * @jest-environment ./timeZoneEnvironment.js
 * @jest-environment-options {"timezone": "Africa/Cairo"}
 */

test('dummy', () => {
  console.log(new Date().toString());
});
// new-york.test.js
/**
 * @jest-environment ./timeZoneEnvironment.js
 * @jest-environment-options {"timezone": "America/New_York"}
 */

test('dummy', () => {
  console.log(new Date().toString());
});

Running that prints

 $ yarn jest cairo new-york
 PASS  ./cairo.test.js
  ● Console

    console.log
      Sun Feb 27 2022 21:57:40 GMT+0200 (Eastern European Standard Time)

      at Object.log (cairo.test.js:7:11)

 PASS  ./new-york.test.js
  ● Console

    console.log
      Sun Feb 27 2022 14:57:40 GMT-0500 (Eastern Standard Time)

      at Object.log (new-york.test.js:7:11)


Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.571 s, estimated 1 s
Ran all test suites matching /cairo|york/i.

Note that these tests should then run sequentially since they both mutate the same global process environment

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants