Skip to content

hasundue/amber

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

amber

A library for mocking Deno APIs with ease.

Warning

Alpha version. Not tested extensively or documented well yet.

Features

  • Built upon and compatible with @std/testing
  • Consistent interfaces across submodules

Usage

Command

import * as cmd from "jsr:@chiezo/amber/cmd";

mock

Replace Deno.Command as a side effect:

cmd.mock();
assert(Deno.Command !== Original);

use

Replace Deno.Command inside the callback:

const echo = cmd.spy("echo");
cmd.use(() => new Deno.Command("echo"));
assertSpyCalls(echo, 1);

spy

Create a spy for a command:

const echo = cmd.spy("echo");
cmd.use(() => new Deno.Command("echo"));
assertSpyCalls(echo, 1);

Create multiple spies for different commands separately:

const echo = cmd.spy("echo");
const ls = cmd.spy("ls");
cmd.use(() => {
  new Deno.Command("echo");
  assertSpyCalls(echo, 1);
  assertSpyCalls(ls, 0);
  new Deno.Command("ls");
  assertSpyCalls(echo, 1);
  assertSpyCalls(ls, 1);
});

stub

Stub a command with the default dummy:

const echo = cmd.stub("echo");
await cmd.use(() => new Deno.Command("echo").output());
assertEquals(
  Deno.permissions.querySync({ name: "run", command: "echo" }).state,
  "prompt",
);
assertSpyCalls(echo, 1);

Stub a command with a given fake:

cmd.stub(
  "echo",
  class extends Deno.Command {
    constructor(command: string | URL) {
      super(command);
      throw new Error();
    }
  },
);
cmd.use(() => assertThrows(() => new Deno.Command("echo")));

restore

Restore Deno.Command:

cmd.mock();
cmd.restore();
assert(Deno.Command === Original);

Not dispose spies created:

const echo = cmd.spy("echo");
cmd.restore();
cmd.use(() => new Deno.Command("echo"));
assertSpyCalls(echo, 1);

dispose

Restore Deno.Command:

cmd.mock();
cmd.dispose();
assert(Deno.Command === Original);

Dispose spies created:

const echo = cmd.spy("echo");
cmd.dispose();
cmd.use(() => new Deno.Command("echo"));
assertSpyCalls(echo, 0);

File System

import * as fs from "jsr:@chiezo/amber/fs";

mock

Replace file system functions as side effects:

fs.mock();
assert(Deno.readTextFile !== original.readTextFile);
assert(Deno.readTextFileSync !== original.readTextFileSync);

Stub the current working directory by default:

fs.mock();
await fs.use(() => Deno.writeTextFile("./test.txt", "amber"));
assertRejects(() => Deno.readTextFile("./test.txt"));

use

Replace file system functions within the callback:

fs.use(() => {
  assert(Deno.readTextFile !== original.readTextFile);
  assert(Deno.readTextFileSync !== original.readTextFileSync);
});

spy

Spy file system functions:

const spy = fs.spy(".");
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(spy.readTextFile, 1);

Spy multiple paths separately:

const cwd = fs.spy(".");
const src = fs.spy("./src");
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(cwd.readTextFile, 1);
assertSpyCalls(src.readTextFile, 0);

Accept a URL:

const spy = fs.spy(new URL("..", import.meta.url));
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(spy.readTextFile, 1);

stub

Not write to the original path:

const stub = fs.stub(".");
await fs.use(() => Deno.writeTextFile("./test.txt", "amber"));
assertEquals(
  (await Deno.permissions.query({ name: "write", path: "./test.txt" }))
    .state,
  "prompt",
);
assertSpyCalls(stub.writeTextFile, 1);

Make the original file readable initially (readThrough):

const stub = fs.stub(".");
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(stub.readTextFile, 1);

Make the updated content readable after being written:

fs.stub(".");
await fs.use(async () => {
  await Deno.writeTextFile("./README.md", "amber");
  assertEquals(
    await Deno.readTextFile("./README.md"),
    "amber",
  );
});

Throw on a file that has not been written if readThrough is disabled:

fs.stub(".", { readThrough: false });
fs.use(() => assertThrows(() => Deno.readTextFileSync("./README.md")));

Stub multiple paths separately:

const cwd = fs.stub(".");
const src = fs.stub("./src");
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(cwd.readTextFile, 1);
assertSpyCalls(src.readTextFile, 0);

restore

Restore file system functions:

fs.mock();
fs.restore();
assert(Deno.readTextFile === original.readTextFile);
assert(Deno.readTextFileSync === original.readTextFileSync);

Not dispose spies created:

const spy = fs.spy(".");
fs.restore();
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(spy.readTextFile, 1);

dispose

Restore file system functions:

fs.mock();
fs.dispose();
assert(Deno.readTextFile === original.readTextFile);
assert(Deno.readTextFileSync === original.readTextFileSync);

Dispose spies created:

const spy = fs.spy(".");
fs.dispose();
await fs.use(() => Deno.readTextFile("./README.md"));
assertSpyCalls(spy.readTextFile, 0);

Utilities

import { all } from "jsr:@chiezo/amber/util";

all

Mock multiple modules simultaneously:

const echo = cmd.stub("echo");
const root = fs.stub("../");
all(cmd, fs).mock();
new Deno.Command("echo");
assertSpyCalls(echo, 1);
await Deno.readTextFile("../README.md");
assertSpyCalls(root.readTextFile, 1);

Use multiple modules simultaneously:

const echo = cmd.stub("echo");
const root = fs.stub("../");
await all(cmd, fs).use(async () => {
  new Deno.Command("echo");
  assertSpyCalls(echo, 1);

  await Deno.writeTextFile("../test.txt", "amber");
  assertSpyCalls(root.writeTextFile, 1);

  assertEquals(
    await Deno.readTextFile("../test.txt"),
    "amber",
  );
  assertSpyCalls(root.readTextFile, 1);
});

Restore multiple modules simultaneously:

all(cmd, fs).mock();
all(cmd, fs).restore();
assert(Deno.Command === original.Command);
assert(Deno.readTextFile === original.readTextFile);

Dispose multiple modules simultaneously:

const echo = cmd.spy("echo");
const root = fs.spy("../");
all(cmd, fs).mock();
all(cmd, fs).dispose();
new Deno.Command("echo");
assertSpyCalls(echo, 0);
await Deno.readTextFile("../README.md");
assertSpyCalls(root.readTextFile, 0);