From 9850aaeca7236161b2208967625d5581bbc2003e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 10 Mar 2020 13:37:13 +0100 Subject: [PATCH] added scripts dir with test for making sure serve and plugin scaffolding works --- package.json | 3 +- scripts/cli-e2e-test.js | 132 ++++++++++++++++++++++++++++++++++++++++ yarn.lock | 32 +++++++--- 3 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 scripts/cli-e2e-test.js diff --git a/package.json b/package.json index 7df61e65f0..6e4bb8f0a0 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "cross-env": "^7.0.0", "lerna": "^3.20.2", "prettier": "^1.19.1", - "typescript": "^3.7.5" + "typescript": "^3.7.5", + "zombie": "^6.1.4" }, "dependencies": { "@types/classnames": "^2.2.9", diff --git a/scripts/cli-e2e-test.js b/scripts/cli-e2e-test.js new file mode 100644 index 0000000000..7735b04779 --- /dev/null +++ b/scripts/cli-e2e-test.js @@ -0,0 +1,132 @@ +const { resolve: resolvePath } = require('path'); +const childProcess = require('child_process'); +const { spawn } = childProcess; +const Browser = require('zombie'); + +Browser.localhost('localhost', 3000); + +async function main() { + process.env.CI = 'true'; + + const projectDir = resolvePath(__dirname, '..'); + process.chdir(projectDir); + + const start = spawnPiped(['yarn', 'start']); + + try { + const browser = new Browser(); + + await waitForPageWithText(browser, '/', 'Welcome to Backstage'); + print('Backstage loaded correctly, creating plugin'); + + const createPlugin = spawnPiped(['yarn', 'create-plugin']); + createPlugin.stdin.write('test-plugin\n'); + + print('Waiting for plugin create script to be done'); + await waitForExit(createPlugin); + + print('Plugin create script is done, waiting for plugin page to load'); + await waitForPageWithText( + browser, + '/test-plugin', + 'Welcome to test-plugin!', + ); + + print('Test plugin loaded correctly, exiting'); + } finally { + start.kill(); + } + await waitForExit(start); + + process.exit(0); +} + +function print(msg) { + return process.stdout.write(`${msg}\n`); +} + +async function waitForExit(child) { + await new Promise((resolve, reject) => + child.once('exit', code => { + if (code) { + reject(new Error(`Child exited with code ${code}`)); + } else { + resolve(); + } + }), + ); +} + +function spawnPiped(cmd, options) { + function pipeWithPrefix(stream, prefix = '') { + return data => { + const prefixedMsg = data + .toString('utf8') + .trimRight() + .replace(/^/gm, prefix); + stream.write(`${prefixedMsg}\n`, 'utf8'); + }; + } + + const child = spawn(cmd[0], cmd.slice(1), { stdio: 'pipe', ...options }); + child.on('error', handleError); + child.on('exit', code => { + if (code) { + print(`Child '${cmd.join(' ')}' exited with code ${code}`); + process.exit(code); + } + }); + child.stdout.on( + 'data', + pipeWithPrefix(process.stdout, `[${cmd.join(' ')}].out: `), + ); + child.stderr.on( + 'data', + pipeWithPrefix(process.stderr, `[${cmd.join(' ')}].err: `), + ); + + return child; +} + +async function waitForPageWithText( + browser, + path, + text, + { intervalMs = 1000, maxAttempts = 60 } = {}, +) { + let attempts = 0; + for (;;) { + try { + await new Promise(resolve => setTimeout(resolve, intervalMs)); + await browser.visit(path); + + break; + } catch (error) { + attempts++; + if (attempts > maxAttempts) { + throw new Error( + `Failed to load page '${path}', max number of attempts reached`, + ); + } + } + } + + const escapedText = text.replace(/"/g, '\\"'); + browser.assert.evaluate( + `Array.from(document.querySelectorAll("*")).some(el => el.textContent === "${escapedText}")`, + true, + `expected to find text ${text}`, + ); +} + +function handleError(err) { + process.stdout.write(`${err.name}: ${err.message}\n`); + if (typeof err.code === 'number') { + process.exit(err.code); + } else { + process.exit(1); + } +} + +process.on('unhandledRejection', handleError); +main(process.argv.slice(2)).catch(handleError); diff --git a/yarn.lock b/yarn.lock index 1dba6942e8..a7af4cfcb1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4276,7 +4276,7 @@ babel-preset-react-app@^9.1.0: babel-plugin-macros "2.8.0" babel-plugin-transform-react-remove-prop-types "0.4.24" -babel-runtime@6.x, babel-runtime@^6.23.0, babel-runtime@^6.26.0: +babel-runtime@6.26.0, babel-runtime@6.x, babel-runtime@^6.23.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -6960,7 +6960,7 @@ events@^3.0.0: resolved "https://registry.npmjs.org/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== -eventsource@^1.0.7: +eventsource@^1.0.5, eventsource@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== @@ -8466,7 +8466,7 @@ hyphenate-style-name@^1.0.2, hyphenate-style-name@^1.0.3: resolved "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48" integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ== -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.21, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -10104,7 +10104,7 @@ jsbn@~0.1.0: resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jsdom@^11.5.1: +jsdom@11.12.0, jsdom@^11.5.1: version "11.12.0" resolved "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== @@ -10946,7 +10946,7 @@ lodash.without@~4.4.0: resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= -lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1: +lodash@4.17.15, "lodash@>=3.5 <5", lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1: version "4.17.15" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -11336,7 +11336,7 @@ mime@1.6.0: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.4.3, mime@^2.4.4: +mime@^2.3.1, mime@^2.4.3, mime@^2.4.4: version "2.4.4" resolved "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== @@ -14514,7 +14514,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.7: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.87.0, request@^2.88.0: +request@^2.85.0, request@^2.87.0, request@^2.88.0: version "2.88.2" resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -17572,3 +17572,21 @@ zen-observable@^0.8.15: version "0.8.15" resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== + +zombie@^6.1.4: + version "6.1.4" + resolved "https://registry.npmjs.org/zombie/-/zombie-6.1.4.tgz#9f0f53f3d9a032beb7f3fe5b382146a3475a4d47" + integrity sha512-yxNvKtyz3PP8lkr31AYh7vdbBD4is9hYXiOQKPp+k/7GiDiFQXX1Ex+peCl4ttodu/bHZcIluJ8lxMla5XefBQ== + dependencies: + babel-runtime "6.26.0" + bluebird "^3.5.1" + debug "^4.1.0" + eventsource "^1.0.5" + iconv-lite "^0.4.21" + jsdom "11.12.0" + lodash "^4.17.10" + mime "^2.3.1" + ms "^2.1.1" + request "^2.85.0" + tough-cookie "^2.3.4" + ws "^6.1.2"