Skip to content

refactor(tests): remove test smells from sync tests - #3309

Closed
Cauan Ricardo (cauanrricardo) wants to merge 42 commits into
microsoft:mainfrom
cauanrricardo:refatoracao-test-smells
Closed

Cauan Ricardo (cauanrricardo) wants to merge 42 commits into
microsoft:mainfrom
cauanrricardo:refatoracao-test-smells

Conversation

@cauanrricardo

Copy link
Copy Markdown

Closes #3308

What

Refactors 41 test smell occurrences across 16 files in tests/sync/, one commit per refactoring, plus one formatting commit (black). Smells addressed (detected with TEMPY): Conditional Test Logic (25), Exception Handling (7), Verbose Test (6) and Non-Functional Statement (3).

Why

Conditional logic, try/except inside tests and very long tests make tests harder to read and to diagnose when they fail. The refactorings make each test a linear flow (dict lookups, parametrization, pytest.raises, fixtures, small helpers) while verifying the same behavior.

How tested

  • Ran the affected test files after each refactoring, on Chromium.
  • Ran the full suite before and after on Chromium, Firefox and WebKit: the same pre-existing failures/errors as before, no new ones. Coverage unchanged (92.31%).
  • Number of tests changes slightly in some files because of parametrization and splitting; 3 more tests are skipped due to skip_browser on split browser-specific tests.
  • black, isort and flake8 pass on all changed files (versions from .pre-commit-config.yaml).
  • TEMPY-detected smells: 267 → 226.

Notes for reviewers

  • Each commit is a single, self-contained refactoring, so it can be reviewed or dropped independently. I'm happy to split this into smaller PRs if you prefer.
  • In a few cases a failure message is less detailed than before; those are noted in the commit messages.
  • This is part of a software quality course project at the Federal University of Ceará (UFC).

Authors

  • Cauan Ricardo (@cauanrricardo): 20 refactorings in test_screencast.py, test_sync.py, test_launcher.py, test_element_handle.py, test_console.py, test_fetch_browser_context.py, test_browsercontext_storage_state.py, test_queryselector.py and test_browsertype_connect.py
  • Clidenor (@ClidenorFilho): 21 refactorings in test_assertions.py, test_browsercontext_request_fallback.py, test_fetch_global.py, test_har.py, test_locators.py, test_page_request_fallback.py and test_page_add_locator_handler.py

…ndler_times_out (Exception Handling + Non-Functional Statement)
…default_should_abort_requests_not_found_in_har
Replace the try/finally around screencast.start() with a with block, so
stop() runs on exit without manual exception handling.

Smell: Exception Handling
Compare browser_type.name directly with the browser_name fixture instead
of branching on is_webkit/is_firefox/is_chromium, so the test has a
single assertion path for every browser.

Smell: Conditional Test Logic
The inline loop duplicated the ensure_some_frames helper already defined
in this file (100 paint cycles followed by a screenshot), so call it
instead of repeating the loop.

Smell: Conditional Test Logic
Assert the viewport height and timestamp type of every received frame
with all() over the frames instead of looping with assertions inside.

Smell: Conditional Test Logic
The pointer-cursor show_actions block had an empty pass body. Render a
button and click it inside the block so the test exercises show_actions
instead of entering and leaving it without doing anything.

Smell: Non-Functional Statement
The cursor="none" show_actions block also had an empty pass body. Click
the same button inside it so both cursor values are exercised by a real
action.

Smell: Non-Functional Statement
Replace the try/except plus assert False with pytest.raises(Error), so
the test fails loudly if evaluate() does not raise, and check the error
message afterwards.

Smell: Exception Handling
Replace the try/finally around the first screencast.start() with a with
block, so stop() runs on exit while pytest.raises keeps checking the
"already started" error.

Smell: Exception Handling
…n test_should_delete_header_with_undefined_value
…ponse_with_text_content_type_if_to_be_ok_fails
Replace the try/finally around screencast.start() with a with block, so
stop() runs on exit without manual exception handling.

Smell: Exception Handling
Give ensure_some_frames a count parameter (default 100, so other callers
are unchanged) and use it with count=3 instead of repeating the inline
paint-cycle loop followed by a screenshot.

Smell: Conditional Test Logic
Run test_scroll once per offscreen button with pytest.mark.parametrize
instead of looping inside a single test. Each case now gets a fresh page,
so the scrollTo(0, 0) reset between iterations is no longer needed.

Smell: Conditional Test Logic
Check each closed page with its own pytest.raises block instead of
looping over a list of pages, so a failure points at the exact page.

Smell: Conditional Test Logic
test_should_set_local_storage verified two unrelated things in about 50
lines. Move the shared storage state, context and page setup into a
fixture and check localStorage and IndexedDB in separate tests.

Smell: Verbose Test
Replace the index loop with one assertion comparing all last-modified
timestamps with pytest.approx(abs=1000). The tolerance is the same, but
the bound is now inclusive (<= 1000 instead of < 1000).

Smell: Conditional Test Logic
Choose the expected console message text with a dict lookup keyed by
browser_name instead of an if/else, keeping the same test and the same
assertions for every browser.

Smell: Conditional Test Logic
Choose the expected console message text with a dict lookup keyed by
browser_name instead of an if/else, keeping the same test and the same
assertions for every browser.

Smell: Conditional Test Logic
Replace the if/else on browser_name with a lookup of the expected text,
keeping the same test, ID and assertion.

Smell: Conditional Test Logic
The try/finally that stopped the HTTPServer now lives in a yield fixture,
so the timing test only holds the assertions. Assertions are unchanged.

Smell: Exception Handling
…r tests

Move the engine registration and page setup into a fixture and split the
long test into main world, isolated world and chaining tests. Every
assertion is kept as is.

Smell: Verbose Test
Move the deadline while loop to wait_for_received_frames, next to
ensure_some_frames. Same 10s deadline and 100ms polling step, so timing
is unchanged.

Smell: Conditional Test Logic
@cauanrricardo

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@cauanrricardo

Copy link
Copy Markdown
Author

Note on merge conflicts: this work was done against commit 3705559 (the base of this branch). Since then, main reorganized and rewrote the test suite (#3276, feat(v2): add playwright/_impl_v2), moving files from tests/sync/ into subfolders such as tests/sync/library/, tests/sync/python/ and tests/sync/page/, and removing some of them. Because of that, this branch no longer merges cleanly.

The changes are small, independent commits (one refactoring each), so they can be ported to the new layout. If the maintainers are interested, we are happy to rebase or re-apply them on top of the current main, or split them into smaller PRs. Linked issue: #3308.

@ClidenorFilho

Copy link
Copy Markdown

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Refactor test smells in tests/sync (conditional logic, exception handling, verbose tests)

3 participants