Skip to content

Commit bd46315

Browse files
Merge pull request #3 from somebodysmokein/develop
Updated with the Android config
2 parents be92604 + e3bfb3f commit bd46315

11 files changed

+273
-153
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
node_modules
2-
playwright-report
2+
playwright-report
3+
local.log
4+
local.log
5+
package-lock.json
6+
local.log

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
- To run a sample test, run `npm run sample-test`
1616

17+
## Running your tests on mobile
18+
19+
- To run a sample test, run `npm run mobile-test`
20+
1721
## Run tests on locally hosted websites
1822
* Run `npm run sample-local-test`
1923

browserstack.config.js

Lines changed: 0 additions & 52 deletions
This file was deleted.

fixture.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
const base = require("@playwright/test");
2+
const cp = require("child_process");
3+
const { _android } = require("playwright");
4+
const clientPlaywrightVersion = cp
5+
.execSync("npx playwright --version")
6+
.toString()
7+
.trim()
8+
.split(" ")[1];
9+
const BrowserStackLocal = require("browserstack-local");
10+
const util = require("util");
11+
12+
// BrowserStack Specific Capabilities.
13+
// Set 'browserstack.local:true For Local testing
14+
const caps = {
15+
osVersion: "13.0",
16+
deviceName: "Samsung Galaxy S23", // "Samsung Galaxy S22 Ultra", "Google Pixel 7 Pro", "OnePlus 9", etc.
17+
browserName: "chrome",
18+
realMobile: "true",
19+
name: "My android playwright test",
20+
build: "playwright-build-1",
21+
"browserstack.username": process.env.BROWSERSTACK_USERNAME || "<USERNAME>",
22+
"browserstack.accessKey":
23+
process.env.BROWSERSTACK_ACCESS_KEY || "<ACCESS_KEY>",
24+
"browserstack.local": process.env.BROWSERSTACK_LOCAL || false,
25+
};
26+
27+
exports.bsLocal = new BrowserStackLocal.Local();
28+
29+
// replace YOUR_ACCESS_KEY with your key. You can also set an environment variable - "BROWSERSTACK_ACCESS_KEY".
30+
exports.BS_LOCAL_ARGS = {
31+
key: process.env.BROWSERSTACK_ACCESS_KEY || "ACCESSKEY",
32+
};
33+
34+
// Patching the capabilities dynamically according to the project name.
35+
const patchMobileCaps = (name, title) => {
36+
let combination = name.split(/@browserstack/)[0];
37+
let [browerCaps, osCaps] = combination.split(/:/);
38+
let [browser, deviceName] = browerCaps.split(/@/);
39+
let osCapsSplit = osCaps.split(/ /);
40+
let os = osCapsSplit.shift();
41+
let osVersion = osCapsSplit.join(" ");
42+
caps.browser = browser ? browser : "chrome";
43+
caps.deviceName = deviceName ? deviceName : "Samsung Galaxy S22 Ultra";
44+
caps.osVersion = osVersion ? osVersion : "12.0";
45+
caps.name = title;
46+
caps.realMobile = "true";
47+
};
48+
49+
const patchCaps = (name, title) => {
50+
let combination = name.split(/@browserstack/)[0];
51+
let [browerCaps, osCaps] = combination.split(/:/);
52+
let [browser, browser_version] = browerCaps.split(/@/);
53+
let osCapsSplit = osCaps.split(/ /);
54+
let os = osCapsSplit.shift();
55+
let os_version = osCapsSplit.join(" ");
56+
caps.browser = browser ? browser : "chrome";
57+
caps.browser_version = browser_version ? browser_version : "latest";
58+
caps.os = os ? os : "osx";
59+
caps.os_version = os_version ? os_version : "catalina";
60+
caps.name = title;
61+
};
62+
63+
const isHash = (entity) =>
64+
Boolean(entity && typeof entity === "object" && !Array.isArray(entity));
65+
const nestedKeyValue = (hash, keys) =>
66+
keys.reduce((hash, key) => (isHash(hash) ? hash[key] : undefined), hash);
67+
const isUndefined = (val) => val === undefined || val === null || val === "";
68+
const evaluateSessionStatus = (status) => {
69+
if (!isUndefined(status)) {
70+
status = status.toLowerCase();
71+
}
72+
if (status === "passed") {
73+
return "passed";
74+
} else if (status === "failed" || status === "timedout") {
75+
return "failed";
76+
} else {
77+
return "";
78+
}
79+
};
80+
81+
exports.test = base.test.extend({
82+
page: async ({ page, playwright }, use, testInfo) => {
83+
if (testInfo.project.name.match(/browserstack/)) {
84+
let vBrowser, vContext, vDevice;
85+
const isMobile = testInfo.project.name.match(/browserstack-mobile/);
86+
if (isMobile) {
87+
patchMobileCaps(
88+
testInfo.project.name,
89+
`${testInfo.file} - ${testInfo.title}`
90+
);
91+
vDevice = await playwright._android.connect(
92+
`wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(
93+
JSON.stringify(caps)
94+
)}`
95+
);
96+
await vDevice.shell("am force-stop com.android.chrome");
97+
vContext = await vDevice.launchBrowser();
98+
} else {
99+
patchCaps(testInfo.project.name, `${testInfo.title}`);
100+
delete caps.osVersion;
101+
delete caps.deviceName;
102+
delete caps.realMobile;
103+
vBrowser = await playwright.chromium.connect({
104+
wsEndpoint:
105+
`wss://cdp.browserstack.com/playwright?caps=` +
106+
`${encodeURIComponent(JSON.stringify(caps))}`,
107+
});
108+
vContext = await vBrowser.newContext(testInfo.project.use);
109+
}
110+
const vPage = await vContext.newPage();
111+
await use(vPage);
112+
113+
await vPage.close();
114+
115+
if (isMobile) {
116+
await vDevice.close();
117+
} else {
118+
await vBrowser.close();
119+
}
120+
} else {
121+
use(page);
122+
}
123+
},
124+
125+
beforeEach: [
126+
async ({ page }, use) => {
127+
await page
128+
.context()
129+
.tracing.start({ screenshots: true, snapshots: true, sources: true });
130+
await use();
131+
},
132+
{ auto: true },
133+
],
134+
135+
afterEach: [
136+
async ({ page }, use, testInfo) => {
137+
await use();
138+
if (testInfo.status == "failed") {
139+
await page
140+
.context()
141+
.tracing.stop({ path: `${testInfo.outputDir}/trace.zip` });
142+
await page.screenshot({ path: `${testInfo.outputDir}/screenshot.png` });
143+
await testInfo.attach("screenshot", {
144+
path: `${testInfo.outputDir}/screenshot.png`,
145+
contentType: "image/png",
146+
});
147+
await testInfo.attach("trace", {
148+
path: `${testInfo.outputDir}/trace.zip`,
149+
contentType: "application/zip",
150+
});
151+
}
152+
},
153+
{ auto: true },
154+
],
155+
});

