tests: add Playwright event badge CRUD + interaction tests; add minimal V3 mocks and env helper; update presenter/badge smoke tests to use helpers; convert test locals to snake_case

This commit is contained in:
Scott Idem
2026-02-24 17:49:43 -05:00
parent 39614c9cc2
commit 197adff33b
10 changed files with 439 additions and 120 deletions

View File

@@ -0,0 +1,97 @@
import { describe, it, expect, vi } from 'vitest';
// Use hoist-safe factories for vi.mock
vi.mock('$lib/api/api', () => ({
api: {
create_nested_obj_v3: vi.fn(),
update_nested_obj_v3: vi.fn(),
delete_nested_ae_obj_v3: vi.fn(),
search_ae_obj_v3: vi.fn()
}
}));
vi.mock('$lib/ae_core/core__idb_dexie', () => ({ db_save_ae_obj_li__ae_obj: vi.fn() }));
vi.mock('$lib/ae_events/db_events', () => ({ db_events: { badge: { get: vi.fn(), delete: vi.fn() } } }));
vi.mock('$lib/ae_events/ae_events__event_badge_template', () => ({ load_ae_obj_id__event_badge_template: vi.fn() }));
import { create_ae_obj__event_badge } from './ae_events__event_badge';
describe('create_ae_obj__event_badge', () => {
it('calls api.create_nested_obj_v3 with the correct params and returns the result', async () => {
const mocked = await import('$lib/api/api');
const mockCreateNested = mocked.api.create_nested_obj_v3 as jest.MockedFunction<any>;
const fakeResult = { event_badge_id: 'eb123', full_name: 'Test User' };
mockCreateNested.mockResolvedValue(fakeResult);
const api_cfg = { base_url: 'http://localhost', headers: {} };
const event_id = 'evt1';
const data_kv = { full_name_override: 'Test User', email: 't@example.com' };
const result = await create_ae_obj__event_badge({ api_cfg, event_id, data_kv, try_cache: false });
expect(mockCreateNested).toHaveBeenCalled();
const calledWith = mockCreateNested.mock.calls[0][0];
expect(calledWith.parent_type).toBe('event');
expect(calledWith.parent_id).toBe(event_id);
expect(calledWith.child_type).toBe('event_badge');
expect(calledWith.fields).toEqual(data_kv);
expect(result).toEqual(fakeResult);
});
});
describe('update_ae_obj__event_badge', () => {
it('calls api.update_nested_obj_v3 with correct params and returns result', async () => {
const mocked = await import('$lib/api/api');
const mockUpdate = mocked.api.update_nested_obj_v3 as jest.MockedFunction<any>;
const fakeResult = { event_badge_id: 'eb999', full_name: 'Updated' };
mockUpdate.mockResolvedValue(fakeResult);
const { update_ae_obj__event_badge } = await import('./ae_events__event_badge');
const api_cfg = { base_url: 'http://localhost', headers: {} };
const res = await update_ae_obj__event_badge({ api_cfg, event_id: 'evt1', event_badge_id: 'eb999', data_kv: { full_name_override: 'Updated' }, try_cache: false });
expect(mockUpdate).toHaveBeenCalled();
const called = mockUpdate.mock.calls[0][0];
expect(called.child_id).toBe('eb999');
expect(called.fields).toEqual({ full_name_override: 'Updated' });
expect(res).toEqual(fakeResult);
});
});
describe('delete_ae_obj_id__event_badge', () => {
it('calls api.delete_nested_ae_obj_v3 and deletes from local DB when try_cache true', async () => {
const mocked = await import('$lib/api/api');
const mockDelete = mocked.api.delete_nested_ae_obj_v3 as jest.MockedFunction<any>;
mockDelete.mockResolvedValue({ success: true });
const db = await import('$lib/ae_events/db_events');
const dbDelete = db.db_events.badge.delete as jest.MockedFunction<any>;
const { delete_ae_obj_id__event_badge } = await import('./ae_events__event_badge');
const api_cfg = { base_url: 'http://localhost', headers: {} };
const res = await delete_ae_obj_id__event_badge({ api_cfg, event_id: 'evt1', event_badge_id: 'ebDel', try_cache: true });
expect(mockDelete).toHaveBeenCalled();
expect(dbDelete).toHaveBeenCalledWith('ebDel');
expect(res).toEqual({ success: true });
});
});
describe('search__event_badge', () => {
it('calls api.search_ae_obj_v3 and returns list (handles data envelope)', async () => {
const mocked = await import('$lib/api/api');
const mockSearch = mocked.api.search_ae_obj_v3 as jest.MockedFunction<any>;
const fakeList = [{ event_badge_id: 'eb1' }, { event_badge_id: 'eb2' }];
mockSearch.mockResolvedValue({ data: fakeList });
const { search__event_badge } = await import('./ae_events__event_badge');
const api_cfg = { base_url: 'http://localhost', headers: {} };
const res = await search__event_badge({ api_cfg, event_id: 'evt1', fulltext_search_qry_str: 'Test', try_cache: false });
expect(mockSearch).toHaveBeenCalled();
expect(Array.isArray(res)).toBe(true);
expect((res as any).length).toBe(2);
});
});

