feat: reconcile application vertical slices
Backfill the completed acquisitions, sales, dashboard, pricing, search, public detail, worker, migration, contracts, validation, tests, and implementation-status changes into one verified application slice.
This commit is contained in:
@@ -1,25 +1,54 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import { buildApp } from '../../src/app/build-app.js';
|
||||
import { buildApp } from "../../src/app/build-app.js";
|
||||
|
||||
test('accepts a protected pricing observation and valuation request', async (testContext) => {
|
||||
test("accepts a protected pricing observation and valuation request", async (testContext) => {
|
||||
let csrfChecks = 0;
|
||||
const app = buildApp({
|
||||
authenticateAdmin: async () => ({ sellerId: 'seller-1' }),
|
||||
authorizeUnsafeRequest: async () => { csrfChecks += 1; },
|
||||
authenticateAdmin: async () => ({ sellerId: "seller-1" }),
|
||||
authorizeUnsafeRequest: async () => {
|
||||
csrfChecks += 1;
|
||||
},
|
||||
pricingService: {
|
||||
async addObservation(input) { return { id: 'observation-1', ...input }; },
|
||||
async calculate() { return { valuation: { id: 'valuation-1', inventoryItemId: 'inventory-1', valueMinor: 2500, currency: 'USD', strategy: 'MEDIAN', confidence: 'LOW', sourceCount: 1 }, observations: [] }; },
|
||||
async addObservation(input) {
|
||||
return { id: "observation-1", ...input };
|
||||
},
|
||||
async calculate() {
|
||||
return {
|
||||
valuation: {
|
||||
id: "valuation-1",
|
||||
inventoryItemId: "inventory-1",
|
||||
valueMinor: 2500,
|
||||
currency: "USD",
|
||||
strategy: "MEDIAN",
|
||||
confidence: "LOW",
|
||||
sourceCount: 1,
|
||||
},
|
||||
observations: [],
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
testContext.after(() => app.close());
|
||||
|
||||
const observationResponse = await app.inject({
|
||||
method: 'POST', url: '/api/v1/admin/pricing/observations', headers: { 'x-csrf-token': 'csrf' },
|
||||
payload: { productId: 'd2f67d74-9647-48d5-b3a4-74d3b16ea9f8', inventoryItemId: '21eb218b-7a95-4f80-a9e3-e306f7ca1f2e', providerId: 'manual', priceMinor: 2500, sourceIdentifier: 'source-1', conditionId: 'ab8150c7-96c1-4b55-8d69-7d0b77d48958' },
|
||||
method: "POST",
|
||||
url: "/api/v1/admin/pricing/observations",
|
||||
headers: { "x-csrf-token": "csrf" },
|
||||
payload: {
|
||||
productId: "d2f67d74-9647-48d5-b3a4-74d3b16ea9f8",
|
||||
inventoryItemId: "21eb218b-7a95-4f80-a9e3-e306f7ca1f2e",
|
||||
providerId: "manual",
|
||||
priceMinor: 2500,
|
||||
sourceIdentifier: "source-1",
|
||||
conditionId: "ab8150c7-96c1-4b55-8d69-7d0b77d48958",
|
||||
},
|
||||
});
|
||||
const valuationResponse = await app.inject({
|
||||
method: "POST",
|
||||
url: "/api/v1/admin/inventory/21eb218b-7a95-4f80-a9e3-e306f7ca1f2e/valuation",
|
||||
});
|
||||
const valuationResponse = await app.inject({ method: 'POST', url: '/api/v1/admin/inventory/21eb218b-7a95-4f80-a9e3-e306f7ca1f2e/valuation' });
|
||||
|
||||
assert.equal(observationResponse.statusCode, 201);
|
||||
assert.equal(valuationResponse.statusCode, 200);
|
||||
@@ -27,59 +56,74 @@ test('accepts a protected pricing observation and valuation request', async (tes
|
||||
assert.equal(csrfChecks, 2);
|
||||
});
|
||||
|
||||
test('accepts a CSRF-protected market-value override', async (testContext) => {
|
||||
test("accepts a CSRF-protected market-value override", async (testContext) => {
|
||||
let received;
|
||||
const app = buildApp({
|
||||
authenticateAdmin: async () => ({ userId: 'user-1', sellerId: 'seller-1' }),
|
||||
authenticateAdmin: async () => ({ userId: "user-1", sellerId: "seller-1" }),
|
||||
authorizeUnsafeRequest: async () => {},
|
||||
pricingService: { async override(input) { received = input; return { id: 'override-1', ...input }; } },
|
||||
pricingService: {
|
||||
async override(input) {
|
||||
received = input;
|
||||
return { id: "override-1", ...input };
|
||||
},
|
||||
},
|
||||
});
|
||||
testContext.after(() => app.close());
|
||||
const response = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/v1/admin/inventory/21eb218b-7a95-4f80-a9e3-e306f7ca1f2e/valuation/override',
|
||||
headers: { 'x-csrf-token': 'csrf' },
|
||||
payload: { valueMinor: 2600, reason: 'Verified recent sale' },
|
||||
method: "POST",
|
||||
url: "/api/v1/admin/inventory/21eb218b-7a95-4f80-a9e3-e306f7ca1f2e/valuation/override",
|
||||
headers: { "x-csrf-token": "csrf" },
|
||||
payload: { valueMinor: 2600, reason: "Verified recent sale" },
|
||||
});
|
||||
assert.equal(response.statusCode, 201);
|
||||
assert.equal(received.actorUserId, 'user-1');
|
||||
assert.equal(received.actorUserId, "user-1");
|
||||
assert.equal(response.json().data.valueMinor, 2600);
|
||||
});
|
||||
|
||||
test('enqueues a pricing refresh and exposes seller-scoped job status', async (testContext) => {
|
||||
test("enqueues a pricing refresh and exposes seller-scoped job status", async (testContext) => {
|
||||
const app = buildApp({
|
||||
authenticateAdmin: async () => ({ userId: 'user-1', sellerId: 'seller-1' }),
|
||||
authenticateAdmin: async () => ({ userId: "user-1", sellerId: "seller-1" }),
|
||||
authorizeUnsafeRequest: async () => {},
|
||||
pricingService: {
|
||||
async enqueueRefresh(input) { return { id: 'job-1', status: 'PENDING', createdAt: input.sellerId }; },
|
||||
async getJob(input) { assert.equal(input.sellerId, 'seller-1'); return { id: input.jobId, status: 'COMPLETED', error: null }; },
|
||||
async enqueueRefresh(input) {
|
||||
return { id: "job-1", status: "PENDING", createdAt: input.sellerId };
|
||||
},
|
||||
async getJob(input) {
|
||||
assert.equal(input.sellerId, "seller-1");
|
||||
return { id: input.jobId, status: "COMPLETED", error: null };
|
||||
},
|
||||
},
|
||||
});
|
||||
testContext.after(() => app.close());
|
||||
|
||||
const response = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/v1/admin/inventory/inventory-1/pricing/refresh',
|
||||
headers: { 'x-csrf-token': 'csrf' },
|
||||
payload: { providerId: 'missing' },
|
||||
method: "POST",
|
||||
url: "/api/v1/admin/inventory/inventory-1/pricing/refresh",
|
||||
headers: { "x-csrf-token": "csrf" },
|
||||
payload: { providerId: "missing" },
|
||||
});
|
||||
|
||||
assert.equal(response.statusCode, 202);
|
||||
assert.equal(response.json().data.status, 'PENDING');
|
||||
assert.equal(response.json().data.status, "PENDING");
|
||||
|
||||
const jobResponse = await app.inject({ method: 'GET', url: '/api/v1/admin/jobs/job-1' });
|
||||
const jobResponse = await app.inject({
|
||||
method: "GET",
|
||||
url: "/api/v1/admin/jobs/job-1",
|
||||
});
|
||||
assert.equal(jobResponse.statusCode, 200);
|
||||
assert.equal(jobResponse.json().data.status, 'COMPLETED');
|
||||
assert.equal(jobResponse.json().data.status, "COMPLETED");
|
||||
});
|
||||
|
||||
test('returns a conflict when refresh has no active product mapping', async (testContext) => {
|
||||
test("returns a conflict when refresh has no active product mapping", async (testContext) => {
|
||||
const app = buildApp({
|
||||
authenticateAdmin: async () => ({ sellerId: 'seller-1' }),
|
||||
authenticateAdmin: async () => ({ sellerId: "seller-1" }),
|
||||
authorizeUnsafeRequest: async () => {},
|
||||
pricingService: {
|
||||
async enqueueRefresh() {
|
||||
const error = new Error('No active pricing provider mapping exists for this product.');
|
||||
error.code = 'PRICING_PROVIDER_MAPPING_NOT_FOUND';
|
||||
const error = new Error(
|
||||
"No active pricing provider mapping exists for this product.",
|
||||
);
|
||||
error.code = "PRICING_PROVIDER_MAPPING_NOT_FOUND";
|
||||
error.statusCode = 409;
|
||||
throw error;
|
||||
},
|
||||
@@ -88,30 +132,53 @@ test('returns a conflict when refresh has no active product mapping', async (tes
|
||||
testContext.after(() => app.close());
|
||||
|
||||
const response = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/v1/admin/inventory/item-1/pricing/refresh',
|
||||
headers: { 'x-csrf-token': 'csrf' },
|
||||
payload: { productId: 'product-1', conditionId: 'condition-1' },
|
||||
method: "POST",
|
||||
url: "/api/v1/admin/inventory/item-1/pricing/refresh",
|
||||
headers: { "x-csrf-token": "csrf" },
|
||||
payload: { productId: "product-1", conditionId: "condition-1" },
|
||||
});
|
||||
|
||||
assert.equal(response.statusCode, 409);
|
||||
assert.equal(response.json().error.code, 'PRICING_PROVIDER_MAPPING_NOT_FOUND');
|
||||
assert.equal(
|
||||
response.json().error.code,
|
||||
"PRICING_PROVIDER_MAPPING_NOT_FOUND",
|
||||
);
|
||||
});
|
||||
|
||||
test('lists jobs and retries a failed job with CSRF protection', async (testContext) => {
|
||||
test("lists jobs and retries a failed job with CSRF protection", async (testContext) => {
|
||||
let csrfChecks = 0;
|
||||
const app = buildApp({
|
||||
authenticateAdmin: async () => ({ sellerId: 'seller-1' }),
|
||||
authorizeUnsafeRequest: async () => { csrfChecks += 1; },
|
||||
authenticateAdmin: async () => ({ sellerId: "seller-1" }),
|
||||
authorizeUnsafeRequest: async () => {
|
||||
csrfChecks += 1;
|
||||
},
|
||||
pricingService: {
|
||||
async listJobs() { return [{ id: 'job-1', status: 'FAILED', providerId: 'fixture', inventoryItemId: 'item-1' }]; },
|
||||
async retryJob() { return { id: 'job-1', status: 'PENDING' }; },
|
||||
async listJobs() {
|
||||
return [
|
||||
{
|
||||
id: "job-1",
|
||||
status: "FAILED",
|
||||
providerId: "fixture",
|
||||
inventoryItemId: "item-1",
|
||||
},
|
||||
];
|
||||
},
|
||||
async retryJob() {
|
||||
return { id: "job-1", status: "PENDING" };
|
||||
},
|
||||
},
|
||||
});
|
||||
testContext.after(() => app.close());
|
||||
const listResponse = await app.inject({ method: 'GET', url: '/api/v1/admin/jobs' });
|
||||
const retryResponse = await app.inject({ method: 'POST', url: '/api/v1/admin/jobs/job-1/retry', headers: { 'x-csrf-token': 'csrf' } });
|
||||
const listResponse = await app.inject({
|
||||
method: "GET",
|
||||
url: "/api/v1/admin/jobs",
|
||||
});
|
||||
const retryResponse = await app.inject({
|
||||
method: "POST",
|
||||
url: "/api/v1/admin/jobs/job-1/retry",
|
||||
headers: { "x-csrf-token": "csrf" },
|
||||
});
|
||||
assert.equal(listResponse.statusCode, 200);
|
||||
assert.equal(retryResponse.statusCode, 202);
|
||||
assert.equal(csrfChecks, 1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user