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

Upgrade mocha to latest version (5.2.0) #2703

Merged
merged 7 commits into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"method-override": "^2.3.1",
"minimatch": "^3.0.0",
"minimist": "^1.2.0",
"mocha": "cypress-io/mocha#58f6eac05e664fc6b69aa9fba70f1f6b5531a900",
"mocha": "5.2.0",
"moment": "^2.14.1",
"morgan": "^1.3.0",
"npm-install-version": "^6.0.2",
Expand Down
4 changes: 0 additions & 4 deletions packages/driver/src/cypress.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ class $Cypress
@action("cypress:config", config)

initialize: ($autIframe) ->
## push down the options
## to the runner
@mocha.options(@runner)

@cy.initialize($autIframe)

run: (fn) ->
Expand Down
12 changes: 9 additions & 3 deletions packages/driver/src/cypress/cy.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -1054,9 +1054,15 @@ create = (specWindow, Cypress, Cookies, state, config, log) ->

## if we're cy or we've enqueued commands
if isCy(ret) or (queue.length > currentLength)
## the run should already be kicked off
## by now and return this promise
return state("promise")
if fn.length
## if user has passed done callback
## don't return anything so we don't get an
## 'overspecified' error from mocha
return
else
## otherwise, return the 'queue promise'
## so mocha awaits it
return state("promise")

