Skip to content

Commit

Permalink
minor #1331 test(deps): replace Zombie by Puppeteer (Kocal)
Browse files Browse the repository at this point in the history
This PR was merged into the main branch.

Discussion
----------

test(deps): replace Zombie by Puppeteer

https://github.com/assaf/zombie is archived since december 2023, and its last release is from 4 years ago.

I've replaced it by https://github.com/puppeteer/puppeteer, a modern and maintained API to run and test code in a **real browser** (zombie used `jsdom`). I had to adapt `requestTestPage` to pass the browser as first argument, because I want to launch the browser **only a single time** (in `before()`).

Commits
-------

39807a7 test(deps): replace Zombie by Puppeteer
  • Loading branch information
Kocal committed Sep 6, 2024
2 parents 5f7df38 + 39807a7 commit 90d4b21
Show file tree
Hide file tree
Showing 8 changed files with 625 additions and 664 deletions.
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ module.exports = {
"rules": {
"quotes": ["error", "double"],
},
},
{
"files": ["test/functional.js"],
"globals": {
// For Puppeteer when calling "page.evaluate()"
"document": "readonly",
},
}
],
};
5 changes: 4 additions & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ jobs:
eslint:
name: ESLint
runs-on: ubuntu-latest

env:
# We don't want Puppeteer to automatically download a browser when dependencies are being installed
PUPPETEER_SKIP_DOWNLOAD: 'true'

steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/testing_apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ jobs:
name: ${{ matrix.app.name }}
runs-on: ubuntu-latest

env:
# We don't want Puppeteer to automatically download a browser when dependencies are being installed
PUPPETEER_SKIP_DOWNLOAD: 'true'

steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"postcss-loader": "^7.0.0 || ^8.1.0",
"preact": "^10.5.0",
"preact-compat": "^3.17.0",
"puppeteer": "^23.2.2",
"sass": "^1.17.0",
"sass-loader": "^16.0.1",
"sinon": "^14.0.0",
Expand All @@ -96,8 +97,7 @@
"vue-loader": "^17.0.0",
"webpack": "^5.72",
"webpack-cli": "^5.1.4",
"webpack-notifier": "^1.15.0",
"zombie": "^6.1.4"
"webpack-notifier": "^1.15.0"
},
"peerDependencies": {
"@babel/core": "^7.17.0",
Expand Down
159 changes: 107 additions & 52 deletions test/functional.js

Large diffs are not rendered by default.

18 changes: 13 additions & 5 deletions test/helpers/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,21 +176,29 @@ class Assert {

/**
*
* @param {import('zombie')} browser
* @param {Array<{ response: import('puppeteer').HTTPResponse}>} loadedResources
* @param {Array} expectedResourcePaths Array of expected resources, but just
* their short filenames - e.g. main.css
* (i.e. without the public path)
* @returns {void}
*/
assertResourcesLoadedCorrectly(browser, expectedResourcePaths) {
assertResourcesLoadedCorrectly(loadedResources, expectedResourcePaths) {
const actualResources = [];
for (let resource of browser.resources) {

for (let resource of loadedResources) {
const url = resource.response.url();

// skip the .html page as a resource
if (resource.request.url.includes('testing.html')) {
if (url.includes('testing.html')) {
continue;
}

// skip the favicon as a resource
if (url.includes('favicon.ico')) {
continue;
}

actualResources.push(resource.request.url);
actualResources.push(url);
}

// prefix each expected resource with its public path
Expand Down
47 changes: 29 additions & 18 deletions test/helpers/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const WebpackConfig = require('../../lib/WebpackConfig');
const parseRuntime = require('../../lib/config/parse-runtime');
const webpack = require('webpack');
const fs = require('fs-extra');
const Browser = require('zombie');
const httpServer = require('http-server');
const configGenerator = require('../../lib/config-generator');
const validator = require('../../lib/config/validator');
Expand Down Expand Up @@ -142,18 +141,22 @@ function stopAllServers() {
* makes a request to it, and executes a callback, passing that
* the Browser instance used to make the request.
*
* @param {import('puppeteer').Browser} browser Puppeteer browser instance
* @param {string} webRootDir Directory path (e.g. /path/to/public) where the web server should be rooted
* @param {Array} scriptSrcs Used to create <script src=""> tags.
* @param {Function} callback Called after the page was requested.
* @returns {void}
* @param {function({
* page: import('puppeteer').Page,
* loadedResources: Array<{ response: import('puppeteer').HTTPResponse }>}
* ): void} callback Called after the page was requested.
* @returns {Promise<void>}
*/
function requestTestPage(webRootDir, scriptSrcs, callback) {
async function requestTestPage(browser, webRootDir, scriptSrcs, callback) {
var scripts = '';
for (let scriptSrc of scriptSrcs) {
scripts += `<script src="${scriptSrc}"></script>`;
}

const testHtml = `
const testHtml = `<!DOCTYPE html>
<html>
<head>
</head>
Expand All @@ -175,23 +178,31 @@ function requestTestPage(webRootDir, scriptSrcs, callback) {
// start a secondary server - can be used as the "CDN"
startHttpServer('8090', webRootDir);

const browser = new Browser();
browser.silent = true;
browser.on('error', function(error) {
throw new Error(`Error when running the browser: ${error}`);
const loadedResources = [];

const context = await browser.createBrowserContext();
const page = await context.newPage();

page.on('error', (error) => {
throw new Error(`Error when running the browser: "${error.message}".`, { cause: error });
});
browser.visit('http://127.0.0.1:8080/testing.html', () => {
stopAllServers();

// sanity check for failed asset loading
for (let resource of browser.resources) {
if (resource.response.status !== 200) {
throw new Error(`Error: status code ${resource.response.status} when requesting resource ${resource.request.url}`);
}
}
page.on('requestfailed', (request) => {
throw new Error(`Error "${request.failure().errorText}" when requesting resource "${request.url()}".`);
});

page.on('response', (response) => {
loadedResources.push({
response,
});
});

callback(browser);
await page.goto('http://127.0.0.1:8080/testing.html', {
waitUntil: 'networkidle0',
});
stopAllServers();
await callback({ page, loadedResources });
await page.close();
}

module.exports = {
Expand Down
Loading

0 comments on commit 90d4b21

Please sign in to comment.