npm test runs node:test on the TypeScript sources with Node's type stripping (Node 22.14 in the image, Node 24 locally), with no dependencies. Node, unlike tsc, does not resolve extensionless relative imports. TypeScript 5.2 cannot emit .ts import extensions. tests/unit/support therefore registers a small resolve hook that appends ".ts" for imports from .ts files. - pricing, paypal-order, log-format: characterization tests of the current output. - The known defects of libretech/mp#67 are tests of the correct behaviour, marked todo: null, two-line and price-null addresses and deliveries, a deleted product, the payment surcharge missing from the breakdown, and in the log line circular JSON, the Basic credentials of an axios error, and an Error rendered as {}. - That the breakdown adds up to the amount holds today, including for the subtotals closest to a half cent, so that test is a regular one. Refs libretech/mp#71
81 lines
3.1 KiB
TypeScript
81 lines
3.1 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { formatLogLine } from "../../src/logging/format.ts";
|
|
|
|
const TIMESTAMP = "2026-10-08 21:29:40.426";
|
|
const CREDENTIALS = "RFVNTVlfQ0xJRU5UX0lEOkRVTU1ZX0NMSUVOVF9TRUNSRVQ="; // base64 of the dummy "DUMMY_CLIENT_ID:DUMMY_CLIENT_SECRET"
|
|
|
|
// Characterization: what the console line looks like today.
|
|
|
|
test("renders timestamp, level and message, with a trailing space when there are no other fields", () => {
|
|
assert.equal(
|
|
formatLogLine({ timestamp: TIMESTAMP, level: "info", message: "app:i:paypal-api: hello" }),
|
|
"2026-10-08 21:29:40.426Z info: app:i:paypal-api: hello "
|
|
);
|
|
});
|
|
|
|
test("appends the other fields as JSON indented by two spaces", () => {
|
|
assert.equal(
|
|
formatLogLine({
|
|
timestamp: TIMESTAMP,
|
|
level: "debug",
|
|
message: "app:d:order-service: Calculating totals",
|
|
productsTotal: 17.9,
|
|
deliveryPrice: 4.95
|
|
}),
|
|
'2026-10-08 21:29:40.426Z debug: app:d:order-service: Calculating totals {\n "productsTotal": 17.9,\n "deliveryPrice": 4.95\n}'
|
|
);
|
|
});
|
|
|
|
test("ignores the symbol keys winston adds", () => {
|
|
const info = { timestamp: TIMESTAMP, level: "info", message: "hello", [Symbol.for("level")]: "info", [Symbol.for("splat")]: [] };
|
|
|
|
assert.equal(formatLogLine(info), "2026-10-08 21:29:40.426Z info: hello ");
|
|
});
|
|
|
|
// Known defects: these assert the correct behaviour and fail today, which the todo marks as expected.
|
|
|
|
test(
|
|
"does not throw on a circular reference",
|
|
{ todo: "JSON.stringify throws on a circular reference — https://git.librete.ch/libretech/mp/issues/67" },
|
|
() => {
|
|
const request: Record<string, unknown> = { method: "POST", path: "/v1/oauth2/token" };
|
|
request.self = request;
|
|
|
|
assert.doesNotThrow(() => formatLogLine({ timestamp: TIMESTAMP, level: "error", message: "app:e:paypal-api", request }));
|
|
}
|
|
);
|
|
|
|
test(
|
|
"does not write the Authorization header of an axios-like error into the line",
|
|
{ todo: "the PayPal client credentials are logged — https://git.librete.ch/libretech/mp/issues/67" },
|
|
() => {
|
|
const error = Object.assign(new Error("getaddrinfo EAI_AGAIN api-m.paypal.com"), {
|
|
name: "AxiosError",
|
|
code: "EAI_AGAIN",
|
|
config: { method: "post", url: "https://api-m.paypal.com/v1/oauth2/token", headers: { Authorization: `Basic ${CREDENTIALS}` } }
|
|
});
|
|
// What strapi.log.error(error) hands this formatter: Strapi's logErrors format spreads the error and appends its stack.
|
|
const line = formatLogLine({ ...error, message: `${error.message}\n${error.stack}`, level: "error", timestamp: TIMESTAMP });
|
|
|
|
assert.ok(!line.includes(CREDENTIALS), line);
|
|
}
|
|
);
|
|
|
|
test(
|
|
"renders an Error with its message instead of {}",
|
|
{ todo: "an Error is rendered as {} — https://git.librete.ch/libretech/mp/issues/67" },
|
|
() => {
|
|
const error = new Error("getaddrinfo EAI_AGAIN api-m.paypal.com");
|
|
// strapi.log.error("…", { error }), as in the order controller's capturePayment
|
|
const line = formatLogLine({
|
|
timestamp: TIMESTAMP,
|
|
level: "error",
|
|
message: "app:e:order-controller: Error capturing payment for order x",
|
|
error
|
|
});
|
|
|
|
assert.ok(line.includes("getaddrinfo EAI_AGAIN api-m.paypal.com"), line);
|
|
}
|
|
);
|