|
| 1 | +const base = require('@playwright/test'); |
| 2 | +const cp = require('child_process'); |
| 3 | +const clientPlaywrightVersion = cp |
| 4 | + .execSync('npx playwright --version') |
| 5 | + .toString() |
| 6 | + .trim() |
| 7 | + .split(' ')[1]; |
| 8 | +const BrowserStackLocal = require('browserstack-local'); |
| 9 | + |
| 10 | +// BrowserStack Specific Capabilities. |
| 11 | +const caps = { |
| 12 | + browser: 'chrome', |
| 13 | + os: 'osx', |
| 14 | + os_version: 'catalina', |
| 15 | + name: 'My first playwright test', |
| 16 | + build: 'playwright-build-1', |
| 17 | + 'browserstack.username': process.env.BROWSERSTACK_USERNAME || 'YOUR_USERNAME', |
| 18 | + 'browserstack.accessKey': |
| 19 | + process.env.BROWSERSTACK_ACCESS_KEY || 'YOUR_ACCESS_KEY', |
| 20 | + 'browserstack.local': process.env.BROWSERSTACK_LOCAL || false, |
| 21 | + 'client.playwrightVersion': clientPlaywrightVersion, |
| 22 | +}; |
| 23 | + |
| 24 | +exports.bsLocal = new BrowserStackLocal.Local(); |
| 25 | + |
| 26 | +// replace YOUR_ACCESS_KEY with your key. You can also set an environment variable - "BROWSERSTACK_ACCESS_KEY". |
| 27 | +exports.BS_LOCAL_ARGS = { |
| 28 | + key: process.env.BROWSERSTACK_ACCESS_KEY || 'YOUR_ACCESS_KEY', |
| 29 | +}; |
| 30 | + |
| 31 | +// Patching the capabilities dynamically according to the project name. |
| 32 | +const patchCaps = (name, title) => { |
| 33 | + let combination = name.split(/@browserstack/)[0]; |
| 34 | + let [browerCaps, osCaps] = combination.split(/:/); |
| 35 | + let [browser, browser_version] = browerCaps.split(/@/); |
| 36 | + let osCapsSplit = osCaps.split(/ /); |
| 37 | + let os = osCapsSplit.shift(); |
| 38 | + let os_version = osCapsSplit.join(' '); |
| 39 | + caps.browser = browser ? browser : 'chrome'; |
| 40 | + caps.browser_version = browser_version ? browser_version : 'latest'; |
| 41 | + caps.os = os ? os : 'osx'; |
| 42 | + caps.os_version = os_version ? os_version : 'catalina'; |
| 43 | + caps.name = title; |
| 44 | +}; |
| 45 | + |
| 46 | +const isHash = (entity) => Boolean(entity && typeof(entity) === "object" && !Array.isArray(entity)); |
| 47 | +const nestedKeyValue = (hash, keys) => keys.reduce((hash, key) => (isHash(hash) ? hash[key] : undefined), hash); |
| 48 | +const isUndefined = val => (val === undefined || val === null || val === ''); |
| 49 | +const evaluateSessionStatus = (status) => { |
| 50 | + if (!isUndefined(status)) { |
| 51 | + status = status.toLowerCase(); |
| 52 | + } |
| 53 | + if (status === "passed") { |
| 54 | + return "passed"; |
| 55 | + } else if (status === "failed" || status === "timedout") { |
| 56 | + return "failed"; |
| 57 | + } else { |
| 58 | + return ""; |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +exports.test = base.test.extend({ |
| 63 | + page: async ({ page, playwright }, use, testInfo) => { |
| 64 | + // Use BrowserStack Launched Browser according to capabilities for cross-browser testing. |
| 65 | + if (testInfo.project.name.match(/browserstack/)) { |
| 66 | + patchCaps(testInfo.project.name, `${testInfo.title}`); |
| 67 | + const vBrowser = await playwright.chromium.connect({ |
| 68 | + wsEndpoint: |
| 69 | + `wss://cdp.browserstack.com/playwright?caps=` + |
| 70 | + `${encodeURIComponent(JSON.stringify(caps))}`, |
| 71 | + }); |
| 72 | + const vContext = await vBrowser.newContext(testInfo.project.use); |
| 73 | + const vPage = await vContext.newPage(); |
| 74 | + await use(vPage); |
| 75 | + const testResult = { |
| 76 | + action: 'setSessionStatus', |
| 77 | + arguments: { |
| 78 | + status: evaluateSessionStatus(testInfo.status), |
| 79 | + reason: nestedKeyValue(testInfo, ['error', 'message']) |
| 80 | + }, |
| 81 | + }; |
| 82 | + await vPage.evaluate(() => {}, |
| 83 | + `browserstack_executor: ${JSON.stringify(testResult)}`); |
| 84 | + await vPage.close(); |
| 85 | + await vBrowser.close(); |
| 86 | + } else { |
| 87 | + use(page); |
| 88 | + } |
| 89 | + }, |
| 90 | +}); |
0 commit comments