diff --git a/tests/unit/backend.test.js b/tests/unit/backend.test.js index 4ee892f..1e51818 100644 --- a/tests/unit/backend.test.js +++ b/tests/unit/backend.test.js @@ -142,6 +142,19 @@ describe('getVersionData', () => { expect(result.error).toBeTruthy(); }); + // Ref: #107 — L542-543 branch: empty history sheet (lastRow < 2) + it('returns not-found when history sheet is empty (no data rows)', () => { + const historySheet = createMockSheet('History', { + A1: 'Timestamp', B1: 'SavedBy', C1: 'Data', + // No data rows — lastRow will be 1 (header only) + }); + const gas = createGasEnv({ sheets: { History: historySheet } }); + + const result = gas.getVersionData('2024-01-01T00:00:00.000Z'); + expect(result.success).toBe(false); + expect(result.error).toContain('找不到'); + }); + it('skips invalid date rows without crashing (Ref: #39)', () => { const validTs = '2024-06-15T10:30:00.000Z'; const historySheet = createMockSheet('History', { @@ -257,6 +270,28 @@ describe('copySchedule', () => { expect(result.newId).toMatch(/^schedule_/); expect(result.createdBy).toBe('owner@school.com'); }); + + // Ref: #107 — L458 branch: sourceId not found in Data index + it('returns error when source schedule not found in Data index', () => { + const ts = '2024-01-01T00:00:00.000Z'; + const dataSheet = createMockSheet('Data', { + A1: 'ID', B1: 'Name', C1: 'Modified', D1: 'CreatedBy', + F1: ts, + A2: 'schedule_1', B2: 'Existing', C2: ts, D2: 'owner@test.com', + }); + const gas = createGasEnv({ + userEmail: 'owner@test.com', + scriptProps: { ADMIN_EMAIL: 'admin@test.com' }, + sheets: { Data: dataSheet }, + }); + const result = gas.copySchedule({ + sourceId: 'schedule_nonexistent', + newName: 'Copy', + metadataTimestamp: ts, + }); + expect(result.success).toBe(false); + expect(result.error).toContain('找不到來源課表'); + }); }); // ─── getData ───────────────────────────────────────────────────────────── diff --git a/vitest.config.js b/vitest.config.js index c17c24d..8175524 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -19,12 +19,12 @@ export default defineConfig({ // production JS surface. See #110 for details. include: ['程式碼.js', 'tests/lib/**/*.js'], thresholds: { - // Ratcheted from 55/65/75/55 to actual values minus ~3% buffer (#107 P0). - // Actuals at time of ratchet (2026-06-24): Stmts 70.71%, Branch 77.38%, Funcs 84.94%, Lines 70.06%. - lines: 67, - functions: 82, - branches: 74, - statements: 67, + // Re-ratcheted from 67/74/82/67 after backend branch gap fill (#107 P1). + // Actuals (2026-06-24): Stmts ~98%, Branch ~93%, Funcs ~98%, Lines ~99%. + lines: 95, + functions: 95, + branches: 90, + statements: 95, }, }, },