============================= test session starts ============================== created: 4/4 workers 4 workers [631 items] ss...................................................................... [ 11%] .............................................s.........................s [ 22%] ........................................................................ [ 34%] ........................................................................ [ 45%] ........................................................................ [ 57%] ........................................................................ [ 68%] ........................................................................ [ 79%] ....s..................................sss.....s..s..sss................ [ 91%] .......FFF........................F...........F..ss..s. [100%] =================================== FAILURES =================================== _________ TeamDeclarationsE2ETests.test_adhoc_individual_declarations __________ [gw1] linux -- Python 3.13.2 /opt/hostedtoolcache/Python/3.13.2/x64/bin/python self = [0m [37m@superuser_login_required [39;49;00m [90m [39;49;00m [94mdef [39;49;00m [90m [39;49;00m [92mtest_adhoc_individual_declarations [39;49;00m( [96mself [39;49;00m): [90m [39;49;00m [90m [39;49;00m [33m""" [39;49;00m [33m Test adhoc team declarations individual events e.g. /en-gb/x/3000/GBR/demo-interhouse-comp/te/BELET/adhoc/edit/. [39;49;00m [33m [39;49;00m [33m Summary: [39;49;00m [33m - User should be able to select athletes for individual events from the available athletes table and move across to the selected athletes table. [39;49;00m [33m - The list of available athletes should only contain those who match the criteria of the event e.g. if genders set to F then only girls should be showing up in selected. [39;49;00m [33m - Also check that the list contains only those in the correct age group. [39;49;00m [33m - Bulk import athletes into selectable table from the grid [39;49;00m [33m - Move athlete orderings up or down [39;49;00m [33m """ [39;49;00m [90m [39;49;00m [90m# 1. Setup: Use competition from fixture and create an adhoc TeamEntry [39;49;00m [90m [39;49;00m team_id = [33m' [39;49;00m [33mADHOC1 [39;49;00m [33m' [39;49;00m [90m [39;49;00m [90m# Organisation 4 is Veterans AC in the fixture [39;49;00m [90m [39;49;00m org_id = [33m' [39;49;00m [33m4 [39;49;00m [33m' [39;49;00m [90m# Use 'VAC' as team_id because it exists in the fixture as an Organisation (pk 4) [39;49;00m [90m [39;49;00m [90m# This avoiding the "Could not find org" warning/error in the view [39;49;00m [90m [39;49;00m team_id = [33m' [39;49;00m [33mVAC [39;49;00m [33m' [39;49;00m [90m [39;49;00m [90m [39;49;00m te = TeamEntry.objects.filter(competition= [96mself [39;49;00m.mc, team_id=team_id).first() [90m [39;49;00m [94mif [39;49;00m te: [90m [39;49;00m te.delete() [90m [39;49;00m [90m [39;49;00m te = TeamEntry( [90m [39;49;00m competition= [96mself [39;49;00m.mc, [90m [39;49;00m team_id=team_id, [90m [39;49;00m team_name= [33m' [39;49;00m [33mAdhoc Fixture Team [39;49;00m [33m' [39;49;00m, [90m [39;49;00m organisation_id=org_id, [90m [39;49;00m is_adhoc= [94mTrue [39;49;00m [90m [39;49;00m ) [90m [39;49;00m te.save() [90m [39;49;00m [90m [39;49;00m [90m# Update event limit and criteria to allow more athletes and make them available [39;49;00m [90m [39;49;00m [96mself [39;49;00m.mc.entry_limit_per_event = [94m10 [39;49;00m [90m [39;49;00m [96mself [39;49;00m.mc.athlete_criteria = [33m' [39;49;00m [33mANYONE [39;49;00m [33m' [39;49;00m [90m [39;49;00m [96mself [39;49;00m.mc.save() [90m [39;49;00m [90m [39;49;00m [90m# Update first event to be permissive [39;49;00m [90m [39;49;00m ev = EventSpec.objects.filter(competition= [96mself [39;49;00m.mc, event_code= [33m' [39;49;00m [33m100 [39;49;00m [33m' [39;49;00m).first() [90m [39;49;00m [94mif [39;49;00m ev: [90m [39;49;00m ev.genders = [33m' [39;49;00m [33mMF [39;49;00m [33m' [39;49;00m [90m [39;49;00m ev.age_groups = [ [33m' [39;49;00m [33mALL [39;49;00m [33m' [39;49;00m] [90m [39;49;00m ev.save() [90m [39;49;00m [90m [39;49;00m [90m# Create some competitors for the adhoc team [39;49;00m [90m [39;49;00m [90m# We'll use persons from organization 4 (Veterans AC) [39;49;00m [90m [39;49;00m p4 = Person.objects.filter(first_name= [33m' [39;49;00m [33mElizabeth [39;49;00m [33m' [39;49;00m, last_name= [33m' [39;49;00m [33mMiller [39;49;00m [33m' [39;49;00m, gender= [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m).first() [90m [39;49;00m p5 = Person.objects.filter(first_name= [33m' [39;49;00m [33mJames [39;49;00m [33m' [39;49;00m, last_name= [33m' [39;49;00m [33mSmith [39;49;00m [33m' [39;49;00m, gender= [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m).first() [90m [39;49;00m p3 = Person.objects.filter(first_name= [33m' [39;49;00m [33mMichael [39;49;00m [33m' [39;49;00m, last_name= [33m' [39;49;00m [33mDavis [39;49;00m [33m' [39;49;00m, gender= [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m).first() [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(p4, [33m" [39;49;00m [33mPerson [39;49;00m [33m' [39;49;00m [33mElizabeth Miller [39;49;00m [33m' [39;49;00m [33m not found in fixture [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(p5, [33m" [39;49;00m [33mPerson [39;49;00m [33m' [39;49;00m [33mJames Smith (M) [39;49;00m [33m' [39;49;00m [33m not found in fixture [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(p3, [33m" [39;49;00m [33mPerson [39;49;00m [33m' [39;49;00m [33mMichael Davis (M) [39;49;00m [33m' [39;49;00m [33m not found in fixture [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Athletes already in the event [39;49;00m [90m [39;49;00m selected_athletes = [p4, p5] [90m [39;49;00m [94mfor [39;49;00m idx, p [95min [39;49;00m [96menumerate [39;49;00m(selected_athletes): [90m [39;49;00m bib = [33mf [39;49;00m [33m" [39;49;00m [33mB [39;49;00m [33m{ [39;49;00midx+ [94m10 [39;49;00m [33m} [39;49;00m [33m" [39;49;00m [90m# Simple short bib [39;49;00m [90m [39;49;00m c = Competitor.objects.filter(competition= [96mself [39;49;00m.mc, competitor_id=bib).first() [90m [39;49;00m [94mif [39;49;00m c: [90m [39;49;00m c.delete() [90m [39;49;00m c = Competitor( [90m [39;49;00m competition= [96mself [39;49;00m.mc, [90m [39;49;00m competitor_id=bib, [90m [39;49;00m first_name=p.first_name, [90m [39;49;00m last_name=p.last_name, [90m [39;49;00m gender=p.gender, [90m [39;49;00m age_group= [33m' [39;49;00m [33mSEN [39;49;00m [33m' [39;49;00m, [90m [39;49;00m category= [33m' [39;49;00m [33mSM [39;49;00m [33m' [39;49;00m [94mif [39;49;00m p.gender == [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m [94melse [39;49;00m [33m' [39;49;00m [33mSW [39;49;00m [33m' [39;49;00m, [90m [39;49;00m team_id=team_id, [90m [39;49;00m ot_athlete_id= [96mstr [39;49;00m(p.id), [90m [39;49;00m date_of_birth=p.date_of_birth, [90m [39;49;00m is_team_entry= [94mTrue [39;49;00m, [90m [39;49;00m numbered= [94mTrue [39;49;00m [90m [39;49;00m ) [90m [39;49;00m c.events_entered.append(Entry(event_id= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m, event_code= [33m' [39;49;00m [33m100 [39;49;00m [33m' [39;49;00m, idx=idx)) [90m [39;49;00m c.save() [90m [39;49;00m [90m [39;49;00m [90m# Athlete available but not in event [39;49;00m [90m [39;49;00m bib = [33m" [39;49;00m [33mB12 [39;49;00m [33m" [39;49;00m [90m [39;49;00m c = Competitor.objects.filter(competition= [96mself [39;49;00m.mc, competitor_id=bib).first() [90m [39;49;00m [94mif [39;49;00m c: [90m [39;49;00m c.delete() [90m [39;49;00m c = Competitor( [90m [39;49;00m competition= [96mself [39;49;00m.mc, [90m [39;49;00m competitor_id=bib, [90m [39;49;00m first_name=p3.first_name, [90m [39;49;00m last_name=p3.last_name, [90m [39;49;00m gender=p3.gender, [90m [39;49;00m age_group= [33m' [39;49;00m [33mSEN [39;49;00m [33m' [39;49;00m, [90m [39;49;00m category= [33m' [39;49;00m [33mSM [39;49;00m [33m' [39;49;00m, [90m [39;49;00m team_id=team_id, [90m [39;49;00m ot_athlete_id= [96mstr [39;49;00m(p3.id), [90m [39;49;00m date_of_birth=p3.date_of_birth, [90m [39;49;00m is_team_entry= [94mTrue [39;49;00m, [90m [39;49;00m numbered= [94mTrue [39;49;00m [90m [39;49;00m ) [90m [39;49;00m c.save() [90m [39;49;00m [90m [39;49;00m url = reverse( [33m' [39;49;00m [33mcomp-team-entry-adhoc-edit [39;49;00m [33m' [39;49;00m, kwargs={ [90m [39;49;00m [33m' [39;49;00m [33myear [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.sc.year, [90m [39;49;00m [33m' [39;49;00m [33mcountry [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.sc.country.alpha3, [90m [39;49;00m [33m' [39;49;00m [33mslug [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.sc.slug, [90m [39;49;00m [33m' [39;49;00m [33mteam_id [39;49;00m [33m' [39;49;00m: team_id [90m [39;49;00m }) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mNavigating to: [39;49;00m [33m{ [39;49;00murl [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00murl [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Selectors [39;49;00m [90m [39;49;00m [90m# Inside #individual_entries_tab, the athlete tables are in: [39;49;00m [90m [39;49;00m [90m# .col-md-9 > .card.min-vh-75 > .card-body > .row:nth-child(3) > .col-lg-5 [39;49;00m [90m [39;49;00m [90m# nth-child(1) = Assigned, nth-child(3) = Available [39;49;00m [90m [39;49;00m available_table_selector = [33m" [39;49;00m [33m#individual_entries_tab .card-body .row:last-child .col-lg-5:nth-child(3) table [39;49;00m [33m" [39;49;00m [90m [39;49;00m selected_table_selector = [33m" [39;49;00m [33m#individual_entries_tab .card-body .row:last-child .col-lg-5:nth-child(1) table [39;49;00m [33m" [39;49;00m [90m [39;49;00m promote_btn_selector = [33m" [39;49;00m [33m#indivPromoteBtn [39;49;00m [33m" [39;49;00m [90m [39;49;00m demote_btn_selector = [33m" [39;49;00m [33m#indivDemoteBtn [39;49;00m [33m" [39;49;00m [90m [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mWaiting for Vue app to load... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m WebDriverWait( [96mself [39;49;00m.selenium, [94m30 [39;49;00m).until( [90m [39;49;00m EC.invisibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m[v-cloak] [39;49;00m [33m" [39;49;00m)) [90m [39;49;00m ) [90m [39;49;00m [90m [39;49;00m [90m# Select event code '100' in the sidebar if not already selected [39;49;00m [90m [39;49;00m [90m# Vue renders :data-eventCode as data-eventcode (lowercase) [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSelecting event 100... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m event_link = WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m).until( [90m [39;49;00m EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[data-eventcode= [39;49;00m [33m' [39;49;00m [33m100 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m)) [90m [39;49;00m ) [90m [39;49;00m event_link.click() [90m [39;49;00m [90m [39;49;00m [90m# Wait for the tabs to update and click the category tab (e.g. 'ALL') [39;49;00m [90m [39;49;00m [90m# The tab has :data-label="ev.category" [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSelecting category ALL... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m category_tab = WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m).until( [90m [39;49;00m EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[data-label= [39;49;00m [33m' [39;49;00m [33mALL [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m)) [90m [39;49;00m ) [90m [39;49;00m category_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [94mfor [39;49;00m c [95min [39;49;00m Competitor.objects.filter(competition= [96mself [39;49;00m.mc, team_id=team_id): [90m [39;49;00m c.events_entered = [e [94mfor [39;49;00m e [95min [39;49;00m c.events_entered [94mif [39;49;00m e.event_id != [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m] [90m [39;49;00m c.save() [90m [39;49;00m [90m [39;49;00m [90m# Refresh to pick up cleared state [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.get( [96mself [39;49;00m.selenium.current_url) [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m[v-cloak] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [90m [39;49;00m [90m# Re-select event and category [39;49;00m [90m [39;49;00m WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m).until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[data-eventcode= [39;49;00m [33m' [39;49;00m [33m100 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))).click() [90m [39;49;00m WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m).until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[data-label= [39;49;00m [33m' [39;49;00m [33mALL [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))).click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# --- Part 1: Move from Available to Selected using double-click --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mMoving athlete from Available to Selected using double-click... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, available_table_selector))) [90m [39;49;00m [90m [39;49;00m rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mavailable_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m visible_rows = [r [94mfor [39;49;00m r [95min [39;49;00m rows [94mif [39;49;00m r.is_displayed() [95mand [39;49;00m [33m" [39;49;00m [33mmuted [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m r.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m [96mself [39;49;00m.assertTrue( [96mlen [39;49;00m(visible_rows) > [94m0 [39;49;00m, [33m" [39;49;00m [33mNo available eligible athletes found [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m athlete_row = visible_rows[ [94m0 [39;49;00m] [90m [39;49;00m athlete_text = athlete_row.text [90m [39;49;00m [90m# Extract the name - skip first word (badge ID) and get remaining text [39;49;00m [90m [39;49;00m words = athlete_text.split() [90m [39;49;00m athlete_name = [33m' [39;49;00m [33m [39;49;00m [33m' [39;49;00m.join(words[ [94m1 [39;49;00m:]) [94mif [39;49;00m [96mlen [39;49;00m(words) > [94m1 [39;49;00m [94melse [39;49;00m words[ [94m0 [39;49;00m] [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mDouble-clicking on athlete: [39;49;00m [33m{ [39;49;00mathlete_name [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Get count of available athletes before double-click [39;49;00m [90m [39;49;00m available_count_before = [96mlen [39;49;00m(visible_rows) [90m [39;49;00m [90m [39;49;00m [90m# Use double-click to assign directly (bypasses highlight/promote flow) [39;49;00m [90m [39;49;00m [94mfrom [39;49;00m [90m [39;49;00m [04m [96mselenium [39;49;00m [04m [96m. [39;49;00m [04m [96mwebdriver [39;49;00m [04m [96m. [39;49;00m [04m [96mcommon [39;49;00m [04m [96m. [39;49;00m [04m [96maction_chains [39;49;00m [90m [39;49;00m [94mimport [39;49;00m ActionChains [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.move_to_element(athlete_row).double_click().perform() [90m [39;49;00m [90m# If double click is flaky, try execute_script for dblclick [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mvar evt = new MouseEvent( [39;49;00m [33m' [39;49;00m [33mdblclick [39;49;00m [33m' [39;49;00m [33m, [39;49;00m [33m{ [39;49;00m [33mbubbles: true, cancelable: true, view: window}); arguments[0].dispatchEvent(evt); [39;49;00m [33m" [39;49;00m, athlete_row) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Verify athlete was moved (available count should decrease by 1) [39;49;00m [90m [39;49;00m available_rows_after = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mavailable_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m available_count_after = [96mlen [39;49;00m([r [94mfor [39;49;00m r [95min [39;49;00m available_rows_after [94mif [39;49;00m r.is_displayed() [95mand [39;49;00m [33m" [39;49;00m [33mmuted [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m r.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m)]) [90m [39;49;00m [96mself [39;49;00m.assertEqual(available_count_after, available_count_before - [94m1 [39;49;00m, [33mf [39;49;00m [33m" [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m [33m{ [39;49;00mathlete_name [33m} [39;49;00m [33m' [39;49;00m [33m should have been removed from available table [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Additional: Test Promote button functionality --- [39;49;00m [90m [39;49;00m [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_text = [r.text [94mfor [39;49;00m r [95min [39;49;00m selected_rows] [90m [39;49;00m [90m [39;49;00m [90m# demote test [39;49;00m [90m [39;49;00m [90m [39;49;00m [94mif [39;49;00m [96mlen [39;49;00m(selected_rows): [90m [39;49;00m row_to_demote = selected_rows[ [96mlen [39;49;00m(selected_rows)- [94m1 [39;49;00m] [90m [39;49;00m [90m [39;49;00m [90m# click it to highlight it [39;49;00m [90m [39;49;00m row_to_demote.click() [90m [39;49;00m [90m [39;49;00m [90m# then click demote button [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mdemote_btn_selector [33m} [39;49;00m [33m" [39;49;00m)[ [94m0 [39;49;00m].click() [90m [39;49;00m [90m [39;49;00m [90m# check they are no longer in select table [39;49;00m [90m [39;49;00m recheck_selected_text = [r.text [94mfor [39;49;00m r [95min [39;49;00m [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m found = [96many [39;49;00m(athlete_name [95min [39;49;00m text [94mfor [39;49;00m text [95min [39;49;00m recheck_selected_text) [90m [39;49;00m [96mself [39;49;00m.assertFalse(found, [33mf [39;49;00m [33m" [39;49;00m [33mAthlete [39;49;00m [33m{ [39;49;00mathlete_name [33m} [39;49;00m [33m was found in the selected table after being demoted! [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mavailable_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m visible_rows = [r [94mfor [39;49;00m r [95min [39;49;00m rows [94mif [39;49;00m r.is_displayed() [95mand [39;49;00m [33m" [39;49;00m [33mmuted [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m r.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m [90m [39;49;00m [90m# Select second athlete for promote test [39;49;00m [90m [39;49;00m [94mif [39;49;00m [96mlen [39;49;00m(visible_rows): [90m [39;49;00m second_athlete_row = visible_rows[ [94m0 [39;49;00m] [90m [39;49;00m second_athlete_text = second_athlete_row.text [90m [39;49;00m [90m# Extract the name - skip first word (badge ID) and get remaining text [39;49;00m [90m [39;49;00m words = second_athlete_text.split() [90m [39;49;00m second_athlete_name = [33m' [39;49;00m [33m [39;49;00m [33m' [39;49;00m.join(words[ [94m1 [39;49;00m:]) [94mif [39;49;00m [96mlen [39;49;00m(words) > [94m1 [39;49;00m [94melse [39;49;00m words[ [94m0 [39;49;00m] [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mTesting promote button with second athlete: [39;49;00m [33m{ [39;49;00msecond_athlete_name [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Highlight the athlete using click [39;49;00m [90m [39;49;00m second_athlete_row.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Check if promote button is available and click it [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m promote_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, promote_btn_selector) [90m [39;49;00m [94mif [39;49;00m promote_btn.is_enabled() [95mand [39;49;00m [33m" [39;49;00m [33mdisabled [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m promote_btn.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m): [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mClicking promote button... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, promote_btn) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mClicked promote button. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Verify it moved to the selected table [39;49;00m [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_text = [r.text [94mfor [39;49;00m r [95min [39;49;00m selected_rows] [90m [39;49;00m found_second = [96many [39;49;00m(second_athlete_name [95min [39;49;00m text [94mfor [39;49;00m text [95min [39;49;00m selected_text) [90m [39;49;00m [96mself [39;49;00m.assertTrue(found_second, [33mf [39;49;00m [33m" [39;49;00m [33mSecond athlete [39;49;00m [33m' [39;49;00m [33m{ [39;49;00msecond_athlete_name [33m} [39;49;00m [33m' [39;49;00m [33m was not moved to the selected table using promote button [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSecond athlete successfully tested with promote button [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mexcept [39;49;00m [96mException [39;49;00m [94mas [39;49;00m e: [90m [39;49;00m [96mprint [39;49;00m(e) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mPromote button test skipped - button not available or not functional [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mNot enough athletes to test promote button [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mAthletes successfully tested with both double-click and promote button (when available) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Part 2: Add via Grid --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mOpening [39;49;00m [33m' [39;49;00m [33mBulk Entry (Excel) [39;49;00m [33m' [39;49;00m [33m grid... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m add_athlete_btn = [96mself [39;49;00m.selenium.find_element(By.XPATH, [33m" [39;49;00m [33m//button[contains(text(), [39;49;00m [33m' [39;49;00m [33mBulk Entry (Excel) [39;49;00m [33m' [39;49;00m [33m)] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m add_athlete_btn.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m ht_container_selector = [33m" [39;49;00m [33m#addCompetitorContainer [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ht_container_selector))) [90m [39;49;00m [90m [39;49;00m ht_selector = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mht_container_selector [33m} [39;49;00m [33m table.htCore [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ht_selector))) [90m [39;49;00m [90m [39;49;00m [90m# Use more persons from fixture for grid input [39;49;00m [90m [39;49;00m p6 = Person.objects.filter(first_name= [33m" [39;49;00m [33mJames [39;49;00m [33m" [39;49;00m, last_name= [33m" [39;49;00m [33mSmith [39;49;00m [33m" [39;49;00m, gender= [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m).first() [90m [39;49;00m p7 = Person.objects.filter(first_name= [33m" [39;49;00m [33mJohn [39;49;00m [33m" [39;49;00m, last_name= [33m" [39;49;00m [33mMartinez [39;49;00m [33m" [39;49;00m).first() [90m [39;49;00m p8 = Person.objects.filter(first_name= [33m" [39;49;00m [33mMichael [39;49;00m [33m" [39;49;00m, last_name= [33m" [39;49;00m [33mMiller [39;49;00m [33m" [39;49;00m, gender= [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m).first() [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(p6, [33m" [39;49;00m [33mPerson [39;49;00m [33m' [39;49;00m [33mJames Smith (F) [39;49;00m [33m' [39;49;00m [33m not found in fixture [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(p7, [33m" [39;49;00m [33mPerson [39;49;00m [33m' [39;49;00m [33mJohn Martinez [39;49;00m [33m' [39;49;00m [33m not found in fixture [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(p8, [33m" [39;49;00m [33mPerson [39;49;00m [33m' [39;49;00m [33mMichael Miller (F) [39;49;00m [33m' [39;49;00m [33m not found in fixture [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m new_athletes = [ [90m [39;49;00m (p6.first_name, p6.last_name, p6.date_of_birth.isoformat(), p6.gender), [90m [39;49;00m (p7.first_name, p7.last_name, p7.date_of_birth.isoformat(), p7.gender), [90m [39;49;00m (p8.first_name, p8.last_name, p8.date_of_birth.isoformat(), p8.gender), [90m [39;49;00m ] [90m [39;49;00m [90m [39;49;00m [94mfrom [39;49;00m [90m [39;49;00m [04m [96mselenium [39;49;00m [04m [96m. [39;49;00m [04m [96mwebdriver [39;49;00m [04m [96m. [39;49;00m [04m [96mcommon [39;49;00m [04m [96m. [39;49;00m [04m [96maction_chains [39;49;00m [90m [39;49;00m [94mimport [39;49;00m ActionChains [90m [39;49;00m [90m [39;49;00m [94mfor [39;49;00m i, (first, last, dob, gender) [95min [39;49;00m [96menumerate [39;49;00m(new_athletes): [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mInputting grid athlete [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m: [39;49;00m [33m{ [39;49;00mfirst [33m} [39;49;00m [33m [39;49;00m [33m{ [39;49;00mlast [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m cell_xpath = [33mf [39;49;00m [33m" [39;49;00m [33m//div[@id= [39;49;00m [33m' [39;49;00m [33mcompetitors_ht [39;49;00m [33m' [39;49;00m [33m]//table[@class= [39;49;00m [33m' [39;49;00m [33mhtCore [39;49;00m [33m' [39;49;00m [33m]/tbody/tr[ [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m]/td[1] [39;49;00m [33m" [39;49;00m [90m [39;49;00m cell = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, cell_xpath))) [90m [39;49;00m [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.move_to_element(cell).click().perform() [90m [39;49;00m time.sleep( [94m0.3 [39;49;00m) [90m [39;49;00m [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.send_keys(first) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(last) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(dob) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(gender) [90m [39;49;00m actions.send_keys(Keys.ENTER) [90m [39;49;00m actions.perform() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Note: The "Add Athletes" button doesn't exist in the template. [39;49;00m [90m [39;49;00m [90m# Bulk entry data is saved via the handsontable's internal state when saveEntry is called. [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Verify grid is in sync with selected athletes after double-click [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mVerifying grid is in sync with selected athletes... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m# Wait for Vue to update [39;49;00m [90m [39;49;00m grid_data = [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mreturn window.competitor_ht ? window.competitor_ht.getData() : []; [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_rows_after_dblclick = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_names = [r.text [94mfor [39;49;00m r [95min [39;49;00m selected_rows_after_dblclick] [90m [39;49;00m [90m [39;49;00m [90m# Check that all selected athletes appear in the grid [39;49;00m [90m [39;49;00m [94mfor [39;49;00m row [95min [39;49;00m selected_rows_after_dblclick: [90m [39;49;00m row_text = row.text [90m [39;49;00m words = row_text.split() [90m [39;49;00m [90m# Skip badge ID (first word) [39;49;00m [90m [39;49;00m athlete_name = [33m' [39;49;00m [33m [39;49;00m [33m' [39;49;00m.join(words[ [94m1 [39;49;00m:]) [94mif [39;49;00m [96mlen [39;49;00m(words) > [94m1 [39;49;00m [94melse [39;49;00m words[ [94m0 [39;49;00m] [90m [39;49;00m found_in_grid = [96many [39;49;00m(athlete_name.split()[ [94m0 [39;49;00m] [95min [39;49;00m [96mstr [39;49;00m(row) [95mor [39;49;00m athlete_name.split()[- [94m1 [39;49;00m] [95min [39;49;00m [96mstr [39;49;00m(row) [94mfor [39;49;00m row [95min [39;49;00m grid_data [94mif [39;49;00m row) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mChecking athlete [39;49;00m [33m' [39;49;00m [33m{ [39;49;00mathlete_name [33m} [39;49;00m [33m' [39;49;00m [33m in grid: [39;49;00m [33m{ [39;49;00m [33m' [39;49;00m [33mFound [39;49;00m [33m' [39;49;00m [90m [39;49;00m [94mif [39;49;00m [90m [39;49;00mfound_in_grid [90m [39;49;00m [94melse [39;49;00m [90m [39;49;00m [33m' [39;49;00m [33mNot found [39;49;00m [33m' [39;49;00m [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mGrid is in sync with selected athletes after double-click. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Part 2b: Add new athletes via grid and verify they appear in selected table --- [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Wait for Vue to process the grid changes and trigger update [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mWaiting for grid sync... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Trigger the Vue update manually to ensure sync [39;49;00m [90m [39;49;00m [90m# self.selenium.execute_script("if (window.app && window.app.updateCompetitorsHandsOnTable) { window.app.updateCompetitorsHandsOnTable(); }") [39;49;00m [90m [39;49;00m [90m# time.sleep(1) [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Check grid data to see what's actually in it [39;49;00m [90m [39;49;00m grid_data = [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mreturn window.competitor_ht ? window.competitor_ht.getData() : []; [39;49;00m [33m" [39;49;00m) [90m [39;49;00m grid_count = [96mlen [39;49;00m([r [94mfor [39;49;00m r [95min [39;49;00m grid_data [94mif [39;49;00m r [95mand [39;49;00m r.get( [33m' [39;49;00m [33mfirst_name [39;49;00m [33m' [39;49;00m)]) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mGrid has [39;49;00m [33m{ [39;49;00mgrid_count [33m} [39;49;00m [33m athletes after entry [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify selected table and grid are in sync [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mVerifying grid and selected table are in sync... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_count = [96mlen [39;49;00m(selected_rows) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mSelected table has [39;49;00m [33m{ [39;49;00mselected_count [33m} [39;49;00m [33m athletes, Grid has [39;49;00m [33m{ [39;49;00mgrid_count [33m} [39;49;00m [33m athletes [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# The grid should be in sync with selected athletes (grid is loaded from selectedAthletes) [39;49;00m [90m [39;49;00m [90m# Note: Some athletes from grid may have been filtered if they don't meet criteria [39;49;00m [90m [39;49;00m [90m# So we just verify that both have athletes and grid/selected are consistent [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertGreater(selected_count, [94m0 [39;49;00m, [33m" [39;49;00m [33mSelected table should have athletes [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertEqual(grid_count, selected_count, [33m" [39;49;00m [33mGrid row count should match selected table count [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mGrid and selected table are in sync. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Also verify grid is in sync with selected table [39;49;00m [90m [39;49;00m grid_data = [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mreturn window.competitor_ht ? window.competitor_ht.getData() : []; [39;49;00m [33m" [39;49;00m) [90m [39;49;00m final_selected_count = [96mlen [39;49;00m( [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m)) [90m [39;49;00m expected_grid_rows = final_selected_count [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mGrid has [39;49;00m [33m{ [39;49;00m [96mlen [39;49;00m([r [90m [39;49;00m [94mfor [39;49;00m [90m [39;49;00mr [90m [39;49;00m [95min [39;49;00m [90m [39;49;00mgrid_data [90m [39;49;00m [94mif [39;49;00m [90m [39;49;00mr [90m [39;49;00m [95mand [39;49;00m [90m [39;49;00m [96many [39;49;00m(r.values())]) [33m} [39;49;00m [33m rows, selected table has [39;49;00m [33m{ [39;49;00mfinal_selected_count [33m} [39;49;00m [33m rows [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Part 3: Save and Refresh --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSaving... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mwindow.scrollTo(0, 0); [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# The save button has class "btn-primary btn-sm rounded-pill px-4 shadow-sm" [39;49;00m [90m [39;49;00m save_btn = WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m).until( [90m [39;49;00m EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton.btn-primary.btn-sm [39;49;00m [33m" [39;49;00m)) [90m [39;49;00m ) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, save_btn) [90m [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33mspan.bg-success-light span.fa-check [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [94mexcept [39;49;00m: [90m [39;49;00m [94mpass [39;49;00m [90m [39;49;00m [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Part 4: Refresh and verify persistence --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mRefreshing page... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.refresh() [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m[v-cloak] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mRe-selecting event... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m event_link = WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m).until( [90m [39;49;00m EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[data-eventcode= [39;49;00m [33m' [39;49;00m [33m100 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m)) [90m [39;49;00m ) [90m [39;49;00m event_link.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mVerifying persistence after refresh... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m# Get selected table state after refresh [39;49;00m [90m [39;49;00m selected_rows_after_refresh = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mselected_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_text_after_refresh = [r.text [94mfor [39;49;00m r [95min [39;49;00m selected_rows_after_refresh] [90m [39;49;00m [90m [39;49;00m [90m# Verify some athletes persisted (not checking specific ones since test flow may have changed selection) [39;49;00m [90m [39;49;00m selected_count_after_refresh = [96mlen [39;49;00m(selected_rows_after_refresh) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mSelected table has [39;49;00m [33m{ [39;49;00mselected_count_after_refresh [33m} [39;49;00m [33m athletes after refresh [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify grid is in sync with selected table after refresh [39;49;00m [90m [39;49;00m [90m# Re-open the bulk entry grid to check its contents [39;49;00m [90m [39;49;00m add_athlete_btn = [96mself [39;49;00m.selenium.find_element(By.XPATH, [33m" [39;49;00m [33m//button[contains(text(), [39;49;00m [33m' [39;49;00m [33mBulk Entry (Excel) [39;49;00m [33m' [39;49;00m [33m)] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m add_athlete_btn.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ht_container_selector))) [90m [39;49;00m [90m [39;49;00m grid_data_after_refresh = [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mreturn window.competitor_ht ? window.competitor_ht.getData() : []; [39;49;00m [33m" [39;49;00m) [90m [39;49;00m grid_count_after_refresh = [96mlen [39;49;00m([r [94mfor [39;49;00m r [95min [39;49;00m grid_data_after_refresh [94mif [39;49;00m r [95mand [39;49;00m [96many [39;49;00m(r.values())]) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mAfter refresh - Selected table: [39;49;00m [33m{ [39;49;00mselected_count_after_refresh [33m} [39;49;00m [33m athletes, Grid: [39;49;00m [33m{ [39;49;00mgrid_count_after_refresh [33m} [39;49;00m [33m rows [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify selected table has athletes (at least some should have been saved) [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertGreater(selected_count_after_refresh, [94m0 [39;49;00m, [33m" [39;49;00m [33mSelected table should have athletes after refresh [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Grid and selected table should be in sync [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertEqual(grid_count_after_refresh, selected_count_after_refresh, [90m [39;49;00m [33mf [39;49;00m [33m" [39;49;00m [33mGrid row count ( [39;49;00m [33m{ [39;49;00mgrid_count_after_refresh [33m} [39;49;00m [33m) should match selected table count ( [39;49;00m [33m{ [39;49;00mselected_count_after_refresh [33m} [39;49;00m [33m) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mGrid and selected table are in sync after refresh. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mAll athletes persisted correctly! [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mTest completed successfully! [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [94mexcept [39;49;00m [96mException [39;49;00m [94mas [39;49;00m e: [90m [39;49;00m [96mself [39;49;00m.selenium.save_screenshot( [33m" [39;49;00m [33mtest_adhoc_indiv_failure.png [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mwith [39;49;00m [96mopen [39;49;00m( [33m" [39;49;00m [33mtest_adhoc_indiv_failure_source.html [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33mw [39;49;00m [33m" [39;49;00m) [94mas [39;49;00m f: [90m [39;49;00m f.write( [96mself [39;49;00m.selenium.page_source) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mTest failed: [39;49;00m [33m{ [39;49;00me [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m > [94mraise [39;49;00m e [90m [39;49;00m project/comp/tests/test_team_declarations.py:735: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ project/comp/tests/test_team_declarations.py:722: in test_adhoc_individual_declarations [0m [96mself [39;49;00m.assertEqual(grid_count_after_refresh, selected_count_after_refresh, [90m [39;49;00m E AssertionError: 0 != 1 : Grid row count (0) should match selected table count (1) ____________ SeedingE2ETests.test_three_round_championship_seeding _____________ [gw2] linux -- Python 3.13.2 /opt/hostedtoolcache/Python/3.13.2/x64/bin/python self = [0m [94mdef [39;49;00m [90m [39;49;00m [92mtest_three_round_championship_seeding [39;49;00m( [96mself [39;49;00m): [90m [39;49;00m [90m [39;49;00m [33m""" [39;49;00m [33m E2E test for multi-round seeding. [39;49;00m [33m """ [39;49;00m [90m [39;49;00m wait = WebDriverWait( [96mself [39;49;00m.selenium, [94m10 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Login [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m [94mfrom [39;49;00m [90m [39;49;00m [04m [96mdjango [39;49;00m [04m [96m. [39;49;00m [04m [96murls [39;49;00m [90m [39;49;00m [94mimport [39;49;00m reverse [90m [39;49;00m login_path = reverse( [33m' [39;49;00m [33mlogin [39;49;00m [33m' [39;49;00m) [90m [39;49;00m login_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mlogin_path [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [94mexcept [39;49;00m [96mException [39;49;00m [94mas [39;49;00m e: [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mError reversing login URL: [39;49;00m [33m{ [39;49;00me [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m login_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m/en-gb/accounts/login/ [39;49;00m [33m" [39;49;00m [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mLogging in at [39;49;00m [33m{ [39;49;00mlogin_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get(login_url) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mCurrent URL: [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.selenium.current_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [94mfrom [39;49;00m [90m [39;49;00m [04m [96mproject [39;49;00m [04m [96m. [39;49;00m [04m [96mreference [39;49;00m [04m [96m. [39;49;00m [04m [96mmongo [39;49;00m [04m [96m. [39;49;00m [04m [96munit [39;49;00m [90m [39;49;00m [94mimport [39;49;00m Unit [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mDEBUG TEST: Competitor count for event 1: [39;49;00m [33m{ [39;49;00mCompetitor.objects(competition= [96mself [39;49;00m.c, [90m [39;49;00mevents_entered__event_id= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m).count() [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m ev1 = [96mself [39;49;00m.c.get_event( [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mDEBUG TEST: Unit count for event 1: [39;49;00m [33m{ [39;49;00mUnit.objects(competition= [96mself [39;49;00m.c, [90m [39;49;00mevent=ev1).count() [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m username_field = wait.until(EC.presence_of_element_located((By.ID, [33m" [39;49;00m [33mid_username [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mFound username field [39;49;00m [33m" [39;49;00m) [90m [39;49;00m username_field.send_keys( [33m" [39;49;00m [33msuperuser [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.find_element(By.ID, [33m" [39;49;00m [33mid_password [39;49;00m [33m" [39;49;00m).send_keys( [33m" [39;49;00m [33msecret [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.find_element(By.ID, [33m" [39;49;00m [33mloginBtn [39;49;00m [33m" [39;49;00m).click() [90m [39;49;00m [94mexcept [39;49;00m: [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mTimeout or Error at login. Current URL: [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.selenium.current_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mPage source snippet: [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.selenium.page_source[: [94m2000 [39;49;00m] [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mraise [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Wait for login to complete by checking for a logout link or a specific dashboard element [39;49;00m [90m [39;49;00m wait.until( [94mlambda [39;49;00m d: d.current_url != login_url) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mLogged in, current URL: [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.selenium.current_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Navigate to event detail private page [39;49;00m [90m [39;49;00m event_private_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mcomp_reverse( [33m' [39;49;00m [33mcomp-event-detail-private [39;49;00m [33m' [39;49;00m, [90m [39;49;00m [96mself [39;49;00m.sql_comp, [90m [39;49;00mevent_id= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m) [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mNavigating to [39;49;00m [33m{ [39;49;00mevent_private_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get(event_private_url) [90m [39;49;00m time.sleep( [94m3 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Round 1: Heats [39;49;00m [90m [39;49;00m [90m# make sure heats tab is selected [39;49;00m [90m [39;49;00m heats_tab = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-heats [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m heats_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mRound 1: Heats [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m# Open Seeding Options (it's a collapsible) [39;49;00m [90m [39;49;00m seeding_options_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton[data-target= [39;49;00m [33m' [39;49;00m [33m#seeding_options_r1 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mFound seeding options button [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mcollapsed [39;49;00m [33m" [39;49;00m [95min [39;49;00m seeding_options_btn.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m): [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mExpanding seeding options [39;49;00m [33m" [39;49;00m) [90m [39;49;00m ActionChains( [96mself [39;49;00m.selenium).click(seeding_options_btn).perform() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Click 'Seed heats' [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mClicking Seed heats [39;49;00m [33m" [39;49;00m) [90m [39;49;00m seed_btn = wait.until(EC.element_to_be_clickable((By.NAME, [33m" [39;49;00m [33mseed [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m seed_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m# Wait for seeding to complete (it reloads the page) [39;49;00m [90m [39;49;00m [90m [39;49;00m heats_tab = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-heats [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m heats_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Accept the upcoming confirm dialog [39;49;00m [90m [39;49;00m [96mself [39;49;00m.accept_confirm() [90m [39;49;00m [90m [39;49;00m [90m# Click 'Fake results' [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mClicking Fake results [39;49;00m [33m" [39;49;00m) [90m [39;49;00m fake_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-heats .fake_results [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m fake_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m heats_tab = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-heats [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m heats_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Accept the upcoming confirm dialog [39;49;00m [90m [39;49;00m [96mself [39;49;00m.accept_confirm() [90m [39;49;00m [90m [39;49;00m [90m# Click 'Mark qualifiers' [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mClicking Mark qualifiers [39;49;00m [33m" [39;49;00m) [90m [39;49;00m mark_btn = wait.until(EC.element_to_be_clickable((By.NAME, [33m" [39;49;00m [33mmark_qualifiers [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m mark_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Round 2: Semi-finals [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mRound 2: Semi-finals [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m# Switch to Semi-finals tab [39;49;00m [90m [39;49;00m semi_tab = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-semifinal [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m semi_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Re-open Seeding Options if needed (it might be different form) [39;49;00m [90m [39;49;00m [90m# For Round 2, the form is in #pills-semifinal [39;49;00m [90m [39;49;00m semi_seeding_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-semifinal button[data-target= [39;49;00m [33m' [39;49;00m [33m#seeding_options_r2 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mcollapsed [39;49;00m [33m" [39;49;00m [95min [39;49;00m semi_seeding_btn.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m): [90m [39;49;00m semi_seeding_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Seed heats for semi-finals [39;49;00m [90m [39;49;00m seed_semi_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-semifinal button[name= [39;49;00m [33m' [39;49;00m [33mseed [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m seed_semi_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Accept the upcoming confirm dialog [39;49;00m [90m [39;49;00m [96mself [39;49;00m.accept_confirm() [90m [39;49;00m [90m [39;49;00m [90m# Fake results for semi-finals [39;49;00m [90m [39;49;00m fake_semi_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-semifinal .fake_results [39;49;00m [33m" [39;49;00m) [90m [39;49;00m fake_semi_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Mark qualifiers for semi-finals [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until( [94mlambda [39;49;00m _ : [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-semifinal button[name= [39;49;00m [33m' [39;49;00m [33mmark_qualifiers [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m).is_displayed()) [90m [39;49;00m mark_semi_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-semifinal button[name= [39;49;00m [33m' [39;49;00m [33mmark_qualifiers [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m mark_semi_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.reset_mouse_position() [90m [39;49;00m [90m [39;49;00m [90m# Round 3: Finals [39;49;00m [90m [39;49;00m [90m# Switch to Finals tab [39;49;00m [90m [39;49;00m final_tab = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-final [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m final_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Seed final [39;49;00m [90m [39;49;00m [90m# Re-open Seeding Options if needed (it might be different form) [39;49;00m [90m [39;49;00m final_seeding_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-final button[data-target= [39;49;00m [33m' [39;49;00m [33m#finalSeedingForm [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mcollapsed [39;49;00m [33m" [39;49;00m [95min [39;49;00m final_seeding_btn.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m): [90m [39;49;00m final_seeding_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m seed_final_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#finalSeedingForm button[name= [39;49;00m [33m' [39;49;00m [33mseed [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m seed_final_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify athletes in final heat table [39;49;00m [90m [39;49;00m [90m# There should be a table within #pills-final [39;49;00m [90m [39;49;00m [90m# The final round table should have 8 athletes [39;49;00m [90m [39;49;00m final_results = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-final tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Filter for rows that have a bib (not empty lanes) [39;49;00m [90m [39;49;00m athletes_in_final = [row [94mfor [39;49;00m row [95min [39;49;00m final_results [94mif [39;49;00m row.find_elements(By.XPATH, [33m" [39;49;00m [33m./td[2][normalize-space()] [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mAthletes in final: [39;49;00m [33m{ [39;49;00m [96mlen [39;49;00m(athletes_in_final) [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m > [96mself [39;49;00m.assertEqual( [96mlen [39;49;00m(athletes_in_final), [94m8 [39;49;00m, [33m" [39;49;00m [33mShould have 8 athletes in the final [39;49;00m [33m" [39;49;00m) [90m [39;49;00m E AssertionError: 0 != 8 : Should have 8 athletes in the final project/comp/tests/test_seeding.py:1912: AssertionError ______________ CompE2ETests.test_record_length_and_height_events _______________ [gw3] linux -- Python 3.13.2 /opt/hostedtoolcache/Python/3.13.2/x64/bin/python self = [0m [94mdef [39;49;00m [90m [39;49;00m [92mtest_record_length_and_height_events [39;49;00m( [96mself [39;49;00m): [90m [39;49;00m [90m [39;49;00m [33m"""E2E test for recording results on length (LJ) and height (HJ) events.""" [39;49;00m [90m [39;49;00m [96mself [39;49;00m.login() [90m [39;49;00m [90m [39;49;00m [90m# ============================================== [39;49;00m [90m [39;49;00m [90m# PART 1: Long Jump (Length Event with Wind) [39;49;00m [90m [39;49;00m [90m# ============================================== [39;49;00m [90m [39;49;00m lj_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mcomp_reverse( [33m' [39;49;00m [33mcomp-unit-record [39;49;00m [33m' [39;49;00m, [90m [39;49;00m [96mself [39;49;00m.sql_comp, [90m [39;49;00mevent_id= [33m' [39;49;00m [33m3 [39;49;00m [33m' [39;49;00m, [90m [39;49;00m [96mround [39;49;00m= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m, [90m [39;49;00mheat= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m) [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mLJ recording URL: [39;49;00m [33m{ [39;49;00mlj_url [33m} [39;49;00m [33m" [39;49;00m, flush= [94mTrue [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get(lj_url) [90m [39;49;00m time.sleep( [94m3 [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mCurrent URL: [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.selenium.current_url [33m} [39;49;00m [33m" [39;49;00m, flush= [94mTrue [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mPage title: [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.selenium.title [33m} [39;49;00m [33m" [39;49;00m, flush= [94mTrue [39;49;00m) [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m body = [96mself [39;49;00m.selenium.find_element(By.TAG_NAME, [33m" [39;49;00m [33mbody [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mBody text: [39;49;00m [33m{ [39;49;00mbody.text[: [94m1500 [39;49;00m] [33m} [39;49;00m [33m" [39;49;00m, flush= [94mTrue [39;49;00m) [90m [39;49;00m [94mexcept [39;49;00m [96mException [39;49;00m [94mas [39;49;00m e: [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mFailed to get body: [39;49;00m [33m{ [39;49;00me [33m} [39;49;00m [33m" [39;49;00m, flush= [94mTrue [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.save_screenshot( [33m' [39;49;00m [33m/tmp/lj_page.png [39;49;00m [33m' [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.accept_confirm() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.wait.until( [94mlambda [39;49;00m _: [96mlen [39;49;00m( [96mself [39;49;00m._length_starter_rows()) > [94m0 [39;49;00m) [90m [39;49;00m athletes = [96mself [39;49;00m._length_starter_rows() [90m [39;49;00m [96mself [39;49;00m.assertGreater( [96mlen [39;49;00m(athletes), [94m0 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Click first athlete and record a valid jump with wind [39;49;00m [90m [39;49;00m athletes[ [94m0 [39;49;00m].click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [96mself [39;49;00m._record_length_trial(distance= [33m" [39;49;00m [33m6.50 [39;49;00m [33m" [39;49;00m, wind= [33m" [39;49;00m [33m+1.2 [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify the trial was saved [39;49;00m [90m [39;49;00m first_bib = athletes[ [94m0 [39;49;00m].find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m.col-xs-1:nth-child(2) [39;49;00m [33m" [39;49;00m).text.strip() [90m [39;49;00m trial_container = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33mdiv[id= [39;49;00m [33m' [39;49;00m [33m{ [39;49;00mfirst_bib [33m} [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33m6.50 [39;49;00m [33m" [39;49;00m, trial_container.text) [90m [39;49;00m [90m [39;49;00m [90m# Delete the result by clicking remove last observation button [39;49;00m [90m [39;49;00m remove_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33m.del.focused .btn-danger [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m remove_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Re-record a different distance for first athlete [39;49;00m [90m [39;49;00m rows = [96mself [39;49;00m._length_starter_rows() [90m [39;49;00m rows[ [94m0 [39;49;00m].click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [96mself [39;49;00m._record_length_trial(distance= [33m" [39;49;00m [33m6.80 [39;49;00m [33m" [39;49;00m, wind= [33m" [39;49;00m [33m+0.5 [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Record results for remaining athletes [39;49;00m [90m [39;49;00m [94mfor [39;49;00m idx [95min [39;49;00m [96mrange [39;49;00m( [94m1 [39;49;00m, [96mlen [39;49;00m(athletes)): [90m [39;49;00m rows = [96mself [39;49;00m._length_starter_rows() [90m [39;49;00m rows[idx].click() [90m [39;49;00m time.sleep( [94m0.3 [39;49;00m) [90m [39;49;00m [94mif [39;49;00m idx == [94m1 [39;49;00m: [90m [39;49;00m [96mself [39;49;00m._record_length_trial(is_foul= [94mTrue [39;49;00m) [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m [96mself [39;49;00m._record_length_trial(distance= [33m" [39;49;00m [33m5.00 [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m0.3 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Click Finish [39;49;00m [90m [39;49;00m finish_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton[title= [39;49;00m [33m' [39;49;00m [33mFinish [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m finish_btn.click() [90m [39;49;00m time.sleep( [94m1.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# ============================================== [39;49;00m [90m [39;49;00m [90m# PART 2: High Jump (Height Event) [39;49;00m [90m [39;49;00m [90m# ============================================== [39;49;00m [90m [39;49;00m hj_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mcomp_reverse( [33m' [39;49;00m [33mcomp-unit-record [39;49;00m [33m' [39;49;00m, [90m [39;49;00m [96mself [39;49;00m.sql_comp, [90m [39;49;00mevent_id= [33m' [39;49;00m [33m9 [39;49;00m [33m' [39;49;00m, [90m [39;49;00m [96mround [39;49;00m= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m, [90m [39;49;00mheat= [33m' [39;49;00m [33m1 [39;49;00m [33m' [39;49;00m) [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.get(hj_url) [90m [39;49;00m [96mself [39;49;00m.accept_confirm() [90m [39;49;00m time.sleep( [94m3 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Set bar height [39;49;00m [90m [39;49;00m form_well = [96mself [39;49;00m.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33mform.well [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m raise_btn = form_well.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton.btn-info [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, raise_btn) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m new_height_input = form_well.find_element(By.NAME, [33m" [39;49;00m [33mnew_height [39;49;00m [33m" [39;49;00m) [90m [39;49;00m new_height_input.clear() [90m [39;49;00m new_height_input.send_keys( [33m" [39;49;00m [33m1.80 [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m confirm_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, [33m" [39;49;00m [33m//button[text()= [39;49;00m [33m' [39;49;00m [33mConfirm [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m confirm_btn.click() [90m [39;49;00m time.sleep( [94m1.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Find jumper rows [39;49;00m [90m [39;49;00m jumper_rows = [94mlambda [39;49;00m: [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33m" [39;49;00m [33mtable.table tbody > tr:not(.obs) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.wait.until( [94mlambda [39;49;00m _: [96mlen [39;49;00m(jumper_rows()) > [94m0 [39;49;00m) [90m [39;49;00m jumpers = jumper_rows() [90m [39;49;00m [96mself [39;49;00m.assertGreater( [96mlen [39;49;00m(jumpers), [94m0 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Record O/X for each jumper [39;49;00m [90m [39;49;00m [94mfor [39;49;00m idx [95min [39;49;00m [96mrange [39;49;00m( [96mlen [39;49;00m(jumpers)): [90m [39;49;00m jumpers = jumper_rows() [90m [39;49;00m jumpers[idx].click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m obs_record_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mtr.obs a.btn-warning [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m obs_record_btn.click() [90m [39;49;00m modal = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.ID, [33m" [39;49;00m [33mobsEntry [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [94mif [39;49;00m idx == [94m1 [39;49;00m: [90m [39;49;00m modal.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m.btn-danger [39;49;00m [33m" [39;49;00m).click() [90m [39;49;00m [90m [39;49;00m obs_record_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mtr.obs a.btn-warning [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m obs_record_btn.click() [90m [39;49;00m modal = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.ID, [33m" [39;49;00m [33mobsEntry [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [90m [39;49;00m modal.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m.btn-danger [39;49;00m [33m" [39;49;00m).click() [90m [39;49;00m [90m [39;49;00m obs_record_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mtr.obs a.btn-warning [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m obs_record_btn.click() [90m [39;49;00m modal = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.ID, [33m" [39;49;00m [33mobsEntry [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [90m [39;49;00m modal.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m.btn-success [39;49;00m [33m" [39;49;00m).click() [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m modal.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m.btn-success [39;49;00m [33m" [39;49;00m).click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.invisibility_of_element_located((By.ID, [33m" [39;49;00m [33mobsEntry [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [90m [39;49;00m [90m# Finish the height event [39;49;00m [90m [39;49;00m hj_finish_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton.btn-primary[title= [39;49;00m [33m' [39;49;00m [33mFinish [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m hj_finish_btn.click() [90m [39;49;00m time.sleep( [94m1.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# ============================================== [39;49;00m [90m [39;49;00m [90m# PART 3: Verify HJ results persistence [39;49;00m [90m [39;49;00m [90m# ============================================== [39;49;00m [90m [39;49;00m time.sleep( [94m2 [39;49;00m) [90m# ensure finish API call has completed [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Re-navigate to HJ recording page to verify data persisted [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.get(hj_url) [90m [39;49;00m [96mself [39;49;00m.accept_confirm() [90m [39;49;00m time.sleep( [94m3 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Wait for jumper rows and verify count [39;49;00m [90m [39;49;00m jumper_rows = [94mlambda [39;49;00m: [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33m" [39;49;00m [33mtable.table tbody > tr:not(.obs) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m > [96mself [39;49;00m.wait.until( [94mlambda [39;49;00m _: [96mlen [39;49;00m(jumper_rows()) > [94m0 [39;49;00m) [90m [39;49;00m project/comp/tests/test_comp_e2e.py:205: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = method = . at 0x7f3992e940e0> message = '' [0m [94mdef [39;49;00m [90m [39;49;00m [92muntil [39;49;00m( [96mself [39;49;00m, method: Callable[[D], Union[Literal[ [94mFalse [39;49;00m], T]], message: [96mstr [39;49;00m = [33m" [39;49;00m [33m" [39;49;00m) -> T: [90m [39;49;00m [90m [39;49;00m [33m"""Wait until the method returns a value that is not False. [39;49;00m [33m [39;49;00m [33m Calls the method provided with the driver as an argument until the [39;49;00m [33m return value does not evaluate to ``False``. [39;49;00m [33m [39;49;00m [33m Parameters: [39;49;00m [33m ----------- [39;49;00m [33m method: callable(WebDriver) [39;49;00m [33m - A callable object that takes a WebDriver instance as an argument. [39;49;00m [33m [39;49;00m [33m message: str [39;49;00m [33m - Optional message for :exc:`TimeoutException` [39;49;00m [33m [39;49;00m [33m Return: [39;49;00m [33m ------- [39;49;00m [33m object: T [39;49;00m [33m - The result of the last call to `method` [39;49;00m [33m [39;49;00m [33m Raises: [39;49;00m [33m ------- [39;49;00m [33m TimeoutException [39;49;00m [33m - If 'method' does not return a truthy value within the WebDriverWait [39;49;00m [33m object's timeout [39;49;00m [33m [39;49;00m [33m Example: [39;49;00m [33m -------- [39;49;00m [33m >>> from selenium.webdriver.common.by import By [39;49;00m [33m >>> from selenium.webdriver.support.ui import WebDriverWait [39;49;00m [33m >>> from selenium.webdriver.support import expected_conditions as EC [39;49;00m [33m [39;49;00m [33m # Wait until an element is visible on the page [39;49;00m [33m >>> wait = WebDriverWait(driver, 10) [39;49;00m [33m >>> element = wait.until(EC.visibility_of_element_located((By.ID, "exampleId"))) [39;49;00m [33m >>> print(element.text) [39;49;00m [33m """ [39;49;00m [90m [39;49;00m screen = [94mNone [39;49;00m [90m [39;49;00m stacktrace = [94mNone [39;49;00m [90m [39;49;00m [90m [39;49;00m end_time = time.monotonic() + [96mself [39;49;00m._timeout [90m [39;49;00m [94mwhile [39;49;00m [94mTrue [39;49;00m: [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m value = method( [96mself [39;49;00m._driver) [90m [39;49;00m [94mif [39;49;00m value: [90m [39;49;00m [94mreturn [39;49;00m value [90m [39;49;00m [94mexcept [39;49;00m [96mself [39;49;00m._ignored_exceptions [94mas [39;49;00m exc: [90m [39;49;00m screen = [96mgetattr [39;49;00m(exc, [33m" [39;49;00m [33mscreen [39;49;00m [33m" [39;49;00m, [94mNone [39;49;00m) [90m [39;49;00m stacktrace = [96mgetattr [39;49;00m(exc, [33m" [39;49;00m [33mstacktrace [39;49;00m [33m" [39;49;00m, [94mNone [39;49;00m) [90m [39;49;00m [94mif [39;49;00m time.monotonic() > end_time: [90m [39;49;00m [94mbreak [39;49;00m [90m [39;49;00m time.sleep( [96mself [39;49;00m._poll) [90m [39;49;00m > [94mraise [39;49;00m TimeoutException(message, screen, stacktrace) [90m [39;49;00m E selenium.common.exceptions.TimeoutException: Message: /opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/selenium/webdriver/support/wait.py:146: TimeoutException ____________ TeamDeclarationsE2ETests.test_adhoc_relay_declarations ____________ [gw1] linux -- Python 3.13.2 /opt/hostedtoolcache/Python/3.13.2/x64/bin/python self = [0m [37m@superuser_login_required [39;49;00m [90m [39;49;00m [94mdef [39;49;00m [90m [39;49;00m [92mtest_adhoc_relay_declarations [39;49;00m( [96mself [39;49;00m): [90m [39;49;00m [90m [39;49;00m [33m""" [39;49;00m [33m Test adhoc team declarations relays. [39;49;00m [33m [39;49;00m [33m Summary: [39;49;00m [33m - Change the team category for a relay team should save after change. [39;49;00m [33m - Select 4 athletes to fill a 4x400 relay event from the available athletes table and move them across to selected table. [39;49;00m [33m - Click the save button and check that they persist after save and refreshing page. [39;49;00m [33m - Use the up and down arrows to change the order of the relay athletes [39;49;00m [33m - Click save and check that the ordering persists after refreshing page. [39;49;00m [33m - Use the relay grid to input two athletes. Check that any existing athletes are not editible through the grid. [39;49;00m [33m - Once finished inputting, check that the athletes show in the selected athletes table and their ordering can be changed. [39;49;00m [33m - Click save and check that the ordering persists after refreshing page. [39;49;00m [33m - Create two new relay team by clicking the plus button. [39;49;00m [33m - Check that the relayteam_id is set to the next character in the alpherbet. [39;49;00m [33m - Click save and check that the ordering persists after refreshing page. [39;49;00m [33m - Add some athletes to the last team then remove the middle relay team and check that the last team is updated. [39;49;00m [33m - If relayteam_id was ADHOC1-C then it should now be ADHOC1-B and the athletes event entries for this relay team should be updated also. [39;49;00m [33m """ [39;49;00m [90m [39;49;00m [90m# 1. Setup: Create a new adhoc TeamEntry (no organisation) [39;49;00m [90m [39;49;00m team_id = [33m' [39;49;00m [33mADHOC1 [39;49;00m [33m' [39;49;00m [90m [39;49;00m te = TeamEntry.objects.filter(competition= [96mself [39;49;00m.mc, team_id=team_id).first() [90m [39;49;00m [94mif [39;49;00m te: [90m [39;49;00m te.delete() [90m [39;49;00m [90m [39;49;00m te = TeamEntry( [90m [39;49;00m competition= [96mself [39;49;00m.mc, [90m [39;49;00m team_id=team_id, [90m [39;49;00m team_name= [33m' [39;49;00m [33mAdhoc Team 1 [39;49;00m [33m' [39;49;00m, [90m [39;49;00m is_adhoc= [94mTrue [39;49;00m [90m [39;49;00m ) [90m [39;49;00m te.save() [90m [39;49;00m [90m [39;49;00m [90m# 1.5 Set some competition settings [39;49;00m [90m [39;49;00m [96mself [39;49;00m.mc.relay_extra_reserves = [94m4 [39;49;00m [90m [39;49;00m [96mself [39;49;00m.mc.save() [90m [39;49;00m [90m [39;49;00m [90m# 2. Setup: Create competitors for this team [39;49;00m [90m [39;49;00m [90m# We need at least 4 for a relay (4x400) [39;49;00m [90m [39;49;00m runners_data = [ [90m [39;49;00m ( [94m1 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mOne [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2015-01-01 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m2 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mTwo [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2015-01-02 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m3 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mThree [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2010-01-03 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m4 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mFour [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2010-01-04 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ] [90m [39;49;00m [90m [39;49;00m reserve_runners_data = [ [90m [39;49;00m ( [94m5 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mFive [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2015-01-01 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m6 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mSix [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2015-01-02 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m7 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mSeven [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2010-01-03 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m8 [39;49;00m, [33m' [39;49;00m [33mAthlete [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mEight [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2010-01-04 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ] [90m [39;49;00m [90m [39;49;00m competitors = [] [90m [39;49;00m [94mfor [39;49;00m idx, first, last, dob, gender [95min [39;49;00m runners_data: [90m [39;49;00m bib = [33mf [39;49;00m [33m" [39;49;00m [33mA [39;49;00m [33m{ [39;49;00midx [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m c = Competitor.objects.filter(competition= [96mself [39;49;00m.mc, competitor_id=bib).first() [90m [39;49;00m [94mif [39;49;00m c: [90m [39;49;00m c.delete() [90m [39;49;00m c = Competitor( [90m [39;49;00m competition= [96mself [39;49;00m.mc, [90m [39;49;00m competitor_id=bib, [90m [39;49;00m first_name=first, [90m [39;49;00m last_name=last, [90m [39;49;00m gender=gender, [90m [39;49;00m age_group= [33m' [39;49;00m [33mSEN [39;49;00m [33m' [39;49;00m, [90m [39;49;00m category= [33m' [39;49;00m [33mSM [39;49;00m [33m' [39;49;00m, [90m [39;49;00m team_id=team_id, [90m [39;49;00m date_of_birth=date.fromisoformat(dob), [90m [39;49;00m is_team_entry= [94mTrue [39;49;00m, [90m [39;49;00m numbered= [94mTrue [39;49;00m [90m [39;49;00m ) [90m [39;49;00m c.save() [90m [39;49;00m competitors.append(c) [90m [39;49;00m [90m [39;49;00m [90m# Ensure a relay event exists [39;49;00m [90m [39;49;00m relay_event = [96mnext [39;49;00m((ev [94mfor [39;49;00m ev [95min [39;49;00m [96mself [39;49;00m.mc.get_events() [94mif [39;49;00m ev.event_code.startswith( [33m' [39;49;00m [33m4x [39;49;00m [33m' [39;49;00m)), [94mNone [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m relay_event: [90m [39;49;00m [90m# try to find any event with 'relay' in name [39;49;00m [90m [39;49;00m relay_event = [96mnext [39;49;00m((ev [94mfor [39;49;00m ev [95min [39;49;00m [96mself [39;49;00m.mc.get_events() [94mif [39;49;00m [33m' [39;49;00m [33mrelay [39;49;00m [33m' [39;49;00m [95min [39;49;00m ev.name.lower()), [94mNone [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(relay_event, [33m" [39;49;00m [33mNo relay event found in competition [39;49;00m [33m" [39;49;00m) [90m [39;49;00m relay_event_id = relay_event.event_id [90m [39;49;00m [90m [39;49;00m [90m# Ensure the relay team exists for this adhoc team [39;49;00m [90m [39;49;00m created, rt = get_or_create_relayteam( [96mself [39;49;00m.mc, relay_event_id, team_id) [90m [39;49;00m [90m [39;49;00m [90m# sync to TeamEntry object for team declarations [39;49;00m [90m [39;49;00m te.sync_from_relay_teams(force= [94mTrue [39;49;00m) [90m [39;49;00m te.save() [90m [39;49;00m te = TeamEntry.objects.filter(competition= [96mself [39;49;00m.mc, team_id=team_id).first() [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mTeamEntry relay teams [39;49;00m [33m" [39;49;00m, te.relay_teams) [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(rt, [33m" [39;49;00m [33mFailed to get or create relay team [39;49;00m [33m" [39;49;00m) [90m [39;49;00m rt.bib = [33m' [39;49;00m [33m100 [39;49;00m [33m' [39;49;00m [90m# Give it a bib [39;49;00m [90m [39;49;00m rt.save() [90m [39;49;00m [90m [39;49;00m [90m# 3. Navigate to the adhoc relay entry page [39;49;00m [90m [39;49;00m url = reverse( [33m' [39;49;00m [33mcomp-team-entry-adhoc-edit [39;49;00m [33m' [39;49;00m, kwargs={ [90m [39;49;00m [33m' [39;49;00m [33myear [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.year, [90m [39;49;00m [33m' [39;49;00m [33mcountry [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.country, [90m [39;49;00m [33m' [39;49;00m [33mslug [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.slug, [90m [39;49;00m [33m' [39;49;00m [33mteam_id [39;49;00m [33m' [39;49;00m: team_id [90m [39;49;00m }) [90m [39;49;00m full_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00murl [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mNavigating to: [39;49;00m [33m{ [39;49;00mfull_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get(full_url) [90m [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mWaiting for Vue app to load... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m[v-cloak] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [90m [39;49;00m [90m# --- Step 1: Relay Teams Tab --- [39;49;00m [90m [39;49;00m relay_tab_link = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#relay_teams_tab [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m relay_tab_link.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Select the relay event [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mSelecting relay event [39;49;00m [33m{ [39;49;00mrelay_event.name [33m} [39;49;00m [33m... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m event_btn_xpath = [33mf [39;49;00m [33m" [39;49;00m [33m//a[@data-eventid= [39;49;00m [33m' [39;49;00m [33m{ [39;49;00mrelay_event_id [33m} [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m [90m [39;49;00m event_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, event_btn_xpath))) [90m [39;49;00m event_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- New: Select athletes from available table using promote button --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m--- Testing selection from available table --- [39;49;00m [33m" [39;49;00m) [90m [39;49;00m relay_available_table_selector = [33m" [39;49;00m [33m#relay_teams_tab .card-body .row:last-child .col-lg-5:nth-child(3) table [39;49;00m [33m" [39;49;00m [90m [39;49;00m relay_selected_table_selector = [33m" [39;49;00m [33m#relay_teams_tab .card-body .row:last-child .col-lg-5:nth-child(1) table [39;49;00m [33m" [39;49;00m [90m [39;49;00m relay_promote_btn_selector = [33m" [39;49;00m [33m#relayPromoteBtn [39;49;00m [33m" [39;49;00m [90m [39;49;00m relay_demote_btn_selector = [33m" [39;49;00m [33m#relayDemoteBtn [39;49;00m [33m" [39;49;00m [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, relay_available_table_selector))) [90m [39;49;00m [90m [39;49;00m [90m# Select 4 runners [39;49;00m [90m [39;49;00m [94mfor [39;49;00m i [95min [39;49;00m [96mrange [39;49;00m( [94m4 [39;49;00m): [90m [39;49;00m rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_available_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m visible_rows = [r [94mfor [39;49;00m r [95min [39;49;00m rows [94mif [39;49;00m r.is_displayed() [95mand [39;49;00m [33m" [39;49;00m [33mmuted [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m r.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m [96mself [39;49;00m.assertTrue( [96mlen [39;49;00m(visible_rows) > [94m0 [39;49;00m, [33mf [39;49;00m [33m" [39;49;00m [33mNo available eligible athletes found at step [39;49;00m [33m{ [39;49;00mi [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m athlete_row = visible_rows[ [94m0 [39;49;00m] [90m [39;49;00m athlete_name = athlete_row.text [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mSelecting athlete [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m: [39;49;00m [33m{ [39;49;00mathlete_name [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m athlete_row.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m promote_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, relay_promote_btn_selector) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, promote_btn) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify 4 runners in selected table [39;49;00m [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_selected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertEqual( [96mlen [39;49;00m(selected_rows), [94m4 [39;49;00m, [33m" [39;49;00m [33mExpected 4 athletes in selected table [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Test demote [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mTesting demote button... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m last_selected_row = selected_rows[- [94m1 [39;49;00m] [90m [39;49;00m last_selected_name = last_selected_row.text [90m [39;49;00m last_selected_row.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m demote_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, relay_demote_btn_selector) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, demote_btn) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_selected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertEqual( [96mlen [39;49;00m(selected_rows), [94m3 [39;49;00m, [33m" [39;49;00m [33mExpected 3 athletes in selected table after demote [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Promote back to 4 [39;49;00m [90m [39;49;00m rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_available_table_selector [33m} [39;49;00m [33m tbody tr [39;49;00m [33m" [39;49;00m) [90m [39;49;00m visible_rows = [r [94mfor [39;49;00m r [95min [39;49;00m rows [94mif [39;49;00m r.is_displayed() [95mand [39;49;00m [33m" [39;49;00m [33mmuted [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m r.get_attribute( [33m" [39;49;00m [33mclass [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m visible_rows[ [94m0 [39;49;00m].click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, promote_btn) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- New: Test ordering with arrows --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m--- Testing ordering with arrows --- [39;49;00m [33m" [39;49;00m) [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_selected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m runner_to_move = selected_rows[ [94m1 [39;49;00m] [90m [39;49;00m runner_name = runner_to_move.text [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mMoving runner [39;49;00m [33m{ [39;49;00mrunner_name [33m} [39;49;00m [33m up [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m runner_to_move.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m# Find the up arrow specifically in the highlighted row [39;49;00m [90m [39;49;00m ath_id = runner_to_move.get_attribute( [33m" [39;49;00m [33mdata-id [39;49;00m [33m" [39;49;00m) [90m [39;49;00m up_arrow_selector = [33mf [39;49;00m [33m" [39;49;00m [33mtr[data-id= [39;49;00m [33m' [39;49;00m [33m{ [39;49;00math_id [33m} [39;49;00m [33m' [39;49;00m [33m] .fa-chevron-up [39;49;00m [33m" [39;49;00m [90m [39;49;00m up_arrow = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, up_arrow_selector))) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, up_arrow) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify it moved to first position [39;49;00m [90m [39;49;00m reordered_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_selected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertEqual(reordered_rows[ [94m0 [39;49;00m].text, runner_name, [33m" [39;49;00m [33mRunner did not move up correctly [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Step 2: Input athletes via Handsontable grid --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mInteracting with Handsontable for relay runners... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m bulk_relay_btn_selector = [33m" [39;49;00m [33m#bulkRelayBtn [39;49;00m [33m" [39;49;00m [90m [39;49;00m bulk_relay_btn = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, bulk_relay_btn_selector))) [90m [39;49;00m bulk_relay_btn.click() [90m [39;49;00m time.sleep( [94m2 [39;49;00m) [90m [39;49;00m [90m [39;49;00m ht_selector = [33m" [39;49;00m [33m#runners_ht table.htCore [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, ht_selector))) [90m [39;49;00m [90m [39;49;00m [90m# Check grid editability: existing runners should be readOnly [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mChecking grid editability... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m is_readonly = [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mreturn window.relay_ht.getCellMeta(0, 1).readOnly; [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertTrue(is_readonly, [33m" [39;49;00m [33mExisting runner in grid should be readOnly [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Adding some reserve runners --- [39;49;00m [90m [39;49;00m [94mfor [39;49;00m i, (idx, first, last, dob, gender) [95min [39;49;00m [96menumerate [39;49;00m(reserve_runners_data, start= [94m4 [39;49;00m): [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mInputting runner [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m: [39;49;00m [33m{ [39;49;00mfirst [33m} [39;49;00m [33m [39;49;00m [33m{ [39;49;00mlast [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m cell_xpath = [33mf [39;49;00m [33m" [39;49;00m [33m//div[@id= [39;49;00m [33m' [39;49;00m [33mrunners_ht [39;49;00m [33m' [39;49;00m [33m]//table[@class= [39;49;00m [33m' [39;49;00m [33mhtCore [39;49;00m [33m' [39;49;00m [33m]/tbody/tr[ [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m]/td[1] [39;49;00m [33m" [39;49;00m [90m [39;49;00m cell = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, cell_xpath))) [90m [39;49;00m [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.move_to_element(cell).click().perform() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.send_keys( [96mstr [39;49;00m(idx)) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(first) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(last) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(dob) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(gender) [90m [39;49;00m actions.send_keys(Keys.ENTER) [90m [39;49;00m actions.perform() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Step 3: Save --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSaving team A... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m save_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, [33m" [39;49;00m [33m//div[@id= [39;49;00m [33m' [39;49;00m [33mrelay_teams_tab [39;49;00m [33m' [39;49;00m [33m]//button[contains(., [39;49;00m [33m' [39;49;00m [33mSave Changes [39;49;00m [33m' [39;49;00m [33m)] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, save_btn) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mWaiting for save confirmation... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.presence_of_element_located((By.XPATH, [33m" [39;49;00m [33m//*[contains(translate(text(), [39;49;00m [33m' [39;49;00m [33mABCDEFGHIJKLMNOPQRSTUVWXYZ [39;49;00m [33m' [39;49;00m [33m, [39;49;00m [33m' [39;49;00m [33mabcdefghijklmnopqrstuvwxyz [39;49;00m [33m' [39;49;00m [33m), [39;49;00m [33m' [39;49;00m [33mentries saved [39;49;00m [33m' [39;49;00m [33m)] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mEntries saved. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m rt.reload() [90m [39;49;00m rt.fetch_runners() [90m [39;49;00m rt.save() [90m [39;49;00m [90m [39;49;00m [90m# --- Step 4: Add two more relay teams --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m=== PART 1: Adding relay teams B and C === [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m event_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, event_btn_xpath))) [90m [39;49;00m event_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m add_team_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33m#relay_teams_tab button.btn-outline-success [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m add_team_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mAdded team B [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m add_team_btn.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mAdded team C [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify alphabetical order in UI tabs [39;49;00m [90m [39;49;00m team_tabs = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33m" [39;49;00m [33m#relay_teams_tab ul.nav-tabs li.nav-item a [39;49;00m [33m" [39;49;00m) [90m [39;49;00m team_labels = [t.text.strip() [94mfor [39;49;00m t [95min [39;49;00m team_tabs [94mif [39;49;00m [33m" [39;49;00m [33mTeam [39;49;00m [33m" [39;49;00m [95min [39;49;00m t.text] [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mTeam tabs found: [39;49;00m [33m{ [39;49;00mteam_labels [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33mTeam A [39;49;00m [33m" [39;49;00m, team_labels) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33mTeam B [39;49;00m [33m" [39;49;00m, team_labels) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33mTeam C [39;49;00m [33m" [39;49;00m, team_labels) [90m [39;49;00m [90m [39;49;00m [90m# Switch to team C and add some runners [39;49;00m [90m [39;49;00m team_tabs[- [94m1 [39;49;00m].click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m team_c_runners = [ [90m [39;49;00m ( [94m1 [39;49;00m, [33m' [39;49;00m [33mCharlie [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mOne [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2015-01-01 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mM [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ( [94m2 [39;49;00m, [33m' [39;49;00m [33mCharlie [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mTwo [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33m2015-01-02 [39;49;00m [33m' [39;49;00m, [33m' [39;49;00m [33mF [39;49;00m [33m' [39;49;00m), [90m [39;49;00m ] [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33m$( [39;49;00m [33m' [39;49;00m [33m#addRelayTeamContainer [39;49;00m [33m' [39;49;00m [33m).collapse( [39;49;00m [33m' [39;49;00m [33mshow [39;49;00m [33m' [39;49;00m [33m) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33mwindow.app.initRelayCompetitorsHandsOnTable() [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [94mfor [39;49;00m i, (idx, first, last, dob, gender) [95min [39;49;00m [96menumerate [39;49;00m(team_c_runners): [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mInputting runner [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m for team C: [39;49;00m [33m{ [39;49;00mfirst [33m} [39;49;00m [33m [39;49;00m [33m{ [39;49;00mlast [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m cell_xpath = [33mf [39;49;00m [33m" [39;49;00m [33m//div[@id= [39;49;00m [33m' [39;49;00m [33mrunners_ht [39;49;00m [33m' [39;49;00m [33m]//table[@class= [39;49;00m [33m' [39;49;00m [33mhtCore [39;49;00m [33m' [39;49;00m [33m]/tbody/tr[ [39;49;00m [33m{ [39;49;00mi+ [94m1 [39;49;00m [33m} [39;49;00m [33m]/td[1] [39;49;00m [33m" [39;49;00m [90m [39;49;00m cell = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, cell_xpath))) [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.move_to_element(cell).click().perform() [90m [39;49;00m time.sleep( [94m0.3 [39;49;00m) [90m [39;49;00m actions = ActionChains( [96mself [39;49;00m.selenium) [90m [39;49;00m actions.send_keys( [96mstr [39;49;00m(idx + [94m20 [39;49;00m)) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(first) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(last) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(dob) [90m [39;49;00m actions.send_keys(Keys.TAB) [90m [39;49;00m actions.send_keys(gender) [90m [39;49;00m actions.send_keys(Keys.ENTER) [90m [39;49;00m actions.perform() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSaving teams... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m save_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, [33m" [39;49;00m [33m//div[@id= [39;49;00m [33m' [39;49;00m [33mrelay_teams_tab [39;49;00m [33m' [39;49;00m [33m]//button[contains(., [39;49;00m [33m' [39;49;00m [33mSave Changes [39;49;00m [33m' [39;49;00m [33m)] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, save_btn) [90m [39;49;00m time.sleep( [94m2 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Step 5: Refresh and verify athletes and order persist --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m=== PART 2: Refreshing and verifying persistence === [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.refresh() [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m[v-cloak] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m relay_tab_link = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#relay_teams_tab [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m relay_tab_link.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m event_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, event_btn_xpath))) [90m [39;49;00m event_btn.click() [90m [39;49;00m [96mself [39;49;00m.wait.until( [94mlambda [39;49;00m d: [33m" [39;49;00m [33m--- [39;49;00m [33m" [39;49;00m [95mnot [39;49;00m [95min [39;49;00m d.find_element(By.CSS_SELECTOR, relay_selected_table_selector + [33m" [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m).text) [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_selected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m# Check team A order persistence [39;49;00m [90m [39;49;00m selected_rows = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mrelay_selected_table_selector [33m} [39;49;00m [33m tbody tr:not(.muted) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mFirst runner at refresh: [39;49;00m [33m{ [39;49;00mselected_rows[ [94m0 [39;49;00m].text.strip()[: [94m20 [39;49;00m] [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertEqual(selected_rows[ [94m0 [39;49;00m].text, runner_name, [33m" [39;49;00m [33mRunner order did not persist after refresh [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Step 6: Remove middle team (B) and check renaming --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m=== PART 3: Removing Team B and checking renaming === [39;49;00m [33m" [39;49;00m) [90m [39;49;00m team_tabs = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33m" [39;49;00m [33m#relay_teams_tab ul.nav-tabs li.nav-item a [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m# Team B is index 1 [39;49;00m [90m [39;49;00m [94mfor [39;49;00m tab [95min [39;49;00m team_tabs: [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mTeam B [39;49;00m [33m" [39;49;00m [95min [39;49;00m tab.text: [90m [39;49;00m tab.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [94mbreak [39;49;00m [90m [39;49;00m [90m [39;49;00m remove_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33m#removeRelayTeamBtn [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, remove_btn) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m [96mself [39;49;00m.selenium.switch_to.alert.accept() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [94mexcept [39;49;00m: [90m [39;49;00m [94mpass [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# Verify UI renaming before save [39;49;00m [90m [39;49;00m team_tabs_after = [96mself [39;49;00m.selenium.find_elements(By.CSS_SELECTOR, [33m" [39;49;00m [33m#relay_teams_tab ul.nav-tabs li.nav-item a [39;49;00m [33m" [39;49;00m) [90m [39;49;00m team_labels_after = [t.text.strip() [94mfor [39;49;00m t [95min [39;49;00m team_tabs_after [94mif [39;49;00m [33m" [39;49;00m [33mTeam [39;49;00m [33m" [39;49;00m [95min [39;49;00m t.text] [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mTeam tabs after removal: [39;49;00m [33m{ [39;49;00mteam_labels_after [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertNotIn( [33m" [39;49;00m [33mTeam C [39;49;00m [33m" [39;49;00m, team_labels_after, [33m" [39;49;00m [33mTeam C should have been renamed [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33mTeam B [39;49;00m [33m" [39;49;00m, team_labels_after, [33m" [39;49;00m [33mTeam B should still exist (now representing what was C) [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Check Charlie moved to B [39;49;00m [90m [39;49;00m [94mfor [39;49;00m tab [95min [39;49;00m team_tabs_after: [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mTeam B [39;49;00m [33m" [39;49;00m [95min [39;49;00m tab.text: [90m [39;49;00m tab.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [94mbreak [39;49;00m [90m [39;49;00m [90m [39;49;00m page_text = [96mself [39;49;00m.selenium.find_element(By.TAG_NAME, [33m" [39;49;00m [33mbody [39;49;00m [33m" [39;49;00m).text [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33mCharlie [39;49;00m [33m" [39;49;00m, page_text, [33m" [39;49;00m [33mFormer Team C athletes (Charlie) not found in renamed Team B [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m save_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.XPATH, [33m" [39;49;00m [33m//div[@id= [39;49;00m [33m' [39;49;00m [33mrelay_teams_tab [39;49;00m [33m' [39;49;00m [33m]//button[contains(., [39;49;00m [33m' [39;49;00m [33mSave Changes [39;49;00m [33m' [39;49;00m [33m)] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].click(); [39;49;00m [33m" [39;49;00m, save_btn) [90m [39;49;00m time.sleep( [94m2 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# Verify in database [39;49;00m [90m [39;49;00m all_teams_db = RelayTeam.objects.filter(competition= [96mself [39;49;00m.mc, event_id=relay_event_id, team_id=team_id).order_by( [33m' [39;49;00m [33mrelayteam_id [39;49;00m [33m' [39;49;00m) [90m [39;49;00m db_ids = [t.relayteam_id [94mfor [39;49;00m t [95min [39;49;00m all_teams_db] [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mRelay teams in DB: [39;49;00m [33m{ [39;49;00mdb_ids [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mteam_id [33m} [39;49;00m [33m-A [39;49;00m [33m" [39;49;00m, db_ids) [90m [39;49;00m [96mself [39;49;00m.assertIn( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mteam_id [33m} [39;49;00m [33m-B [39;49;00m [33m" [39;49;00m, db_ids) [90m [39;49;00m [96mself [39;49;00m.assertNotIn( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mteam_id [33m} [39;49;00m [33m-C [39;49;00m [33m" [39;49;00m, db_ids) [90m [39;49;00m [90m [39;49;00m team_b_db = all_teams_db.filter(relayteam_id= [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mteam_id [33m} [39;49;00m [33m-B [39;49;00m [33m" [39;49;00m).first() [90m [39;49;00m team_b_runners = [r.first_name [94mfor [39;49;00m r [95min [39;49;00m team_b_db.runners] [90m [39;49;00m [96mself [39;49;00m.assertIn( [33m" [39;49;00m [33mCharlie [39;49;00m [33m" [39;49;00m, team_b_runners, [33m" [39;49;00m [33mDatabase did not update runners for renamed team [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mAll relay tests completed successfully! [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# --- Step 7: Number all athletes before seeding --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m=== PART 4: Numbering athletes === [39;49;00m [33m" [39;49;00m) [90m [39;49;00m numbering_url = reverse( [33m' [39;49;00m [33mcomp-edit-numbering [39;49;00m [33m' [39;49;00m, kwargs={ [90m [39;49;00m [33m' [39;49;00m [33myear [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.year, [90m [39;49;00m [33m' [39;49;00m [33mcountry [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.country, [90m [39;49;00m [33m' [39;49;00m [33mslug [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.slug [90m [39;49;00m }) [90m [39;49;00m numbering_full_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mnumbering_url [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mNavigating to numbering page: [39;49;00m [33m{ [39;49;00mnumbering_full_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get(numbering_full_url) [90m [39;49;00m [90m [39;49;00m [94mif [39;49;00m [33m' [39;49;00m [33m/accounts/login/ [39;49;00m [33m' [39;49;00m [95min [39;49;00m [96mself [39;49;00m.selenium.current_url: [90m [39;49;00m [96mself [39;49;00m.login(redirect=numbering_url) [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton[name= [39;49;00m [33m' [39;49;00m [33mapply_numbers [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m apply_numbers_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable( [90m [39;49;00m (By.CSS_SELECTOR, [33m" [39;49;00m [33mbutton[name= [39;49;00m [33m' [39;49;00m [33mapply_numbers [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m) [90m [39;49;00m )) [90m [39;49;00m [96mself [39;49;00m.selenium.execute_script( [33m" [39;49;00m [33marguments[0].scrollIntoView(true); [39;49;00m [33m" [39;49;00m, apply_numbers_btn) [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m apply_numbers_btn.click() [90m [39;49;00m time.sleep( [94m2 [39;49;00m) [90m [39;49;00m [90m [39;49;00m page_text = [96mself [39;49;00m.selenium.page_source [90m [39;49;00m [94mif [39;49;00m [33m' [39;49;00m [33msuccess [39;49;00m [33m' [39;49;00m [95min [39;49;00m page_text.lower() [95mor [39;49;00m [33m' [39;49;00m [33mapplied [39;49;00m [33m' [39;49;00m [95min [39;49;00m page_text.lower(): [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mNumbers applied successfully [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mNumbering page content - checking for confirmation... [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mAthletes numbered! [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# --- Step 8: Seed and Publish via Event Detail Private --- [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m=== PART 4: Seeding and publishing === [39;49;00m [33m" [39;49;00m) [90m [39;49;00m private_event_url = reverse( [33m' [39;49;00m [33mcomp-event-detail-private [39;49;00m [33m' [39;49;00m, kwargs={ [90m [39;49;00m [33m' [39;49;00m [33myear [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.year, [90m [39;49;00m [33m' [39;49;00m [33mcountry [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.country, [90m [39;49;00m [33m' [39;49;00m [33mslug [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.slug, [90m [39;49;00m [33m' [39;49;00m [33mevent_id [39;49;00m [33m' [39;49;00m: relay_event_id [90m [39;49;00m }) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mNavigating to private event detail: [39;49;00m [33m{ [39;49;00mprivate_event_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mprivate_event_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [94mif [39;49;00m [33m' [39;49;00m [33m/accounts/login/ [39;49;00m [33m' [39;49;00m [95min [39;49;00m [96mself [39;49;00m.selenium.current_url: [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mOn login page [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.login(redirect=private_event_url) [90m [39;49;00m [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m heats_tab = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-heats [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m heats_tab.click() [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m seeding_options_container = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-heats form#seeding_options_r1 [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m seeding_options_container.is_displayed(): [90m [39;49;00m seeding_options_link = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-heats button[data-target= [39;49;00m [33m' [39;49;00m [33m#seeding_options_r1 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m seeding_options_link.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m seeding_select = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-heats button[name= [39;49;00m [33m' [39;49;00m [33mseed [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m seeding_select.click() [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSelected open_meet seeding method. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m lanes_input = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.NAME, [33m" [39;49;00m [33mlanes [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m lanes_input.clear() [90m [39;49;00m lanes_input.send_keys( [33m" [39;49;00m [33m8 [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSet lanes to 8. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m seed_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.NAME, [33m" [39;49;00m [33mseed [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m seed_btn.click() [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mSeeding triggered. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m heats_tab = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33ma[href= [39;49;00m [33m' [39;49;00m [33m#pills-heats [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m heats_tab.click() [90m [39;49;00m [90m [39;49;00m seeding_options_container = [96mself [39;49;00m.wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-heats form#seeding_options_r1 [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m seeding_options_container.is_displayed(): [90m [39;49;00m seeding_options_link = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, [33m" [39;49;00m [33m#pills-heats button[data-target= [39;49;00m [33m' [39;49;00m [33m#seeding_options_r1 [39;49;00m [33m' [39;49;00m [33m] [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m seeding_options_link.click() [90m [39;49;00m time.sleep( [94m0.5 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.wait.until(EC.presence_of_element_located((By.NAME, [33m" [39;49;00m [33mpublic [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m [90m [39;49;00m publish_btn = [96mself [39;49;00m.wait.until(EC.element_to_be_clickable((By.NAME, [33m" [39;49;00m [33mpublic [39;49;00m [33m" [39;49;00m))) [90m [39;49;00m publish_btn.click() [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mPublished results. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [90m [39;49;00m [90m# --- Step 9: Verify on unit detail page --- [39;49;00m [90m [39;49;00m [94mfrom [39;49;00m [90m [39;49;00m [04m [96mproject [39;49;00m [04m [96m. [39;49;00m [04m [96mreference [39;49;00m [04m [96m. [39;49;00m [04m [96mmongo [39;49;00m [90m [39;49;00m [94mimport [39;49;00m Unit [90m [39;49;00m unit = Unit.objects.filter(competition= [96mself [39;49;00m.mc, event=relay_event).first() [90m [39;49;00m [96mself [39;49;00m.assertIsNotNone(unit, [33m" [39;49;00m [33mNo unit found for the relay event after seeding. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m unit_url = reverse( [33m' [39;49;00m [33mcomp-unit-detail [39;49;00m [33m' [39;49;00m, kwargs={ [90m [39;49;00m [33m' [39;49;00m [33myear [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.year, [90m [39;49;00m [33m' [39;49;00m [33mcountry [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.country, [90m [39;49;00m [33m' [39;49;00m [33mslug [39;49;00m [33m' [39;49;00m: [96mself [39;49;00m.mc.slug, [90m [39;49;00m [33m' [39;49;00m [33mevent_id [39;49;00m [33m' [39;49;00m: unit.event.event_id, [90m [39;49;00m [33m' [39;49;00m [33mround [39;49;00m [33m' [39;49;00m: unit.round, [90m [39;49;00m [33m' [39;49;00m [33mheat [39;49;00m [33m' [39;49;00m: unit.heat [90m [39;49;00m }) [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mNavigating to unit detail: [39;49;00m [33m{ [39;49;00munit_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.get( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00munit_url [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m page_text = [96mself [39;49;00m.selenium.find_element(By.TAG_NAME, [33m" [39;49;00m [33mbody [39;49;00m [33m" [39;49;00m).text [90m [39;49;00m [94mfor [39;49;00m idx, first, last, dob, gender [95min [39;49;00m runners_data: [90m [39;49;00m [96mself [39;49;00m.assertIn(first, page_text, [33mf [39;49;00m [33m" [39;49;00m [33mAthlete [39;49;00m [33m{ [39;49;00mfirst [33m} [39;49;00m [33m [39;49;00m [33m{ [39;49;00mlast [33m} [39;49;00m [33m not found in unit detail page [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.assertIn(last, page_text, [33mf [39;49;00m [33m" [39;49;00m [33mAthlete [39;49;00m [33m{ [39;49;00mfirst [33m} [39;49;00m [33m [39;49;00m [33m{ [39;49;00mlast [33m} [39;49;00m [33m not found in unit detail page [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33mVerified athletes in unit detail page. [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [96mprint [39;49;00m( [33m" [39;49;00m [33m=== TEST PASSED: Add/Remove relay team with athlete persistence and seeding verified === [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [90m [39;49;00m [94mexcept [39;49;00m [96mException [39;49;00m [94mas [39;49;00m e: [90m [39;49;00m [96mprint [39;49;00m( [33mf [39;49;00m [33m" [39;49;00m [33mTest failed: [39;49;00m [33m{ [39;49;00me [33m} [39;49;00m [33m" [39;49;00m) [90m [39;49;00m time.sleep( [94m1 [39;49;00m) [90m [39;49;00m [96mself [39;49;00m.selenium.save_screenshot( [33m" [39;49;00m [33mrelay_test_failure.png [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mwith [39;49;00m [96mopen [39;49;00m( [33m" [39;49;00m [33mrelay_test_failure.html [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33mw [39;49;00m [33m" [39;49;00m) [94mas [39;49;00m f: [90m [39;49;00m f.write( [96mself [39;49;00m.selenium.page_source) [90m [39;49;00m > [94mraise [39;49;00m e [90m [39;49;00m project/comp/tests/test_team_declarations.py:1245: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ project/comp/tests/test_team_declarations.py:1116: in test_adhoc_relay_declarations [0m [96mself [39;49;00m.assertNotIn( [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mteam_id [33m} [39;49;00m [33m-C [39;49;00m [33m" [39;49;00m, db_ids) [90m [39;49;00m E AssertionError: 'ADHOC1-C' unexpectedly found in ['ADHOC1-A', 'ADHOC1-B', 'ADHOC1-C'] __________________ BMCE2ETests.test_associate_membership_join __________________ [gw2] linux -- Python 3.13.2 /opt/hostedtoolcache/Python/3.13.2/x64/bin/python self = [0m [37m@superuser_login_required [39;49;00m [90m [39;49;00m [94mdef [39;49;00m [90m [39;49;00m [92mtest_associate_membership_join [39;49;00m( [96mself [39;49;00m): [90m [39;49;00m [90m [39;49;00m [96mself [39;49;00m.person.roles().filter(organisation__code= [33m' [39;49;00m [33mBMC [39;49;00m [33m' [39;49;00m).delete() [90m [39;49;00m [90m [39;49;00m fed_index_url = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00m [96mself [39;49;00m.live_server_url [33m} [39;49;00m [33m{ [39;49;00mreverse( [33m' [39;49;00m [33mfed-index [39;49;00m [33m' [39;49;00m) [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m [96mself [39;49;00m.selenium.get(fed_index_url) [90m [39;49;00m [90m [39;49;00m [90m# join button [39;49;00m [90m [39;49;00m join_btn = [96mself [39;49;00m.selenium.find_element(By.ID, [33m" [39;49;00m [33mjoinMembershipBtn [39;49;00m [33m" [39;49;00m) [90m [39;49;00m join_btn.click() [90m [39;49;00m [90m [39;49;00m [90m [39;49;00m [90m# contact details popup will show, hide it [39;49;00m [90m [39;49;00m contact_details_close_btn = [96mself [39;49;00m.selenium.find_element(By.CSS_SELECTOR, [33m" [39;49;00m [33m#inputMissingDataModal .close-btn [39;49;00m [33m" [39;49;00m) [90m [39;49;00m > contact_details_close_btn.click() [90m [39;49;00m project/federation/tests/test_bmc.py:438: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/selenium/webdriver/remote/webelement.py:119: in click [0m [96mself [39;49;00m._execute(Command.CLICK_ELEMENT) [90m [39;49;00m /opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/selenium/webdriver/remote/webelement.py:572: in _execute [0m [94mreturn [39;49;00m [96mself [39;49;00m._parent.execute(command, params) [90m [39;49;00m ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [90m [39;49;00m /opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/selenium/webdriver/remote/webdriver.py:448: in execute [0m [96mself [39;49;00m.error_handler.check_response(response) [90m [39;49;00m _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self = response = {'status': 404, 'value': '{"value":{"error":"stale element reference","message":"stale element reference: stale elemen...\\n#17 0x563ffb47ff88 \\u003Cunknown>\\n#18 0x563ffb4915de \\u003Cunknown>\\n#19 0x7fbd7a294ac3 \\u003Cunknown>\\n"}}'} [0m [94mdef [39;49;00m [90m [39;49;00m [92mcheck_response [39;49;00m( [96mself [39;49;00m, response: Dict[ [96mstr [39;49;00m, Any]) -> [94mNone [39;49;00m: [90m [39;49;00m [90m [39;49;00m [33m"""Checks that a JSON response from the WebDriver does not have an [39;49;00m [33m error. [39;49;00m [33m [39;49;00m [33m :Args: [39;49;00m [33m - response - The JSON response from the WebDriver server as a dictionary [39;49;00m [33m object. [39;49;00m [33m [39;49;00m [33m :Raises: If the response contains an error message. [39;49;00m [33m """ [39;49;00m [90m [39;49;00m status = response.get( [33m" [39;49;00m [33mstatus [39;49;00m [33m" [39;49;00m, [94mNone [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m status [95mor [39;49;00m status == ErrorCode.SUCCESS: [90m [39;49;00m [94mreturn [39;49;00m [90m [39;49;00m value = [94mNone [39;49;00m [90m [39;49;00m message = response.get( [33m" [39;49;00m [33mmessage [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33m" [39;49;00m) [90m [39;49;00m screen: [96mstr [39;49;00m = response.get( [33m" [39;49;00m [33mscreen [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33m" [39;49;00m) [90m [39;49;00m stacktrace = [94mNone [39;49;00m [90m [39;49;00m [94mif [39;49;00m [96misinstance [39;49;00m(status, [96mint [39;49;00m): [90m [39;49;00m value_json = response.get( [33m" [39;49;00m [33mvalue [39;49;00m [33m" [39;49;00m, [94mNone [39;49;00m) [90m [39;49;00m [94mif [39;49;00m value_json [95mand [39;49;00m [96misinstance [39;49;00m(value_json, [96mstr [39;49;00m): [90m [39;49;00m [94mimport [39;49;00m [90m [39;49;00m [04m [96mjson [39;49;00m [90m [39;49;00m [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m value = json.loads(value_json) [90m [39;49;00m [94mif [39;49;00m [96mlen [39;49;00m(value) == [94m1 [39;49;00m: [90m [39;49;00m value = value[ [33m" [39;49;00m [33mvalue [39;49;00m [33m" [39;49;00m] [90m [39;49;00m status = value.get( [33m" [39;49;00m [33merror [39;49;00m [33m" [39;49;00m, [94mNone [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m status: [90m [39;49;00m status = value.get( [33m" [39;49;00m [33mstatus [39;49;00m [33m" [39;49;00m, ErrorCode.UNKNOWN_ERROR) [90m [39;49;00m message = value.get( [33m" [39;49;00m [33mvalue [39;49;00m [33m" [39;49;00m) [95mor [39;49;00m value.get( [33m" [39;49;00m [33mmessage [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m [96misinstance [39;49;00m(message, [96mstr [39;49;00m): [90m [39;49;00m value = message [90m [39;49;00m message = message.get( [33m" [39;49;00m [33mmessage [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m message = value.get( [33m" [39;49;00m [33mmessage [39;49;00m [33m" [39;49;00m, [94mNone [39;49;00m) [90m [39;49;00m [94mexcept [39;49;00m [96mValueError [39;49;00m: [90m [39;49;00m [94mpass [39;49;00m [90m [39;49;00m [90m [39;49;00m exception_class: Type[WebDriverException] [90m [39;49;00m e = ErrorCode() [90m [39;49;00m error_codes = [item [94mfor [39;49;00m item [95min [39;49;00m [96mdir [39;49;00m(e) [94mif [39;49;00m [95mnot [39;49;00m item.startswith( [33m" [39;49;00m [33m__ [39;49;00m [33m" [39;49;00m)] [90m [39;49;00m [94mfor [39;49;00m error_code [95min [39;49;00m error_codes: [90m [39;49;00m error_info = [96mgetattr [39;49;00m(ErrorCode, error_code) [90m [39;49;00m [94mif [39;49;00m [96misinstance [39;49;00m(error_info, [96mlist [39;49;00m) [95mand [39;49;00m status [95min [39;49;00m error_info: [90m [39;49;00m exception_class = [96mgetattr [39;49;00m(ExceptionMapping, error_code, WebDriverException) [90m [39;49;00m [94mbreak [39;49;00m [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m exception_class = WebDriverException [90m [39;49;00m [90m [39;49;00m [94mif [39;49;00m [95mnot [39;49;00m value: [90m [39;49;00m value = response[ [33m" [39;49;00m [33mvalue [39;49;00m [33m" [39;49;00m] [90m [39;49;00m [94mif [39;49;00m [96misinstance [39;49;00m(value, [96mstr [39;49;00m): [90m [39;49;00m [94mraise [39;49;00m exception_class(value) [90m [39;49;00m [94mif [39;49;00m message == [33m" [39;49;00m [33m" [39;49;00m [95mand [39;49;00m [33m" [39;49;00m [33mmessage [39;49;00m [33m" [39;49;00m [95min [39;49;00m value: [90m [39;49;00m message = value[ [33m" [39;49;00m [33mmessage [39;49;00m [33m" [39;49;00m] [90m [39;49;00m [90m [39;49;00m screen = [94mNone [39;49;00m [90m# type: ignore[assignment] [39;49;00m [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mscreen [39;49;00m [33m" [39;49;00m [95min [39;49;00m value: [90m [39;49;00m screen = value[ [33m" [39;49;00m [33mscreen [39;49;00m [33m" [39;49;00m] [90m [39;49;00m [90m [39;49;00m stacktrace = [94mNone [39;49;00m [90m [39;49;00m st_value = value.get( [33m" [39;49;00m [33mstackTrace [39;49;00m [33m" [39;49;00m) [95mor [39;49;00m value.get( [33m" [39;49;00m [33mstacktrace [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m st_value: [90m [39;49;00m [94mif [39;49;00m [96misinstance [39;49;00m(st_value, [96mstr [39;49;00m): [90m [39;49;00m stacktrace = st_value.split( [33m" [39;49;00m [33m\n [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94melse [39;49;00m: [90m [39;49;00m stacktrace = [] [90m [39;49;00m [94mtry [39;49;00m: [90m [39;49;00m [94mfor [39;49;00m frame [95min [39;49;00m st_value: [90m [39;49;00m line = frame.get( [33m" [39;49;00m [33mlineNumber [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33m" [39;49;00m) [90m [39;49;00m file = frame.get( [33m" [39;49;00m [33mfileName [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33m [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m line: [90m [39;49;00m file = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mfile [33m} [39;49;00m [33m: [39;49;00m [33m{ [39;49;00mline [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m meth = frame.get( [33m" [39;49;00m [33mmethodName [39;49;00m [33m" [39;49;00m, [33m" [39;49;00m [33m [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mclassName [39;49;00m [33m" [39;49;00m [95min [39;49;00m frame: [90m [39;49;00m meth = [33mf [39;49;00m [33m" [39;49;00m [33m{ [39;49;00mframe[ [33m' [39;49;00m [33mclassName [39;49;00m [33m' [39;49;00m] [33m} [39;49;00m [33m. [39;49;00m [33m{ [39;49;00mmeth [33m} [39;49;00m [33m" [39;49;00m [90m [39;49;00m msg = [33m" [39;49;00m [33m at [39;49;00m [33m%s [39;49;00m [33m ( [39;49;00m [33m%s [39;49;00m [33m) [39;49;00m [33m" [39;49;00m [90m [39;49;00m msg = msg % (meth, file) [90m [39;49;00m stacktrace.append(msg) [90m [39;49;00m [94mexcept [39;49;00m [96mTypeError [39;49;00m: [90m [39;49;00m [94mpass [39;49;00m [90m [39;49;00m [94mif [39;49;00m exception_class == UnexpectedAlertPresentException: [90m [39;49;00m alert_text = [94mNone [39;49;00m [90m [39;49;00m [94mif [39;49;00m [33m" [39;49;00m [33mdata [39;49;00m [33m" [39;49;00m [95min [39;49;00m value: [90m [39;49;00m alert_text = value[ [33m" [39;49;00m [33mdata [39;49;00m [33m" [39;49;00m].get( [33m" [39;49;00m [33mtext [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94melif [39;49;00m [33m" [39;49;00m [33malert [39;49;00m [33m" [39;49;00m [95min [39;49;00m value: [90m [39;49;00m alert_text = value[ [33m" [39;49;00m [33malert [39;49;00m [33m" [39;49;00m].get( [33m" [39;49;00m [33mtext [39;49;00m [33m" [39;49;00m) [90m [39;49;00m [94mraise [39;49;00m exception_class(message, screen, stacktrace, alert_text) [90m# type: ignore[call-arg] # mypy is not smart enough here [39;49;00m [90m [39;49;00m > [94mraise [39;49;00m exception_class(message, screen, stacktrace) [90m [39;49;00m E selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: stale element not found in the current frame E (Session info: chrome=147.0.7727.55); For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception E Stacktrace: E #0 0x563ffb492b6a E #1 0x563ffae94265 E #2 0x563ffae9b111 E #3 0x563ffae9d95b E #4 0x563ffae9da03 E #5 0x563ffaee8cd0 E #6 0x563ffaedc437 E #7 0x563ffaedbe07 E #8 0x563ffaf2f969 E #9 0x563ffaeda5cf E #10 0x563ffaedb391 E #11 0x563ffb45804b E #12 0x563ffb45b00d E #13 0x563ffb444808 E #14 0x563ffb45bba0 E #15 0x563ffb42b280 E #16 0x563ffb47fdb8 E #17 0x563ffb47ff88 E #18 0x563ffb4915de E #19 0x7fbd7a294ac3 /opt/hostedtoolcache/Python/3.13.2/x64/lib/python3.13/site-packages/selenium/webdriver/remote/errorhandler.py:232: StaleElementReferenceException =========================== short test summary info ============================ [31mFAILED [0m project/comp/tests/test_team_declarations.py:: [1mTeamDeclarationsE2ETests::test_adhoc_individual_declarations [0m - AssertionError: 0 != 1 : Grid row count (0) should match selected table count (1) [31mFAILED [0m project/comp/tests/test_seeding.py:: [1mSeedingE2ETests::test_three_round_championship_seeding [0m - AssertionError: 0 != 8 : Should have 8 athletes in the final [31mFAILED [0m project/comp/tests/test_comp_e2e.py:: [1mCompE2ETests::test_record_length_and_height_events [0m - selenium.common.exceptions.TimeoutException: Message: [31mFAILED [0m project/comp/tests/test_team_declarations.py:: [1mTeamDeclarationsE2ETests::test_adhoc_relay_declarations [0m - AssertionError: 'ADHOC1-C' unexpectedly found in ['ADHOC1-A', 'ADHOC1-B', 'ADHOC1-C'] [31mFAILED [0m project/federation/tests/test_bmc.py:: [1mBMCE2ETests::test_associate_membership_join [0m - selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: stale element not found in the current frame (Session info: chrome=147.0.7727.55); For documentation on this error, please visit: https://www.selenium.dev/documentation/webdriver/troubleshooting/errors#stale-element-reference-exception Stacktrace: #0 0x563ffb492b6a #1 0x563ffae94265 #2 0x563ffae9b111 #3 0x563ffae9d95b #4 0x563ffae9da03 #5 0x563ffaee8cd0 #6 0x563ffaedc437 #7 0x563ffaedbe07 #8 0x563ffaf2f969 #9 0x563ffaeda5cf #10 0x563ffaedb391 #11 0x563ffb45804b #12 0x563ffb45b00d #13 0x563ffb444808 #14 0x563ffb45bba0 #15 0x563ffb42b280 #16 0x563ffb47fdb8 #17 0x563ffb47ff88 #18 0x563ffb4915de #19 0x7fbd7a294ac3 ==== [31m [1m5 failed [0m, [32m610 passed [0m, [33m16 skipped [0m, [33m20285 warnings [0m [31m in 580.30s (0:09:40) [0m [31m =====