Skip to content

Commit 3c010cd

Browse files
authored
Adds configurable browser close behavior (#1923)
* Adds configurable browser close behavior Introduces a `closeBrowser` option in launch settings to control browser closure after tasks. Updates logic in `Browser` and `Session` classes to respect this option, enabling flexibility in workflows. Includes relevant unit tests to ensure proper handling of the `closeBrowser` option in various scenarios. * launchOptions will always have closeBrowser in it
1 parent f6b7891 commit 3c010cd

File tree

4 files changed

+96
-7
lines changed

4 files changed

+96
-7
lines changed

packages/core/src/browser.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class Browser extends EventEmitter {
7777
if (this.readyState != null) return;
7878
this.readyState = 0;
7979

80-
let { cookies = [], launchOptions = {} } = this.percy.config.discovery;
80+
let { cookies = [], launchOptions } = this.percy.config.discovery;
8181
let { executable, headless = true, args = [], timeout } = launchOptions;
8282
executable ??= process.env.PERCY_BROWSER_EXECUTABLE;
8383

@@ -120,7 +120,13 @@ export class Browser extends EventEmitter {
120120
return this.ws?.readyState === WebSocket.OPEN;
121121
}
122122

123-
async close() {
123+
async close(force = false) {
124+
// Check for the new closeBrowser option
125+
if (!force && this.percy.config.discovery?.launchOptions?.closeBrowser === false) {
126+
this.log.debug('Skipping browser close due to closeBrowser:false option');
127+
return true;
128+
}
129+
124130
// not running, already closed, or closing
125131
if (this._closed) return this._closed;
126132
this.readyState = 2;

packages/core/src/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ export const configSchema = {
357357
executable: { type: 'string' },
358358
timeout: { type: 'integer' },
359359
args: { type: 'array', items: { type: 'string' } },
360-
headless: { type: 'boolean' }
360+
headless: { type: 'boolean' },
361+
closeBrowser: { type: 'boolean', default: true }
361362
}
362363
}
363364
}

packages/core/src/session.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ export class Session extends EventEmitter {
2222
}
2323

2424
async close() {
25+
// Check for the new closeBrowser option
26+
if (this.browser?.percy.config.discovery?.launchOptions?.closeBrowser === false) {
27+
this.log.debug('Skipping session close due to closeBrowser:false option');
28+
return true;
29+
}
30+
2531
if (!this.browser || this.closing) return;
2632
this.closing = true;
2733

packages/core/test/discovery.test.js

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,8 @@ describe('Discovery', () => {
24482448

24492449
describe('with launch options', () => {
24502450
beforeEach(async () => {
2451-
await percy.stop(true);
2451+
// ensure a new percy instance is used for each test
2452+
await percy?.stop(true);
24522453
});
24532454

24542455
it('should log an error if a provided executable cannot be found', async () => {
@@ -2525,6 +2526,81 @@ describe('Discovery', () => {
25252526

25262527
sharedExpectBlock(expectedBody);
25272528
});
2529+
2530+
it('does not close the browser when closeBrowser is false', async () => {
2531+
percy = await Percy.start({
2532+
token: 'PERCY_TOKEN',
2533+
snapshot: { widths: [1000] },
2534+
discovery: {
2535+
launchOptions: {
2536+
closeBrowser: false
2537+
}
2538+
}
2539+
});
2540+
2541+
await percy.snapshot({
2542+
name: 'test snapshot',
2543+
url: 'http://localhost:8000',
2544+
domSnapshot: testDOM
2545+
});
2546+
2547+
await percy.idle();
2548+
// Check if browser is still connected after snapshot and idle
2549+
expect(percy.browser.isConnected()).toBe(true);
2550+
// Explicitly stop percy to close the browser for subsequent tests
2551+
await percy.browser.close(true); // force close
2552+
expect(percy.browser.isConnected()).toBe(false);
2553+
});
2554+
2555+
it('closes the browser by default when closeBrowser is not set', async () => {
2556+
percy = await Percy.start({
2557+
token: 'PERCY_TOKEN',
2558+
snapshot: { widths: [1000] },
2559+
discovery: {
2560+
launchOptions: {} // closeBrowser is not set
2561+
}
2562+
});
2563+
const browserInstance = percy.browser;
2564+
spyOn(browserInstance, 'close').and.callThrough();
2565+
2566+
await percy.snapshot({
2567+
name: 'test snapshot',
2568+
url: 'http://localhost:8000',
2569+
domSnapshot: testDOM
2570+
});
2571+
2572+
await percy.idle();
2573+
// Percy stop is called internally, which should close the browser
2574+
await percy.stop(true);
2575+
expect(browserInstance.close).toHaveBeenCalled();
2576+
expect(browserInstance.isConnected()).toBe(false);
2577+
});
2578+
2579+
it('closes the browser when closeBrowser is true', async () => {
2580+
percy = await Percy.start({
2581+
token: 'PERCY_TOKEN',
2582+
snapshot: { widths: [1000] },
2583+
discovery: {
2584+
launchOptions: {
2585+
closeBrowser: true
2586+
}
2587+
}
2588+
});
2589+
const browserInstance = percy.browser;
2590+
spyOn(browserInstance, 'close').and.callThrough();
2591+
2592+
await percy.snapshot({
2593+
name: 'test snapshot',
2594+
url: 'http://localhost:8000',
2595+
domSnapshot: testDOM
2596+
});
2597+
2598+
await percy.idle();
2599+
// Percy stop is called internally, which should close the browser
2600+
await percy.stop(true);
2601+
expect(browserInstance.close).toHaveBeenCalled();
2602+
expect(browserInstance.isConnected()).toBe(false);
2603+
});
25282604
});
25292605

25302606
describe('Asset Discovery Page JS =>', () => {
@@ -2893,8 +2969,8 @@ describe('Discovery', () => {
28932969
<body>
28942970
<p>Hello Percy!<p>
28952971
<img srcset="/img-fromsrcset.png 400w, /img-throwserror.gif 600w, /img-withdifferentcontenttype.gif 800w"
2896-
sizes="(max-width: 600px) 400px, (max-width: 800px) 600px, 800px"
2897-
src="/img-already-captured.png">
2972+
sizes="(max-width: 600px) 400px, (max-width: 800px) 600px, 800px"
2973+
src="/img-already-captured.png">
28982974
</body>
28992975
</html>
29002976
`;
@@ -3499,7 +3575,7 @@ describe('Discovery', () => {
34993575

35003576
server.reply('/', () => [200, 'text/html', lazyDOM]);
35013577

3502-
// Take a snapshot with scrollToBottom disabled
3578+
// Take a Percy snapshot with scrollToBottom disabled
35033579
await percy.snapshot({
35043580
name: 'no scroll to bottom test',
35053581
url: 'http://localhost:8080',

0 commit comments

Comments
 (0)