Skip to content

Commit

Permalink
test: add unit test coverage (adevinta#3)
Browse files Browse the repository at this point in the history
Covers the existing behaviour in unit tests.
  • Loading branch information
danieleloscozzese committed Jan 12, 2025
1 parent 7a02bb8 commit b30910d
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm cit
- run: npm cit --quiet
timeout-minutes: 5

publish-npm:
Expand Down
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

.prettierrc.json
.prettierignore
*.spec.*
127 changes: 127 additions & 0 deletions index.spec.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import assert from "node:assert/strict";
import { test, suite, before, after } from "node:test";
import postTask from "./index.mjs";

suite("postTask", () => {
const {
queueMicrotask: queueMicrotaskOriginal,
scheduler: schedulerOriginal,
} = globalThis;

suite("when neither the scheduler nor queueMicrotask are available", () => {
before(() => {
delete globalThis.queueMicrotask;
delete globalThis.scheduler;
});

after(() => {
globalThis.queueMicrotask = queueMicrotaskOriginal;
globalThis.scheduler = schedulerOriginal;
});

test("all priorities should call back", (context) => {
context.mock.timers.enable(["setTimeout"]);

const callback = context.mock.fn();

// Schedule all tasks synchronously: the loops will queue all three
// tasks because there is no `await`.
postTask(callback, "user-blocking");
postTask(callback, "user-visible");
postTask(callback, "background");

assert.equal(callback.mock.calls.length, 0);

// Allow the minimal tick to pass, which will enable both timeouts
// with a 0ms delay to run, and not the third which has a minimum
context.mock.timers.tick(0);
assert.equal(callback.mock.calls.length, 2);

// Allow the 150ms delay for the background task to pass.
context.mock.timers.tick(150);
assert.equal(callback.mock.calls.length, 3);
});
});

suite("when `queueMicrotask` is available", () => {
before(() => {
delete globalThis.scheduler;
});

after(() => {
globalThis.queueMicrotask = queueMicrotaskOriginal;
globalThis.scheduler = schedulerOriginal;
});

test("all priorities should call back", async (context) => {
context.mock.timers.enable(["setTimeout"]);

const callback = context.mock.fn();

// Schedule all tasks synchronously: the loops will queue all three
// tasks because there is no `await`.
postTask(callback, "user-blocking");
postTask(callback, "user-visible");
postTask(callback, "background");

assert.equal(callback.mock.calls.length, 0);

// Await for the resolution of a microtask: giving that control back to
// the event loop results in it running _all_ microtasks, including the
// queued one for the `"user-blocking"` task.
await Promise.resolve();
assert.equal(callback.mock.calls.length, 1);

// Allow the minimal tick to pass, which will enable both timeouts
// with a 0ms delay to run, and not the third which has a minimum
context.mock.timers.tick(0);
assert.equal(callback.mock.calls.length, 2);

// Allow the 150ms delay for the background task to pass.
context.mock.timers.tick(150);
assert.equal(callback.mock.calls.length, 3);
});
});

suite("when `scheduler` is available", async () => {
after(() => {
globalThis.scheduler = schedulerOriginal;
});

test("all priorities should be scheduled", async (context) => {
// Mock the function which is to be called
const mockSchedulerPostTask = context.mock.fn();
globalThis.scheduler = { postTask: mockSchedulerPostTask };

const noop = () => undefined;

// Schedule all tasks synchronously
postTask(noop, "user-blocking");
postTask(noop, "user-visible");
postTask(noop, "background");

// Assert that the control flow correctly forwards the tasks:
// the callback is handled by the scheduler, so asserting on the callback
// would be testing the mock, and not useful.
assert.equal(mockSchedulerPostTask.mock.calls.length, 3);
assert.deepEqual(mockSchedulerPostTask.mock.calls[0].arguments, [
noop,
{
priority: "user-blocking",
},
]);
assert.deepEqual(mockSchedulerPostTask.mock.calls[1].arguments, [
noop,
{
priority: "user-visible",
},
]);
assert.deepEqual(mockSchedulerPostTask.mock.calls[2].arguments, [
noop,
{
priority: "background",
},
]);
});
});
});
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
},
"version": "1.0.0",
"scripts": {
"test": "echo 'no tests yet'; exit 0;",
"pretest": "node --check index.mjs",
"test": "node --disable-warning=ExperimentalWarning ./index.spec.mjs",
"prepublishOnly": "sed 's/export default/module.exports =/g' ./index.mjs > index.cjs"
},
"repository": {
Expand Down

0 comments on commit b30910d

Please sign in to comment.