@jaypie/testkit v1.1.31
Jaypie Testkit š¦āā¬š«
Test utilities built for Jaypie
š Usage
Installation
npm install --save-dev @jaypie/testkitExample
Mocking Jaypie
The testkit provides a complete mock for Jaypie including:
- Log spying (
expect(log.warn).toHaveBeenCalled()) - Default responses for runtime-only functions (
connect,sendMessage,submitMetric) - No automatic error handling for handlers (which is good in production but obfuscates tests)
- Most non-utility functions are mocked to allow simple testing
vi.mock("jaypie", async () => vi.importActual("@jaypie/testkit/mock"));Error Spying
import { ConfigurationError } from "@jaypie/core";
vi.mock("jaypie", async () => vi.importActual("@jaypie/testkit/mock"));
test("ConfigurationError", () => {
try {
throw new ConfigurationError("Sorpresa!");
} catch (error) {
expect(error).toBeJaypieError();
expect(ConfigurationError).toHaveBeenCalled();
}
});Log Spying
import { log } from "jaypie";
vi.mock("jaypie", async () => vi.importActual("@jaypie/testkit/mock"));
afterEach(() => {
vi.clearAllMocks();
});
test("log", () => {
expect(vi.isMockFunction(log.warn)).toBe(true);
expect(log.warn).not.toHaveBeenCalled();
log.warn("Danger");
expect(log.warn).toHaveBeenCalled();
expect(log.error).not.toHaveBeenCalled();
});šŗ Logging Conventions:
- Only use
log.traceorlog.varduring "happy path" - Use
log.debugfor edge cases - Now you can add an "observability" test that will fail as soon as new code triggers an unexpected edge condition
describe("Observability", () => {
it("Does not log above trace", async () => {
// Arrange
// TODO: "happy path" setup
// Act
await myNewFunction(); // TODO: add any "happy path" parameters
// Assert
expect(log).not.toBeCalledAboveTrace();
// or individually:
expect(log.debug).not.toHaveBeenCalled();
expect(log.info).not.toHaveBeenCalled();
expect(log.warn).not.toHaveBeenCalled();
expect(log.error).not.toHaveBeenCalled();
expect(log.fatal).not.toHaveBeenCalled();
});
});šŗ Follow the "arrange, act, assert" pattern
Test Matchers
testSetup.js
import { matchers as jaypieMatchers } from "@jaypie/testkit";
import * as extendedMatchers from "jest-extended";
import { expect } from "vitest";
expect.extend(extendedMatchers);
expect.extend(jaypieMatchers);test.spec.js
import { ConfigurationError } from "@jaypie/core";
const error = new ConfigurationError();
const json = error.json();
expect(error).toBeJaypieError();
expect(json).toBeJaypieError();š Reference
import {
LOG,
jsonApiErrorSchema,
jsonApiSchema,
matchers,
mockLogFactory,
restoreLog,
spyLog,
} from '@jaypie/testkit'LOG
LOG constant provided by @jaypie/core for convenience
import { log } from "@jaypie/core";
import { LOG } from "@jaypie/testkit";
const libLogger = log.lib({ level: LOG.LEVEL.WARN, lib: "myLib" });jsonApiErrorSchema
A JSON Schema validator for the JSON:API error schema. Powers the toBeJaypieError matcher (via toMatchSchema).
jsonApiSchema
A JSON Schema validator for the JSON:API data schema.
matchers
export default {
toBeCalledAboveTrace,
toBeCalledWithInitialParams,
toBeClass,
toBeJaypieError,
toBeValidSchema: jsonSchemaMatchers.toBeValidSchema,
toMatchBase64,
toMatchJwt,
toMatchMongoId,
toMatchSchema: jsonSchemaMatchers.toMatchSchema,
toMatchSignedCookie,
toMatchUuid4,
toMatchUuid5,
toMatchUuid,
toThrowBadGatewayError,
toThrowBadRequestError,
toThrowConfigurationError,
toThrowForbiddenError,
toThrowGatewayTimeoutError,
toThrowInternalError,
toThrowJaypieError,
toThrowNotFoundError,
toThrowUnauthorizedError,
toThrowUnavailableError,
};testSetup.js
import { matchers as jaypieMatchers } from "@jaypie/testkit";
import * as extendedMatchers from "jest-extended";
import { expect } from "vitest";
expect.extend(extendedMatchers);
expect.extend(jaypieMatchers);expect(subject).toBeCalledAboveTrace()
import { log } from "@jaypie/core";
log.trace("Hello, World!");
expect(log).not.toBeCalledAboveTrace();
log.warn("Look out, World!");
expect(log).toBeCalledAboveTrace();expect(subject).toBeJaypieError()
Validates instance objects:
try {
throw new Error("Sorpresa!");
} catch (error) {
expect(error).not.toBeJaypieError();
}Validates plain old JSON:
expect({ errors: [ { status, title, detail } ] }).toBeJaypieError();Jaypie errors, which are ProjectErrors, all have a .json() to convert
expect(subject).toBeValidSchema()
import { jsonApiErrorSchema, jsonApiSchema } from "@jaypie/testkit";
expect(jsonApiErrorSchema).toBeValidSchema();
expect(jsonApiSchema).toBeValidSchema();
expect({ project: "mayhem" }).not.toBeValidSchema();From jest-json-schema toBeValidSchema.js (not documented in README)
expect(subject).toMatchSchema(schema)
import { jsonApiErrorSchema, jsonApiSchema } from "@jaypie/testkit";
import { ConfigurationError } from "@jaypie/core";
const error = new ConfigurationError();
const json = error.json();
expect(json).toMatchSchema(jsonApiErrorSchema);
expect(json).not.toMatchSchema(jsonApiSchema);From jest-json-schema; see README
expect(subject).toMatch*() Regular Expression Matchers
Note: these regular expressions matchers so not verify the value is value, only that it matches the pattern (it "looks like" something). For example, expect("123e4567-e89b-12d3-a456-426614174000").toMatchUuid() will pass because the string matches a UUID pattern, even though it is not a valid UUID.
toMatchBase64toMatchJwttoMatchMongoIdtoMatchSignedCookietoMatchUuid4toMatchUuid5toMatchUuid
expect(subject).toThrowJaypieError()
import { ConfigurationError } from "@jaypie/core";
const error = new ConfigurationError();
expect(() => {
throw error;
}).toThrowJaypieError();Do not forget to await expect when passing async functions:
import { ConfigurationError } from "@jaypie/core";
const error = new ConfigurationError();
await expect(async () => {
throw error;
}).toThrowJaypieError();
// Breaks and causes a false-positive because `expect` did not `await`
// expect(async () => {}).toThrowJaypieError();
// > Error: Expected function to throw a JaypieError, but it did not throw.mockLogFactory()
Creates a mock of the log provided by @jaypie/core.
import { mockLogFactory } from "@jaypie/testkit";
const log = mockLogFactory();
log.warn("Danger");
expect(log.warn).toHaveBeenCalled();
expect(log.error).not.toHaveBeenCalled();restoreLog(log)
Restores the log provided by @jaypie/core, commonly performed afterEach with spyLog in beforeEach. See example with spyLog.
spyLog(log)
Spies on the log provided by @jaypie/core, commonly performed beforeEach with restoreLog in afterEach. Not necessary when mocking the entire Jaypie module.
import { restoreLog, spyLog } from "@jaypie/testkit";
import { log } from "@jaypie/core";
beforeEach(() => {
spyLog(log);
});
afterEach(() => {
restoreLog(log);
vi.clearAllMocks();
});
test("log", () => {
log.warn("Danger");
expect(log.warn).toHaveBeenCalled();
expect(log.error).not.toHaveBeenCalled();
});sqsTestRecords(message, message, ...) or sqsTestRecords([...])
Generates an event object for testing SQS Lambda functions with as many messages as provided. Note, test will accept more than ten messages, but AWS will only send ten at a time.
import { sqsTestRecords } from "@jaypie/testkit";
const event = sqsTestRecords(
{ MessageId: "1", Body: "Hello, World!" },
{ MessageId: "2", Body: "Goodbye, World!" }
);š Wishlist
- matcher toBeHttpStatus
- matcher toBeJaypieAny
- matcher toBeJaypieData
- matcher toBeJaypieDataObject
- matcher toBeJaypieDataArray
- ...@knowdev/jest
š Changelog
| Date | Version | Summary |
|---|---|---|
| 9/15/2024 | 1.0.29 | All errors exported as mocks |
| 9/14/2024 | 1.0.28 | Matchers toThrowBadGatewayError, toThrowGatewayTimeoutError, toThrowUnavailableError |
| 9/13/2024 | 1.0.27 | Matcher toBeCalledAboveTrace |
| 7/16/2024 | 1.0.21 | Export Jaypie mock as default |
| 3/20/2024 | 1.0.2 | Export LOG |
| 3/16/2024 | 1.0.0 | Artists ship |
| 3/15/2024 | 0.1.0 | Initial deploy |
| 3/15/2024 | 0.0.1 | Initial commit |
š License
Published by Finlayson Studio. All rights reserved
5 months ago
5 months ago
5 months ago
5 months ago
10 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
8 months ago
8 months ago
9 months ago
8 months ago
8 months ago
8 months ago
7 months ago
8 months ago
8 months ago
6 months ago
6 months ago
7 months ago
7 months ago
6 months ago
6 months ago
6 months ago
6 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago