Skip to content

Commit

Permalink
fix: qr code show not found exception handling (#107)
Browse files Browse the repository at this point in the history
* test: add firebase and getUser unit test

* fix: qr code show not found exception handling
  • Loading branch information
howard9199 authored Dec 25, 2024
1 parent c2cc5d6 commit 43ff8c7
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 3 deletions.
17 changes: 14 additions & 3 deletions src/lib/components/QrScanner.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@
scanning = false;
},
(err) => {
notifications.error(err);
if ((err as unknown as Error).toString().includes('NotFoundException')) {
return;
}
notifications.error(`error during scanning: ${err}`);
}
);
} catch (err) {
notifications.error(`Error starting camera: ${err}`);
notifications.error(`error during starting camera: ${err}`);
scanning = false;
}
}
Expand All @@ -53,7 +56,15 @@
const result = await scanner.scanFile(file, true);
onScan(result);
} catch (err) {
notifications.error(`Error scanning file: ${err}`);
if ((err as unknown as Error).toString().includes('NotFoundException')) {
notifications.error(
'Unable to find QR code in the image. Please ensure the image is clear and contains a valid QR code.'
);
} else {
notifications.error(`error during scanning file: ${err}`);
}
} finally {
fileInput.value = '';
}
}
</script>
Expand Down
166 changes: 166 additions & 0 deletions tests/firebase.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import type { CollectionReference, DocumentReference } from 'firebase-admin/firestore';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import {
adminDb,
checkRemoveParticipantPermission,
getGroupsData,
getSessionData
} from '../src/lib/server/firebase';

// Mock Firestore
vi.mock('firebase-admin/firestore', () => ({
getFirestore: vi.fn(() => ({
collection: vi.fn(),
doc: vi.fn()
})),
Timestamp: {
now: vi.fn(() => ({ toMillis: () => 1234567890000 }))
}
}));

describe('Firebase Server Functions', () => {
beforeEach(() => {
vi.clearAllMocks();
});

describe('getGroupsData', () => {
it('應該正確返回群組資料', async () => {
const mockGroups = {
empty: false,
docs: [
{
data: () => ({
number: 1,
participants: ['user1', 'user2'],
concept: null
})
},
{
data: () => ({
number: 2,
participants: ['user3', 'user4'],
concept: null
})
}
]
};

const groupsRef = {
get: vi.fn().mockResolvedValue(mockGroups)
} as unknown as CollectionReference;

const result = await getGroupsData(groupsRef);
expect(result).toHaveLength(2);
expect(result[0].number).toBe(1);
expect(result[1].participants).toContain('user3');
});

it('當沒有找到群組時應該拋出404錯誤', async () => {
const groupsRef = {
get: vi.fn().mockResolvedValue({ empty: true })
} as unknown as CollectionReference;

await expect(getGroupsData(groupsRef)).rejects.toThrow('Groups not found');
});
});

describe('getSessionData', () => {
it('應該正確返回會話資料', async () => {
const mockSession = {
exists: true,
data: () => ({
title: 'Test Session',
host: 'user1',
status: 'preparing'
})
};

const sessionRef = {
get: vi.fn().mockResolvedValue(mockSession)
} as unknown as DocumentReference;

const result = await getSessionData(sessionRef);
expect(result.title).toBe('Test Session');
expect(result.host).toBe('user1');
});

it('當沒有找到會話時應該拋出404錯誤', async () => {
const sessionRef = {
get: vi.fn().mockResolvedValue({ exists: false })
} as unknown as DocumentReference;

await expect(getSessionData(sessionRef)).rejects.toThrow('Session not found');
});
});

describe('checkRemoveParticipantPermission', () => {
it('當使用者是主持人時應該返回true', async () => {
const mockSession = {
exists: true,
data: () => ({
host: 'host123',
status: 'preparing'
})
};

vi.spyOn(adminDb, 'collection').mockReturnValue({
doc: vi.fn().mockReturnValue({
get: vi.fn().mockResolvedValue(mockSession)
})
} as unknown as CollectionReference);

const result = await checkRemoveParticipantPermission(
'session123',
'host123',
'participant123'
);
expect(result).toBe(true);
});

it('當使用者是被移除的參與者時應該返回true', async () => {
const mockSession = {
exists: true,
data: () => ({
host: 'host123',
status: 'preparing'
})
};

vi.spyOn(adminDb, 'collection').mockReturnValue({
doc: vi.fn().mockReturnValue({
get: vi.fn().mockResolvedValue(mockSession)
})
} as unknown as CollectionReference);

const result = await checkRemoveParticipantPermission(
'session123',
'participant123',
'participant123'
);
expect(result).toBe(true);
});

it('當使用者既不是主持人也不是被移除的參與者時應該返回false', async () => {
const mockSession = {
exists: true,
data: () => ({
host: 'host123',
status: 'preparing'
})
};

vi.spyOn(adminDb, 'collection').mockReturnValue({
doc: vi.fn().mockReturnValue({
get: vi.fn().mockResolvedValue(mockSession)
})
} as unknown as CollectionReference);

const result = await checkRemoveParticipantPermission(
'session123',
'otherUser123',
'participant123'
);
expect(result).toBe(false);
});
});
});
79 changes: 79 additions & 0 deletions tests/getUser.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type { DocumentReference, DocumentSnapshot } from 'firebase/firestore';
import { doc, getDoc } from 'firebase/firestore';
import type { Mock } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { getUser } from '../src/lib/utils/getUser';

// Mock Firebase
vi.mock('firebase/firestore', () => ({
doc: vi.fn(),
getDoc: vi.fn()
}));

vi.mock('$lib/firebase', () => ({
db: {}
}));

describe('getUser', () => {
beforeEach(() => {
vi.clearAllMocks();
});

it('應該正確返回使用者資料', async () => {
const mockUserData = {
uid: 'test122',
displayName: 'Test User',
title: 'Developer',
bio: 'Hello World'
};

(doc as unknown as Mock).mockReturnValue({} as DocumentReference);
(getDoc as unknown as Mock).mockResolvedValue({
exists: () => true,
data: () => mockUserData
} as unknown as DocumentSnapshot);

const user = await getUser('test123');
expect(user).toEqual(mockUserData);
});

it('當使用者不存在時應該返回預設資料', async () => {
const uid = 'nonexistent123';
(doc as unknown as Mock).mockReturnValue({} as DocumentReference);
(getDoc as unknown as Mock).mockResolvedValue({
exists: () => false,
data: () => null
} as unknown as DocumentSnapshot);

const user = await getUser(uid);
expect(user).toEqual({
uid,
displayName: uid,
title: null,
bio: null
});
});

it('應該快取使用者資料', async () => {
const mockUserData = {
uid: 'test122',
displayName: 'Test User',
title: 'Developer',
bio: 'Hello World'
};

(doc as unknown as Mock).mockReturnValue({} as DocumentReference);
(getDoc as unknown as Mock).mockResolvedValue({
exists: () => true,
data: () => mockUserData
} as unknown as DocumentSnapshot);

// 第一次呼叫
await getUser('test122');
// 第二次呼叫
await getUser('test122');

// 應該只呼叫一次 getDoc
expect(getDoc).toHaveBeenCalledTimes(1);
});
});

0 comments on commit 43ff8c7

Please sign in to comment.