-
Notifications
You must be signed in to change notification settings - Fork 34
Major Feature Parity Update #75
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
Open
tristanperalta
wants to merge
52
commits into
coreyti:main
Choose a base branch
from
tristanperalta:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- Upgrade Elixir from 1.16.2-otp-26 to 1.18.4-otp-27 - Upgrade Erlang from 26.2.5 to 27.3.4.6 - Upgrade Node.js from 22.2.0 to 22.21.1 - Migrate from asdf (.tool-versions) to mise (.mise.toml) - Update CI workflow to use new versions - Fix `mix playwright.install` to support Arch Linux and Ubuntu - Add OS detection to install system dependencies appropriately - Install both Chromium and Firefox browsers explicitly The playwright install task now detects the OS and: - On Arch Linux: Installs dependencies via pacman, then browsers - On Ubuntu/Debian: Uses --with-deps flag as before - On unknown OS: Installs browsers without system dependencies
- credo: 1.6 → 1.7 - dialyxir: 1.1 → 1.4 - esbuild: 0.8.1 → 0.10 - ex_doc: 0.34 → 0.39 - mix_audit: 1.0 → 2.1 - recase: 0.7 → 0.9 Note: cowlib and gun cannot be upgraded due to playwright_assets constraints requiring cowlib ~> 2.7.3
- Use forked playwright_assets (github: tristanperalta/playwright-assets) to unblock dependency upgrades - Upgrade cowlib 2.7.3 → 2.16.0, gun 1.3.3 → 2.2.0, cowboy 2.6.3 → 2.14.2 - Fix gun 2.x API: ws_send/2 → ws_send/3 (requires stream_ref) - Fix regex route patterns: use camelCase keys (regexSource/regexFlags) and convert Elixir regex opts to JS flags - Rename unit_test.ex → unit_case.ex to silence ExUnit warning
Credo fixes: - route_handler.ex: Use Enum.map_join instead of Enum.map |> Enum.join - config.ex: Remove parentheses from zero-arity function definitions - page.ex: Alphabetize alias groups - channel.ex: Extract async_evaluate/2 to reduce nesting depth - frame.ex: Split select_option_values into pattern-matched clauses - .credo.exs: Disable PredicateFunctionNames (is_* matches Playwright API) Documentation: - Add man/guides/contributing.md documenting known issues and improvements - Add contributing guide to mix.exs docs config
Dialyzer fixes: - Fix @SPEC for BrowserContext.route/4, unroute/3, Page.route/4 - Return type changed from :ok to t() | {:error, Channel.Error.t()} - Added Regex.t() to pattern parameter types New precommit task (mix precommit): - compile --warnings-as-errors - format --check-formatted - credo --strict - dialyzer - test Also: - Fix trailing blank lines (mix format)
Browser.new_page/2 now returns {:ok, Page.t()} instead of Page.t()
Changes:
- Browser.new_page/2 now returns {:ok, page} tuple with proper error handling
- Page.on/3 validates events against whitelist to prevent atom exhaustion
- ChannelOwner.module/1 uses reraise instead of exit() for proper error handling
- Page.close/1 uses latest channel state for owned_context check
- Page.request/1 fetches fresh page state for owned_context access
- Remove dead code: FetchRequest module (not in modern Playwright API)
- Fix with_latest/2 to explicitly discard first find result
Test updates:
- Update all tests to use {:ok, page} pattern matching
- Use Page.owned_context(page) instead of page.owned_context field access
- Set async: false for browser/context tests needing exclusive access
- Add man/guides/feature_parity.md documenting implementation status of all Playwright features compared to TypeScript client - Add .claude/ to .gitignore - Add feature_parity.md to mix.exs docs config
Implement Page and Frame navigation methods: - Page.go_back/2 - Navigate to previous page in history - Page.go_forward/2 - Navigate to next page in history - Page.wait_for_url/3 - Wait for URL to match pattern - Frame.wait_for_url/3 - Same for frames wait_for_url supports: - Glob patterns (e.g., "**/login") - Regex patterns (e.g., ~r/dashboard$/) - Function predicates (e.g., fn url -> ... end) Implementation uses polling approach since wait_for_navigation is not yet implemented.
Add support for handling browser dialogs (alert, confirm, prompt, beforeunload): - Dialog.accept/1 and accept/2 for accepting dialogs with optional prompt text - Dialog.dismiss/1 for dismissing/canceling dialogs - Dialog.message/1, type/1, default_value/1, page/1 property accessors Note: Dialog handlers should spawn a Task to avoid deadlock with Connection GenServer when calling Dialog.accept/dismiss from within event handlers.
Implement modern locator methods for Page, Frame, and Locator modules: - get_by_role/3 with full options support (name, checked, disabled, etc.) - get_by_test_id/2 for data-testid attribute selection - get_by_label/3 for label-based element selection All methods follow the existing three-layer delegation pattern and support chaining.
- Replace references to undefined set_default_timeout/2 functions with generic text - Replace references to hidden Channel.Error module with generic error types - Use term() in @SPEC for error returns to avoid hidden module references
Replace references to hidden/private types and functions with generic text: - Channel.Error.t() → term() - Playwright.SDK.Channel.Event → generic "event struct" text - Playwright.SDK.Config types → map() with descriptive text - Playwright.APIResponse.t() → struct() - Playwright.CDPSession.t() → struct() - set_default_timeout/2 references → "BrowserContext or Page timeout settings" - JSHandle.dispose/1 references → generic "disposed" text - BrowserContext.new_page/2 → new_page/1 (correct arity) - Fix unclosed backquote in Locator.all/1 docs
Implement Page.wait_for_navigation and Frame.wait_for_navigation to wait for navigation events with optional URL filtering and load state options. Features: - Trigger function support to avoid race conditions - URL pattern matching (glob, regex, or function predicate) - Configurable wait_until load state - Timeout option with 30s default Also fixes a bug in wait_for_load_state where the predicate checked the event's load state directly instead of fetching the updated frame state, causing "load" state waits to timeout when other events arrived first.
Implement filter/2 to narrow down locator matches by: - has_text/has_not_text: Filter by text content (string or regex) - has/has_not: Filter by presence of nested locator - visible: Filter by element visibility Filters can be combined and chained for complex selections.
Implement storage_state to capture cookies and localStorage for saving and restoring browser sessions. Supports optional path option to save state as JSON file. Also adds Response.parse/2 clauses to handle the storage state response format which contains both cookies and origins keys.
Enables location-based testing by overriding the browser's geolocation. Accepts a map with latitude, longitude, and optional accuracy parameters.
Implements full Download module with Artifact backing: - Download.from_event/1 to create Download from event - save_as/2, path/1, failure/1, cancel/1, delete/1 - url/1, suggested_filename/1, page/1 accessors
Implements click, dblclick, move, down, up, and wheel methods following the Keyboard module pattern.
Implements FrameLocator with all locator methods: first, last, nth, frame_locator, locator, owner, and all get_by_* methods. Adds Page.frame_locator/2 and Frame.frame_locator/2 entry points.
Implements PDF generation with options for format, margins, scale, headers/footers, and more. Chromium headless only. Also adds response parsing for :pdf channel responses.
Implement full Tracing API for debugging and analysis: - start/2, start_chunk/2 for beginning trace recording - stop/2, stop_chunk/2 for stopping and saving traces - group/3, group_end/1 for organizing actions in trace viewer Access via BrowserContext.tracing/1 property accessor.
Implements three missing getBy* methods across Page, Frame, and Locator modules for consistency with FrameLocator (which already had them): - get_by_placeholder/3: locate inputs by placeholder attribute - get_by_alt_text/3: locate elements by alt attribute - get_by_title/3: locate elements by title attribute All methods support the :exact option for case-sensitive whole-string matching (default: false for partial match).
Add delegation methods for element state and content queries: - inner_text/3, inner_html/3, input_value/3 - is_checked/3, is_disabled/3, is_editable/3 - is_enabled/3, is_hidden/3, is_visible/3
- bring_to_front/1: Brings page to front (activates the tab)
- viewport_size/1: Returns current viewport dimensions as %{width, height}
Also added @Property :viewport_size to sync state, and updated
set_viewport_size/2 to patch local state for immediate reads.
Implement FileChooser as a simple struct (like Download) with: - from_event/1 to create FileChooser from :file_chooser events - element/1, is_multiple/1, page/1 accessors - set_files/3 delegating to ElementHandle.set_input_files/3 Key implementation details: - Fixed Page.on/3 to bind :file_chooser to page channel (not context) - Added ElementHandle.set_input_files/3 with file payload preparation - Uses Playwright protocol format (payloads key, timeout required)
Non-deprecated replacement for type/3.
…ached Implement frame tree navigation methods to traverse the frame hierarchy: - page/1: Returns the Page containing the frame - parent_frame/1: Returns the parent frame (nil for main frame) - child_frames/1: Returns list of child frames - is_detached/1: Returns whether frame is detached from DOM - name/1: Returns the frame name
Selector-based methods that delegate to Frame.
Add Frame.highlight/2 to highlight elements matching a selector, useful for debugging. Locator.highlight/1 delegates to Frame.highlight/2. Locator.page/1 returns the Page containing the locator by delegating to the existing Frame.page/1 implementation.
Implement methods to wait for network requests/responses matching URL patterns or custom predicates: - wait_for_request/4: Wait for matching request (glob, regex, or function) - wait_for_response/4: Wait for matching response (glob, regex, or function) Both methods support: - URL glob patterns (e.g., "**/api/users") - Regex patterns - Custom predicate functions for flexible matching - Trigger functions to avoid race conditions - Configurable timeout Also fixes flaky frame hierarchy test by using more specific URL matching.
is_connected/1 checks if the browser is still in the channel catalog, returning false after the browser has been closed. browser_type/1 returns the BrowserType that launched the browser by accessing the parent field from ChannelOwner.
Implement Page.frame/2 method to locate frames matching specified criteria:
- By name string (shorthand): Page.frame(page, "frame-name")
- By name map: Page.frame(page, %{name: "frame-name"})
- By URL with glob/regex/predicate: Page.frame(page, %{url: pattern})
Allows emulating CSS media features including media type (screen/print), color scheme (dark/light), reduced motion, forced colors, and contrast preferences. Pass nil to reset any option to the default value.
Implement methods: - Page.opener/1: Returns the page that opened this popup, or nil - Frame.frame_element/1: Returns the iframe ElementHandle for a frame - Touchscreen.tap/3: Dispatches touch events at given coordinates
Implement Clock module for controlling time: - install/2: Initialize fake timers with optional start time - fast_forward/2: Jump forward, firing timers - pause_at/2: Pause clock at specific time - resume/1: Resume paused clock - run_for/2: Advance by duration, firing timers - set_fixed_time/2: Freeze time (doesn't advance) - set_system_time/2: Set time but allow natural advance Supports time as epoch ms, ISO strings, or DateTime structs. Supports duration as ms or "hh:mm:ss" format.
Adds methods to inject JavaScript and CSS into pages: - Frame.add_script_tag/2 and Frame.add_style_tag/2 send channel commands - Page methods delegate to Frame via main_frame() - Both return ElementHandle for the added element
…ments Delegates to Frame.eval_on_selector_all which was already implemented.
Page and BrowserContext now support: - set_default_timeout/2 - Set default timeout for operations - set_default_navigation_timeout/2 - Set default navigation timeout - set_extra_http_headers/2 - Set extra HTTP headers for requests - unroute_all/2 - Remove all route handlers (Page only)
Implements browser-level tracing for performance profiling: - start_tracing/3: Begin recording with optional screenshots/categories - stop_tracing/1: Stop and return trace data as binary Trace output is JSON format viewable in Chrome DevTools or trace.playwright.dev.
- Route.abort/2: Aborts a route with optional error code - Frame.aria_snapshot/3: Gets ARIA accessibility snapshot for selector - Locator.aria_snapshot/2: Delegates to Frame.aria_snapshot - Added response parser for snapshot results
- Implement Video module with path/1, save_as/2, delete/1 methods - Add Page.video/1 to access video recordings - Use ETS-based storage to persist videos across page lifecycle - Fix Artifact.delete/1 and cancel/1 to return :ok consistently - Video events require actual rendered content to trigger frame capture
Sets HTTP authentication credentials for all requests in the context. Pass nil to disable authentication. Also adds TODO note for Locator.describe/2 which requires Playwright > 1.49.1 (internal:describe selector engine not available in current version).
- Browser.new_browser_cdp_session/1: Creates CDP session at browser level (Chromium only) - BrowserContext.background_pages/1: Returns background pages (stub) - BrowserContext.service_workers/1: Returns service workers (stub) Also fixes feature_parity.md: removed incorrect Locator.owner entry (only exists on FrameLocator which is already implemented).
Implements locator handlers for auto-dismissing overlays, dialogs, and cookie banners during page interactions. Handlers execute when the specified element becomes visible and block actions until resolved.
Implements WebSocket routing for intercepting, mocking, and modifying WebSocket connections. Includes WebSocketRoute module with support for: - Sending/receiving messages to/from page - Connecting to actual server (proxy mode) - Closing connections with custom codes/reasons - Message and close event handlers
Implement Coverage methods for Chromium: - start_js_coverage/2 and stop_js_coverage/1 - start_css_coverage/2 and stop_css_coverage/1 Uses string command names to preserve JS/CSS acronym casing.
These methods return collected console messages and page errors (up to 200 items). Requires Playwright > 1.49.1 to function. Tests are skipped until Playwright is upgraded.
- pause/1: Opens the Playwright Inspector for interactive debugging - request_gc/1: Triggers JavaScript garbage collection in the browser
- tap/3: Performs touch tap action (delegates to Frame.tap) - type/4: Types text character by character (deprecated, use fill)
Add @doc blocks to Frame.drag_and_drop/4, Page.drag_and_drop/4, and Locator.drag_to/3 explaining available options like :force, :steps, :trial, :source_position, and :target_position. These options help with JS drag libraries (like SortableJS) that rely on mousemove events rather than HTML5 drag-and-drop.
tristanperalta
commented
Jan 19, 2026
| {:jason, "~> 1.4"}, | ||
| {:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false}, | ||
| {:playwright_assets, "1.49.1", only: [:test]}, | ||
| {:playwright_assets, github: "tristanperalta/playwright-assets", only: [:test]}, |
Author
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to take note that I forked playwright_assets so that I can upgrade gun.
|
Hey @tristanperalta any way I can contact / speak to you ? 🙏 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This PR brings playwright-elixir significantly closer to feature parity with the official TypeScript Playwright client.
New Modules
Playwright.ArtifactPlaywright.ClockPlaywright.CoveragePlaywright.LocatorHandlersPlaywright.WebSocketRouteNew Methods by Module
Page
add_script_tag/2,add_style_tag/2- Inject scripts/stylesadd_locator_handler/4,remove_locator_handler/2- Auto-dismiss overlaysbring_to_front/1,viewport_size/1- Window managementcheck/3,uncheck/3,set_checked/4,set_input_files/4- Form interactionsconsole_messages/1,page_errors/1- Debug info collectionemulate_media/2- CSS media emulationeval_on_selector_all/4- Evaluate JS on all matchesframe/2- Find frames by name/URLgo_back/2,go_forward/2,wait_for_url/3- Navigationopener/1- Get popup openerpause/1- Open Playwright Inspectorpdf/2- Generate PDFs (Chromium)query_selector/3,query_selector_all/3- DOM queriesrequest_gc/1- Trigger garbage collectionroute_web_socket/3- WebSocket interceptiontap/3,type/4- Touch and keyboard inputvideo/1- Access video recordingswait_for_navigation/3- Wait for navigationwait_for_request/4,wait_for_response/4- Network waitingBrowserContext
route_web_socket/3- WebSocket interceptionset_geolocation/2- Mock geolocationset_http_credentials/2- HTTP authstorage_state/1-2- Session persistenceunroute_all/2- Clear all routesBrowser
browser_type/1- Get browser typeis_connected/1- Check connection statusnew_browser_cdp_session/1- CDP access (Chromium)start_tracing/2,stop_tracing/1- Performance tracingLocator
and_/2,or_/2- Combine locatorsaria_snapshot/2- Accessibility tree snapshotcontent_frame/1- Navigate into iframesfilter/2- Filter by conditionsframe_locator/2- Nested frame navigationget_by_role/3,get_by_test_id/2,get_by_label/3- Semantic locatorsget_by_placeholder/3,get_by_alt_text/3,get_by_title/3highlight/1- Visual debuggingpage/1- Get containing pagepress_sequentially/3- Type character by characterFrame
child_frames/1,parent_frame/1,is_detached/1- Hierarchyframe_element/1- Get iframe elementpage/1- Get containing pagewait_for_navigation/3- Wait for navigationOther Modules
Dialog- Full dialog handling (accept/dismiss/message)Download- Save downloads, get pathsFileChooser- Handle file inputsFrameLocator- Navigate iframesMouse- Click, move, wheel, dragRoute-abort/2for request blockingTouchscreen-tap/3for touch eventsTracing- Record/export tracesVideo- Save video recordingsInfrastructure Improvements
mix precommittask (format, credo, dialyzer, test)Browser.new_page/2