## else just return ret
return ret
Expand Down
11 changes: 11 additions & 0 deletions packages/driver/src/cypress/error_messages.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,17 @@ module.exports = {
async_timed_out: "Timed out after '{{ms}}ms'. The done() callback was never invoked!"
invalid_interface: "Invalid mocha interface '{{name}}'"
timed_out: "Cypress command timeout of '{{ms}}ms' exceeded."
overspecified: """
Cypress detected that you returned a promise in a test, but also invoked a done callback. Return a promise -or- invoke a done callback, not both.

Read more here: https://on.cypress.io/returning-promise-and-invoking-done-callback

#{divider(60, '-')}

Original mocha error:

{{error}}
"""

navigation:
cross_origin: """
Expand Down
6 changes: 3 additions & 3 deletions packages/driver/src/cypress/mocha.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ patchRunnerFail = ->
## matching the current Runner.prototype.fail except
## changing the logic for determing whether this is a valid err
Runner::fail = (runnable, err) ->
if err?.message?.indexOf("Resolution method is overspecified") > -1
err.message = $utils.errMessageByPath("mocha.overspecified", { error: err.stack })

## if this isnt a correct error object then just bail
## and call the original function
if Object.prototype.toString.call(err) isnt "[object Error]"
Expand Down Expand Up @@ -189,9 +192,6 @@ create = (specWindow, Cypress, reporter) ->

getRootSuite: ->
_mocha.suite

options: (runner) ->
runner.options(_mocha.options)
}

module.exports = {
Expand Down
150 changes: 58 additions & 92 deletions packages/driver/src/cypress/runner.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ Pending = require("mocha/lib/pending")
$Log = require("./log")
$utils = require("./utils")

defaultGrepRe = /.*/
mochaCtxKeysRe = /^(_runnable|test)$/
betweenQuotesRe = /\"(.+?)\"/

Expand Down Expand Up @@ -193,7 +192,7 @@ getAllSiblingTests = (suite, getTestById) ->
## iterate through each of our suites tests.
## this will iterate through all nested tests
## as well. and then we add it only if its
## in our grepp'd tests array
## in our filtered tests array
if getTestById(test.id)
tests.push test

Expand All @@ -212,7 +211,7 @@ getTestFromHook = (hook, suite, getTestById) ->
return found if found

## returns us the very first test
## which is in our grepped tests array
## which is in our filtered tests array
## based on walking down the current suite
## iterating through each test until it matches
found = onFirstTest suite, (test) =>
Expand All @@ -227,11 +226,11 @@ getTestFromHook = (hook, suite, getTestById) ->

## we have to see if this is the last suite amongst
## its siblings. but first we have to filter out
## suites which dont have a grep'd test in them
## suites which dont have a filtered test in them
isLastSuite = (suite, tests) ->
return false if suite.root

## grab all of the suites from our grep'd tests
## grab all of the suites from our filtered tests
## including all of their ancestor suites!
suites = _.reduce tests, (memo, test) ->
while parent = test.parent
Expand Down Expand Up @@ -296,17 +295,17 @@ overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, getTests)
when "afterEach"
t = getTest()

## find all of the grep'd _tests which share
## find all of the filtered _tests which share
## the same parent suite as our current _test
tests = getAllSiblingTests(t.parent, getTestById)

## make sure this test isnt the last test overall but also
## isnt the last test in our grep'd parent suite's tests array
## isnt the last test in our filtered parent suite's tests array
if @suite.root and (t isnt _.last(allTests)) and (t isnt _.last(tests))
changeFnToRunAfterHooks()

when "afterAll"
## find all of the grep'd allTests which share
## find all of the filtered allTests which share
## the same parent suite as our current _test
if t = getTest()
siblings = getAllSiblingTests(t.parent, getTestById)
Expand All @@ -327,17 +326,6 @@ overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, getTests)

_runnerHook.call(@, name, fn)

matchesGrep = (runnable, grep) ->
## we have optimized this iteration to the maximum.
## we memoize the existential matchesGrep property
## so we dont regex again needlessly when going
## through tests which have already been set earlier
if (not runnable.matchesGrep?) or (not _.isEqual(runnable.grepRe, grep))
runnable.grepRe = grep
runnable.matchesGrep = grep.test(runnable.fullTitle())

runnable.matchesGrep

getTestResults = (tests) ->
_.map tests, (test) ->
obj = _.pick(test, "id", "duration", "state")
Expand All @@ -347,7 +335,12 @@ getTestResults = (tests) ->
obj.state = "skipped"
obj

normalizeAll = (suite, initialTests = {}, grep, setTestsById, setTests, onRunnable, onLogsById, getTestId) ->
hasOnly = (suite) ->
suite._onlyTests.length or
suite._onlySuites.length or
_.some(suite.suites, hasOnly)

normalizeAll = (suite, initialTests = {}, setTestsById, setTests, onRunnable, onLogsById, getTestId) ->
hasTests = false

## only loop until we find the first test
Expand All @@ -361,10 +354,8 @@ normalizeAll = (suite, initialTests = {}, grep, setTestsById, setTests, onRunnab
## we hand back a normalized object but also
## create optimized lookups for the tests without
## traversing through it multiple times
tests = {}
grepIsDefault = _.isEqual(grep, defaultGrepRe)

obj = normalize(suite, tests, initialTests, grep, grepIsDefault, onRunnable, onLogsById, getTestId)
tests = {}
normalizedSuite = normalize(suite, tests, initialTests, onRunnable, onLogsById, getTestId)

if setTestsById
## use callback here to hand back
Expand All @@ -375,10 +366,10 @@ normalizeAll = (suite, initialTests = {}, grep, setTestsById, setTests, onRunnab
## same pattern here
setTests(_.values(tests))

return obj
return normalizedSuite

normalize = (runnable, tests, initialTests, grep, grepIsDefault, onRunnable, onLogsById, getTestId) ->
normalizer = (runnable) =>
normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTestId) ->
normalizeRunnable = (runnable) =>
runnable.id = getTestId()

## tests have a type of 'test' whereas suites do not have a type property
Expand All @@ -402,57 +393,50 @@ normalize = (runnable, tests, initialTests, grep, grepIsDefault, onRunnable, onL
push = (test) =>
tests[test.id] ?= test

obj = normalizer(runnable)
normalizedRunnable = normalizeRunnable(runnable)

## if we have a default grep then avoid
## grepping altogether and just push
## tests into the array of tests
if grepIsDefault
if runnable.type isnt "suite" or not hasOnly(runnable)
if runnable.type is "test"
push(runnable)

## and recursively iterate and normalize all other _runnables
_.each {tests: runnable.tests, suites: runnable.suites}, (_runnables, key) =>
if runnable[key]
obj[key] = _.map _runnables, (runnable) =>
normalize(runnable, tests, initialTests, grep, grepIsDefault, onRunnable, onLogsById, getTestId)
else
## iterate through all tests and only push them in
## if they match the current grep
obj.tests = _.reduce runnable.tests ? [], (memo, test) =>
## only push in the test if it matches
## our grep
if matchesGrep(test, grep)
memo.push(normalizer(test))
push(test)
memo
, []

## and go through the suites
obj.suites = _.reduce runnable.suites ? [], (memo, suite) =>
## but only add them if a single nested test
## actually matches the grep
any = anyTestInSuite suite, (test) =>
matchesGrep(test, grep)

if any
memo.push(
normalize(
suite,
tests,
initialTests,
grep,
grepIsDefault,
onRunnable,
onLogsById,
getTestId
)
)

memo
, []

return obj
## recursively iterate and normalize all other _runnables
_.each {tests: runnable.tests, suites: runnable.suites}, (_runnables, type) =>
if runnable[type]
normalizedRunnable[type] = _.map _runnables, (runnable) =>
normalize(runnable, tests, initialTests, onRunnable, onLogsById, getTestId)

return normalizedRunnable

## this follows how mocha filters onlys. its runner#filterOnly
## is pretty much the same minus the normalization part
filterOnly = (normalizedSuite, suite) ->
if suite._onlyTests.length
suite.tests = suite._onlyTests
normalizedSuite.tests = _.map suite._onlyTests, (test) =>
normalizedTest = normalizeRunnable(test, initialTests, onRunnable, onLogsById, getTestId)
push(normalizedTest)
normalizedTest
suite.suites = []
normalizedSuite.suites = []
else
suite.tests = []
normalizedSuite.tests = []
_.each suite._onlySuites, (onlySuite) ->
normalizedOnlySuite = normalizeRunnable(onlySuite, initialTests, onRunnable, onLogsById, getTestId)
if hasOnly(onlySuite)
filterOnly(normalizedOnlySuite, onlySuite)

suite.suites = _.filter suite.suites, (childSuite) ->
normalizedChildSuite = normalizeRunnable(childSuite, initialTests, onRunnable, onLogsById, getTestId)
suite._onlySuites.indexOf(childSuite) isnt -1 or filterOnly(normalizedChildSuite, childSuite)
normalizedSuite.suites = _.map suite.suites, (childSuite) ->
normalize(childSuite, tests, initialTests, onRunnable, onLogsById, getTestId)

return suite.tests.length or suite.suites.length

filterOnly(normalizedRunnable, runnable)

return normalizedRunnable

afterEachFailed = (Cypress, test, err) ->
test.state = "failed"
Expand Down Expand Up @@ -717,23 +701,6 @@ create = (specWindow, mocha, Cypress, cy) ->
overrideRunnerHook(Cypress, _runner, getTestById, getTest, setTest, getTests)

return {
grep: (re) ->
if arguments.length
_runner._grep = re
else
## grab grep from the mocha _runner
## or just set it to all in case
## there is a mocha regression
_runner._grep ?= defaultGrepRe

options: (options = {}) ->
## TODO
## need to handle
## ignoreLeaks, asyncOnly, globals

if re = options.grep
@grep(re)

normalizeAll: (tests) ->
## if we have an uncaught error then slice out
## all of the tests and suites and just generate
Expand All @@ -750,7 +717,6 @@ create = (specWindow, mocha, Cypress, cy) ->
normalizeAll(
_runner.suite,
tests,
@grep(),
setTestsById,
setTests,
onRunnable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe "driver/src/cypress/index", ->
expect($el.get(0)).to.eq($foo.get(0))

context "#backend", ->
it "sets __stackCleaned__ on errors", (done) ->
it "sets __stackCleaned__ on errors", ->
cy.stub(@Cypress, "emit")
.withArgs("backend:request")
.yieldsAsync({
Expand All @@ -45,8 +45,6 @@ describe "driver/src/cypress/index", ->
expect(err.backend).to.be.true
expect(err.stack).not.to.include("From previous event")

done()

context "Log", ->
it "throws when using Cypress.Log.command()", ->
fn = ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ describe "promises", ->

cy.foo()

it "can return a promise that throws on its own without warning", (done) ->
it "can return a promise that throws on its own without warning", ->
Cypress.Promise
.delay(10)
.then ->
Expand All @@ -116,7 +116,6 @@ describe "promises", ->

throw new Error("foo")
.catch ->
done()

it "can still fail cypress commands", (done) ->
cy.on "fail", (err) ->
Expand All @@ -128,3 +127,4 @@ describe "promises", ->
.then ->
cy.wrap({}).then ->
throw new Error("foo")
return
Loading