test: inject real ConfirmService via context (batch 1/2)
Replaces the vi.mock('$lib/shared/services/confirm.svelte') stub with a
real createConfirmService() provided through render's context map, mirroring
the existing admin/tags/[id]/page.svelte.spec.ts pattern. The generic
confirm.test-fixture.svelte renders only ConfirmDialog and cannot wrap an
arbitrary page; none of these specs trigger confirm(), so the children's
getConfirmService() simply reads the provided context instead of a module
mock. No vi.mock of confirm.svelte remains in these 5 specs. Part of #560.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
|
||||
vi.mock('$lib/shared/services/confirm.svelte', () => ({
|
||||
getConfirmService: () => ({ confirm: async () => false })
|
||||
}));
|
||||
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
|
||||
|
||||
const { default: AdminGroupEditPage } = await import('./+page.svelte');
|
||||
|
||||
@@ -19,13 +17,17 @@ const baseGroup = (overrides: Record<string, unknown> = {}) => ({
|
||||
|
||||
describe('admin/groups/[id] page', () => {
|
||||
it('renders the edit heading with the group name', async () => {
|
||||
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: undefined }
|
||||
});
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /familie/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('hydrates the name input from data.group.name', async () => {
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup({ name: 'Admins' }) }, form: undefined }
|
||||
});
|
||||
|
||||
@@ -35,6 +37,7 @@ describe('admin/groups/[id] page', () => {
|
||||
|
||||
it('checks the permission checkboxes that are in data.group.permissions', async () => {
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: {
|
||||
data: { group: baseGroup({ permissions: ['READ_ALL', 'ADMIN_TAG'] }) },
|
||||
form: undefined
|
||||
@@ -57,6 +60,7 @@ describe('admin/groups/[id] page', () => {
|
||||
|
||||
it('shows the success banner when form.success is true', async () => {
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: { success: true } }
|
||||
});
|
||||
|
||||
@@ -65,6 +69,7 @@ describe('admin/groups/[id] page', () => {
|
||||
|
||||
it('shows the error banner when form.error is set', async () => {
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: {
|
||||
data: { group: baseGroup() },
|
||||
form: { error: 'Name darf nicht leer sein.' }
|
||||
@@ -75,21 +80,30 @@ describe('admin/groups/[id] page', () => {
|
||||
});
|
||||
|
||||
it('renders the cancel link to /admin/groups', async () => {
|
||||
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: undefined }
|
||||
});
|
||||
|
||||
const links = document.querySelectorAll('a[href="/admin/groups"]');
|
||||
expect(links.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('renders the delete and save buttons', async () => {
|
||||
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: undefined }
|
||||
});
|
||||
|
||||
await expect.element(page.getByRole('button', { name: /löschen/i })).toBeVisible();
|
||||
await expect.element(page.getByRole('button', { name: /speichern/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('does not render success banner when form is undefined', async () => {
|
||||
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: undefined }
|
||||
});
|
||||
|
||||
const banner = document.querySelector('.bg-green-50');
|
||||
expect(banner).toBeNull();
|
||||
@@ -97,6 +111,7 @@ describe('admin/groups/[id] page', () => {
|
||||
|
||||
it('does not render error-banner div when form.success is true (success path only)', async () => {
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: { success: true } }
|
||||
});
|
||||
|
||||
@@ -106,7 +121,10 @@ describe('admin/groups/[id] page', () => {
|
||||
});
|
||||
|
||||
it('renders all 8 permission checkboxes (4 standard + 4 admin)', async () => {
|
||||
render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } });
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup() }, form: undefined }
|
||||
});
|
||||
|
||||
const checkboxes = document.querySelectorAll('input[name="permissions"]');
|
||||
expect(checkboxes.length).toBe(8);
|
||||
@@ -114,6 +132,7 @@ describe('admin/groups/[id] page', () => {
|
||||
|
||||
it('handles a group with empty permissions array', async () => {
|
||||
render(AdminGroupEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: { group: baseGroup({ permissions: [] }) }, form: undefined }
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
|
||||
vi.mock('$lib/shared/services/confirm.svelte', () => ({
|
||||
getConfirmService: () => ({ confirm: async () => false })
|
||||
}));
|
||||
import { createConfirmService, CONFIRM_KEY } from '$lib/shared/services/confirm.svelte.js';
|
||||
|
||||
const { default: AdminUserEditPage } = await import('./+page.svelte');
|
||||
|
||||
@@ -32,13 +30,19 @@ const baseData = (overrides: Record<string, unknown> = {}) => ({
|
||||
|
||||
describe('admin/users/[id] page', () => {
|
||||
it('renders the edit heading with the user email', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: undefined }
|
||||
});
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /anna@example/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders all three card sections', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: undefined }
|
||||
});
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /persönliche daten/i })).toBeVisible();
|
||||
await expect.element(page.getByRole('heading', { name: /^gruppen$/i })).toBeVisible();
|
||||
@@ -46,13 +50,17 @@ describe('admin/users/[id] page', () => {
|
||||
});
|
||||
|
||||
it('shows the update success banner when form.success is true', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: { success: true } } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: { success: true } }
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Änderungen gespeichert.')).toBeVisible();
|
||||
});
|
||||
|
||||
it('shows the update error banner when form.error is set', async () => {
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: { error: 'E-Mail bereits vergeben' } }
|
||||
});
|
||||
|
||||
@@ -60,7 +68,10 @@ describe('admin/users/[id] page', () => {
|
||||
});
|
||||
|
||||
it('preselects the user groups in UserGroupsSection', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: undefined }
|
||||
});
|
||||
|
||||
const checkboxes = Array.from(
|
||||
document.querySelectorAll('input[name="groupIds"]')
|
||||
@@ -70,27 +81,39 @@ describe('admin/users/[id] page', () => {
|
||||
});
|
||||
|
||||
it('renders cancel link to /admin/users', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: undefined }
|
||||
});
|
||||
|
||||
const cancel = document.querySelector('a[href="/admin/users"]');
|
||||
expect(cancel).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders the delete button', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: undefined }
|
||||
});
|
||||
|
||||
await expect.element(page.getByRole('button', { name: /löschen/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('does not show success banner when form is undefined', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: undefined } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: undefined }
|
||||
});
|
||||
|
||||
const banner = document.querySelector('.bg-green-50');
|
||||
expect(banner).toBeNull();
|
||||
});
|
||||
|
||||
it('does not show error banner when form.error is undefined', async () => {
|
||||
render(AdminUserEditPage, { props: { data: baseData(), form: { success: false } } });
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData(), form: { success: false } }
|
||||
});
|
||||
|
||||
// The error banner has both border-red-200 AND text-red-700 — the delete button has red-50
|
||||
// background but is a button, not a div. Look for the specific error <div>.
|
||||
@@ -100,6 +123,7 @@ describe('admin/users/[id] page', () => {
|
||||
|
||||
it('handles a user with empty groups list (selectedGroupIds defaults to [])', async () => {
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: {
|
||||
data: baseData({ editUser: { ...baseEditUser, groups: [] } }),
|
||||
form: undefined
|
||||
@@ -117,6 +141,7 @@ describe('admin/users/[id] page', () => {
|
||||
const editUser = { ...baseEditUser } as typeof baseEditUser & { groups?: undefined };
|
||||
delete (editUser as { groups?: unknown }).groups;
|
||||
render(AdminUserEditPage, {
|
||||
context: new Map([[CONFIRM_KEY, createConfirmService()]]),
|
||||
props: { data: baseData({ editUser }), form: undefined }
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user