Mocha: Error Timeout of 2000ms exceeded - javascript

I am trying to seed the database for unit test.
Below is the seed.js file:
.......
const app = require('./app')
const db = app.get('db')
const saveUsersToDB = (done) => {
db.User.bulkCreate(users)
.then(() => (done))
}
module.exports = {saveUsersToDB};
My app.test.js file:
.......
const expect = require('expect')
const request = require('supertest')
const {saveUsersToDB} = require('./seed/seed');
before(saveUsersToDB)
When I run the test below is the error I get:
Express listening on port 3000!
1) "before all" hook: saveUsersToDB
0 passing (2s)
1 failing
1) "before all" hook: saveUsersToDB:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
npm ERR! Test failed. See above for more details.
I thought returning .then(() => (done)) was enough? What am I doing wrong?

By default, Mocha tests have a 2 second timeout (which means that the test needs to be completed in 2 seconds).
You can increase it (in milliseconds) as follows:
this.timeout(5000); // this test can take up to 5 seconds
https://mochajs.org/#timeouts

Because (done) will actually return the function instead of invoking it. In order to call done, you need to write it this way.
.then(() => done())
However, I don't recommend using done along with promises. You just simply need to return the promise then mocha will handle it automatically.
const saveUsersToDB = () => db.User.bulkCreate(users)

I had the same isue. This error promps because the 2 seconds timeout, so if your test needs to connect to ddbb it will most provably surpas it.
What I did was to separate all my tests that needed somme kind of connection to external resources into my integration tests folder and then added the next flag in my package.json test script:
"int-test": "mocha --timeout 15000 tests/integration/**/*.test.js --compilers js:babel-register "
Follow this link for other ways to increase the timeout: mocha timout

Related

Pending operations in playwright on nodejs

I'm trying to get a new page at the moment of clicking on the link:
await test.step(`Step name`, async () => {
const [newPage] = await Promise.all([
context.waitForEvent('page'),
page.click('//span[normalize-space(#title)=\'Bup\']')
]);
}
And I get this page. Further operations with this instance are successful. But after 30 seconds the test ends with the following error:
Timeout of 30000ms exceeded.
Pending operations:
- browserContext.waitForEvent at "path to the file":48:21
- at <unknown>
I will assume that it is related to a promise, but I do not understand what exactly the problem is. Help is needed.
Playwright v14.0, nodejs v16.7.0.
I run the tests with the following command: npx playwright test tests/diag.spec.mjs --headed
A strange observation. When I run it in debug mode, there is no such error
:
PWDEBUG=1 npx playwright test tests/diag.spec.mjs
Ok, I found the answer, but it's a little weird. You need to increase the timeout in the playwright config:
https://github.com/microsoft/playwright/issues/8268
Also you can add test.slow() https://playwright.dev/docs/api/class-test#test-slow

For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves puppeteer and mocha

I'm trying to test my component using mocha and google puppeteer. In my unit test file i'am launching puppeteer browser in before and closing the browser in after function. When i'm running my test file i'm getting following error in
"Before All" hook
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
const puppeteer = require('puppeteer');
const { expect } = require('chai');
const _ = require('lodash');
/* create the global variable by using lodash function */
const globalVariables = _.pick(global, ['browser', 'expect']);
/* configurable options or object for puppeteer */
const opts = {
headless: false,
slowMo: 100,
timeout: 0,
args: ['--start-maximized', '--window-size=1920,1040']
}
/* call the before for puppeteer for execute this code before start testing */
before (async () => {
global.expect = expect;
global.browser = await puppeteer.launch(opts);
});
/* call the function after puppeteer done testing */
after ( () => {
browser.close();
global.browser = globalVariables.browser;
global.expect = globalVariables.expect;
});
Inside the root directory of your unit test cases, where the test files are kept, add a mocha.opts file, and add --timeout 50000 which will set mocha to timeout after 50000 ms.
Right now the default timeout is applied and since the test actions are not getting completed, you're getting this error.

Mocha test not running the `try..finally` clause

I am running my Node.js tests with Mocha. When I add a try..finally clause I expect that Mocha will run the finally bit after the test. It works with errors and exceptions, but not when the test times out.
The tests below show the issue in detail.
describe('try-finally', () => {
it('should run finally with an error', async() => {
console.log('starting')
try {
console.log('started')
throw new Error('Error!')
console.log('finished')
} finally {
console.log('finally!')
}
});
it('should run finally with a timeout', async() => {
console.log('starting')
try {
console.log('started')
await timeout()
console.log('finished')
} finally {
console.log('finally!')
}
});
});
function timeout() {
return new Promise(ok => {
setTimeout(ok, 10*1000)
})
}
To run the test: save into a file try-finally.js, install Mocha with npm install -g mocha and then run test with mocha --exit try-finally.js. Output:
$ mocha --exit try-finally.js
try-finally
starting
started
finally!
1) should run finally with an error
starting
started
2) should run finally with a timeout
0 passing (2s)
2 failing
1) try-finally
should run finally with an error:
Error: Error!
at Context.it (try-finally.js:9:13)
2) try-finally
should run finally with a timeout:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. /home/alex/devo/batrasio/try-finally.js)
Both tests fail; the first one runs the finally clause and displays "finally!", while the second times out (waits for 10s when the test default timeout is 2s) and does not run the finally clause.
A couple of searches on Google and here on Stack Overflow yielded nothing. What am I doing wrong? Is this even possible, or do I need to use the obnoxious beforeEach() and afterEach() functions?
The finally block will run after the contents of the try block, not necessarily the whole test. Things like errors and exceptions are meant to be caught in the try block but with a timeout, the error is thrown by mocha (so outside of your try block).
If you need to run the finally block after the test is finished and it is taking too long, you can change the default timeout by putting
this.timeout(<insert time in ms>);
inside of your it function (or the describe function if you want it to apply to everything).
If you are wanting to do the same thing after every test, then yes the afterEach() function is the way to go.

