diff --git a/build.js b/build.mjs similarity index 56% rename from build.js rename to build.mjs index e0c3723..dfced49 100644 --- a/build.js +++ b/build.mjs @@ -1,6 +1,8 @@ -const esbuild = require('esbuild') -const yargs = require('yargs') -const { nodeExternalsPlugin } = require('esbuild-node-externals') +/*eslint-env node*/ + +import { build } from 'esbuild' +import yargs from 'yargs' +import { nodeExternalsPlugin } from 'esbuild-node-externals' const argv = yargs(process.argv) .alias('w', 'watch') @@ -17,30 +19,26 @@ if (argv.watch) { } // // Build the CLI -esbuild - .build({ - entryPoints: ['lib/cli.ts'], - outfile: 'build/cli.js', +build({ + entryPoints: ['lib/cli/index.ts'], + outfile: 'build/cli.js', + bundle: true, + platform: 'node', + plugins: [nodeExternalsPlugin()], + watch, + external: ['chrome-aws-lambda', 'puppeteer-core'], +}).catch(() => process.exit(1)) + +function buildSimpleFile(file, outfile, platform = 'browser') { + build({ + entryPoints: [file], + outfile: `build/${outfile}.js`, + platform, bundle: true, - platform: 'node', plugins: [nodeExternalsPlugin()], - watch, external: ['chrome-aws-lambda', 'puppeteer-core'], - }) - .catch(() => process.exit(1)) - -function buildSimpleFile(file, outfile, platform = 'browser') { - esbuild - .build({ - entryPoints: [file], - outfile: `build/${outfile}.js`, - platform, - bundle: true, - plugins: [nodeExternalsPlugin()], - external: ['chrome-aws-lambda', 'puppeteer-core'], - watch, - }) - .catch(() => process.exit(1)) + watch, + }).catch(() => process.exit(1)) } buildSimpleFile('lib/webpack/webpack-client.ts', 'webpack-client', 'node') diff --git a/lib/cli/index.ts b/lib/cli/index.ts new file mode 100644 index 0000000..17df86f --- /dev/null +++ b/lib/cli/index.ts @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +// @ts-expect-error server is not typed +import Server from '../server' +import initZen from '../index' +import yargs from 'yargs' +import runRemote from './run_remote' + +export type CLIOptions = { + logging: boolean + maxAttempts: number + debug: boolean + configFile: string + junit: string +} + +yargs(process.argv.slice(2)) + .usage('$0 [configFile]') + .command( + ['local [configFile]', 'server [configFile]'], + 'Run zen with a local server', + // @ts-expect-error yargs changed their type def but this pattern still works + (yargs: yargs.Argv) => { + yargs.positional('file', { + type: 'string', + describe: 'Path to the config file', + }) + }, + async (argv: CLIOptions) => { + await initZen(argv.configFile) + new Server() + } + ) + .command( + 'remote [configFile]', + 'Run zen in the console', + // @ts-expect-error yargs changed their type def but this pattern still works + (yargs: yargs.Argv) => { + yargs.positional('file', { + type: 'string', + describe: 'Path to the config file', + }) + }, + async (argv: CLIOptions) => { + const zen = await initZen(argv.configFile) + runRemote(zen, argv) + } + ) + .options({ + logging: { type: 'boolean', default: false }, + maxAttempts: { type: 'number', default: 3 }, + debug: { type: 'boolean', default: false }, + junit: { type: 'string', default: '' }, + }).argv diff --git a/lib/cli.ts b/lib/cli/run_remote.ts old mode 100755 new mode 100644 similarity index 78% rename from lib/cli.ts rename to lib/cli/run_remote.ts index 858c747..bbf8ed4 --- a/lib/cli.ts +++ b/lib/cli/run_remote.ts @@ -1,67 +1,44 @@ -#!/usr/bin/env node - -// @ts-expect-error server is not typed -import Server from './server' -import initZen from './index' -import yargs from 'yargs' -import { invoke, workTests } from './util' -import * as Profiler from './profiler' -import { Zen } from './types' +import { invoke, workTests } from '../util' +import * as Profiler from '../profiler' +import { Zen } from '../types' +import { CLIOptions } from './index' +import { encodeXML } from 'entities' +import { writeFileSync } from 'fs' +import { join } from 'path' type testFailure = { + resolved?: boolean fullName: string attempts: number error?: string time: number } -export type CLIOptions = { - logging: boolean - maxAttempts: number - debug: boolean - configFile: string -} - -yargs(process.argv.slice(2)) - .usage('$0 [configFile]') - .command( - ['local [configFile]', 'server [configFile]'], - 'Run zen with a local server', - // @ts-expect-error yargs changed their type def but this pattern still works - (yargs: yargs.Argv) => { - yargs.positional('file', { - type: 'string', - describe: 'Path to the config file', - }) - }, - async (argv: CLIOptions) => { - await initZen(argv.configFile) - new Server() - } - ) - .command( - 'remote [configFile]', - 'Run zen in the console', - // @ts-expect-error yargs changed their type def but this pattern still works - (yargs: yargs.Argv) => { - yargs.positional('file', { - type: 'string', - describe: 'Path to the config file', - }) - }, - async (argv: CLIOptions) => { - const zen = await initZen(argv.configFile) - run(zen, argv) - } - ) - .options({ - logging: { type: 'boolean', default: false }, - maxAttempts: { type: 'number', default: 3 }, - debug: { type: 'boolean', default: false }, - }).argv - type TestResultsMap = Record +function resultsToXML(results: TestResultsMap): string { + const failures = Object.values(results) + + const xml = ` + + + +${failures + .map((failure) => { + return ` + + ` + }) + .join('\n')} + +` + return xml +} + async function runTests( zen: Zen, opts: CLIOptions, @@ -138,7 +115,7 @@ function combineFailures( // Reset the error state for all the previous tests, that way if they // succeed it will report only as a flake for (const testName in failures) { - failures[testName].error = undefined + failures[testName].resolved = true } for (const testName in currentFailures) { @@ -146,10 +123,14 @@ function combineFailures( const curFailure = currentFailures[testName] if (!prevFailure) { - failures[testName] = curFailure + failures[testName] = { + ...curFailure, + resolved: false, + } } else { failures[testName] = { ...prevFailure, + resolved: false, error: curFailure.error, time: prevFailure.time + curFailure.time, attempts: prevFailure.attempts + curFailure.attempts, @@ -160,7 +141,10 @@ function combineFailures( return failures } -async function run(zen: Zen, opts: CLIOptions) { +export default async function runRemote( + zen: Zen, + opts: CLIOptions +): Promise { try { let t0 = Date.now() if (zen.webpack) { @@ -254,7 +238,15 @@ async function run(zen: Zen, opts: CLIOptions) { failCount === 1 ? '' : 's' }` ) - process.exit(failCount ? 1 : 0) + if (opts.junit && failures) { + const xml = resultsToXML(failures) + + console.log('Writing results to ' + opts.junit) + writeFileSync(join(process.cwd(), opts.junit), xml) + process.exit(0) + } else { + process.exit(failCount ? 1 : 0) + } } catch (e) { console.error(e) process.exit(1) diff --git a/lib/head.js b/lib/head.js index 4bcd658..61d908a 100644 --- a/lib/head.js +++ b/lib/head.js @@ -1,3 +1,5 @@ +/* eslint-env browser */ + let socket = null, store = null diff --git a/lib/journal.ts b/lib/journal.ts index 7dc9505..30e8605 100644 --- a/lib/journal.ts +++ b/lib/journal.ts @@ -30,7 +30,6 @@ export default class Journal { entry.tPass = test.time } - if (test.time > 2000) console.log(`{${test.time}} - ${test.fullName}`) this.lazyFlush() } diff --git a/lib/lambda.ts b/lib/lambda.ts index 2593cfa..f1be091 100644 --- a/lib/lambda.ts +++ b/lib/lambda.ts @@ -65,7 +65,6 @@ export const workTests = async ( const deflakeLimit = opts.deflakeLimit || 3 for (let attempt = 1; attempt <= deflakeLimit; attempt++) { const remainingTests = getRemainingTests() - console.log('REMAINING TESTS', remainingTests) if (remainingTests.length === 0) break await runTestSet(remainingTests, tab) @@ -104,7 +103,6 @@ export const workTests = async ( time: 0, // TODO figure out a good way to get time }) } else { - console.log('UNKOWN ERROR') console.error(e) } } @@ -129,7 +127,6 @@ export const sync = async ( ): Promise<{ needed: File[] }> => { if (!process.env.ASSET_BUCKET) throw new Error('ASSET_BUCKET not set') const bucket = process.env.ASSET_BUCKET - console.log('bucket', bucket) const s3 = new AWS.S3({ params: { Bucket: bucket } }) // Write the updated session manifest to S3 @@ -145,17 +142,15 @@ export const sync = async ( // to check, and S3 is pruned to have less than 2k files. Blame this comment for an example. const needed: File[] = [] const toCheck = manifest.files.filter((f) => f.toCheck) - console.log(`Checking ${toCheck.length} files`) await Promise.all( toCheck.map(async (f) => { try { - const resp = await s3 + await s3 .headObject({ Bucket: bucket, Key: f.versionedPath, }) .promise() - console.log('Found', f.versionedPath, resp) } catch (e) { if (e instanceof Error) { const error = e as AWS.AWSError @@ -169,7 +164,6 @@ export const sync = async ( ) await manifestWrite - console.log('Manifest written') return { needed } } @@ -187,7 +181,6 @@ async function prepareChrome({ sessionId }: { sessionId: string }) { console.log('Chrome is already setup!') } - console.log('Opening tab') return await wrapper.openTab( process.env.GATEWAY_URL + '/index.html', sessionId, @@ -218,7 +211,7 @@ async function getManifest(sessionId: string) { manifest.assetUrl = `https://s3-${process.env.AWS_REGION}.amazonaws.com/${bucket}` return manifest } catch (e) { - console.log(e) + console.error('Error getting manifest: ', e) return null } } diff --git a/lib/latte.ts b/lib/latte.ts index 95085eb..f7c5312 100644 --- a/lib/latte.ts +++ b/lib/latte.ts @@ -164,7 +164,6 @@ declare global { try { for (const test of tests) { if (!test.fn) continue - console.log(`${test.fullName}`) Latte.currentTest = test whenCurrentTestFinished = new RealPromise( (res) => (currentTestResolve = res) diff --git a/lib/server.js b/lib/server.js index 44c53f0..dbc21b1 100644 --- a/lib/server.js +++ b/lib/server.js @@ -105,7 +105,6 @@ module.exports = class Server { const result = results.at(-1) if (!result) { - console.log(test, response.results, results) return { fullName: test, attempts: 0, diff --git a/lib/util.ts b/lib/util.ts index 01bc627..dec19a6 100644 --- a/lib/util.ts +++ b/lib/util.ts @@ -183,20 +183,8 @@ export async function workTests( // If there are timeouts, then keep calling workTests again with the unresolved tests if (timeoutTests.length > 0 && rerun) { - console.log('RERUNNING DUE TO LAMBDA TIMEOUT', timeoutTests) - await timeout(30_000) - // We don't want this going on endlessly, because there are other errors we may want to do work - const newResponse = await workTests( - zen, - { ...args, testNames: timeoutTests }, - false - ) - timeoutTests.forEach((test) => { - response.results[test] = [ - ...response.results[test], - ...newResponse.results[test], - ] - }) + console.log('Delaying tests a bit due to lambda timeout') + await timeout(10_000) } return response diff --git a/lib/webpack/webpack-client.ts b/lib/webpack/webpack-client.ts index 5fd5308..8bc9b84 100644 --- a/lib/webpack/webpack-client.ts +++ b/lib/webpack/webpack-client.ts @@ -1,6 +1,4 @@ module.hot?.accept((err) => { - // TODO I think this might be the source of refresh looping - console.log('LOOPING') if (err) location.reload() }) diff --git a/lib/worker.js b/lib/worker.js index 9b4d1f2..1ee98b2 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -1,3 +1,5 @@ +/* eslint-env browser */ + ;(function () { let params = new URLSearchParams(location.search) let workerId = params.get('id') diff --git a/package.json b/package.json index 3e36941..03fdc5d 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "test": "echo \"Ironic: no test specified\" && exit 1", "format": "prettier --write --ignore-unknown .", "lint": "prettier --check . && tsc --noEmit", - "build": "node ./build.js", - "start": "node ./build.js -w", + "build": "node ./build.mjs", + "start": "node ./build.mjs -w", "prepare": "npm run build", "tools:upload-lambda": "ts-node ./tools/upload_lambda.ts" }, @@ -36,6 +36,7 @@ "aws-sdk": "^2.238.1", "btoa": "^1.2.1", "connect": "^3.6.1", + "entities": "^4.4.0", "fuzzysort": "^1.1.4", "klaw": "^2.1.1", "mime-types": "^2.1.17", diff --git a/yarn.lock b/yarn.lock index dbc446c..39affba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1771,6 +1771,11 @@ enquirer@^2.3.5: dependencies: ansi-colors "^4.1.1" +entities@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" + integrity sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA== + errno@^0.1.3, errno@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"