Skip to main content

playwright_rs/protocol/
coverage.rs

1// Coverage — Chromium-only code coverage collection
2//
3// See: https://playwright.dev/docs/api/class-coverage
4
5use crate::error::Result;
6use crate::protocol::page::Page;
7
8/// Options for `Coverage::start_js_coverage`.
9///
10/// See: <https://playwright.dev/docs/api/class-coverage#coverage-start-js-coverage>
11#[derive(Debug, Default, Clone)]
12#[non_exhaustive]
13pub struct StartJSCoverageOptions {
14    /// Whether to reset coverage on every navigation.
15    ///
16    /// Defaults to `true`.
17    pub reset_on_navigation: Option<bool>,
18
19    /// Whether to report anonymous scripts generated by the page.
20    ///
21    /// Defaults to `false`.
22    pub report_anonymous_scripts: Option<bool>,
23}
24
25/// Options for `Coverage::start_css_coverage`.
26///
27/// See: <https://playwright.dev/docs/api/class-coverage#coverage-start-css-coverage>
28#[derive(Debug, Default, Clone)]
29#[non_exhaustive]
30pub struct StartCSSCoverageOptions {
31    /// Whether to reset coverage on every navigation.
32    ///
33    /// Defaults to `true`.
34    pub reset_on_navigation: Option<bool>,
35}
36
37/// A byte-offset range within a CSS stylesheet.
38///
39/// Used in [`CSSCoverageEntry`].
40#[derive(Debug, Clone, serde::Deserialize)]
41#[non_exhaustive]
42pub struct CoverageRange {
43    /// Start byte offset (inclusive).
44    pub start: usize,
45    /// End byte offset (exclusive).
46    pub end: usize,
47}
48
49/// A byte-offset range with hit count within a JavaScript function.
50///
51/// Used in [`JSFunctionCoverage`].
52#[derive(Debug, Clone, serde::Deserialize)]
53#[non_exhaustive]
54pub struct JSCoverageRange {
55    /// Start byte offset (inclusive).
56    #[serde(rename = "startOffset")]
57    pub start_offset: usize,
58    /// End byte offset (exclusive).
59    #[serde(rename = "endOffset")]
60    pub end_offset: usize,
61    /// Number of times this range was executed.
62    pub count: i64,
63}
64
65/// Per-function coverage data within a [`JSCoverageEntry`].
66#[derive(Debug, Clone, serde::Deserialize)]
67#[non_exhaustive]
68pub struct JSFunctionCoverage {
69    /// The function name (empty string for anonymous functions).
70    #[serde(rename = "functionName")]
71    pub function_name: String,
72    /// Whether this is block-level coverage (true) or function-level (false).
73    #[serde(rename = "isBlockCoverage")]
74    pub is_block_coverage: bool,
75    /// Covered byte-offset ranges within this function.
76    pub ranges: Vec<JSCoverageRange>,
77}
78
79/// A JavaScript coverage entry returned by `Coverage::stop_js_coverage`.
80///
81/// See: <https://playwright.dev/docs/api/class-coverage#coverage-stop-js-coverage>
82#[derive(Debug, Clone, serde::Deserialize)]
83#[non_exhaustive]
84pub struct JSCoverageEntry {
85    /// The URL of the script.
86    pub url: String,
87    /// The V8 script ID.
88    #[serde(rename = "scriptId")]
89    pub script_id: String,
90    /// The script source text.
91    pub source: Option<String>,
92    /// Per-function coverage data.
93    pub functions: Vec<JSFunctionCoverage>,
94}
95
96/// A CSS coverage entry returned by `Coverage::stop_css_coverage`.
97///
98/// See: <https://playwright.dev/docs/api/class-coverage#coverage-stop-css-coverage>
99#[derive(Debug, Clone, serde::Deserialize)]
100#[non_exhaustive]
101pub struct CSSCoverageEntry {
102    /// The URL of the stylesheet.
103    pub url: String,
104    /// The stylesheet source text.
105    pub text: Option<String>,
106    /// Byte-offset ranges of used CSS rules.
107    pub ranges: Vec<CoverageRange>,
108}
109
110/// Provides JavaScript and CSS code coverage collection (Chromium only).
111///
112/// Access via [`Page::coverage`].
113///
114/// Coverage collection is only supported in Chromium. Calling these methods on
115/// Firefox or WebKit will return an error.
116///
117/// See: <https://playwright.dev/docs/api/class-coverage>
118#[derive(Clone)]
119pub struct Coverage {
120    page: Page,
121}
122
123impl Coverage {
124    pub(crate) fn new(page: Page) -> Self {
125        Self { page }
126    }
127
128    /// Starts collecting JavaScript coverage.
129    ///
130    /// Must be called before navigating to the page(s) you want to measure.
131    ///
132    /// # Errors
133    ///
134    /// Returns error if coverage is already started, if the browser is not
135    /// Chromium, or if the RPC call fails.
136    ///
137    /// See: <https://playwright.dev/docs/api/class-coverage#coverage-start-js-coverage>
138    pub async fn start_js_coverage(
139        &self,
140        options: impl Into<Option<StartJSCoverageOptions>>,
141    ) -> Result<()> {
142        let options = options.into();
143        self.page.coverage_start_js(options).await
144    }
145
146    /// Stops JavaScript coverage collection and returns the entries.
147    ///
148    /// # Errors
149    ///
150    /// Returns error if coverage was not started or if the RPC call fails.
151    ///
152    /// See: <https://playwright.dev/docs/api/class-coverage#coverage-stop-js-coverage>
153    pub async fn stop_js_coverage(&self) -> Result<Vec<JSCoverageEntry>> {
154        self.page.coverage_stop_js().await
155    }
156
157    /// Starts collecting CSS coverage.
158    ///
159    /// # Errors
160    ///
161    /// Returns error if coverage is already started, if the browser is not
162    /// Chromium, or if the RPC call fails.
163    ///
164    /// See: <https://playwright.dev/docs/api/class-coverage#coverage-start-css-coverage>
165    pub async fn start_css_coverage(
166        &self,
167        options: impl Into<Option<StartCSSCoverageOptions>>,
168    ) -> Result<()> {
169        let options = options.into();
170        self.page.coverage_start_css(options).await
171    }
172
173    /// Stops CSS coverage collection and returns the entries.
174    ///
175    /// # Errors
176    ///
177    /// Returns error if coverage was not started or if the RPC call fails.
178    ///
179    /// See: <https://playwright.dev/docs/api/class-coverage#coverage-stop-css-coverage>
180    pub async fn stop_css_coverage(&self) -> Result<Vec<CSSCoverageEntry>> {
181        self.page.coverage_stop_css().await
182    }
183}