mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
Add tests.ts for fast unit tests.
Also deno_testing/ which will be released as a standalone module.
This commit is contained in:
parent
844f565cc0
commit
08d3850fa8
7 changed files with 211 additions and 1 deletions
96
deno_testing/testing.ts
Normal file
96
deno_testing/testing.ts
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/*!
|
||||||
|
Copyright 2018 Propel http://propel.site/. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { assert, assertEqual, equal } from "./util";
|
||||||
|
|
||||||
|
export type TestFunction = () => void | Promise<void>;
|
||||||
|
|
||||||
|
export interface TestDefinition {
|
||||||
|
fn: TestFunction;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const exitOnFail = true;
|
||||||
|
|
||||||
|
/* A subset of the tests can be ran by providing a filter expression.
|
||||||
|
* In Node.js the filter is specified on the command line:
|
||||||
|
*
|
||||||
|
* ts-node test_node log # all tests with 'log' in the name
|
||||||
|
* ts-node test_node ^util # tests starting with 'util'
|
||||||
|
*
|
||||||
|
* In the browser, the filter is specified as part of the url:
|
||||||
|
*
|
||||||
|
* http://localhost:9876/test.html#script=some/script.js&filter=log
|
||||||
|
* http://localhost:9876/test.html#script=some/script.js&filter=^util
|
||||||
|
*/
|
||||||
|
let filterExpr: string = null;
|
||||||
|
|
||||||
|
const filterRegExp = filterExpr ? new RegExp(filterExpr, "i") : null;
|
||||||
|
const tests: TestDefinition[] = [];
|
||||||
|
|
||||||
|
export function test(t: TestDefinition | TestFunction): void {
|
||||||
|
const fn: TestFunction = typeof t === "function" ? t : t.fn;
|
||||||
|
const name: string = t.name;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
throw new Error("Test function may not be anonymous");
|
||||||
|
}
|
||||||
|
if (filter(name)) {
|
||||||
|
tests.push({ fn, name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter(name: string): boolean {
|
||||||
|
if (filterRegExp) {
|
||||||
|
return filterRegExp.test(name);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runTests() {
|
||||||
|
let passed = 0;
|
||||||
|
let failed = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < tests.length; i++) {
|
||||||
|
const { fn, name } = tests[i];
|
||||||
|
console.log(`${i+1}/${tests.length} +${passed} -${failed}: ${name}`);
|
||||||
|
try {
|
||||||
|
await fn();
|
||||||
|
passed++;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("\nTest FAIL", name);
|
||||||
|
console.error((e && e.stack) || e);
|
||||||
|
failed++;
|
||||||
|
if (exitOnFail) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nDONE. Test passed: ${passed}, failed: ${failed}`);
|
||||||
|
|
||||||
|
if (failed === 0) {
|
||||||
|
// All good.
|
||||||
|
} else {
|
||||||
|
// Use setTimeout to avoid the error being ignored due to unhandled
|
||||||
|
// promise rejections being swallowed.
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new Error(`There were ${failed} test failures.`);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(runTests, 0);
|
60
deno_testing/util.ts
Normal file
60
deno_testing/util.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*!
|
||||||
|
Copyright 2018 Propel http://propel.site/. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
export function assertEqual(actual: any, expected: any, msg?: string) {
|
||||||
|
if (!msg) { msg = `actual: ${actual} expected: ${expected}`; }
|
||||||
|
if (!equal(actual, expected)) {
|
||||||
|
console.error(
|
||||||
|
"assertEqual failed. actual = ", actual, "expected =", expected);
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assert(expr: boolean, msg = "") {
|
||||||
|
if (!expr) {
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line:no-any
|
||||||
|
export function equal(c: any, d: any): boolean {
|
||||||
|
const seen = new Map();
|
||||||
|
return (function compare(a, b) {
|
||||||
|
if (a === b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (typeof a === "number" && typeof b === "number" &&
|
||||||
|
isNaN(a) && isNaN(b)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (a && typeof a === "object" && b && typeof b === "object") {
|
||||||
|
if (seen.get(a) === b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Object.keys(a).length !== Object.keys(b).length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (const key in { ...a, ...b }) {
|
||||||
|
if (!compare(a[key], b[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seen.set(a, b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})(c, d);
|
||||||
|
}
|
32
deno_testing/util_test.ts
Normal file
32
deno_testing/util_test.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*!
|
||||||
|
Copyright 2018 Propel http://propel.site/. All rights reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { test } from "./index";
|
||||||
|
import { assert } from "./util";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
|
test(async function util_equal() {
|
||||||
|
assert(util.equal("world", "world"));
|
||||||
|
assert(!util.equal("hello", "world"));
|
||||||
|
assert(util.equal(5, 5));
|
||||||
|
assert(!util.equal(5, 6));
|
||||||
|
assert(util.equal(NaN, NaN));
|
||||||
|
assert(util.equal({ hello: "world" }, { hello: "world" }));
|
||||||
|
assert(!util.equal({ world: "hello" }, { hello: "world" }));
|
||||||
|
assert(util.equal({ hello: "world", hi: { there: "everyone" } },
|
||||||
|
{ hello: "world", hi: { there: "everyone" } }));
|
||||||
|
assert(!util.equal({ hello: "world", hi: { there: "everyone" } },
|
||||||
|
{ hello: "world", hi: { there: "everyone else" } }));
|
||||||
|
});
|
|
@ -144,3 +144,14 @@ func TestErrors(t *testing.T) {
|
||||||
t.Fatalf("Expected error.")
|
t.Fatalf("Expected error.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTestsTs(t *testing.T) {
|
||||||
|
integrationTestSetup()
|
||||||
|
cmd := exec.Command(denoFn, "tests.ts")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@ type AmdDefine = (deps: string[], factory: AmdFactory) => void;
|
||||||
|
|
||||||
// Uncaught exceptions are sent to window.onerror by v8worker2.
|
// Uncaught exceptions are sent to window.onerror by v8worker2.
|
||||||
window.onerror = (message, source, lineno, colno, error) => {
|
window.onerror = (message, source, lineno, colno, error) => {
|
||||||
|
// TODO Currently there is a bug in v8_source_maps.ts that causes a segfault
|
||||||
|
// if it is used within window.onerror. To workaround we uninstall the
|
||||||
|
// Error.prepareStackTrace handler. Users will get unmapped stack traces on
|
||||||
|
// uncaught exceptions until this issue is fixed.
|
||||||
|
Error.prepareStackTrace = null;
|
||||||
console.log(error.message, error.stack);
|
console.log(error.message, error.stack);
|
||||||
os.exit(1);
|
os.exit(1);
|
||||||
};
|
};
|
||||||
|
|
5
tests.ts
Normal file
5
tests.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { test, assert } from "./deno_testing/testing.ts";
|
||||||
|
|
||||||
|
test(async function test_matchTesters() {
|
||||||
|
assert(false, "assert failed on purpose.");
|
||||||
|
});
|
|
@ -20,5 +20,6 @@
|
||||||
"allowUnreachableCode": false,
|
"allowUnreachableCode": false,
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"include": ["*.ts", "*.js"]
|
"include": ["*.ts", "*.js"],
|
||||||
|
"exclude": ["tests.ts"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue