Add unit tests for autoSaveService to handle document dirty states and periodic saves
- Implement tests for various scenarios including user edits, initial dirty state, and document changes. - Ensure proper flagging of uncommitted changes and silent saves for documents opened in a dirty state. - Test debounce behavior for document change notifications and version clearing functionality. - Validate suspension and resumption of auto-saving during versioning processes.
This commit is contained in:
parent
0b6ee8cc84
commit
454c90d17e
17 changed files with 1167 additions and 33 deletions
115
tests/wordaddin/autoSaveService.test.ts
Normal file
115
tests/wordaddin/autoSaveService.test.ts
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// autoSaveService (FR-17/FR-3) — คุมพฤติกรรม flag "มีการแก้ไขที่ยังไม่เป็น version":
|
||||
// ติดเฉพาะ clean→dirty (ผู้ใช้แก้จริง) หรือ notifyDocumentChanged ของ service ที่แก้เอกสาร
|
||||
// ส่วนไฟล์ที่เปิดมา dirty ตั้งแต่แรก (quirk ของ Word หลัง stamp properties หรือแก้ค้าง
|
||||
// จาก session ก่อน) ต้องถูก save เงียบ ๆ ไม่เด้ง banner ให้ผู้ใช้งงว่าไม่ได้ทำอะไร
|
||||
// (คำขอผู้ใช้ 2026-11-03) — mock documentService แทน Word.run ทั้งหมด
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { autoSaveConfig, autoSaveService } from "@/wordaddin/services/autoSaveService";
|
||||
|
||||
const doc = vi.hoisted(() => ({ dirty: false, saves: 0 }));
|
||||
vi.mock("@/wordaddin/services/documentService", () => ({
|
||||
isDocumentDirty: vi.fn(async () => doc.dirty),
|
||||
saveDocument: vi.fn(async () => {
|
||||
doc.saves += 1;
|
||||
}),
|
||||
}));
|
||||
|
||||
/** หมายเหตุ timing: seedBaseline ของ start() อ่าน dirty ณ ตอนเรียก — จะซิม "เปิดมา dirty"
|
||||
* ต้องตั้ง doc.dirty ก่อน startService() แล้ว flush microtask ให้ baseline จบก่อนเดินเวลา */
|
||||
async function flushMicrotasks(): Promise<void> {
|
||||
await vi.advanceTimersByTimeAsync(0);
|
||||
}
|
||||
|
||||
/** เดินเวลาไปอีกหนึ่ง periodic tick (30 วิ) แบบ flush microtask ของ tick ด้วย */
|
||||
async function tick(): Promise<void> {
|
||||
await vi.advanceTimersByTimeAsync(autoSaveConfig.periodicIntervalMs);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
doc.dirty = false;
|
||||
doc.saves = 0;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
autoSaveService.stop();
|
||||
autoSaveService.clearUncommittedSinceVersion();
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("flag FR-3 (hasUncommitted) กับ periodic save", () => {
|
||||
it("เปิดไฟล์สะอาด → ผู้ใช้แก้จริง (dirty ภายหลัง) → tick ตั้ง flag + save", async () => {
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks(); // baseline: สะอาด
|
||||
doc.dirty = true; // ผู้ใช้พิมพ์
|
||||
await tick();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(true);
|
||||
expect(doc.saves).toBe(1);
|
||||
});
|
||||
|
||||
it("เปิดมา dirty ตั้งแต่แรก (quirk หลัง stamp/แก้ค้าง) → save เงียบ ๆ ไม่ตั้ง flag", async () => {
|
||||
doc.dirty = true; // ก่อน start — ไฟล์เปิดมา dirty
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks();
|
||||
await tick();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(false);
|
||||
expect(doc.saves).toBe(1);
|
||||
});
|
||||
|
||||
it("quirk ถาวร (save แล้วยัง dirty ทุกรอบ) → หลาย tick ก็ไม่ตั้ง flag (แต่ยัง save)", async () => {
|
||||
doc.dirty = true;
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks();
|
||||
await tick();
|
||||
await tick();
|
||||
await tick();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(false);
|
||||
expect(doc.saves).toBe(3);
|
||||
});
|
||||
|
||||
it("dirty แรก (quirk) → save แล้วสะอาด → แก้จริงหลังจากนั้น → flag ติด (เห็น clean→dirty)", async () => {
|
||||
doc.dirty = true;
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks();
|
||||
await tick(); // save + ไม่ flag
|
||||
doc.dirty = false; // save ทำให้สะอาด
|
||||
await tick(); // เห็น clean → จุดอ้างอิงกลับมา
|
||||
doc.dirty = true; // ผู้ใช้แก้จริง
|
||||
await tick();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(true);
|
||||
});
|
||||
|
||||
it("notifyDocumentChanged (service ที่แก้เอกสาร เช่น เครื่องมือ template) → flag ทันที + debounce save 3 วิ", async () => {
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks();
|
||||
doc.dirty = true;
|
||||
autoSaveService.notifyDocumentChanged();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(true); // ไม่รอ tick
|
||||
expect(doc.saves).toBe(0); // ยังไม่ save — รอ debounce
|
||||
await vi.advanceTimersByTimeAsync(autoSaveConfig.debounceMs);
|
||||
expect(doc.saves).toBe(1);
|
||||
});
|
||||
|
||||
it("สร้าง version สำเร็จ → clearUncommittedSinceVersion เคลียร์ flag", async () => {
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks();
|
||||
doc.dirty = true;
|
||||
await tick();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(true);
|
||||
autoSaveService.clearUncommittedSinceVersion();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(false);
|
||||
});
|
||||
|
||||
it("suspend ระหว่าง flow (versioning) → tick ไม่ save ไม่แตะ flag", async () => {
|
||||
autoSaveService.start();
|
||||
await flushMicrotasks();
|
||||
doc.dirty = true;
|
||||
await autoSaveService.suspend();
|
||||
await tick();
|
||||
expect(autoSaveService.hasUncommittedSinceVersion).toBe(false);
|
||||
expect(doc.saves).toBe(0);
|
||||
autoSaveService.resume();
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue