jest-puppeteer
jest-puppeteer copied to clipboard
Keep browser opened on failure
As suggested in #38, the idea is to intercept a test failure and stop the browser. It is not an easy task and it needs some research. Jest does not provide any API to intercept a test failure, so we have to hack it.
Maybe Jest team could help us to achieve that? @SimenB
#43 could also help to find a solution for this.
Jest does not provide any API to intercept a test failure, so we have to hack it.
What do you mean? Right now we just throw (unless you use done
callback), so you could just replace test
with your own function with built in try-catch
I think?
Or do you want us to have a function on e.g. testEnvironment
's where it can intercept errors and either forward or swallow them?
I think it would be better to be able to intercept an error in the test environment. I don’t want to invent another method than « it » and « test ». I could patch them but if every Jest plugin do it, it will become a jungle.
So your advice for now is to patch « it » and « test »?
For now, yeah. You can open up a feature request with jest if you want, but I'm not sure if it'll be accepted. Some examples of the API you envision would be nice :)
I've tried to wrap « it » with the following function:
global.makeSure = (description, func) => {
return it(description, async () => {
try {
await func();
} catch (e) {
console.log(page);
await page.screenshot({ path: `screenshot.png` });
}
});
};
The page object is accessible but I'm unable to take a screenshot (page._closed is true at this point). Is there any way around it?
// jest.setup.js
global.it = async function(name, func) {
return await test(name, async () => {
try {
await func();
} catch (e) {
await fs.ensureDir('e2e/screenshots');
await page.screenshot({ path: `e2e/screenshots/${name}.png` });
throw e;
}
});
};
We got an traction on this guys?
// jest.setup.js global.it = async function(name, func) { return await test(name, async () => { try { await func(); } catch (e) { await fs.ensureDir('e2e/screenshots'); await page.screenshot({ path: `e2e/screenshots/${name}.png` }); throw e; } }); };
This works great for taking screenshots! thx @celador
for typescript users:
// jest.setup.ts
import { ensureDir } from "fs-extra";
declare global {
namespace NodeJS {
interface Global {
it: (name: any, func: any) => Promise<void>;
}
}
}
global.it = async function(name, func) {
return await test(name, async () => {
try {
await func();
} catch (e) {
await ensureDir("screenshots");
await page.screenshot({ path: `screenshots/${name}.png` });
throw e;
}
});
};
That works perfectly fine, the only question I have, after I start using that function for screenshots generation, i can't use it.only in tests, getting error it.only is not a function
. Maybe someone knows what's wrong? I'm using Jest
That works perfectly fine, the only question I have, after I start using that function for screenshots generation, i can't use it.only in tests, getting error
it.only is not a function
. Maybe someone knows what's wrong? I'm using Jest
I suppose it is not chaining methods. Try this https://stackoverflow.com/questions/44446626/run-only-one-test-with-jest
v25.3.0 (released 15 minutes ago) includes https://github.com/facebook/jest/pull/9397 which should unblock both this and #131 without hacks. Note that it only works with jest-circus
, not the default jest-jasmine2
runner. We'll be swapping the default in Jest 26, but for now jest-circus
is opt-in
@SimenB is there a solution for this problem as of today? I understand Jest now provides the necessary functionalities but I don't understand if jest-puppeteer makes use of them.
@Mahanchello you can do the following instead
global.it = Object.assign(async (name, func, timeout) => {
return await test(name, async () => {
try {
await func();
} catch (e) {
if (page) {
try {
await page.screenshot({path: `screenshots/${name}.png`});
} catch (e) {
console.error(e)
}
}
throw e;
}
}, timeout);
}, test)
@sjurgis what if page is closed at that time? How can we get the screenshot?
@rajeshkumarp I guess not. Only wanted to try this solution because I was reluctant to try jest-circus.
I've now switched to it and it's much easier and works better (we're actually using Playwright, not Puppeteer). It was as easy as adding testEnvironment: "./jest.environment.js",
and preset: "jest-playwright-preset",
to our jest.config.js and then
const PlaywrightEnvironment = require('jest-playwright-preset/lib/PlaywrightEnvironment').default
class CustomEnvironment extends PlaywrightEnvironment {
async handleTestEvent(event) {
if (event.name === 'test_done' && event.test.errors.length > 0) {
const parentName = event.test.parent.name.replace(/\W/g, '-')
const specName = event.test.name.replace(/\W/g, '-')
try {
const url = this.global.page.url()
if (this.global.page && url && url !== 'about:blank') {
await this.global.page.screenshot({
path: `screenshots/${parentName}_${specName}.png`,
})
}
} catch (e) {
console.error(e)
}
}
}
}
module.exports = CustomEnvironment
Why not simply use a very long timer to prevent the browser from closing?
It will not happen. But we will take a screenshot.