View File

@@ -9,46 +9,6 @@
let { data, children, log_lvl = 0 }: Props = $props();
// *** Import Svelte specific
// import { liveQuery } from 'dexie';
// import type { key_val } from '$lib/stores/ae_stores';
// import { ae_util } from '$lib/ae_utils/ae_utils';
// import { core_func } from '$lib/ae_core_functions';
// import { db_events } from '$lib/ae_events/db_events';
// import {
// ae_snip,
// ae_loc,
// ae_sess,
// ae_api,
// ae_trig,
// slct,
// slct_trigger
// } from '$lib/stores/ae_stores';
// import {
// events_loc,
// events_sess,
// events_slct,
// events_trigger
// } from '$lib/stores/ae_events_stores';
// import { events_func } from '$lib/ae_events_functions';
// let lq__event_obj = $derived(
// liveQuery(async () => {
// if (log_lvl) {
// console.log(
// `*** LiveQuery: lq__event_obj *** event_id=${$events_slct.event_id}`
// );
// }
// let results = await db_events.event.get(
// $events_slct?.event_id ?? ''
// );
// return results;
// })
// );
// let nav_y_height = $state(0);
let box: any;
let xLeft = $state(0);
@@ -73,10 +33,6 @@
}
// *** Functions and Logic
// $effect(() => {
// // if ($events_trigger == 'load__event_badge_obj_li' && $events_slct.event_id) {
// // }
// });
</script>
<!-- <svelte:head>
@@ -92,6 +48,5 @@
</svelte:head> -->
<!-- - Badges - {$events_loc?.title} -->
<!-- +layout: Where is here??? -->
{@render children?.()}

View File

@@ -55,3 +55,11 @@ git commit -m "test: add <description>"
Help
- If a test fails due to external network calls or platform-specific behavior, try mocking the relevant endpoints and move the test to `tests/disabled` if it cannot be made deterministic.
Development / Testing / Demo environment information
Use snake_case (or Snake_Case or Snake_case or test_NASA_example or test_API_key)
Aether test/demo base URL: 'http://demo.localhost:5173'
Aether development API: 'https://dev-api.oneskyit.com'
Aether test/demo account: '_XY7DXtc9MY' (1) "One Sky IT Demo"
Aether test/demo event: 'pjrcghqwert' (1) "Demo One Sky IT Conference"

17
tests/_helpers/env.ts Normal file
View File

@@ -0,0 +1,17 @@
/**
* Centralized test environment constants for Playwright and unit tests.
* Use snake_case names per project preference.
*/
export const test_base_url = 'http://demo.localhost:5173';
export const dev_api_base = 'https://dev-api.oneskyit.com';
export const demo_account_id = '_XY7DXtc9MY';
export const demo_event_id = 'pjrcghqwert';
export const TEST_ENV = {
test_base_url,
dev_api_base,
demo_account_id,
demo_event_id
};
export default TEST_ENV;

