A starter-kit quipped with the minimal requirements for Puppeteer + Jest, making E2E testing a breeze.
$ npm i
$ npm start
$ npm start:headed
- provide wrapped
global.page
instance so that you can start writting your test case immediately.
- A screenshot will be taken for each failed test case, put in
screenshots
folder. (/tmp/screenshots
ifenv.CI
) - Each file will be named by the spec description
- A
json
file named by the spec description will be generated for each failed test case. Contents in the file include:- The current page url
- Spec description
- console messages
Sometimes, we'd like to manipulate more than on browsers in a test case. For example, testing two sided chat. We can do that by:
const { getPageFromBrowser } = require('lib/browserStore')
describe('Demo', () => {
it('manipulates multiple browsers', async ()=> {
const page2 = await getPageFromBrowser('page2')
// do something with `global.page` here
// and do some other thing to `page2` here
await page.goto('...')
await page2.goto('...')
})
})
where the getPageFromBrowser
works as a browser store providing multiple browser references by browserName
:
page1 = await getPageFromBrowser('the-name')
page2 = await getPageFromBrowser('the-name')
page1 === page2 // true
Wrapped global.page
with convenient default options and behaviors which can be overwritten easily when needed
For example, global.page.goto
is with default option waitUntil: networkidle0
and fails with readable erorr message if the returning status code is not 200.
To overwrite it, just
global.page.goto({
waitUntil: 'my-other-desired-options',
myOtherKey: 'my-other-value'
})
The default options/overwritten methods can be modified in lib/pageWrapper
.
page.goto
:waitUntil: 'networkidle0'
, guard status200
page.waitForSelector
:visible: true
page.click
: FirstwaitForSelector
withvisible: true
then click
In e2e testing, it's easy to scatter css selectors all around the code base. This makes maintainance when UI changes a nightmare.
Here we use window driver
layer to mitigate this issue and make the error message more readable at the same time:
before
it('is nasty', async () => {
// do payment
await page.click('.my-first-css-selector')
await page.click('.my-another-css-selector')
await page.click('.my-yet-another-css-selector')
await page.click('.this-drove-me-crazy')
})
after
const { getPageFromBrowser } = require('lib/browserStore')
function createPageDriver (page) {
return wrapErrorHandler({
async doPayment() {
// when UI implementation changed, change here
await page.click('.my-first-css-selector')
await page.click('.my-another-css-selector')
await page.click('.my-yet-another-css-selector')
await page.click('.this-drove-me-crazy')
},
}, 'MyDemoPage')
}
it('is much better', async () => {
// when UI implementation changed, this part won't change if the business logic remains the same
const driver = createPageDriver(page)
await page.doPayment()
})
By adding a layer between business logic and UI details, we can abstract out the UI implementation detail there.
CircleCI config is included!