Stundenplan Phase 3d: all 15 constraint editors via shared shell
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 30s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m38s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 20s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 30s
CI / test-go-edu-search (push) Successful in 29s
CI / test-python-klausur (push) Failing after 2m38s
CI / test-python-agent-core (push) Successful in 18s
CI / test-nodejs-website (push) Successful in 20s
Backend was already complete in Phase 2; this finishes the UI.
- regeln/_shell.tsx introduces useConstraintCrud (handles list/create/
delete state + reload), ConstraintShell (header, prereq banner,
form toggle, error display, empty/loading/table render), and
useShellStyles for the recurring theme tokens. Each editor now
only carries its schema-specific bits.
- Existing 4 editors (TeacherUnavailableDay/Window, SubjectMax
Consecutive/PreferredPeriod) refactored onto the shell — every
Playwright selector preserved.
- 11 new editors covering the remaining constraint tables:
TeacherMaxHours{Day,Week}, TeacherExcluded{Subject,Room},
Subject{MinDayGap,ContiguousWhenRepeated,DoubleLesson},
Class{MaxHoursDay,NoGaps},
Room{RequiresType,Unavailable}.
- RegelnHub now references all 15 editors directly — no more 'soon'
placeholders. The two duplicate 'Max. Stunden / Tag' entries
(teacher + class) are intentional and disambiguated by group.
Tests:
- e2e/stundenplan.spec.ts: mock routes added for all 11 new constraint
endpoints. RegelnHub suite gains a single test that switches
through 13 uniquely-labelled editors, plus a dedicated test for
the two duplicate 'Max. Stunden / Tag' labels.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,8 +78,19 @@ async function mockSchoolApi(page: Page, opts: MockOpts = {}) {
|
||||
for (const path of [
|
||||
'constraints/teacher/unavailable-day',
|
||||
'constraints/teacher/unavailable-window',
|
||||
'constraints/teacher/max-hours-day',
|
||||
'constraints/teacher/max-hours-week',
|
||||
'constraints/teacher/excluded-subject',
|
||||
'constraints/teacher/excluded-room',
|
||||
'constraints/subject/max-consecutive',
|
||||
'constraints/subject/preferred-period',
|
||||
'constraints/subject/min-day-gap',
|
||||
'constraints/subject/contiguous-when-repeated',
|
||||
'constraints/subject/double-lesson',
|
||||
'constraints/class/max-hours-day',
|
||||
'constraints/class/no-gaps',
|
||||
'constraints/room/requires-type',
|
||||
'constraints/room/unavailable',
|
||||
]) {
|
||||
await staticList(path, [])
|
||||
}
|
||||
@@ -314,10 +325,37 @@ test.describe('Stundenplan — Regeln Hub', () => {
|
||||
await expect(page.getByTestId('subject-preferred-period-editor')).toBeVisible()
|
||||
})
|
||||
|
||||
test('unimplemented rules are disabled in the sidebar', async ({ page }) => {
|
||||
const soonBtn = page.getByRole('button', { name: /Min\. Tagesabstand/ })
|
||||
await expect(soonBtn).toBeDisabled()
|
||||
await expect(page.getByText('soon').first()).toBeVisible()
|
||||
test('all unique-labelled constraint editors mount when selected', async ({ page }) => {
|
||||
// Skip 'Max. Stunden / Tag' (teacher + class both use it) — covered separately below.
|
||||
const cases: { label: string; testId: string }[] = [
|
||||
{ label: 'Tag nicht verfuegbar', testId: 'teacher-unavailable-day-editor' },
|
||||
{ label: 'Zeitfenster nicht verfuegbar', testId: 'teacher-unavailable-window-editor' },
|
||||
{ label: 'Max. Stunden / Woche', testId: 'teacher-max-hours-week-editor' },
|
||||
{ label: 'Fach ausgeschlossen', testId: 'teacher-excluded-subject-editor' },
|
||||
{ label: 'Raum ausgeschlossen', testId: 'teacher-excluded-room-editor' },
|
||||
{ label: 'Max. Stunden am Stueck', testId: 'subject-max-consecutive-editor' },
|
||||
{ label: 'Bevorzugter Stunden-Bereich', testId: 'subject-preferred-period-editor' },
|
||||
{ label: 'Min. Tagesabstand', testId: 'subject-min-day-gap-editor' },
|
||||
{ label: 'Bei Mehrfach: zusammenhaengend', testId: 'subject-contiguous-when-repeated-editor' },
|
||||
{ label: 'Doppelstunde bevorzugt', testId: 'subject-double-lesson-editor' },
|
||||
{ label: 'Keine Freistunden', testId: 'class-no-gaps-editor' },
|
||||
{ label: 'Fach benoetigt Raumtyp', testId: 'room-requires-type-editor' },
|
||||
{ label: 'Raum nicht verfuegbar', testId: 'room-unavailable-editor' },
|
||||
]
|
||||
for (const c of cases) {
|
||||
await page.getByRole('button', { name: c.label, exact: true }).click()
|
||||
await expect(page.getByTestId(c.testId)).toBeVisible()
|
||||
}
|
||||
})
|
||||
|
||||
test('both Max. Stunden / Tag entries mount the right editor', async ({ page }) => {
|
||||
// The label appears twice (Lehrer + Klasse). .first() targets the
|
||||
// teacher entry (earlier in the DOM), .nth(1) the class entry.
|
||||
const buttons = page.getByRole('button', { name: 'Max. Stunden / Tag', exact: true })
|
||||
await buttons.first().click()
|
||||
await expect(page.getByTestId('teacher-max-hours-day-editor')).toBeVisible()
|
||||
await buttons.nth(1).click()
|
||||
await expect(page.getByTestId('class-max-hours-day-editor')).toBeVisible()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user