Rework test suite

This commit is contained in:
Lukas Tetzlaff 2017-11-02 02:40:30 +01:00
parent a5e5f68ff7
commit 00bbbb0456

View file

@ -1,147 +1,183 @@
import util from 'util'; import * as util from 'util';
import test from 'ava'; import test, { TestContext, Context } from 'ava';
import {jsdom} from 'jsdom'; import * as jsdom from 'jsdom';
import m from '.'; import m from '../src';
const isNode8orHigher = Number(process.versions.node.split('.')[0]) >= 8; const isNode8orHigher = Number(process.versions.node.split('.')[0]) >= 8;
const PromiseSubclassFixture = class extends Promise {}; class PromiseSubclassFixture<T> extends Promise<T> {};
const ErrorSubclassFixture = class extends Error {}; class ErrorSubclassFixture extends Error {};
const document = jsdom(); const document = new jsdom.JSDOM().window.document
const createDomElement = el => document.createElement(el); const createDomElement = (el: string) => document.createElement(el);
const types = new Map([ type Test = { is: (value: any) => boolean, fixtures: any[] }
['undefined', undefined], const types = new Map<string, Test>([
['null', null], ['undefined',
['string', [ { is: m.undefined, fixtures: [undefined] }
'🦄', ],['null',
'hello world', { is: m.null_, fixtures: [null] }
'' ],['string',
]], { is: m.string, fixtures: [
['number', [ '🦄',
6, 'hello world',
1.4, ''
0, ] }
-0, ],['number',
Infinity, { is: m.number, fixtures: [
-Infinity 6,
]], 1.4,
['boolean', [ 0,
true, -0,
false Infinity,
]], -Infinity
['symbol', Symbol('🦄')], ] }
['array', [ ],['boolean',
[1, 2], { is: m.boolean, fixtures: [true, false] }
new Array(2) ],['symbol',
]], { is: m.symbol, fixtures: [Symbol('🦄')] }
['function', [ ],['array',
function foo() {}, // eslint-disable-line func-names { is: m.array, fixtures: [[1, 2], new Array(2)] }
function () {}, ],['function',
() => {}, { is: m.func, fixtures: [
async function () {}, function foo() {}, // eslint-disable-line func-names
function * () {} function () {},
]], () => {},
['buffer', Buffer.from('🦄')], async function () {},
['object', [ function * (): any {}
{x: 1}, ] }
Object.create({x: 1}) ],['buffer',
]], { is: m.buffer, fixtures: [Buffer.from('🦄')] }
['regExp', [ ],['object',
/\w/, { is: m.object, fixtures: [
new RegExp('\\w') {x: 1},
]], Object.create({x: 1})
['date', new Date()], ] }
['error', [ ],['regExp',
new Error('🦄'), { is: m.regExp, fixtures: [
new ErrorSubclassFixture() /\w/,
]], new RegExp('\\w')
['nativePromise', [ ] }
Promise.resolve(), ],['date',
PromiseSubclassFixture.resolve() { is: m.date, fixtures: [new Date()] }
]], ],['error',
['promise', {then() {}, catch() {}}], { is: m.error, fixtures: [
['generator', (function * () { new Error('🦄'),
yield 4; new ErrorSubclassFixture()
})()], ] }
['generatorFunction', function * () { ],['nativePromise',
yield 4; { is: m.nativePromise, fixtures: [
}], Promise.resolve(),
['asyncFunction', [
async function () {}, // currently out of order, see https://github.com/Microsoft/TypeScript/issues/15202
async () => {} //PromiseSubclassFixture.resolve()
]], ] }
['map', new Map()], ],['promise',
['set', new Set()], { is: m.promise, fixtures: [{then() {}, catch() {}}] }
['weakMap', new WeakMap()], ],['generator',
['int8Array', new Int8Array()], { is: m.generator, fixtures: [(function * () {
['uint8Array', new Uint8Array()], yield 4;
['uint8ClampedArray', new Uint8ClampedArray()], })()] }
['uint16Array', new Uint16Array()], ],['generatorFunction',
['int32Array', new Int32Array()], { is: m.generatorFunction, fixtures: [function * () {
['uint32Array', new Uint32Array()], yield 4;
['float32Array', new Float32Array()], }] }
['float64Array', new Float64Array()], ],['asyncFunction',
['arrayBuffer', new ArrayBuffer(10)], { is: m.asyncFunction, fixtures: [
['nan', [ async function () {},
NaN, async () => {}
Number.NaN ] }
]], ],['map',
['nullOrUndefined', [ { is: m.map, fixtures: [new Map()] }
null, ],['set',
undefined { is: m.set, fixtures: [new Set()] }
]], ],['weakSet',
['plainObject', [ { is: m.weakSet, fixtures: [new WeakSet()] }
{x: 1}, ],['weakMap',
Object.create(null), { is: m.weakMap, fixtures: [new WeakMap()] }
new Object() // eslint-disable-line no-new-object ],['int8Array',
]], { is: m.int8Array, fixtures: [new Int8Array(0)] }
['integer', 6], ],['uint8Array',
['safeInteger', [ { is: m.uint8Array, fixtures: [new Uint8Array(0)] }
Math.pow(2, 53) - 1, ],['uint8ClampedArray',
-Math.pow(2, 53) + 1 { is: m.uint8ClampedArray, fixtures: [new Uint8ClampedArray(0)] }
]], ],['int16Array',
['domElement', [ { is: m.int16Array, fixtures: [new Int16Array(0)]}
'div', ],['uint16Array',
'input', { is: m.uint16Array, fixtures: [new Uint16Array(0)] }
'span', ],['int32Array',
'img', { is: m.int32Array, fixtures: [new Int32Array(0)] }
'canvas', ],['uint32Array',
'script' { is: m.uint32Array, fixtures: [new Uint32Array(0)] }
].map(createDomElement)], ],['float32Array',
['non-domElements', [ { is: m.float32Array, fixtures: [new Float32Array(0)] }
document.createTextNode('data'), ],['float64Array',
document.createProcessingInstruction('xml-stylesheet', 'href="mycss.css" type="text/css"'), { is: m.float64Array, fixtures: [new Float64Array(0)] }
document.createComment('This is a comment'), ],['arrayBuffer',
document, { is: m.arrayBuffer, fixtures: [new ArrayBuffer(10)] }
document.implementation.createDocumentType('svg:svg', '-//W3C//DTD SVG 1.1//EN', 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'), ],['nan',
document.createDocumentFragment() { is: m.nan, fixtures: [NaN, Number.NaN] }
]], ],['nullOrUndefined',
['infinite', [ { is: m.nullOrUndefined, fixtures: [null, undefined] }
Infinity, ],['plainObject',
-Infinity { is: m.plainObject, fixtures: [
]] {x: 1},
Object.create(null),
new Object() // eslint-disable-line no-new-object
] }
],['integer',
{ is: m.integer, fixtures: [6] }
],['safeInteger',
{ is: m.safeInteger, fixtures: [
Math.pow(2, 53) - 1,
-Math.pow(2, 53) + 1
] }
],['domElement',
{ is: m.domElement, fixtures: [
'div',
'input',
'span',
'img',
'canvas',
'script'
].map(createDomElement) }
],['non-domElements',
{ is: value => !m.domElement(value), fixtures: [
document.createTextNode('data'),
document.createProcessingInstruction('xml-stylesheet', 'href="mycss.css" type="text/css"'),
document.createComment('This is a comment'),
document,
document.implementation.createDocumentType('svg:svg', '-//W3C//DTD SVG 1.1//EN', 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'),
document.createDocumentFragment()
] }
],['infinite',
{ is: m.infinite, fixtures: [Infinity, -Infinity] }
]
]); ]);
// This ensures a certain method matches only the types // This ensures a certain method matches only the types
// it's supposed to and none of the other methods' types // it's supposed to and none of the other methods' types
const testType = (t, type, exclude) => { const testType = (t: TestContext & Context<any>, type: string, exclude?: Array<string>) => {
for (const [key, value] of types) { const test = types.get(type)
if (test === undefined) {
t.fail(`is.${type} not defined`)
return
}
const { is } = test as Test
types.forEach(({ fixtures }, key) => {
// TODO: Automatically exclude value types in other tests that we have in the current one. // TODO: Automatically exclude value types in other tests that we have in the current one.
// Could reduce the use of `exclude`. // Could reduce the use of `exclude`.
if (exclude && exclude.indexOf(key) !== -1) { if (exclude && exclude.indexOf(key) !== -1) {
continue; return;
} }
const assert = key === type ? t.true.bind(t) : t.false.bind(t); const assert = key === type ? t.true.bind(t) : t.false.bind(t);
const is = m[type];
const fixtures = Array.isArray(value) ? value : [value];
for (const fixture of fixtures) { for (const fixture of fixtures) {
assert(is(fixture), `Value: ${util.inspect(fixture)}`); assert(is(fixture), `Value: ${util.inspect(fixture)}`);
} }
} })
}; };
test('is', t => { test('is', t => {
@ -188,7 +224,9 @@ test('is.buffer', t => {
}); });
test('is.object', t => { test('is.object', t => {
for (const el of types.get('object')) { const testData = types.get('object')
if (testData === undefined) t.fail("is.object not defined")
for (const el of (testData as Test).fixtures) {
t.true(m.object(el)); t.true(m.object(el));
} }
}); });
@ -343,6 +381,7 @@ test('is.safeInteger', t => {
t.false(m.safeInteger(-Math.pow(2, 53))); t.false(m.safeInteger(-Math.pow(2, 53)));
}); });
test('is.plainObject', t => { test('is.plainObject', t => {
testType(t, 'plainObject', ['object', 'promise']); testType(t, 'plainObject', ['object', 'promise']);
}); });
@ -367,20 +406,20 @@ test('is.class', t => {
]; ];
for (const x of classDeclarations) { for (const x of classDeclarations) {
t.true(m.class(x)); t.true(m.class_(x));
} }
}); });
test('is.typedArray', t => { test('is.typedArray', t => {
const typedArrays = [ const typedArrays = [
new Int8Array(), new Int8Array(0),
new Uint8Array(), new Uint8Array(0),
new Uint8ClampedArray(), new Uint8ClampedArray(0),
new Uint16Array(), new Uint16Array(0),
new Int32Array(), new Int32Array(0),
new Uint32Array(), new Uint32Array(0),
new Float32Array(), new Float32Array(0),
new Float64Array() new Float64Array(0)
]; ];
for (const el of typedArrays) { for (const el of typedArrays) {
@ -393,8 +432,8 @@ test('is.typedArray', t => {
}); });
test('is.arrayLike', t => { test('is.arrayLike', t => {
(() => { ((...args: any[]) => {
t.true(m.arrayLike(arguments)); t.true(m.arrayLike(args));
})(); })();
t.true(m.arrayLike([])); t.true(m.arrayLike([]));
t.true(m.arrayLike('unicorn')); t.true(m.arrayLike('unicorn'));
@ -422,10 +461,6 @@ test('is.inRange', t => {
t.false(m.inRange(x, 2)); t.false(m.inRange(x, 2));
t.false(m.inRange(-3, -2)); t.false(m.inRange(-3, -2));
t.throws(() => {
m.inRange(0);
});
t.throws(() => { t.throws(() => {
m.inRange(0, []); m.inRange(0, []);
}); });