135 lines
4.3 KiB
TypeScript
135 lines
4.3 KiB
TypeScript
import { expect } from '@playwright/test';
|
|
import { test } from './helpers/fixtures';
|
|
import { mock } from './helpers/mock';
|
|
|
|
// ─── Staff scanner ────────────────────────────────────────────────────────────
|
|
|
|
test('Lv10 user is blocked from /checkin with 403', async ({ page, loggedInUser }) => {
|
|
void loggedInUser;
|
|
await page.goto('/app/checkin');
|
|
await page.waitForLoadState('networkidle');
|
|
await expect(page.getByText('权限不足')).toBeVisible();
|
|
});
|
|
|
|
test('staff scanner: valid code shows success alert', async ({ page, staffUser }) => {
|
|
void staffUser;
|
|
await mock.override('POST', '/event/checkin/submit', {
|
|
status: 200,
|
|
body: { status: 200, data: {} }
|
|
});
|
|
|
|
await page.goto('/app/checkin');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Fill OTP boxes — 6 individual inputs
|
|
const boxes = page.locator('[data-otp-input] input');
|
|
const digits = ['4', '8', '3', '9', '1', '7'];
|
|
for (let i = 0; i < 6; i++) {
|
|
await boxes.nth(i).fill(digits[i]);
|
|
}
|
|
|
|
// Last digit fill auto-submits; wait for success alert
|
|
await expect(page.getByText('签到成功')).toBeVisible({ timeout: 5000 });
|
|
});
|
|
|
|
test('staff scanner: backend error shows error alert', async ({ page, staffUser }) => {
|
|
void staffUser;
|
|
await mock.override('POST', '/event/checkin/submit', {
|
|
status: 400,
|
|
body: { status: 400, msg: '签到码无效或已过期' }
|
|
});
|
|
|
|
await page.goto('/app/checkin');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const boxes = page.locator('[data-otp-input] input');
|
|
for (let i = 0; i < 6; i++) await boxes.nth(i).fill('0');
|
|
|
|
await expect(page.getByText('签到码无效或已过期')).toBeVisible({ timeout: 5000 });
|
|
});
|
|
|
|
// ─── Attendee QR dialog ───────────────────────────────────────────────────────
|
|
|
|
const mockEventBody = (overrides: Record<string, unknown> = {}) => ({
|
|
status: 200,
|
|
data: {
|
|
event_id: 'evt1',
|
|
name: 'Test Event',
|
|
subtitle: '',
|
|
type: 'official',
|
|
start_time: new Date(Date.now() - 3600_000).toISOString(),
|
|
end_time: new Date(Date.now() + 3600_000).toISOString(),
|
|
enable_kyc: false,
|
|
is_joined: true,
|
|
is_checked_in: false,
|
|
is_agenda_published: false,
|
|
...overrides
|
|
}
|
|
});
|
|
|
|
test('attendee QR dialog shows code and QR image', async ({ page, loggedInUser }) => {
|
|
void loggedInUser;
|
|
await mock.override('GET', '/event/checkin', {
|
|
status: 200,
|
|
body: { status: 200, data: { checkin_code: '483917' } }
|
|
});
|
|
await mock.override('GET', '/event/checkin/query', {
|
|
status: 200,
|
|
body: { status: 200, data: { checkin_at: null } }
|
|
});
|
|
await mock.override('GET', '/event/info', {
|
|
status: 200,
|
|
body: mockEventBody()
|
|
});
|
|
|
|
await page.goto('/app/events/evt1');
|
|
await page.waitForLoadState('networkidle');
|
|
await page.getByRole('button', { name: '签到' }).click();
|
|
|
|
await expect(page.getByText('483917')).toBeVisible({ timeout: 5000 });
|
|
await expect(page.locator('img[alt="checkin-qr"]')).toBeVisible();
|
|
});
|
|
|
|
test('attendee QR dialog shows success when poll detects check-in', async ({
|
|
page,
|
|
loggedInUser
|
|
}) => {
|
|
void loggedInUser;
|
|
await mock.override('GET', '/event/checkin', {
|
|
status: 200,
|
|
body: { status: 200, data: { checkin_code: '111111' } }
|
|
});
|
|
await mock.override('GET', '/event/checkin/query', {
|
|
status: 200,
|
|
body: { status: 200, data: { checkin_at: '2026-04-16T12:00:00Z' } }
|
|
});
|
|
await mock.override('GET', '/event/info', {
|
|
status: 200,
|
|
body: mockEventBody()
|
|
});
|
|
|
|
await page.goto('/app/events/evt1');
|
|
await page.waitForLoadState('networkidle');
|
|
await page.getByRole('button', { name: '签到' }).click();
|
|
|
|
await expect(page.getByText('签到成功')).toBeVisible({ timeout: 6000 });
|
|
});
|
|
|
|
test('attendee QR dialog shows error when code fetch fails', async ({ page, loggedInUser }) => {
|
|
void loggedInUser;
|
|
await mock.override('GET', '/event/checkin', {
|
|
status: 500,
|
|
body: { status: 500, msg: '服务器错误' }
|
|
});
|
|
await mock.override('GET', '/event/info', {
|
|
status: 200,
|
|
body: mockEventBody()
|
|
});
|
|
|
|
await page.goto('/app/events/evt1');
|
|
await page.waitForLoadState('networkidle');
|
|
await page.getByRole('button', { name: '签到' }).click();
|
|
|
|
await expect(page.getByText('获取签到码失败')).toBeVisible({ timeout: 5000 });
|
|
});
|