Skip to content

Commit

Permalink
the future is now and modules are here
Browse files Browse the repository at this point in the history
  • Loading branch information
okwolf committed Feb 7, 2022
1 parent 86b4413 commit aa184fa
Show file tree
Hide file tree
Showing 29 changed files with 250 additions and 258 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [10.x, 12.x, 14.x]
node-version: [12.x, 14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
node_modules
esm
coverage
*.log
8 changes: 0 additions & 8 deletions Dockerfile

This file was deleted.

54 changes: 27 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
# Tead - Lighting the way to simpler testing

[![Travis Build Status](https://travis-ci.org/teadjs/tead.svg?branch=master)](https://travis-ci.org/teadjs/tead) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/teadjs/tead?svg=true)](https://ci.appveyor.com/project/okwolf/tead/branch/master) [![Code Coverage](https://img.shields.io/codecov/c/github/teadjs/tead/master.svg)](https://codecov.io/gh/teadjs/tead) [![npm version](https://img.shields.io/npm/v/tead.svg?style=flat)](https://www.npmjs.com/package/tead)
[![Build Status](https://github.com/teadjs/tead/actions/workflows/ci.yml/badge.svg)](https://github.com/teadjs/tead/actions)
[![Codecov](https://img.shields.io/codecov/c/github/teadjs/tead/master.svg)](https://codecov.io/gh/teadjs/tead)
[![npm](https://img.shields.io/npm/v/tead.svg?maxAge=2592000?style=plastic)](https://www.npmjs.com/package/tead)

In a world full of complex test-runners, Tead dares to keep it simple. Tests are defined as plain JavaScript objects. The only test assertion supported is a basic form of deep equals. Mocks/fakes/spies will never be provided. Asynchronous tests are not possible. These are all very intentional key features.

The boilerplate and global nastiness of functions such as `describe/beforeEach/beforeAll/afterEach/afterAll/test/it/assert/expect/...` are gone. Your linter is so happy, it no longer cares whether you use semicolons or not. Callback functions with `done` arguments that you're responsible for calling - history. Once you learn the simple convention for test values, you will notice they are all signal and no noise. Standard-issue watch mode is built-in. Support for your ES6 modules comes attached to its frontal lobe.

Tead is compatible with `Node.js >= 6`.
Tead is compatible with `Node.js >= 12`.

If you are interested in using a functional style of building applications from pure functions free of side effects, Tead will aid you in your noble quest. There is only one possible kind of function that can be written in this utopian world, and but a single way to test it. Each test merely calls one of these pure functions with an input value and compares the actual result with the expected output for equality. Writing tests changes from being a chore to a joy, and suddenly tests are written first instead of as an afterthought. Such coverage. So much rejoicing.

The name is from an obscure word for torch.

## Getting Started

Let's get started by writing a test for a hypothetical function that adds two numbers. First create a `sum.js` file:
Let's get started by writing a test for a hypothetical function that adds two numbers. Create a new folder and bootstrap a new module with `npm init -y` then add the following to the generated `package.json`:

```json
{
"type": "module"
}
```

Next create a `sum.js` file:

```js
export default (a, b) => a + b;
Expand All @@ -23,7 +33,7 @@ export default (a, b) => a + b;
Then create a file named `sum.test.js` and add some tests:

```js
import sum from "./sum";
import sum from "./sum.js";

export default {
"sum can add": {
Expand All @@ -37,7 +47,7 @@ export default {

Object keys are used to group and describe tests. Array values represent test expectations. The order of the elements in the expectation is `[actual, expected]` and differences will be reported as test failures.

Finally, run `npx tead` (see the [note below](#npx) if using an older version of Node.js) and Tead will print this message:
Finally, run `npx tead` and Tead will print this message:

```console
$ npx tead
Expand Down Expand Up @@ -66,27 +76,15 @@ npm i -g tead
Then you may run tests in any project folder with:

```console
tead
tead --coverage
```

### `npx`

No install required, just run from any project folder:

```console
npx tead
```

Keep in mind that in order to use `npx` with `Node.js < 8` you need to either install `npx` globally:

```console
npm i -g npx
```

or update your version of `npm`:

```console
npm i -g npm
npx tead --coverage
```

### Local
Expand All @@ -100,8 +98,10 @@ npm i -D tead
Then add Tead as the test script in your `package.json`:

```json
"scripts": {
"test": "tead"
{
"scripts": {
"test": "tead --coverage"
}
}
```

Expand All @@ -117,12 +117,12 @@ npm test

Here are the available command line arguments:

| Argument | Usage | Default |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| testPattern | The regex pattern Tead uses to detect test files. Defaults to files ending with `test.js` or `spec.js` not in `node_modules`. | <code>^((?!node_modules).)\*(test&#124;spec)\.js$</code> |
| watch | Watch files for changes and rerun tests. Output is limited to only failing tests and overall passing/failing counts. | |
| watchPattern | The regex pattern Tead uses when in watch mode to match which file changes should rereun tests. Defaults to files ending with `.js` not in `node_modules`. | <code>^((?!node_modules).)\*\.js$</code> |
| coverage | Test coverage information is collected, reported in the output, and written to the `/coverage` folder. This argument makes use of `npx`, so the same [caveat](#npx) about Node.js versions above applies. | |
| Argument | Usage | Default |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| testPattern | The regex pattern Tead uses to detect test files. Defaults to files ending with `test.js` or `spec.js` not in `node_modules`. | <code>^((?!node_modules).)\*(test&#124;spec)\.js\$</code> |
| watch | Watch files for changes and rerun tests. Output is limited to only failing tests and overall passing/failing counts. | |
| watchPattern | The regex pattern Tead uses when in watch mode to match which file changes should rereun tests. Defaults to files ending with `.js` not in `node_modules`. | <code>^((?!node_modules).)\*\.js\$</code> |
| coverage | Test coverage information is collected, reported in the output, and written to the `/coverage` folder. This argument makes use of `npx`, so the same [caveat](#npx) about Node.js versions above applies. | |

Each argument is passed in the form `--argument=value`. Here is an example:

Expand Down
3 changes: 0 additions & 3 deletions old-node.sh

This file was deleted.

24 changes: 11 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
{
"name": "tead",
"version": "0.5.3",
"version": "0.6.0",
"description": "Lighting the way to simpler testing",
"files": [
"src",
"esm"
"src"
],
"type": "module",
"main": "./src/index.js",
"bin": {
"tead": "./src/tead.js"
},
"engines": {
"node": ">=6.0"
},
"dependencies": {
"esm": "=3.2.25"
"node": ">=12.0"
},
"devDependencies": {
"prettier": "=2.0.1"
"prettier": "=2.5.1"
},
"scripts": {
"clean": "npx rimraf node_modules coverage",
"format": "prettier --write {src,test}/**/*.js",
"format:check": "prettier --list-different {src,test}/**/*.js",
"clean": "npx --ignore-existing --quiet rimraf coverage node_modules",
"format": "prettier --write \"{src,test}/**/*.js\"",
"format:check": "prettier --list-different \"{src,test}/**/*.js\"",
"pretest": "node test/bootstrap",
"test": "node src/tead.js --coverage",
"test:watch": "node src/tead.js --watch",
"prepare": "npm run format:check",
"release": "./pre-flight-tests && npm run clean && npm i && git tag $npm_package_version && git push && git push --tags && npm publish"
"check": "npm run format:check && npm t",
"release:dry": "npm run clean && npm i && npm run check",
"release": "node --experimental-json-modules release"
},
"prettier": {
"trailingComma": "none",
Expand Down
25 changes: 0 additions & 25 deletions pre-flight-tests

This file was deleted.

37 changes: 37 additions & 0 deletions release.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { execSync } from "child_process";
import packageJson from "./package.json";
import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const exec = command => execSync(command, { encoding: "utf8" }).trim();

const exitWithError = error => {
process.stderr.write(`\x1b[1;31m${error}\x1b[0m\n\n`);
process.exit(1);
};

const gitBranchName = exec("git rev-parse --abbrev-ref HEAD");
if (gitBranchName !== "master") {
exitWithError("please checkout the master branch to make a release!");
}

const workingCopyChanges = exec("git status --porcelain");
if (workingCopyChanges) {
exitWithError("please commit your changes before making a release!");
}

const tagExists = exec(`git tag -l "${packageJson.version}"`);
if (tagExists) {
exitWithError(`${packageJson.version} has already been released!`);
}

execSync(
`npm run release:dry && git tag ${packageJson.version} && git push && git push --tags && npm publish`,
{
shell: true,
stdio: "inherit",
cwd: __dirname
}
);
2 changes: 1 addition & 1 deletion src/diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ const diff = (before, after, context = []) => {
return [{ before, after, context }];
};

module.exports = diff;
export default diff;
2 changes: 1 addition & 1 deletion src/flattenTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ const flattenTests = (test = {}, prefixes = []) =>
[]
);

module.exports = flattenTests;
export default flattenTests;
2 changes: 1 addition & 1 deletion src/formatTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,4 @@ const formatTests = (testSuites = []) => {
];
};

module.exports = formatTests;
export default formatTests;
18 changes: 11 additions & 7 deletions src/getFiles.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
const path = require("path");
const fs = require("fs");
const promisify = fn => (...args) =>
new Promise((resolve, reject) =>
fn(...args, (err, ...results) => (err ? reject(err) : resolve(...results)))
);
import path from "path";
import fs from "fs";
const promisify =
fn =>
(...args) =>
new Promise((resolve, reject) =>
fn(...args, (err, ...results) =>
err ? reject(err) : resolve(...results)
)
);
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

Expand All @@ -28,4 +32,4 @@ const getFiles = (folderPath, fileFilter = () => true) =>
)
);

module.exports = getFiles;
export default getFiles;
2 changes: 1 addition & 1 deletion src/options.js → src/getOptions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = () =>
export default () =>
process.argv
.filter(opt => opt.startsWith("--"))
.map(opt => opt.substring(2).split("="))
Expand Down
47 changes: 25 additions & 22 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
const path = require("path");
const fs = require("fs");
const getFiles = require("./getFiles");
const runTests = require("./runTests");
const flattenTests = require("./flattenTests");
const formatTests = require("./formatTests");
const readline = require("readline");
const { spawn } = require("child_process");
import path from "path";
import fs from "fs";
import { fileURLToPath } from "url";
import readline from "readline";
import { spawn } from "child_process";
import getFiles from "./getFiles.js";
import runTests from "./runTests.js";
import flattenTests from "./flattenTests.js";
import formatTests from "./formatTests.js";

const compose = (...fns) =>
fns.reduceRight((f, g) => (...args) => f(g(...args)));
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const executeTests = ({ testFilter }) =>
getFiles(process.cwd(), testFilter)
.then(testFiles =>
formatTests(
Promise.all(
testFiles.map(fullPath => {
const file = path.basename(fullPath);
return {
file,
folder: fullPath.substring(
process.cwd().length + 1,
fullPath.length - file.length
),
tests: compose(require, runTests, flattenTests)(fullPath)
};
return import(`file://${fullPath}`).then(({ default: tests }) => {
return {
file,
folder: fullPath.substring(
process.cwd().length + 1,
fullPath.length - file.length
),
tests: flattenTests(runTests(tests))
};
});
})
)
).then(formatTests)
)
.catch(error => {
console.log(error);
return [[], [[error]], []];
});

module.exports = options => {
export default options => {
const {
testPattern = "^((?!node_modules).)*(test|spec)\\.js$",
watchPattern = "^((?!node_modules).)*\\.js$",
Expand All @@ -41,7 +44,7 @@ module.exports = options => {
} = options;
if (coverage) {
spawn(
`npx nyc --require esm --temp-directory coverage -r lcov -r text node ${__dirname}/tead.js "--testPattern=${testPattern}"`,
`npx c8 --reporter=text --reporter=lcov node ${__dirname}/tead.js "--testPattern=${testPattern}"`,
{
shell: true,
stdio: "inherit"
Expand Down
4 changes: 2 additions & 2 deletions src/runTests.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const diff = require("./diff");
import diff from "./diff.js";

const resultsForTest = ([actual, expected]) => {
const resultsDiff = diff(expected, actual);
Expand All @@ -18,4 +18,4 @@ const runTests = test =>
)
: { "invalid test": [false, [{ invalid: test }]] };

module.exports = runTests;
export default runTests;
7 changes: 3 additions & 4 deletions src/tead.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#!/usr/bin/env node

const options = require("./options")();
require = require("esm")(module);

require("./")(options);
import getOptions from "./getOptions.js";
import index from "./index.js";
index(getOptions());
Loading

0 comments on commit aa184fa

Please sign in to comment.