Given3 is a testing framework for TypeScript that allows you to write tests in a more readable and expressive way. It is a spiritual successor to Given2 but extends it with more powerful caching and typescript support.
Install the version of Given3 that matches your testing framework.
for Jest:
npm install --save-dev @given3/jestfor Mocha:
npm install --save-dev @given3/mochafor Node:
npm install --save-dev @given3/nodefor Vitest:
npm install --save-dev @given3/vitestGiven3 allows you to write more readable and expressive tests by reusing setup code in an intelligent way.
import { given } from "@given3/vitest";
import { describe, it, expect } from "vitest";
import { userRepository } from "../user-repository.mjs";
describe("a user repository", () => {
  // Arrange
  const id = given(() => Math.random());
  const user = given("a user", () => ({
    id: id.value,
    name: "John Doe",
    email: "[email protected]",
  }));
  const repository = given("a user repository with the user", () =>
    userRepository([user.value]),
  );
  // Act
  const userByIdRequest = given<number>("a user by id input"); // defer the value till later
  const userByIdResponse = given(() => repository.value.getUserById(id.value));
  describe("when a known userId is requested", () => {
    // Define the value of the userByIdRequest
    userByIdRequest.define(id.value);
    // Assert
    it("should return the user", () => {
      expect(userByIdResponse.value).toEqual(user.value);
    });
  });
  describe("when an unknown userId is requested", () => {
    // Define the value of the userByIdRequest
    userByIdRequest.define(() => Math.random());
    // Assert
    it("should return null", () => {
      expect(userByIdResponse.value).toBeNull();
    });
  });
});Given3 uses a caching mechanism to store the results of the given functions. This means that the functions are only executed once and the results are cached.
const id = given(() => Math.random());
const user = given("a user", () => ({
  id: id.value,
  name: "John Doe",
  email: "[email protected]",
}));
it("should have the same user with multiple accesses", () => {
  expect(user.value).toBe(user.value);
});
it("when the id changes the user should be different", () => {
  const user1 = user.value;
  id.define(() => 4938);
  expect(user.value).not.toBe(user1);
});Given3 supports 3 cache modes:
Each- the cache is evicted after each testAll- the cache is evicted after all the tests in the suite / describe blockfalse- the value is not cached
All cache mode is useful for tests that use external resources, such as end-to-end or integration tests.
import { given } from "@given3/vitest";
import { describe, it, expect } from "vitest";
import { userRepository } from "../user-repository.mjs";
describe("a user repository", () => {
  const user = given(
    "a user",
    () => ({
      id: Math.random(),
      name: "John Doe",
      email: "[email protected]",
    }),
    { cache: "All" },
  );
  // Setup the repository, register a cleanup function and reuse it for all the tests
  const repository = given(
    "a user repository",
    async (cleanup) => {
      const repo = await userRepository.connect();
      cleanup(() => repo.disconnect());
      return repo;
    },
    { cache: "All" },
  );
  // Add the user to the repository, register a cleanup function and reuse it for all the tests
  // If the user changes a new user will be added to the repository
  const userAddedToRepository = given(
    "a user added to the repository",
    async (cleanup) => {
      const u = user.value;
      const repo = await repository.value;
      await repo.addUser(u);
      cleanup(() => repo.deleteUser(u.id));
    },
    { cache: "All" },
  );
  describe("when the user is requested by id", () => {
    const userByIdResponse = given(
      async () => {
        await userAddedToRepository.value;
        const repo = await repository.value;
        return repo.getUserById(user.value.id);
      },
      { cache: "All" },
    );
    it("should return the user", async () => {
      expect(await userByIdResponse.value).toEqual(user.value);
    });
  });
  describe("when the user is requested by email", () => {
    const userByEmailResponse = given(
      async () => {
        await userAddedToRepository.value;
        const repo = await repository.value;
        return repo.getUserByEmail(user.value.email);
      },
      { cache: "All" },
    );
    it("should return the user", async () => {
      expect(await userByEmailResponse.value).toEqual(user.value);
    });
  });
});