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

feat: test runner #516

Merged
merged 20 commits into from
Aug 15, 2019
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
32 changes: 32 additions & 0 deletions .ci/check_source_file_changes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { xrun } from "../prettier/util.ts";
import { red, green } from "../colors/mod.ts";

/**
* Checks whether any source file is changed since the given start time.
* If some files are changed, this function exits with 1.
ry marked this conversation as resolved.
Show resolved Hide resolved
*/
async function main(startTime: number): Promise<void> {
ry marked this conversation as resolved.
Show resolved Hide resolved
console.log("test checkSourceFileChanges ...");
const changed = new TextDecoder()
.decode(await xrun({ args: ["git", "ls-files"], stdout: "piped" }).output())
.trim()
.split("\n")
.filter(file => {
const stat = Deno.lstatSync(file);
if (stat != null) {
return (stat as any).modified * 1000 > startTime;
}
});
if (changed.length > 0) {
console.log(red("FAILED"));
console.log(
`Error: Some source files are modified during test: ${changed.join(", ")}`
);
Deno.exit(1);
} else {
console.log(green("ok"));
}
}

main(parseInt(Deno.args[1]));
4 changes: 3 additions & 1 deletion .ci/template.common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ parameters:

steps:
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-write --allow-read --allow-env ./format.ts --check
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-net --allow-write --allow-read --allow-env --config=tsconfig.test.json ./test.ts
- bash: export START_TIME=$(date +%s)
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-net --allow-write --allow-read --allow-env --config=tsconfig.test.json ./testing/runner.ts --exclude node_modules
- bash: deno${{ parameters.exe_suffix }} run --allow-run --allow-read .ci/check_source_file_changes.ts $START_TIME
4 changes: 0 additions & 4 deletions encoding/test.ts

This file was deleted.

14 changes: 0 additions & 14 deletions flags/test.ts

This file was deleted.

19 changes: 0 additions & 19 deletions fs/test.ts

This file was deleted.

5 changes: 0 additions & 5 deletions http/test.ts

This file was deleted.

6 changes: 0 additions & 6 deletions io/test.ts

This file was deleted.

3 changes: 0 additions & 3 deletions log/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import { assertEquals } from "../testing/asserts.ts";
import * as log from "./mod.ts";
import { LogLevel } from "./levels.ts";

import "./handlers_test.ts";
import "./logger_test.ts";

