Last active
September 24, 2019 08:29
-
-
Save zeropaper/7e92442c5a282fda8616ab797f524cdc to your computer and use it in GitHub Desktop.
puppeteer tips and tricks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const renderScreenshot = ({ | |
title = '', | |
slug = '', | |
pageIndex = 0, | |
screenshotPath = '', | |
description = '', | |
}) => `<figure id="${slug}-${pageIndex}"> | |
<img src="${screenshotPath}" title="${title}" /> | |
<figcaption>${description}</figcaption> | |
</figure>`; | |
const renderSection = ({ | |
title = '', | |
slug = '', | |
screenshots = [], | |
}) => `<section id="${slug}"> | |
<header> | |
<h1>${title}</h1> | |
</header> | |
<div class="content"> | |
<div class="screenshots"> | |
${screenshots.map(renderScreenshot).join('\n')} | |
</div> | |
<div class="description"> | |
</div> | |
</div> | |
</div> | |
</section>`; | |
module.exports = async ({ | |
title = 'Documentation', | |
info = {}, | |
} = {}) => `<html> | |
<head> | |
<title>${title}</title> | |
<style> | |
section .content { | |
display: flex; | |
} | |
section .screenshots, | |
section .description { | |
flex-grow: 1; | |
width: 50%; | |
} | |
section figure, | |
section img { | |
max-width: 100%; | |
} | |
</style> | |
</head> | |
<body> | |
<header> | |
<h1>${title}</h1> | |
</header> | |
${info.map(renderSection).join('\n')} | |
</body> | |
</html>`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
const NodeEnvironment = require('jest-environment-node'); | |
const puppeteer = require('puppeteer'); | |
const path = require('path'); | |
const rimraf = require('rimraf'); | |
const mkdirp = require('mkdirp'); | |
const httpServer = require('http-server'); | |
const { promisify } = require('util'); | |
const { writeFile: fsWriteFile } = require('fs'); | |
const documentationTemplate = require('./e2e.documentation-template'); | |
const writeFile = promisify(fsWriteFile); | |
const slugify = str => str | |
.trim() | |
.toLowerCase() | |
.split(/[^a-z0-9]+/g) | |
.join('-'); | |
const { | |
TEST_KEEP_BROWSER, | |
NODE_WATCH, | |
HEADLESS, | |
JEST_SERVE, | |
SLOWMO, | |
} = process.env; | |
const watching = (!!TEST_KEEP_BROWSER || !!NODE_WATCH) && !HEADLESS; | |
const docsOutputDir = path.resolve(__dirname, '../test-results/docs'); | |
const processDocsScreenshot = ({ | |
title, | |
slug, | |
testPages, | |
number, | |
}) => async ({ | |
pageIndex = 0, | |
description = '', | |
}) => { | |
const screenshotPath = path | |
.join(docsOutputDir, 'screenshots', `${number}-${pageIndex}-${slug}.png`); | |
await testPages[pageIndex].screenshot({ | |
path: screenshotPath, | |
}); | |
return { | |
title, | |
slug, | |
pageIndex, | |
screenshotPath: path.relative(docsOutputDir, screenshotPath), | |
description, | |
}; | |
}; | |
class PuppeteerEnvironment extends NodeEnvironment { | |
async setup() { | |
await super.setup(); | |
this.counter = 0; | |
this.docsInfo = []; | |
if (!watching || JEST_SERVE) { | |
this.server = httpServer.createServer({ root: path.resolve(__dirname, '../build') }); | |
await new Promise((res, rej) => this.server.listen(5000, err => (err ? rej(err) : res()))); | |
} | |
rimraf.sync(docsOutputDir); | |
mkdirp.sync(path.join(docsOutputDir, 'screenshots')); | |
const commonOptions = { | |
headless: !watching, | |
slowMo: (!watching || SLOWMO) ? parseInt(SLOWMO || 20, 10) : 0, | |
}; | |
this.global.testSlowMo = commonOptions.slowMo; | |
this.global.testWatching = commonOptions.watching; | |
const browser = await puppeteer.launch({ | |
...commonOptions, | |
}); | |
this.global.testPages = [ | |
await browser.newPage(), | |
]; | |
this.global.writeDocs = async ({ | |
info = {}, | |
screenshots = [], | |
} = {}) => { | |
const { | |
title = 'Missing title', | |
description = '', | |
} = info; | |
const generated = { | |
title, | |
description, | |
screenshots: await Promise | |
.all(screenshots | |
.map(processDocsScreenshot({ | |
title, | |
slug: slugify(title), | |
testPages: this.global.testPages, | |
number: this.docsInfo.length, | |
}))), | |
}; | |
this.docsInfo.push(generated); | |
}; | |
} | |
async teardown() { | |
await new Promise(res => setTimeout(res, 200 * (this.global.slowMo + 1))); | |
if (!TEST_KEEP_BROWSER) { | |
await Promise.all((this.global.testPages || []) | |
.map(async (page) => { | |
try { | |
const br = await page.browser(); | |
await closePage(br, page); | |
await br.close(); | |
} catch (err) { | |
console.warn(err.message); | |
} | |
})); | |
} | |
await writeFile(path.join(docsOutputDir, 'index.html'), await documentationTemplate({ | |
title: 'Mesh Documenation', | |
info: this.docsInfo, | |
}), 'utf8'); | |
if (this.server) this.server.close(); | |
await super.teardown(); | |
} | |
runScript(script) { | |
return super.runScript(script); | |
} | |
} | |
module.exports = PuppeteerEnvironment; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = { | |
testMatch: ['**/test/**/*e2e.test.js'], | |
testRegex: null, | |
verbose: true, | |
testEnvironment: absPath('./e2e.environment.js'), | |
setupFiles: [ | |
absPath('./e2e.init'), | |
], | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
describe('Some interaction', () => { | |
// … do something | |
await writeDocs({ | |
info: { | |
title: 'Title of the "step"', | |
}, | |
screenshots: [ | |
{ | |
pageIndex: 0, | |
description: 'The connection is established and the chat opens on Alice\'s app.', | |
}, | |
{ | |
pageIndex: 1, | |
description: 'As well as Bernard\'s.', | |
}, | |
], | |
}); | |
// … continue and do something else | |
await writeDocs({ | |
info: { | |
title: 'An other "step"', | |
}, | |
screenshots: [ | |
{ | |
pageIndex: 0, | |
description: 'Alice sends a message.', | |
}, | |
], | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment