Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: test config overrides #5346

Merged
merged 118 commits into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
12e363e
decaffeinate: Rename browser.coffee from .coffee to .js
kuceb Feb 13, 2020
f2f06be
decaffeinate: Convert browser.coffee to JS
kuceb Feb 13, 2020
b81af00
decaffeinate: Run post-processing cleanups on browser.coffee
kuceb Feb 13, 2020
bf8bc35
temp 02/14/20 [skip ci]
kuceb Feb 14, 2020
599d978
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Feb 14, 2020
55f33c0
add beforeEachRestoreRunner to select specs, remove support file hook
kuceb Feb 14, 2020
14b43e4
temp 03/03/20 [skip ci]
kuceb Mar 3, 2020
dc82406
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Mar 3, 2020
2e4057c
fix more specs due to support file change
kuceb Mar 5, 2020
b18f616
fix errored spec
kuceb Mar 6, 2020
f183c53
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Mar 6, 2020
06fab91
add isInteractive config to many specs
kuceb Mar 6, 2020
21ae7d7
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Mar 6, 2020
9640993
update yarn.lock
kuceb Mar 6, 2020
43ce710
use yarn.lock from develop
kuceb Mar 6, 2020
517f78e
fix nested suite configurations
kuceb Mar 9, 2020
b53ece7
fix nested suite configurations 2
kuceb Mar 10, 2020
725840c
force isInteractive in driver/support file
kuceb Mar 10, 2020
1f0ba14
update more specs to use test config format
kuceb Mar 10, 2020
1bc586f
update more specs to use test config format 2
kuceb Mar 10, 2020
9d6665f
update more specs to use test config format 3
kuceb Mar 10, 2020
691f2b2
update more specs to use test config format 4
kuceb Mar 11, 2020
0bf0a32
update more specs to use test config format 5
kuceb Mar 11, 2020
742f786
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Mar 11, 2020
818d67b
fix cli/types tests, unit tests
kuceb Mar 11, 2020
2888e04
cleanup
kuceb Mar 11, 2020
0cfc60a
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Apr 7, 2020
bd55fdc
allow .isBrowser to support array, use .isBrowser for per-test-config
kuceb Apr 8, 2020
fa3d8d1
allow null browser test/suite config value
kuceb Apr 8, 2020
75860b4
temp 04/10/20 [skip ci]
kuceb Apr 10, 2020
d2a4b9d
restore test originalTitle when skip due to browser
kuceb Apr 15, 2020
d02ffec
add tests for per-test-config baseUrl
kuceb Apr 15, 2020
10c97af
update .isBrowser error message
kuceb Apr 15, 2020
c09f90b
fix rerunning hooks on top navigation
kuceb Apr 16, 2020
b0500bf
rename duplicate issue number
kuceb Apr 16, 2020
4c520b7
up timeout for server/integration test
kuceb Apr 16, 2020
1bc41ff
change test to be more specific
kuceb Apr 16, 2020
742ed86
Merge branch 'fix-rerun-hooks-on-navigation' into declarative-test-co…
kuceb Apr 16, 2020
0834715
rename TestOptions, add baseUrl test, override xit xdescribe methods
kuceb Apr 17, 2020
e4fd561
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Apr 17, 2020
fc62315
add tests for xit/xdescribe
kuceb Apr 17, 2020
53ece8a
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Apr 22, 2020
368e5ac
Merge branch 'fix-rerun-hooks-on-navigation' into declarative-test-co…
kuceb Apr 22, 2020
71f7658
disable video for flaky e2e test
kuceb Apr 22, 2020
9efee15
fix lint-types, e2e snapshot
kuceb Apr 22, 2020
2dd7b41
try 2: fix rerun before/after hooks
kuceb Apr 27, 2020
82d8203
Merge branch 'develop' into declarative-test-configs
brian-mann Apr 27, 2020
2c6d1f9
temp 04/29/20 [skip ci]
kuceb Apr 29, 2020
85503d3
change logic to rerun before hooks after top navigation
kuceb Apr 30, 2020
46c116d
fix windowSize for browser e2e test
kuceb May 4, 2020
590a573
fix windowSize for xvfb chrome in e2e test
kuceb May 4, 2020
22d2780
ok fine, just disable screenshots
kuceb May 4, 2020
6d1451d
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 7, 2020
ec77ac3
perf: faster lookup for hooks without runnables
kuceb May 7, 2020
751e752
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 8, 2020
6790888
fix afterAll hook switch logic
kuceb May 8, 2020
2f06046
backport to before/after fix
kuceb May 20, 2020
75bf3bf
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 20, 2020
d230c17
backport to before/after fix 2
kuceb May 20, 2020
f2977b7
fix noExit passed to e2e test inline options
kuceb May 22, 2020
836fc0a
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 22, 2020
d15fc1f
remove extra root afterhook check
kuceb May 22, 2020
ba5c388
add issue link..twice
kuceb May 22, 2020
9061197
cleanup function to arrows
kuceb May 22, 2020
bc27e9c
remove Cypress object proxying related code for certain utils
kuceb May 26, 2020
e653294
use getTest() as we did previously
kuceb May 26, 2020
b5fc7a0
remove Cypress object proxying related code for certain utils
kuceb May 26, 2020
512ccd0
fix Cypress._RESUMED_AT_TEST access
kuceb May 26, 2020
2802664
fix Cypress._RESUMED_AT_TEST access 2
kuceb May 26, 2020
fd3e7b1
fix runner.getResumedAtTestIndex, state accesses
kuceb May 26, 2020
2538d7b
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 26, 2020
ffc1c3d
fix firefoxgcinterval access
kuceb May 26, 2020
dd41468
fix arrow function
kuceb May 26, 2020
e5a1040
fix firefoxgcinterval access
kuceb May 26, 2020
7070f4f
try a simpler way to fix afterAll hook issue
kuceb May 26, 2020
f2d4663
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 27, 2020
e8eeabf
Merge remote-tracking branch 'origin/develop' into chore-remove-obj-p…
kuceb May 27, 2020
e3ad51a
fix decaf after merge
kuceb May 27, 2020
a2c39f6
cleanup internal-types.d.ts
kuceb May 27, 2020
929fa48
Merge branch 'chore-remove-obj-proxying-logic' into 2-fix-rerun-hooks…
kuceb May 27, 2020
366578e
fix internal-types
kuceb May 27, 2020
9643cb1
Merge branch 'chore-remove-obj-proxying-logic' into 2-fix-rerun-hooks…
kuceb May 27, 2020
f239874
Merge remote-tracking branch 'origin/develop' into 2-fix-rerun-hooks-…
kuceb May 27, 2020
02f12f7
fix comment, getTestFromRunnable signature
kuceb May 27, 2020
0172ad7
Merge branch '2-fix-rerun-hooks-on-navigation' into declarative-test-…
kuceb May 27, 2020
ea8142c
remove unneeded lastTestInSuiteLogic
kuceb May 27, 2020
cb044eb
fix after merge: many decaffed specs, typedefs
kuceb May 28, 2020
00e02e9
Merge remote-tracking branch 'origin/2-fix-rerun-hooks-on-navigation'…
kuceb May 28, 2020
8b02cff
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb May 28, 2020
8951420
minor cleanup
kuceb May 28, 2020
9f850cd
Merge remote-tracking branch 'origin/declarative-test-configs' into d…
kuceb May 28, 2020
455c3e9
fix typedefs: add taskTimeout
kuceb May 28, 2020
e776f7d
Merge branch 'fix-typedefs-config-taskTimeout' into declarative-test-…
kuceb May 28, 2020
a141f06
minor typedef fix, fix more specs modifying config()
kuceb May 28, 2020
5ae0298
fix e2e snapshot
kuceb May 29, 2020
5893eef
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb May 29, 2020
bf59979
fix flake: waiting_spec cancel outstanding XHR between tests
kuceb Jun 1, 2020
cff307f
fix flake
kuceb Jun 2, 2020
03ec65d
change config mutation logic, add tests, update typedefs
kuceb Jun 2, 2020
7521bda
add env support to testConfigOverride
kuceb Jun 2, 2020
1d6cbb9
fix specs: remove isInteractive override, add to beforeEach
kuceb Jun 2, 2020
2b62849
move testConfigOverride to file
kuceb Jun 2, 2020
f20c4bb
finish moving local config logic to cy.js
kuceb Jun 3, 2020
022c30a
Merge remote-tracking branch 'origin/develop' into declarative-test-c…
kuceb Jun 3, 2020
95de111
fix typedefs cypress.d.ts
kuceb Jun 3, 2020
b58c039
fix minor minor dtslint
kuceb Jun 3, 2020
3c21868
minor spec cleanup
kuceb Jun 3, 2020
ce5ed51
chunk: typescript spec fixes, bind Cypress.$
kuceb Jun 3, 2020
36c2d40
apply chunk: typescript spec fixes, bind Cypress.$
kuceb Jun 3, 2020
b9f97c9
fix stop-only
kuceb Jun 3, 2020
645315d
fix stop-only 2
kuceb Jun 3, 2020
f1c4722
extend the jqueryProxyFn in the constructor
brian-mann Jun 3, 2020
20ba034
remove experimental code
brian-mann Jun 3, 2020
bbaa98a
Merge remote-tracking branch 'origin/chore-fix-typescript-spec-global…
kuceb Jun 3, 2020
bef013b
rename spec files for overrides, cleanup
kuceb Jun 3, 2020
f4cdfb6
Merge branch 'develop' into declarative-test-configs
brian-mann Jun 3, 2020
a8b3271
rename snapshots + tests to match updated test config overrides
brian-mann Jun 4, 2020
bd4e943
fix firefox flake: navigation_spec
kuceb Jun 4, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
76 changes: 74 additions & 2 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ declare namespace Cypress {
clear: (keys?: string[]) => void
}

