mirror of
https://github.com/pretix/pretix.git
synced 2026-05-07 15:34:02 +00:00
less flaky e2e tests
This commit is contained in:
@@ -742,7 +742,7 @@ def event_series(organizer):
|
|||||||
event=event,
|
event=event,
|
||||||
name=f'Concert Night {i+1}',
|
name=f'Concert Night {i+1}',
|
||||||
date_from=base_date + timedelta(days=i*2),
|
date_from=base_date + timedelta(days=i*2),
|
||||||
date_to=base_date + timedelta(days=i*2, hours=3),
|
date_to=base_date + timedelta(days=i*2, hours=2),
|
||||||
active=True,
|
active=True,
|
||||||
)
|
)
|
||||||
subevents.append(se)
|
subevents.append(se)
|
||||||
@@ -808,10 +808,16 @@ def widget_page(page):
|
|||||||
|
|
||||||
def wait_for_widget_load(self):
|
def wait_for_widget_load(self):
|
||||||
"""Wait for widget to finish loading."""
|
"""Wait for widget to finish loading."""
|
||||||
# Wait for widget element with longer timeout
|
|
||||||
self.page.wait_for_selector('.pretix-widget', timeout=15000)
|
self.page.wait_for_selector('.pretix-widget', timeout=15000)
|
||||||
# Give it a moment to render content
|
# Wait for loading spinner to be hidden (widget has rendered content)
|
||||||
self.page.wait_for_timeout(1000)
|
self.page.locator('.pretix-widget-loading').wait_for(state='hidden', timeout=15000)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def wait_for_loading_indicator(self, timeout=15000):
|
||||||
|
"""Wait for the loading indicator to appear and then disappear (display: none)."""
|
||||||
|
loading = self.page.locator('.pretix-widget-loading')
|
||||||
|
loading.wait_for(state='visible', timeout=timeout)
|
||||||
|
loading.wait_for(state='hidden', timeout=timeout)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def select_item_quantity(self, item_name: str, quantity: int):
|
def select_item_quantity(self, item_name: str, quantity: int):
|
||||||
@@ -824,6 +830,7 @@ def widget_page(page):
|
|||||||
number_input.wait_for(state='visible', timeout=5000)
|
number_input.wait_for(state='visible', timeout=5000)
|
||||||
if number_input.count() > 0:
|
if number_input.count() > 0:
|
||||||
number_input.fill(str(quantity))
|
number_input.fill(str(quantity))
|
||||||
|
number_input.dispatch_event('change')
|
||||||
else:
|
else:
|
||||||
# Maybe it's a checkbox (order_max=1)
|
# Maybe it's a checkbox (order_max=1)
|
||||||
checkbox = item_row.locator('input[type="checkbox"]').first
|
checkbox = item_row.locator('input[type="checkbox"]').first
|
||||||
@@ -845,6 +852,7 @@ def widget_page(page):
|
|||||||
# Find input
|
# Find input
|
||||||
input_field = variation.locator('input[type="number"]').first
|
input_field = variation.locator('input[type="number"]').first
|
||||||
input_field.fill(str(quantity))
|
input_field.fill(str(quantity))
|
||||||
|
input_field.dispatch_event('change')
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def click_buy_button(self):
|
def click_buy_button(self):
|
||||||
@@ -871,10 +879,27 @@ def widget_page(page):
|
|||||||
return iframe
|
return iframe
|
||||||
|
|
||||||
def close_iframe(self):
|
def close_iframe(self):
|
||||||
"""Close the checkout iframe."""
|
"""Close the checkout iframe and wait for the widget to reload.
|
||||||
|
|
||||||
|
The widget triggers a reload() when the iframe is closed
|
||||||
|
(without incrementing the loading counter), so we wait for
|
||||||
|
the XHR response to complete before returning.
|
||||||
|
"""
|
||||||
close_btn = self.page.locator('.pretix-widget-frame-close button')
|
close_btn = self.page.locator('.pretix-widget-frame-close button')
|
||||||
close_btn.click()
|
# Wait for the reload XHR that fires when the iframe closes
|
||||||
self.page.locator('.pretix-widget-frame-shown').wait_for(state='detached', timeout=5000)
|
with self.page.expect_response(
|
||||||
|
lambda r: 'widget/product_list' in r.url,
|
||||||
|
timeout=15000
|
||||||
|
):
|
||||||
|
close_btn.click()
|
||||||
|
self.page.locator('.pretix-widget-frame-shown').wait_for(
|
||||||
|
state='detached', timeout=5000
|
||||||
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def wait_for_view(self, selector: str, timeout=15000):
|
||||||
|
"""Wait for a specific element to appear after a view switch."""
|
||||||
|
self.page.locator(selector).first.wait_for(state='visible', timeout=timeout)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def expand_variations(self, item_name: str):
|
def expand_variations(self, item_name: str):
|
||||||
|
|||||||
@@ -6,9 +6,52 @@ from playwright.sync_api import Page, expect
|
|||||||
class TestEventSeriesJourney:
|
class TestEventSeriesJourney:
|
||||||
"""
|
"""
|
||||||
Complete purchase journeys for an event series.
|
Complete purchase journeys for an event series.
|
||||||
Tests the different views (calendar, list) and adds multiple items to the cart.
|
Tests the different views (calendar, list, week) and adds multiple items to the cart.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def test_multi_subevent_journey_calendar_view(
|
||||||
|
self,
|
||||||
|
page: Page,
|
||||||
|
live_server_url: str,
|
||||||
|
organizer,
|
||||||
|
event_series,
|
||||||
|
widget_page
|
||||||
|
):
|
||||||
|
event, _subevents = event_series
|
||||||
|
widget_page.goto(
|
||||||
|
live_server_url,
|
||||||
|
organizer.slug,
|
||||||
|
event.slug,
|
||||||
|
# **{'list-type': 'list'}
|
||||||
|
)
|
||||||
|
page.locator('.pretix-widget-event-calendar-event').first.click()
|
||||||
|
|
||||||
|
widget_page.select_item_quantity('Concert Ticket', 2)
|
||||||
|
widget_page.click_buy_button()
|
||||||
|
|
||||||
|
iframe = widget_page.wait_for_iframe_checkout()
|
||||||
|
expect(
|
||||||
|
iframe.locator('text=/45\\.00/').first
|
||||||
|
).to_be_visible(timeout=15000)
|
||||||
|
|
||||||
|
widget_page.close_iframe()
|
||||||
|
page.locator('a[rel="back"]').click()
|
||||||
|
|
||||||
|
widget_page.wait_for_view('.pretix-widget-event-calendar-next-month')
|
||||||
|
|
||||||
|
page.locator('.pretix-widget-event-calendar-next-month').click()
|
||||||
|
widget_page.wait_for_loading_indicator()
|
||||||
|
page.locator('.pretix-widget-event-calendar-event').first.click()
|
||||||
|
|
||||||
|
widget_page.select_item_quantity('Concert Ticket', 1)
|
||||||
|
widget_page.click_buy_button()
|
||||||
|
iframe = widget_page.wait_for_iframe_checkout()
|
||||||
|
|
||||||
|
# TODO a bit janky selector
|
||||||
|
expect(
|
||||||
|
iframe.locator('text=/90\\.00/').first
|
||||||
|
).to_be_visible(timeout=15000)
|
||||||
|
|
||||||
def test_multi_subevent_journey_list_view(
|
def test_multi_subevent_journey_list_view(
|
||||||
self,
|
self,
|
||||||
page: Page,
|
page: Page,
|
||||||
@@ -24,13 +67,9 @@ class TestEventSeriesJourney:
|
|||||||
event.slug,
|
event.slug,
|
||||||
**{'list-type': 'list'}
|
**{'list-type': 'list'}
|
||||||
)
|
)
|
||||||
# page.pause()
|
|
||||||
page.locator('.pretix-widget-event-list-entry').first.click()
|
page.locator('.pretix-widget-event-list-entry').first.click()
|
||||||
|
|
||||||
# expect(
|
|
||||||
# page.locator(
|
|
||||||
# '.pretix-widget-item:has-text("Concert Ticket")')
|
|
||||||
# ).to_be_visible(timeout=15000)
|
|
||||||
widget_page.select_item_quantity('Concert Ticket', 2)
|
widget_page.select_item_quantity('Concert Ticket', 2)
|
||||||
widget_page.click_buy_button()
|
widget_page.click_buy_button()
|
||||||
|
|
||||||
@@ -42,8 +81,54 @@ class TestEventSeriesJourney:
|
|||||||
widget_page.close_iframe()
|
widget_page.close_iframe()
|
||||||
page.locator('a[rel="back"]').click()
|
page.locator('a[rel="back"]').click()
|
||||||
|
|
||||||
|
widget_page.wait_for_view('.pretix-widget-event-list-entry')
|
||||||
|
|
||||||
page.locator('.pretix-widget-event-list-entry').nth(1).click()
|
page.locator('.pretix-widget-event-list-entry').nth(1).click()
|
||||||
|
|
||||||
|
widget_page.select_item_quantity('Concert Ticket', 1)
|
||||||
|
widget_page.click_buy_button()
|
||||||
|
iframe = widget_page.wait_for_iframe_checkout()
|
||||||
|
|
||||||
|
# TODO a bit janky selector
|
||||||
|
expect(
|
||||||
|
iframe.locator('text=/90\\.00/').first
|
||||||
|
).to_be_visible(timeout=15000)
|
||||||
|
|
||||||
|
def test_multi_subevent_journey_week_view(
|
||||||
|
self,
|
||||||
|
page: Page,
|
||||||
|
live_server_url: str,
|
||||||
|
organizer,
|
||||||
|
event_series,
|
||||||
|
widget_page
|
||||||
|
):
|
||||||
|
event, _subevents = event_series
|
||||||
|
widget_page.goto(
|
||||||
|
live_server_url,
|
||||||
|
organizer.slug,
|
||||||
|
event.slug,
|
||||||
|
**{'list-type': 'week'}
|
||||||
|
)
|
||||||
|
page.locator('.pretix-widget-event-calendar-event').first.click()
|
||||||
|
|
||||||
|
widget_page.select_item_quantity('Concert Ticket', 2)
|
||||||
|
widget_page.click_buy_button()
|
||||||
|
|
||||||
|
iframe = widget_page.wait_for_iframe_checkout()
|
||||||
|
expect(
|
||||||
|
iframe.locator('text=/45\\.00/').first
|
||||||
|
).to_be_visible(timeout=15000)
|
||||||
|
|
||||||
|
widget_page.close_iframe()
|
||||||
|
page.locator('a[rel="back"]').click()
|
||||||
|
|
||||||
|
widget_page.wait_for_view('.pretix-widget-event-calendar-event')
|
||||||
|
|
||||||
|
page.locator('.pretix-widget-event-calendar-next-month').click()
|
||||||
|
widget_page.wait_for_loading_indicator()
|
||||||
|
page.locator('.pretix-widget-event-calendar-event').first.click()
|
||||||
|
|
||||||
|
widget_page.select_item_quantity('Concert Ticket', 1)
|
||||||
widget_page.click_buy_button()
|
widget_page.click_buy_button()
|
||||||
iframe = widget_page.wait_for_iframe_checkout()
|
iframe = widget_page.wait_for_iframe_checkout()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user