Files
agiledancers/agiledancers-fe/e2e/school-management.spec.ts
Wanja Krah 1b4c7f7f2f
All checks were successful
Build, test and publish / verify (push) Successful in 1m48s
S9 OR Tools basic scheduling
2026-10-30 15:00:45 +01:00

177 lines
8.1 KiB
TypeScript

import { test, expect, Page } from '@playwright/test';
import type { School } from '../src/app/core/api-models';
const backend = process.env['PLAYWRIGHT_BASE_URL'] || 'http://127.0.0.1:8080';
let schoolToDelete: number | undefined;
test.afterEach(async ({ request }) => {
if (schoolToDelete !== undefined) {
await request.delete(`${backend}/api/dance-schools/${schoolToDelete}`);
schoolToDelete = undefined;
}
});
async function tab(page: Page, label: string) {
await page
.getByRole('navigation', { name: 'Dansschool onderdelen' })
.getByRole('link', { name: new RegExp(`^${label}`) })
.click();
}
async function save(page: Page) {
await page.getByRole('dialog').getByRole('button', { name: 'Opslaan', exact: true }).click();
await expect(page.getByRole('dialog')).toHaveCount(0);
}
async function confirmDelete(page: Page) {
await page
.getByRole('dialog')
.getByRole('button', { name: 'Definitief verwijderen', exact: true })
.click();
await expect(page.getByRole('dialog')).toHaveCount(0);
}
test('manages a school, shared memberships and shows through the real REST API', async ({
page,
}) => {
const schoolName = `E2E Studio ${Date.now()}`;
const browserErrors: string[] = [];
page.on('pageerror', (error) => browserErrors.push(error.message));
await page.goto('/');
await page.getByRole('button', { name: 'Dansschool toevoegen' }).click();
await page.getByRole('dialog').getByLabel('Naam', { exact: true }).fill(schoolName);
const created = page.waitForResponse(
(response) =>
response.url().endsWith('/api/dance-schools') && response.request().method() === 'POST',
);
await save(page);
const school: unknown = await (await created).json();
expect(school).toEqual(expect.objectContaining({ id: expect.any(Number) }));
schoolToDelete = (school as School).id;
await page.getByRole('link', { name: new RegExp(schoolName) }).click();
await expect(page.getByRole('heading', { name: schoolName, exact: true })).toBeVisible();
await page.getByRole('button', { name: 'School bewerken' }).click();
await page
.getByRole('dialog')
.getByLabel('Naam', { exact: true })
.fill(`${schoolName} vernieuwd`);
await save(page);
await expect(
page.getByRole('heading', { name: `${schoolName} vernieuwd`, exact: true }),
).toBeVisible();
await page.getByRole('button', { name: /Voeg een danser toe/ }).click();
await page.getByRole('dialog').getByLabel('Naam', { exact: true }).fill('Sam Testdanser');
await page.getByLabel('Geboortedatum').fill('2010-05-12');
await save(page);
await tab(page, 'Dansers');
await expect(page.getByRole('cell', { name: 'Sam Testdanser', exact: true })).toBeVisible();
await page.getByRole('button', { name: 'Sam Testdanser bewerken' }).click();
await page.getByLabel('Geboortedatum').fill('2011-06-13');
await save(page);
await expect(page.getByRole('cell', { name: '13 jun 2011' })).toBeVisible();
await tab(page, 'Dansgroepen');
for (const name of ['Hiphop Teens', 'Jazz Teens']) {
await page.getByRole('button', { name: 'Dansgroep toevoegen' }).click();
const dialog = page.getByRole('dialog');
await dialog.getByLabel('Naam / categorie').fill(name);
await dialog.getByLabel('Leeftijd vanaf').fill('12');
await dialog.getByLabel('Leeftijd tot en met').fill('18');
await dialog.getByLabel(name.startsWith('Hiphop') ? 'Hiphop' : 'Jazz', { exact: true }).check();
await save(page);
await page.getByRole('button', { name: `Dansers beheren voor ${name}`, exact: true }).click();
await page
.getByRole('dialog')
.locator('.member-row')
.filter({ hasText: 'Sam Testdanser' })
.getByRole('checkbox')
.check();
await expect(page.getByRole('dialog').getByText('1 van 1 dansers gekoppeld')).toBeVisible();
await page.getByRole('button', { name: 'Gereed', exact: true }).click();
await expect(
page
.getByRole('article')
.filter({ has: page.getByRole('heading', { name, exact: true }) })
.getByText(/1 dansers/),
).toBeVisible();
}
await page.getByRole('button', { name: 'Hiphop Teens bewerken' }).click();
await page.getByLabel('Naam / categorie').fill('Hiphop Selectie');
await page.getByLabel('Type', { exact: true }).selectOption({ label: 'Selectie' });
await save(page);
await expect(
page
.getByRole('article')
.filter({ hasText: 'Hiphop Selectie' })
.getByText(/1 dansers/),
).toBeVisible();
await page.screenshot({ path: 'test-results/groups-desktop.png', fullPage: true });
await tab(page, 'Shows');
await page.getByRole('button', { name: 'Show toevoegen' }).click();
await page.getByRole('dialog').getByLabel('Naam', { exact: true }).fill('Zomershow');
await page.getByRole('button', { name: 'Dagdeel toevoegen', exact: true }).click();
await page.getByLabel('Datum', { exact: true }).fill('2027-06-12');
await save(page);
await expect(page.getByText('2027-06-12 · AFTERNOON:', { exact: false })).toBeVisible();
await page.getByRole('button', { name: 'Zomershow bewerken' }).click();
await page.getByLabel('Datum', { exact: true }).fill('2027-07-01');
await save(page);
await expect(page.locator('.date-tile')).toContainText('jul 2027');
page.once('dialog', (dialog) => dialog.accept());
await page.getByRole('button', { name: /Schedule groups/ }).click();
await expect(page.getByText('Planning voldoet aan alle optredensaantallen.')).toBeVisible();
await expect(page.getByRole('status').filter({ hasText: 'Optimale balans.' })).toBeVisible();
await page.getByRole('button', { name: 'Zomershow bewerken' }).click();
await page.getByRole('button', { name: 'Dagdeel toevoegen', exact: true }).click();
await page.getByLabel('Datum', { exact: true }).nth(1).fill('2027-07-02');
page.once('dialog', async (dialog) => {
expect(dialog.message()).toContain('Zomershow');
await dialog.dismiss();
});
await page.getByRole('button', { name: 'Opslaan', exact: true }).click();
await expect(page.getByRole('dialog')).toBeVisible();
await page.getByRole('button', { name: 'Annuleren', exact: true }).click();
await tab(page, 'Overzicht');
await page.setViewportSize({ width: 390, height: 844 });
await expect(
page.getByRole('heading', { name: `${schoolName} vernieuwd`, exact: true }),
).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth <= window.innerWidth)).toBe(
true,
);
await page.screenshot({ path: 'test-results/overview-mobile.png', fullPage: true });
await page.setViewportSize({ width: 1440, height: 1000 });
await page.screenshot({ path: 'test-results/overview-desktop.png', fullPage: true });
await tab(page, 'Dansers');
await page.getByRole('button', { name: 'Sam Testdanser verwijderen' }).click();
await confirmDelete(page);
await expect(page.getByText('De dansvloer is nog leeg')).toBeVisible();
await tab(page, 'Dansgroepen');
await expect(page.getByText(/0 dansers/)).toHaveCount(2);
await page.getByRole('button', { name: 'Hiphop Selectie verwijderen' }).click();
await confirmDelete(page);
await expect(page.getByRole('heading', { name: 'Hiphop Selectie', exact: true })).toHaveCount(0);
await tab(page, 'Shows');
await page.getByRole('button', { name: 'Zomershow verwijderen' }).click();
await confirmDelete(page);
await expect(page.getByText('Het podium wacht op je')).toBeVisible();
await tab(page, 'Overzicht');
await page.getByRole('button', { name: 'School verwijderen', exact: true }).click();
await confirmDelete(page);
await expect(page).toHaveURL(/\/schools$/);
await expect(page.getByRole('link', { name: new RegExp(schoolName) })).toHaveCount(0);
expect(browserErrors).toEqual([]);
});
test('shows a useful connection error and recovers on retry', async ({ page }) => {
await page.route('**/api/dance-schools', (route) => route.abort('connectionfailed'));
await page.goto('/schools');
await expect(page.getByRole('alert')).toContainText('niet bereikbaar');
await page.unroute('**/api/dance-schools');
await page.getByRole('button', { name: 'Opnieuw proberen' }).click();
await expect(page.getByRole('heading', { name: /Mijn dansscholen/ })).toBeVisible();
});