Files
OSIT-AE-App-Svelte/tests/event_badge_render.test.ts
Scott Idem af02e38528 test: badge E2E tests — fix __version wipe, extract idb_helpers, add render + workflow tests
Root cause fix: tests/_helpers/ae_defaults.ts was missing __version: 1, causing
store_versions.ts to wipe ae_loc from localStorage on every test page load. This
made trusted_access fall back to false, hiding the print button (can_print guard)
and failing all attendee workflow tests.

Changes:
- ae_defaults.ts: add __version: 1 with comment explaining the store_versions guard
- idb_helpers.ts: extract inject_badge_and_template() from print layout test into
  shared helper; now used by all three print/render test files
- event_badge_render.test.ts: new — 4 tests covering full_name_override priority,
  full_name fallback, duplex=0 hides badge back, duplex=1 shows badge back
- event_badge_attendee_workflow.test.ts: cleaned up (diagnostic code removed);
  all 3 tests now pass
- event_badge_print_layout.test.ts: renamed from badge_print_layout.test.ts;
  inline inject_idb() replaced with shared idb_helpers import
- event_badge_smoke.test.ts: renamed from event_badge.test.ts
- playwright.config.ts: use system /usr/bin/chromium on Arch Linux (avoids
  Playwright's bundled Chromium which requires Ubuntu libs not present on Arch)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 16:58:55 -04:00

191 lines
8.9 KiB
TypeScript

/**
* Badge Render — Content and Visibility Tests
*
* Verifies badge rendering logic using IDB injection:
* navigate → inject IDB → reload → assert rendered content
*
* These tests protect specific business rules that have caused real bugs:
*
* 1. full_name_override renders in preference to full_name
* The badge displays `full_name_override ?? full_name`. If override priority
* breaks (e.g. wrong field precedence in display_name derived value), the
* wrong name prints on the badge.
*
* 2. full_name renders when no override is set (sanity)
* Confirms the fallback chain works — no override should still show a name.
*
* 3. duplex=0 hides the badge back section
* The Zebra ZC10L PVC workflow uses single-sided cards (duplex=0). If the
* show_badge_back derived value regresses, the back section prints on
* single-sided stock and wastes/jams cards.
*
* 4. duplex=1 (or unset) shows the badge back section
* Standard fanfold badges are two-sided. Confirms the default is duplex-on.
*/
import { test, expect } from '@playwright/test';
import { ae_app_local_data_defaults } from './_helpers/ae_defaults';
import { testing_event_id, testing_account_id, mock_site_domain } from './_helpers/env';
import { inject_badge_and_template } from './_helpers/idb_helpers';
const event_id = testing_event_id;
// Each test uses a distinct badge_id so IDB records from parallel or sequential
// tests don't collide within the same browser context.
const BADGE_OVERRIDE = 'test-render-override-001';
const BADGE_NO_OVERRIDE = 'test-render-no-override-001';
const BADGE_DUPLEX_OFF = 'test-render-duplex-off-001';
const BADGE_DUPLEX_ON = 'test-render-duplex-on-001';
const TMPL_STANDARD = 'test-render-tmpl-standard-001';
const TMPL_DUPLEX_OFF = 'test-render-tmpl-duplex-off-001';
function make_badge(badge_id: string, template_id: string, overrides: Record<string, any> = {}) {
return {
id: badge_id,
event_badge_id: badge_id,
event_badge_id_random: badge_id,
event_id: event_id,
event_id_random: event_id,
event_badge_template_id: template_id,
event_badge_template_id_random: template_id,
full_name: 'Jane Doe',
full_name_override: null,
given_name: 'Jane',
family_name: 'Doe',
email: 'jane@example.com',
badge_type: 'member',
badge_type_code: 'current_member',
print_count: 0,
affiliations: 'Test Org',
location: 'Minneapolis, MN',
enable: true,
...overrides,
};
}
function make_template(template_id: string, overrides: Record<string, any> = {}) {
return {
id: template_id,
id_random: template_id,
event_badge_template_id: template_id,
badge_template_id: template_id,
event_id: event_id,
event_id_random: event_id,
name: 'Test Template',
layout: 'badge_4x5_fanfold',
cfg_json: '{}',
enable: true,
...overrides,
};
}
test.describe('Badge Render — content and visibility', () => {
test.beforeEach(async ({ page }) => {
page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`));
await page.route('**/v3/**', async (route) => {
const url = route.request().url();
const method = route.request().method();
if (url.includes('site_domain/search')) {
return route.fulfill({ status: 200, contentType: 'application/json',
body: JSON.stringify({ data: [mock_site_domain] }) });
}
if (url.includes(`/v3/crud/event/${event_id}`) && !url.includes('event_badge') && method === 'GET') {
return route.fulfill({ status: 200, contentType: 'application/json',
body: JSON.stringify({ data: {
id: event_id, event_id, name: 'Test Event',
cfg_json: {}, mod_badges_json: {}, mod_pres_mgmt_json: {},
mod_abstracts_json: {}, mod_exhibits_json: {}, mod_meetings_json: {},
}}) });
}
return route.fulfill({ status: 200, contentType: 'application/json',
body: JSON.stringify({ data: [] }) });
});
await page.addInitScript(([defaults, e_id, a_id]) => {
const data = {
...defaults,
account_id: a_id,
allow_access: true,
authenticated_access: true,
trusted_access: true,
manager_access: true,
edit_mode: false,
} as any;
data.mod = { ...defaults.mod, events: { ...defaults.mod.events, event_id: e_id } };
window.localStorage.setItem('ae_loc', JSON.stringify(data));
}, [ae_app_local_data_defaults, event_id, testing_account_id] as const);
});
test('full_name_override renders in preference to full_name', async ({ page }) => {
const badge = make_badge(BADGE_OVERRIDE, TMPL_STANDARD, { full_name_override: 'Dr. Jane Override' });
const template = make_template(TMPL_STANDARD);
await page.goto(`/events/${event_id}/badges/${BADGE_OVERRIDE}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge, template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
const name_text = await page.locator('.full_name_override').textContent();
// Override name must be shown — not the base full_name
expect(name_text?.trim()).toBe('Dr. Jane Override');
expect(name_text?.trim()).not.toBe('Jane Doe');
});
test('full_name renders when no override is set', async ({ page }) => {
// full_name_override is null — should fall back to full_name
const badge = make_badge(BADGE_NO_OVERRIDE, TMPL_STANDARD, { full_name: 'Jane Doe', full_name_override: null });
const template = make_template(TMPL_STANDARD);
await page.goto(`/events/${event_id}/badges/${BADGE_NO_OVERRIDE}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge, template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
const name_text = await page.locator('.full_name_override').textContent();
expect(name_text?.trim()).toBe('Jane Doe');
});
test('duplex=0 hides the badge back section (single-sided PVC)', async ({ page }) => {
// duplex=0 → show_badge_back is false → .badge_back must not be in DOM.
// Critical for Zebra ZC10L PVC single-sided cards — if back renders, it
// prints on the card surface and ruins the card stock.
const badge = make_badge(BADGE_DUPLEX_OFF, TMPL_DUPLEX_OFF);
const template = make_template(TMPL_DUPLEX_OFF, { duplex: 0 });
await page.goto(`/events/${event_id}/badges/${BADGE_DUPLEX_OFF}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge, template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
const back_count = await page.locator('.badge_back').count();
expect(back_count, 'badge_back must not be in DOM when duplex=0').toBe(0);
});
test('duplex=1 shows the badge back section (duplex fanfold)', async ({ page }) => {
// duplex=1 (or null) → show_badge_back is true → .badge_back must be present.
const badge = make_badge(BADGE_DUPLEX_ON, TMPL_STANDARD);
const template = make_template(TMPL_STANDARD, { duplex: 1 });
await page.goto(`/events/${event_id}/badges/${BADGE_DUPLEX_ON}/print`);
await page.waitForLoadState('domcontentloaded');
await page.evaluate(inject_badge_and_template, { badge, template });
await page.reload();
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('.event_badge_wrapper', { timeout: 8000 });
const back_count = await page.locator('.badge_back').count();
expect(back_count, 'badge_back must be present when duplex=1').toBeGreaterThan(0);
});
});