From 1ff421fc71e39876f0ae32dd9d6ed1c2ba0826ea Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 5 Oct 2021 14:38:28 -0700 Subject: [PATCH] Add 'slow' option to configure slow test threshold --- cli/lib/cli.js | 3 +++ cli/lib/exec/run.js | 4 ++++ cli/lib/util.js | 1 + cli/schema/cypress.schema.json | 5 +++++ cli/types/cypress-npm-api.d.ts | 4 ++++ cli/types/cypress.d.ts | 5 +++++ packages/server/lib/config_options.ts | 4 ++++ packages/server/lib/project-base.ts | 13 ++++++++----- packages/server/lib/reporter.js | 21 ++++++++++++++------- packages/server/lib/util/args.js | 2 +- packages/server/test/support/helpers/e2e.ts | 4 ++++ packages/server/test/unit/config_spec.js | 1 + packages/server/test/unit/reporter_spec.js | 13 ++++++++++++- 13 files changed, 66 insertions(+), 14 deletions(-) diff --git a/cli/lib/cli.js b/cli/lib/cli.js index a0237380c5..8d6c3ea882 100644 --- a/cli/lib/cli.js +++ b/cli/lib/cli.js @@ -125,6 +125,7 @@ const descriptions = { record: 'records the run. sends test results, screenshots and videos to your Cypress Dashboard.', reporter: 'runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec"', reporterOptions: 'options for the mocha reporter. defaults to "null"', + slow: '"slow" test threshold in milliseconds. defaults to 5000', spec: 'runs specific spec file(s). defaults to "all"', tag: 'named tag(s) for recorded runs in the Cypress Dashboard', version: 'prints Cypress version', @@ -264,6 +265,7 @@ const addCypressRunCommand = (program) => { .option('-r, --reporter ', text('reporter')) .option('-o, --reporter-options ', text('reporterOptions')) .option('-s, --spec ', text('spec')) + .option('-S, --slow ', text('slow')) .option('-t, --tag ', text('tag')) .option('--dev', text('dev'), coerceFalse) } @@ -451,6 +453,7 @@ module.exports = { .option('-r, --reporter ', text('reporter')) .option('-o, --reporter-options ', text('reporterOptions')) .option('-s, --spec ', text('spec')) + .option('-S, --slow ', text('slow')) .option('-t, --tag ', text('tag')) .option('--dev', text('dev'), coerceFalse) .action((opts) => { diff --git a/cli/lib/exec/run.js b/cli/lib/exec/run.js index b5fac314e8..03c59a3d4d 100644 --- a/cli/lib/exec/run.js +++ b/cli/lib/exec/run.js @@ -128,6 +128,10 @@ const processRunOptions = (options = {}) => { args.push('--reporter-options', options.reporterOptions) } + if (options.slow) { + args.push('--slow', options.slow) + } + // if we have specific spec(s) push that into the args if (options.spec) { args.push('--spec', options.spec) diff --git a/cli/lib/util.js b/cli/lib/util.js index da4729caab..f85fc242e0 100644 --- a/cli/lib/util.js +++ b/cli/lib/util.js @@ -220,6 +220,7 @@ const parseOpts = (opts) => { 'reporterOptions', 'record', 'runProject', + 'slow', 'spec', 'tag') diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json index 617664c102..c269b6c1bc 100644 --- a/cli/schema/cypress.schema.json +++ b/cli/schema/cypress.schema.json @@ -44,6 +44,11 @@ "default": null, "description": "The reporter options used. Supported options depend on the reporter. See https://on.cypress.io/reporters#Reporter-Options" }, + "slow": { + "type": "number", + "default": 5000, + "description": "Slow test timeout passed to mocha. See See https://on.cypress.io/configuration#Global" + }, "testFiles": { "type": [ "string", diff --git a/cli/types/cypress-npm-api.d.ts b/cli/types/cypress-npm-api.d.ts index c60a347138..28e273fc5d 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -91,6 +91,10 @@ declare namespace CypressCommandLine { * Specify mocha reporter options */ reporterOptions: any + /** + * Specify a slow test threshold in milliseconds + */ + slow: number /** * Specify the specs to run */ diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 5dd65e6b05..1e7d4c1e30 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -2572,6 +2572,11 @@ declare namespace Cypress { * @default "spec" */ reporterOptions: { [key: string]: any } + /** + * A slow test threshold in milliseconds + * @default 5000 + */ + slow: number | null /** * Whether Cypress will watch and restart tests on test file changes * @default true diff --git a/packages/server/lib/config_options.ts b/packages/server/lib/config_options.ts index 2c02b10dad..62990f0fcd 100644 --- a/packages/server/lib/config_options.ts +++ b/packages/server/lib/config_options.ts @@ -216,6 +216,10 @@ export const options = [ defaultValue: 'cypress/screenshots', validation: v.isStringOrFalse, isFolder: true, + }, { + name: 'slow', + defaultValue: 5000, + validation: v.isNumber, }, { name: 'socketId', defaultValue: null, diff --git a/packages/server/lib/project-base.ts b/packages/server/lib/project-base.ts index 7ccf66ded5..75c0b5cb90 100644 --- a/packages/server/lib/project-base.ts +++ b/packages/server/lib/project-base.ts @@ -38,7 +38,7 @@ import type { LaunchArgs } from './open_project' // and are required when creating a project. type ReceivedCypressOptions = Pick - & Pick // TODO: Figure out how to type this better. + & Pick // TODO: Figure out how to type this better. export interface Cfg extends ReceivedCypressOptions { projectRoot: string @@ -75,7 +75,7 @@ const localCwd = cwd() const debug = Debug('cypress:server:project') const debugScaffold = Debug('cypress:server:scaffold') -type StartWebsocketOptions = Pick +type StartWebsocketOptions = Pick export class ProjectBase extends EE { protected watchers: Watchers @@ -273,6 +273,7 @@ export class ProjectBase extends EE { report: cfg.report, reporter: cfg.reporter, reporterOptions: cfg.reporterOptions, + slow: cfg.slow, projectRoot: this.projectRoot, }) @@ -554,7 +555,8 @@ export class ProjectBase extends EE { reporter, projectRoot, reporterOptions, - }: Pick) { + slow, + }: Pick) { if (!report) { return } @@ -575,10 +577,10 @@ export class ProjectBase extends EE { }) } - return Reporter.create(reporter, reporterOptions, projectRoot) + return Reporter.create(reporter, reporterOptions, projectRoot, slow) } - startWebsockets (options: Omit, { socketIoCookie, namespace, screenshotsFolder, report, reporter, reporterOptions, projectRoot }: StartWebsocketOptions) { + startWebsockets (options: Omit, { socketIoCookie, namespace, screenshotsFolder, report, reporter, reporterOptions, slow, projectRoot }: StartWebsocketOptions) { // if we've passed down reporter // then record these via mocha reporter const reporterInstance = this.initializeReporter({ @@ -586,6 +588,7 @@ export class ProjectBase extends EE { reporter, reporterOptions, projectRoot, + slow, }) const onBrowserPreRequest = (browserPreRequest) => { diff --git a/packages/server/lib/reporter.js b/packages/server/lib/reporter.js index f4b09fad4f..a511a4b16f 100644 --- a/packages/server/lib/reporter.js +++ b/packages/server/lib/reporter.js @@ -70,9 +70,11 @@ const getParentTitle = function (runnable, titles) { return titles } -const createSuite = function (obj, parent) { +const createSuite = function (obj, parent, slow) { const suite = new Mocha.Suite(obj.title, {}) + suite.slow(slow) + if (parent) { suite.parent = parent } @@ -83,7 +85,7 @@ const createSuite = function (obj, parent) { return suite } -const createRunnable = function (obj, parent) { +const createRunnable = function (obj, parent, slow) { let fn const { body } = obj @@ -104,6 +106,9 @@ const createRunnable = function (obj, parent) { runnable._retries = obj._retries // shouldn't need to set _currentRetry, but we'll do it anyways runnable._currentRetry = obj._currentRetry + // Because of the way we create the runnables without belonging to an instantiated mocha object, + // we have to set the 'slow' speed for each test and suite individually + runnable.slow(slow) if (runnable.body == null) { runnable.body = body @@ -250,7 +255,7 @@ const reporters = { } class Reporter { - constructor (reporterName = 'spec', reporterOptions = {}, projectRoot) { + constructor (reporterName = 'spec', reporterOptions = {}, projectRoot, slow) { if (!(this instanceof Reporter)) { return new Reporter(reporterName) } @@ -258,6 +263,7 @@ class Reporter { this.reporterName = reporterName this.projectRoot = projectRoot this.reporterOptions = reporterOptions + this.slow = slow this.normalizeTest = this.normalizeTest.bind(this) } @@ -273,6 +279,7 @@ class Reporter { const reporter = Reporter.loadReporter(this.reporterName, this.projectRoot) this.mocha = new Mocha({ reporter }) + this.mocha.slow(this.slow) this.mocha.suite = rootRunnable this.runner = new Mocha.Runner(rootRunnable) mochaCreateStatsCollector(this.runner) @@ -301,7 +308,7 @@ class Reporter { switch (type) { case 'suite': // eslint-disable-next-line no-case-declarations - const suite = createSuite(runnableProps, parent) + const suite = createSuite(runnableProps, parent, this.slow) suite.tests = _.map(runnableProps.tests, (testProps) => { return this._createRunnable(testProps, 'test', suite) @@ -313,7 +320,7 @@ class Reporter { return suite case 'test': - return createRunnable(runnableProps, parent) + return createRunnable(runnableProps, parent, this.slow) default: throw new Error(`Unknown runnable type: '${type}'`) } @@ -472,8 +479,8 @@ class Reporter { }) } - static create (reporterName, reporterOptions, projectRoot) { - return new Reporter(reporterName, reporterOptions, projectRoot) + static create (reporterName, reporterOptions, projectRoot, slow) { + return new Reporter(reporterName, reporterOptions, projectRoot, slow) } static loadReporter (reporterName, projectRoot) { diff --git a/packages/server/lib/util/args.js b/packages/server/lib/util/args.js index 1dd9d19ee3..6a227dc686 100644 --- a/packages/server/lib/util/args.js +++ b/packages/server/lib/util/args.js @@ -13,7 +13,7 @@ const nestedObjectsInCurlyBracesRe = /\{(.+?)\}/g const nestedArraysInSquareBracketsRe = /\[(.+?)\]/g const everythingAfterFirstEqualRe = /=(.*)/ -const allowList = 'appPath apiKey browser ci ciBuildId clearLogs config configFile cwd env execPath exit exitWithCode group headed inspectBrk key logs mode outputPath parallel ping port project proxySource quiet record reporter reporterOptions returnPkg runMode runProject smokeTest spec tag updating version testingType'.split(' ') +const allowList = 'appPath apiKey browser ci ciBuildId clearLogs config configFile cwd env execPath exit exitWithCode group headed inspectBrk key logs mode outputPath parallel ping port project proxySource quiet record reporter reporterOptions returnPkg runMode runProject slow smokeTest spec tag updating version testingType'.split(' ') // returns true if the given string has double quote character " // only at the last position. const hasStrayEndQuote = (s) => { diff --git a/packages/server/test/support/helpers/e2e.ts b/packages/server/test/support/helpers/e2e.ts index 5f778be5af..bfe83d70b7 100644 --- a/packages/server/test/support/helpers/e2e.ts +++ b/packages/server/test/support/helpers/e2e.ts @@ -605,6 +605,10 @@ const e2e = { args.push(`--reporter-options=${options.reporterOptions}`) } + if (options.slow) { + args.push(`--slow=${options.slow}`) + } + if (options.browser) { args.push(`--browser=${options.browser}`) } diff --git a/packages/server/test/unit/config_spec.js b/packages/server/test/unit/config_spec.js index 0d35983df6..ccce7b931c 100644 --- a/packages/server/test/unit/config_spec.js +++ b/packages/server/test/unit/config_spec.js @@ -1460,6 +1460,7 @@ describe('lib/config', () => { retries: { value: { runMode: 0, openMode: 0 }, from: 'default' }, screenshotOnRunFailure: { value: true, from: 'default' }, screenshotsFolder: { value: 'cypress/screenshots', from: 'default' }, + slow: { value: 5000, from: 'default' }, supportFile: { value: 'cypress/support', from: 'default' }, taskTimeout: { value: 60000, from: 'default' }, testFiles: { value: '**/*.*', from: 'default' }, diff --git a/packages/server/test/unit/reporter_spec.js b/packages/server/test/unit/reporter_spec.js index c84db90e43..cde8b266d5 100644 --- a/packages/server/test/unit/reporter_spec.js +++ b/packages/server/test/unit/reporter_spec.js @@ -94,6 +94,18 @@ describe('lib/reporter', () => { expect(junitFn).to.be.calledWith(reporter.runner) }) + + it('passes the slow option through to mocha', function () { + const reporter = new Reporter('spec', {}, undefined, 2000) + + reporter.setRunnables(this.root) + + Object.values(reporter.runnables).forEach(function (v) { + expect(v._slow).to.eq(2000) + }) + + expect(reporter.mocha.suite._slow).to.eq(2000) + }) }) context('createSuite', () => { @@ -111,7 +123,6 @@ describe('lib/reporter', () => { it('recursively creates suites for fullTitle', function () { const args = this.reporter.parseArgs('fail', [this.testObj]) - console.log(args) expect(args[0]).to.eq('fail') const title = 'TodoMVC - React When page is initially opened should focus on the todo input field'