JEST: "Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.", despite it being already configured

Before you point it out, yes, I know this seems like a likely duplicate of multiple questions like;
JEST: Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout
Got Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout
However, I implemented all 3 fixes suggested;
Use jest.setTimeout() inside the test to set the async timeout
Use the third parameter of test() to pass in an extended async timeout limit
Call the done function when complete
However, when running my jest test on an automated linux machine (Jenkins), it's still throwing the same error. Also, it's worth mentioning this works fine on my MacOS machine running NodeJS v10, while the automated linux machine runs NodeJS V8.8.3 (the latest LTS version)
This is what my jest test looks like;
const webdriverio = require('webdriverio');
const options = {
desiredCapabilities: {
browserName: 'chrome',
chromeOptions: {
args: ["--no-sandbox", "disable-web-security", "--disable-dev-shm-usage"]
}
}
};
const client = webdriverio.remote(options);
beforeEach(async () => {
await client.init();
})
test('Google Search for WebdriverIO has correct title', async (done) => {
jest.setTimeout(30000)
await client.url('https://www.google.com/ncr');
await client.setValue('input[name=q]', 'WebdriverIO');
await client.click('input[value="Google Search"]');
const title = await client.getTitle();
expect(title).toBe('WebdriverIO - Google Search');
done();
}, 30000);
afterEach(async () => {
await client.end();
});
And here is the log I get when I try to run the test;
09:57:19 > jest --config jest.config.js
09:57:19
09:57:20 Installing selenium server ...
09:57:22 Starting selenium server ...
09:57:23 Selenium server started ...
09:57:29 FAIL jest/test/google.spec.js (5.874s)
09:57:29 ��� Google Search for WebdriverIO has correct title (5016ms)
09:57:29
09:57:29 ��� Google Search for WebdriverIO has correct title
09:57:29
09:57:29 Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
09:57:29
09:57:29 at mapper (node_modules/jest-jasmine2/build/queue_runner.js:41:52)
09:57:29
09:57:29 ��� Google Search for WebdriverIO has correct title
09:57:29
09:57:29 A session id is required for this command but wasn't found in the response payload
09:57:29
09:57:29 at new RuntimeError (node_modules/webdriverio/build/lib/utils/ErrorHandler.js:143:12)
09:57:29 at RequestHandler.createOptions (node_modules/webdriverio/build/lib/utils/RequestHandler.js:121:23)
09:57:29 at RequestHandler.create (node_modules/webdriverio/build/lib/utils/RequestHandler.js:212:43)
09:57:29 at Object.url (node_modules/webdriverio/build/lib/protocol/url.js:24:32)
09:57:29 at Object.exec (node_modules/webdriverio/build/lib/helpers/safeExecute.js:28:24)
09:57:29 at Object.resolve (node_modules/webdriverio/build/lib/webdriverio.js:191:29)
09:57:29 at lastPromise.then.resolve.call.depth (node_modules/webdriverio/build/lib/webdriverio.js:486:32)
09:57:29 at _fulfilled (node_modules/q/q.js:854:54)
09:57:29 at self.promiseDispatch.done (node_modules/q/q.js:883:30)
09:57:29 at Promise.promise.promiseDispatch (node_modules/q/q.js:816:13)
09:57:29
09:57:29 Test Suites: 1 failed, 1 total
09:57:29 Tests: 1 failed, 1 total
09:57:29 Snapshots: 0 total
09:57:29 Time: 5.988s, estimated 7s
09:57:29 Ran all test suites.
09:57:29 Killing selenium server ...
Any thoughts on why this could fail while it works fine on my local machine would be greatly appreciated. Also, I tried setting jest.setTimeout inside my Jest global setup file, but it throws jest.setTimeout is not a function;
https://github.com/facebook/jest/issues/3788
I had something similar in my tests. My tests passed fine locally but failed on GitHub Actions.
My problem was that locally, Test tools were already downloaded (in my case, in-memory MongoDB. In your case, the chrome browser), but on the remote environment, they had to download first.
Check your Jenkins logs for your environment downloading chrome, and the test fails before the download reaches 100%. Even if you don't find that, the logs you published in the question kinda hint in that direction, because the log prints out that the timeout is set to 5000ms, even though you set the timeout for the first test to a different value:
Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
This tells me that the part of the test that timed-out, was the part before the test.
To solve this, you need to specifically add a longer timeout to the beforeEach function, where you initialize webdriver. This way, on the first test, when chrome is being downloaded, you'll get enough time to finish downloading chrome. On the next tests, this should not be an issue since chrome is already available.
It's also recommended to actively download the chrome\chromium browser in Jenkins so it will be available even before the test run starts.
So, I suggest you try this:
const webdriverio = require('webdriverio');
const options = {
desiredCapabilities: {
browserName: 'chrome',
chromeOptions: {
args: ["--no-sandbox", "disable-web-security", "--disable-dev-shm-usage"]
}
}
};
const client = webdriverio.remote(options);
beforeEach(async () => {
await client.init();
}, 30000) // <-- This is what you need. not the timeout in the actual test
test('Google Search for WebdriverIO has correct title', async () => {
jest.setTimeout(30000); // you can keep this if you think is needed,
// but I'm pretty sure it's not
await client.url('https://www.google.com/ncr');
await client.setValue('input[name=q]', 'WebdriverIO');
await client.click('input[value="Google Search"]');
const title = await client.getTitle();
expect(title).toBe('WebdriverIO - Google Search');
});
afterEach(async () => {
await client.end();
});
Here's an example of an old run, failing because the in-memory db didn't finish downloading before the timeout. This results in the tests starting even though the database isn't ready yet for use.
After adding the timeout to my beforeEach functions, it stopped happening.
If you're still facing the problem after the suggested fix, feel free to comment on this answer. If this was the correct answer, please don't forget to mark the answer :-)

