@govtechsg/oobee 0.10.78-alpha1 → 0.10.84
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/Dockerfile +3 -2
- package/INTEGRATION.md +1 -1
- package/README.md +6 -1
- package/dist/constants/common.js +166 -91
- package/dist/constants/constants.js +1 -0
- package/dist/crawlers/crawlDomain.js +220 -120
- package/dist/crawlers/crawlIntelligentSitemap.js +22 -7
- package/dist/crawlers/custom/extractAndGradeText.js +1 -1
- package/dist/crawlers/custom/gradeReadability.js +1 -1
- package/dist/crawlers/runCustom.js +8 -2
- package/dist/generateHtmlReport.js +8 -3
- package/dist/mergeAxeResults/itemReferences.js +55 -0
- package/dist/mergeAxeResults/jsonArtifacts.js +335 -0
- package/dist/mergeAxeResults/scanPages.js +159 -0
- package/dist/mergeAxeResults/sentryTelemetry.js +152 -0
- package/dist/mergeAxeResults/types.js +1 -0
- package/dist/mergeAxeResults/writeCsv.js +125 -0
- package/dist/mergeAxeResults/writeScanDetailsCsv.js +35 -0
- package/dist/mergeAxeResults/writeSitemap.js +10 -0
- package/dist/mergeAxeResults.js +157 -971
- package/dist/proxyService.js +90 -5
- package/dist/static/ejs/partials/scripts/decodeUnzipParse.ejs +39 -2
- package/dist/static/ejs/partials/scripts/pako.ejs +4 -0
- package/dist/static/ejs/partials/scripts/ruleModal/itemCardRenderer.ejs +48 -2
- package/dist/static/ejs/partials/scripts/ruleModal/pageAccordionBuilder.ejs +129 -48
- package/dist/static/ejs/partials/scripts/ruleModal/utilities.ejs +2 -0
- package/dist/static/ejs/partials/scripts/screenshotLightbox.ejs +9 -4
- package/dist/static/ejs/partials/scripts/wcagCompliance/FailedCriteria.ejs +0 -2
- package/dist/static/ejs/partials/styles/fontAwesomeCssAll.ejs +7 -0
- package/dist/static/ejs/partials/styles/ruleModal/ruleOffcanvas.ejs +2 -0
- package/dist/static/ejs/report.ejs +122 -127
- package/dist/utils.js +22 -10
- package/package.json +17 -10
- package/src/constants/common.ts +181 -104
- package/src/constants/constants.ts +1 -0
- package/src/crawlers/crawlDomain.ts +248 -137
- package/src/crawlers/crawlIntelligentSitemap.ts +22 -8
- package/src/crawlers/custom/extractAndGradeText.ts +1 -1
- package/src/crawlers/custom/gradeReadability.ts +1 -1
- package/src/crawlers/runCustom.ts +10 -2
- package/src/generateHtmlReport.ts +9 -3
- package/src/mergeAxeResults/itemReferences.ts +62 -0
- package/src/mergeAxeResults/jsonArtifacts.ts +451 -0
- package/src/mergeAxeResults/scanPages.ts +207 -0
- package/src/mergeAxeResults/sentryTelemetry.ts +183 -0
- package/src/mergeAxeResults/types.ts +99 -0
- package/src/mergeAxeResults/writeCsv.ts +145 -0
- package/src/mergeAxeResults/writeScanDetailsCsv.ts +51 -0
- package/src/mergeAxeResults/writeSitemap.ts +13 -0
- package/src/mergeAxeResults.ts +203 -1326
- package/src/proxyService.ts +96 -4
- package/src/static/ejs/partials/scripts/decodeUnzipParse.ejs +39 -2
- package/src/static/ejs/partials/scripts/pako.ejs +4 -0
- package/src/static/ejs/partials/scripts/ruleModal/itemCardRenderer.ejs +48 -2
- package/src/static/ejs/partials/scripts/ruleModal/pageAccordionBuilder.ejs +129 -48
- package/src/static/ejs/partials/scripts/ruleModal/utilities.ejs +2 -0
- package/src/static/ejs/partials/scripts/screenshotLightbox.ejs +9 -4
- package/src/static/ejs/partials/scripts/wcagCompliance/FailedCriteria.ejs +0 -2
- package/src/static/ejs/partials/styles/fontAwesomeCssAll.ejs +7 -0
- package/src/static/ejs/partials/styles/ruleModal/ruleOffcanvas.ejs +2 -0
- package/src/static/ejs/report.ejs +122 -127
- package/src/utils.ts +20 -9
- package/scripts/decodeUnzipParse.js +0 -29
package/Dockerfile
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Use Microsoft Playwright image as base image
|
|
2
2
|
# Node version is v22
|
|
3
|
-
FROM mcr.microsoft.com/playwright:v1.
|
|
3
|
+
FROM mcr.microsoft.com/playwright:v1.58.2-noble
|
|
4
4
|
|
|
5
5
|
# Installation of packages for oobee and runner (locked versions from build log)
|
|
6
6
|
RUN apt-get update && apt-get install -y \
|
|
@@ -23,7 +23,8 @@ ENV NODE_ENV=production
|
|
|
23
23
|
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD="true"
|
|
24
24
|
|
|
25
25
|
# Install oobee dependencies
|
|
26
|
-
|
|
26
|
+
# TODO: Move back to npm ci --omit=dev once module package-lock issue vs MacOS is resolved
|
|
27
|
+
RUN npm install --omit=dev
|
|
27
28
|
|
|
28
29
|
# Compile TypeScript for oobee
|
|
29
30
|
RUN npm run build || true # true exits with code 0 - workaround for TS errors
|
package/INTEGRATION.md
CHANGED
|
@@ -468,4 +468,4 @@ Scans raw HTML string(s). Note that this runs in a JSDOM environment (NodeJS) us
|
|
|
468
468
|
|
|
469
469
|
**Returns:**
|
|
470
470
|
|
|
471
|
-
- Scan results object containing categorized violations
|
|
471
|
+
- Scan results object containing categorized violations (mustFix, goodToFux, needsReview).
|
package/README.md
CHANGED
|
@@ -90,6 +90,11 @@ verapdf --version
|
|
|
90
90
|
| WARN_LEVEL | Only used in tests. | |
|
|
91
91
|
| OOBEE_DISABLE_BROWSER_DOWNLOAD | Experimental flag to disable file downloads on Chrome/Chromium/Edge. Does not affect Local File scan | |
|
|
92
92
|
| OOBEE_SLOWMO | Experimental flag to slow down web browser behaviour by specified duration (in miliseconds) | |
|
|
93
|
+
| HTTP_PROXY | URL of the proxy server to be used for HTTP requests (e.g. `http://proxy.example.com:8080`). | |
|
|
94
|
+
| HTTPS_PROXY | URL of the proxy server to be used for HTTPS requests (e.g. `https://proxy.example.com:8080`). | |
|
|
95
|
+
| ALL_PROXY | URL of the proxy server to be used for all requests, typically used for SOCKS5 proxies (e.g. `socks5://proxy.example.com:1080`. Note: IPv6 direct connections may still continue even though socks5 proxy is specified due to a known issue with Chrome/Chromium. (Recommended workaround is to turn off IPv6 at host-level). | |
|
|
96
|
+
| NO_PROXY | Comma-separated list of domains that should bypass the proxy (e.g. `localhost,127.0.0.1,.example.com`). | |
|
|
97
|
+
| INCLUDE_PROXY | Comma-separated list of domains that should specifically be routed through the proxy. | |
|
|
93
98
|
|
|
94
99
|
#### Environment variables used internally (Do not set)
|
|
95
100
|
Do not set these environment variables or behaviour might change unexpectedly.
|
|
@@ -677,4 +682,4 @@ It uses the existing report *.json files for the embedded HTML dataset.
|
|
|
677
682
|
|
|
678
683
|
```
|
|
679
684
|
npx tsx dev/runGenerateJustHtmlReport.ts results/<report directory>
|
|
680
|
-
```
|
|
685
|
+
```
|
package/dist/constants/common.js
CHANGED
|
@@ -288,16 +288,45 @@ const checkUrlConnectivityWithBrowser = async (url, browserToRun, clonedDataDir,
|
|
|
288
288
|
extraHTTPHeaders.Accept ||= 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
|
|
289
289
|
await initModifiedUserAgent(browserToRun, playwrightDeviceDetailsObject, clonedDataDir);
|
|
290
290
|
let browserContext;
|
|
291
|
+
let browserInstance;
|
|
292
|
+
const rawDevice = (playwrightDeviceDetailsObject || {});
|
|
293
|
+
const { viewport, isMobile, hasTouch, userAgent: deviceUserAgent, ...restDevice } = rawDevice;
|
|
294
|
+
const launchOptions = getPlaywrightLaunchOptions(browserToRun);
|
|
295
|
+
const contextOptions = {
|
|
296
|
+
...restDevice,
|
|
297
|
+
...(extraHTTPHeaders && { extraHTTPHeaders }),
|
|
298
|
+
ignoreHTTPSErrors: true,
|
|
299
|
+
...(process.env.OOBEE_DISABLE_BROWSER_DOWNLOAD && { acceptDownloads: false }),
|
|
300
|
+
};
|
|
301
|
+
// Keep UA emulation explicitly.
|
|
302
|
+
contextOptions.userAgent = process.env.OOBEE_USER_AGENT || deviceUserAgent;
|
|
291
303
|
try {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
304
|
+
const launchPersistent = async () => {
|
|
305
|
+
browserContext = await constants.launcher.launchPersistentContext(clonedDataDir, {
|
|
306
|
+
...launchOptions,
|
|
307
|
+
...contextOptions,
|
|
308
|
+
});
|
|
309
|
+
register(browserContext);
|
|
310
|
+
};
|
|
311
|
+
const launchEphemeral = async () => {
|
|
312
|
+
browserInstance = await constants.launcher.launch(launchOptions);
|
|
313
|
+
register(browserInstance);
|
|
314
|
+
browserContext = await browserInstance.newContext(contextOptions);
|
|
315
|
+
};
|
|
316
|
+
if (process.env.CRAWLEE_HEADLESS === '1') {
|
|
317
|
+
try {
|
|
318
|
+
await launchPersistent();
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
// Fallback to ephemeral context if persistent context fails (e.g. protocol errors)
|
|
322
|
+
// More prone to falling back here when running localFile scans
|
|
323
|
+
consoleLogger.warn(`Persistent context launch failed, retrying with ephemeral context: ${error.message}`);
|
|
324
|
+
await launchEphemeral();
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
await launchEphemeral();
|
|
329
|
+
}
|
|
301
330
|
}
|
|
302
331
|
catch (err) {
|
|
303
332
|
printMessage([`Unable to launch browser\n${err}`], messageOptions);
|
|
@@ -335,7 +364,19 @@ const checkUrlConnectivityWithBrowser = async (url, browserToRun, clonedDataDir,
|
|
|
335
364
|
});
|
|
336
365
|
if (!response)
|
|
337
366
|
throw new Error('No response from navigation');
|
|
338
|
-
//
|
|
367
|
+
// Wait briefly for JS/meta-refresh redirects to settle before reading the final URL.
|
|
368
|
+
// Server-side redirects are already reflected after goto(), but client-side redirects
|
|
369
|
+
// (e.g. domain.tld -> www.domain.tld via JS or meta-refresh) need extra time.
|
|
370
|
+
try {
|
|
371
|
+
await Promise.race([
|
|
372
|
+
page.waitForURL(currentUrl => currentUrl !== url, { timeout: 5000 }),
|
|
373
|
+
new Promise(resolve => setTimeout(resolve, 1000)), // minimum settle time
|
|
374
|
+
]);
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
// No redirect happened within the window — that's fine, continue with current URL
|
|
378
|
+
}
|
|
379
|
+
// Re-read page.url() AFTER potential client-side redirects have resolved
|
|
339
380
|
const finalUrl = page.url();
|
|
340
381
|
const finalStatus = response.status();
|
|
341
382
|
const headers = response.headers();
|
|
@@ -399,7 +440,10 @@ const checkUrlConnectivityWithBrowser = async (url, browserToRun, clonedDataDir,
|
|
|
399
440
|
}
|
|
400
441
|
}
|
|
401
442
|
finally {
|
|
402
|
-
await browserContext
|
|
443
|
+
await browserContext?.close();
|
|
444
|
+
if (browserInstance) {
|
|
445
|
+
await browserInstance.close();
|
|
446
|
+
}
|
|
403
447
|
}
|
|
404
448
|
return res;
|
|
405
449
|
};
|
|
@@ -630,24 +674,49 @@ export const getUrlsFromRobotsTxt = async (url, browserToRun, userDataDirectory,
|
|
|
630
674
|
constants.robotsTxtUrls[domain] = { disallowedUrls, allowedUrls };
|
|
631
675
|
};
|
|
632
676
|
const getRobotsTxtViaPlaywright = async (robotsUrl, browser, userDataDirectory, extraHTTPHeaders) => {
|
|
633
|
-
|
|
677
|
+
let robotsDataDir = '';
|
|
678
|
+
let browserContext;
|
|
679
|
+
let browserInstance;
|
|
634
680
|
// Bug in Chrome which causes browser pool crash when userDataDirectory is set in non-headless mode
|
|
635
681
|
if (process.env.CRAWLEE_HEADLESS === '1') {
|
|
636
682
|
// Create robots own user data directory else SingletonLock: File exists (17) with crawlDomain or crawlSitemap's own browser
|
|
637
|
-
|
|
683
|
+
robotsDataDir = path.join(userDataDirectory, 'robots');
|
|
638
684
|
if (!fs.existsSync(robotsDataDir)) {
|
|
639
685
|
fs.mkdirSync(robotsDataDir, { recursive: true });
|
|
640
686
|
}
|
|
641
687
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
688
|
+
try {
|
|
689
|
+
if (process.env.CRAWLEE_HEADLESS === '1') {
|
|
690
|
+
browserContext = await constants.launcher.launchPersistentContext(robotsDataDir, {
|
|
691
|
+
...getPlaywrightLaunchOptions(browser),
|
|
692
|
+
...(extraHTTPHeaders && { extraHTTPHeaders }),
|
|
693
|
+
});
|
|
694
|
+
register(browserContext);
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
// In headful mode, avoid launchPersistentContext with custom user data dir to prevent "Browser window not found"
|
|
698
|
+
const launchOptions = getPlaywrightLaunchOptions(browser);
|
|
699
|
+
browserInstance = await constants.launcher.launch(launchOptions);
|
|
700
|
+
register(browserInstance);
|
|
701
|
+
browserContext = await browserInstance.newContext({
|
|
702
|
+
...(extraHTTPHeaders && { extraHTTPHeaders }),
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
const page = await browserContext.newPage();
|
|
706
|
+
await page.goto(robotsUrl, { waitUntil: 'networkidle', timeout: 30000 });
|
|
707
|
+
const robotsTxt = await page.evaluate(() => document.body.textContent);
|
|
708
|
+
return robotsTxt;
|
|
709
|
+
}
|
|
710
|
+
catch (e) {
|
|
711
|
+
consoleLogger.error(`Error fetching robots.txt: ${e.message}`);
|
|
712
|
+
throw e;
|
|
713
|
+
}
|
|
714
|
+
finally {
|
|
715
|
+
await browserContext?.close();
|
|
716
|
+
if (browserInstance) {
|
|
717
|
+
await browserInstance.close();
|
|
718
|
+
}
|
|
719
|
+
}
|
|
651
720
|
};
|
|
652
721
|
export const isDisallowedInRobotsTxt = (url) => {
|
|
653
722
|
if (!constants.robotsTxtUrls)
|
|
@@ -771,39 +840,59 @@ export const getLinksFromSitemap = async (sitemapUrl, maxLinksCount, browser, us
|
|
|
771
840
|
return;
|
|
772
841
|
}
|
|
773
842
|
const getDataUsingPlaywright = async () => {
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
else {
|
|
788
|
-
const urlSet = page.locator('urlset');
|
|
789
|
-
const sitemapIndex = page.locator('sitemapindex');
|
|
790
|
-
const rss = page.locator('rss');
|
|
791
|
-
const feed = page.locator('feed');
|
|
792
|
-
const isRoot = async (locator) => (await locator.count()) > 0;
|
|
793
|
-
if (await isRoot(urlSet)) {
|
|
794
|
-
data = await urlSet.evaluate(elem => elem.outerHTML);
|
|
843
|
+
let browserContext;
|
|
844
|
+
let browserInstance;
|
|
845
|
+
try {
|
|
846
|
+
if (process.env.CRAWLEE_HEADLESS === '1') {
|
|
847
|
+
browserContext = await constants.launcher.launchPersistentContext(finalUserDataDirectory, {
|
|
848
|
+
...getPlaywrightLaunchOptions(browser),
|
|
849
|
+
// Not necessary to parse http_credentials as I am parsing it directly in URL
|
|
850
|
+
// Bug in Chrome which causes browser pool crash when userDataDirectory is set in non-headless mode
|
|
851
|
+
...(process.env.CRAWLEE_HEADLESS === '1' && { userDataDir: userDataDirectory }),
|
|
852
|
+
...(extraHTTPHeaders && { extraHTTPHeaders }),
|
|
853
|
+
});
|
|
854
|
+
register(browserContext);
|
|
795
855
|
}
|
|
796
|
-
else
|
|
797
|
-
data
|
|
856
|
+
else {
|
|
857
|
+
// In headful mode, avoid launchPersistentContext with custom user data dir to prevent "Browser window not found"
|
|
858
|
+
const launchOptions = getPlaywrightLaunchOptions(browser);
|
|
859
|
+
browserInstance = await constants.launcher.launch(launchOptions);
|
|
860
|
+
register(browserInstance);
|
|
861
|
+
browserContext = await browserInstance.newContext({
|
|
862
|
+
...(extraHTTPHeaders && { extraHTTPHeaders }),
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
const page = await browserContext.newPage();
|
|
866
|
+
await page.goto(url, { waitUntil: 'networkidle', timeout: 60000 });
|
|
867
|
+
if ((await page.locator('body').count()) > 0) {
|
|
868
|
+
data = await page.locator('body').innerText();
|
|
798
869
|
}
|
|
799
|
-
else
|
|
800
|
-
|
|
870
|
+
else {
|
|
871
|
+
const urlSet = page.locator('urlset');
|
|
872
|
+
const sitemapIndex = page.locator('sitemapindex');
|
|
873
|
+
const rss = page.locator('rss');
|
|
874
|
+
const feed = page.locator('feed');
|
|
875
|
+
const isRoot = async (locator) => (await locator.count()) > 0;
|
|
876
|
+
if (await isRoot(urlSet)) {
|
|
877
|
+
data = await urlSet.evaluate(elem => elem.outerHTML);
|
|
878
|
+
}
|
|
879
|
+
else if (await isRoot(sitemapIndex)) {
|
|
880
|
+
data = await sitemapIndex.evaluate(elem => elem.outerHTML);
|
|
881
|
+
}
|
|
882
|
+
else if (await isRoot(rss)) {
|
|
883
|
+
data = await rss.evaluate(elem => elem.outerHTML);
|
|
884
|
+
}
|
|
885
|
+
else if (await isRoot(feed)) {
|
|
886
|
+
data = await feed.evaluate(elem => elem.outerHTML);
|
|
887
|
+
}
|
|
801
888
|
}
|
|
802
|
-
|
|
803
|
-
|
|
889
|
+
}
|
|
890
|
+
finally {
|
|
891
|
+
await browserContext?.close();
|
|
892
|
+
if (browserInstance) {
|
|
893
|
+
await browserInstance.close();
|
|
804
894
|
}
|
|
805
895
|
}
|
|
806
|
-
await browserContext.close();
|
|
807
896
|
};
|
|
808
897
|
if (validator.isURL(url, urlOptions)) {
|
|
809
898
|
if (isUrlPdf(url)) {
|
|
@@ -1486,36 +1575,25 @@ export const submitForm = async (browserToRun, userDataDirectory, scannedUrl, en
|
|
|
1486
1575
|
}
|
|
1487
1576
|
};
|
|
1488
1577
|
// Legacy code end - Google Sheets submission
|
|
1489
|
-
export async function initModifiedUserAgent(browser,
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
const defaultUA = await page.evaluate(() => navigator.userAgent);
|
|
1509
|
-
await browserContext.close();
|
|
1510
|
-
// Modify the UA:
|
|
1511
|
-
// Replace "HeadlessChrome" with "Chrome" if present.
|
|
1512
|
-
const modifiedUA = defaultUA.includes('HeadlessChrome')
|
|
1513
|
-
? defaultUA.replace('HeadlessChrome', 'Chrome')
|
|
1514
|
-
: defaultUA;
|
|
1515
|
-
// Push the modified UA flag into your global launch options.
|
|
1516
|
-
constants.launchOptionsArgs.push(`--user-agent=${modifiedUA}`);
|
|
1517
|
-
// Optionally log the modified UA.
|
|
1518
|
-
// console.log('Modified User Agent:', modifiedUA);
|
|
1578
|
+
export async function initModifiedUserAgent(browser, _playwrightDeviceDetailsObject, _userDataDirectory) {
|
|
1579
|
+
// UA bootstrap must not use persistent context / user-data-dir.
|
|
1580
|
+
const launchOptions = getPlaywrightLaunchOptions(browser);
|
|
1581
|
+
const browserInstance = await constants.launcher.launch(launchOptions);
|
|
1582
|
+
register(browserInstance);
|
|
1583
|
+
try {
|
|
1584
|
+
const context = await browserInstance.newContext();
|
|
1585
|
+
const page = await context.newPage();
|
|
1586
|
+
const defaultUA = await page.evaluate(() => navigator.userAgent);
|
|
1587
|
+
await context.close();
|
|
1588
|
+
const modifiedUA = defaultUA.includes('HeadlessChrome')
|
|
1589
|
+
? defaultUA.replace('HeadlessChrome', 'Chrome')
|
|
1590
|
+
: defaultUA;
|
|
1591
|
+
// Do not mutate global CLI args with --user-agent=
|
|
1592
|
+
process.env.OOBEE_USER_AGENT = modifiedUA;
|
|
1593
|
+
}
|
|
1594
|
+
finally {
|
|
1595
|
+
await browserInstance.close();
|
|
1596
|
+
}
|
|
1519
1597
|
}
|
|
1520
1598
|
const cacheProxyInfo = getProxyInfo();
|
|
1521
1599
|
/**
|
|
@@ -1525,12 +1603,13 @@ const cacheProxyInfo = getProxyInfo();
|
|
|
1525
1603
|
export const getPlaywrightLaunchOptions = (browser) => {
|
|
1526
1604
|
const channel = browser || undefined;
|
|
1527
1605
|
const resolution = proxyInfoToResolution(cacheProxyInfo);
|
|
1528
|
-
// Start with your base args
|
|
1529
|
-
const finalArgs = [...constants.launchOptionsArgs]
|
|
1606
|
+
// Start with your base args and sanitise
|
|
1607
|
+
const finalArgs = [...constants.launchOptionsArgs].filter(arg => !arg.startsWith('--headless') &&
|
|
1608
|
+
!arg.startsWith('--user-agent=') &&
|
|
1609
|
+
arg !== '--mute-audio' &&
|
|
1610
|
+
!(browser === BrowserTypes.CHROME && arg === '--edge-skip-compat-layer-relaunch'));
|
|
1530
1611
|
// Headless flags (unchanged)
|
|
1531
1612
|
if (process.env.CRAWLEE_HEADLESS === '1') {
|
|
1532
|
-
if (!finalArgs.includes('--headless=new'))
|
|
1533
|
-
finalArgs.push('--headless=new');
|
|
1534
1613
|
if (!finalArgs.includes('--mute-audio'))
|
|
1535
1614
|
finalArgs.push('--mute-audio');
|
|
1536
1615
|
}
|
|
@@ -1551,21 +1630,17 @@ export const getPlaywrightLaunchOptions = (browser) => {
|
|
|
1551
1630
|
break;
|
|
1552
1631
|
}
|
|
1553
1632
|
const options = {
|
|
1554
|
-
ignoreDefaultArgs: ['--use-mock-keychain'
|
|
1633
|
+
ignoreDefaultArgs: ['--use-mock-keychain'],
|
|
1555
1634
|
args: finalArgs,
|
|
1556
|
-
headless:
|
|
1635
|
+
headless: process.env.CRAWLEE_HEADLESS === '1',
|
|
1557
1636
|
...(channel && { channel }),
|
|
1558
1637
|
...(proxyOpt ? { proxy: proxyOpt } : {}),
|
|
1559
1638
|
};
|
|
1560
|
-
// SlowMo
|
|
1639
|
+
// SlowMo for debugging, can be set via env variable OOBEE_SLOWMO to avoid adding it as a CLI argument and causing confusion for users who don't need it
|
|
1561
1640
|
if (!options.slowMo && process.env.OOBEE_SLOWMO && Number(process.env.OOBEE_SLOWMO) >= 1) {
|
|
1562
1641
|
options.slowMo = Number(process.env.OOBEE_SLOWMO);
|
|
1563
1642
|
consoleLogger.info(`Enabled browser slowMo with value: ${process.env.OOBEE_SLOWMO}ms`);
|
|
1564
1643
|
}
|
|
1565
|
-
// Edge on Windows should not be headless (unchanged)
|
|
1566
|
-
if (browser === BrowserTypes.EDGE && os.platform() === 'win32') {
|
|
1567
|
-
options.headless = false;
|
|
1568
|
-
}
|
|
1569
1644
|
return options;
|
|
1570
1645
|
};
|
|
1571
1646
|
export const waitForPageLoaded = async (page, timeout = 10000) => {
|