130 lines
3.8 KiB
JavaScript
130 lines
3.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
createPricingProvider,
|
|
createPricingProviderRegistry,
|
|
} from "../../src/modules/pricing/providers/pricing-provider.js";
|
|
import { createFixturePricingProvider } from "../../src/modules/pricing/providers/fixture-pricing-provider.js";
|
|
import {
|
|
assertProductionPricingProviderConfig,
|
|
createHttpPricingProvider,
|
|
} from "../../src/modules/pricing/providers/http-pricing-provider.js";
|
|
|
|
test("registers pricing providers behind a validated adapter contract", async () => {
|
|
const provider = createPricingProvider({
|
|
id: "example",
|
|
async observe() {
|
|
return [{ priceMinor: 2500, sourceIdentifier: "example-1" }];
|
|
},
|
|
});
|
|
const registry = createPricingProviderRegistry([provider]);
|
|
|
|
assert.equal(registry.get("example"), provider);
|
|
assert.deepEqual(await registry.get("example").observe({}), [
|
|
{ priceMinor: 2500, sourceIdentifier: "example-1" },
|
|
]);
|
|
assert.deepEqual(registry.list(), [provider]);
|
|
});
|
|
|
|
test("rejects malformed provider adapters and responses", async () => {
|
|
assert.throws(
|
|
() => createPricingProvider({ id: "broken" }),
|
|
/observe function is required/,
|
|
);
|
|
const provider = createPricingProvider({
|
|
id: "broken",
|
|
async observe() {
|
|
return null;
|
|
},
|
|
});
|
|
await assert.rejects(
|
|
() => provider.observe({}),
|
|
/must return an observation array/,
|
|
);
|
|
});
|
|
|
|
test("fixture provider returns deterministic normalized observations", async () => {
|
|
const [observation] = await createFixturePricingProvider().observe({
|
|
productId: "product-1",
|
|
inventoryItemId: "item-1",
|
|
conditionId: "condition-1",
|
|
});
|
|
assert.deepEqual(observation, {
|
|
productId: "product-1",
|
|
inventoryItemId: "item-1",
|
|
conditionId: "condition-1",
|
|
priceMinor: 2500,
|
|
currency: "USD",
|
|
sourceIdentifier: "fixture-item-1",
|
|
qualityScore: 50,
|
|
});
|
|
});
|
|
|
|
test("http provider rejects insecure or malformed external provider URLs", () => {
|
|
assert.throws(
|
|
() =>
|
|
createHttpPricingProvider({
|
|
id: "http-provider",
|
|
endpoint: "http://provider.example/prices",
|
|
}),
|
|
/HTTPS/i,
|
|
);
|
|
|
|
assert.throws(
|
|
() =>
|
|
createHttpPricingProvider({
|
|
id: "http-provider",
|
|
endpoint: "not-a-url",
|
|
}),
|
|
/valid https URL/i,
|
|
);
|
|
});
|
|
|
|
test("requires a secure external provider in production", () => {
|
|
assert.throws(
|
|
() => assertProductionPricingProviderConfig({ fixtureEnabled: true, endpoint: "https://provider.example/prices" }),
|
|
/fixture pricing provider must be disabled/i,
|
|
);
|
|
assert.throws(
|
|
() => assertProductionPricingProviderConfig({ fixtureEnabled: false, endpoint: "" }),
|
|
/endpoint is required/i,
|
|
);
|
|
assert.throws(
|
|
() => assertProductionPricingProviderConfig({ fixtureEnabled: false, endpoint: "http://provider.example/prices" }),
|
|
/must use HTTPS/i,
|
|
);
|
|
assert.doesNotThrow(() => assertProductionPricingProviderConfig({
|
|
fixtureEnabled: false,
|
|
endpoint: "https://provider.example/prices",
|
|
}));
|
|
});
|
|
|
|
test("http provider sends mapping context and normalizes its response", async () => {
|
|
let request;
|
|
const provider = createHttpPricingProvider({
|
|
id: "http-provider",
|
|
endpoint: "https://provider.example/prices",
|
|
token: "test-token",
|
|
async fetchImplementation(url, options) {
|
|
request = { url: String(url), options };
|
|
return {
|
|
ok: true,
|
|
async json() {
|
|
return { observations: [{ priceMinor: 2500 }] };
|
|
},
|
|
};
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(
|
|
await provider.observe({
|
|
externalIdentifier: "catalog-1",
|
|
searchQuery: "Charizard",
|
|
}),
|
|
[{ priceMinor: 2500 }],
|
|
);
|
|
assert.match(request.url, /externalIdentifier=catalog-1/);
|
|
assert.equal(request.options.headers.authorization, "Bearer test-token");
|
|
});
|