14

Before you point it out, yes, I know this seems like a likely duplicate of multiple questions like;

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

skyboyer
  • 15,149
  • 4
  • 41
  • 56
sgarcia.dev
  • 4,375
  • 11
  • 33
  • 57
  • 1
    Try wrapping the test case body into a try-catch block, and put done in finally. That might help with the timeout. – Herman Starikov Jul 08 '18 at 01:38
  • 1
    If I was in your situation I would post it as a bug at https://github.com/facebook/jest/issues. If it is not a bug, the people with extensive knowledge about jest will be able to point it out. – EECOLOR Jul 09 '18 at 07:32
  • I have never seen async functions used together with the 'done' callback, I think you should use one or the other. Also, have you tried setting the timeout directly to jasmine as shown in the last issue you have linked like this `jasmine.DEFAULT_TIMEOUT_INTERVAL = `? – Giorgio Tempesta Jul 09 '18 at 16:11
  • I opened a jest issue 15 days ago on this but got no response yet, https://github.com/facebook/jest/issues/6557 – sgarcia.dev Jul 11 '18 at 16:15
  • @skyboyer can you make suer NodeJS version on Jenkins is the same as on your local machine? Also, make sure the browser can be started in Jenkins! – Mike G. Sep 21 '20 at 14:45

1 Answers1

2

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 :-)

Thatkookooguy
  • 5,356
  • 1
  • 24
  • 47