test-suite.js in JavaScript
A whole test file: suites, hooks, table cases, mocks and fake timers.
#!/usr/bin/env node --test
import { before, beforeEach, describe, it } from "node:test";
import assert from "node:assert/strict";
class Scorer {
#history = [];
constructor(target = 90) {
if (target <= 0) throw new RangeError("target must be positive");
this.target = target;
}
stars(tpm, accuracy) {
if (accuracy < 0 || accuracy > 100) {
throw new RangeError(`accuracy out of range: ${accuracy}`);
}
let earned = 1;
if (accuracy >= 95) earned = 2;
if (accuracy >= 98 && tpm >= this.target) earned = 3;
this.#history.push(earned);
return earned;
}
get best() {
return this.#history.length ? Math.max(...this.#history) : 0;
}
async save(store) {
return store.write(this.#history);
}
}
describe("Scorer", () => {
let scorer;
before(() => assert.equal(typeof Scorer, "function"));
beforeEach(() => { scorer = new Scorer(90); });
describe("stars", () => {
const cases = [
{ name: "slow but clean", tpm: 60, accuracy: 99, want: 2 },
{ name: "fast and clean", tpm: 95, accuracy: 99, want: 3 },
{ name: "fast and sloppy", tpm: 95, accuracy: 80, want: 1 },
{ name: "exactly at the bar", tpm: 90, accuracy: 98, want: 3 },
];
for (const { name, tpm, accuracy, want } of cases) {
it(name, () => assert.equal(scorer.stars(tpm, accuracy), want));
}
it("rejects an impossible accuracy", () => {
assert.throws(() => scorer.stars(90, 140), {
name: "RangeError",
message: /out of range/,
});
});
});
describe("best", () => {
it("is zero before any run", () => assert.equal(scorer.best, 0));
it("keeps the highest", () => {
scorer.stars(95, 99);
scorer.stars(10, 50);
assert.equal(scorer.best, 3);
});
});
describe("save", () => {
it("hands the history to the store", async (t) => {
const write = t.mock.fn(async () => "written");
scorer.stars(95, 99);
assert.equal(await scorer.save({ write }), "written");
assert.equal(write.mock.callCount(), 1);
assert.deepEqual(write.mock.calls[0].arguments, [[3]]);
});
});
it("refuses a zero target", () => {
assert.throws(() => new Scorer(0), /positive/);
});
});
How it works
- The code under test sits at the top, so the file stands alone.
- Cases live in an array, so adding one is a single line.
- Mocks and fake timers keep it fast and deterministic.
Keywords and builtins used here
Mathasyncawaitclassconstconstructorforfromifimportletofreturnthisthrowthrows
The run, in numbers
- Lines
- 83
- Characters to type
- 2000
- Tokens
- 588
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 321 seconds.
Step 1 of 1 in Encore, step 9 of 9 in Testing with node:test.