Decaffeinate chai.coffee and assertions_spec.coffee. (#5556)

Decaffeinate chai.coffee and assertions_spec.coffee.
This commit is contained in:
Jennifer Shehane
2019-11-06 12:46:48 -05:00
committed by GitHub
4 changed files with 2882 additions and 2325 deletions

View File

@@ -1,338 +0,0 @@
## tests in driver/test/cypress/integration/commands/assertions_spec.coffee
_ = require("lodash")
$ = require("jquery")
chai = require("chai")
sinonChai = require("@cypress/sinon-chai")
$dom = require("../dom")
$utils = require("../cypress/utils")
$chaiJquery = require("../cypress/chai_jquery")
## all words between single quotes which are at
## the end of the string
allPropertyWordsBetweenSingleQuotes = /('.*?')$/g
## grab all words between single quotes except
## when the single quote word is the LAST word
allButLastWordsBetweenSingleQuotes = /('.*?')(.+)/g
allBetweenFourStars = /\*\*.*\*\*/
allSingleQuotes = /'/g
allEscapedSingleQuotes = /\\'/g
allQuoteMarkers = /__quote__/g
allWordsBetweenCurlyBraces = /(#{.+?})/g
allQuadStars = /\*\*\*\*/g
assertProto = null
matchProto = null
lengthProto = null
containProto = null
existProto = null
getMessage = null
chaiUtils = null
chai.use(sinonChai)
chai.use (chai, u) ->
chaiUtils = u
$chaiJquery(chai, chaiUtils, {
onInvalid: (method, obj) ->
err = $utils.cypressErr(
$utils.errMessageByPath(
"chai.invalid_jquery_obj", {
assertion: method
subject: $utils.stringifyActual(obj)
}
)
)
throw err
onError: (err, method, obj, negated) ->
switch method
when "visible"
if not negated
## add reason hidden unless we expect the element to be hidden
reason = $dom.getReasonIsHidden(obj)
err.message += "\n\n" + reason
## always rethrow the error!
throw err
})
assertProto = chai.Assertion::assert
matchProto = chai.Assertion::match
lengthProto = chai.Assertion::__methods.length.method
containProto = chai.Assertion::__methods.contain.method
existProto = Object.getOwnPropertyDescriptor(chai.Assertion::, "exist").get
getMessage = chaiUtils.getMessage
removeOrKeepSingleQuotesBetweenStars = (message) ->
## remove any single quotes between our **, preserving escaped quotes
## and if an empty string, put the quotes back
message.replace allBetweenFourStars, (match) ->
match
.replace(allEscapedSingleQuotes, "__quote__") # preserve escaped quotes
.replace(allSingleQuotes, "")
.replace(allQuoteMarkers, "'") ## put escaped quotes back
.replace(allQuadStars, "**''**") ## fix empty strings that end up as ****
replaceArgMessages = (args, str) ->
_.reduce args, (memo, value, index) =>
if _.isString(value)
value = value
.replace(allWordsBetweenCurlyBraces, "**$1**")
.replace(allEscapedSingleQuotes, "__quote__")
.replace(allButLastWordsBetweenSingleQuotes, "**$1**$2")
.replace(allPropertyWordsBetweenSingleQuotes, "**$1**")
memo.push value
else
memo.push value
memo
, []
restoreAsserts = ->
chaiUtils.getMessage = getMessage
chai.Assertion::assert = assertProto
chai.Assertion::match = matchProto
chai.Assertion::__methods.length.method = lengthProto
chai.Assertion::__methods.contain.method = containProto
Object.defineProperty(chai.Assertion::, "exist", {get: existProto})
overrideChaiAsserts = (assertFn) ->
_this = @
chai.Assertion.prototype.assert = createPatchedAssert(assertFn)
chaiUtils.getMessage = (assert, args) ->
obj = assert._obj
## if we are formatting a DOM object
if $dom.isDom(obj)
## replace object with our formatted one
assert._obj = $dom.stringify(obj, "short")
msg = getMessage.call(@, assert, args)
## restore the real obj if we changed it
if obj isnt assert._obj
assert._obj = obj
return msg
chai.Assertion.overwriteMethod "match", (_super) ->
return (regExp) ->
if _.isRegExp(regExp) or $dom.isDom(@_obj)
_super.apply(@, arguments)
else
err = $utils.cypressErr($utils.errMessageByPath("chai.match_invalid_argument", { regExp }))
err.retry = false
throw err
containFn1 = (_super) ->
return (text) ->
obj = @_obj
if not ($dom.isJquery(obj) or $dom.isElement(obj))
return _super.apply(@, arguments)
escText = $utils.escapeQuotes(text)
selector = ":contains('#{escText}'), [type='submit'][value~='#{escText}']"
## the assert checks below only work if $dom.isJquery(obj)
## https://github.com/cypress-io/cypress/issues/3549
if not ($dom.isJquery(obj))
obj = $(obj)
@assert(
obj.is(selector) or !!obj.find(selector).length
'expected #{this} to contain #{exp}'
'expected #{this} not to contain #{exp}'
text
)
containFn2 = (_super) ->
return ->
_super.apply(@, arguments)
chai.Assertion.overwriteChainableMethod("contain", containFn1, containFn2)
chai.Assertion.overwriteChainableMethod "length",
fn1 = (_super) ->
return (length) ->
obj = @_obj
if not ($dom.isJquery(obj) or $dom.isElement(obj))
return _super.apply(@, arguments)
length = $utils.normalizeNumber(length)
## filter out anything not currently in our document
if $dom.isDetached(obj)
obj = @_obj = obj.filter (index, el) ->
$dom.isAttached(el)
node = if obj and obj.length then $dom.stringify(obj, "short") else obj.selector
## if our length assertion fails we need to check to
## ensure that the length argument is a finite number
## because if its not, we need to bail on retrying
try
@assert(
obj.length is length,
"expected '#{node}' to have a length of \#{exp} but got \#{act}",
"expected '#{node}' to not have a length of \#{act}",
length,
obj.length
)
catch e1
e1.node = node
e1.negated = chaiUtils.flag(@, "negate")
e1.type = "length"
if _.isFinite(length)
getLongLengthMessage = (len1, len2) ->
if len1 > len2
"Too many elements found. Found '#{len1}', expected '#{len2}'."
else
"Not enough elements found. Found '#{len1}', expected '#{len2}'."
e1.displayMessage = getLongLengthMessage(obj.length, length)
throw e1
e2 = $utils.cypressErr($utils.errMessageByPath("chai.length_invalid_argument", { length }))
e2.retry = false
throw e2
fn2 = (_super) ->
return ->
_super.apply(@, arguments)
chai.Assertion.overwriteProperty "exist", (_super) ->
return ->
obj = @_obj
if not ($dom.isJquery(obj) or $dom.isElement(obj))
try
_super.apply(@, arguments)
catch e
e.type = "existence"
throw e
else
if not obj.length
@_obj = null
node = if obj and obj.length then $dom.stringify(obj, "short") else obj.selector
try
@assert(
isAttached = $dom.isAttached(obj),
"expected \#{act} to exist in the DOM",
"expected \#{act} not to exist in the DOM",
node,
node
)
catch e1
e1.node = node
e1.negated = chaiUtils.flag(@, "negate")
e1.type = "existence"
getLongExistsMessage = (obj) ->
## if we expected not for an element to exist
if isAttached
"Expected #{node} not to exist in the DOM, but it was continuously found."
else
"Expected to find element: '#{obj.selector}', but never found it."
e1.displayMessage = getLongExistsMessage(obj)
throw e1
createPatchedAssert = (assertFn) ->
return (args...) ->
passed = chaiUtils.test(@, args)
value = chaiUtils.flag(@, "object")
expected = args[3]
customArgs = replaceArgMessages(args, @_obj)
message = chaiUtils.getMessage(@, customArgs)
actual = chaiUtils.getActual(@, customArgs)
message = removeOrKeepSingleQuotesBetweenStars(message)
try
assertProto.apply(@, args)
catch e
err = e
assertFn(passed, message, value, actual, expected, err)
throw err if err
overrideExpect = ->
## only override assertions for this specific
## expect function instance so we do not affect
## the outside world
return (val, message) ->
## make the assertion
return new chai.Assertion(val, message)
overrideAssert = ->
fn = (express, errmsg) ->
chai.assert(express, errmsg)
fns = _.functions(chai.assert)
_.each fns, (name) ->
fn[name] = ->
chai.assert[name].apply(@, arguments)
return fn
setSpecWindowGlobals = (specWindow, assertFn) ->
expect = overrideExpect()
assert = overrideAssert()
specWindow.chai = chai
specWindow.expect = expect
specWindow.assert = assert
return {
chai
expect
assert
}
create = (specWindow, assertFn) ->
# restoreOverrides()
restoreAsserts()
# overrideChai()
overrideChaiAsserts(assertFn)
return setSpecWindowGlobals(specWindow)
module.exports = {
replaceArgMessages
removeOrKeepSingleQuotesBetweenStars
setSpecWindowGlobals
# overrideChai: overrideChai
restoreAsserts
overrideExpect
overrideChaiAsserts
create
}

View File

@@ -0,0 +1,400 @@
// tests in driver/test/cypress/integration/commands/assertions_spec.coffee
const _ = require('lodash')
const $ = require('jquery')
const chai = require('chai')
const sinonChai = require('@cypress/sinon-chai')
const $dom = require('../dom')
const $utils = require('../cypress/utils')
const $chaiJquery = require('../cypress/chai_jquery')
// all words between single quotes which are at
// the end of the string
const allPropertyWordsBetweenSingleQuotes = /('.*?')$/g
// grab all words between single quotes except
// when the single quote word is the LAST word
const allButLastWordsBetweenSingleQuotes = /('.*?')(.+)/g
const allBetweenFourStars = /\*\*.*\*\*/
const allSingleQuotes = /'/g
const allEscapedSingleQuotes = /\\'/g
const allQuoteMarkers = /__quote__/g
const allWordsBetweenCurlyBraces = /(#{.+?})/g
const allQuadStars = /\*\*\*\*/g
let assertProto = null
let matchProto = null
let lengthProto = null
let containProto = null
let existProto = null
let getMessage = null
let chaiUtils = null
chai.use(sinonChai)
chai.use((chai, u) => {
chaiUtils = u
$chaiJquery(chai, chaiUtils, {
onInvalid (method, obj) {
const err = $utils.cypressErr(
$utils.errMessageByPath(
'chai.invalid_jquery_obj', {
assertion: method,
subject: $utils.stringifyActual(obj),
}
)
)
throw err
},
onError (err, method, obj, negated) {
switch (method) {
case 'visible':
if (!negated) {
// add reason hidden unless we expect the element to be hidden
const reason = $dom.getReasonIsHidden(obj)
err.message += `\n\n${reason}`
}
break
default:
break
}
// always rethrow the error!
throw err
},
})
assertProto = chai.Assertion.prototype.assert
matchProto = chai.Assertion.prototype.match
lengthProto = chai.Assertion.prototype.__methods.length.method
containProto = chai.Assertion.prototype.__methods.contain.method
existProto = Object.getOwnPropertyDescriptor(chai.Assertion.prototype, 'exist').get;
({ getMessage } = chaiUtils)
// remove any single quotes between our **, preserving escaped quotes
// and if an empty string, put the quotes back
const removeOrKeepSingleQuotesBetweenStars = (message) => {
return message.replace(allBetweenFourStars, (match) => {
return match
.replace(allEscapedSingleQuotes, '__quote__') // preserve escaped quotes
.replace(allSingleQuotes, '')
.replace(allQuoteMarkers, '\'') // put escaped quotes back
.replace(allQuadStars, '**\'\'**')
})
} // fix empty strings that end up as ****
const replaceArgMessages = (args, str) => {
return _.reduce(args, (memo, value, index) => {
if (_.isString(value)) {
value = value
.replace(allWordsBetweenCurlyBraces, '**$1**')
.replace(allEscapedSingleQuotes, '__quote__')
.replace(allButLastWordsBetweenSingleQuotes, '**$1**$2')
.replace(allPropertyWordsBetweenSingleQuotes, '**$1**')
memo.push(value)
} else {
memo.push(value)
}
return memo
}, [])
}
const restoreAsserts = function () {
chaiUtils.getMessage = getMessage
chai.Assertion.prototype.assert = assertProto
chai.Assertion.prototype.match = matchProto
chai.Assertion.prototype.__methods.length.method = lengthProto
chai.Assertion.prototype.__methods.contain.method = containProto
return Object.defineProperty(chai.Assertion.prototype, 'exist', { get: existProto })
}
const overrideChaiAsserts = function (assertFn) {
chai.Assertion.prototype.assert = createPatchedAssert(assertFn)
chaiUtils.getMessage = function (assert, args) {
const obj = assert._obj
// if we are formatting a DOM object
if ($dom.isDom(obj)) {
// replace object with our formatted one
assert._obj = $dom.stringify(obj, 'short')
}
const msg = getMessage.call(this, assert, args)
// restore the real obj if we changed it
if (obj !== assert._obj) {
assert._obj = obj
}
return msg
}
chai.Assertion.overwriteMethod('match', (_super) => {
return (function (regExp, ...args) {
if (_.isRegExp(regExp) || $dom.isDom(this._obj)) {
return _super.apply(this, [regExp, ...args])
}
const err = $utils.cypressErr($utils.errMessageByPath('chai.match_invalid_argument', { regExp }))
err.retry = false
throw err
})
})
const containFn1 = (_super) => {
return (function (text, ...args) {
let obj = this._obj
if (!($dom.isJquery(obj) || $dom.isElement(obj))) {
return _super.apply(this, [text, ...args])
}
const escText = $utils.escapeQuotes(text)
const selector = `:contains('${escText}'), [type='submit'][value~='${escText}']`
// the assert checks below only work if $dom.isJquery(obj)
// https://github.com/cypress-io/cypress/issues/3549
if (!($dom.isJquery(obj))) {
obj = $(obj)
}
this.assert(
obj.is(selector) || !!obj.find(selector).length,
'expected #{this} to contain #{exp}',
'expected #{this} not to contain #{exp}',
text
)
})
}
const containFn2 = (_super) => {
return (function (...args) {
_super.apply(this, args)
})
}
chai.Assertion.overwriteChainableMethod('contain', containFn1, containFn2)
chai.Assertion.overwriteChainableMethod('length',
(_super) => {
return (function (length, ...args) {
let obj = this._obj
if (!($dom.isJquery(obj) || $dom.isElement(obj))) {
return _super.apply(this, [length, ...args])
}
length = $utils.normalizeNumber(length)
// filter out anything not currently in our document
if ($dom.isDetached(obj)) {
obj = (this._obj = obj.filter((index, el) => {
return $dom.isAttached(el)
}))
}
const node = obj && obj.length ? $dom.stringify(obj, 'short') : obj.selector
// if our length assertion fails we need to check to
// ensure that the length argument is a finite number
// because if its not, we need to bail on retrying
try {
return this.assert(
obj.length === length,
`expected '${node}' to have a length of \#{exp} but got \#{act}`,
`expected '${node}' to not have a length of \#{act}`,
length,
obj.length
)
} catch (e1) {
e1.node = node
e1.negated = chaiUtils.flag(this, 'negate')
e1.type = 'length'
if (_.isFinite(length)) {
const getLongLengthMessage = function (len1, len2) {
if (len1 > len2) {
return `Too many elements found. Found '${len1}', expected '${len2}'.`
}
return `Not enough elements found. Found '${len1}', expected '${len2}'.`
}
e1.displayMessage = getLongLengthMessage(obj.length, length)
throw e1
}
const e2 = $utils.cypressErr($utils.errMessageByPath('chai.length_invalid_argument', { length }))
e2.retry = false
throw e2
}
})
},
(_super) => {
return (function (...args) {
return _super.apply(this, args)
})
})
return chai.Assertion.overwriteProperty('exist', (_super) => {
return (function (...args) {
const obj = this._obj
if (!($dom.isJquery(obj) || $dom.isElement(obj))) {
try {
return _super.apply(this, args)
} catch (e) {
e.type = 'existence'
throw e
}
} else {
let isAttached
if (!obj.length) {
this._obj = null
}
const node = obj && obj.length ? $dom.stringify(obj, 'short') : obj.selector
try {
return this.assert(
(isAttached = $dom.isAttached(obj)),
'expected \#{act} to exist in the DOM',
'expected \#{act} not to exist in the DOM',
node,
node
)
} catch (e1) {
e1.node = node
e1.negated = chaiUtils.flag(this, 'negate')
e1.type = 'existence'
const getLongExistsMessage = function (obj) {
// if we expected not for an element to exist
if (isAttached) {
return `Expected ${node} not to exist in the DOM, but it was continuously found.`
}
return `Expected to find element: '${obj.selector}', but never found it.`
}
e1.displayMessage = getLongExistsMessage(obj)
throw e1
}
}
})
})
}
const createPatchedAssert = (assertFn) => {
return (function (...args) {
let err
const passed = chaiUtils.test(this, args)
const value = chaiUtils.flag(this, 'object')
const expected = args[3]
const customArgs = replaceArgMessages(args, this._obj)
let message = chaiUtils.getMessage(this, customArgs)
const actual = chaiUtils.getActual(this, customArgs)
message = removeOrKeepSingleQuotesBetweenStars(message)
try {
assertProto.apply(this, args)
} catch (e) {
err = e
}
assertFn(passed, message, value, actual, expected, err)
if (err) {
throw err
}
})
}
// only override assertions for this specific
// expect function instance so we do not affect
// the outside world
const overrideExpect = () => {
// make the assertion
return (val, message) => {
return new chai.Assertion(val, message)
}
}
const overrideAssert = function () {
const fn = (express, errmsg) => {
return chai.assert(express, errmsg)
}
const fns = _.functions(chai.assert)
_.each(fns, (name) => {
return fn[name] = function (...args) {
return chai.assert[name].apply(this, args)
}
})
return fn
}
const setSpecWindowGlobals = function (specWindow, assertFn) {
const expect = overrideExpect()
const assert = overrideAssert()
specWindow.chai = chai
specWindow.expect = expect
specWindow.assert = assert
return {
chai,
expect,
assert,
}
}
const create = function (specWindow, assertFn) {
// restoreOverrides()
restoreAsserts()
// overrideChai()
overrideChaiAsserts(assertFn)
return setSpecWindowGlobals(specWindow)
}
module.exports = {
replaceArgMessages,
removeOrKeepSingleQuotesBetweenStars,
setSpecWindowGlobals,
// overrideChai: overrideChai
restoreAsserts,
overrideExpect,
overrideChaiAsserts,
create,
}
})

File diff suppressed because it is too large Load Diff