Changelog¶
Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]¶
[1.1.0] - 2026-10-07¶
Added¶
to_have_texts_match(patterns)andto_have_values_contains(values)list assertions- Assertion methods now return
self, enabling fluent chaining (expect(el).to_be_visible().to_be_enabled()) expect.configure()variants expose.pollextend()validates matcher names (must be a public identifier)
Changed¶
to_be_in_frame()takes no arguments and asserts the driver is currently inside a frame (no context switch side effects)to_be_in_default_content()performs a real check instead of always passingExpectConfig.polling_intervalsis normalized to an immutable tuplenormalize_timeout()treats any value >= 1000 as milliseconds (floats included); scalarpollingis normalized the same wayexpect()accepts tuples as list targets- Screenshot capture works for
Alertand element-list targets - Locator assertion failures preserve the inner assertion's error message
pytestruns unit tests by default; usepytest -m integrationfor browser tests- Integration tests run against a local HTTP server (no external network dependency)
SoftAssertionCollectorstores failures per thread/async context (ContextVar), so parallel tests are isolated- Release workflow verifies the tag matches
pyproject.tomlversion (and__version__) before building
Fixed¶
LocatorExpect.to_satisfy_all/any/nonepassed the WebDriver instead of the re-found element to conditionsto_have_frame_availableandto_have_frame_textnow restore the previous frame context (parent_frame) instead of always jumping to top-level contentto_be_visible,to_be_enabled,to_be_checked, andto_be_selectedno longer query the element twice per polltest_smoke.py::test_versionexpected version0.1.0- Documentation: fluent chaining, soft assertions,
expect.configure(), custom matcher, iframe, select, JS, and API-reference examples now match the real API; broken comparison tables fixed
[1.0.0] - 2026-08-27¶
Added¶
- Project skeleton with CI, linting, and build infrastructure
- Regression tests for all bug fixes listed below
CONTRIBUTING.mdwith development setup, testing guidelines, and architecture overviewSECURITY.mdwith vulnerability reporting policyCODE_OF_CONDUCT.mdbased on Contributor Covenant 2.1- GitHub issue templates for bug reports and feature requests
- Automated release workflow (
.github/workflows/release.yml) with PyPI trusted publishing and GitHub Releases expect.configure()example and Features section to README- Ruff badge to README header
- Comprehensive MkDocs documentation with Material theme
- Auto-retry polling with configurable timeout and backoff schedules
- Fluent assertion API for
WebElement,WebDriver,list[WebElement],Alert,Select,ShadowRoot, iframes, cookies, JavaScript, and windows - Locator-based expect to avoid
StaleElementReferenceException - Soft assertions with
SoftAssertionCollectorandassert_all() - Custom matchers via
@extenddecorator andmerge_expects() expect.poll()for retry-based assertions on arbitrary functionsExpectConfigdataclass for global and per-assertion configuration- Screenshot capture on assertion failure
- Debug mode with per-poll logging
- Descriptive error messages with timelines and actual vs expected values
- Composition assertions:
to_satisfy_all,to_satisfy_any,to_satisfy_none - Negation via
.not_on all assertions
Fixed¶
_retry.py: Emptypolling_intervalslist causedIndexErroron first poll_retry.py:timeout=0skipped the first poll, never evaluating the condition_config.py:ExpectConfigdid not validate emptypolling_intervalslists_config.py:set_default_timeout()did not normalize milliseconds (int >= 1000 treated as seconds instead of ms)_poll.py:PollAssertion.to_contain()crashed on falsy non-string values (0,False,[])_poll.py:PollAssertiondid not normalize timeout consistently withexpect()_poll.py: Missing validation for empty per-assertionpollinglists_expect.py:expect(timeout=5000)stored 5000 seconds instead of 5 seconds (timeout not normalized before config overrides)_locator.py:LocatorExpect.__getattr__did not fall back toCustomMatcherRegistry, breaking custom matchers on locator-based assertionslist.py:to_have_texts_containsandto_have_texts_containingcrashed onNoneelement textjs.py:to_have_js_result_containscrashed on falsy non-string values (0,False,[])js.py: JavaScript injection vulnerability inlocalStorage,sessionStorage, andto_have_js_variablemethods (f-string interpolation replaced witharguments[0]parameter passing)driver.py:to_have_capability_containscrashed on falsy non-string capability values (False,0)element.py:to_have_property_containscrashed on falsy non-string property values (False,0)
Changed¶
_expect.py: Replacedexpectfunction with monkeypatched.poll/.configureattributes with a properExpectcallable class — eliminatestype: ignore, improves type safety and API discoverability_base.py: Replacedos/os.pathwithpathlib.Pathfor screenshot path handling_base.py: Screenshot timestamps now use timezone-awaredatetime.now(tz=UTC)instead of naivedatetime.now()_config.py: Centralizednormalize_timeoutfunction imported by all modules that need timeout normalization