Initial Commit
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { readdirSync, readFileSync, statSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
|
||||
const PKG_ROOT = join(__dirname, "..");
|
||||
const SRC_ROOT = join(PKG_ROOT, "src");
|
||||
|
||||
function walkTypescript(dir: string): string[] {
|
||||
const entries = readdirSync(dir);
|
||||
const files: string[] = [];
|
||||
for (const entry of entries) {
|
||||
const full = join(dir, entry);
|
||||
const st = statSync(full);
|
||||
if (st.isDirectory()) {
|
||||
files.push(...walkTypescript(full));
|
||||
} else if (
|
||||
entry.endsWith(".ts") &&
|
||||
!entry.endsWith(".test.ts") &&
|
||||
!entry.endsWith(".spec.ts")
|
||||
) {
|
||||
files.push(full);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
describe("universal dep graph", () => {
|
||||
it("src contains no node/bun/fs/path/stream/net/http/crypto imports", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const banned =
|
||||
/from\s+['"](node:|bun:|fs|path|stream|net|http|crypto)['"]/;
|
||||
const offenders: string[] = [];
|
||||
for (const file of walkTypescript(SRC_ROOT)) {
|
||||
const text = readFileSync(file, "utf8");
|
||||
if (banned.test(text)) {
|
||||
offenders.push(file);
|
||||
}
|
||||
}
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
it("package.json exposes exactly the feature subpaths", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const pkg = JSON.parse(
|
||||
readFileSync(join(PKG_ROOT, "package.json"), "utf8")
|
||||
) as { exports: Record<string, unknown> };
|
||||
const featurePaths = Object.keys(pkg.exports).filter(
|
||||
(k) => k.startsWith("./") && k !== "." && k !== "./package.json"
|
||||
);
|
||||
expect(featurePaths.sort()).toEqual(
|
||||
["./adyen/adyen", "./types/adyen"].sort()
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,76 @@
|
||||
import type { FetchLike } from "@suaveplan/payment-providers";
|
||||
import { AdyenProvider } from "../src/adyen/adyen.js";
|
||||
import type { AdyenConfig } from "../src/types/adyen.js";
|
||||
|
||||
/** Single recorded call on the test `FetchLike`. */
|
||||
export interface RecordedCall {
|
||||
readonly url: string;
|
||||
readonly init?: RequestInit;
|
||||
}
|
||||
|
||||
/** Test harness bundling a provider with helpers for inspecting requests. */
|
||||
export interface Harness {
|
||||
readonly provider: AdyenProvider;
|
||||
readonly calls: RecordedCall[];
|
||||
readonly bodyOf: (index: number) => Record<string, unknown>;
|
||||
readonly headersOf: (index: number) => Record<string, string>;
|
||||
}
|
||||
|
||||
/** Convenience: build a `FetchLike` that responds with the given JSON payload. */
|
||||
export function makeFetch(payload: unknown, status = 200): FetchLike {
|
||||
return async () =>
|
||||
new Response(JSON.stringify(payload), {
|
||||
status,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}
|
||||
|
||||
function recording(payload: unknown): {
|
||||
calls: RecordedCall[];
|
||||
fetch: FetchLike;
|
||||
} {
|
||||
const calls: RecordedCall[] = [];
|
||||
const fetch: FetchLike = async (url, init) => {
|
||||
calls.push({ url, init });
|
||||
return new Response(JSON.stringify(payload), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
};
|
||||
return { calls, fetch };
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a harness around an `AdyenProvider` whose `fetch` records every
|
||||
* request and replies with the supplied JSON payload. Optional `extra`
|
||||
* config overrides merge over the defaults (`apiKey`, `merchantAccount`,
|
||||
* `baseUrl`).
|
||||
*/
|
||||
export function setupRecording(
|
||||
payload: unknown,
|
||||
extra: Partial<AdyenConfig> = {}
|
||||
): Harness {
|
||||
const { calls, fetch } = recording(payload);
|
||||
const provider = new AdyenProvider({
|
||||
apiKey: "adyen_key_123",
|
||||
merchantAccount: "TestMerchant",
|
||||
baseUrl: "https://adyen.mock/v71",
|
||||
fetch,
|
||||
...extra,
|
||||
});
|
||||
const bodyOf = (index: number): Record<string, unknown> => {
|
||||
const raw = calls[index]?.init?.body;
|
||||
if (typeof raw !== "string") {
|
||||
throw new Error("expected string body");
|
||||
}
|
||||
return JSON.parse(raw) as Record<string, unknown>;
|
||||
};
|
||||
const headersOf = (index: number): Record<string, string> => {
|
||||
const raw = calls[index]?.init?.headers;
|
||||
if (raw === undefined) {
|
||||
throw new Error("expected headers");
|
||||
}
|
||||
return raw as Record<string, string>;
|
||||
};
|
||||
return { provider, calls, bodyOf, headersOf };
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Polyfills for the payment-provider-adyen test environment — none required.
|
||||
// Every test injects a recording `FetchLike` closure via the provider's
|
||||
// constructor `fetch` option, so the suite never depends on a platform
|
||||
// `fetch` global. This file exists to mirror the sibling-package layout
|
||||
// and to give vitest a stable setup-file path.
|
||||
export {};
|
||||
Reference in New Issue
Block a user