Refactor admin to shared generic CRUD; restructure proclamation categories/groups and APIs
- Replace per-model admin forms with the shared generic AdminTable/AdminModal CRUD - Add ProclamationGroup model and admin + API v2 routes (replaces subscription levels) - Drop subscription levels and flatten proclamation categories - Update v2 serializers and seed data accordingly
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
import { page } from 'vitest/browser';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { render } from 'vitest-browser-svelte';
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
vi.mock('$app/forms', () => ({
|
||||
enhance: () => () => {}
|
||||
}));
|
||||
|
||||
import Page from './+page.svelte';
|
||||
|
||||
const relationOptionsData = {
|
||||
solfeggioFrequencyId: [
|
||||
{ label: 'UT - 396', value: 1 },
|
||||
{ label: 'RE - 417', value: 2 }
|
||||
]
|
||||
};
|
||||
|
||||
const categories = [
|
||||
{ id: 1, name: 'Healing' },
|
||||
{ id: 2, name: 'Manifestation' }
|
||||
];
|
||||
|
||||
const groups = [
|
||||
{ id: 1, name: 'General' },
|
||||
{ id: 2, name: 'Specific' }
|
||||
];
|
||||
|
||||
const superAdmin = {
|
||||
id: 'admin-1',
|
||||
name: 'Super Admin',
|
||||
roleId: 1,
|
||||
roleName: 'SUPER'
|
||||
};
|
||||
|
||||
function makeData(overrides: Partial<PageProps['data']> = {}): PageProps['data'] {
|
||||
return {
|
||||
records: [],
|
||||
relationOptionsData,
|
||||
categories,
|
||||
groups,
|
||||
adminUser: superAdmin,
|
||||
userRoleId: superAdmin.roleId,
|
||||
...overrides
|
||||
};
|
||||
}
|
||||
|
||||
function mountPage(dataOverrides: Partial<PageProps['data']> = {}) {
|
||||
return render(Page, { params: {}, data: makeData(dataOverrides), form: null });
|
||||
}
|
||||
|
||||
const editRecord = {
|
||||
id: 'proc-1',
|
||||
name: 'Test Proclamation',
|
||||
content: '<p>Secret</p>',
|
||||
solfeggioFrequencyId: 2,
|
||||
categoryId: 1,
|
||||
groupId: 2,
|
||||
category: { name: 'Healing' },
|
||||
group: { name: 'Specific' },
|
||||
solfeggioFrequency: { name: 'RE - 417' }
|
||||
};
|
||||
|
||||
async function openCreateModal() {
|
||||
await page.getByRole('button', { name: 'New Proclamation +' }).click();
|
||||
}
|
||||
|
||||
async function openEditModal() {
|
||||
await page.getByRole('cell', { name: 'Test Proclamation' }).click();
|
||||
}
|
||||
|
||||
describe('proclamations admin page (super user)', () => {
|
||||
it('renders all basic fields in create mode', async () => {
|
||||
mountPage();
|
||||
|
||||
await openCreateModal();
|
||||
|
||||
await expect.element(page.getByRole('textbox', { name: 'Name' })).toBeInTheDocument();
|
||||
await expect.element(page.getByRole('combobox', { name: /^Frequency$/ })).toBeInTheDocument();
|
||||
await expect.element(page.getByRole('combobox', { name: /^Category$/ })).toBeInTheDocument();
|
||||
await expect.element(page.getByRole('combobox', { name: /^Group$/ })).toBeInTheDocument();
|
||||
await expect.element(page.getByRole('button', { name: 'Create' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('pre-fills name input when editing an existing record', async () => {
|
||||
mountPage({ records: [editRecord] });
|
||||
|
||||
await openEditModal();
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('textbox', { name: 'Name' }))
|
||||
.toHaveValue('Test Proclamation');
|
||||
});
|
||||
|
||||
it('pre-fills select values when editing an existing record', async () => {
|
||||
mountPage({ records: [editRecord] });
|
||||
|
||||
await openEditModal();
|
||||
|
||||
const freqEl = (await page
|
||||
.getByRole('combobox', { name: /^Frequency$/ })
|
||||
.element()) as HTMLSelectElement;
|
||||
const categoryEl = (await page
|
||||
.getByRole('combobox', { name: /^Category$/ })
|
||||
.element()) as HTMLSelectElement;
|
||||
const groupEl = (await page
|
||||
.getByRole('combobox', { name: /^Group$/ })
|
||||
.element()) as HTMLSelectElement;
|
||||
|
||||
expect(freqEl.value).toBe('2');
|
||||
expect(categoryEl.value).toBe('1');
|
||||
expect(groupEl.value).toBe('2');
|
||||
});
|
||||
|
||||
it('keeps group selection independent of category selection (movable filter)', async () => {
|
||||
mountPage({ records: [editRecord] });
|
||||
|
||||
await openEditModal();
|
||||
|
||||
const categoryEl = (await page
|
||||
.getByRole('combobox', { name: /^Category$/ })
|
||||
.element()) as HTMLSelectElement;
|
||||
const groupEl = (await page
|
||||
.getByRole('combobox', { name: /^Group$/ })
|
||||
.element()) as HTMLSelectElement;
|
||||
|
||||
categoryEl.value = '2';
|
||||
categoryEl.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
|
||||
expect(categoryEl.value).toBe('2');
|
||||
expect(groupEl.value).toBe('2');
|
||||
});
|
||||
|
||||
it('shows content editor when isSuper is true', async () => {
|
||||
mountPage({ records: [editRecord] });
|
||||
|
||||
await openEditModal();
|
||||
|
||||
await expect.element(page.getByText('Content')).toBeInTheDocument();
|
||||
await expect.element(page.getByTestId('tiptap-editor')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('disables submit button when editing and not dirty', async () => {
|
||||
mountPage({ records: [editRecord] });
|
||||
|
||||
await openEditModal();
|
||||
|
||||
await expect.element(page.getByRole('button', { name: 'Update' })).toBeDisabled();
|
||||
});
|
||||
|
||||
it('enables submit button when editing and user modifies a field', async () => {
|
||||
mountPage({ records: [editRecord] });
|
||||
|
||||
await openEditModal();
|
||||
|
||||
await page.getByRole('textbox', { name: 'Name' }).fill('New Name');
|
||||
|
||||
await expect.element(page.getByRole('button', { name: 'Update' })).toBeEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('proclamations admin page (non-super user)', () => {
|
||||
it('hides create/edit entry points and content field from non-super users', async () => {
|
||||
mountPage({
|
||||
records: [editRecord],
|
||||
adminUser: { ...superAdmin, id: 'admin-2', roleId: 2, roleName: 'ADMIN' }
|
||||
});
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('button', { name: 'New Proclamation +' }))
|
||||
.not.toBeInTheDocument();
|
||||
await expect.element(page.getByText('Content')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user