class TestHandler extends log.handlers.BaseHandler {
public messages: string[] = [];

Expand Down
2 changes: 0 additions & 2 deletions mime/test.ts

This file was deleted.

2 changes: 0 additions & 2 deletions multipart/test.ts

This file was deleted.

1 change: 0 additions & 1 deletion prettier/test.ts

This file was deleted.

2 changes: 0 additions & 2 deletions strings/test.ts

This file was deleted.

65 changes: 0 additions & 65 deletions test.ts

This file was deleted.

2 changes: 2 additions & 0 deletions testing/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ export interface RunOptions {
* Runs specified test cases.
* Parallel execution can be enabled via the boolean option; default: serial.
*/
// TODO: change return type to `Promise<boolean>` - ie. don't
// exit but return value
export async function runTests({
parallel = false,
exitOnFail = false,
Expand Down
127 changes: 127 additions & 0 deletions testing/runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env deno -A
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { parse } from "../flags/mod.ts";
import { glob, isGlob, walk } from "../fs/mod.ts";
import { runTests } from "./mod.ts";
const { args, cwd } = Deno;

const DEFAULT_GLOBS = [
"**/*_test.ts",
"**/*_test.js",
"**/test.ts",
"**/test.js"
];

/* eslint-disable max-len */
function showHelp(): void {
console.log(`Deno test runner

USAGE:
deno -A https://deno.land/std/testing/runner.ts [OPTIONS] [FILES...]

OPTIONS:
-q, --quiet Don't show output from test cases
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--silent

Prevent tests from printing messages through the console.

-f, --failfast Stop test suite on first error
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--bail

Alias: -b. Exit the test suite immediately upon n number of failing test suite. Defaults to 1.

-e, --exclude <FILES...> List of file names to exclude from run. If this options is
used files to match must be specified after "--".
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--testPathIgnorePatterns=[array]

An array of regexp pattern strings that is tested against all tests paths before executing the test. Contrary to --testPathPattern, it will only run those test with a path that does not match with the provided regexp expressions.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I’m wondering if -x would be a better short name for this option if you keep the exclude name.


ARGS:
[FILES...] List of file names to run. Defaults to: ${DEFAULT_GLOBS.join(
","
)}
`);
}
/* eslint-enable max-len */

function filePathToRegExp(str: string): RegExp {
if (isGlob(str)) {
return glob(str);
}

return RegExp(str);
}

/**
* This function runs matching test files in `root` directory.
*
* File matching and excluding supports glob syntax, ie. if encountered arg is
* a glob it will be expanded using `glob` method from `fs` module.
*
* Note that your shell may expand globs for you:
* $ deno -A ./runner.ts **\/*_test.ts **\/test.ts
*
* Expanding using `fs.glob`:
* $ deno -A ./runner.ts \*\*\/\*_test.ts \*\*\/test.ts
*
* `**\/*_test.ts` and `**\/test.ts"` are arguments that will be parsed and
* expanded as: [glob("**\/*_test.ts"), glob("**\/test.ts")]
*/
// TODO: change return type to `Promise<void>` once, `runTests` is updated
// to return boolean instead of exiting
export async function main(root: string = cwd()): Promise<void> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Describe the glob behavior in a jsdoc comment

const parsedArgs = parse(args.slice(1), {
boolean: ["quiet", "failfast", "help"],
string: ["exclude"],
alias: {
help: ["h"],
quiet: ["q"],
failfast: ["f"],
exclude: ["e"]
}
});

if (parsedArgs.help) {
return showHelp();
}

let includeFiles: string[];
let excludeFiles: string[];

if (parsedArgs._.length) {
includeFiles = (parsedArgs._ as string[])
.map(
(fileGlob: string): string[] => {
return fileGlob.split(",");
}
)
.flat();
} else {
includeFiles = DEFAULT_GLOBS;
}

if (parsedArgs.exclude) {
excludeFiles = (parsedArgs.exclude as string).split(",");
} else {
excludeFiles = [];
}

const filesIterator = walk(root, {
match: includeFiles.map((f: string): RegExp => filePathToRegExp(f)),
skip: excludeFiles.map((f: string): RegExp => filePathToRegExp(f))
});

const foundTestFiles: string[] = [];
for await (const { filename } of filesIterator) {
foundTestFiles.push(filename);
}

if (foundTestFiles.length === 0) {
console.error("No matching test files found.");
return;
}

console.log(`Found ${foundTestFiles.length} matching test files.`);

for (const filename of foundTestFiles) {
await import(filename);
}

await runTests({
exitOnFail: !!parsedArgs.failfast,
disableLog: !!parsedArgs.quiet
});
bartlomieju marked this conversation as resolved.
Show resolved Hide resolved
}

if (import.meta.main) {
main();
}
4 changes: 0 additions & 4 deletions testing/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ import {
assertThrows,
assertThrowsAsync
} from "./asserts.ts";
import "./format_test.ts";
import "./diff_test.ts";
import "./asserts_test.ts";
import "./bench_test.ts";

test(function testingAssertEqualActualUncoercable(): void {
let didThrow = false;
Expand Down
1 change: 0 additions & 1 deletion textproto/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import { append } from "./mod.ts";
import { assertEquals } from "../testing/asserts.ts";
import { test } from "../testing/mod.ts";
import "./reader_test.ts";

test(async function textprotoAppend(): Promise<void> {
const enc = new TextEncoder();
Expand Down
2 changes: 0 additions & 2 deletions util/test.ts

This file was deleted.

1 change: 0 additions & 1 deletion ws/test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import "./sha1_test.ts";
import { BufReader } from "../io/bufio.ts";
import { assert, assertEquals } from "../testing/asserts.ts";
import { runIfMain, test } from "../testing/mod.ts";
Expand Down