global-setup.js

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
// global-setup.js
2-
const { bsLocal, BS_LOCAL_ARGS } = require('./browserstack.config');
3-
const { promisify } = require('util');
2+
const { bsLocal, BS_LOCAL_ARGS } = require("./fixture");
3+
const { promisify } = require("util");
44
const sleep = promisify(setTimeout);
5-
const redColour = '\x1b[31m';
6-
const whiteColour = '\x1b[0m';
5+
const redColour = "\x1b[31m";
6+
const whiteColour = "\x1b[0m";
77
module.exports = async () => {
8-
console.log('Starting BrowserStackLocal ...');
9-
// Starts the Local instance with the required arguments
10-
let localResponseReceived = false;
11-
bsLocal.start(BS_LOCAL_ARGS, (err) => {
12-
if (err) {
13-
console.error(
14-
`${redColour}Error starting BrowserStackLocal${whiteColour}`
15-
);
16-
} else {
17-
console.log('BrowserStackLocal Started');
8+
if (process.env.BROWSERSTACK_LOCAL === "true") {
9+
console.log("Starting BrowserStackLocal ...");
10+
// Starts the Local instance with the required arguments
11+
let localResponseReceived = false;
12+
bsLocal.start(BS_LOCAL_ARGS, (err) => {
13+
if (err) {
14+
console.error(
15+
`${redColour}Error starting BrowserStackLocal${whiteColour}`
16+
);
17+
} else {
18+
console.log("BrowserStackLocal Started");
19+
}
20+
localResponseReceived = true;
21+
});
22+
while (!localResponseReceived) {
23+
await sleep(1000);
1824
}
19-
localResponseReceived = true;
20-
});
21-
while (!localResponseReceived) {
22-
await sleep(1000);
25+
} else {
26+
console.log("Skipping BrowserStackLocal...");
2327
}
2428
};

global-teardown.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// global-teardown.js
2-
const { bsLocal } = require('./browserstack.config');
3-
const { promisify } = require('util');
2+
const { bsLocal } = require("./fixture");
3+
const { promisify } = require("util");
44
const sleep = promisify(setTimeout);
55
module.exports = async () => {
66
// Stop the Local instance after your test run is completed, i.e after driver.quit
@@ -9,10 +9,10 @@ module.exports = async () => {
99
if (bsLocal && bsLocal.isRunning()) {
1010
bsLocal.stop(() => {
1111
localStopped = true;
12-
console.log('Stopped BrowserStackLocal');
12+
console.log("Stopped BrowserStackLocal");
1313
});
1414
while (!localStopped) {
1515
await sleep(1000);
1616
}
1717
}
18-
}
18+
};

local.log

14.1 KB
Binary file not shown.

package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44
"description": "",
55
"main": "index.js",
66
"scripts": {
7-
"sample-local-test":"npx playwright test tests/local_test.js",
8-
"sample-test":"npx playwright test tests/sample_test.js"
7+
"sample-local-test": "BROWSERSTACK_LOCAL=true npx playwright test tests/local_test.js",
8+
"sample-test": "npx playwright test tests/sample_test.js",
9+
"mobile-test": "npx playwright test tests/sample_test.js --project='chrome@Samsung Galaxy S22:13@browserstack-mobile'"
910
},
1011
"keywords": [],
1112
"author": "",
1213
"license": "ISC",
1314
"devDependencies": {
14-
"@playwright/test": "^1.29.1",
15-
"browserstack-local": "^1.5.1"
15+
"@playwright/test": "^1.34.3",
16+
"browserstack-local": "^1.5.1",
17+
"playwright": "1.34.3",
18+
"prettier": "2.8.8"
1619
}
1720
}

0 commit comments

Comments
 (0)