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-releases.git
The following commit(s) were added to refs/heads/main by this push:
new 56cf9d1 Add some vote page tests
56cf9d1 is described below
commit 56cf9d18d1f415d528dd19077dfb565f84a1ab21
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Dec 11 17:10:31 2025 +0000
Add some vote page tests
---
tests/e2e/vote/__init__.py | 16 ++++++
tests/e2e/vote/conftest.py | 86 +++++++++++++++++++++++++++++++
tests/e2e/vote/helpers.py | 38 ++++++++++++++
tests/e2e/vote/test_get.py | 126 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 266 insertions(+)
diff --git a/tests/e2e/vote/__init__.py b/tests/e2e/vote/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/tests/e2e/vote/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/tests/e2e/vote/conftest.py b/tests/e2e/vote/conftest.py
new file mode 100644
index 0000000..5544357
--- /dev/null
+++ b/tests/e2e/vote/conftest.py
@@ -0,0 +1,86 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from __future__ import annotations
+
+import pathlib
+from typing import TYPE_CHECKING, Final
+
+import e2e.helpers as helpers # type: ignore[reportMissingImports]
+import pytest
+
+if TYPE_CHECKING:
+ from collections.abc import Generator
+
+ from playwright.sync_api import Browser, BrowserContext, Page
+
+PROJECT_NAME: Final[str] = "test"
+VERSION_NAME: Final[str] = "0.1+vote"
+FILE_NAME: Final[str] = "apache-test-0.2.tar.gz"
+CURRENT_DIR: Final[pathlib.Path] = pathlib.Path(__file__).parent.resolve()
+VOTE_URL: Final[str] = f"/vote/{PROJECT_NAME}/{VERSION_NAME}"
+
+
[email protected]
+def page_vote(vote_context: BrowserContext) -> Generator[Page]:
+ """Navigate to the vote page with a fresh page for each test."""
+ page = vote_context.new_page()
+ helpers.visit(page, VOTE_URL)
+ yield page
+ page.close()
+
+
[email protected](scope="module")
+def vote_context(browser: Browser) -> Generator[BrowserContext]:
+ """Create a release in the vote phase."""
+ context = browser.new_context(
+ ignore_https_errors=True,
+ permissions=["clipboard-read", "clipboard-write"],
+ )
+ page = context.new_page()
+
+ helpers.log_in(page)
+
+ helpers.visit(page, f"/start/{PROJECT_NAME}")
+ page.locator("input#version_name").fill(VERSION_NAME)
+ page.get_by_role("button", name="Start new release").click()
+ page.wait_for_url(f"**/compose/{PROJECT_NAME}/{VERSION_NAME}")
+
+ helpers.visit(page, f"/upload/{PROJECT_NAME}/{VERSION_NAME}")
+
page.locator('input[name="file_data"]').set_input_files(f"{CURRENT_DIR}/../test_files/{FILE_NAME}")
+ page.get_by_role("button", name="Add files").click()
+ page.wait_for_url(f"**/compose/{PROJECT_NAME}/{VERSION_NAME}")
+
+ helpers.visit(page, f"/compose/{PROJECT_NAME}/{VERSION_NAME}")
+ _wait_for_tasks_banner_hidden(page, timeout=60000)
+
+ page.locator('a[title="Start a vote on this draft"]').click()
+ page.wait_for_load_state()
+
+ page.get_by_role("button", name="Send vote email").click()
+ page.wait_for_url(f"**/vote/{PROJECT_NAME}/{VERSION_NAME}")
+
+ page.close()
+
+ yield context
+
+ context.close()
+
+
+def _wait_for_tasks_banner_hidden(page: Page, timeout: int = 30000) -> None:
+ """Wait for all background tasks to be completed."""
+ page.wait_for_selector("#ongoing-tasks-banner", state="hidden",
timeout=timeout)
diff --git a/tests/e2e/vote/helpers.py b/tests/e2e/vote/helpers.py
new file mode 100644
index 0000000..0bb32ff
--- /dev/null
+++ b/tests/e2e/vote/helpers.py
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from playwright.sync_api import Locator, Page
+
+
+def get_curl_command_text(page: Page) -> Locator:
+ """Return the curl command text locator."""
+ return page.locator("#curl-command")
+
+
+def get_curl_copy_button(page: Page) -> Locator:
+ """Return the curl command copy button locator."""
+ return
page.locator('button.atr-copy-btn[data-clipboard-target="#curl-command"]')
+
+
+def get_rsync_command_text(page: Page) -> Locator:
+ """Return the rsync command text locator."""
+ return page.locator("#rsync-command")
+
+
+def get_rsync_copy_button(page: Page) -> Locator:
+ """Return the rsync command copy button locator."""
+ return
page.locator('button.atr-copy-btn[data-clipboard-target="#rsync-command"]')
diff --git a/tests/e2e/vote/test_get.py b/tests/e2e/vote/test_get.py
new file mode 100644
index 0000000..df79fb6
--- /dev/null
+++ b/tests/e2e/vote/test_get.py
@@ -0,0 +1,126 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import e2e.vote.helpers as helpers # type: ignore[reportMissingImports]
+from playwright.sync_api import Page, expect
+
+
+def test_browse_files_link_visible(page_vote: Page) -> None:
+ """The browse files link should be visible."""
+ browse_link = page_vote.locator('a:has-text("Browse files")')
+ expect(browse_link).to_be_visible()
+
+
+def test_curl_command_contains_expected_text(page_vote: Page) -> None:
+ """The curl command should contain the expected curl invocation."""
+ command_text = helpers.get_curl_command_text(page_vote)
+ expect(command_text).to_contain_text("curl -s https://")
+ expect(command_text).to_contain_text("| sh")
+
+
+def test_curl_copy_button_restores_original_text(page_vote: Page) -> None:
+ """The curl copy button should restore original text after feedback."""
+ copy_button = helpers.get_curl_copy_button(page_vote)
+ copy_button.click()
+
+ expect(copy_button).to_contain_text("Copy", timeout=5000)
+
+
+def test_curl_copy_button_shows_copied_feedback(page_vote: Page) -> None:
+ """Clicking the curl copy button should show Copied feedback."""
+ copy_button = helpers.get_curl_copy_button(page_vote)
+ expect(copy_button).to_contain_text("Copy")
+
+ copy_button.click()
+
+ expect(copy_button).to_contain_text("Copied!")
+
+
+def test_curl_copy_button_visible(page_vote: Page) -> None:
+ """The curl copy button should be visible on the vote page."""
+ copy_button = helpers.get_curl_copy_button(page_vote)
+ expect(copy_button).to_be_visible()
+
+
+def test_download_zip_button_visible(page_vote: Page) -> None:
+ """The download ZIP button should be visible for authenticated users."""
+ zip_button = page_vote.locator('a:has-text("Download all (ZIP)")')
+ expect(zip_button).to_be_visible()
+
+
+def test_page_has_checks_section(page_vote: Page) -> None:
+ """The vote page should have a checks section."""
+ checks_heading = page_vote.locator("h2#checks")
+ expect(checks_heading).to_be_visible()
+ expect(checks_heading).to_contain_text("Review file checks")
+
+
+def test_page_has_download_section(page_vote: Page) -> None:
+ """The vote page should have a download section."""
+ download_heading = page_vote.locator("h2#download")
+ expect(download_heading).to_be_visible()
+ expect(download_heading).to_contain_text("Download")
+
+
+def test_page_has_vote_section(page_vote: Page) -> None:
+ """The vote page should have a vote section."""
+ vote_heading = page_vote.locator("h2#vote")
+ expect(vote_heading).to_be_visible()
+ expect(vote_heading).to_contain_text("Cast your vote")
+
+
+def test_rsync_command_contains_expected_text(page_vote: Page) -> None:
+ """The rsync command should contain the expected rsync invocation."""
+ command_text = helpers.get_rsync_command_text(page_vote)
+ expect(command_text).to_contain_text("rsync -av")
+ # We don't include the port since that can be configured
+ expect(command_text).to_contain_text("-e 'ssh -p")
+
+
+def test_rsync_copy_button_restores_original_text(page_vote: Page) -> None:
+ """The rsync copy button should restore original text after feedback."""
+ copy_button = helpers.get_rsync_copy_button(page_vote)
+ copy_button.click()
+
+ expect(copy_button).to_contain_text("Copy", timeout=5000)
+
+
+def test_rsync_copy_button_shows_copied_feedback(page_vote: Page) -> None:
+ """Clicking the rsync copy button should show Copied feedback."""
+ copy_button = helpers.get_rsync_copy_button(page_vote)
+ expect(copy_button).to_contain_text("Copy")
+
+ copy_button.click()
+
+ expect(copy_button).to_contain_text("Copied!")
+
+
+def test_rsync_copy_button_visible(page_vote: Page) -> None:
+ """The rsync copy button should be visible for authenticated users."""
+ copy_button = helpers.get_rsync_copy_button(page_vote)
+ expect(copy_button).to_be_visible()
+
+
+def test_vote_buttons_visible(page_vote: Page) -> None:
+ """The vote decision buttons should be visible."""
+ plus_one = page_vote.locator('label[for="decision_0"]')
+ zero = page_vote.locator('label[for="decision_1"]')
+ minus_one = page_vote.locator('label[for="decision_2"]')
+
+ expect(plus_one).to_be_visible()
+ expect(zero).to_be_visible()
+ expect(minus_one).to_be_visible()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]