@probolabs/playwright 1.0.3 → 1.0.4
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/dist/fixtures.d.ts +4 -5
- package/dist/fixtures.js +67 -27
- package/dist/fixtures.js.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/types/actions.d.ts.map +1 -1
- package/dist/types/fixtures.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/replay-utils.d.ts.map +1 -1
- package/loaded_extensions/README.md +23 -0
- package/loaded_extensions/microsoft-single-sign-on.crx +0 -0
- package/package.json +5 -27
package/dist/fixtures.d.ts
CHANGED
|
@@ -5,14 +5,13 @@ export { expect } from '@playwright/test';
|
|
|
5
5
|
* Configuration options for Probo fixtures
|
|
6
6
|
*/
|
|
7
7
|
interface ProboFixturesConfig {
|
|
8
|
-
/** The debug port where your recorder app's Chrome instance is running */
|
|
9
|
-
debugPort?: number;
|
|
10
8
|
/** Whether to show browser console logs */
|
|
11
9
|
showBrowserConsole?: boolean;
|
|
10
|
+
/** Custom path to extensions directory */
|
|
11
|
+
extensionsPath?: string;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* Creates Probo fixtures that
|
|
15
|
-
* instead of launching a new browser.
|
|
14
|
+
* Creates Probo fixtures that launch Chromium with extensions
|
|
16
15
|
*
|
|
17
16
|
* @param config Configuration options for the fixtures
|
|
18
17
|
* @returns Extended test function with Probo fixtures
|
|
@@ -20,7 +19,7 @@ interface ProboFixturesConfig {
|
|
|
20
19
|
declare function createProboFixtures(config?: ProboFixturesConfig): _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions>;
|
|
21
20
|
/**
|
|
22
21
|
* Default Probo fixtures with standard configuration
|
|
23
|
-
*
|
|
22
|
+
* Launches Chromium with Microsoft SSO extension
|
|
24
23
|
*/
|
|
25
24
|
declare const test: _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions>;
|
|
26
25
|
|
package/dist/fixtures.js
CHANGED
|
@@ -1,50 +1,90 @@
|
|
|
1
1
|
import { test as test$1, chromium } from '@playwright/test';
|
|
2
2
|
export { expect } from '@playwright/test';
|
|
3
|
+
import { mkdtempSync, readFileSync } from 'fs';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import AdmZip from 'adm-zip';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
3
8
|
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
4
11
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
12
|
+
* Extracts a CRX file to a temporary directory
|
|
13
|
+
* Uses adm-zip with manual ZIP content detection
|
|
14
|
+
*/
|
|
15
|
+
function extractCrxFile(crxPath) {
|
|
16
|
+
const crxBuffer = readFileSync(crxPath);
|
|
17
|
+
// Find ZIP content by looking for ZIP magic number (PK)
|
|
18
|
+
let zipStart = -1;
|
|
19
|
+
for (let i = 0; i < crxBuffer.length - 4; i++) {
|
|
20
|
+
if (crxBuffer[i] === 0x50 && crxBuffer[i + 1] === 0x4B) { // "PK"
|
|
21
|
+
zipStart = i;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (zipStart === -1) {
|
|
26
|
+
throw new Error('Could not find ZIP content in CRX file');
|
|
27
|
+
}
|
|
28
|
+
const zipBuffer = crxBuffer.subarray(zipStart);
|
|
29
|
+
// Create temporary directory
|
|
30
|
+
const tempDir = mkdtempSync(join(tmpdir(), 'probo-extension-'));
|
|
31
|
+
// Extract ZIP content
|
|
32
|
+
const zip = new AdmZip(zipBuffer);
|
|
33
|
+
zip.extractAllTo(tempDir, true);
|
|
34
|
+
return tempDir;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates Probo fixtures that launch Chromium with extensions
|
|
7
38
|
*
|
|
8
39
|
* @param config Configuration options for the fixtures
|
|
9
40
|
* @returns Extended test function with Probo fixtures
|
|
10
41
|
*/
|
|
11
42
|
function createProboFixtures(config = {}) {
|
|
12
|
-
const {
|
|
43
|
+
const { showBrowserConsole = false, extensionsPath } = config;
|
|
44
|
+
// Default extensions path
|
|
45
|
+
const defaultExtensionsPath = join(__dirname, '../loaded_extensions');
|
|
46
|
+
const extensionsDir = extensionsPath || defaultExtensionsPath;
|
|
13
47
|
return test$1.extend({
|
|
14
|
-
|
|
15
|
-
//
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
48
|
+
context: async ({}, use) => {
|
|
49
|
+
// Extract extensions
|
|
50
|
+
const extensionDirs = [];
|
|
51
|
+
try {
|
|
52
|
+
const crxFile = join(extensionsDir, 'microsoft-single-sign-on.crx');
|
|
53
|
+
const extractedDir = extractCrxFile(crxFile);
|
|
54
|
+
extensionDirs.push(extractedDir);
|
|
21
55
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
// Don't close the browser - it's managed by your recorder app
|
|
25
|
-
},
|
|
26
|
-
// Override the page fixture to use existing page
|
|
27
|
-
page: async ({ browser }, use) => {
|
|
28
|
-
const context = browser.contexts()[0];
|
|
29
|
-
const allPages = context.pages();
|
|
30
|
-
// Find the main page (not chrome-extension pages)
|
|
31
|
-
const mainPage = allPages.find(page => !page.url().startsWith('chrome-extension://'));
|
|
32
|
-
if (!mainPage) {
|
|
33
|
-
throw new Error('No main page found in existing browser context. Make sure your recorder app has opened a page.');
|
|
56
|
+
catch (error) {
|
|
57
|
+
console.warn('Could not load Microsoft SSO extension:', error);
|
|
34
58
|
}
|
|
59
|
+
// Launch Chromium with extensions
|
|
60
|
+
const userDataDir = mkdtempSync(join(tmpdir(), 'probo-user-data-'));
|
|
61
|
+
const context = await chromium.launchPersistentContext(userDataDir, {
|
|
62
|
+
headless: false, // Extensions work better in non-headless mode
|
|
63
|
+
args: [
|
|
64
|
+
...extensionDirs.map(dir => `--load-extension=${dir}`),
|
|
65
|
+
'--disable-extensions-except=' + extensionDirs.join(','),
|
|
66
|
+
'--disable-web-security', // Allow extensions to work properly
|
|
67
|
+
'--disable-features=VizDisplayCompositor'
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
await use(context);
|
|
71
|
+
// Cleanup
|
|
72
|
+
await context.close();
|
|
73
|
+
},
|
|
74
|
+
page: async ({ context }, use) => {
|
|
75
|
+
const page = await context.newPage();
|
|
35
76
|
// Set up console logging if requested
|
|
36
77
|
if (showBrowserConsole) {
|
|
37
|
-
|
|
78
|
+
page.on('console', msg => console.log('Browser console:', msg.text()));
|
|
38
79
|
}
|
|
39
|
-
|
|
40
|
-
await
|
|
41
|
-
// Don't close the page - it's managed by your recorder app
|
|
80
|
+
await use(page);
|
|
81
|
+
await page.close();
|
|
42
82
|
},
|
|
43
83
|
});
|
|
44
84
|
}
|
|
45
85
|
/**
|
|
46
86
|
* Default Probo fixtures with standard configuration
|
|
47
|
-
*
|
|
87
|
+
* Launches Chromium with Microsoft SSO extension
|
|
48
88
|
*/
|
|
49
89
|
const test = createProboFixtures();
|
|
50
90
|
|
package/dist/fixtures.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixtures.js","sources":["../src/fixtures.ts"],"sourcesContent":["import { test as base, chromium } from '@playwright/test';\n\n/**\n * Configuration options for Probo fixtures\n */\nexport interface ProboFixturesConfig {\n /**
|
|
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 { execSync } from 'child_process';\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 ({}, 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: false, // 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.js
CHANGED
|
@@ -34,9 +34,14 @@ var PlaywrightAction;
|
|
|
34
34
|
PlaywrightAction["TOGGLE_SWITCH"] = "TOGGLE_SWITCH";
|
|
35
35
|
PlaywrightAction["TYPE_KEYS"] = "TYPE_KEYS";
|
|
36
36
|
PlaywrightAction["HOVER"] = "HOVER";
|
|
37
|
+
//TODO: remove these after migration
|
|
37
38
|
PlaywrightAction["VALIDATE_EXACT_VALUE"] = "VALIDATE_EXACT_VALUE";
|
|
38
39
|
PlaywrightAction["VALIDATE_CONTAINS_VALUE"] = "VALIDATE_CONTAINS_VALUE";
|
|
39
40
|
PlaywrightAction["VALIDATE_URL"] = "VALIDATE_URL";
|
|
41
|
+
///////////////////////////////////////////////////
|
|
42
|
+
PlaywrightAction["ASSERT_EXACT_VALUE"] = "ASSERT_EXACT_VALUE";
|
|
43
|
+
PlaywrightAction["ASSERT_CONTAINS_VALUE"] = "ASSERT_CONTAINS_VALUE";
|
|
44
|
+
PlaywrightAction["ASSERT_URL"] = "ASSERT_URL";
|
|
40
45
|
PlaywrightAction["SCROLL_TO_ELEMENT"] = "SCROLL_TO_ELEMENT";
|
|
41
46
|
PlaywrightAction["EXTRACT_VALUE"] = "EXTRACT_VALUE";
|
|
42
47
|
PlaywrightAction["ASK_AI"] = "ASK_AI";
|
|
@@ -1360,12 +1365,14 @@ class ProboPlaywright {
|
|
|
1360
1365
|
case PlaywrightAction.SELECT_DROPDOWN:
|
|
1361
1366
|
await locator.selectOption(argument);
|
|
1362
1367
|
break;
|
|
1368
|
+
case PlaywrightAction.ASSERT_CONTAINS_VALUE:
|
|
1363
1369
|
case PlaywrightAction.VALIDATE_CONTAINS_VALUE:
|
|
1364
1370
|
const containerText = await this.getTextValue(locator);
|
|
1365
1371
|
if (!matchRegex(containerText, argument)) {
|
|
1366
1372
|
throw new Error(`Validation failed. Expected text "${containerText}" to match "${argument}".`);
|
|
1367
1373
|
}
|
|
1368
1374
|
break;
|
|
1375
|
+
case PlaywrightAction.ASSERT_EXACT_VALUE:
|
|
1369
1376
|
case PlaywrightAction.VALIDATE_EXACT_VALUE:
|
|
1370
1377
|
const actualText = await this.getTextValue(locator);
|
|
1371
1378
|
if (actualText !== argument) {
|
|
@@ -1414,7 +1421,7 @@ class ProboPlaywright {
|
|
|
1414
1421
|
if (isVisible) {
|
|
1415
1422
|
// Get the current text content only if element is visible
|
|
1416
1423
|
currentText = await this.getTextValue(locator);
|
|
1417
|
-
// Check if the text matches (using the same logic as
|
|
1424
|
+
// Check if the text matches (using the same logic as ASSERT_CONTAINS_VALUE)
|
|
1418
1425
|
if (matchRegex(currentText, expectedText)) {
|
|
1419
1426
|
textMatches = true;
|
|
1420
1427
|
console.log(`✅ Wait for text completed successfully. Found: "${currentText}"`);
|
|
@@ -2011,8 +2018,10 @@ class Probo {
|
|
|
2011
2018
|
highlightTimeout: 0
|
|
2012
2019
|
});
|
|
2013
2020
|
let stepStatus;
|
|
2014
|
-
if ([PlaywrightAction.
|
|
2015
|
-
|
|
2021
|
+
if ([PlaywrightAction.ASSERT_EXACT_VALUE, PlaywrightAction.ASSERT_CONTAINS_VALUE, PlaywrightAction.ASSERT_URL,
|
|
2022
|
+
//TODO: remove these after migration
|
|
2023
|
+
PlaywrightAction.VALIDATE_EXACT_VALUE, PlaywrightAction.VALIDATE_CONTAINS_VALUE, PlaywrightAction.VALIDATE_URL
|
|
2024
|
+
].includes(action))
|
|
2016
2025
|
stepStatus = returnValue;
|
|
2017
2026
|
else
|
|
2018
2027
|
stepStatus = true;
|