wip: implement e2e tests with cypress

This commit is contained in:
Björn Fromme
2026-03-16 11:59:11 +01:00
parent 647fa8e212
commit 8436124cbc
9 changed files with 4194 additions and 1483 deletions
+8
View File
@@ -0,0 +1,8 @@
const {defineConfig} = require("cypress");
module.exports = defineConfig({
e2e: {
baseUrl: 'https://myep-next-booking.ddev.site',
supportFile: false,
},
});
+61
View File
@@ -0,0 +1,61 @@
describe('Booking test', () => {
it('Books a double room on test travel 1', () => {
cy.visit('/bookings/create/11946/157047')
cy.contains('Neue Buchung')
// await form refresh after selecting registration type
cy.intercept('POST', '/bookings/create/refresh').as('htmxRequest')
cy.get('#booking_create_step1_roomSelections_76_quantity').select('1')
cy.wait('@htmxRequest')
cy.intercept('POST', '/bookings/create').as('htmxRequest')
cy.get('[data-qa-btn-submit]').click()
cy.wait('@htmxRequest')
cy.intercept('GET', '/bookings/create/participants/0').as('htmxRequest')
cy.get('[data-qa-btn-edit-participant="0"]').click()
cy.wait('@htmxRequest')
cy.get('#booking_participant_firstName').type('Theo')
cy.get('#booking_participant_lastName').type('Test')
cy.get('#booking_participant_email').type('[email protected]')
cy.get('#booking_participant_mobile').type('1234567890')
cy.get('#booking_participant_address_street').type('Teststraße 1')
cy.get('#booking_participant_address_postCode').type('12345')
cy.get('#booking_participant_address_city').type('Testhausen')
cy.intercept('POST', '/bookings/create/participants/0/refresh').as('htmxRequest')
cy.get('#booking_participant_dateOfBirth').type('1980-11-11')
cy.get('#booking_participant_dateOfBirth').trigger('change')
cy.wait('@htmxRequest')
cy.get('#booking_participant_skiPass_0').check()
cy.intercept('POST', '/bookings/create/participants/0/refresh').as('htmxRequest')
cy.get('#booking_participant_courses_0').check()
cy.wait('@htmxRequest')
cy.intercept('POST', '/bookings/create/participants/0/refresh').as('htmxRequest')
cy.get('#booking_participant_insurance_0').check()
cy.wait('@htmxRequest')
cy.intercept('POST', '/bookings/create/participants/0/refresh').as('htmxRequest')
cy.get('#booking_participant_transportationOutbound_1').check()
cy.wait('@htmxRequest')
cy.intercept('POST', '/bookings/create/participants/0/refresh').as('htmxRequest')
cy.get('#booking_participant_transportationInbound_1').check()
cy.wait('@htmxRequest')
cy.intercept('POST', '/bookings/create/participants/0').as('htmxRequest')
cy.get('[data-qa-btn-submit]').click()
cy.wait('@htmxRequest')
cy.intercept('POST', '/bookings/create/participants').as('htmxRequest')
cy.get('[data-qa-btn-submit]').click()
cy.wait('@htmxRequest')
cy.get('[data-qa-alert-form-errors]').should('be.visible')
cy.get('[data-qa-participant-incomplete="1"]').should('be.visible')
})
})
+4070 -1434
View File
File diff suppressed because it is too large Load Diff
+36 -34
View File
@@ -1,36 +1,38 @@
{
"name": "myep-next",
"devDependencies": {
"@babel/core": "^7.17.0",
"@babel/preset-env": "^7.16.0",
"@hotwired/stimulus": "^3.0.0",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/webpack-encore": "^5.0.0",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"core-js": "^3.38.0",
"file-loader": "^6.2.0",
"htmx.org": "^1.9.12",
"postcss": "^8.4.49",
"postcss-loader": "^8.1.1",
"regenerator-runtime": "^0.13.9",
"tailwindcss": "^3.4.15",
"webpack": "^5.74.0",
"webpack-cli": "^5.1.0",
"webpack-notifier": "^1.15.0"
},
"license": "WTFPL",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
},
"dependencies": {
"@iframe-resizer/child": "^5.3.2",
"tippy.js": "^6.3.7",
"toastify-js": "^1.12.0"
}
"name": "myep-next",
"devDependencies": {
"@babel/core": "^7.17.0",
"@babel/preset-env": "^7.16.0",
"@hotwired/stimulus": "^3.0.0",
"@symfony/stimulus-bridge": "^3.2.0",
"@symfony/webpack-encore": "^5.0.0",
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
"autoprefixer": "^10.4.20",
"core-js": "^3.38.0",
"cypress": "^15.5.0",
"file-loader": "^6.2.0",
"htmx.org": "^1.9.12",
"postcss": "^8.4.49",
"postcss-loader": "^8.1.1",
"regenerator-runtime": "^0.13.9",
"tailwindcss": "^3.4.15",
"webpack": "^5.74.0",
"webpack-cli": "^5.1.0",
"webpack-notifier": "^1.15.0"
},
"license": "WTFPL",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress",
"cy:open": "cypress open"
},
"dependencies": {
"@iframe-resizer/child": "^5.3.2",
"tippy.js": "^6.3.7",
"toastify-js": "^1.12.0"
}
}
@@ -8,15 +8,15 @@
{{ isCanceled ? 'border-gray-400 bg-gray-50' : (hasErrors ? 'border-red-500 bg-red-50' : '') }}">
<div>
<div class="flex items-center gap-2">
<h3 class="font-semibold {{ hasErrors ? 'text-red-800' : (isCanceled ? 'text-gray-600' : '') }}">
<h3 class="font-semibold {{ hasErrors ? 'text-red-800' : (isCanceled ? 'text-gray-600' : '') }}" {{ qa_attribute('participant-name', index) }}>
{{ cardData.name }}
</h3>
{% if isCanceled %}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-700 text-white">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-700 text-white" {{ qa_attribute('participant-canceled', index) }}>
storniert
</span>
{% elseif hasErrors %}
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800">
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800" {{ qa_attribute('participant-incomplete', index) }}>
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path>
</svg>
@@ -24,10 +24,10 @@
</span>
{% endif %}
</div>
<p class="text-sm text-gray-600">{{ cardData.roomName }}</p>
<p class="text-sm text-gray-600" {{ qa_attribute('participant-room-name', index) }}>{{ cardData.roomName }}</p>
</div>
<div class="flex items-center gap-4">
<span class="font-medium {{ isCanceled ? 'text-gray-500' : '' }}">{{ cardData.price }}</span>
<span class="font-medium {{ isCanceled ? 'text-gray-500' : '' }}" {{ qa_attribute('participant-price', index) }}>{{ cardData.price }}</span>
{% if isCanceled %}
<button type="button"
class="button bg-button bg-button--secondary opacity-50 cursor-not-allowed"
@@ -41,7 +41,8 @@
class="button bg-button {{ hasErrors ? 'bg-button--primary' : 'bg-button--secondary' }}"
hx-get="{{ path('app_booking_edit_participant', {id: bookingId, index: index}) }}"
hx-target="#main-content"
hx-swap="innerHTML">
hx-swap="innerHTML"
{{ qa_attribute('btn-edit-participant', index) }}>
Bearbeiten
</button>
{% else %}
@@ -49,7 +50,8 @@
class="button bg-button {{ hasErrors ? 'bg-button--primary' : 'bg-button--secondary' }}"
hx-get="{{ path('app_booking_create_step_2_participant', {index: index}) }}"
hx-target="#main-content"
hx-swap="innerHTML">
hx-swap="innerHTML"
{{ qa_attribute('btn-edit-participant', index) }}>
Bearbeiten
</button>
{% endif %}
@@ -305,7 +305,8 @@
class="button bg-button bg-button--secondary"
hx-get="{{ path(cancelRouteName, cancelRouteParams|default({})) }}"
hx-target="#main-content"
hx-swap="innerHTML">
hx-swap="innerHTML"
{{ qa_attribute('btn-cancel') }}>
Abbrechen
</button>
{% else %}
@@ -313,11 +314,12 @@
class="button bg-button bg-button--secondary"
hx-get="{{ path('app_booking_create_step_2') }}"
hx-target="#main-content"
hx-swap="innerHTML">
hx-swap="innerHTML"
{{ qa_attribute('btn-cancel') }}>
Abbrechen
</button>
{% endif %}
<button type="submit" class="button bg-button bg-button--secondary">
<button type="submit" class="button bg-button bg-button--secondary" {{ qa_attribute('btn-submit') }}>
Speichern
</button>
</div>
+1 -1
View File
@@ -110,7 +110,7 @@
<div class="pt-4 border-t-2 border-gray-300">
<div class="flex justify-between items-center">
<span class="font-bold text-lg text-gray-800">Gesamtpreis:</span>
<span class="font-bold text-xl text-gray-900">
<span class="font-bold text-xl text-gray-900" {{ qa_attribute('summary-total') }}>
{{ pricingData.grandTotal|number_format(2, ',', '.') }}
</span>
</div>
+1 -1
View File
@@ -58,7 +58,7 @@
</div>
{% endblock %}
<div class="flex justify-end pt-4">
<button type="submit" class="button bg-button bg-button--secondary" {{ stimulus_action('loading', 'toggle') }}>Weiter</button>
<button type="submit" class="button bg-button bg-button--secondary" {{ qa_attribute('btn-submit')}} {{ stimulus_action('loading', 'toggle') }}>Weiter</button>
</div>
{{ form_rest(form) }}
{{ form_end(form) }}
+3 -3
View File
@@ -21,7 +21,7 @@
{# Display form-level validation errors #}
{% if form.vars.submitted and not form.vars.valid %}
<div class="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg">
<div class="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg" {{ qa_attribute('alert-form-errors') }}>
<div class="flex items-start">
<svg class="w-5 h-5 text-red-600 mr-2 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path>
@@ -47,10 +47,10 @@
</div>
<div class="flex justify-between mt-8">
<a href="{{ path('app_booking_create_step_1') }}" class="button bg-button bg-button--secondary">
<a href="{{ path('app_booking_create_step_1') }}" class="button bg-button bg-button--secondary" {{ qa_attribute('btn-back') }}>
Zurück
</a>
<button type="submit" class="button bg-button bg-button--secondary">
<button type="submit" class="button bg-button bg-button--secondary" {{ qa_attribute('btn-submit') }}>
Weiter
</button>
</div>