This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new d1d3cb8  Ensure that there is a release in every phase after the 
browser tests
d1d3cb8 is described below

commit d1d3cb85b46aabec1196499d69529564cdef0500
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Apr 21 19:47:50 2025 +0100

    Ensure that there is a release in every phase after the browser tests
---
 playwright/test.py | 324 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 192 insertions(+), 132 deletions(-)

diff --git a/playwright/test.py b/playwright/test.py
index 4413dd5..057a5f0 100644
--- a/playwright/test.py
+++ b/playwright/test.py
@@ -52,6 +52,10 @@ class Credentials:
 #     credentials: Credentials
 
 
+def esc_id(text: str) -> str:
+    return re.escape(text)
+
+
 def get_credentials() -> Credentials | None:
     try:
         username = input("Enter ASF Username: ")
@@ -92,6 +96,170 @@ def go_to_path(page: sync_api.Page, path: str, wait: bool = 
True) -> None:
         wait_for_path(page, path)
 
 
+def lifecycle_01_add_draft(page: sync_api.Page, credentials: Credentials, 
version_name: str) -> None:
+    logging.info("Following link to add draft")
+    add_draft_link_locator = page.get_by_role("link", name="Add draft")
+    sync_api.expect(add_draft_link_locator).to_be_visible()
+    add_draft_link_locator.click()
+
+    logging.info("Waiting for the add draft page")
+    project_select_locator = page.locator('select[name="project_name"]')
+    sync_api.expect(project_select_locator).to_be_visible()
+    logging.info("Add draft page loaded")
+
+    logging.info("Selecting project 'tooling-test-example'")
+    project_select_locator.select_option(label="Apache Tooling Test Example")
+
+    logging.info(f"Filling version '{version_name}'")
+    page.locator('input[name="version_name"]').fill(version_name)
+
+    logging.info("Submitting the add draft form")
+    submit_button_locator = page.locator('input[type="submit"][value="Create 
candidate draft"]')
+    sync_api.expect(submit_button_locator).to_be_enabled()
+    submit_button_locator.click()
+
+    logging.info(f"Waiting for navigation to 
/draft/content/tooling-test-example/{version_name} after adding draft")
+    wait_for_path(page, f"/draft/content/tooling-test-example/{version_name}")
+    logging.info("Add draft actions completed successfully")
+
+
+def lifecycle_02_check_draft_added(page: sync_api.Page, credentials: 
Credentials, version_name: str) -> None:
+    logging.info(f"Checking for draft 'tooling-test-example {version_name}'")
+    go_to_path(page, "/drafts")
+    draft_card_locator = 
page.locator(f"#tooling-test-example-{esc_id(version_name)}")
+    sync_api.expect(draft_card_locator).to_be_visible()
+    logging.info(f"Draft 'tooling-test-example {version_name}' found 
successfully")
+
+
+def lifecycle_03_add_file(page: sync_api.Page, credentials: Credentials, 
version_name: str) -> None:
+    logging.info(f"Navigating to the add file page for tooling-test-example 
{version_name}")
+    go_to_path(page, f"/draft/add/tooling-test-example/{version_name}")
+    logging.info("Add file page loaded")
+
+    logging.info("Locating the file input")
+    file_input_locator = page.locator('input[name="file_data"]')
+    sync_api.expect(file_input_locator).to_be_visible()
+
+    logging.info("Setting the input file to /run/tests/example.txt")
+    file_input_locator.set_input_files("/run/tests/example.txt")
+
+    logging.info("Locating and activating the add files button")
+    submit_button_locator = page.locator('input[type="submit"][value="Add 
files"]')
+    sync_api.expect(submit_button_locator).to_be_enabled()
+    submit_button_locator.click()
+
+    logging.info(f"Waiting for navigation to 
/draft/evaluate/tooling-test-example/{version_name} after adding file")
+    wait_for_path(page, f"/draft/evaluate/tooling-test-example/{version_name}")
+    logging.info("Add file actions completed successfully")
+
+    logging.info("Navigating back to /drafts")
+    go_to_path(page, "/drafts")
+    logging.info("Navigation back to /drafts completed successfully")
+
+
+def lifecycle_04_start_vote(page: sync_api.Page, credentials: Credentials, 
version_name: str) -> None:
+    logging.info(f"Navigating to the drafts page for tooling-test-example 
{version_name}")
+    go_to_path(page, "/drafts")
+    logging.info("Drafts page loaded successfully")
+
+    logging.info(f"Locating start vote link for tooling-test-example 
{version_name}")
+    draft_card_locator = 
page.locator(f"#tooling-test-example-{esc_id(version_name)}")
+    start_vote_link_locator = draft_card_locator.locator(
+        f'a[title="Start vote for Apache Tooling Test Example {version_name}"]'
+    )
+    sync_api.expect(start_vote_link_locator).to_be_visible()
+
+    logging.info("Follow the start vote link")
+    start_vote_link_locator.click()
+
+    logging.info("Waiting for page load after following the start vote link")
+    page.wait_for_load_state()
+    logging.info("Page loaded after following the start vote link")
+    logging.info(f"Current URL: {page.url}")
+
+    logging.info("Locating and activating the button to prepare the vote 
email")
+    submit_button_locator = page.locator('input[type="submit"][value="Send 
vote email"]')
+    sync_api.expect(submit_button_locator).to_be_enabled()
+    submit_button_locator.click()
+
+    logging.info("Waiting for navigation to /candidate/resolve after 
submitting vote email")
+    wait_for_path(page, "/candidate/resolve")
+    logging.info("Vote initiation actions completed successfully")
+
+
+def lifecycle_05_resolve_vote(page: sync_api.Page, credentials: Credentials, 
version_name: str) -> None:
+    logging.info(f"Navigating to the candidate resolve page for 
tooling-test-example {version_name}")
+    go_to_path(page, "/candidate/resolve")
+    logging.info("Candidate resolve page loaded successfully")
+
+    logging.info(f"Locating the form to resolve the vote for 
tooling-test-example {version_name}")
+    form_locator = page.locator(
+        
f'form:has(input[name="candidate_name"][value="tooling-test-example-{esc_id(version_name)}"])'
+    )
+    sync_api.expect(form_locator).to_be_visible()
+
+    logging.info("Locating and selecting the 'Passed' radio button")
+    passed_radio_locator = 
form_locator.locator('input[name="vote_result"][value="passed"]')
+    sync_api.expect(passed_radio_locator).to_be_enabled()
+    passed_radio_locator.check()
+
+    logging.info("Locating and activating the button to resolve the vote")
+    submit_button_locator = 
form_locator.locator('input[type="submit"][value="Resolve vote"]')
+    sync_api.expect(submit_button_locator).to_be_enabled()
+    submit_button_locator.click()
+
+    logging.info("Waiting for navigation to /previews after resolving the 
vote")
+    wait_for_path(page, "/previews")
+    logging.info("Vote resolution actions completed successfully")
+
+
+def lifecycle_06_announce_preview(page: sync_api.Page, credentials: 
Credentials, version_name: str) -> None:
+    logging.info(f"Locating the link to announce the preview for 
tooling-test-example {version_name}")
+    announce_link_locator = page.locator(f'a[title="Announce Apache Tooling 
Test Example {version_name}"]')
+    sync_api.expect(announce_link_locator).to_be_visible()
+
+    logging.info("Following the link to announce the preview")
+    announce_link_locator.click()
+
+    logging.info("Waiting for navigation to /preview/announce")
+    wait_for_path(page, "/preview/announce")
+    logging.info("Announce preview navigation completed successfully")
+
+    logging.info(f"Locating the announcement form for tooling-test-example 
{version_name}")
+    form_locator = page.locator(f'#tooling-test-example-{esc_id(version_name)} 
form[action="/preview/announce"]')
+    sync_api.expect(form_locator).to_be_visible()
+
+    logging.info("Locating the confirmation checkbox within the form")
+    checkbox_locator = form_locator.locator('input[name="confirm_announce"]')
+    sync_api.expect(checkbox_locator).to_be_visible()
+
+    logging.info("Checking the confirmation checkbox")
+    checkbox_locator.check()
+
+    logging.info("Locating and activating the announce button within the form")
+    submit_button_locator = form_locator.get_by_role("button", name="Announce 
release")
+    sync_api.expect(submit_button_locator).to_be_enabled()
+    submit_button_locator.click()
+
+    logging.info("Waiting for navigation to /releases after submitting 
announcement")
+    wait_for_path(page, "/releases")
+    logging.info("Preview announcement actions completed successfully")
+
+
+def lifecycle_07_release_exists(page: sync_api.Page, credentials: Credentials, 
version_name: str) -> None:
+    logging.info(f"Checking for release tooling-test-example {version_name} on 
the /releases page")
+
+    release_card_locator = page.locator(f'div.card:has(h3:has-text("Apache 
Tooling Test Example {version_name}"))')
+    sync_api.expect(release_card_locator).to_be_visible()
+    logging.info(f"Found card for tooling-test-example {version_name} release")
+    logging.info(f"Release tooling-test-example {version_name} confirmed 
exists on /releases page")
+
+    logging.info(f"Verifying release tooling-test-example {version_name} card 
exists")
+    release_card_locator = page.locator(f'div.card:has(h3:has-text("Apache 
Tooling Test Example {version_name}"))')
+    sync_api.expect(release_card_locator).to_be_visible()
+    logging.info(f"Release tooling-test-example {version_name} card found")
+
+
 def main() -> None:
     # TODO: Only members of ASF Tooling can run these tests
     parser = argparse.ArgumentParser(description="Run Playwright debugging 
test")
@@ -566,155 +734,43 @@ def test_gpg_01_upload(page: sync_api.Page, credentials: 
Credentials) -> None:
 
 
 def test_lifecycle_01_add_draft(page: sync_api.Page, credentials: Credentials) 
-> None:
-    logging.info("Following link to add draft")
-    add_draft_link_locator = page.get_by_role("link", name="Add draft")
-    sync_api.expect(add_draft_link_locator).to_be_visible()
-    add_draft_link_locator.click()
-
-    logging.info("Waiting for the add draft page")
-    project_select_locator = page.locator('select[name="project_name"]')
-    sync_api.expect(project_select_locator).to_be_visible()
-    logging.info("Add draft page loaded")
-
-    logging.info("Selecting project 'tooling-test-example'")
-    project_select_locator.select_option(label="Apache Tooling Test Example")
-
-    logging.info("Filling version '0.1'")
-    page.locator('input[name="version_name"]').fill("0.1")
-
-    logging.info("Submitting the add draft form")
-    submit_button_locator = page.locator('input[type="submit"][value="Create 
candidate draft"]')
-    sync_api.expect(submit_button_locator).to_be_enabled()
-    submit_button_locator.click()
-
-    logging.info("Waiting for navigation to 
/draft/content/tooling-test-example/0.1 after adding draft")
-    wait_for_path(page, "/draft/content/tooling-test-example/0.1")
-    logging.info("Add draft actions completed successfully")
+    lifecycle_01_add_draft(page, credentials, version_name="0.1+draft")
+    lifecycle_01_add_draft(page, credentials, version_name="0.1+candidate")
+    lifecycle_01_add_draft(page, credentials, version_name="0.1+preview")
+    lifecycle_01_add_draft(page, credentials, version_name="0.1+release")
 
 
 def test_lifecycle_02_check_draft_added(page: sync_api.Page, credentials: 
Credentials) -> None:
-    logging.info("Checking for draft 'tooling-test-example-0.1'")
-    go_to_path(page, "/drafts")
-    draft_card_locator = page.locator(r"#tooling-test-example-0\.1")
-    sync_api.expect(draft_card_locator).to_be_visible()
-    logging.info("Draft 'tooling-test-example-0.1' found successfully")
+    lifecycle_02_check_draft_added(page, credentials, version_name="0.1+draft")
+    lifecycle_02_check_draft_added(page, credentials, 
version_name="0.1+candidate")
+    lifecycle_02_check_draft_added(page, credentials, 
version_name="0.1+preview")
+    lifecycle_02_check_draft_added(page, credentials, 
version_name="0.1+release")
 
 
 def test_lifecycle_03_add_file(page: sync_api.Page, credentials: Credentials) 
-> None:
-    logging.info("Navigating to the add file page for 
tooling-test-example-0.1")
-    go_to_path(page, "/draft/add/tooling-test-example/0.1")
-    logging.info("Add file page loaded")
-
-    logging.info("Locating the file input")
-    file_input_locator = page.locator('input[name="file_data"]')
-    sync_api.expect(file_input_locator).to_be_visible()
-
-    logging.info("Setting the input file to /run/tests/example.txt")
-    file_input_locator.set_input_files("/run/tests/example.txt")
-
-    logging.info("Locating and activating the add files button")
-    submit_button_locator = page.locator('input[type="submit"][value="Add 
files"]')
-    sync_api.expect(submit_button_locator).to_be_enabled()
-    submit_button_locator.click()
-
-    logging.info("Waiting for navigation to 
/draft/evaluate/tooling-test-example/0.1 after adding file")
-    wait_for_path(page, "/draft/evaluate/tooling-test-example/0.1")
-    logging.info("Add file actions completed successfully")
-
-    logging.info("Navigating back to /drafts")
-    go_to_path(page, "/drafts")
-    logging.info("Navigation back to /drafts completed successfully")
+    lifecycle_03_add_file(page, credentials, version_name="0.1+draft")
+    lifecycle_03_add_file(page, credentials, version_name="0.1+candidate")
+    lifecycle_03_add_file(page, credentials, version_name="0.1+preview")
+    lifecycle_03_add_file(page, credentials, version_name="0.1+release")
 
 
 def test_lifecycle_04_start_vote(page: sync_api.Page, credentials: 
Credentials) -> None:
-    logging.info("Locating start vote link for tooling-test-example-0.1")
-    draft_card_locator = page.locator(r"#tooling-test-example-0\.1")
-    start_vote_link_locator = draft_card_locator.locator('a[title="Start vote 
for Apache Tooling Test Example 0.1"]')
-    sync_api.expect(start_vote_link_locator).to_be_visible()
-
-    logging.info("Follow the start vote link")
-    start_vote_link_locator.click()
-
-    logging.info("Waiting for page load after following the start vote link")
-    page.wait_for_load_state()
-    logging.info("Page loaded after following the start vote link")
-    logging.info(f"Current URL: {page.url}")
-
-    logging.info("Locating and activating the button to prepare the vote 
email")
-    submit_button_locator = page.locator('input[type="submit"][value="Send 
vote email"]')
-    sync_api.expect(submit_button_locator).to_be_enabled()
-    submit_button_locator.click()
-
-    logging.info("Waiting for navigation to /candidate/resolve after 
submitting vote email")
-    wait_for_path(page, "/candidate/resolve")
-    logging.info("Vote initiation actions completed successfully")
+    lifecycle_04_start_vote(page, credentials, version_name="0.1+candidate")
+    lifecycle_04_start_vote(page, credentials, version_name="0.1+preview")
+    lifecycle_04_start_vote(page, credentials, version_name="0.1+release")
 
 
 def test_lifecycle_05_resolve_vote(page: sync_api.Page, credentials: 
Credentials) -> None:
-    logging.info("Locating the form to resolve the vote for 
tooling-test-example-0.1")
-    form_locator = 
page.locator('form:has(input[name="candidate_name"][value="tooling-test-example-0.1"])')
-    sync_api.expect(form_locator).to_be_visible()
-
-    logging.info("Locating and selecting the 'Passed' radio button")
-    passed_radio_locator = 
form_locator.locator('input[name="vote_result"][value="passed"]')
-    sync_api.expect(passed_radio_locator).to_be_enabled()
-    passed_radio_locator.check()
-
-    logging.info("Locating and activating the button to resolve the vote")
-    submit_button_locator = 
form_locator.locator('input[type="submit"][value="Resolve vote"]')
-    sync_api.expect(submit_button_locator).to_be_enabled()
-    submit_button_locator.click()
-
-    logging.info("Waiting for navigation to /previews after resolving the 
vote")
-    wait_for_path(page, "/previews")
-    logging.info("Vote resolution actions completed successfully")
+    lifecycle_05_resolve_vote(page, credentials, version_name="0.1+preview")
+    lifecycle_05_resolve_vote(page, credentials, version_name="0.1+release")
 
 
 def test_lifecycle_06_announce_preview(page: sync_api.Page, credentials: 
Credentials) -> None:
-    logging.info("Locating the link to announce the preview for 
tooling-test-example-0.1")
-    announce_link_locator = page.locator('a[title="Announce Apache Tooling 
Test Example 0.1"]')
-    sync_api.expect(announce_link_locator).to_be_visible()
-
-    logging.info("Following the link to announce the preview")
-    announce_link_locator.click()
-
-    logging.info("Waiting for navigation to /preview/announce")
-    wait_for_path(page, "/preview/announce")
-    logging.info("Announce preview navigation completed successfully")
-
-    logging.info("Locating the announcement form for tooling-test-example-0.1")
-    form_locator = page.locator(r'#tooling-test-example-0\.1 
form[action="/preview/announce"]')
-    sync_api.expect(form_locator).to_be_visible()
-
-    logging.info("Locating the confirmation checkbox within the form")
-    checkbox_locator = form_locator.locator('input[name="confirm_announce"]')
-    sync_api.expect(checkbox_locator).to_be_visible()
-
-    logging.info("Checking the confirmation checkbox")
-    checkbox_locator.check()
-
-    logging.info("Locating and activating the announce button within the form")
-    submit_button_locator = form_locator.get_by_role("button", name="Announce 
release")
-    sync_api.expect(submit_button_locator).to_be_enabled()
-    submit_button_locator.click()
-
-    logging.info("Waiting for navigation to /releases after submitting 
announcement")
-    wait_for_path(page, "/releases")
-    logging.info("Preview announcement actions completed successfully")
+    lifecycle_06_announce_preview(page, credentials, 
version_name="0.1+release")
 
 
 def test_lifecycle_07_release_exists(page: sync_api.Page, credentials: 
Credentials) -> None:
-    logging.info("Checking for release tooling-test-example-0.1 on the 
/releases page")
-
-    release_card_locator = page.locator('div.card:has(h3:has-text("Apache 
Tooling Test Example 0.1"))')
-    sync_api.expect(release_card_locator).to_be_visible()
-    logging.info("Found card for tooling-test-example-0.1 release")
-    logging.info("Release tooling-test-example-0.1 confirmed exists on 
/releases page")
-
-    logging.info("Verifying release tooling-test-example-0.1 card exists")
-    release_card_locator = page.locator('div.card:has(h3:has-text("Apache 
Tooling Test Example 0.1"))')
-    sync_api.expect(release_card_locator).to_be_visible()
-    logging.info("Release tooling-test-example-0.1 card found")
+    lifecycle_07_release_exists(page, credentials, version_name="0.1+release")
 
 
 def test_login(page: sync_api.Page, credentials: Credentials) -> None:
@@ -1151,7 +1207,11 @@ def test_tidy_up_releases(page: sync_api.Page) -> None:
     go_to_path(page, "/admin/delete-release")
     logging.info("Admin delete release page loaded")
 
-    release_remove(page, "tooling-test-example-0.1")
+    # TODO: Get these names automatically
+    release_remove(page, "tooling-test-example-0.1+draft")
+    release_remove(page, "tooling-test-example-0.1+candidate")
+    release_remove(page, "tooling-test-example-0.1+preview")
+    release_remove(page, "tooling-test-example-0.1+release")
     release_remove(page, "tooling-test-example-0.2")
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to