import { test, expect } from '@playwright/test'; import { ae_app_local_data_defaults } from './_helpers/ae_defaults'; /** * ==================================================================================== * Aether V3 Nested CRUD API Integration Tests * ==================================================================================== * * Purpose: * This test suite verifies that the SvelteKit frontend correctly uses the * nested API endpoints for creating, updating, and deleting child objects. * It builds on the patterns established in `v3_api_security.test.ts`. * * Key Scenarios Verified: * 1. **Nested Create:** Confirms that creating a child object (e.g., an Event Location) * sends a POST request to the correct nested URL (`/v3/crud/:parent_type/:parent_id/:child_type`). * 2. **Nested Update:** Confirms that updating a child object sends a PATCH * request to the correct nested URL. * 3. **Nested Delete:** Confirms that deleting a child object sends a DELETE * request to the correct nested URL. * * Strategy: * - Uses the same API mocking and state injection strategy as the security tests. * - Focuses assertions on the outgoing request's URL, method, and payload to * validate the refactored data-handling logic. */ const testing_event_id = 'pjrcghqwert'; // Per README test data test.describe('V3 API Nested CRUD Integrity', () => { test.setTimeout(7000); test.beforeEach(async ({ page }) => { // Log browser console errors to the terminal page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`)); page.on('console', (msg) => { if (msg.type() === 'error' || msg.type() === 'warning') { console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`); } }); // Mock API requests under /v3/ to isolate test network activity await page.route('**/v3/**', async (route) => { const req = route.request(); const url = req.url(); // Initial handshake mock to allow the app to boot if (url.includes('site_domain/search')) { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [{ id: '_6jcTbnJk-o', site_id: '_6jcTbnJk-o', account_id: '_XY7DXtc9MY' }] }) // Per README test data }); } // Mock the parent event object so the page can load if (url.includes(`/v3/crud/event/${testing_event_id}`) && req.method() === 'GET') { return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: { id: testing_event_id, event_id: testing_event_id, name: 'Test Event for Nested CRUD' } }) }); } // For nested create endpoint, capture and forward (fulfill) with created object if (url.includes(`/v3/crud/event/${testing_event_id}/event_location`) && req.method() === 'POST') { const post = await req.postData(); console.log('Captured POST to nested endpoint:', url, post ? post.slice(0,200) : ''); return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify({ data: { event_location_id: 'new-loc-1', name: 'TEMP Location Name', event_id: testing_event_id } }) }); } // Default mock for other /v3/ calls return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) }); }); // Accept any confirm() dialogs that appear when creating page.on('dialog', async (dialog) => { await dialog.accept(); }); // Inject a valid localStorage state before the app loads await page.addInitScript( ({ defaults, eventId }) => { const testData = { ...defaults, account_id: '_XY7DXtc9MY', 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(testData)); }, { defaults: ae_app_local_data_defaults, eventId: testing_event_id } ); // Navigate to the page for each test. await page.goto(`/events/${testing_event_id}/locations`); }); test('should send a nested request when creating an Event Location', async ({ page }) => { // Validate the real app flow: click the UI button and assert the outgoing // nested POST request shape and endpoint. const requestPromise = page.waitForRequest( (request) => request.method() === 'POST' && request.url().includes(`/v3/crud/event/${testing_event_id}/event_location`) ); // Ensure the Add Location button is present const addBtn = page.getByRole('button', { name: 'Add Location' }); await expect(addBtn).toBeVisible(); await addBtn.click(); const request = await requestPromise; const postData = JSON.parse(request.postData() ?? '{}'); expect(request.url()).toContain(`/v3/crud/event/${testing_event_id}/event_location`); expect(postData.name).toBe('TEMP Location Name'); expect(postData.event_id).toBe(testing_event_id); }); });