| 123456789101112131415161718 |
- import assert from 'node:assert/strict';
- import test from 'node:test';
- import { CompetitorListingMonitorService, type CompetitorListingMonitorRepository } from '../src/modules/competitor-listing-monitor/competitor-listing-monitor.service.js';
- import type { CompetitorListingChange, CompetitorListingRefreshRun, CompetitorListingSnapshot } from '../src/modules/competitor-listing-monitor/domain.js';
- const specs = { model: null, color: null, specification: null, origin: null, weightKg: null, lengthMm: null, widthMm: null, heightMm: null };
- class Repo implements CompetitorListingMonitorRepository {
- snapshots: CompetitorListingSnapshot[] = []; changes: CompetitorListingChange[] = []; runs: CompetitorListingRefreshRun[] = [];
- async listTargets() { return []; } async getLatestSnapshot() { return null; } async listSnapshots() { return this.snapshots; } async saveSnapshot(v: CompetitorListingSnapshot) { return v; } async listChanges() { return this.changes; } async saveChange(v: CompetitorListingChange) { return v; } async findActiveRun() { return null; } async createRun(v: CompetitorListingRefreshRun) { return v; } async updateRun(v: CompetitorListingRefreshRun) { return v; } async getRun() { return null; } async listRuns() { return this.runs; }
- }
- const snap = (id: string, prev: string|null, title: string, priceCents: number): CompetitorListingSnapshot => ({ id, naturalKey: id, workspaceId: 'ws', platform: 'jd', productId: 'c1', previousSnapshotId: prev, contentHash: id.padEnd(64, '0'), observedAt: `2026-01-0${id.slice(-1)}T00:00:00.000Z`, title, priceCents, currency: 'CNY', availability: 'online', mainImageUrl: null, keySpecifications: specs, observedFields: ['title', 'price', 'availability'], collectionStatus: 'succeeded' });
- test('history returns field-filtered diffs and failed runs', async () => {
- const repository = new Repo(); repository.snapshots = [snap('s1', null, 'A', 1000), snap('s2', 's1', 'B', 900)];
- repository.changes = [{ id:'ch', naturalKey:'s1:s2', workspaceId:'ws', platform:'jd', productId:'c1', previousSnapshotId:'s1', currentSnapshotId:'s2', detectedAt:'2026-01-02T00:00:00.000Z', changeTypes:['title','price'], changes:[{field:'title',before:'A',after:'B'},{field:'priceCents',before:1000,after:900}] }];
- repository.runs = [{ id:'r', workspaceId:'ws', platform:'jd', trigger:'manual', status:'partial', total:1, completed:1, baseline:0, unchanged:0, changed:0, failed:1, itemResults:[{productId:'c1',status:'failed',errorCode:'timeout',observedAt:'2026-01-02T00:00:00.000Z'}], requestedAt:'2026-01-02T00:00:00.000Z',startedAt:null,completedAt:null }];
- const history = await new CompetitorListingMonitorService(repository, { request: async <T>() => ({} as T) }).history('ws','jd','c1',{ fields:['price'] });
- assert.equal(history.snapshots.length, 2); assert.deepEqual(history.changes[0]!.changeTypes, ['price']); assert.equal(history.collectionRuns[0]!.result?.status, 'failed');
- });
|