type IsBrowserMatcher = BrowserName | Partial<Browser> | Array<BrowserName | Partial<Browser>>

interface ViewportPosition extends WindowPosition {
right: number
bottom: number
Expand Down Expand Up @@ -327,12 +329,15 @@ declare namespace Cypress {
isCy(obj: any): obj is Chainable

/**
* Returns true if currently running the supplied browser name or matcher object.
* Returns true if currently running the supplied browser name or matcher object. Also accepts an array of matchers.
* @example isBrowser('chrome') will be true for the browser 'chrome:canary' and 'chrome:stable'
* @example isBrowser({ name: 'firefox', channel: 'dev' }) will be true only for the browser 'firefox:dev' (Firefox Developer Edition)
* @example isBrowser(['firefox', 'edge']) will be true only for the browsers 'firefox' and 'edge'
* @example isBrowser('!firefox') will be true for every browser other than 'firefox'
* @example isBrowser({ family: '!chromium'}) will be true for every browser not matching { family: 'chromium' }
* @param matcher browser name or matcher object to check.
*/
isBrowser(name: BrowserName | Partial<Browser>): boolean
isBrowser(name: IsBrowserMatcher): boolean

/**
* Internal options for "cy.log" used in custom commands.
Expand Down Expand Up @@ -2417,6 +2422,11 @@ declare namespace Cypress {
experimentalSourceRewriting: boolean
}

interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'baseUrl' | 'defaultCommandTimeout' | 'taskTimeout' | 'animationDistanceThreshold' | 'waitForAnimations' | 'viewportHeight' | 'viewportWidth' | 'requestTimeout' | 'execTimeout' | 'env' | 'responseTimeout'>> {
// retries?: number
browser?: IsBrowserMatcher | IsBrowserMatcher[]
}

/**
* All configuration items are optional.
*/
Expand Down Expand Up @@ -4810,3 +4820,65 @@ declare namespace Cypress {
*/
interface cy extends Chainable<undefined> {}
}

declare namespace Mocha {
interface TestFunction {
/**
* Describe a specification or test-case with the given `title`, TestCptions, and callback `fn` acting
* as a thunk.
*/
(title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test

/**
* Describe a specification or test-case with the given `title`, TestCptions, and callback `fn` acting
* as a thunk.
*/
(title: string, config: Cypress.TestConfigOverrides, fn?: AsyncFunc): Test
}
interface ExclusiveTestFunction {
/**
* Describe a specification or test-case with the given `title`, TestCptions, and callback `fn` acting
* as a thunk.
*/
(title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test

/**
* Describe a specification or test-case with the given `title`, TestCptions, and callback `fn` acting
* as a thunk.
*/
(title: string, config: Cypress.TestConfigOverrides, fn?: AsyncFunc): Test
}
interface PendingTestFunction {
/**
* Describe a specification or test-case with the given `title`, TestCptions, and callback `fn` acting
* as a thunk.
*/
(title: string, config: Cypress.TestConfigOverrides, fn?: Func): Test

/**
* Describe a specification or test-case with the given `title`, TestCptions, and callback `fn` acting
* as a thunk.
*/
(title: string, config: Cypress.TestConfigOverrides, fn?: AsyncFunc): Test
}

interface SuiteFunction {
/**
* Describe a "suite" with the given `title`, TestCptions, and callback `fn` containing
* nested suites.
*/
(title: string, config: Cypress.TestConfigOverrides, fn: (this: Suite) => void): Suite
}

interface ExclusiveSuiteFunction {
/**
* Describe a "suite" with the given `title`, TestCptions, and callback `fn` containing
* nested suites. Indicates this suite should be executed exclusively.
*/
(title: string, config: Cypress.TestConfigOverrides, fn: (this: Suite) => void): Suite
}

interface PendingSuiteFunction {
(title: string, config: Cypress.TestConfigOverrides, fn: (this: Suite) => void): Suite | void
}
}
44 changes: 44 additions & 0 deletions cli/types/tests/cypress-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,47 @@ namespace CypressDomTests {
Cypress.dom.getElementCoordinatesByPosition(doc, 'top') // $ExpectError
Cypress.dom.getElementCoordinatesByPositionRelativeToXY(doc, 1, 2) // $ExpectError
}

namespace CypressTestConfigOverridesTests {
// set config on a per-test basis
it('test', {
browser: {name: 'firefox'}
}, () => {})
it('test', {
browser: [{name: 'firefox'}, {name: 'chrome'}]
}, () => {})
it('test', {
baseUrl: 'www.foobar.com',
browser: 'firefox'
}, () => {})
it('test', {
browser: {foo: 'bar'} // $ExpectError
}, () => {})

it.skip('test', {}, () => {})
it.only('test', {}, () => {})
xit('test', {}, () => {})

specify('test', {}, () => {})
specify.only('test', {}, () => {})
specify.skip('test', {}, () => {})
xspecify('test', {}, () => {})

// set config on a per-suite basis
describe('suite', {
browser: {family: 'firefox'},
baseUrl: 'www.example.com'
}, () => {})

context('suite', {}, () => {})

describe('suite', {
browser: {family: 'firefox'},
baseUrl: 'www.example.com'
foo: 'foo' // $ExpectError
}, () => {})

describe.only('suite', {}, () => {})
describe.skip('suite', {}, () => {})
xdescribe('suite', {}, () => {})
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"set-next-ci-version": "node ./scripts/binary.js setNextVersion",
"prestart": "yarn ensure-deps",
"start": "node $(yarn bin cypress) open --dev --global",
"stop-only": "npx stop-only --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,src --exclude e2e.ts",
"stop-only": "npx stop-only --skip .cy,.publish,.projects,node_modules,dist,dist-test,fixtures,lib,bower_components,src --exclude e2e.ts,cypress-tests.ts",
"stop-only-all": "yarn stop-only --folder packages",
"pretest": "yarn ensure-deps",
"test": "yarn lerna exec yarn test --scope cypress --scope \"'@packages/{electron,extension,https-proxy,launcher,network,proxy,rewriter,reporter,runner,socket}'\"",
Expand Down
76 changes: 76 additions & 0 deletions packages/driver/src/cy/testConfigOverrides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const _ = require('lodash')

function mutateConfiguration (testConfigOverride, config, env) {
const globalConfig = _.clone(config())
const globalEnv = _.clone(env())

delete testConfigOverride.browser
config(testConfigOverride)

const localTestConfig = config()
const localTestConfigBackup = _.clone(localTestConfig)

if (testConfigOverride.env) {
env(testConfigOverride.env)
}

const localTestEnv = env()
const localTestEnvBackup = _.clone(localTestEnv)

// we restore config back to what it was before the test ran
// UNLESS the user mutated config with Cypress.config, in which case
// we apply those changes to the global config
// TODO: (NEXT_BREAKING) always restore configuration
// do not allow global mutations inside test
const restoreConfigFn = function () {
_.each(localTestConfig, (val, key) => {
if (localTestConfigBackup[key] !== val) {
globalConfig[key] = val
}
})

_.each(localTestEnv, (val, key) => {
if (localTestEnvBackup[key] !== val) {
globalEnv[key] = val
}
})

config.reset()
config(globalConfig)
env.reset()
env(globalEnv)
}

return restoreConfigFn
}

function getResolvedTestConfigOverride (test) {
let curParent = test.parent

const cfgs = [test.cfg]

while (curParent) {
if (curParent.cfg) {
cfgs.push(curParent.cfg)
}

curParent = curParent.parent
}

return _.reduceRight(cfgs, (acc, cfg) => _.extend(acc, cfg), {})
}

class TestConfigOverride {
private restoreTestConfigFn: Nullable<() => void> = null
restoreAndSetTestConfigOverrides (test, config, env) {
if (this.restoreTestConfigFn) this.restoreTestConfigFn()

const resolvedTestConfig = getResolvedTestConfigOverride(test)

this.restoreTestConfigFn = mutateConfiguration(resolvedTestConfig, config, env)
}
}

export function create () {
return new TestConfigOverride()
}
4 changes: 3 additions & 1 deletion packages/driver/src/cypress.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ class $Cypress {
longStackTraces: config.isInteractive,
})

// TODO: env is unintentionally preserved between soft reruns unlike config.
// change this in the NEXT_BREAKING
const { env } = config

config = _.omit(config, 'env', 'remote', 'resolved', 'scaffoldedFiles', 'javascripts', 'state')
Expand Down Expand Up @@ -362,7 +364,7 @@ class $Cypress {

case 'runner:test:before:run':
// get back to a clean slate
this.cy.reset()
this.cy.reset(...args)

return this.emit('test:before:run', ...args)

Expand Down
60 changes: 51 additions & 9 deletions packages/driver/src/cypress/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,63 @@ const _ = require('lodash')
const $utils = require('./utils')
const $errUtils = require('./error_utils')

const isBrowser = function (config, obj = '') {
if (_.isString(obj)) {
const name = obj.toLowerCase()
const currentName = config.browser.name.toLowerCase()
const _isBrowser = (browser, matcher, errPrefix) => {
let isMatch
let exclusive = false

return name === currentName
const matchWithExclusion = (objValue, srcValue) => {
if (srcValue.startsWith('!')) {
exclusive = true

return objValue !== srcValue.slice(1)
}

return objValue === srcValue
}

if (_.isObject(obj)) {
return _.isMatch(config.browser, obj)
if (_.isString(matcher)) {
const name = matcher.toLowerCase()
const currentName = browser.name.toLowerCase()

isMatch = matchWithExclusion(currentName, name)
} else if (_.isObject(matcher)) {
isMatch = _.isMatchWith(browser, matcher, matchWithExclusion)
} else {
$errUtils.throwErrByPath('browser.invalid_arg', {
args: { prefix: errPrefix, obj: $utils.stringify(matcher) },
})
}

$errUtils.throwErrByPath('browser.invalid_arg', {
args: { method: 'isBrowser', obj: $utils.stringify(obj) },
return {
isMatch,
exclusive,
}
}

const isBrowser = (config, obj = '', errPrefix = '`Cypress.isBrowser()`') => {
return _
.chain(obj)
.concat([])
.map((matcher) => _isBrowser(config.browser, matcher, errPrefix))
.reduce((a, b) => {
kuceb marked this conversation as resolved.
Show resolved Hide resolved
if (!a) return b

if (a.exclusive && b.exclusive) {
return {
isMatch: a.isMatch && b.isMatch,
exclusive: true,
}
}

return {
isMatch: a.isMatch || b.isMatch,
exclusive: b.exclusive,
}
}, null)
.thru((result) => {
return Boolean(result) && result.isMatch
})
.value()
}

module.exports = (config) => {
Expand Down
5 changes: 4 additions & 1 deletion packages/driver/src/cypress/cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const $selection = require('../dom/selection')
const $Snapshots = require('../cy/snapshots')
const $CommandQueue = require('./command_queue')
const $VideoRecorder = require('../cy/video-recorder')
const $TestConfigOverrides = require('../cy/testConfigOverrides')

const privateProps = {
props: { name: 'state', url: true },
Expand Down Expand Up @@ -147,6 +148,7 @@ const create = function (specWindow, Cypress, Cookies, state, config, log) {
const ensures = $Ensures.create(state, expect)

const snapshots = $Snapshots.create($$, state)
const testConfigOverrides = $TestConfigOverrides.create()

const isCy = (val) => {
return (val === cy) || $utils.isInstanceOf(val, $Chainer)
Expand Down Expand Up @@ -950,7 +952,7 @@ const create = function (specWindow, Cypress, Cookies, state, config, log) {
return doneEarly()
},

reset () {
reset (attrs, test) {
stopped = false

const s = state()
Expand All @@ -969,6 +971,7 @@ const create = function (specWindow, Cypress, Cookies, state, config, log) {

queue.reset()
timers.reset()
testConfigOverrides.restoreAndSetTestConfigOverrides(test, Cypress.config, Cypress.env)

return cy.removeAllListeners()
},
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/cypress/error_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ module.exports = {
},

browser: {
invalid_arg: '`Cypress.{{method}}()` must be passed the name of a browser or an object to filter with. You passed: `{{obj}}`',
invalid_arg: '{{prefix}} must be passed a string, object, or an array. You passed: `{{obj}}`',
},

chai: {
Expand Down