feat(FN-1465): merge fusion/fn-1465
This commit is contained in:
@@ -104,6 +104,98 @@ describe("isTaskStuck", () => {
|
||||
const task = createTask({ updatedAt: boundary });
|
||||
expect(isTaskStuck(task, 600000)).toBe(false);
|
||||
});
|
||||
|
||||
describe("dataAsOfMs parameter (freshness-aware stuck detection)", () => {
|
||||
it("uses dataAsOfMs instead of Date.now() when provided", () => {
|
||||
// Task updatedAt is 11 minutes ago
|
||||
const taskUpdatedAt = new Date(Date.now() - 11 * 60 * 1000).toISOString();
|
||||
const task = createTask({ updatedAt: taskUpdatedAt });
|
||||
|
||||
// dataAsOfMs is 5 minutes ago (task was fresh 5 minutes ago)
|
||||
const dataAsOfMs = Date.now() - 5 * 60 * 1000;
|
||||
|
||||
// 10 minute timeout
|
||||
// With dataAsOfMs: 5 min - 11 min = -6 min < 10 min → NOT stuck
|
||||
// Without dataAsOfMs: 0 min - 11 min = -11 min > 10 min → stuck
|
||||
expect(isTaskStuck(task, 600000, dataAsOfMs)).toBe(false);
|
||||
});
|
||||
|
||||
it("falls back to Date.now() when dataAsOfMs is undefined", () => {
|
||||
// Task updatedAt is 5 minutes ago
|
||||
const taskUpdatedAt = new Date(Date.now() - 5 * 60 * 1000).toISOString();
|
||||
const task = createTask({ updatedAt: taskUpdatedAt });
|
||||
|
||||
// Without dataAsOfMs, should use Date.now() → NOT stuck (within 10 min timeout)
|
||||
expect(isTaskStuck(task, 600000)).toBe(false);
|
||||
});
|
||||
|
||||
it("correctly identifies a task that would be stuck with Date.now() but not with dataAsOfMs", () => {
|
||||
// Scenario: Tab was in background for 20 minutes
|
||||
// Task was updated 10 minutes ago (relative to dataAsOfMs)
|
||||
// dataAsOfMs represents "10 minutes ago" (when we fetched fresh data)
|
||||
// Date.now() is "now" (20 minutes after the fetch)
|
||||
//
|
||||
// This simulates the background tab scenario:
|
||||
// - User opened tab at T=0, fetched tasks
|
||||
// - Tab went to background at T=0
|
||||
// - User came back at T=20
|
||||
// - dataAsOfMs = T=0 (when we last had fresh data)
|
||||
// - Task was updated at T=-10 (10 minutes before fetch)
|
||||
// - task.updatedAt represents T=-10
|
||||
//
|
||||
// Check: dataAsOfMs - updatedAt = 0 - (-10) = 10 min < 10 min timeout → NOT stuck
|
||||
// Without dataAsOfMs: Date.now() - updatedAt = 20 - (-10) = 30 min > 10 min → STUCK (false positive!)
|
||||
|
||||
// In fake timers, we set Date.now() to a fixed point
|
||||
// Let's say Date.now() = 1000 (representing "now")
|
||||
// dataAsOfMs = 0 (representing 20 minutes before "now" in fake time)
|
||||
// task.updatedAt = -600 (representing 10 minutes before dataAsOfMs)
|
||||
|
||||
vi.setSystemTime(new Date(1000)); // Date.now() = 1000
|
||||
const dataAsOfMs = 0; // 20 minutes before Date.now() in this scenario
|
||||
const taskUpdatedAt = new Date(-600000).toISOString(); // 10 minutes before dataAsOfMs
|
||||
const task = createTask({ updatedAt: taskUpdatedAt });
|
||||
|
||||
// With dataAsOfMs: 0 - (-600000) = 600000ms = 10 min = timeout → NOT stuck (boundary)
|
||||
// Without dataAsOfMs: 1000 - (-600000) = 601000ms > 10 min → STUCK
|
||||
// The key test: with dataAsOfMs it should NOT be stuck even though Date.now() would say it is
|
||||
expect(isTaskStuck(task, 600000, dataAsOfMs)).toBe(false);
|
||||
});
|
||||
|
||||
it("prevents false positive when tab was in background", () => {
|
||||
// Simulate: Tab in background, data fetched 15 min ago
|
||||
// Task.updatedAt is 12 min ago (stale from server perspective)
|
||||
// taskStuckTimeoutMs = 10 min
|
||||
// With fresh data (15 min ago): 15 - 12 = 3 min < 10 min → NOT stuck
|
||||
// With stale Date.now(): 0 - 12 = 12 min > 10 min → STUCK (FALSE POSITIVE)
|
||||
|
||||
vi.setSystemTime(new Date(0)); // Date.now() = 0
|
||||
const dataAsOfMs = -900000; // 15 minutes ago (in fake time)
|
||||
const taskUpdatedAt = new Date(-720000).toISOString(); // 12 minutes ago (in fake time)
|
||||
const task = createTask({ updatedAt: taskUpdatedAt });
|
||||
|
||||
// With dataAsOfMs: -900000 - (-720000) = -180000ms = -3 min < 10 min → NOT stuck
|
||||
// Without dataAsOfMs: 0 - (-720000) = 720000ms = 12 min > 10 min → STUCK
|
||||
expect(isTaskStuck(task, 600000, dataAsOfMs)).toBe(false);
|
||||
});
|
||||
|
||||
it("correctly identifies genuinely stuck tasks even with dataAsOfMs", () => {
|
||||
// Task really is stuck: updatedAt is 15 min ago, timeout is 10 min
|
||||
// With dataAsOfMs of 2 min ago: 2 - 15 = -13 min < 10 min → NOT stuck (hmm, this is a problem)
|
||||
|
||||
// Actually, dataAsOfMs should represent when we last got FRESH data from the server
|
||||
// If dataAsOfMs = 2 min ago and task.updatedAt = 15 min ago, the task was stale
|
||||
// even when we fetched it, because 2 - 15 = -13 min > 10 min timeout
|
||||
|
||||
vi.setSystemTime(new Date(0));
|
||||
const dataAsOfMs = -120000; // 2 minutes ago
|
||||
const taskUpdatedAt = new Date(-900000).toISOString(); // 15 minutes ago
|
||||
const task = createTask({ updatedAt: taskUpdatedAt });
|
||||
|
||||
// With dataAsOfMs: -120000 - (-900000) = 780000ms = 13 min > 10 min → STUCK
|
||||
expect(isTaskStuck(task, 600000, dataAsOfMs)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("countStuckTasks", () => {
|
||||
@@ -152,4 +244,27 @@ describe("countStuckTasks", () => {
|
||||
];
|
||||
expect(countStuckTasks(tasks, 600000)).toBe(2);
|
||||
});
|
||||
|
||||
describe("dataAsOfMs parameter (freshness-aware stuck detection)", () => {
|
||||
it("passes dataAsOfMs through to isTaskStuck", () => {
|
||||
// Task would be stuck with Date.now() but not with dataAsOfMs
|
||||
vi.setSystemTime(new Date(0));
|
||||
const dataAsOfMs = -900000; // 15 minutes ago
|
||||
const taskUpdatedAt = new Date(-720000).toISOString(); // 12 minutes ago
|
||||
const tasks = [createTask({ updatedAt: taskUpdatedAt })];
|
||||
|
||||
// With dataAsOfMs: -900000 - (-720000) = -180000ms = -3 min < 10 min → NOT stuck
|
||||
expect(countStuckTasks(tasks, 600000, dataAsOfMs)).toBe(0);
|
||||
});
|
||||
|
||||
it("counts tasks that are genuinely stuck even with dataAsOfMs", () => {
|
||||
vi.setSystemTime(new Date(0));
|
||||
const dataAsOfMs = -120000; // 2 minutes ago
|
||||
const taskUpdatedAt = new Date(-900000).toISOString(); // 15 minutes ago
|
||||
const tasks = [createTask({ updatedAt: taskUpdatedAt })];
|
||||
|
||||
// With dataAsOfMs: -120000 - (-900000) = 780000ms = 13 min > 10 min → STUCK
|
||||
expect(countStuckTasks(tasks, 600000, dataAsOfMs)).toBe(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user