From 7955477863d8846179354674d299def3cdbc1d8f Mon Sep 17 00:00:00 2001 From: Jay Goss Date: Fri, 2 Oct 2026 14:48:15 -0500 Subject: [PATCH 1/2] test(onboarding): Run create-project acceptance tests through SCM project creation Port the legacy create-project acceptance coverage (inline team creation and project deletion on going back) to the SCM flow and drop the legacy class. Enable SCM project creation in the org creation and quick start tests, which land on the create-project page, so all of them keep passing once the legacy flow is removed. Platform selection is already covered by test_create_without_repository. Refs VDY-235 --- tests/acceptance/test_create_organization.py | 6 +- tests/acceptance/test_create_project.py | 100 +++++++++---------- tests/acceptance/test_quick_start.py | 12 ++- 3 files changed, 57 insertions(+), 61 deletions(-) diff --git a/tests/acceptance/test_create_organization.py b/tests/acceptance/test_create_organization.py index 533e60b731fe..7d1b169366a4 100644 --- a/tests/acceptance/test_create_organization.py +++ b/tests/acceptance/test_create_organization.py @@ -1,6 +1,7 @@ from django.test import override_settings from sentry.testutils.cases import AcceptanceTestCase +from sentry.testutils.helpers.features import with_feature from sentry.testutils.silo import no_silo_test @@ -11,6 +12,7 @@ def setUp(self) -> None: self.user = self.create_user("foo@example.com") self.login_as(self.user) + @with_feature("organizations:onboarding-scm-project-creation") @override_settings( PRIVACY_URL="https://sentry.io/privacy/", TERMS_URL="https://sentry.io/terms/" ) @@ -24,5 +26,5 @@ def test_simple(self) -> None: self.browser.element('input[name="agreeTerms"]').click() self.browser.click('button[type="submit"]') # After creating an org should end up on create project - self.browser.wait_until_test_id("platform-javascript-react") - assert self.browser.element_exists_by_test_id("create-project") + self.browser.wait_until(xpath='//h4[text()="Repository"]') + assert self.browser.element_exists(xpath='//button[contains(., "Create project")]') diff --git a/tests/acceptance/test_create_project.py b/tests/acceptance/test_create_project.py index de15f9069b44..965e9fddfbbb 100644 --- a/tests/acceptance/test_create_project.py +++ b/tests/acceptance/test_create_project.py @@ -9,61 +9,6 @@ from sentry.testutils.thread_leaks.pytest import thread_leak_allowlist -@no_silo_test -@thread_leak_allowlist(reason="sentry sdk background worker", issue=97042) -class CreateProjectTest(AcceptanceTestCase): - def setUp(self) -> None: - super().setUp() - self.user = self.create_user("foo@example.com") - self.org = self.create_organization(name="Rowdy Tiger", owner=self.user) - self.login_as(self.user) - self.path = f"/organizations/{self.org.slug}/projects/new/" - - def load_project_creation_page(self) -> None: - self.browser.get(self.path) - self.browser.wait_until('[aria-label="Create Project"]') - - def test_no_teams(self) -> None: - self.load_project_creation_page() - self.browser.click(None, "//*[text()='Select a Team']") - self.browser.click('[data-test-id="create-team-option"]') - self.browser.wait_until("[role='dialog']") - input = self.browser.element('input[name="slug"]') - input.send_keys("new-team") - self.browser.element("[role='dialog'] form").submit() - self.browser.wait_until(xpath='//div[text()="#new-team"]') - - def test_select_correct_platform(self) -> None: - self.create_team(organization=self.org, name="team three") - self.load_project_creation_page() - self.browser.click("[data-test-id='platform-javascript-react']") - self.browser.click('[data-test-id="create-project"]') - self.browser.wait_until(xpath="//h2[text()='Configure React SDK']") - - def test_project_deletion_on_going_back(self) -> None: - self.create_team(organization=self.org, name="team three", members=[self.user]) - self.load_project_creation_page() - self.browser.click("[data-test-id='platform-php-laravel']") - self.browser.click('[data-test-id="create-project"]') - self.browser.wait_until(xpath="//h2[text()='Configure Laravel SDK']") - project1 = Project.objects.get(organization=self.org, slug="php-laravel") - self.browser.click('[aria-label="Back to Platform Selection"]') - self.browser.wait_until("[data-test-id='platform-javascript-nextjs']") - self.browser.driver.execute_script( - "arguments[0].click()", - self.browser.element("[data-test-id='platform-javascript-nextjs']"), - ) - self.browser.click('[data-test-id="create-project"]') - self.browser.wait_until(xpath="//h2[text()='Configure Next.js SDK']") - project2 = Project.objects.get(organization=self.org, slug="javascript-nextjs") - self.browser.back() - self.browser.get("/organizations/%s/projects/" % self.org.slug) - self.browser.wait_until(xpath='//*[text()="Remain Calm"]') - assert_existing_projects_status( - self.org, active_project_ids=[], deleted_project_ids=[project1.id, project2.id] - ) - - @no_silo_test @thread_leak_allowlist(reason="sentry sdk background worker", issue=97042) class ScmCreateProjectTest(AcceptanceTestCase): @@ -280,3 +225,48 @@ def test_create_with_existing_integration(self) -> None: self.select_repository() self.create_scm_project("Django", "python-django") + + def select_platform(self, name: str) -> None: + platform_input = self.browser.element('input[aria-autocomplete="list"]') + platform_input.send_keys(name) + option = f'//p[@data-test-id="menu-list-item-label"][text()="{name}"]' + self.browser.wait_until(xpath=option) + self.browser.click(xpath=option) + + def test_create_team(self) -> None: + org = self.create_organization(name="Rowdy Tiger", owner=self.user) + + with self.feature({"organizations:onboarding-scm-project-creation": True}): + self.browser.get(f"/organizations/{org.slug}/projects/new/") + self.browser.wait_until(xpath='//h4[text()="Repository"]') + + self.browser.click(None, "//*[text()='Select a Team']") + self.browser.click('[data-test-id="create-team-option"]') + self.browser.wait_until("[role='dialog']") + input = self.browser.element('input[name="slug"]') + input.send_keys("new-team") + self.browser.element("[role='dialog'] form").submit() + self.browser.wait_until(xpath='//div[text()="#new-team"]') + + def test_project_deletion_on_going_back(self) -> None: + with self.feature({"organizations:onboarding-scm-project-creation": True}): + self.load_project_creation_page() + self.select_platform("Laravel") + self.browser.click(xpath='//button[contains(., "Create project")]') + self.browser.wait_until(xpath="//h2[text()='Configure Laravel SDK']") + project1 = Project.objects.get(organization=self.org, slug="php-laravel") + + self.browser.click(xpath='//button[contains(., "Back to Platform Selection")]') + self.load_project_creation_page() + self.select_platform("Next.js") + self.browser.wait_until_clickable(xpath='//button[contains(., "Create project")]') + self.browser.click(xpath='//button[contains(., "Create project")]') + self.browser.wait_until(xpath="//h2[text()='Configure Next.js SDK']") + project2 = Project.objects.get(organization=self.org, slug="javascript-nextjs") + + self.browser.back() + self.browser.get(f"/organizations/{self.org.slug}/projects/") + self.browser.wait_until(xpath='//*[text()="Remain Calm"]') + assert_existing_projects_status( + self.org, active_project_ids=[], deleted_project_ids=[project1.id, project2.id] + ) diff --git a/tests/acceptance/test_quick_start.py b/tests/acceptance/test_quick_start.py index 8ec77f342e4f..543739f10cbb 100644 --- a/tests/acceptance/test_quick_start.py +++ b/tests/acceptance/test_quick_start.py @@ -20,7 +20,7 @@ def setUp(self) -> None: self.user = self.create_user("foo@example.com") self.login_as(self.user) - @with_feature("organizations:onboarding") + @with_feature(["organizations:onboarding", "organizations:onboarding-scm-project-creation"]) @override_settings( PRIVACY_URL="https://sentry.io/privacy/", TERMS_URL="https://sentry.io/terms/" ) @@ -32,9 +32,13 @@ def test_quick_start_sidebar_is_not_automatically_opened_after_project_creation( self.browser.element('input[name="agreeTerms"]').click() self.browser.click('button[type="submit"]') - self.browser.wait_until_test_id("platform-javascript-react") - self.browser.click('[data-test-id="platform-javascript-react"') - self.browser.click('button[aria-label="Create Project"]') + self.browser.wait_until(xpath='//h4[text()="Repository"]') + self.browser.element('input[aria-autocomplete="list"]').send_keys("React") + react_option = '//p[@data-test-id="menu-list-item-label"][text()="React"]' + self.browser.wait_until(xpath=react_option) + self.browser.click(xpath=react_option) + self.browser.wait_until_clickable(xpath='//button[contains(., "Create project")]') + self.browser.click(xpath='//button[contains(., "Create project")]') self.browser.wait_until(xpath='//h2[text()="Configure React SDK"]') From 8cf0e44383daa85e1f2bcd04ed72ae3220242864 Mon Sep 17 00:00:00 2001 From: Jay Goss Date: Fri, 2 Oct 2026 15:24:08 -0500 Subject: [PATCH 2/2] test(onboarding): Wait for the restored form after going back from setup docs Follow the back navigation instead of reloading the create-project page so the test waits for the project deletion, and reuse select_platform in test_create_without_repository. --- tests/acceptance/test_create_project.py | 35 ++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/tests/acceptance/test_create_project.py b/tests/acceptance/test_create_project.py index 965e9fddfbbb..d9d3dbb65da0 100644 --- a/tests/acceptance/test_create_project.py +++ b/tests/acceptance/test_create_project.py @@ -1,5 +1,9 @@ from unittest import mock +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions +from selenium.webdriver.support.wait import WebDriverWait + from sentry.integrations.github.integration import GitHubOAuthLoginResult from sentry.integrations.models.integration import Integration from sentry.models.project import Project @@ -58,6 +62,13 @@ def load_project_creation_page(self) -> None: self.browser.get(self.path) self.browser.wait_until(xpath='//h4[text()="Repository"]') + def select_platform(self, name: str) -> None: + platform_input = self.browser.element('input[aria-autocomplete="list"]') + platform_input.send_keys(name) + option = f'//p[@data-test-id="menu-list-item-label"][text()="{name}"]' + self.browser.wait_until(xpath=option) + self.browser.click(xpath=option) + def select_repository(self) -> None: repository_input = self.browser.element('input[aria-autocomplete="list"]') repository_input.send_keys("sentry") @@ -179,13 +190,7 @@ def test_create_without_repository(self) -> None: } ): self.load_project_creation_page() - - platform_input = self.browser.element('input[aria-autocomplete="list"]') - platform_input.send_keys("React") - self.browser.wait_until( - xpath='//p[@data-test-id="menu-list-item-label"][text()="React"]' - ) - self.browser.click(xpath='//p[@data-test-id="menu-list-item-label"][text()="React"]') + self.select_platform("React") self.browser.wait_until(xpath='//*[@role="checkbox"][.//*[text()="Tracing"]]') self.browser.click(xpath='//*[@role="checkbox"][.//*[text()="Tracing"]]') @@ -226,13 +231,6 @@ def test_create_with_existing_integration(self) -> None: self.select_repository() self.create_scm_project("Django", "python-django") - def select_platform(self, name: str) -> None: - platform_input = self.browser.element('input[aria-autocomplete="list"]') - platform_input.send_keys(name) - option = f'//p[@data-test-id="menu-list-item-label"][text()="{name}"]' - self.browser.wait_until(xpath=option) - self.browser.click(xpath=option) - def test_create_team(self) -> None: org = self.create_organization(name="Rowdy Tiger", owner=self.user) @@ -252,12 +250,19 @@ def test_project_deletion_on_going_back(self) -> None: with self.feature({"organizations:onboarding-scm-project-creation": True}): self.load_project_creation_page() self.select_platform("Laravel") + self.browser.wait_until_clickable(xpath='//button[contains(., "Create project")]') self.browser.click(xpath='//button[contains(., "Create project")]') self.browser.wait_until(xpath="//h2[text()='Configure Laravel SDK']") project1 = Project.objects.get(organization=self.org, slug="php-laravel") + # Going back deletes the project before returning to the form, which + # restores the Laravel selection. self.browser.click(xpath='//button[contains(., "Back to Platform Selection")]') - self.load_project_creation_page() + WebDriverWait(self.browser.driver, 10).until( + expected_conditions.text_to_be_present_in_element_value( + (By.CSS_SELECTOR, 'input[placeholder="project-name"]'), "php-laravel" + ) + ) self.select_platform("Next.js") self.browser.wait_until_clickable(xpath='//button[contains(., "Create project")]') self.browser.click(xpath='//button[contains(., "Create project")]')