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

Recover vows tests, drop proof tests #59

Merged
merged 13 commits into from
Jun 28, 2020
1,136 changes: 1,004 additions & 132 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@
"lib"
],
"scripts": {
"test": "proof platform win32 && proof test */*/*.t.js || t/test"
"pretest": "XMLDOM_ASSERT_STRICT=1 npm run test:assert",
"test": "vows 'test/**/*.vows.js'",
"test:assert": "vows test/assert.vows.js",
"start": "nodemon --watch package.json --watch lib --watch test --exec 'npm --silent run test'"
},
"engines": {
"node": ">=10.0.0"
},
"dependencies": {},
"devDependencies": {
"proof": "~7.0.9"
"dom-js": "0.0.9",
"nodemon": "^2.0.4",
"vows": "^0.8.3"
},
"maintainers": [
{
Expand Down
18 changes: 0 additions & 18 deletions t/cover

This file was deleted.

5 changes: 0 additions & 5 deletions t/dom/require.t.js

This file was deleted.

17 changes: 0 additions & 17 deletions t/test

This file was deleted.

1 change: 0 additions & 1 deletion test/3rd-cases/index.js

This file was deleted.

2 changes: 1 addition & 1 deletion test/3rd-cases/o3xml.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
var DOMParser = require('xmldom').DOMParser;
var DOMParser = require('../../lib/dom-parser').DOMParser;
require('./mock')
//Compatibility
{
Expand Down
114 changes: 114 additions & 0 deletions test/assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
var node_assert = require('assert')

function isAssertionError (error) {
return error.name.startsWith('AssertionError')
}

/**
* Picks the location of the assertion from the stacktrace if available.
*
* @param {Error} error
*/
function locateAssertion (error) {
return error && error.stack &&
error.stack.split('\n').find(
l => l.includes(__dirname) && !l.includes(__filename)
)
|| '[No stacktrace available]'
}

/**
* The existing vows testsuite makes heavy use of `console.assert(actual+'' == expected, ...)`.
* With the assumption that the equivalent call to an assertion method that can fail a test,
* is `assert(expected == actual, ...)` (the non strict assert using loose equality)
* this function is provided to solve:
*
* - `...` often contains a repetition of `actual` to have it in the test message
* - we want to make sure `assert.isTrue` is checked to cater for any weird type coercion
* - we would "prefer" using `assert.isEqual` for better failure message and test maintainability
* - easy switch to this method by
*
* by just making both assertions :)
* It prefixes each assertion with `(strict ===)` or `(strict ===)`, so it's clear which one fails
*
* @param {*} actual The the value returned by the code under test
* @param {*} expected The expected value
* @param {...*} messages values to use as assertion message, no need to repeat expected or actual
* @returns {undefined} if both assertion pass
* @throws {AssertionError} if one of the assertion fails
*
* @see https://nodejs.org/docs/latest-v10.x/api/assert.html#assert_class_assert_assertionerror
* @see https://nodejs.org/docs/latest-v10.x/api/assert.html#assert_strict_mode
* @see https://github.com/vowsjs/vows#assertistrueactual-message
* @see https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
*/
function assert (actual, expected, ...messages) {
// in case console.assert gets converted without changing == to ,: fail
// it makes no sense to call this method with only one boolean argument
if (typeof actual === 'boolean' && arguments.length === 1) throw new Error('convert equal to ,')
let caught
// the assertion with the better error message comes first so we can benefit
try {
node_assert.strict.equal(actual, expected)
} catch (error) {
if (!isAssertionError(error)) throw error
caught = error
}
// the original assertion comes second, it has to always be executed
node_assert(actual == expected, ['(loose ==)', ...messages, actual, locateAssertion(caught)].join(' '))
if (caught) {
const msg = ['(strict ===) ', ...messages, caught.message, locateAssertion(caught)]
if ((this.strictThrows || assert.strictThrows)()) {
caught.message = msg.join(' ')
throw caught
}
(this.log || assert.log)(...msg)
}
}

assert.log = console.warn
assert.strictThrows = () => process.env.XMLDOM_ASSERT_STRICT || false

/**
* This is a consistent way of skipping an assertion since it currently fails:
* Change `assert(exp, act, ...)` to `assert.skip(exp, act, ...)`
*
* - it prints something to the output when the assertion fails (like `console.assert`)
* - it fails if no assertion fails (no more need to skip it, if it's no longer needed, remove it)
* - it fails if the reason for skipping is not provided
*
* @param {*} expected The expected value
* @param {*} actual The the value returned by the code under test
* @param {...*} messages values to use as assertion message, no need to repeat expected or actual
* @returns {undefined} if the assertion fails
* @throws {AssertionError} if no assertion fails
*/
function skip (actual, expected, ...messages) {
try {
assert.apply(this, arguments)
} catch (error) {
if (!isAssertionError(error)) {
throw error
}
(this.log || assert.log)(
'Skipped assertion fails as expected:\n ',
error.message,
'in',
locateAssertion(error)
)
return
}
const error = new Error(`Skipped assertion is not failing: '''${messages.join(' ')}'''\n `)
error.message += locateAssertion(error)
throw error
}

assert.skip = skip

// provide access to used node assertions to avoid cumbersome duplicate imports
// and avoid forgetting to import .strict methods
assert.fail = node_assert.strict.fail
assert.equal = node_assert.strict.equal
assert.isTrue = node_assert.isTrue

module.exports = assert
146 changes: 146 additions & 0 deletions test/assert.vows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
const vows = require('vows')
const assert = require('assert').strict
const a = require('./assert')

const values = [
undefined, null,
true, false,
NaN, 0, 1, Infinity, -Infinity,
'', '0', '1', 'true', 'false', '[object Object]', '() => {}',
[], {},
() => {}
]
const describe = (...arguments) => arguments
.map(a => {
const type = typeof a
let str = JSON.stringify(a)
if (str === undefined) {
str = String(a)
}
return `${type} ${str}`
}).join(', ')

const suite = vows.describe('assert')
values.forEach(actual => {
values.forEach(expected => {
// `NaN === NaN` and `NaN == NaN` are false so skip NaN as expected
if (typeof expected === 'number' && isNaN(expected)) return

if (expected == actual) {// actual and expected are loose equal

if (expected !== actual) {// actual and expected are loose equal but not strict equal
suite.addBatch({
[`assert(${describe(actual, expected)}) {strictThrows: false} logs`]: () => {
const logs = []
const t = {
strictThrows: () => false,
log: (...args) => {
logs.push(args.join(' '))
// console.warn(...args)
}
}
a.call(t, actual, expected, 'msg1', 'msg2')
assert.equal(logs.length, 1, 'expected 1 log entry but was ' + logs.length)
const missing = ['(strict ===)', 'msg1', 'msg2', `${__filename}:`]
.filter(em => !logs[0].includes(em))
assert(
missing.length === 0,
`Expected all of [${describe(...missing)}] in '''${logs[0]}'''.`
)
},
[`assert(${describe(actual, expected)}) {strictThrows: true} throws`]: () => {
const t = {
strictThrows: () => true,
}
// assert.throws doesn't work here since the check is not triggered for AssertionError
let caught
try {
a.call(t, actual, expected, 'msg1', 'msg2')
} catch (error) {
caught = error
}
assert(
caught && caught.name.startsWith('AssertionError'),
'expected an AssertionError to be thrown'
)
const missing = ['(strict ===)', 'msg1', 'msg2', `${__filename}:`]
.filter(em => !caught.message.includes(em))
assert(
missing.length === 0,
`Expected all of [${describe(...missing)}] in '''${caught.message}'''.`
)
},
[`assert.skip(${describe(actual, expected)}) logs`]: () => {
const logs = []
const t = {
strictThrows: () => true,
log: (...args) => {
logs.push(args.join(' '))
// console.warn(...args)
}
}
a.skip.call(t, actual, expected, 'msg1', 'msg2')
assert.equal(logs.length, 1, 'expected 1 log entry but was ' + logs.length)
const missing = ['Skipped', '(strict ===)', 'msg1', 'msg2', `${__filename}:`]
.filter(em => !logs[0].includes(em))
assert(
missing.length === 0,
`Expected all of [${describe(...missing)}] in '''${logs[0]}'''.`
)
},
})
} else {// actual and expected are loose and strict equal
suite.addBatch({
[`assert.skip(${describe(actual, expected)}) throws since no asssertion fails`]: () => {
// assert.throws doesn't work here since the check is not triggered for AssertionError
let caught
try {
a.skip(actual, expected, 'msg1', 'msg2')
} catch (error) {
caught = error
}
assert(caught, 'expected an nError to be thrown')
const missing = ['Skipped', 'not failing', 'msg1', 'msg2', `${__filename}:`]
.filter(em => !caught.message.includes(em))
assert(
missing.length === 0,
`Expected all of [${describe(...missing)}] in '''${caught.message}'''.`
)
}
})
}
} else { // actual and expected are NOT loose equal
suite.addBatch({
[`assert(${describe(actual, expected)}) loose fails`]: () => {
assert.throws(
() => a(actual, expected, 'msg1', 'msg2'),
e => {
const check = /AssertionError/.test(e.name) &&
['(loose ==)', 'msg1', 'msg2'].every(em => e.message.includes(em))
return check || console.error(e)
}
)
},
[`assert.skip(${describe(actual, expected)}) logs`]: () => {
const logs = []
const t = {
log: (...args) => {
logs.push(args.join(' '))
// console.warn(...args)
}
}
a.skip.call(t, actual, expected, 'msg1', 'msg2')
assert.equal(logs.length, 1, 'expected 1 log entry but was ' + logs.length)
const missing = ['Skipped', '(loose ==)', 'msg1', 'msg2', `${__filename}:`]
.filter(em => !logs[0].includes(em))
assert(
missing.length === 0,
`Expected all of [${describe(...missing)}] in '''${logs[0]}'''.`
)
},
})
}
})
})

suite.export(module)