feat: implement project development module, transfer management features, and industrial AVM model integration

This commit is contained in:
Ho Ngoc Hai
2026-04-18 20:34:35 +07:00
parent 0f3b4d7b0d
commit 38b9def99a
66 changed files with 9051 additions and 17 deletions

View File

@@ -287,4 +287,46 @@ test.describe('Listings API', () => {
expect(res.status()).toBe(401);
});
});
test.describe('GET /listings/:id/price-history — Price history timeline', () => {
test('returns empty array when listing has no price changes', async ({ request }) => {
const { listing } = await createListing(request, accessToken);
const res = await request.get(`listings/${listing.listingId}/price-history`);
expect(res.status()).toBe(200);
const body = await res.json();
expect(Array.isArray(body)).toBe(true);
expect(body).toHaveLength(0);
});
test('returns a price history entry after price update', async ({ request }) => {
const { listing } = await createListing(request, accessToken);
const updateRes = await request.patch(`listings/${listing.listingId}`, {
data: { priceVND: '6000000000' },
headers: { Authorization: `Bearer ${accessToken}` },
});
expect(updateRes.status()).toBe(200);
// Event bus is async — poll briefly for the snapshot to land.
const deadline = Date.now() + 5000;
let body: Array<{ oldPrice: string; newPrice: string; source: string; changedAt: string }> = [];
while (Date.now() < deadline) {
const res = await request.get(`listings/${listing.listingId}/price-history`);
expect(res.status()).toBe(200);
body = await res.json();
if (body.length > 0) break;
await new Promise((r) => setTimeout(r, 100));
}
expect(body.length).toBeGreaterThanOrEqual(1);
const entry = body[0]!;
expect(entry).toHaveProperty('oldPrice');
expect(entry).toHaveProperty('newPrice');
expect(entry).toHaveProperty('source');
expect(entry).toHaveProperty('changedAt');
expect(entry.source).toBe('manual_update');
});
});
});