chore: 현재 작업 중간 커밋

This commit is contained in:
chungyeong
2026-03-05 11:00:45 +09:00
parent 02970df6af
commit be88b4fcec
43 changed files with 6837 additions and 466 deletions

View File

@@ -0,0 +1,133 @@
"use strict";
const test = require("node:test");
const assert = require("node:assert/strict");
const { createDashboardRuntime } = require("../src/dashboardRuntime");
function createStore({ controls }) {
const events = [];
const watches = [
{
id: "watch-1",
rawInput: "인천->도쿄",
searchParams: { segments: [{ from: "ICN", to: "NRT" }], departureDateWindow: { from: "2026-06-01" } },
alertRules: {
targetPrice: null,
notifyOnPriceChange: true,
notifyOnFirstResult: true,
},
pollingEnabled: true,
alertsEnabled: true,
createdAt: "2026-02-19T00:00:00.000Z",
updatedAt: "2026-02-19T00:00:00.000Z",
lastSnapshot: null,
lastError: null,
},
];
return {
events,
async init() {},
async close() {},
async listWatches() {
return watches;
},
async getWatch() {
return null;
},
async saveWatch(watch) {
return watch;
},
async deleteWatch() {
return true;
},
async savePollResult() {},
async saveEvent(event) {
events.push(event);
return event;
},
async listEvents() {
return events;
},
async getGlobalControls() {
return controls;
},
async setGlobalControls(patch = {}) {
controls = { ...controls, ...patch };
return controls;
},
};
}
test("runtime stores failed notification state when notifier throws", async () => {
const store = createStore({
controls: { crawlingEnabled: true, alertsEnabled: true },
});
const crawler = {
async getQuotes() {
return [{ provider: "mock", price: 120000, currency: "KRW" }];
},
};
const notifier = {
async notify() {
throw new Error("network down");
},
};
const runtime = await createDashboardRuntime({
store,
crawler,
notifier,
logger: { error: () => {} },
pollIntervalSec: 3600,
});
try {
assert.equal(store.events.length, 1);
const payload = store.events[0].payload;
assert.equal(payload.notificationState, "failed");
assert.equal(payload.notificationSent, false);
assert.equal(payload.notificationSuppressed, undefined);
assert.equal(payload.notificationError.phase, "notify");
assert.match(payload.notificationError.message, /Notifier failed/);
} finally {
await runtime.close();
}
});
test("runtime stores suppressed notification state when alerts are disabled", async () => {
let notifyCalls = 0;
const store = createStore({
controls: { crawlingEnabled: true, alertsEnabled: false },
});
const crawler = {
async getQuotes() {
return [{ provider: "mock", price: 120000, currency: "KRW" }];
},
};
const notifier = {
async notify() {
notifyCalls += 1;
},
};
const runtime = await createDashboardRuntime({
store,
crawler,
notifier,
logger: { error: () => {} },
pollIntervalSec: 3600,
});
try {
assert.equal(store.events.length, 1);
const payload = store.events[0].payload;
assert.equal(payload.notificationState, "suppressed");
assert.equal(payload.notificationSent, false);
assert.equal(payload.notificationSuppressed, true);
assert.equal(payload.notificationError, null);
assert.equal(notifyCalls, 0);
} finally {
await runtime.close();
}
});