mirror of
https://github.com/fergalmoran/onearmy-community-platform.git
synced 2025-12-22 09:37:54 +00:00
139 lines
5.2 KiB
TypeScript
139 lines
5.2 KiB
TypeScript
#!/usr/bin/env ts-node
|
|
import { spawn, spawnSync } from 'child_process'
|
|
import * as dotenv from 'dotenv'
|
|
import fs from 'fs-extra'
|
|
import waitOn from 'wait-on'
|
|
|
|
import { generateAlphaNumeric } from '../src/utils/TestUtils'
|
|
import PATHS from './paths'
|
|
|
|
const e2eEnv = dotenv.config()
|
|
|
|
const isCi = process.argv.includes('ci')
|
|
const isProduction = process.argv.includes('prod')
|
|
|
|
// Prevent unhandled errors being silently ignored
|
|
process.on('unhandledRejection', (err) => {
|
|
console.error('There was an uncaught error', err)
|
|
process.exitCode = 1
|
|
})
|
|
/**
|
|
* When running e2e tests with cypress we need to first get the server up and running
|
|
* before launching the test suite. We will seed the DB from within the test suite
|
|
*
|
|
* @argument ci - specify if running in ci (e.g. circleci) to run and record
|
|
* @argument prod - specify to use a production build instead of local development server
|
|
* @example npm run test ci prod
|
|
*
|
|
* TODO: CC - 2021-02-24
|
|
* - DB seeding happens inbetween test suites, but really should happen before/after test
|
|
* scripts start and end (particularly teardown, as it won't be called if tests fail).
|
|
* Possibly could be done with a Cypress.task or similar
|
|
* Temp cli function to wipe hanging db: `firebase use ci; firebase firestore:delete --all-collections`
|
|
*/
|
|
main()
|
|
.then(() => process.exit(0))
|
|
.catch((err) => {
|
|
console.error(err)
|
|
process.exit(1)
|
|
})
|
|
|
|
async function main() {
|
|
// copy endpoints for use in testing
|
|
fs.copyFileSync(PATHS.SRC_DB_ENDPOINTS, PATHS.WORKSPACE_DB_ENDPOINTS)
|
|
await startAppServer()
|
|
runTests()
|
|
}
|
|
|
|
/** We need to ensure the platform is up and running before starting tests
|
|
* There are npm packages like start-server-and-test but they seem to have flaky
|
|
* performance in some environments (https://github.com/bahmutov/start-server-and-test/issues/250).
|
|
* Instead manually track via child spawns
|
|
*
|
|
*/
|
|
async function startAppServer() {
|
|
const { CROSSENV_BIN, BUILD_SERVE_JSON } = PATHS
|
|
// by default spawns will not respect colours used in stdio, so try to force
|
|
const crossEnvArgs = `FORCE_COLOR=1 VITE_APP_SITE_VARIANT=test-ci`
|
|
|
|
// run local debug server for testing unless production build specified
|
|
let serverCmd = `${CROSSENV_BIN} ${crossEnvArgs} BROWSER=none PORT=3456 yarn start`
|
|
|
|
// for production will instead serve from production build folder
|
|
if (isProduction) {
|
|
// create local build if not running on ci (which will have build already generated)
|
|
if (!isCi) {
|
|
// specify CI=false to prevent throwing lint warnings as errors
|
|
spawnSync(`${CROSSENV_BIN} ${crossEnvArgs} CI=false yarn build`, {
|
|
shell: true,
|
|
stdio: ['inherit', 'inherit', 'pipe'],
|
|
})
|
|
}
|
|
// create a rewrites file for handling local server behaviour
|
|
const opts = { rewrites: [{ source: '/**', destination: '/index.html' }] }
|
|
fs.writeFileSync(BUILD_SERVE_JSON, JSON.stringify(opts))
|
|
|
|
serverCmd = `npx serve build -l 3456`
|
|
}
|
|
|
|
/******************* Run the main commands ******************* */
|
|
// as the spawn will not terminate create non-async, and just listen to and handle messages
|
|
// from the methods
|
|
const child = spawn(serverCmd, {
|
|
shell: true,
|
|
stdio: ['pipe', 'pipe', 'inherit'],
|
|
cwd: PATHS.PLATFORM_ROOT_DIR,
|
|
})
|
|
|
|
child.stdout.on('data', (d) => {
|
|
const msg = d.toString('utf8')
|
|
console.log(msg)
|
|
// throw typescript build errors
|
|
if (msg.includes('Failed to compile')) {
|
|
// the server will still be running after compile failure (waiting for changes),
|
|
// so give time for any other messages to come through before exiting manually
|
|
setTimeout(() => {
|
|
process.exit(1)
|
|
}, 2000)
|
|
}
|
|
})
|
|
// do not end function until server responsive on port 3456
|
|
// give up if not reponsive after 5 minutes (assume uncaught error somewhere)
|
|
const timeout = 5 * 60 * 1000
|
|
await waitOn({ resources: ['http-get://127.0.0.1:3456'], timeout })
|
|
}
|
|
|
|
function runTests() {
|
|
console.log(isCi ? 'Start tests' : 'Opening cypress for manual testing')
|
|
const e = process.env
|
|
const { CYPRESS_KEY } = e2eEnv.parsed
|
|
const CI_BROWSER = e.CI_BROWSER || 'chrome'
|
|
const CI_GROUP = e.CI_GROUP || '1x-chrome'
|
|
// not currently used, but can pass variables accessed by Cypress.env()
|
|
const CYPRESS_ENV = `DUMMY_VAR=1`
|
|
// use workflow ID so that jobs running in parallel can be assigned to same cypress build
|
|
// cypress will use this to split tests between parallel runs
|
|
const buildId = e.CIRCLE_WORKFLOW_ID || generateAlphaNumeric(8)
|
|
|
|
// main testing command, depending on whether running on ci machine or interactive local
|
|
// call with path to bin as to ensure locally installed used
|
|
const { CY_BIN, CROSSENV_BIN } = PATHS
|
|
|
|
const testCMD = isCi
|
|
? `${CY_BIN} run --record --env ${CYPRESS_ENV} --key=${CYPRESS_KEY} --parallel --headless --browser ${CI_BROWSER} --group ${CI_GROUP} --ci-build-id ${buildId}`
|
|
: `${CY_BIN} open --browser chrome --env ${CYPRESS_ENV}`
|
|
|
|
console.log(`Running cypress with cmd: ${testCMD}`)
|
|
|
|
const spawn = spawnSync(`${CROSSENV_BIN} FORCE_COLOR=1 ${testCMD}`, {
|
|
shell: true,
|
|
stdio: ['inherit', 'inherit', 'pipe'],
|
|
cwd: PATHS.WORKSPACE_DIR,
|
|
})
|
|
console.log('testing complete with exit code', spawn.status)
|
|
if (spawn.status === 1) {
|
|
console.error('error', spawn.stderr.toString())
|
|
}
|
|
process.exit(spawn.status)
|
|
}
|