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?
const itif = (condition) => condition ? it : it.skip;
describe('suite name', () => {
itif(true)('test name', async () => {
// Your test
});
});
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;
});
});
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");
});
});
or here's the typescript version
const testIf = (condition: boolean, ...args: Parameters<typeof test>) =>
condition ? test(...args) : test.skip(...args);
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:
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).
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.
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
> jest-codelab#1.0.0 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
> jest-codelab#1.0.0 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
Related
I want my test suite to work as if it was on Windows platform. Unfortunately, a lot of dependencies use path module. I want to mock it with path.win32 implementation. However, this approach doesn't work:
const winPath = require("path").win32;
jest.mock("path", () => winPath);
ReferenceError: Cannot access 'winPath' before initialization
What is the proper way to do this?
jest.mock() should work. The below example shows how to mock the win32.normalize() method.
const winPath = require("path").win32;
jest.mock('path', () => {
return {
...(jest.requireActual('path') as typeof import('path')),
win32: {
normalize: jest.fn(),
}
}
})
describe('74717157', () => {
test('should pass', () => {
winPath.normalize.mockImplementation(() => 'override the original implementation')
expect(jest.isMockFunction(winPath.normalize)).toBeTruthy();
expect(winPath.normalize()).toBe('override the original implementation')
})
})
Test result:
PASS stackoverflow/74717157/index.test.ts (10.557 s)
74717157
✓ should pass (1 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 14.116 s
I was writing an automatic test framework with Jest. For this, I need to run some background tasks under certain intervals. In summary, this is like polling. Let's give an example with a pseudo code.
test('Some potato poteto test', () => {
jest.setTimeout(12000000); // 20 min
const intervalPeriod = 5 * 60 * 1000; // 5 min
let retry = 0;
const intervalId = setInterval(() => {
console.log("I am doing my 5 minutes check");
// my custom logic goes here
retry++;
if(retry === MAX_RETRY) { // this will be always hit
clearInterval(intervalId)
}
}, intervalPeriod);
});
So, in every 5 mins, I'll make a network call, do some of my custom logic. Now, the problem is while running this, the test finished but jest can't terminate.
By 'test-finished' I meant, test suite ran, but the code inside the setInterval does not get executed right then.
My question is, does this happen because setInterval does not run immediately in the event-loop and is jest not configured to run a setInterval?
Please note that I don't want to mock the setInterval and also I don't want to use any fake timer.
Therefore, is it possible to achieve this with Jest?
I also tried the same thing with the cron library for node but it is the same issue. Jest does not execute the code and finish executing then halted because those setInterval/cron are still running in the background.
Is there a way to run those tasks inside Jest? I mean is there a way to run those jobs and when they are done then terminate Jest?
That's intended, Jest execute all the test instructions and quit the test.
For jest to wait for a computation, you need to use Promises and its async mode.
Doc for Jest async mode: https://jestjs.io/docs/asynchronous
Learn more about Promises here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
And async/await syntax here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
This is a naive way for doing it:
const MAX_RETRY = 3;
const INTERVAL_PERIOD = 5 * 60 * 1000; // 5 min
const SAFETY_TIME = INTERVAL_PERIOD;
const TEST_TIMEOUT = (1 + MAX_RETRY) * INTERVAL_PERIOD + SAFETY_TIME;
test('Some potato poteto test', async () => {
let retry = 0;
let success = false;
function yourLogicFunction(): boolean {
const resultOfYourLogicFunction = retry === MAX_RETRY; // because retry is used in this condition I store the result before changing it
console.log(`this is my attempt number ${retry}`);
retry++;
return resultOfYourLogicFunction;
}
function mockRequest(resolve: (value: unknown) => void): void {
setTimeout(() => resolve(yourLogicFunction()), INTERVAL_PERIOD);
}
while (!success && retry <= MAX_RETRY) {
success = await new Promise(mockRequest) as boolean;
}
}, TEST_TIMEOUT);
The third parameter of test is its timeout.
I have 2 files with 1 function in it. My test is just as simple, see below:
doc.js
export function createSynthId(doc) {
const synthId = `${doc.attachmentId}-${doc.materialId}-${doc.fileName}-${doc.title}-${doc.materialURL}`;
return synthId;
}
doc.test.js
import { createSynthId } from './doc';
describe('doc', () => {
it('create synthetic id', () => {
expect(createSynthId(global.doc)).toEqual('987654-123456-File Name.pptx-undefined-');
});
it('create synthetic id', () => {
expect(createSynthId({})).toEqual('undefined-undefined-undefined-undefined-undefined');
});
});
My second file is virtually the same, just a larger function. Both tests pass, but coverage is being reported at 0% for Statements, Functions, and Lines, but 100% for Branches. The coverage report is showing all the lines red as well.
We have many similar files and they all work. What am I missing here?
UPDATE
I added a temp function to doc.js
export const makeTestsHappy = () => {
console.log(CONFIG);
};
adding to doc.test.js
it('does more', () => {
makeTestsHappy();
});
and when I try to test that, I get the error TypeError: (0 , _doc.makeTestsHappy) is not a function
Dummy over here was mocking the file I was testing. I forgot to jest.unmock('/doc') It immediately started working when I unlocked. Thanks all for your patience :D
Try to rename your test file from doc.test.js to doc.spec.js. You are using the BDD syntax and the correct name should include spec.
I am new to jest unit testing as well as NodeJS and i'm trying to test my API using the following code.
const request = require('supertest');
const quick_registration = require('../../../routes/register/quick_registration_of_user')
describe('Quick Registration of users', () => {
beforeAll(() => {
con.connect();
});
describe("GET / ", () => {
test("It should respond with an array of students", async () => {
const response = await request(quick_registration).get("/api/quickregistration");
expect(response.status).toBe(200);
});
});
})
But the test keep failing and throws me an error
FAIL tests/routes/register/quick_registration_of_user.test.js
Quick Registration of users
GET /
× It should respond with an array of students (20ms)
● Quick Registration of users › GET / › It should respond with an array of students
TypeError: Cannot read property 'apply' of undefined
at node_modules/express/lib/router/index.js:635:15
at next (node_modules/express/lib/router/index.js:260:14)
at Function.handle (node_modules/express/lib/router/index.js:174:3)
at Server.router (node_modules/express/lib/router/index.js:47:12)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.649s, estimated 2s
Ran all test suites.
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
I'm assuming the line
const quick_registration = require('../../../routes/register/quick_registration_of_user')
is requiring the file where you've defined your router. You need to be requiring instead the file where you define your app.
I have several testcases in a suite for testcafe. And when I run this in QA environment say I get a report like this
TC1 -- 5 secs
TC2- 4 secs
TC3- 10 secs
So each test case is taking different time to complete( best case scenario) Now in production also I want the test case to run in the same amount of time say TC1 in Production should not take more than 5 secs, how do I code that in testcafe?
Is there an assertion which will allow me to monitor the test case completion within a particular time? I want full testcase completion, not selector or assertion completion.
I suggest you try the TestCafe Programming Interface. In this case you can separate all your tests into "lists" and add your own "run-done" logic. See the following "one-run" example:
const createTestCafe = require('testcafe');
let testcafe = null;
createTestCafe('localhost', 1337, 1338)
.then(tc => {
testcafe = tc;
const runner = testcafe.createRunner();
const testList = ['tests/fixture1.js', 'tests/func/fixture3.js'];
const runPromise = runner
.src(testList)
.browsers(['chrome'])
.run();
const deadlinePromise = new Promise(resolve => setTimeout(resolve, 10000))
.then(throw new Error('fail'));
return Promise.race(runPromise, deadlinePromise).
})
.then(() => {
// success
})
.catch(() => {
// fail
});