View File

@@ -0,0 +1,73 @@
import { Page } from '@playwright/test';
export const minimal_event = (event_id: string) => ({
data: {
id: event_id,
event_id: event_id,
name: 'Test Event (minimal)',
cfg_json: {},
mod_pres_mgmt_json: {},
mod_badges_json: {},
mod_abstracts_json: {},
mod_exhibits_json: {},
mod_meetings_json: {},
},
});
export const minimal_badge = (overrides: Record<string, any> = {}) => ({
event_badge_id: 'badge-1',
full_name_override: 'Test User',
email: 'test@example.com',
badge_type: 'test',
...overrides,
});
/**
* Attach minimal V3 route handlers to a Playwright `page`.
* - Responds to event GET, badge search/create/update/delete, and a simple site_domain/search.
* - Keeps created badge state in-memory for the page session.
*/
export async function attach_minimal_v3_routes(page: Page, event_id: string) {
let created_badge: any = null;
await page.route('**/v3/**', async (route) => {
const req = route.request();
const url = req.url();
const method = req.method();
if (url.includes('site_domain/search')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [{ id: 'td', site_id: 'ts' }] }) });
}
if (url.includes(`/v3/crud/event/${event_id}`) && method === 'GET') {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(minimal_event(event_id)) });
}
if (url.includes(`/v3/crud/event/${event_id}/event_badge/search`) && method === 'POST') {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: created_badge ? [created_badge] : [] }) });
}
if (url.includes(`/v3/crud/event/${event_id}/event_badge`) && method === 'POST') {
const post = await req.postData();
const body = post ? JSON.parse(post) : {};
created_badge = { ...minimal_badge(body) };
return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify({ data: created_badge }) });
}
if (url.match(new RegExp(`/v3/crud/event/${event_id}/event_badge/.+`)) && (method === 'PATCH' || method === 'PUT')) {
const post = await req.postData();
const body = post ? JSON.parse(post) : {};
if (created_badge) created_badge = { ...created_badge, ...body };
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: created_badge }) });
}
if (url.match(new RegExp(`/v3/crud/event/${event_id}/event_badge/.+`)) && method === 'DELETE') {
created_badge = null;
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: true }) });
}
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
});
}
export default { minimal_event, minimal_badge, attach_minimal_v3_routes };

View File

