From e83dc7d4b276a3e4fdc90b979df5c30556a673b1 Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Mon, 28 Dec 2020 12:17:41 +0000 Subject: [PATCH 1/2] chore: add browser example test --- .github/workflows/main.yml | 9 +- .gitignore | 1 + examples/libp2p-in-the-browser/package.json | 2 + examples/libp2p-in-the-browser/test.js | 21 +++++ examples/nightwatch.conf.js | 35 ++++++++ examples/package.json | 3 + examples/test.js | 39 ++++++++- examples/utils.js | 92 +++++++++++++++++++++ 8 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 examples/libp2p-in-the-browser/test.js create mode 100644 examples/nightwatch.conf.js diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6dabc16c2a..4acb1a87e5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -71,4 +71,11 @@ jobs: steps: - uses: actions/checkout@v2 - run: yarn - - run: cd examples && yarn && npm run test -- chat \ No newline at end of file + - run: cd examples && yarn && npm run test -- chat + test-libp2p-in-the-browser-example: + needs: check + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - run: yarn + - run: cd examples && yarn && npm run test -- libp2p-in-the-browser diff --git a/.gitignore b/.gitignore index 61b3b5aa3d..e683589fda 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ dist test/test-data/go-ipfs-repo/LOCK test/test-data/go-ipfs-repo/LOG test/test-data/go-ipfs-repo/LOG.old +tests_output/ # while testing npm5 package-lock.json diff --git a/examples/libp2p-in-the-browser/package.json b/examples/libp2p-in-the-browser/package.json index 8d09b86d31..6d3aa1cb14 100644 --- a/examples/libp2p-in-the-browser/package.json +++ b/examples/libp2p-in-the-browser/package.json @@ -8,6 +8,7 @@ ], "scripts": { "test": "echo \"Error: no test specified\" && exit 1", + "build": "parcel build index.html", "start": "parcel index.html" }, "keywords": [], @@ -28,6 +29,7 @@ "babel-plugin-syntax-async-functions": "^6.13.0", "babel-plugin-transform-regenerator": "^6.26.0", "babel-polyfill": "^6.26.0", + "p-retry": "^4.2.0", "parcel-bundler": "^1.12.4" } } diff --git a/examples/libp2p-in-the-browser/test.js b/examples/libp2p-in-the-browser/test.js new file mode 100644 index 0000000000..8077a610a9 --- /dev/null +++ b/examples/libp2p-in-the-browser/test.js @@ -0,0 +1,21 @@ +'use strict' + +const pkg = require('./package.json') + +module.exports = { + [pkg.name]: function (browser) { + browser + .url(process.env.LIBP2P_EXAMPLE_TEST_URL) + .waitForElementVisible('#status') + .waitForElementVisible('#output') + .pause(5000) + + browser.expect.element('#status').text.to.contain('libp2p started!') + browser.expect.element('#output').text.to.contain('libp2p id is') + + browser.expect.element('#output').text.to.contain('Found peer') + browser.expect.element('#output').text.to.contain('Connected to') + + browser.end() + } +} diff --git a/examples/nightwatch.conf.js b/examples/nightwatch.conf.js new file mode 100644 index 0000000000..573a1d9fab --- /dev/null +++ b/examples/nightwatch.conf.js @@ -0,0 +1,35 @@ +'use strict' + +const { ephemeralPort } = require('./utils') + +const WEBRIVER_PORT = ephemeralPort() + +// config used to test examples +module.exports = { + src_folders: ['tests'], + + webdriver: { + start_process: true, + server_path: 'node_modules/.bin/chromedriver', + port: WEBRIVER_PORT, + cli_args: [ + `--port=${WEBRIVER_PORT}` + ] + }, + + test_settings: { + default: { + desiredCapabilities: { + browserName: 'chrome', + chromeOptions: { + args: ['headless'] + } + } + } + }, + + globals: { + asyncHookTimeout: 120000, + waitForConditionTimeout: 60000 + } +} diff --git a/examples/package.json b/examples/package.json index feaf656d1b..71fddc06f6 100644 --- a/examples/package.json +++ b/examples/package.json @@ -8,9 +8,12 @@ }, "license": "MIT", "dependencies": { + "chromedriver": "^87.0.0", "execa": "^2.1.0", "fs-extra": "^8.1.0", "p-defer": "^3.0.0", + "http-server": "~0.11.1", + "nightwatch": "^1.2.4", "which": "^2.0.1" } } diff --git a/examples/test.js b/examples/test.js index 3da6eccdb9..1c8316927c 100644 --- a/examples/test.js +++ b/examples/test.js @@ -7,6 +7,7 @@ const fs = require('fs-extra') const path = require('path') const execa = require('execa') const dir = path.join(__dirname, process.argv[2]) +const { startServer } = require('./utils') testExample(dir) .then(() => {}, (err) => { @@ -21,8 +22,12 @@ testExample(dir) async function testExample (dir) { await installDeps(dir) await build(dir) - await runTest(dir) - // TODO: add browser test setup + + if (dir.includes('browser')) { + await runBrowserTest(dir) + } else { + await runNodeTest(dir) + } } async function installDeps (dir) { @@ -80,7 +85,7 @@ async function build (dir) { await proc } -async function runTest (dir) { +async function runNodeTest (dir) { console.info('Running node tests in', dir) const testFile = path.join(dir, 'test.js') @@ -92,4 +97,30 @@ async function runTest (dir) { const runTest = require(testFile) await runTest() -} \ No newline at end of file +} + +async function runBrowserTest (dir) { + console.info('Running browser tests in', dir) + + const server = await startServer(dir) + + console.info('Running tests at', server.url) + + const proc = execa('nightwatch', [ path.join(dir, 'test.js') ], { + cwd: __dirname, + env: { + ...process.env, + LIBP2P_EXAMPLE_TEST_URL: server.url + } + }) + + proc.all.on('data', (data) => { + process.stdout.write(data) + }) + + try { + await proc + } finally { + server.stop() + } +} diff --git a/examples/utils.js b/examples/utils.js index aec6df5418..3257768a35 100644 --- a/examples/utils.js +++ b/examples/utils.js @@ -3,6 +3,96 @@ const execa = require('execa') const fs = require('fs-extra') const which = require('which') +const path = require('path') + +async function startServer (dir) { + async function serveFrom (path) { + return new Promise((resolve, reject) => { + let output = '' + + const proc = execa.command(`http-server ${path} -a 127.0.0.1`, { + cwd: __dirname + }) + proc.all.on('data', (data) => { + process.stdout.write(data) + + const line = data.toString('utf8') + output += line + + if (output.includes('Hit CTRL-C to stop the server')) { + // find the port + const port = output.match(/http:\/\/127.0.0.1:(\d+)/)[1] + + if (!port) { + throw new Error(`Could not find port in ${output}`) + } + + resolve({ + stop: () => { + console.info('Stopping server') + proc.kill('SIGINT', { + forceKillAfterTimeout: 2000 + }) + }, + url: `http://127.0.0.1:${port}` + }) + } + }) + + proc.then(() => {}, (err) => reject(err)) + }) + } + + const serverPaths = [ + path.join(dir, 'build'), + path.join(dir, 'dist'), + path.join(dir, 'public') + ] + + for (const p of serverPaths) { + if (fs.existsSync(p)) { + return serveFrom(p) + } + } + + // running a bare index.html file + const files = [ + path.join(dir, 'index.html') + ] + + for (const f of files) { + if (fs.existsSync(f)) { + console.info('Found bare file', f) + + if (!fs.existsSync(path.resolve(dir, '../../dist'))) { + console.info('Building IPFS') + const proc = execa.command('npm run build', { + cwd: path.resolve(dir, '../../'), + env: { + ...process.env, + CI: true // needed for some "clever" build tools + } + }) + proc.all.on('data', (data) => { + process.stdout.write(data) + }) + + await proc + } + + return Promise.resolve({ + url: `file://${f}`, + stop: () => { } + }) + } + } + + throw new Error('Browser examples must contain a `public`, `dist` or `build` folder or an `index.html` file') +} + +function ephemeralPort (min = 49152, max = 65535) { + return Math.floor(Math.random() * (max - min + 1) + min) +} async function isExecutable (command) { try { @@ -57,5 +147,7 @@ async function waitForOutput (expectedOutput, command, args = [], opts = {}) { } module.exports = { + startServer, + ephemeralPort, waitForOutput } From 03173f35a5a1441bb282f77e2a16123334a847de Mon Sep 17 00:00:00 2001 From: Vasco Santos Date: Mon, 18 Jan 2021 17:56:39 +0100 Subject: [PATCH 2/2] chore: use playwright --- .gitignore | 1 - examples/libp2p-in-the-browser/package.json | 1 - examples/libp2p-in-the-browser/test.js | 59 +++++++++---- examples/nightwatch.conf.js | 35 -------- examples/package.json | 6 +- examples/test.js | 40 +-------- examples/utils.js | 92 --------------------- 7 files changed, 52 insertions(+), 182 deletions(-) delete mode 100644 examples/nightwatch.conf.js diff --git a/.gitignore b/.gitignore index e683589fda..61b3b5aa3d 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,6 @@ dist test/test-data/go-ipfs-repo/LOCK test/test-data/go-ipfs-repo/LOG test/test-data/go-ipfs-repo/LOG.old -tests_output/ # while testing npm5 package-lock.json diff --git a/examples/libp2p-in-the-browser/package.json b/examples/libp2p-in-the-browser/package.json index 6d3aa1cb14..b59c8cdbf9 100644 --- a/examples/libp2p-in-the-browser/package.json +++ b/examples/libp2p-in-the-browser/package.json @@ -29,7 +29,6 @@ "babel-plugin-syntax-async-functions": "^6.13.0", "babel-plugin-transform-regenerator": "^6.26.0", "babel-polyfill": "^6.26.0", - "p-retry": "^4.2.0", "parcel-bundler": "^1.12.4" } } diff --git a/examples/libp2p-in-the-browser/test.js b/examples/libp2p-in-the-browser/test.js index 8077a610a9..c0e67fe7bf 100644 --- a/examples/libp2p-in-the-browser/test.js +++ b/examples/libp2p-in-the-browser/test.js @@ -1,21 +1,52 @@ 'use strict' -const pkg = require('./package.json') +const execa = require('execa') +const { chromium } = require('playwright'); -module.exports = { - [pkg.name]: function (browser) { - browser - .url(process.env.LIBP2P_EXAMPLE_TEST_URL) - .waitForElementVisible('#status') - .waitForElementVisible('#output') - .pause(5000) +async function run() { + let url = '' + const proc = execa('parcel', ['./index.html'], { + preferLocal: true, + localDir: __dirname, + cwd: __dirname, + all: true + }) - browser.expect.element('#status').text.to.contain('libp2p started!') - browser.expect.element('#output').text.to.contain('libp2p id is') + proc.all.on('data', async (chunk) => { + /**@type {string} */ + const out = chunk.toString() - browser.expect.element('#output').text.to.contain('Found peer') - browser.expect.element('#output').text.to.contain('Connected to') + if (out.includes('Server running at')) { + url = out.replace('Server running at ', '') + } + + if (out.includes('✨ Built in ')) { + try { + const browser = await chromium.launch(); + const page = await browser.newPage(); + await page.goto(url); + await page.waitForFunction(selector => document.querySelector(selector).innerText === 'libp2p started!', '#status') + await page.waitForFunction( + selector => { + const text = document.querySelector(selector).innerText + return text.includes('libp2p id is') && + text.includes('Found peer') && + text.includes('Connected to') + }, + '#output', + { timeout: 5000 } + ) + await browser.close(); + + } catch (err) { + console.error(err) + process.exit(1) + } finally { + proc.cancel() + } + } + }) - browser.end() - } } + +module.exports = run diff --git a/examples/nightwatch.conf.js b/examples/nightwatch.conf.js deleted file mode 100644 index 573a1d9fab..0000000000 --- a/examples/nightwatch.conf.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict' - -const { ephemeralPort } = require('./utils') - -const WEBRIVER_PORT = ephemeralPort() - -// config used to test examples -module.exports = { - src_folders: ['tests'], - - webdriver: { - start_process: true, - server_path: 'node_modules/.bin/chromedriver', - port: WEBRIVER_PORT, - cli_args: [ - `--port=${WEBRIVER_PORT}` - ] - }, - - test_settings: { - default: { - desiredCapabilities: { - browserName: 'chrome', - chromeOptions: { - args: ['headless'] - } - } - } - }, - - globals: { - asyncHookTimeout: 120000, - waitForConditionTimeout: 60000 - } -} diff --git a/examples/package.json b/examples/package.json index 71fddc06f6..b8c0a46a54 100644 --- a/examples/package.json +++ b/examples/package.json @@ -8,12 +8,12 @@ }, "license": "MIT", "dependencies": { - "chromedriver": "^87.0.0", "execa": "^2.1.0", "fs-extra": "^8.1.0", "p-defer": "^3.0.0", - "http-server": "~0.11.1", - "nightwatch": "^1.2.4", "which": "^2.0.1" + }, + "devDependencies": { + "playwright": "^1.7.1" } } diff --git a/examples/test.js b/examples/test.js index 1c8316927c..69f2be8bca 100644 --- a/examples/test.js +++ b/examples/test.js @@ -7,7 +7,6 @@ const fs = require('fs-extra') const path = require('path') const execa = require('execa') const dir = path.join(__dirname, process.argv[2]) -const { startServer } = require('./utils') testExample(dir) .then(() => {}, (err) => { @@ -22,12 +21,7 @@ testExample(dir) async function testExample (dir) { await installDeps(dir) await build(dir) - - if (dir.includes('browser')) { - await runBrowserTest(dir) - } else { - await runNodeTest(dir) - } + await runTest(dir) } async function installDeps (dir) { @@ -85,7 +79,7 @@ async function build (dir) { await proc } -async function runNodeTest (dir) { +async function runTest (dir) { console.info('Running node tests in', dir) const testFile = path.join(dir, 'test.js') @@ -94,33 +88,7 @@ async function runNodeTest (dir) { return } - const runTest = require(testFile) - - await runTest() -} - -async function runBrowserTest (dir) { - console.info('Running browser tests in', dir) - - const server = await startServer(dir) + const test = require(testFile) - console.info('Running tests at', server.url) - - const proc = execa('nightwatch', [ path.join(dir, 'test.js') ], { - cwd: __dirname, - env: { - ...process.env, - LIBP2P_EXAMPLE_TEST_URL: server.url - } - }) - - proc.all.on('data', (data) => { - process.stdout.write(data) - }) - - try { - await proc - } finally { - server.stop() - } + await test() } diff --git a/examples/utils.js b/examples/utils.js index 3257768a35..aec6df5418 100644 --- a/examples/utils.js +++ b/examples/utils.js @@ -3,96 +3,6 @@ const execa = require('execa') const fs = require('fs-extra') const which = require('which') -const path = require('path') - -async function startServer (dir) { - async function serveFrom (path) { - return new Promise((resolve, reject) => { - let output = '' - - const proc = execa.command(`http-server ${path} -a 127.0.0.1`, { - cwd: __dirname - }) - proc.all.on('data', (data) => { - process.stdout.write(data) - - const line = data.toString('utf8') - output += line - - if (output.includes('Hit CTRL-C to stop the server')) { - // find the port - const port = output.match(/http:\/\/127.0.0.1:(\d+)/)[1] - - if (!port) { - throw new Error(`Could not find port in ${output}`) - } - - resolve({ - stop: () => { - console.info('Stopping server') - proc.kill('SIGINT', { - forceKillAfterTimeout: 2000 - }) - }, - url: `http://127.0.0.1:${port}` - }) - } - }) - - proc.then(() => {}, (err) => reject(err)) - }) - } - - const serverPaths = [ - path.join(dir, 'build'), - path.join(dir, 'dist'), - path.join(dir, 'public') - ] - - for (const p of serverPaths) { - if (fs.existsSync(p)) { - return serveFrom(p) - } - } - - // running a bare index.html file - const files = [ - path.join(dir, 'index.html') - ] - - for (const f of files) { - if (fs.existsSync(f)) { - console.info('Found bare file', f) - - if (!fs.existsSync(path.resolve(dir, '../../dist'))) { - console.info('Building IPFS') - const proc = execa.command('npm run build', { - cwd: path.resolve(dir, '../../'), - env: { - ...process.env, - CI: true // needed for some "clever" build tools - } - }) - proc.all.on('data', (data) => { - process.stdout.write(data) - }) - - await proc - } - - return Promise.resolve({ - url: `file://${f}`, - stop: () => { } - }) - } - } - - throw new Error('Browser examples must contain a `public`, `dist` or `build` folder or an `index.html` file') -} - -function ephemeralPort (min = 49152, max = 65535) { - return Math.floor(Math.random() * (max - min + 1) + min) -} async function isExecutable (command) { try { @@ -147,7 +57,5 @@ async function waitForOutput (expectedOutput, command, args = [], opts = {}) { } module.exports = { - startServer, - ephemeralPort, waitForOutput }