Newer
Older
client_dwatch / lib / fixtures / __tests__ / schedules.test.ts
/**
 * fixtures の不変条件テスト(D-050 で再設計した schedules.ts を守る側)
 *
 * ★★2026-10-29(案B)で `computeScheduleProgress()` はこのファイルの schedules を使わなくなった★★
 *   (`planned` は対象日の清掃ログの行数。`data.anomaly` の `clean_log_rows_vs_scheduled` も消した)。
 *   下の説明は当時の経緯。不変条件そのものは fixtures の整合として残す。
 *
 * `computeScheduleProgress`(lib/dashboard/aggregate.ts)の `planned` は
 * 「その日の曜日に該当する active なスケジュールの総数」で決まり(docs/decisions.md D-049)、
 * `completed` は当日の清掃ログの行数から出発件数を数える。
 *
 * lib/fixtures/schedules.ts は、この2つが**どの曜日であっても常に一致する**よう
 * 有効スケジュールの曜日パターンを補完ペア+「毎日」で構成している
 * (schedules.ts 冒頭のコメント参照)。この一致が崩れると、/dashboard を
 * 何も指定せず開いたとき(当日・date省略の既定表示)に planned と実際の
 * 清掃ログ行数が食い違い、data.anomaly が発生して「9 / 6 完了」のように
 * 既定画面そのものが異常系になってしまう。
 *
 * スケジュールを1件追加・削除しただけで曜日ごとの該当件数は静かにズレうるため、
 * ★件数を 10 と決め打ちしない★。lib/fixtures/clean-logs.ts から当日分
 * (daysBack=0 相当)の行数を実際に数えて比較する。これにより、清掃ログ側の
 * 当日行数が将来変わっても、テストは「守るべき条件」を守り続ける。
 */
import { describe, expect, test } from "vitest";
import { cleanLogs } from "@/lib/fixtures/clean-logs";
import { dateOnly } from "@/lib/fixtures/_helpers";
import { schedules } from "@/lib/fixtures/schedules";

// weekdays 文字列のインデックスは getUTCDay() と同じ並び(日=0, 月=1, ..., 土=6)。
// lib/dashboard/aggregate.ts の weekdayIndex() 参照。
const WEEKDAY_LABELS = ["日", "月", "火", "水", "木", "金", "土"];

describe("fixtures の不変条件: schedules と clean-logs の当日行数(D-050)", () => {
  // daysBack=0 相当 = 今日の日付に一致する清掃ログの行数を実測する(ハードコード禁止)
  const today = dateOnly(0);
  const todayLogCount = cleanLogs.filter((log) =>
    log.scheduled_at.startsWith(today)
  ).length;

  test("前提: 当日分の清掃ログが1件以上存在する", () => {
    expect(todayLogCount).toBeGreaterThan(0);
  });

  WEEKDAY_LABELS.forEach((label, dow) => {
    test(`${label}曜日: 有効スケジュールの該当件数が当日の清掃ログ行数と一致する`, () => {
      const plannedForDow = schedules.filter(
        (s) => s.active && s.weekdays[dow] === "1"
      ).length;

      expect(
        plannedForDow,
        [
          `${label}曜日の active スケジュール該当件数(${plannedForDow})が`,
          `当日の清掃ログ行数(${todayLogCount})と一致しません。`,
          `この不変条件が崩れると、/dashboard を何も指定せず開いたとき(既定表示)に`,
          `planned と実績が食い違い data.anomaly が発生し、既定画面が「9 / 6 完了」のような`,
          `異常系表示になります。lib/fixtures/schedules.ts の active スケジュールの`,
          `曜日構成(補完ペア/毎日の件数)を見直してください。`,
        ].join("")
      ).toBe(todayLogCount);
    });
  });
});