@@ -1,5 +1,9 @@
import { test, expect } from '@playwright/test';
import { ae_app_local_data_defaults } from './_helpers/ae_defaults';
import { demo_event_id, demo_account_id } from './_helpers/env';
import { attach_minimal_v3_routes } from './_helpers/minimal_v3_mocks';
const demo_event = demo_event_id;
test.describe('Event Badge Page - smoke', () => {
test.beforeEach(async ({ page }) => {
@@ -8,25 +12,20 @@ test.describe('Event Badge Page - smoke', () => {
if (msg.type() === 'error' || msg.type() === 'warn') console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`);
});
await page.route('**/*oneskyit.com/**', async (route) => {
const url = route.request().url();
if (url.includes('site_domain/search')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [{ id: 'td', site_id: 'ts' }] }) });
}
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
});
await attach_minimal_v3_routes(page, demo_event);
await page.addInitScript((defaults) => {
const testData = { ...defaults, account_id: 'smoke-account', manager_access: true };
window.localStorage.setItem('ae_loc', JSON.stringify(testData));
}, ae_app_local_data_defaults);
await page.addInitScript((defaults, event_id, account_id) => {
const test_data = { ...defaults, account_id: account_id, manager_access: true };
test_data.mod = { ...defaults.mod, events: { ...defaults.mod.events, event_id } };
window.localStorage.setItem('ae_loc', JSON.stringify(test_data));
}, ae_app_local_data_defaults, demo_event, demo_account_id);
});
test('loads badges list without console errors', async ({ page }) => {
const errors: string[] = [];
page.on('pageerror', (err) => errors.push(err.message));
await page.goto('/events/test-event/badges');
await page.goto(`/events/${demo_event}/badges`);
await page.waitForResponse((r) => r.url().includes('site_domain/search') && r.status() === 200);
expect(errors).toHaveLength(0);

View File

@@ -0,0 +1,136 @@
import { test, expect } from '@playwright/test';
import { ae_app_local_data_defaults } from './_helpers/ae_defaults';
import { demo_event_id, demo_account_id } from './_helpers/env';
const test_event_id = demo_event_id;
test.describe('event_badge_crud (create, find, edit, delete)', () => {
test.beforeEach(async ({ page }) => {
page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`));
page.on('console', (msg) => {
if (msg.type() === 'error' || msg.type() === 'warn')
console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`);
});
// Minimal in-test state for created badge
let created_badge: any = null;
await page.route('**/v3/**', async (route) => {
const req = route.request();
const url = req.url();
const method = req.method();
if (url.includes('site_domain/search')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [{ id: 'td', site_id: 'ts' }] }) });
}
// Minimal event GET payload (include cfg_json and mod_* for bindings)
if (url.includes(`/v3/crud/event/${test_event_id}`) && method === 'GET') {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ data: { id: test_event_id, event_id: test_event_id, name: 'Test Event for Badge CRUD', cfg_json: {}, mod_pres_mgmt_json: {}, mod_badges_json: {}, mod_abstracts_json: {}, mod_exhibits_json: {}, mod_meetings_json: {} } })
});
}
// Search/list badges
if (url.includes(`/v3/crud/event/${test_event_id}/event_badge/search`) && method === 'POST') {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: created_badge ? [created_badge] : [] }) });
}
// Create badge - return created envelope with fixed id
if (url.includes(`/v3/crud/event/${test_event_id}/event_badge`) && method === 'POST') {
const post = await req.postData();
const body = post ? JSON.parse(post) : {};
created_badge = { ...body, event_badge_id: 'badge-1' };
return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify({ data: created_badge }) });
}
// Update badge
if (url.match(new RegExp(`/v3/crud/event/${test_event_id}/event_badge/.+`)) && (method === 'PATCH' || method === 'PUT')) {
const post = await req.postData();
const body = post ? JSON.parse(post) : {};
if (created_badge) created_badge = { ...created_badge, ...body };
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: created_badge }) });
}
// Delete badge
if (url.match(new RegExp(`/v3/crud/event/${test_event_id}/event_badge/.+`)) && method === 'DELETE') {
created_badge = null;
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: true }) });
}
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
});
page.on('dialog', async (dialog) => { await dialog.accept(); });
await page.addInitScript(({ defaults, eventId, accountId }) => {
const test_data = { ...defaults, account_id: accountId, manager_access: true, administrator_access: true, edit_mode: true, mod: { ...defaults.mod, events: { ...defaults.mod.events, event_id: eventId } } };
window.localStorage.setItem('ae_loc', JSON.stringify(test_data));
}, { defaults: ae_app_local_data_defaults, eventId: test_event_id, accountId: demo_account_id });
});
test('create -> find -> edit -> delete badge', async ({ page }) => {
// Create via Settings modal UI
await page.goto(`/events/${test_event_id}/settings`);
const add_btn = page.getByRole('button', { name: 'Add New Badge' });
await expect(add_btn).toBeVisible();
await add_btn.click();
const form = page.locator('form:has-text("Create Badge")');
await expect(form).toBeVisible();
await form.locator('label:has-text("Full Name Override") input').fill('CRUD User');
await form.locator('label:has-text("Email") input').fill('crud@example.com');
await form.locator('label:has-text("Badge Type") select').selectOption('test');
// Wait for POST create request and response
const [create_req, create_resp] = await Promise.all([
page.waitForRequest((r) => r.url().includes(`/v3/crud/event/${test_event_id}/event_badge`) && r.method() === 'POST'),
page.waitForResponse((r) => r.url().includes(`/v3/crud/event/${test_event_id}/event_badge`) && (r.status() === 201 || r.status() === 200)),
page.getByRole('button', { name: 'Create Badge' }).click()
]);
const post_body = create_req.postData();
const post_json = post_body ? JSON.parse(post_body) : {};
expect(post_json.email).toBe('crud@example.com');
const created = await create_resp.json();
expect(created.data).toBeDefined();
const badge_id = created.data.event_badge_id || created.data.id || 'badge-1';
// Find badges via search endpoint (simulate listing page) using in-page fetch
await page.goto(`/events/${test_event_id}/badges`);
const search_json = await page.evaluate(async (eventId) => {
const r = await fetch(`/v3/crud/event/${eventId}/event_badge/search`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) });
return await r.json();
}, test_event_id);
expect(Array.isArray(search_json.data)).toBeTruthy();
expect(search_json.data.length).toBeGreaterThanOrEqual(1);
// Edit badge via browser fetch (exercise nested update)
const edit_resp = await page.evaluate(async (args) => {
const { eventId, badgeId } = args;
const r = await fetch(`/v3/crud/event/${eventId}/event_badge/${badgeId}/`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ full_name_override: 'Edited User' }) });
return { status: r.status, json: await r.json() };
}, { eventId: test_event_id, badgeId: badge_id });
expect(edit_resp.status === 200).toBeTruthy();
expect(edit_resp.json.data.full_name_override).toBe('Edited User');
// Delete badge via browser fetch
const del_resp = await page.evaluate(async (args) => {
const { eventId, badgeId } = args;
const r = await fetch(`/v3/crud/event/${eventId}/event_badge/${badgeId}/`, { method: 'DELETE' });
return { status: r.status, ok: r.ok };
}, { eventId: test_event_id, badgeId: badge_id });
expect(del_resp.ok).toBeTruthy();
// Confirm search returns no items
const post_delete_json = await page.evaluate(async (eventId) => {
const r = await fetch(`/v3/crud/event/${eventId}/event_badge/search`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) });
return await r.json();
}, test_event_id);
expect(Array.isArray(post_delete_json.data)).toBeTruthy();
expect(post_delete_json.data.length).toBe(0);
});
});

View File

@@ -1,7 +1,8 @@
import { test, expect } from '@playwright/test';
import { ae_app_local_data_defaults } from './_helpers/ae_defaults';
import { demo_event_id, demo_account_id } from './_helpers/env';
const testEventId = 'pjrcghqwert';
const demo_event = demo_event_id;
test.describe('Event Badge - interaction', () => {
test.beforeEach(async ({ page }) => {
@@ -11,25 +12,19 @@ test.describe('Event Badge - interaction', () => {
console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`);
});
// Minimal network mock: fulfill only what's necessary for the UI to render
await page.route('**/v3/**', async (route) => {
const req = route.request();
const url = req.url();
if (url.includes('site_domain/search')) {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ data: [{ id: 'test-site-domain-id', site_id: 'test-site-id', account_id: '_XY7DXtc9MY' }] })
});
}
if (url.includes(`/v3/crud/event/${testEventId}`) && req.method() === 'GET') {
// Provide the minimal event payload for the settings page to render
if (url.includes(`/v3/crud/event/${demo_event}`) && req.method() === 'GET') {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ data: {
id: testEventId,
event_id: testEventId,
id: demo_event,
event_id: demo_event,
name: 'Test Event for Badge Interaction',
cfg_json: {},
mod_pres_mgmt_json: {},
@@ -41,14 +36,12 @@ test.describe('Event Badge - interaction', () => {
});
}
if (url.includes(`/v3/crud/event/${testEventId}/event_badge`) && req.method() === 'POST') {
const post = await req.postData();
console.log('Captured POST to event_badge endpoint:', url, post ? post.slice(0,200) : '');
const body = post ? JSON.parse(post) : {};
const created = { ...body, event_badge_id: 'new-badge-1' };
return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify({ data: created }) });
// For badge create requests, return a simple created envelope with a fixed id.
if (url.includes(`/v3/crud/event/${demo_event}/event_badge`) && req.method() === 'POST') {
return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify({ data: { event_badge_id: 'new-badge-1' } }) });
}
// Default: empty envelope so other calls don't error
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
});
@@ -57,58 +50,60 @@ test.describe('Event Badge - interaction', () => {
});
await page.addInitScript(
({ defaults, eventId }) => {
({ defaults, event_id, account_id }) => {
const testData = {
...defaults,
account_id: '_XY7DXtc9MY',
account_id: account_id,
manager_access: true,
administrator_access: true,
edit_mode: true,
mod: { ...defaults.mod, events: { ...defaults.mod.events, event_id: eventId } }
mod: { ...defaults.mod, events: { ...defaults.mod.events, event_id: event_id } }
};
window.localStorage.setItem('ae_loc', JSON.stringify(testData));
},
{ defaults: ae_app_local_data_defaults, eventId: testEventId }
{ defaults: ae_app_local_data_defaults, event_id: demo_event, account_id: demo_account_id }
);
});
test('creates a badge via UI and posts to nested endpoint', async ({ page }) => {
await page.goto(`/events/${testEventId}/settings`);
await page.goto(`/events/${demo_event}/settings`);
const addBtn = page.getByRole('button', { name: 'Add New Badge' });
await expect(addBtn).toBeVisible();
await addBtn.click();
const add_btn = page.getByRole('button', { name: 'Add New Badge' });
await expect(add_btn).toBeVisible();
await add_btn.click();
const form = page.locator('form:has-text("Create Badge")');
await expect(form).toBeVisible();
const fullNameInput = form.locator('label:has-text("Full Name Override") input');
await expect(fullNameInput).toBeVisible();
await fullNameInput.fill('Test User');
const full_name_input = form.locator('label:has-text("Full Name Override") input');
await expect(full_name_input).toBeVisible();
await full_name_input.fill('Test User');
const emailInput = form.locator('label:has-text("Email") input');
await emailInput.fill('testuser@example.com');
const email_input = form.locator('label:has-text("Email") input');
await email_input.fill('testuser@example.com');
const select = form.locator('label:has-text("Badge Type") select');
await select.selectOption('test');
const badge_type_select = form.locator('label:has-text("Badge Type") select');
await badge_type_select.selectOption('test');
const checkbox = form.locator('label:has-text("Allow Tracking") input[type="checkbox"]');
await checkbox.check();
const allow_tracking_checkbox = form.locator('label:has-text("Allow Tracking") input[type="checkbox"]');
await allow_tracking_checkbox.check();
const [request] = await Promise.all([
page.waitForRequest((r) => r.url().includes(`/v3/crud/event/${testEventId}/event_badge`) && r.method() === 'POST'),
page.getByRole('button', { name: 'Create Badge' }).click()
]);
const [create_request] = await Promise.all([
page.waitForRequest((r) => r.url().includes(`/v3/crud/event/${demo_event}/event_badge`) && r.method() === 'POST'),
page.getByRole('button', { name: 'Create Badge' }).click()
]);
const postBody = request.postData();
const postJson = postBody ? JSON.parse(postBody) : {};
expect(postJson.email).toBe('testuser@example.com');
expect(postJson.full_name_override).toBe('Test User');
const post_body = create_request.postData();
const post_json = post_body ? JSON.parse(post_body) : {};
expect(post_json.email).toBe('testuser@example.com');
expect(post_json.full_name_override).toBe('Test User');
const response = await page.waitForResponse((r) => r.url().includes(`/v3/crud/event/${testEventId}/event_badge`) && (r.status() === 201 || r.status() === 200));
const respJson = await response.json();
expect(respJson).toBeDefined();
expect(respJson.data).toBeDefined();
expect(respJson.data.event_badge_id).toBe('new-badge-1');
// Use the request's response for reliability (page.request bypasses page.route otherwise)
const response = await create_request.response();
expect(response).not.toBeNull();
const resp_json = response ? await response.json() : {};
expect(resp_json).toBeDefined();
expect(resp_json.data).toBeDefined();
expect(resp_json.data.event_badge_id).toBe('new-badge-1');
});
});

