Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: qr code show not found exception handling #107

Merged
merged 2 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
});
});
Loading