0

I would like to be able to isolate the side effects that seem to be related when testing two functions that modify the same state variable myVar independently of each other.

example.js

export function foobar() {
  sideEffect1();
  sideEffect2();
}

let myVar;

function sideEffect1() {
  if (myVar === undefined) {
    myVar = 'foo';
  }
}

function sideEffect2() {
  if (myVar === undefined) {
    myVar = 'bar';
  }
}

example.test.js

import example, {return2} from "../src/example";

test('Test Side Effect 1', () => {
  let se = example.__get__('sideEffect1');
  se();
  let myVar = example.__get__('myVar');
  expect(myVar).toBe("foo");
});


test('Test Side Effect 2', () => {
  let se = example.__get__('sideEffect2');
  se();
  let myVar = example.__get__('myVar');
  expect(myVar).toBe("bar");
});

Output

> jest "js/tests/example.test.js"

 FAIL  js/tests/example.test.js (6.056 s)
  ✓ Test Side Effect 1 (1 ms)
  ✕ Test Side Effect 2 (4 ms)

  ● Test Side Effect 2

    expect(received).toBe(expected) // Object.is equality

    Expected: "bar"
    Received: "foo"

      23 |   se();
      24 |   let myVar = example.__get__('myVar');
    > 25 |   expect(myVar).toBe("bar");
         |                 ^
      26 | });
      27 | 
      28 | 

If I run each test separately, both work ok. The problem seems to be when running the whole test suite. This is a simplification of the same problem that I have in a code that use in a more complex application. Any ideas why and how can it be solved?

babel.config.json

{
  "presets": ["@babel/preset-env"],
  "plugins": ["babel-plugin-rewire"]
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
DraQ
  • 340
  • 2
  • 13
  • a) don't use stateful modules b) have a function to initialise the variable to an arbitrary state, and reset it before each test c) evict the module from the cache and re-`require` it. – Bergi Dec 21 '20 at 20:11
  • If you're using `rewire` already (are you not?), then just use `__set__`! – Bergi Dec 21 '20 at 20:13
  • Yes I'm using rewire (with babel), I've just added the config options. I could manually reset that variable through __set__ then. Is it good practice to do so? Regarding the "state" it is a design consideration since the original code, that variable is used to hold the current state for an operation during a session with the browser. Does your observation about it still applies? is there something else to improve or it was a workaround just for the test? thx! – DraQ Dec 21 '20 at 20:50
  • Regarding using set, you mean doing this? `example.__set__('sideEffect1', "myCustomValue")` I'm not being able to reset the value of the variable in question in this way. – DraQ Dec 21 '20 at 21:26
  • I'd say the best practice would be to move the state in a `Session` class that you'd instantiate once in your application and multiple times in the tests. But if it's really a global browser-window state, putting it in the module might be fine. You just need to be able to reset it for tests (and maybe also for some kind of log out functionality). The tests will become integration tests, not unit tests. – Bergi Dec 22 '20 at 09:37
  • I haven't used rewire before, but doesn't `example.__set__('myVar', undefined)` work? – Bergi Dec 22 '20 at 09:38

1 Answers1

0

Modules are loaded at the start of the execution and loaded as one - so yours example.js is executed properly, whichever function is executed first sideEffect1 or sideEffect2 this function sets the variable myVar and you then get this variable value

Seti
  • 2,169
  • 16
  • 26