From 813792359ff8f8dd2cb06467999c83bade36bc64 Mon Sep 17 00:00:00 2001 From: adroitwhiz Date: Fri, 8 May 2020 16:32:38 -0400 Subject: [PATCH] Revert "Switch from Chromeless to Playwright for tests" --- .travis.yml | 8 ++- package.json | 2 +- test/helper/page-util.js | 54 --------------------- test/integration/cpu-render.html | 43 +++++++++++----- test/integration/index.html | 31 ++++++++++-- test/integration/pick-tests.js | 29 +++++------ test/integration/scratch-tests.js | 81 +++++++++++++++---------------- 7 files changed, 116 insertions(+), 132 deletions(-) delete mode 100644 test/helper/page-util.js diff --git a/.travis.yml b/.travis.yml index 1a04bcb..969909f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ language: node_js dist: trusty +addons: + chrome: stable node_js: -- 10 +- 8 - node env: - NODE_ENV=production +before_install: + - google-chrome-stable --headless --no-sandbox --remote-debugging-port=9222 & install: - npm --production=false install - npm --production=false update @@ -20,7 +24,7 @@ jobs: - npm run docs - npm run tap - stage: deploy - node_js: 10 + node_js: 8 script: npm run build before_deploy: - VPKG=$($(npm bin)/json -f package.json version) diff --git a/package.json b/package.json index ae17db6..5fe93af 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "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", @@ -36,7 +37,6 @@ "gh-pages": "^1.0.0", "jsdoc": "^3.5.5", "json": "^9.0.4", - "playwright-chromium": "^1.0.1", "scratch-vm": "0.2.0-prerelease.20191227164934", "tap": "^11.0.0", "travis-after-all": "^1.4.4", diff --git a/test/helper/page-util.js b/test/helper/page-util.js deleted file mode 100644 index 25f5b00..0000000 --- a/test/helper/page-util.js +++ /dev/null @@ -1,54 +0,0 @@ -/* global window, VirtualMachine, ScratchStorage, ScratchSVGRenderer */ -/* eslint-env browser */ - -// Wait for all SVG skins to be loaded. -// TODO: this is extremely janky and should be removed once vm.loadProject waits for SVG skins to load -// https://github.com/LLK/scratch-render/issues/563 -window.waitForSVGSkinLoad = renderer => new Promise(resolve => { - // eslint-disable-next-line prefer-const - let interval; - - const waitInner = () => { - let numSVGSkins = 0; - let numLoadedSVGSkins = 0; - for (const skin of renderer._allSkins) { - if (skin.constructor.name !== 'SVGSkin') continue; - numSVGSkins++; - if (skin._svgRenderer.loaded) numLoadedSVGSkins++; - } - - if (numSVGSkins === numLoadedSVGSkins) { - clearInterval(interval); - resolve(); - } - }; - - interval = setInterval(waitInner, 1); -}); - -window.loadFileInputIntoVM = (fileInput, vm, render) => { - const reader = new FileReader(); - return new Promise(resolve => { - reader.onload = () => { - vm.start(); - vm.loadProject(reader.result) - .then(() => window.waitForSVGSkinLoad(render)) - .then(() => { - resolve(); - }); - }; - reader.readAsArrayBuffer(fileInput.files[0]); - }); -}; - -window.initVM = render => { - const vm = new VirtualMachine(); - const storage = new ScratchStorage(); - - vm.attachStorage(storage); - vm.attachRenderer(render); - vm.attachV2SVGAdapter(new ScratchSVGRenderer.SVGRenderer()); - vm.attachV2BitmapAdapter(new ScratchSVGRenderer.BitmapAdapter()); - - return vm; -}; diff --git a/test/integration/cpu-render.html b/test/integration/cpu-render.html index 26a79c3..d6d3630 100644 --- a/test/integration/cpu-render.html +++ b/test/integration/cpu-render.html @@ -2,7 +2,6 @@ - @@ -18,18 +17,38 @@ window.devicePixelRatio = 1; const gpuCanvas = document.getElementById('test'); var render = new ScratchRender(gpuCanvas); - var vm = initVM(render); + var vm = new VirtualMachine(); + var storage = new ScratchStorage(); - const fileInput = document.getElementById('file'); - const loadFile = loadFileInputIntoVM.bind(null, fileInput, vm, render); - fileInput.addEventListener('change', e => { - loadFile() - .then(() => { - vm.greenFlag(); - setTimeout(() => { - renderCpu(); - }, 1000); - }); + vm.attachStorage(storage); + vm.attachRenderer(render); + vm.attachV2SVGAdapter(new ScratchSVGRenderer.SVGRenderer()); + vm.attachV2BitmapAdapter(new ScratchSVGRenderer.BitmapAdapter()); + + document.getElementById('file').addEventListener('click', e => { + document.body.removeChild(document.getElementById('loaded')); + }); + + document.getElementById('file').addEventListener('change', e => { + const reader = new FileReader(); + const thisFileInput = e.target; + reader.onload = () => { + vm.start(); + vm.loadProject(reader.result) + .then(() => { + // we add a `#loaded` div to our document, the integration suite + // waits for that element to show up to assume the vm is ready + // to play! + const div = document.createElement('div'); + div.id='loaded'; + document.body.appendChild(div); + vm.greenFlag(); + setTimeout(() => { + renderCpu(); + }, 1000); + }); + }; + reader.readAsArrayBuffer(thisFileInput.files[0]); }); const cpuCanvas = document.getElementById('cpu'); diff --git a/test/integration/index.html b/test/integration/index.html index 114fa5b..e3d8dd8 100644 --- a/test/integration/index.html +++ b/test/integration/index.html @@ -2,7 +2,6 @@ - @@ -16,13 +15,39 @@ var canvas = document.getElementById('test'); var render = new ScratchRender(canvas); - var vm = initVM(render); + var vm = new VirtualMachine(); + var storage = new ScratchStorage(); var mockMouse = data => vm.runtime.postIOData('mouse', { canvasWidth: canvas.width, canvasHeight: canvas.height, ...data, }); - const loadFile = loadFileInputIntoVM.bind(null, document.getElementById('file'), vm, render); + vm.attachStorage(storage); + vm.attachRenderer(render); + vm.attachV2SVGAdapter(new ScratchSVGRenderer.SVGRenderer()); + vm.attachV2BitmapAdapter(new ScratchSVGRenderer.BitmapAdapter()); + + document.getElementById('file').addEventListener('click', e => { + document.body.removeChild(document.getElementById('loaded')); + }); + + document.getElementById('file').addEventListener('change', e => { + const reader = new FileReader(); + const thisFileInput = e.target; + reader.onload = () => { + vm.start(); + vm.loadProject(reader.result) + .then(() => { + // we add a `#loaded` div to our document, the integration suite + // waits for that element to show up to assume the vm is ready + // to play! + const div = document.createElement('div'); + div.id='loaded'; + document.body.appendChild(div); + }); + }; + reader.readAsArrayBuffer(thisFileInput.files[0]); + }); diff --git a/test/integration/pick-tests.js b/test/integration/pick-tests.js index 4012bcd..6d3222e 100644 --- a/test/integration/pick-tests.js +++ b/test/integration/pick-tests.js @@ -1,34 +1,29 @@ /* global vm, render, Promise */ -const {chromium} = require('playwright-chromium'); +const {Chromeless} = require('chromeless'); 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 = async (file, action, page, script) => { +const runFile = (file, action, script) => // start each test by going to the index.html, and loading the scratch file - await page.goto(`file://${indexHTML}`); - const fileInput = await page.$('#file'); - await fileInput.setInputFiles(testDir(file)); - - await page.evaluate(() => - // `loadFile` is defined on the page itself. - // eslint-disable-next-line no-undef - loadFile() - ); - return page.evaluate(`(function () {return (${script})(${action});})()`); -}; + 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});}`) +; // immediately invoked async function to let us wait for each test to finish before starting the next. (async () => { - const browser = await chromium.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, page, boundAction => { + const results = await runFile('test-mouse-touch.sb2', action, boundAction => { vm.greenFlag(); const sendResults = []; @@ -102,5 +97,5 @@ const runFile = async (file, action, page, script) => { } // close the browser window we used - await browser.close(); + await chromeless.end(); })(); diff --git a/test/integration/scratch-tests.js b/test/integration/scratch-tests.js index bad0774..f11bc5b 100644 --- a/test/integration/scratch-tests.js +++ b/test/integration/scratch-tests.js @@ -1,56 +1,54 @@ /* global vm, Promise */ -const {chromium} = require('playwright-chromium'); +const {Chromeless} = require('chromeless'); 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, page) => test(file, async t => { +const testFile = file => test(file, async t => { // start each test by going to the index.html, and loading the scratch file - await page.goto(`file://${indexHTML}`); - const fileInput = await page.$('#file'); - await fileInput.setInputFiles(testDir(file)); - await page.evaluate(() => - // `loadFile` is defined on the page itself. - // eslint-disable-next-line no-undef - loadFile() - ); - 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. + 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. - // 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; + 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)); } - await new Promise(resolve => setTimeout(resolve, 50)); - } - - return messages; - }); - }); + return messages; + }); + }); // Map string messages to tap reporting methods. This will be used // with events from scratch's runtime emitted on block instructions. @@ -105,16 +103,13 @@ const testFile = (file, page) => 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 chromium.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, page); + await testFile(file); } // close the browser window we used - await browser.close(); + await chromeless.end(); })();