Skip to content

feat(onboarding): Bulletproof critical back actions with new tests #88532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/sentry/testutils/asserts.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

from django.http import StreamingHttpResponse

from sentry.constants import ObjectStatus
from sentry.integrations.types import EventLifecycleOutcome
from sentry.models.auditlogentry import AuditLogEntry
from sentry.models.commitfilechange import CommitFileChange
from sentry.models.organization import Organization
from sentry.models.project import Project
from sentry.silo.base import SiloMode
from sentry.testutils.silo import assume_test_silo_mode

Expand Down Expand Up @@ -45,6 +48,23 @@ def assert_status_code(response, minimum: int, maximum: int | None = None):
)


def assert_existing_projects_status(
org: Organization, active_project_ids: list[int], deleted_project_ids: list[int]
):
all_projects = Project.objects.filter(organization=org).values_list("id", "status")
active_ids = []
deleted_or_to_be_deleted_ids = []

for project_id, status in all_projects:
if status == ObjectStatus.ACTIVE:
active_ids.append(project_id)
else:
deleted_or_to_be_deleted_ids.append(project_id)

assert active_ids == active_project_ids
assert deleted_or_to_be_deleted_ids == deleted_project_ids


@assume_test_silo_mode(SiloMode.CONTROL)
def org_audit_log_exists(**kwargs):
assert kwargs
Expand Down
45 changes: 25 additions & 20 deletions tests/acceptance/test_create_project.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from selenium.webdriver.common.by import By

from sentry.models.project import Project
from sentry.testutils.asserts import assert_existing_projects_status
from sentry.testutils.cases import AcceptanceTestCase
from sentry.testutils.silo import no_silo_test

Expand All @@ -11,37 +11,42 @@ def setUp(self):
self.user = self.create_user("[email protected]")
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 test_no_teams(self):
def load_project_creation_page(self):
self.browser.get(self.path)
self.browser.wait_until_not(".loading")
self.browser.wait_until('[aria-label="Create Project"]')

def test_no_teams(self):
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()

# After creating team, should end up in onboarding screen
self.browser.wait_until(xpath='//div[text()="#new-team"]')

def test_select_correct_platform(self):
self.create_team(organization=self.org, name="team three")

self.browser.get(self.path)
self.browser.wait_until_not(".loading")

self.browser.click('[data-test-id="platform-javascript-react"]')
self.browser.wait_until_not(".loading")
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']")

self.browser.wait_until_not(".loading")
self.browser.wait_until("h2")

title = self.browser.find_element(by=By.CSS_SELECTOR, value="h2")

assert "React" in title.text
def test_project_deletion_on_going_back(self):
self.create_team(organization=self.org, name="team three")
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.click("[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='//h1[text()="Remain Calm"]')
assert_existing_projects_status(self.org, [], [project1.id, project2.id])
94 changes: 55 additions & 39 deletions tests/acceptance/test_onboarding.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from selenium.common.exceptions import TimeoutException
import pytest

from sentry.models.project import Project
from sentry.testutils.asserts import assert_existing_projects_status
from sentry.testutils.cases import AcceptanceTestCase
from sentry.testutils.silo import no_silo_test
from sentry.utils.retries import TimedRetryPolicy

pytestmark = pytest.mark.sentry_metrics


@no_silo_test
Expand All @@ -18,55 +20,69 @@ def setUp(self):
)
self.login_as(self.user)

def test_onboarding(self):
def start_onboarding(self):
self.browser.get("/onboarding/%s/" % self.org.slug)

# Welcome step
self.browser.wait_until('[data-test-id="onboarding-step-welcome"]')
self.browser.click('[aria-label="Start"]')

# Platform selection step
self.browser.wait_until('[data-test-id="onboarding-step-select-platform"]')

@TimedRetryPolicy.wrap(timeout=5, exceptions=((TimeoutException,)))
def click_platform_select_name(browser):
# Select and create React project
browser.click('[data-test-id="platform-javascript-react"]')

