From 3d02a6c7697014a73d61ce21f6c01b10820130ea Mon Sep 17 00:00:00 2001 From: adroitwhiz Date: Tue, 7 Jan 2020 14:46:34 -0500 Subject: [PATCH] Replace Chromeless with Puppeteer --- package.json | 2 +- test/integration/pick-tests.js | 26 +++++----- test/integration/scratch-tests.js | 79 ++++++++++++++++--------------- 3 files changed, 56 insertions(+), 51 deletions(-) diff --git a/package.json b/package.json index 91c1c6d..65e0dd4 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "babel-loader": "^7.1.4", "babel-polyfill": "^6.22.0", "babel-preset-env": "^1.6.1", - "chromeless": "^1.5.1", "copy-webpack-plugin": "^4.5.1", "docdash": "^0.4.0", "eslint": "^4.6.1", @@ -37,6 +36,7 @@ "gh-pages": "^1.0.0", "jsdoc": "^3.5.5", "json": "^9.0.4", + "puppeteer": "^2.0.0", "scratch-vm": "0.2.0-prerelease.20191227164934", "tap": "^11.0.0", "travis-after-all": "^1.4.4", diff --git a/test/integration/pick-tests.js b/test/integration/pick-tests.js index 6d3222e..37341fc 100644 --- a/test/integration/pick-tests.js +++ b/test/integration/pick-tests.js @@ -1,29 +1,31 @@ /* global vm, render, Promise */ -const {Chromeless} = require('chromeless'); +const puppeteer = require('puppeteer'); const test = require('tap').test; const path = require('path'); -const chromeless = new Chromeless(); const indexHTML = path.resolve(__dirname, 'index.html'); const testDir = (...args) => path.resolve(__dirname, 'pick-tests', ...args); -const runFile = (file, action, script) => +const runFile = async (file, action, page, script) => { // start each test by going to the index.html, and loading the scratch file - chromeless.goto(`file://${indexHTML}`) - .setFileInput('#file', testDir(file)) - // the index.html handler for file input will add a #loaded element when it - // finishes. - .wait('#loaded') - .evaluate(`function () {return (${script})(${action});}`) -; + await page.goto(`file://${indexHTML}`); + const fileInput = await page.$('#file'); + await fileInput.uploadFile(testDir(file)); + // the index.html handler for file input will add a #loaded element when it + // finishes. + await page.waitForSelector('#loaded'); + return page.evaluate(`(function () {return (${script})(${action});})()`); +}; // immediately invoked async function to let us wait for each test to finish before starting the next. (async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); const testOperation = async function (name, action, expect) { await test(name, async t => { - const results = await runFile('test-mouse-touch.sb2', action, boundAction => { + const results = await runFile('test-mouse-touch.sb2', action, page, boundAction => { vm.greenFlag(); const sendResults = []; @@ -97,5 +99,5 @@ const runFile = (file, action, script) => } // close the browser window we used - await chromeless.end(); + await browser.close(); })(); diff --git a/test/integration/scratch-tests.js b/test/integration/scratch-tests.js index f11bc5b..022841b 100644 --- a/test/integration/scratch-tests.js +++ b/test/integration/scratch-tests.js @@ -1,54 +1,54 @@ /* global vm, Promise */ -const {Chromeless} = require('chromeless'); +const puppeteer = require('puppeteer'); const test = require('tap').test; const path = require('path'); const fs = require('fs'); -const chromeless = new Chromeless(); const indexHTML = path.resolve(__dirname, 'index.html'); const testDir = (...args) => path.resolve(__dirname, 'scratch-tests', ...args); -const testFile = file => test(file, async t => { +const testFile = (file, page) => test(file, async t => { // start each test by going to the index.html, and loading the scratch file - const says = await chromeless.goto(`file://${indexHTML}`) - .setFileInput('#file', testDir(file)) - // the index.html handler for file input will add a #loaded element when it - // finishes. - .wait('#loaded') - .evaluate(() => { - // This function is run INSIDE the integration chrome browser via some - // injection and .toString() magic. We can return some "simple data" - // back across as a promise, so we will just log all the says that happen - // for parsing after. + await page.goto(`file://${indexHTML}`); + const fileInput = await page.$('#file'); + await fileInput.uploadFile(testDir(file)); + // the index.html handler for file input will add a #loaded element when it + // finishes. + await page.waitForSelector('#loaded'); + const says = await page.evaluate(() => { + // This function is run INSIDE the integration chrome browser via some + // injection and .toString() magic. We can return some "simple data" + // back across as a promise, so we will just log all the says that happen + // for parsing after. - // this becomes the `says` in the outer scope - const messages = []; - const TIMEOUT = 5000; + // this becomes the `says` in the outer scope + const messages = []; + const TIMEOUT = 5000; - vm.runtime.on('SAY', (_, __, message) => { - messages.push(message); - }); + vm.runtime.on('SAY', (_, __, message) => { + messages.push(message); + }); - vm.greenFlag(); - const startTime = Date.now(); + vm.greenFlag(); + const startTime = Date.now(); - return Promise.resolve() - .then(async () => { - // waiting for all threads to complete, then we return - while (vm.runtime.threads.some(thread => vm.runtime.isActiveThread(thread))) { - if ((Date.now() - startTime) >= TIMEOUT) { - // if we push the message after end, the failure from tap is not very useful: - // "not ok test after end() was called" - messages.unshift(`fail Threads still running after ${TIMEOUT}ms`); - break; - } - - await new Promise(resolve => setTimeout(resolve, 50)); + return Promise.resolve() + .then(async () => { + // waiting for all threads to complete, then we return + while (vm.runtime.threads.some(thread => vm.runtime.isActiveThread(thread))) { + if ((Date.now() - startTime) >= TIMEOUT) { + // if we push the message after end, the failure from tap is not very useful: + // "not ok test after end() was called" + messages.unshift(`fail Threads still running after ${TIMEOUT}ms`); + break; } - return messages; - }); - }); + await new Promise(resolve => setTimeout(resolve, 50)); + } + + return messages; + }); + }); // Map string messages to tap reporting methods. This will be used // with events from scratch's runtime emitted on block instructions. @@ -103,13 +103,16 @@ const testFile = file => test(file, async t => { // immediately invoked async function to let us wait for each test to finish before starting the next. (async () => { + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + const files = fs.readdirSync(testDir()) .filter(uri => uri.endsWith('.sb2') || uri.endsWith('.sb3')); for (const file of files) { - await testFile(file); + await testFile(file, page); } // close the browser window we used - await chromeless.end(); + await browser.close(); })();