Ajout de test, correctif d'un problème d'horloge pour le workflow gitea actions pour le e2e
Some checks failed
E2E Tests / e2e (push) Failing after 3m33s
Some checks failed
E2E Tests / e2e (push) Failing after 3m33s
This commit is contained in:
@@ -60,6 +60,13 @@ jobs:
|
|||||||
working-directory: web
|
working-directory: web
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Work around runner clock skew for apt
|
||||||
|
run: |
|
||||||
|
sudo tee /etc/apt/apt.conf.d/99no-check-valid-until >/dev/null <<'EOF'
|
||||||
|
Acquire::Check-Valid-Until "false";
|
||||||
|
Acquire::Check-Date "false";
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
- name: Install Playwright browsers
|
||||||
working-directory: web
|
working-directory: web
|
||||||
run: npx playwright install --with-deps chromium
|
run: npx playwright install --with-deps chromium
|
||||||
|
|||||||
49
web/e2e/tests/campaign/arc-delete.spec.ts
Normal file
49
web/e2e/tests/campaign/arc-delete.spec.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import {
|
||||||
|
seedCampaign,
|
||||||
|
seedArc,
|
||||||
|
deleteCampaign,
|
||||||
|
type SeededCampaign,
|
||||||
|
type SeededArc,
|
||||||
|
} from '../../fixtures/api';
|
||||||
|
|
||||||
|
test.describe('Arc delete', () => {
|
||||||
|
let campaign: SeededCampaign;
|
||||||
|
let arc: SeededArc;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ request }) => {
|
||||||
|
campaign = await seedCampaign(request);
|
||||||
|
arc = await seedArc(request, { campaignId: campaign.id });
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async ({ request }) => {
|
||||||
|
if (campaign?.id) await deleteCampaign(request, campaign.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deletes an arc after accepting confirm and redirects to the campaign', async ({
|
||||||
|
page,
|
||||||
|
request,
|
||||||
|
}) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.accept());
|
||||||
|
|
||||||
|
await page.goto(`/campaigns/${campaign.id}/arcs/${arc.id}/edit`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/campaigns/${campaign.id}$`));
|
||||||
|
|
||||||
|
const res = await request.get(`/api/arcs/${arc.id}`);
|
||||||
|
expect(res.status()).toBe(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps the arc when confirm is dismissed', async ({ page, request }) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.dismiss());
|
||||||
|
|
||||||
|
await page.goto(`/campaigns/${campaign.id}/arcs/${arc.id}/edit`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/campaigns/${campaign.id}/arcs/${arc.id}/edit$`));
|
||||||
|
|
||||||
|
const res = await request.get(`/api/arcs/${arc.id}`);
|
||||||
|
expect(res.ok()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
41
web/e2e/tests/campaign/campaign-delete.spec.ts
Normal file
41
web/e2e/tests/campaign/campaign-delete.spec.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import { seedCampaign, deleteCampaign, type SeededCampaign } from '../../fixtures/api';
|
||||||
|
|
||||||
|
test.describe('Campaign delete', () => {
|
||||||
|
let campaign: SeededCampaign;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ request }) => {
|
||||||
|
campaign = await seedCampaign(request);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async ({ request }) => {
|
||||||
|
if (campaign?.id) await deleteCampaign(request, campaign.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deletes a campaign after accepting confirm and redirects to the list', async ({
|
||||||
|
page,
|
||||||
|
request,
|
||||||
|
}) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.accept());
|
||||||
|
|
||||||
|
await page.goto(`/campaigns/${campaign.id}`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(/\/campaigns$/);
|
||||||
|
|
||||||
|
const res = await request.get(`/api/campaigns/${campaign.id}`);
|
||||||
|
expect(res.status()).toBe(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps the campaign when confirm is dismissed', async ({ page, request }) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.dismiss());
|
||||||
|
|
||||||
|
await page.goto(`/campaigns/${campaign.id}`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/campaigns/${campaign.id}$`));
|
||||||
|
|
||||||
|
const res = await request.get(`/api/campaigns/${campaign.id}`);
|
||||||
|
expect(res.ok()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
53
web/e2e/tests/lore/lore-delete.spec.ts
Normal file
53
web/e2e/tests/lore/lore-delete.spec.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import { seedLoreWithFolder, deleteLore, type SeededLore } from '../../fixtures/api';
|
||||||
|
|
||||||
|
test.describe('Lore delete', () => {
|
||||||
|
let seeded: SeededLore;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ request }) => {
|
||||||
|
seeded = await seedLoreWithFolder(request);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async ({ request }) => {
|
||||||
|
// Best-effort cleanup — ne fait rien si déjà supprimé par le test.
|
||||||
|
if (seeded?.id) await deleteLore(request, seeded.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deletes a lore after accepting the confirm and redirects to the list', async ({
|
||||||
|
page,
|
||||||
|
request,
|
||||||
|
}) => {
|
||||||
|
let confirmMessage = '';
|
||||||
|
page.on('dialog', async (dialog) => {
|
||||||
|
confirmMessage = dialog.message();
|
||||||
|
await dialog.accept();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(`/lore/${seeded.id}`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
// Attente du dialog et du retour sur la liste des lores.
|
||||||
|
await expect(page).toHaveURL(/\/lore$/);
|
||||||
|
expect(confirmMessage).toContain(seeded.name);
|
||||||
|
// Lore contient un dossier seedé : le récapitulatif doit l'indiquer.
|
||||||
|
expect(confirmMessage).toMatch(/1 dossier/i);
|
||||||
|
|
||||||
|
const res = await request.get(`/api/lores/${seeded.id}`);
|
||||||
|
expect(res.status()).toBe(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps the lore when the confirm is dismissed', async ({ page, request }) => {
|
||||||
|
page.on('dialog', async (dialog) => {
|
||||||
|
await dialog.dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.goto(`/lore/${seeded.id}`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
// On reste sur le détail, le titre du lore est toujours visible.
|
||||||
|
await expect(page.locator('.detail-header h1')).toHaveText(seeded.name);
|
||||||
|
|
||||||
|
const res = await request.get(`/api/lores/${seeded.id}`);
|
||||||
|
expect(res.ok()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
58
web/e2e/tests/lore/page-delete.spec.ts
Normal file
58
web/e2e/tests/lore/page-delete.spec.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import {
|
||||||
|
seedLoreWithFolder,
|
||||||
|
seedTemplate,
|
||||||
|
seedPage,
|
||||||
|
deleteLore,
|
||||||
|
type SeededLore,
|
||||||
|
type SeededTemplate,
|
||||||
|
type SeededPage,
|
||||||
|
} from '../../fixtures/api';
|
||||||
|
|
||||||
|
test.describe('Page delete', () => {
|
||||||
|
let seeded: SeededLore;
|
||||||
|
let template: SeededTemplate;
|
||||||
|
let pageEntity: SeededPage;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ request }) => {
|
||||||
|
seeded = await seedLoreWithFolder(request);
|
||||||
|
template = await seedTemplate(request, {
|
||||||
|
loreId: seeded.id,
|
||||||
|
defaultNodeId: seeded.rootFolderId,
|
||||||
|
});
|
||||||
|
pageEntity = await seedPage(request, {
|
||||||
|
loreId: seeded.id,
|
||||||
|
nodeId: seeded.rootFolderId,
|
||||||
|
templateId: template.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async ({ request }) => {
|
||||||
|
if (seeded?.id) await deleteLore(request, seeded.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deletes the page after accepting confirm', async ({ page, request }) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.accept());
|
||||||
|
|
||||||
|
await page.goto(`/lore/${seeded.id}/pages/${pageEntity.id}/edit`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
// Le composant redirige vers la racine du Lore après suppression.
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/lore/${seeded.id}$`));
|
||||||
|
|
||||||
|
const res = await request.get(`/api/pages/${pageEntity.id}`);
|
||||||
|
expect(res.status()).toBe(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps the page when confirm is dismissed', async ({ page, request }) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.dismiss());
|
||||||
|
|
||||||
|
await page.goto(`/lore/${seeded.id}/pages/${pageEntity.id}/edit`);
|
||||||
|
await page.getByRole('button', { name: /^Supprimer$/i }).click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/lore/${seeded.id}/pages/${pageEntity.id}/edit$`));
|
||||||
|
|
||||||
|
const res = await request.get(`/api/pages/${pageEntity.id}`);
|
||||||
|
expect(res.ok()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
51
web/e2e/tests/lore/template-delete.spec.ts
Normal file
51
web/e2e/tests/lore/template-delete.spec.ts
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
import {
|
||||||
|
seedLoreWithFolder,
|
||||||
|
seedTemplate,
|
||||||
|
deleteLore,
|
||||||
|
getTemplatesForLore,
|
||||||
|
type SeededLore,
|
||||||
|
type SeededTemplate,
|
||||||
|
} from '../../fixtures/api';
|
||||||
|
|
||||||
|
test.describe('Template delete', () => {
|
||||||
|
let seeded: SeededLore;
|
||||||
|
let template: SeededTemplate;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ request }) => {
|
||||||
|
seeded = await seedLoreWithFolder(request);
|
||||||
|
template = await seedTemplate(request, {
|
||||||
|
loreId: seeded.id,
|
||||||
|
defaultNodeId: seeded.rootFolderId,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterEach(async ({ request }) => {
|
||||||
|
if (seeded?.id) await deleteLore(request, seeded.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deletes the template after accepting confirm', async ({ page, request }) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.accept());
|
||||||
|
|
||||||
|
await page.goto(`/lore/${seeded.id}/templates/${template.id}`);
|
||||||
|
await page.locator('.page-header .btn-danger').click();
|
||||||
|
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/lore/${seeded.id}$`));
|
||||||
|
|
||||||
|
const templates = await getTemplatesForLore(request, seeded.id);
|
||||||
|
expect(templates.find((t) => t.id === template.id)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps the template when confirm is dismissed', async ({ page, request }) => {
|
||||||
|
page.on('dialog', (dialog) => dialog.dismiss());
|
||||||
|
|
||||||
|
await page.goto(`/lore/${seeded.id}/templates/${template.id}`);
|
||||||
|
await page.locator('.page-header .btn-danger').click();
|
||||||
|
|
||||||
|
// On reste sur l'écran d'édition (l'URL ne change pas).
|
||||||
|
await expect(page).toHaveURL(new RegExp(`/lore/${seeded.id}/templates/${template.id}$`));
|
||||||
|
|
||||||
|
const templates = await getTemplatesForLore(request, seeded.id);
|
||||||
|
expect(templates.find((t) => t.id === template.id)).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user