chore: seminarhof customer project
This commit is contained in:
0
e2e/tests/features/.gitkeep
Normal file
0
e2e/tests/features/.gitkeep
Normal file
102
e2e/tests/features/admin-booking-detail.feature
Normal file
102
e2e/tests/features/admin-booking-detail.feature
Normal file
@@ -0,0 +1,102 @@
|
||||
@admin @bookings
|
||||
Feature: Admin booking detail — read & edit
|
||||
The admin booking-detail page replaces the spreadsheet — admins must be able
|
||||
to *edit* every column they used to edit, not just look at it.
|
||||
|
||||
Background:
|
||||
Given "the admin" is logged in
|
||||
When they visit "/admin/bookings/b_yoga_2026_summer"
|
||||
|
||||
# ── Read ────────────────────────────────────────────────────────────────
|
||||
Scenario: admin opens the summer retreat detail
|
||||
Then they see "Summer Yoga Retreat 2026"
|
||||
And they see "Yoga Retreat e.V."
|
||||
And they see "Teilnehmende"
|
||||
|
||||
Scenario: admin sees the seeded participant list
|
||||
When they click "Teilnehmende"
|
||||
Then they see "Anja Weber"
|
||||
And they see "Bernd Krause"
|
||||
|
||||
# ── Edit booking metadata ───────────────────────────────────────────────
|
||||
Scenario: admin edits the course name and persists across reload
|
||||
When they fill "courseName" with "Summer Yoga Retreat 2026 — revised"
|
||||
And they click "Änderungen speichern"
|
||||
Then they see "Gespeichert"
|
||||
When they visit "/admin/bookings/b_yoga_2026_summer"
|
||||
Then they see "Summer Yoga Retreat 2026 — revised"
|
||||
|
||||
Scenario: admin updates expected participants
|
||||
When they fill "expectedPersons" with "32"
|
||||
And they click "Änderungen speichern"
|
||||
Then they see "Gespeichert"
|
||||
|
||||
Scenario: admin toggles half-house and online listing flags
|
||||
When they select "Ja" from "halfHouse"
|
||||
And they select "Ja" from "onlineAd"
|
||||
And they click "Änderungen speichern"
|
||||
Then they see "Gespeichert"
|
||||
|
||||
Scenario: admin cannot save when no field changed
|
||||
Then they see "Änderungen speichern"
|
||||
# Save button is disabled until a field is touched — clicking has no effect.
|
||||
|
||||
# ── Edit organisation ──────────────────────────────────────────────────
|
||||
Scenario: admin edits organisation contact email and phone
|
||||
When they fill "organisation-email" with "ops@yoga-retreat.example"
|
||||
And they fill "organisation-phone" with "+49 30 12345678"
|
||||
And they click "Organisation speichern"
|
||||
Then they see "Organisation gespeichert"
|
||||
When they visit "/admin/bookings/b_yoga_2026_summer"
|
||||
Then the field "organisation-email" has value "ops@yoga-retreat.example"
|
||||
And the field "organisation-phone" has value "+49 30 12345678"
|
||||
|
||||
Scenario: organisation save rejects an invalid email
|
||||
When they fill "organisation-email" with "not-an-email"
|
||||
And they click "Organisation speichern"
|
||||
Then they do not see "Organisation gespeichert"
|
||||
|
||||
# ── Booking status transitions ─────────────────────────────────────────
|
||||
Scenario: admin cancels a booking
|
||||
# ConfirmButton: first click arms, second click (testid `-confirm`) fires.
|
||||
When they trigger booking action "action-cancel-booking"
|
||||
Then they see "Storniert"
|
||||
And they do not see "Buchung stornieren"
|
||||
|
||||
# ── Participants CRUD ──────────────────────────────────────────────────
|
||||
Scenario: admin adds a participant
|
||||
When they click "Teilnehmende"
|
||||
And they fill "new-participant-name" with "Ingrid Vogel"
|
||||
And they click "Hinzufügen"
|
||||
Then they see "Ingrid Vogel"
|
||||
|
||||
Scenario: admin removes a participant
|
||||
When they click "Teilnehmende"
|
||||
And they accept the next confirmation
|
||||
And they click "remove-participant-p_s_08"
|
||||
Then they do not see "Hans Becker"
|
||||
|
||||
Scenario: admin changes a participant's diet
|
||||
When they click "Teilnehmende"
|
||||
And they select "Pescetarisch" from "participant-diet-p_s_06"
|
||||
Then the field "participant-diet-p_s_06" has value "Pescetarisch"
|
||||
|
||||
# ── Allergies CRUD ─────────────────────────────────────────────────────
|
||||
Scenario: admin adds an allergy to a participant
|
||||
When they click "Teilnehmende"
|
||||
And they fill "new-allergy-p_s_02" with "shellfish"
|
||||
And they click "add-allergy-p_s_02"
|
||||
Then they see "Meeresfrüchte"
|
||||
|
||||
Scenario: admin removes an existing allergy
|
||||
When they click "Teilnehmende"
|
||||
And they click "remove-allergy-p_s_01-nuts"
|
||||
Then they do not see "nuts"
|
||||
|
||||
# ── Rooms assign / unassign ────────────────────────────────────────────
|
||||
Scenario: admin assigns and then unassigns a participant to a room
|
||||
When they click "Zimmer"
|
||||
And they select "Anja Weber" from "assign-room-r_1"
|
||||
Then they see "Anja Weber"
|
||||
When they click "Entfernen"
|
||||
Then the field "assign-room-r_1" has value ""
|
||||
39
e2e/tests/features/auth.feature
Normal file
39
e2e/tests/features/auth.feature
Normal file
@@ -0,0 +1,39 @@
|
||||
@auth
|
||||
Feature: Authentication
|
||||
Users authenticate with email + password. Sessions are cookie-based.
|
||||
Roles (client / admin / owner) gate access to portals.
|
||||
|
||||
Scenario: client logs in and lands on their portal
|
||||
When "the client" logs in
|
||||
Then the URL contains "/"
|
||||
And they see "Seminarhof Drawehn"
|
||||
|
||||
Scenario: admin logs in and reaches the admin bookings list
|
||||
When "the admin" logs in
|
||||
And they visit "/admin/bookings"
|
||||
Then they see "Buchungen"
|
||||
And they see "Summer Yoga Retreat"
|
||||
|
||||
Scenario: owner logs in and reaches the admin bookings list
|
||||
When "the owner" logs in
|
||||
And they visit "/admin/bookings"
|
||||
Then they see "Buchungen"
|
||||
|
||||
Scenario: wrong password is rejected
|
||||
Given "the client" visits "/login"
|
||||
When they fill "input[type=email]" with "demo@yoga-retreat.example"
|
||||
And they fill "input[type=password]" with "wrong-password"
|
||||
And they click "Anmelden"
|
||||
Then they see "E-Mail oder Passwort ist falsch."
|
||||
|
||||
Scenario: client is redirected away from the admin portal
|
||||
When "the client" logs in
|
||||
And they visit "/admin/bookings"
|
||||
Then the URL does not contain "/admin/"
|
||||
|
||||
Scenario: logout clears the session
|
||||
Given "the client" is logged in
|
||||
When they visit "/logout"
|
||||
Then they see "Sie wurden abgemeldet. Bis bald."
|
||||
When they click "Zurück zur Anmeldung"
|
||||
Then the URL contains "/login"
|
||||
8
e2e/tests/features/availability.feature
Normal file
8
e2e/tests/features/availability.feature
Normal file
@@ -0,0 +1,8 @@
|
||||
@public @availability
|
||||
Feature: Public availability calendar
|
||||
Visitors can see which days the venue is free to book.
|
||||
|
||||
Scenario: visitor opens the availability calendar
|
||||
Given "a visitor" visits "/availability"
|
||||
Then they see "Seminarhof Drawehn"
|
||||
And they see "2026"
|
||||
43
e2e/tests/features/booking-full-flow.feature
Normal file
43
e2e/tests/features/booking-full-flow.feature
Normal file
@@ -0,0 +1,43 @@
|
||||
@booking @flow
|
||||
Feature: Full booking flow — enquiry through confirmed
|
||||
A client submits an enquiry via the public form. The admin then drives
|
||||
the booking through every step: approval, contract, deposit, confirmation.
|
||||
|
||||
# ── Guest: submit enquiry ───────────────────────────────────────────────
|
||||
Scenario: client submits an enquiry via the public form
|
||||
Given "a guest" visits "/enquiry"
|
||||
When they fill "courseName" with "E2E Full Flow Test"
|
||||
And they fill "startDate" with "2028-06-15"
|
||||
And they fill "endDate" with "2028-06-22"
|
||||
And they fill "organisationName" with "E2E Organisation"
|
||||
And they fill "contactEmail" with "e2e@example.com"
|
||||
And they turn on "agbAccepted"
|
||||
And they turn on "privacyAccepted"
|
||||
And they click "Anfrage absenden"
|
||||
Then they see "Ihre Anfrage ist eingegangen"
|
||||
|
||||
# ── Admin: full flow from enquiry to confirmed ──────────────────────────
|
||||
Scenario: admin drives a booking from enquiry through to confirmed
|
||||
Given the app data is reset
|
||||
And "the admin" is logged in
|
||||
|
||||
# 1. Open the seeded enquiry directly
|
||||
When they visit "/admin/bookings/b_lc_enquiry"
|
||||
|
||||
# 2. Approve the enquiry → reserved
|
||||
When they trigger booking action "action-approve-enquiry"
|
||||
Then they see "Reserviert"
|
||||
And the audit log tab includes "Reservierung bestätigt"
|
||||
|
||||
# 3. Send the contract manually (bypasses the 365-day cron window)
|
||||
When they trigger booking action "action-send-contract"
|
||||
Then the audit log tab includes "Vertrag & Anzahlungsrechnung"
|
||||
|
||||
# 4. Record the client's contract signature
|
||||
When they trigger booking action "action-contract-approved"
|
||||
Then they see "Anzahlung als erhalten markieren"
|
||||
|
||||
# 5. Record the deposit received → confirmed
|
||||
When they trigger booking action "action-deposit-received"
|
||||
Then they see "Bestätigt"
|
||||
And the audit log tab includes "Buchung bestätigt"
|
||||
26
e2e/tests/features/booking-lifecycle.feature
Normal file
26
e2e/tests/features/booking-lifecycle.feature
Normal file
@@ -0,0 +1,26 @@
|
||||
@admin @lifecycle
|
||||
Feature: Booking lifecycle — rule-based cron assertions
|
||||
Verifies each cron rule fires against pre-seeded bookings whose dates are
|
||||
computed relative to today in testReset, so the rules always trigger.
|
||||
|
||||
Background:
|
||||
Given the app data is reset
|
||||
And "the admin" is logged in
|
||||
|
||||
# ── R1: contract + deposit email ────────────────────────────────────────
|
||||
Scenario: lifecycle R1 — cron sends contract and deposit email to a reserved booking
|
||||
# b_lc_reserved: reserved, no contractSentAt, startDate 200 days away
|
||||
Then the lifecycle cron sent 1 contracts
|
||||
And the audit log for "b_lc_reserved" includes "Vertrag & Anzahlungsrechnung"
|
||||
|
||||
# ── R2: deposit reminder ─────────────────────────────────────────────────
|
||||
Scenario: lifecycle R2 — cron sends deposit reminder when deposit is 7+ days unpaid
|
||||
# b_lc_contract_sent: contractSentAt 8 days ago, deposit invoice unpaid
|
||||
Then the lifecycle cron sent 1 reminders
|
||||
And the audit log for "b_lc_contract_sent" includes "Anzahlungserinnerung"
|
||||
|
||||
# ── R4: auto-complete ────────────────────────────────────────────────────
|
||||
Scenario: lifecycle R4 — cron auto-completes a confirmed booking after it ends
|
||||
# b_lc_confirmed: confirmed, endDate yesterday
|
||||
Then the lifecycle cron completed 1 bookings
|
||||
And the booking "b_lc_confirmed" has status "Beendet"
|
||||
13
e2e/tests/features/events.feature
Normal file
13
e2e/tests/features/events.feature
Normal file
@@ -0,0 +1,13 @@
|
||||
@public @events
|
||||
Feature: Public events listing
|
||||
Anyone can browse the public retreats listing without logging in. Only
|
||||
bookings flagged for online listing appear here.
|
||||
|
||||
Scenario: visitor sees the published summer retreat
|
||||
Given "a visitor" visits "/events"
|
||||
Then they see "Summer Yoga Retreat 2026"
|
||||
And they see "Yoga Retreat e.V."
|
||||
|
||||
Scenario: unpublished retreats stay hidden
|
||||
Given "a visitor" visits "/events"
|
||||
Then they do not see "Winter Stille 2026"
|
||||
30
e2e/tests/features/invoices.feature
Normal file
30
e2e/tests/features/invoices.feature
Normal file
@@ -0,0 +1,30 @@
|
||||
@admin @invoices
|
||||
Feature: Invoice creation and payment recording
|
||||
Admin issues invoices against a booking and records payments when they
|
||||
arrive. Both actions create audit trail entries.
|
||||
|
||||
Background:
|
||||
Given "the admin" is logged in
|
||||
When they visit "/admin/bookings/b_yoga_2026_summer"
|
||||
And they click "Rechnungen"
|
||||
|
||||
Scenario: admin creates a final invoice
|
||||
When they create an invoice numbered "2026-FIN-002" for 1500.00 €
|
||||
Then they see "2026-FIN-002"
|
||||
And they see "Offen"
|
||||
|
||||
Scenario: admin creates an invoice with an attached PDF
|
||||
When they attach invoice PDF "invoice-sample.pdf"
|
||||
And they create an invoice numbered "2026-PDF-001" for 500.00 €
|
||||
Then they see "PDF öffnen"
|
||||
|
||||
Scenario: admin records a payment on an outstanding invoice
|
||||
When they create an invoice numbered "2026-PAY-001" for 250.00 €
|
||||
And they mark invoice "2026-PAY-001" as paid on "2026-05-10"
|
||||
Then they see "Bezahlt"
|
||||
|
||||
Scenario: admin cancels an outstanding invoice
|
||||
When they create an invoice numbered "2026-CXL-001" for 100.00 €
|
||||
And they accept the next confirmation
|
||||
And they click "invoice-cancel-2026-CXL-001"
|
||||
Then they see "Storniert"
|
||||
Reference in New Issue
Block a user