Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally run tests in Jest

I've been playing around comparing the functional paradigm and the object-oriented paradigm.

As part of this - I'm wanting to do some performance tests.

I have some tests that look like this for now:

it("Some long running performance test", () => {
    const result = myFunctionWithLotsOfData();       
}); 

For now, I'm just printing how long this code takes to run (around 5000ms).

I like using Jest for all of the assertions and mocking functionality it gives, and it's live reload, etc.

However, I don't want these tests to all the time, I'd run create a npm script like npm test:performance, and only run these tests if an environment variable is present or similar.

What's the best way to do this?

like image 753
dwjohnston Avatar asked Oct 07 '19 06:10

dwjohnston


4 Answers

const itif = (condition) => condition ? it : it.skip;

describe('suite name', () => {
  itif(true)('test name', async () => {
    // Your test
  });
});
like image 55
Damir Manapov Avatar answered Oct 03 '22 02:10

Damir Manapov


Along the same lines as the accepted answer:

const maybe = process.env.JEST_ALLOW_INTEG ? describe : describe.skip;
maybe('Integration', () => {
  test('some integration test', async () => {
    expect(1).toEqual(1);
    return;
  });
});
like image 26
Or Gal Avatar answered Oct 03 '22 03:10

Or Gal


A small variation on the accepted post, but if we combine Jest's test.skip(...) with the kind of blind argument forwarding that modern JS allows thanks to the spread operator, we can get a cleaner solution that conditionally runs tests, while letting Jest know it skipped something "the official way", without needing a "functionfunction" call:

const testIf = (condition, ...args) =>
  condition ? test(...args) : test.skip(...args);

describe(`a mix of tests and conditional tests`, () => {
  test(`this will always run`, () => {
    expect("1").toBe("1");
  });

  testIf(Math.random() > 0.5, `this will only run half the time`, () => {
    expect("2").toBe("2");
  });
});

Half the time this will run as:

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.451 s, estimated 1 s

And half the time it will show:

Test Suites: 1 passed, 1 total
Tests:       1 skipped, 1 passed, 2 total
Snapshots:   0 total
Time:        0.354 s, estimated 1 s

But to cover the part that no one seems to have included in their answers, we can use this to skip over long-running tests by combining it with "looking at process.argv for a runtime flag":

const runLong = process.argv.includes(`--run-long`);

const testIf = (condition, ...args) =>
  condition ? test(...args) : test.skip(...args);

describe(`Run tests, and long tests only if told to`, () => {

  // ...

  testIf(runLong, `Some long-running test, skip if --run-long is not set`, () => {
    // a test that runs for a long time here
  });
});

And then we can just put that runtime flag in our npm script. However, we need to make sure to forward that flag on to our script, rather than to jest, or to npm:

...
"scripts": {
  ...
  "test": "jest somedir",
  "test:long": "npm run test -- -- --run-long",
  ...
},
...

This looks kind of weird, and it is kind of weird, but it's a consequence of how argument forwarding works for npm scripts:

  1. The first -- tells npm that it needs to forward what follows, rather than interpreting that flag itself (in effect: this makes npm run jest somedir -- --run-long).
  2. The second -- tells jest that it needs to forward what follows, instead of considering it a runtime flag for itself, so that our script gets to see it in its process.argv list (so that we call ourscript --run-long).

A common mistake is to forget that second --, which would lead to a fun error that doesn't tell you that just forgot two dashes, and no tests running at all.

like image 44
Mike 'Pomax' Kamermans Avatar answered Oct 03 '22 02:10

Mike 'Pomax' Kamermans


Here is one solution, create itif function so that we can run the unit tests based on some conditions.

For example, the itif function:

export const itif = (name: string, condition: () => boolean | Promise<boolean>, cb) => {
  it(name, async done => {
    if (await condition()) {
      cb(done);
    } else {
      console.warn(`[skipped]: ${name}`);
      done();
    }
  });
};

The unit tests:

describe('test suites', () => {
  itif(
    'functional-approach-2 perforance test',
    async () => process.env.PERFORMANCE_TEST === 'true',
    done => {
      console.info('Functional Approach 2 Performance Test');
      const t0 = Date.now();
      const m0 = getMemory();
      const li0 = instantiateFanRecursive(20, 2, 0, 0, 1, 1, 2, 1);
      const r0 = getDrawablesFromLineInstances(li0);
      printMemory(getMemory() - m0);
      console.info(`Length: ${r0.length}`);
      console.info(`Time Taken: ${Date.now() - t0}ms`);
      done();
    }
  );
});

Run your unit test when the value of process.env.PERFORMANCE_TEST environment variable equal 'true', the result:

PERFORMANCE_TEST=true npm t -- /Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/58264344/index.spec.t

> [email protected] test /Users/elsa/workspace/github.com/mrdulin/jest-codelab
> jest --detectOpenHandles "/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/58264344/index.spec.ts"

 PASS  src/stackoverflow/58264344/index.spec.ts
  test suites
    ✓ functional-approach-2 perforance test (18ms)

  console.info src/stackoverflow/58264344/index.spec.ts:22
    Functional Approach 2 Performance Test

  console.log src/stackoverflow/58264344/index.spec.ts:4
    0

  console.info src/stackoverflow/58264344/index.spec.ts:28
    Length: 0

  console.info src/stackoverflow/58264344/index.spec.ts:29
    Time Taken: 5ms

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.67s, estimated 9s

Do not run the unit test when the value of process.env.PERFORMANCE_TEST environment variable is not set:

npm t -- /Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/58264344/index.spec.ts

> [email protected] test /Users/elsa/workspace/github.com/mrdulin/jest-codelab
> jest --detectOpenHandles "/Users/elsa/workspace/github.com/mrdulin/jest-codelab/src/stackoverflow/58264344/index.spec.ts"

 PASS  src/stackoverflow/58264344/index.spec.ts
  test suites
    ✓ functional-approach-2 perforance test (11ms)

  console.warn src/stackoverflow/58264344/index.spec.ts:11
    [skipped]: functional-approach-2 perforance test

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.758s, estimated 5s
like image 32
slideshowp2 Avatar answered Oct 03 '22 03:10

slideshowp2