ReferenceError: You are trying to `import` a file after the Jest environment has been torn down

I have a component that makes use of Animated component from react native. I started writing a test case to simulate onPress of a component, which calls a function that has Animated.timing in it, and setState.
running jest works fine, but the tests never stops running, and one unrelated test case that I've written before never seem to pass now (which passed before).
running jest --watch, I get this error:
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down.
at Function.bezier (node_modules/react-native/Libraries/Animated/src/Easing.js:113:21)
at ease (node_modules/react-native/Libraries/Animated/src/Easing.js:34:24)
at TimingAnimation._easing (node_modules/react-native/Libraries/Animated/src/Easing.js:133:18)
at TimingAnimation.onUpdate (node_modules/react-native/Libraries/Animated/src/animations/TimingAnimation.js:107:45)
RUNS src/__tests__/SlideDownMenu.test.js
/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:114
return _bezier(x1, y1, x2, y2);
^
TypeError: _bezier is not a function
at Function.bezier (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:224:12)
at ease (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:94:21)
at TimingAnimation._easing (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/Easing.js:255:16)
at TimingAnimation.onUpdate (/home/nrion/Desktop/mobile-ui/PriceInsight_app/node_modules/react-native/Libraries/Animated/src/animations/TimingAnimation.js:138:14)
at ontimeout (timers.js:386:11)
at tryOnTimeout (timers.js:250:5)
at Timer.listOnTimeout (timers.js:214:5)
Link to repl
https://repl.it/repls/PartialGrimyMetadata
Environment:
OS: Linux 4.14
Node: 6.14.2
Yarn: 1.7.0
npm: 3.10.10
Watchman: Not Found
Xcode: N/A
Android Studio: Not Found
OK, found a solution.
Should use jest.useFakeTimers()
Note: Put the code above just after import section in your test file.
jest.useFakeTimers()
With above it's extremely important to understand this
jest.useFakeTimers() mocks out setTimeout and other timer functions with mock functions.
If running multiple tests inside of one file or describe block, jest.useFakeTimers(); can be called before each test manually or with a setup function such as beforeEach.
Not doing so will result in the internal usage counter not being reset.
Add "testEnvironment": "jsdom" into jest key in package.json or jest.config.js
"jest": {
"testEnvironment": "jsdom",
"preset": "react-native",
...
taken from: https://stackoverflow.com/a/64567257/728287
I would like to contribute to the answer.
Well let's see the error message
ReferenceError: You are trying to 'import' a file after the Jest environment has been torn down.
Torn down means: Jest already finished running and some part of your code is trying to execute after jest has already finished running the test. This is pretty common on Javascript due to its asynchronous nature.
Sometimes it happens after a promise callback was executed. For example:
import { someProcess } from 'a-library'
task.job().then(result => {
someProcess(result)
})
In the example above, the code imports someProcess from a-library.
If the method job from the task object takes longer than the jest execution, its callback (then() invocation) will run outside jest because jest has already finished running the test. Therefore when someProcess gets executed it will be loaded from a-library so jest will complain that you are trying to load a library after jest has been torn down.
The answer marked as the solution is partially right because calling jest.useFakeTimers() will prevent your code to wait the n seconds you supposed to wait when calling setTime or similar, making your code artificially synchronous.
Making your test await those method calls would help you understand better where the error is being introduced.
The code that worked for me was
describe("Some test set", () => {
let heavyWorkingService = library.workingService();
// We are marking the test function call as async
test(("Name of the test"), async () => {
// we are awaiting heavyWorkingService to finish its job
await heavyWorkingService("some data")
})
})
In my real scenario, my code was getting data from firebase and because I'm not using mocks for this test, it was trying to import firebase after the .get() data read returned. Marking the test as async and calling the method with the await keyword solved my problem
Of course there are a lot of ways to deal with this error, just wanted you to know the true reason behind this error so you can work in the right solution for your tests!
I am using #testing-library/react-native, so what I did is to cleanup in the setup file.
// jest.setup.js
import { cleanup } from '#testing-library/react-native';
afterEach(cleanup);
add the below lines at the very end of the jest test file,
after all, tests are written.
afterAll(() => {
mongoose.connection.close()
})
and also just run a single test file at a time, for example,
> jest --verbose --runInBand -- filename.test.js
None of above works for me. My solution is to add to jest-setup.js file this code:
import { Animated } from 'react-native';
Animated.timing = () => ({
start: () => jest.fn(),
});
Don't forget to include this file to your package.json jest configuration:
...
"jest": {
...,
"setupFiles": [
"<rootDir>/src/tests/jest-setup.js"
]
},
...
I hope it will help anybody
jest.useFakeTimers was not an option for me since it brakes the execution of other libraries I am using.
My workaround was to simply add a delay after each test, so that any async operation has time to complete before Jest environment is torn down:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
describe('Test suite', () => {
// Give time to any async operation to complete after each test
afterEach(async () => {
await sleep(2000);
});
// Also close any pending connection (or related) if any
afterAll(async () => {
await closeConnections();
});
it('My test', async () => {
// Test...
});
});
Of course the delay time must be tuned for your application.
I was getting this issue while testing Apollo with react-native-testing-library.
In this case there were two queries, in a parent and child component. The parent query needed to resolve before the child rendered and fired its query.
The solution was to run the wait() function twice rather than just once. I assume the double-fire is necessary to ensure both queries run. The error message is very opaque though.
test("...", () => {
const rr = render(...);
await wait();
await wait(); // Child query must also run
expect(...);
}
// Wait a tick so the query runs
// https://www.apollographql.com/docs/react/development-testing/testing/#testing-final-state
export async function wait(ms = 0) {
await act(async () => {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
});
}
I'm using #testing-library/react-native. On my test case, I need to call render(<MyComponent/>) twice so I needed to add afterEach(cleanup) that way it fixed the issue.
In my case i was using typeorm and put that code inside my jest.setup.ts
afterAll(async () => {
const connection = getConnection();
connection.close();
});
Just to add my bit to the discussion... Double-check if you have any asynchronous code in your test case.
My case was basically a lack of attention, see:
it('should not allow click', async () => {
const page = await newE2EPage();
await page.setContent(`<my-button disabled></my-button>`);
const component = await page.find('my-button');
// WRONG ! ! ! (since click() is async)
component.click();
// ✅ Correct
await component.click()
...
});
The error message isn't that straightforward to understand (at least it wasn't for me). I hope this helps someone!
I tried adding jest.useFakeTimers() inside my beforeEach() method but it didn't resolve the issue for me.
This jest.mock() call above my test cases was the culprit for me:
jest.mock('axios', () => ({
post: () => Promise.resolve({ data: 'data' }),
}));
Removing it resolved my issue.
Hope this helps someone.
Adding "testEnvironment": "jsdom" in package.json didn't helped in my case.
Then I added in the test file under all imports:
jest.useFakeTimers();
and inside describe but above the first test:
beforeEach(() => {
jest.resetAllMocks();
});
and that solved the problem for me.
IN THIS CASE THE ERROR IS SELF EXPLANATORY:
Maybe a bit late to the party but I just want to help whoever is still struggling with this. As the error says, the problem is that some part of your code is trying to import a module after the test has finished. Check the following code:
it('should do something', () => {
someAsyncFuntion(); // We arent awaiting this function so the test ends before execution
});
const someAsyncFunction = async () => {
const {getByPlaceholderText} = render(<SomeComponent />)
getByPlaceholderText('Some placeholder text')
}
With this code the error will be fired, but why? If we check the code for getByPlaceholderText we will see that it is dynamically importing the TextInput component:
const getTextInputNodeByPlaceholderText = (node, placeholder, options = {}) => {
try {
const {
TextInput
} = require('react-native'); // <--- Here we have our import
const {
exact,
normalizer
} = options;
return (0, _filterNodeByType.filterNodeByType)(node, TextInput) && (0, _matches.matches)(placeholder, node.props.placeholder, normalizer, exact);
} catch (error) {
throw (0, _errors.createLibraryNotSupportedError)(error);
}
};
So as the error says, we are trying to import a module after the test has finished.
Add this into your jest.config.js
timers: "fake",
This helps me to resolve this problem.
My jest.config.js file now looks this way
module.exports = {
preset: "react-native",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
transformIgnorePatterns: [
"node_modules/(?!(#react-native|react-native|react-native-vector-icons)/)",
],
timers: "fake",
};
In the latest versions of Jest use this one
import type { Config } from "jest";
const config: Config = {
preset: "react-native",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
testPathIgnorePatterns: [
"/node_modules/",
"<rootDir>/template",
"Libraries/Renderer",
"RNTester/e2e",
],
transformIgnorePatterns: [
"node_modules/(?!(#react-native|react-native|react-native-vector-icons)/)",
],
fakeTimers: {
enableGlobally: true,
},
verbose: true,
};
export default config;
My project is with ReactNative and TypeScipt
and my Jest config by default is in package.json.
To solve this issue i just had to add "timers": "fake"
"jest": {
"timers": "fake",
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
]}
The reason why you need this was already explained:
Torn down means: Jest already finished running and some part of your code is trying to execute after jest has already finished running the test. This is pretty common on Javascript due to its asynchronous nature.
There's NO need to add "testEnvironment": "jsdom". As people say above; has no sense with ReactNative.
Using jest.useFakeTimers() on top of code after imports, did not work for me.
I found the below solution here
now at least, I do not see the error now but a warning message appeared at the end saying..
A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.
it('your test case', () => {...})
becomes:
it('your test case', async () => {...})
adding async removes the erroring out.
I used jest.useFakeTimers() in beforeEach() method inside test suit of that file
beforeEach(() => {
jest.useFakeTimers();
});
OR
use jest.useFakeTimers() on top of code after imports

Categories