From f0f536671bfd4400049aede42933c09ebc0709f3 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Mon, 5 Jan 2026 17:39:17 +0100 Subject: [PATCH] test(server): fix testing gaps and failing tests 1. Add DELETE /api/sync/data route tests to sync.routes.spec.ts: - Test successful deletion returns { success: true } - Test 401 without authorization - Test uploading new data works after reset 2. Fix passkey.spec.ts failures (4 tests): - Add missing passkey.findUnique mock for credential lookup - Update test expectations for discoverable credentials (no allowCredentials - implementation changed) 3. Fix password-reset-api.spec.ts failures (12 tests): - Exclude from vitest - tests routes that don't exist - Server uses passkey/magic link auth, not password auth All 412 tests now pass. --- .../super-sync-server/tests/passkey.spec.ts | 35 +++++-- .../tests/sync.routes.spec.ts | 96 +++++++++++++++++++ packages/super-sync-server/vitest.config.ts | 2 + 3 files changed, 127 insertions(+), 6 deletions(-) diff --git a/packages/super-sync-server/tests/passkey.spec.ts b/packages/super-sync-server/tests/passkey.spec.ts index 8a6f3696c..d2ca7d0c5 100644 --- a/packages/super-sync-server/tests/passkey.spec.ts +++ b/packages/super-sync-server/tests/passkey.spec.ts @@ -25,6 +25,7 @@ vi.mock('../src/db', () => { create: vi.fn(), update: vi.fn(), deleteMany: vi.fn(), + findUnique: vi.fn(), }, $transaction: vi.fn(), }; @@ -86,6 +87,7 @@ describe('Passkey Authentication', () => { create: Mock; update: Mock; deleteMany: Mock; + findUnique: Mock; }; $transaction: Mock; }; @@ -281,14 +283,12 @@ describe('Passkey Authentication', () => { expect(options).toBeDefined(); expect(options.challenge).toBe(testChallenge); + // Implementation uses discoverable credentials (no allowCredentials) + // to let browser show all available passkeys for this RP expect(mockGenerateAuthentication).toHaveBeenCalledWith( expect.objectContaining({ - allowCredentials: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(String), - transports: ['internal'], - }), - ]), + rpID: 'localhost', + userVerification: 'preferred', }), ); }); @@ -311,6 +311,16 @@ describe('Passkey Authentication', () => { passkeys: [mockPasskey], }); + // Mock passkey lookup by credential ID (new implementation uses discoverable credentials) + mockPrisma.passkey.findUnique.mockResolvedValue({ + ...mockPasskey, + user: { + id: 1, + email: testEmail, + isVerified: 1, + }, + }); + mockVerifyAuthentication.mockResolvedValue({ verified: true, authenticationInfo: { @@ -356,6 +366,16 @@ describe('Passkey Authentication', () => { passkeys: [mockPasskey], }); + // Mock passkey lookup - user is unverified + mockPrisma.passkey.findUnique.mockResolvedValue({ + ...mockPasskey, + user: { + id: 1, + email: testEmail, + isVerified: 0, + }, + }); + // Generate options first await generateAuthenticationOptions(testEmail); @@ -384,6 +404,9 @@ describe('Passkey Authentication', () => { passkeys: [mockPasskey], }); + // Mock passkey lookup returns null (credential not found) + mockPrisma.passkey.findUnique.mockResolvedValue(null); + // Generate options first await generateAuthenticationOptions(testEmail); diff --git a/packages/super-sync-server/tests/sync.routes.spec.ts b/packages/super-sync-server/tests/sync.routes.spec.ts index e713f5164..5bcab0d33 100644 --- a/packages/super-sync-server/tests/sync.routes.spec.ts +++ b/packages/super-sync-server/tests/sync.routes.spec.ts @@ -1440,4 +1440,100 @@ describe('Restore Points API', () => { expect(retryResponse.json().errorCode).toBe('SYNC_IMPORT_EXISTS'); }); }); + + describe('DELETE /api/sync/data - Reset Account (Delete All User Data)', () => { + it('should delete all user data and return success', async () => { + // First upload some operations + await app.inject({ + method: 'POST', + url: '/api/sync/ops', + headers: { authorization: `Bearer ${authToken}` }, + payload: { + ops: [ + createOp(clientId, { entityId: 'task-1' }), + createOp(clientId, { entityId: 'task-2' }), + ], + clientId, + }, + }); + + // Verify ops exist + const opsBefore = await app.inject({ + method: 'GET', + url: '/api/sync/ops?sinceSeq=0', + headers: { authorization: `Bearer ${authToken}` }, + }); + expect(opsBefore.json().ops.length).toBe(2); + + // Delete all user data + const deleteResponse = await app.inject({ + method: 'DELETE', + url: '/api/sync/data', + headers: { authorization: `Bearer ${authToken}` }, + }); + + expect(deleteResponse.statusCode).toBe(200); + expect(deleteResponse.json()).toEqual({ success: true }); + + // Verify ops are gone + const opsAfter = await app.inject({ + method: 'GET', + url: '/api/sync/ops?sinceSeq=0', + headers: { authorization: `Bearer ${authToken}` }, + }); + expect(opsAfter.json().ops.length).toBe(0); + }); + + it('should return 401 without authorization', async () => { + const response = await app.inject({ + method: 'DELETE', + url: '/api/sync/data', + }); + + expect(response.statusCode).toBe(401); + }); + + it('should allow uploading new data after reset', async () => { + // Upload initial data + await app.inject({ + method: 'POST', + url: '/api/sync/ops', + headers: { authorization: `Bearer ${authToken}` }, + payload: { + ops: [createOp(clientId, { entityId: 'old-task' })], + clientId, + }, + }); + + // Delete all data + await app.inject({ + method: 'DELETE', + url: '/api/sync/data', + headers: { authorization: `Bearer ${authToken}` }, + }); + + // Upload new data after reset + const uploadResponse = await app.inject({ + method: 'POST', + url: '/api/sync/ops', + headers: { authorization: `Bearer ${authToken}` }, + payload: { + ops: [createOp(clientId, { entityId: 'new-task' })], + clientId, + }, + }); + + expect(uploadResponse.statusCode).toBe(200); + expect(uploadResponse.json().results[0].accepted).toBe(true); + + // Verify only new data exists + const ops = await app.inject({ + method: 'GET', + url: '/api/sync/ops?sinceSeq=0', + headers: { authorization: `Bearer ${authToken}` }, + }); + expect(ops.json().ops.length).toBe(1); + expect(ops.json().ops[0].entityId).toBe('new-task'); + }); + }); }); diff --git a/packages/super-sync-server/vitest.config.ts b/packages/super-sync-server/vitest.config.ts index 85660b77f..972cd61c1 100644 --- a/packages/super-sync-server/vitest.config.ts +++ b/packages/super-sync-server/vitest.config.ts @@ -21,6 +21,8 @@ export default defineConfig({ 'tests/snapshot-skip-optimization.spec.ts', 'tests/integration/multi-client-sync.integration.spec.ts', 'tests/integration/snapshot-skip-optimization.integration.spec.ts', + // Tests password reset routes that don't exist - server uses passkey/magic link auth + 'tests/password-reset-api.spec.ts', ], }, });