View File

@@ -1,5 +1,9 @@
import { test, expect } from '@playwright/test';
import { ae_app_local_data_defaults } from './_helpers/ae_defaults';
import { demo_event_id, demo_account_id } from './_helpers/env';
import { attach_minimal_v3_routes } from './_helpers/minimal_v3_mocks';
const demo_event = demo_event_id;
test.describe('Event Presenter Page - smoke', () => {
test.beforeEach(async ({ page }) => {
@@ -8,28 +12,21 @@ test.describe('Event Presenter Page - smoke', () => {
if (msg.type() === 'error' || msg.type() === 'warn') console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`);
});
await page.route('**/*oneskyit.com/**', async (route) => {
const url = route.request().url();
if (url.includes('site_domain/search')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [{ id: 'td', site_id: 'ts' }] }) });
}
if (url.includes('/v3/crud/event/')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: { id: 'test-event', name: 'Test' } }) });
}
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
});
await attach_minimal_v3_routes(page, demo_event);
await page.addInitScript((defaults) => {
const testData = { ...defaults, account_id: 'smoke-account', manager_access: true };
window.localStorage.setItem('ae_loc', JSON.stringify(testData));
}, ae_app_local_data_defaults);
await page.addInitScript((defaults, event_id, account_id) => {
const test_data = { ...defaults, account_id: account_id, manager_access: true };
// ensure the events module has the event id available
test_data.mod = { ...defaults.mod, events: { ...defaults.mod.events, event_id } };
window.localStorage.setItem('ae_loc', JSON.stringify(test_data));
}, ae_app_local_data_defaults, demo_event, demo_account_id);
});
test('opens presenter editor without throwing', async ({ page }) => {
const errors: string[] = [];
page.on('pageerror', (e) => errors.push(e.message));
await page.goto('/events/test-event/presenters');
await page.goto(`/events/${demo_event}/presenters`);
await page.waitForResponse((r) => r.url().includes('site_domain/search') && r.status() === 200);
expect(errors).toHaveLength(0);

View File

@@ -0,0 +1,42 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Aether test/demo base URL: 'http://demo.localhost:5173'
// Aether development API: 'https://dev-api.oneskyit.com'
// Aether test/demo account: '_XY7DXtc9MY' (1) "One Sky IT Demo"
// Aether test/demo event: 'pjrcghqwert' (1) "Demo One Sky IT Conference"
// Mock the api module used by the ae_events file
const mockCreateNested = vi.fn();
vi.mock('$lib/api/api', () => ({ api: { create_nested_obj_v3: mockCreateNested } }));
// Avoid touching IndexedDB caching in this unit test
vi.mock('$lib/ae_core/core__idb_dexie', () => ({ db_save_ae_obj_li__ae_obj: vi.fn() }));
// Import the function under test after mocks
import { create_ae_obj__event_badge } from '../../../src/lib/ae_events/ae_events__event_badge';
describe('create_ae_obj__event_badge', () => {
beforeEach(() => {
mockCreateNested.mockReset();
});
it('calls api.create_nested_obj_v3 with the correct params and returns the result', async () => {
const fakeResult = { event_badge_id: 'eb123', full_name: 'Test User' };
mockCreateNested.mockResolvedValue(fakeResult);
const api_cfg = { base_url: 'http://localhost', headers: {} };
const event_id = 'evt1';
const data_kv = { full_name_override: 'Test User', email: 't@example.com' };
const result = await create_ae_obj__event_badge({ api_cfg, event_id, data_kv, try_cache: false });
expect(mockCreateNested).toHaveBeenCalled();
const calledWith = mockCreateNested.mock.calls[0][0];
expect(calledWith.parent_type).toBe('event');
expect(calledWith.parent_id).toBe(event_id);
expect(calledWith.child_type).toBe('event_badge');
expect(calledWith.fields).toEqual(data_kv);
expect(result).toEqual(fakeResult);
});
});