# Project getting started loads
browser.wait_until(xpath='//h2[text()="Configure React SDK"]')

click_platform_select_name(self.browser)

# Verify project was created for org
project = Project.objects.get(organization=self.org)
def test_onboarding_happy_path(self):
self.start_onboarding()
self.browser.click('[data-test-id="platform-javascript-react"]')
self.browser.wait_until(xpath='//h2[text()="Configure React SDK"]')
project = Project.objects.get(organization=self.org, slug="javascript-react")
assert project.name == "javascript-react"
assert project.platform == "javascript-react"

# Click on back button
assert_existing_projects_status(self.org, [project.id], [])

def test_project_deletion_on_going_back(self):
self.start_onboarding()
self.browser.click('[data-test-id="platform-javascript-nextjs"]')
self.browser.wait_until(xpath='//h2[text()="Configure Next.js SDK"]')
project1 = Project.objects.get(organization=self.org, slug="javascript-nextjs")
assert project1.name == "javascript-nextjs"
assert project1.platform == "javascript-nextjs"
self.browser.click('[aria-label="Back"]')

# Assert no deletion confirm dialog is shown
assert not self.browser.element_exists("[role='dialog']")

# Platform selection step
self.browser.wait_until('[data-test-id="onboarding-step-select-platform"]')

# Select generic platform
self.browser.click('[data-test-id="platform-javascript-react"]')
self.browser.wait_until(xpath='//h2[text()="Configure React SDK"]')
project2 = Project.objects.get(organization=self.org, slug="javascript-react")
assert project2.name == "javascript-react"
assert project2.platform == "javascript-react"
self.browser.back()
self.browser.click(xpath='//a[text()="Skip Onboarding"]')
self.browser.get("/organizations/%s/projects/" % self.org.slug)
self.browser.wait_until(xpath='//h1[text()="Remain Calm"]')
assert_existing_projects_status(self.org, [], [project1.id, project2.id])

def test_framework_modal_open_by_selecting_vanilla_platform(self):
self.start_onboarding()
self.browser.click('[data-test-id="platform-javascript"]')

# Modal is shown prompting to select a framework
self.browser.wait_until(xpath='//h6[text()="Do you use a framework?"]')

# Close modal
self.browser.click('[aria-label="Close Modal"]')

# Platform is not selected
assert not self.browser.element_exists('[aria-label="Clear"]')

# Click again on the modal and continue with the vanilla project
self.browser.click('[data-test-id="platform-javascript"]')
self.browser.click('[aria-label="Configure SDK"]')

# Project getting started loads
self.browser.wait_until(xpath='//h2[text()="Configure Browser JavaScript SDK"]')
project = Project.objects.get(organization=self.org, slug="javascript")
assert project.name == "javascript"
assert project.platform == "javascript"
assert_existing_projects_status(self.org, [project.id], [])

def test_create_delete_create_same_platform(self):
"This test ensures that the regression fixed in PR https://github.com/getsentry/sentry/pull/87869 no longer occurs."
self.start_onboarding()
self.browser.click('[data-test-id="platform-javascript-nextjs"]')
self.browser.wait_until(xpath='//h2[text()="Configure Next.js SDK"]')
project1 = Project.objects.get(organization=self.org, slug="javascript-nextjs")
assert project1.name == "javascript-nextjs"
assert project1.platform == "javascript-nextjs"
self.browser.click('[aria-label="Back"]')
self.browser.click('[data-test-id="platform-javascript-nextjs"]')
self.browser.wait_until(xpath='//h2[text()="Configure Next.js SDK"]')
project2 = Project.objects.get(organization=self.org, slug="javascript-nextjs")
assert project2.name == "javascript-nextjs"
assert project2.platform == "javascript-nextjs"
self.browser.click(xpath='//a[text()="Skip Onboarding"]')
self.browser.get("/organizations/%s/projects/" % self.org.slug)
self.browser.wait_until("[data-test-id='javascript-nextjs']")
assert_existing_projects_status(self.org, [project2.id], [project1.id])
Loading