Files
OSIT-AE-App-Svelte/tests/event_badge_attendee_workflow.test.ts
2026-03-24 11:15:01 -04:00

133 lines
6.0 KiB
TypeScript

/**
* Badge Print Page — Attendee Print Workflow Tests
*
* Verifies the real staff-facing print workflow:
* Badge list → click badge → /print page renders → Print Badge button → PATCH → navigate back
*
* There is no separate "badge detail" page. From the badge list, clicking a badge
* goes directly to /events/{event_id}/badges/{badge_id}/print.
*
* Strategy: inject badge + template into IDB (same pattern as event_badge_print_layout.test.ts),
* then interact with the print page controls.
*/
import { test, expect } from '@playwright/test';
import { testing_event_id } from './_helpers/env';
import { inject_badge_and_template } from './_helpers/idb_helpers';
import { setup_badge_test_page } from './_helpers/minimal_ae_api_mocks';
const event_id = testing_event_id;
const badge_id = 'UIJT-73-63-61';
const template_id = 'jgfixEpYp1B';
const mock_badge = {
id: badge_id,
event_badge_id: badge_id,
event_badge_id_random: badge_id, // NO LONGER USE "_random"
event_id: event_id,
event_id_random: event_id,
event_badge_template_id: template_id,
event_badge_template_id_random: template_id, // NO LONGER USE "_random"
full_name_override: 'Scott Idem',
given_name: 'Scott',
family_name: 'Idem',
email: 'scott@example.com',
badge_type: 'presenter',
badge_type_code: 'presenter',
print_count: 0,
affiliations: 'One Sky IT',
location: 'Minneapolis, MN',
enable: true,
};
const mock_template = {
id: template_id,
id_random: template_id, // NO LONGER USE "_random"
event_badge_template_id: template_id,
badge_template_id: template_id,
event_id: event_id,
event_id_random: event_id,
name: 'Dev Demo 202x',
layout: 'badge_3.5x5.5_pvc',
cfg_json: '{}',
duplex: 1,
enable: true,
};
test.describe('Badge Print Page — attendee print workflow', () => {
test.beforeEach(async ({ page }) => {
await setup_badge_test_page(page, event_id);
// attach_minimal_routes (inside setup_badge_test_page) already handles
// badge PATCH — returns { data: null } but tests only inspect the request body.
});
test('print page renders badge name from IDB', async ({ page }) => {
await page.goto(`/events/${event_id}/badges/${badge_id}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge: mock_badge, template: mock_template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
// Badge header should display the attendee name
const name_text = await page.locator('.full_name_override').textContent();
expect(name_text?.trim()).toBe('Scott Idem');
// Print button should be visible (trusted user, print_count=0)
await expect(page.locator('[data-testid="badge-print-btn"]')).toBeVisible({ timeout: 5000 });
});
test('print button sends PATCH with incremented print_count', async ({ page }) => {
await page.goto(`/events/${event_id}/badges/${badge_id}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge: mock_badge, template: mock_template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
await page.waitForSelector('[data-testid="badge-print-btn"]', { timeout: 5000 });
const patch_promise = page.waitForRequest(
(r) => r.url().includes(`event_badge/${badge_id}`) &&
(r.method() === 'PATCH' || r.method() === 'PUT'),
{ timeout: 10000 }
);
await page.locator('[data-testid="badge-print-btn"]').click();
const patch_req = await patch_promise;
const body = JSON.parse(patch_req.postData() ?? '{}');
expect(body.print_count, 'print_count should increment to 1').toBe(1);
expect(body.print_last_datetime, 'print_last_datetime should be set').toBeDefined();
expect(body.print_first_datetime,'print_first_datetime set on first print').toBeDefined();
});
test('print button navigates back to badge search after printing', async ({ page }) => {
await page.goto(`/events/${event_id}/badges/${badge_id}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge: mock_badge, template: mock_template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
await page.waitForSelector('[data-testid="badge-print-btn"]', { timeout: 5000 });
await page.locator('[data-testid="badge-print-btn"]').click();
// handle_print_badge waits ~1s after PATCH then does window.location.href = /badges
await expect(page).toHaveURL(new RegExp(`/events/${event_id}/badges$`), { timeout: 8000 });
await expect(page.locator('#badge_fulltext_search_qry_str')).toBeVisible({ timeout: 5000 });
});
test.skip('future: attendee self-review via email link', () => {
/*
* Attendee receives an email link to /events/{event_id}/badges/{badge_id}/review.
* They can view and edit their own name, title, affiliations, location.
* Token is time-limited and single-use.
* Not yet implemented — review page exists but email dispatch does not.
*/
});
});