@probolabs/playwright 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,227 +1,227 @@
1
- # Probolib: drive your playwright scripts with AI superpowers
2
-
3
- Probolib is a powerful AI-driven automation library that enhances Playwright testing and automation by making your scripts more robust and maintainable. Instead of relying on brittle CSS selectors or complex XPath expressions, Probolib uses natural language to interact with web elements.
4
-
5
- ## Why Probolib?
6
-
7
- - **Natural Language Automation**: Write human-readable instructions instead of complex selectors
8
- - **More Resilient Tests**: AI-powered element detection that adapts to UI changes
9
- - **Simpler Maintenance**: Reduce the need to update selectors when the UI changes
10
- - **Faster Development**: Write automation scripts in plain English
11
-
12
- ## Example
13
-
14
- Instead of writing:
15
-
16
- ```
17
- page.click('some > super > complex > css > and non robust selector')
18
- ```
19
-
20
- You can simply write:
21
-
22
- ```
23
- probo.runStep(page, 'click on the save button')
24
- ```
25
-
26
- ## Quickstart
27
-
28
- ```
29
- npm install @probolabs/playwright
30
- ```
31
-
32
- ## Accessing our backend
33
-
34
- the heavy lifting of the AI reasoning is done at the moment on our backend server. in order to access it you would need to tell the library how to access it.
35
-
36
- ## easyiest - set ENV var
37
-
38
- probolib expects the existance of 2 env vars:
39
-
40
- ```
41
- export PROBO_API_ENDPOINT=api.probolabs.ai
42
- export PROBO_API_KEY=<api key we will give you>
43
-
44
- ```
45
-
46
- Or use dotenv
47
-
48
- ```
49
- // npm install dotenv
50
- // in your script add this line
51
- import 'dotenv/config' // ES6
52
-
53
- // .env file located in the root of your project (the same level as your package.json)
54
- PROBO_API_ENDPOINT=https://api.probolabs.ai
55
- PROBO_API_KEY=<api key we will give you>
56
-
57
- ```
58
-
59
- ## A complete example for Playwright integration. step by step
60
-
61
- **step 1:** init a playwright project
62
-
63
- ```
64
- # from your work directory
65
- mkdir probo-example
66
- cd probo-example
67
- npm init playwright@latest
68
- # follow the instructions and wait till the installation is finished
69
- # verify that playwright is installed properly
70
- npx playwright test --project chromium
71
- ```
72
-
73
- **step 2**: integrate probolabs
74
-
75
- ```
76
- npm install @probolabs/playwright dotenv
77
- ```
78
-
79
- **step 3:** configure the env with our endpoint and api key
80
-
81
- ```
82
- touch .env
83
- ```
84
-
85
- edit the .env file
86
-
87
- ```
88
- #.env
89
- PROBO_API_ENDPOINT=https://api.probolabs.ai
90
- PROBO_API_KEY=<api key we will give you>
91
-
92
- ```
93
-
94
- **step 4:** create a file under the tests folder named `probo-example-todo-mvc.spec.mjs`
95
-
96
- ```
97
- // tests/probo-example-todo-mvc.spec.mjs
98
- import 'dotenv/config';
99
- import { test} from '@playwright/test';
100
- import { Probo } from '@probolabs/playwright';
101
-
102
- //
103
- // Important: Before running this script set PROBO_API_KEY and PROBO_API_ENDPOINT
104
- //
105
-
106
- test.describe('Todo MVC', () => {
107
- test('basic example', async ({ page }) => {
108
- try {
109
- // Initialize Probo
110
- const probo = new Probo({
111
- scenarioName: 'probo-example-todo-mvc' // important for caching the AI reasoning
112
- });
113
-
114
- //Goto page
115
- await page.goto('https://demo.playwright.dev/todomvc');
116
-
117
- // Run test steps
118
- console.log('Running test steps...');
119
- await probo.runStep(page, 'enter a new todo item: "Buy groceries"');
120
- await probo.runStep(page, 'press the Enter key');
121
-
122
- console.log('✨ Test completed successfully!');
123
- } catch (error) {
124
- console.error('❌ Test failed:', error);
125
- throw error; // Re-throw to mark the test as failed
126
- }
127
- });
128
- });
129
-
130
- ```
131
-
132
- **run the example**
133
-
134
- ```
135
- npx playwright test tests/probo-example-todo-mvc.spec.mjs --headed --project chromium
136
- ```
137
-
138
- ## Using Probo Fixtures (Connect to Existing Browser)
139
-
140
- Probo fixtures allow you to connect to an existing Chrome instance (like your recorder app) instead of launching a new browser. This is useful when you want to run tests against a browser that's already running with specific extensions or configurations.
141
-
142
- ### Quick Setup
143
-
144
- **Step 1:** Install the package
145
-
146
- ```bash
147
- npm install @probolabs/playwright
148
- ```
149
-
150
- **Step 2:** Create a `playwright.config.ts` file
151
-
152
- ```typescript
153
- // playwright.config.ts
154
- import { defineConfig } from "@playwright/test";
155
-
156
- export default defineConfig({
157
- testDir: "./tests",
158
- use: {
159
- // Don't launch a new browser - Probo fixtures will connect to existing one
160
- launchOptions: {},
161
- },
162
- workers: 1, // Use 1 worker to avoid conflicts with existing browser
163
- });
164
- ```
165
-
166
- **Step 3:** Use Probo fixtures in your test files
167
-
168
- ```typescript
169
- // tests/example.spec.ts
170
- import { test, expect } from "@probolabs/playwright/fixtures";
171
-
172
- test.describe("My Tests", () => {
173
- test("should work with existing browser", async ({ page }) => {
174
- // This page comes from your existing Chrome instance
175
- await page.goto("https://example.com");
176
- await page.click("button");
177
-
178
- // Your test code here...
179
- });
180
- });
181
- ```
182
-
183
- **Step 4:** Make sure your recorder app is running, then run tests
184
-
185
- ```bash
186
- npx playwright test
187
- ```
188
-
189
- ### Advanced Configuration
190
-
191
- You can customize the fixtures with different options:
192
-
193
- ```typescript
194
- // tests/example.spec.ts
195
- import { createProboFixtures, expect } from "@probolabs/playwright/fixtures";
196
-
197
- // Create custom fixtures with specific configuration
198
- const test = createProboFixtures({
199
- debugPort: 9333, // Default port where your recorder app runs
200
- showBrowserConsole: true, // Show browser console logs
201
- });
202
-
203
- test.describe("My Tests", () => {
204
- test("custom configuration", async ({ page }) => {
205
- // Your test code here...
206
- });
207
- });
208
- ```
209
-
210
- ### Requirements
211
-
212
- - Your recorder app must be running with Chrome accessible via CDP
213
- - Chrome must be launched with `--remote-debugging-port=9333` (or your custom port)
214
- - The browser must have at least one page open (not just extension pages)
215
-
216
- ### Troubleshooting
217
-
218
- **Error: "No browser context found"**
219
-
220
- - Make sure your recorder app is running
221
- - Check that Chrome is accessible at `http://localhost:9333`
222
- - Verify the debug port matches your configuration
223
-
224
- **Error: "No main page found"**
225
-
226
- - Make sure your recorder app has opened a page
227
- - The page should not be a chrome-extension:// URL
1
+ # Probolib: drive your playwright scripts with AI superpowers
2
+
3
+ Probolib is a powerful AI-driven automation library that enhances Playwright testing and automation by making your scripts more robust and maintainable. Instead of relying on brittle CSS selectors or complex XPath expressions, Probolib uses natural language to interact with web elements.
4
+
5
+ ## Why Probolib?
6
+
7
+ - **Natural Language Automation**: Write human-readable instructions instead of complex selectors
8
+ - **More Resilient Tests**: AI-powered element detection that adapts to UI changes
9
+ - **Simpler Maintenance**: Reduce the need to update selectors when the UI changes
10
+ - **Faster Development**: Write automation scripts in plain English
11
+
12
+ ## Example
13
+
14
+ Instead of writing:
15
+
16
+ ```
17
+ page.click('some > super > complex > css > and non robust selector')
18
+ ```
19
+
20
+ You can simply write:
21
+
22
+ ```
23
+ probo.runStep(page, 'click on the save button')
24
+ ```
25
+
26
+ ## Quickstart
27
+
28
+ ```
29
+ npm install @probolabs/playwright
30
+ ```
31
+
32
+ ## Accessing our backend
33
+
34
+ the heavy lifting of the AI reasoning is done at the moment on our backend server. in order to access it you would need to tell the library how to access it.
35
+
36
+ ## easyiest - set ENV var
37
+
38
+ probolib expects the existance of 2 env vars:
39
+
40
+ ```
41
+ export PROBO_API_ENDPOINT=api.probolabs.ai
42
+ export PROBO_API_KEY=<api key we will give you>
43
+
44
+ ```
45
+
46
+ Or use dotenv
47
+
48
+ ```
49
+ // npm install dotenv
50
+ // in your script add this line
51
+ import 'dotenv/config' // ES6
52
+
53
+ // .env file located in the root of your project (the same level as your package.json)
54
+ PROBO_API_ENDPOINT=https://api.probolabs.ai
55
+ PROBO_API_KEY=<api key we will give you>
56
+
57
+ ```
58
+
59
+ ## A complete example for Playwright integration. step by step
60
+
61
+ **step 1:** init a playwright project
62
+
63
+ ```
64
+ # from your work directory
65
+ mkdir probo-example
66
+ cd probo-example
67
+ npm init playwright@latest
68
+ # follow the instructions and wait till the installation is finished
69
+ # verify that playwright is installed properly
70
+ npx playwright test --project chromium
71
+ ```
72
+
73
+ **step 2**: integrate probolabs
74
+
75
+ ```
76
+ npm install @probolabs/playwright dotenv
77
+ ```
78
+
79
+ **step 3:** configure the env with our endpoint and api key
80
+
81
+ ```
82
+ touch .env
83
+ ```
84
+
85
+ edit the .env file
86
+
87
+ ```
88
+ #.env
89
+ PROBO_API_ENDPOINT=https://api.probolabs.ai
90
+ PROBO_API_KEY=<api key we will give you>
91
+
92
+ ```
93
+
94
+ **step 4:** create a file under the tests folder named `probo-example-todo-mvc.spec.mjs`
95
+
96
+ ```
97
+ // tests/probo-example-todo-mvc.spec.mjs
98
+ import 'dotenv/config';
99
+ import { test} from '@playwright/test';
100
+ import { Probo } from '@probolabs/playwright';
101
+
102
+ //
103
+ // Important: Before running this script set PROBO_API_KEY and PROBO_API_ENDPOINT
104
+ //
105
+
106
+ test.describe('Todo MVC', () => {
107
+ test('basic example', async ({ page }) => {
108
+ try {
109
+ // Initialize Probo
110
+ const probo = new Probo({
111
+ scenarioName: 'probo-example-todo-mvc' // important for caching the AI reasoning
112
+ });
113
+
114
+ //Goto page
115
+ await page.goto('https://demo.playwright.dev/todomvc');
116
+
117
+ // Run test steps
118
+ console.log('Running test steps...');
119
+ await probo.runStep(page, 'enter a new todo item: "Buy groceries"');
120
+ await probo.runStep(page, 'press the Enter key');
121
+
122
+ console.log('✨ Test completed successfully!');
123
+ } catch (error) {
124
+ console.error('❌ Test failed:', error);
125
+ throw error; // Re-throw to mark the test as failed
126
+ }
127
+ });
128
+ });
129
+
130
+ ```
131
+
132
+ **run the example**
133
+
134
+ ```
135
+ npx playwright test tests/probo-example-todo-mvc.spec.mjs --headed --project chromium
136
+ ```
137
+
138
+ ## Using Probo Fixtures (Connect to Existing Browser)
139
+
140
+ Probo fixtures allow you to connect to an existing Chrome instance (like your recorder app) instead of launching a new browser. This is useful when you want to run tests against a browser that's already running with specific extensions or configurations.
141
+
142
+ ### Quick Setup
143
+
144
+ **Step 1:** Install the package
145
+
146
+ ```bash
147
+ npm install @probolabs/playwright
148
+ ```
149
+
150
+ **Step 2:** Create a `playwright.config.ts` file
151
+
152
+ ```typescript
153
+ // playwright.config.ts
154
+ import { defineConfig } from "@playwright/test";
155
+
156
+ export default defineConfig({
157
+ testDir: "./tests",
158
+ use: {
159
+ // Don't launch a new browser - Probo fixtures will connect to existing one
160
+ launchOptions: {},
161
+ },
162
+ workers: 1, // Use 1 worker to avoid conflicts with existing browser
163
+ });
164
+ ```
165
+
166
+ **Step 3:** Use Probo fixtures in your test files
167
+
168
+ ```typescript
169
+ // tests/example.spec.ts
170
+ import { test, expect } from "@probolabs/playwright/fixtures";
171
+
172
+ test.describe("My Tests", () => {
173
+ test("should work with existing browser", async ({ page }) => {
174
+ // This page comes from your existing Chrome instance
175
+ await page.goto("https://example.com");
176
+ await page.click("button");
177
+
178
+ // Your test code here...
179
+ });
180
+ });
181
+ ```
182
+
183
+ **Step 4:** Make sure your recorder app is running, then run tests
184
+
185
+ ```bash
186
+ npx playwright test
187
+ ```
188
+
189
+ ### Advanced Configuration
190
+
191
+ You can customize the fixtures with different options:
192
+
193
+ ```typescript
194
+ // tests/example.spec.ts
195
+ import { createProboFixtures, expect } from "@probolabs/playwright/fixtures";
196
+
197
+ // Create custom fixtures with specific configuration
198
+ const test = createProboFixtures({
199
+ debugPort: 9333, // Default port where your recorder app runs
200
+ showBrowserConsole: true, // Show browser console logs
201
+ });
202
+
203
+ test.describe("My Tests", () => {
204
+ test("custom configuration", async ({ page }) => {
205
+ // Your test code here...
206
+ });
207
+ });
208
+ ```
209
+
210
+ ### Requirements
211
+
212
+ - Your recorder app must be running with Chrome accessible via CDP
213
+ - Chrome must be launched with `--remote-debugging-port=9333` (or your custom port)
214
+ - The browser must have at least one page open (not just extension pages)
215
+
216
+ ### Troubleshooting
217
+
218
+ **Error: "No browser context found"**
219
+
220
+ - Make sure your recorder app is running
221
+ - Check that Chrome is accessible at `http://localhost:9333`
222
+ - Verify the debug port matches your configuration
223
+
224
+ **Error: "No main page found"**
225
+
226
+ - Make sure your recorder app has opened a page
227
+ - The page should not be a chrome-extension:// URL
@@ -1 +1 @@
1
- {"version":3,"file":"fixtures.js","sources":["../src/fixtures.ts"],"sourcesContent":["import { test as base, chromium } from '@playwright/test';\r\nimport { readFileSync, mkdtempSync } from 'fs';\r\nimport { join, dirname } from 'path';\r\nimport { tmpdir } from 'os';\r\nimport AdmZip from 'adm-zip';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\n\r\n/**\r\n * Configuration options for Probo fixtures\r\n */\r\nexport interface ProboFixturesConfig {\r\n /** Whether to show browser console logs */\r\n showBrowserConsole?: boolean;\r\n /** Custom path to extensions directory */\r\n extensionsPath?: string;\r\n}\r\n\r\n/**\r\n * Extracts a CRX file to a temporary directory\r\n * Uses adm-zip with manual ZIP content detection\r\n */\r\nfunction extractCrxFile(crxPath: string): string {\r\n const crxBuffer = readFileSync(crxPath);\r\n \r\n // Find ZIP content by looking for ZIP magic number (PK)\r\n let zipStart = -1;\r\n for (let i = 0; i < crxBuffer.length - 4; i++) {\r\n if (crxBuffer[i] === 0x50 && crxBuffer[i + 1] === 0x4B) { // \"PK\"\r\n zipStart = i;\r\n break;\r\n }\r\n }\r\n \r\n if (zipStart === -1) {\r\n throw new Error('Could not find ZIP content in CRX file');\r\n }\r\n \r\n const zipBuffer = crxBuffer.subarray(zipStart);\r\n \r\n // Create temporary directory\r\n const tempDir = mkdtempSync(join(tmpdir(), 'probo-extension-'));\r\n \r\n // Extract ZIP content\r\n const zip = new AdmZip(zipBuffer);\r\n zip.extractAllTo(tempDir, true);\r\n \r\n return tempDir;\r\n}\r\n\r\n/**\r\n * Creates Probo fixtures that launch Chromium with extensions\r\n * \r\n * @param config Configuration options for the fixtures\r\n * @returns Extended test function with Probo fixtures\r\n */\r\nexport function createProboFixtures(config: ProboFixturesConfig = {}) {\r\n const { showBrowserConsole = false, extensionsPath } = config;\r\n \r\n // Default extensions path\r\n const defaultExtensionsPath = join(__dirname, '../loaded_extensions');\r\n const extensionsDir = extensionsPath || defaultExtensionsPath;\r\n\r\n return base.extend({\r\n context: async ({headless}, use) => {\r\n // Extract extensions\r\n const extensionDirs: string[] = [];\r\n \r\n try {\r\n const crxFile = join(extensionsDir, 'microsoft-single-sign-on.crx');\r\n const extractedDir = extractCrxFile(crxFile);\r\n extensionDirs.push(extractedDir);\r\n } catch (error) {\r\n console.warn('Could not load Microsoft SSO extension:', error);\r\n }\r\n \r\n // Launch Chromium with extensions\r\n const userDataDir = mkdtempSync(join(tmpdir(), 'probo-user-data-'));\r\n \r\n const context = await chromium.launchPersistentContext(userDataDir, {\r\n headless, // Extensions work better in non-headless mode\r\n args: [\r\n ...extensionDirs.map(dir => `--load-extension=${dir}`),\r\n '--disable-extensions-except=' + extensionDirs.join(','),\r\n '--disable-web-security', // Allow extensions to work properly\r\n '--disable-features=VizDisplayCompositor'\r\n ]\r\n });\r\n \r\n await use(context);\r\n \r\n // Cleanup\r\n await context.close();\r\n },\r\n \r\n page: async ({ context }, use) => {\r\n const page = await context.newPage();\r\n \r\n // Set up console logging if requested\r\n if (showBrowserConsole) {\r\n page.on('console', msg => console.log('Browser console:', msg.text()));\r\n }\r\n \r\n await use(page);\r\n await page.close();\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Default Probo fixtures with standard configuration\r\n * Launches Chromium with Microsoft SSO extension\r\n */\r\nexport const test = createProboFixtures();\r\n\r\n/**\r\n * Re-export expect from Playwright for convenience\r\n */\r\nexport { expect } from '@playwright/test';\r\n"],"names":["base"],"mappings":"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"}
1
+ {"version":3,"file":"fixtures.js","sources":["../src/fixtures.ts"],"sourcesContent":["import { test as base, chromium } from '@playwright/test';\nimport { readFileSync, mkdtempSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { tmpdir } from 'os';\nimport AdmZip from 'adm-zip';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Configuration options for Probo fixtures\n */\nexport interface ProboFixturesConfig {\n /** Whether to show browser console logs */\n showBrowserConsole?: boolean;\n /** Custom path to extensions directory */\n extensionsPath?: string;\n}\n\n/**\n * Extracts a CRX file to a temporary directory\n * Uses adm-zip with manual ZIP content detection\n */\nfunction extractCrxFile(crxPath: string): string {\n const crxBuffer = readFileSync(crxPath);\n \n // Find ZIP content by looking for ZIP magic number (PK)\n let zipStart = -1;\n for (let i = 0; i < crxBuffer.length - 4; i++) {\n if (crxBuffer[i] === 0x50 && crxBuffer[i + 1] === 0x4B) { // \"PK\"\n zipStart = i;\n break;\n }\n }\n \n if (zipStart === -1) {\n throw new Error('Could not find ZIP content in CRX file');\n }\n \n const zipBuffer = crxBuffer.subarray(zipStart);\n \n // Create temporary directory\n const tempDir = mkdtempSync(join(tmpdir(), 'probo-extension-'));\n \n // Extract ZIP content\n const zip = new AdmZip(zipBuffer);\n zip.extractAllTo(tempDir, true);\n \n return tempDir;\n}\n\n/**\n * Creates Probo fixtures that launch Chromium with extensions\n * \n * @param config Configuration options for the fixtures\n * @returns Extended test function with Probo fixtures\n */\nexport function createProboFixtures(config: ProboFixturesConfig = {}) {\n const { showBrowserConsole = false, extensionsPath } = config;\n \n // Default extensions path\n const defaultExtensionsPath = join(__dirname, '../loaded_extensions');\n const extensionsDir = extensionsPath || defaultExtensionsPath;\n\n return base.extend({\n context: async ({headless}, use) => {\n // Extract extensions\n const extensionDirs: string[] = [];\n \n try {\n const crxFile = join(extensionsDir, 'microsoft-single-sign-on.crx');\n const extractedDir = extractCrxFile(crxFile);\n extensionDirs.push(extractedDir);\n } catch (error) {\n console.warn('Could not load Microsoft SSO extension:', error);\n }\n \n // Launch Chromium with extensions\n const userDataDir = mkdtempSync(join(tmpdir(), 'probo-user-data-'));\n \n const context = await chromium.launchPersistentContext(userDataDir, {\n headless, // Extensions work better in non-headless mode\n args: [\n ...extensionDirs.map(dir => `--load-extension=${dir}`),\n '--disable-extensions-except=' + extensionDirs.join(','),\n '--disable-web-security', // Allow extensions to work properly\n '--disable-features=VizDisplayCompositor'\n ]\n });\n \n await use(context);\n \n // Cleanup\n await context.close();\n },\n \n page: async ({ context }, use) => {\n const page = await context.newPage();\n \n // Set up console logging if requested\n if (showBrowserConsole) {\n page.on('console', msg => console.log('Browser console:', msg.text()));\n }\n \n await use(page);\n await page.close();\n },\n });\n}\n\n/**\n * Default Probo fixtures with standard configuration\n * Launches Chromium with Microsoft SSO extension\n */\nexport const test = createProboFixtures();\n\n/**\n * Re-export expect from Playwright for convenience\n */\nexport { expect } from '@playwright/test';\n"],"names":["base"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -100,7 +100,6 @@ interface RunStepParams extends Partial<PlaywrightTimeoutConfig> {
100
100
  declare class ProboPlaywright {
101
101
  private readonly config;
102
102
  private page;
103
- private lastNavigationTime;
104
103
  constructor(config?: PlaywrightTimeoutConfig, page?: Page$1 | null);
105
104
  /**
106
105
  * Sets the Playwright page instance for this ProboPlaywright instance.
@@ -109,7 +108,6 @@ declare class ProboPlaywright {
109
108
  * @param page - The Playwright Page instance to use, or null to unset.
110
109
  */
111
110
  setPage(page: Page$1 | null): void;
112
- private onFrameNav;
113
111
  /**
114
112
  * Executes a single step in the test scenario with the specified action on the target element.
115
113
  * Handles iframe navigation, element highlighting, and various Playwright actions like click, fill, validate, etc.
@@ -159,14 +157,21 @@ declare class ProboPlaywright {
159
157
  * @returns Normalized text content with consistent whitespace handling
160
158
  */
161
159
  private getTextValue;
160
+ private setSliderValue;
162
161
  }
163
162
 
164
163
  interface NavTrackerOptions {
165
- stabilizationTimeout?: number;
164
+ waitForStabilityQuietTimeout?: number;
165
+ waitForStabilityInitialDelay?: number;
166
+ waitForStabilityGlobalTimeout?: number;
167
+ pollMs?: number;
168
+ maxInflight?: number;
169
+ inflightGraceMs?: number;
170
+ waitForStabilityVerbose?: boolean;
166
171
  }
167
172
  /**
168
- * Global navigation tracker that monitors page navigation events
169
- * and provides methods to check if navigation has stabilized
173
+ * Global navigation tracker that monitors page navigation events and network activity
174
+ * using CDP (Chrome DevTools Protocol) for comprehensive network monitoring
170
175
  *
171
176
  * This is a singleton class - only one instance can exist at a time
172
177
  */
@@ -175,30 +180,51 @@ declare class NavTracker {
175
180
  private page;
176
181
  private navigationCount;
177
182
  private lastNavTime;
178
- private stabilizationTimeout;
183
+ private waitForStabilityQuietTimeout;
184
+ private waitForStabilityInitialDelay;
185
+ private waitForStabilityGlobalTimeout;
186
+ private pollMs;
187
+ private maxInflight;
188
+ private inflightGraceMs;
189
+ private waitForStabilityVerbose;
179
190
  private isListening;
180
- private onFrameNavHandler;
181
191
  private instanceId;
192
+ private client;
193
+ private inflight;
194
+ private lastHardNavAt;
195
+ private lastSoftNavAt;
196
+ private lastNetworkActivityAt;
197
+ private totalRequestsTracked;
198
+ private readonly RELEVANT_RESOURCE_TYPES;
199
+ private readonly RELEVANT_CONTENT_TYPES;
200
+ private readonly IGNORED_URL_PATTERNS;
182
201
  /**
183
202
  * Private constructor - use getInstance() to get the singleton instance
184
203
  */
185
204
  private constructor();
186
205
  /**
187
- * Start listening for navigation events (private method)
206
+ * Start listening for navigation and network events using CDP (private method)
188
207
  */
189
208
  private start;
190
209
  /**
191
- * Stop listening for navigation events (private method)
210
+ * Stop listening for navigation and network events (private method)
192
211
  */
193
212
  private stop;
194
213
  /**
195
- * Check if navigation has stabilized (no navigation for stabilizationTimeout ms) (private method)
214
+ * Handle network request events
215
+ */
216
+ private onNetworkRequest;
217
+ /**
218
+ * Handle network response events
219
+ */
220
+ private onNetworkResponse;
221
+ /**
222
+ * Check if navigation and network activity has stabilized
196
223
  */
197
224
  private hasNavigationStabilized;
198
225
  /**
199
- * Wait for navigation to stabilize
200
- * Waits a short time to catch any missed navigation events, then ensures
201
- * the latest navigation happened at least stabilizationTimeout ms ago
226
+ * Wait for navigation and network activity to stabilize
227
+ * Uses CDP-based monitoring for comprehensive network activity tracking
202
228
  */
203
229
  waitForNavigationToStabilize(): Promise<void>;
204
230
  /**
@@ -207,7 +233,11 @@ declare class NavTracker {
207
233
  * @param options Optional configuration
208
234
  * @returns The singleton NavTracker instance
209
235
  */
210
- static getInstance(page?: Page, options?: NavTrackerOptions): NavTracker;
236
+ static getInstance(page?: Page, options?: NavTrackerOptions): Promise<NavTracker>;
237
+ /**
238
+ * Reset the singleton instance (useful for testing or page changes)
239
+ */
240
+ static resetInstance(): void;
211
241
  }
212
242
 
213
243
  /**
@@ -222,7 +252,7 @@ interface ProboConfig {
222
252
  logToFile?: boolean;
223
253
  debugLevel?: ProboLogLevel;
224
254
  aiModel?: AIModel;
225
- timeoutConfig?: PlaywrightTimeoutConfig;
255
+ timeoutConfig?: Partial<PlaywrightTimeoutConfig>;
226
256
  }
227
257
  interface RunStepOptions {
228
258
  useCache: boolean;