@browserless.io/browserless 2.24.0-beta-4 → 2.24.0
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/CHANGELOG.md +17 -1
- package/bin/browserless.js +1 -1
- package/build/browsers/browsers.playwright.d.ts +1 -0
- package/build/browsers/browsers.playwright.js +3 -0
- package/build/browsers/index.d.ts +2 -1
- package/build/browsers/index.js +28 -7
- package/build/http.d.ts +5 -0
- package/build/http.js +1 -0
- package/build/routes/chrome/http/content.post.body.json +35 -10
- package/build/routes/chrome/http/content.post.query.json +4 -0
- package/build/routes/chrome/http/download.post.query.json +4 -0
- package/build/routes/chrome/http/function.post.query.json +4 -0
- package/build/routes/chrome/http/pdf.post.body.json +35 -10
- package/build/routes/chrome/http/pdf.post.query.json +4 -0
- package/build/routes/chrome/http/performance.post.query.json +4 -0
- package/build/routes/chrome/http/scrape.post.body.json +35 -10
- package/build/routes/chrome/http/scrape.post.query.json +4 -0
- package/build/routes/chrome/http/scrape.post.response.json +26 -1
- package/build/routes/chrome/http/screenshot.post.body.json +35 -10
- package/build/routes/chrome/http/screenshot.post.query.json +4 -0
- package/build/routes/chrome/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/chrome/tests/kill-sessions.spec.js +80 -0
- package/build/routes/chrome/ws/browser.query.json +4 -0
- package/build/routes/chrome/ws/cdp.query.json +4 -0
- package/build/routes/chrome/ws/page.query.json +4 -0
- package/build/routes/chrome/ws/playwright.query.json +4 -0
- package/build/routes/chromium/http/content.post.body.json +35 -10
- package/build/routes/chromium/http/content.post.query.json +4 -0
- package/build/routes/chromium/http/download.post.query.json +4 -0
- package/build/routes/chromium/http/function.post.query.json +4 -0
- package/build/routes/chromium/http/pdf.post.body.json +35 -10
- package/build/routes/chromium/http/pdf.post.query.json +4 -0
- package/build/routes/chromium/http/performance.post.query.json +4 -0
- package/build/routes/chromium/http/scrape.post.body.json +35 -10
- package/build/routes/chromium/http/scrape.post.query.json +4 -0
- package/build/routes/chromium/http/scrape.post.response.json +26 -1
- package/build/routes/chromium/http/screenshot.post.body.json +35 -10
- package/build/routes/chromium/http/screenshot.post.query.json +4 -0
- package/build/routes/chromium/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/chromium/tests/kill-sessions.spec.js +80 -0
- package/build/routes/chromium/tests/websocket.spec.js +23 -0
- package/build/routes/chromium/ws/browser.query.json +4 -0
- package/build/routes/chromium/ws/cdp.query.json +4 -0
- package/build/routes/chromium/ws/page.query.json +4 -0
- package/build/routes/chromium/ws/playwright.query.json +4 -0
- package/build/routes/firefox/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/firefox/tests/kill-sessions.spec.js +72 -0
- package/build/routes/firefox/ws/playwright.query.json +4 -0
- package/build/routes/management/http/kill.get.d.ts +21 -0
- package/build/routes/management/http/kill.get.js +19 -0
- package/build/routes/management/http/kill.get.query.json +193 -0
- package/build/routes/management/http/meta.get.js +3 -2
- package/build/routes/management/http/sessions.get.query.json +1 -0
- package/build/routes/management/tests/management.spec.js +12 -0
- package/build/routes/webkit/tests/kill-sessions.spec.d.ts +1 -0
- package/build/routes/webkit/tests/kill-sessions.spec.js +72 -0
- package/build/routes/webkit/ws/playwright.query.json +4 -0
- package/build/types.d.ts +2 -0
- package/build/types.js +1 -0
- package/build/utils.d.ts +1 -1
- package/build/utils.js +1 -10
- package/package.json +5 -5
- package/src/browsers/browsers.playwright.ts +3 -0
- package/src/browsers/index.ts +33 -12
- package/src/http.ts +6 -0
- package/src/routes/chrome/tests/kill-sessions.spec.ts +99 -0
- package/src/routes/chromium/tests/kill-sessions.spec.ts +99 -0
- package/src/routes/chromium/tests/websocket.spec.ts +29 -0
- package/src/routes/firefox/tests/kill-sessions.spec.ts +99 -0
- package/src/routes/management/http/kill.get.ts +40 -0
- package/src/routes/management/http/meta.get.ts +12 -10
- package/src/routes/management/tests/management.spec.ts +19 -0
- package/src/routes/webkit/tests/kill-sessions.spec.ts +99 -0
- package/src/types.ts +1 -0
- package/src/utils.ts +2 -11
- package/static/docs/swagger.json +384 -15
- package/static/docs/swagger.min.json +383 -14
- package/static/function/client.js +954 -845
- package/static/function/index.html +954 -845
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Browserless, Config, Metrics } from '@browserless.io/browserless';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import { webkit } from 'playwright-core';
|
|
4
|
+
describe('/kill API webkit', function () {
|
|
5
|
+
let browserless;
|
|
6
|
+
const start = ({ config = new Config(), metrics = new Metrics(), } = {}) => {
|
|
7
|
+
config.setToken('browserless');
|
|
8
|
+
browserless = new Browserless({ config, metrics });
|
|
9
|
+
return browserless.start();
|
|
10
|
+
};
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
await browserless.stop();
|
|
13
|
+
});
|
|
14
|
+
it('Kill all sessions', async () => {
|
|
15
|
+
await start();
|
|
16
|
+
const browser1 = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless&trackingId=session-1`);
|
|
17
|
+
const browser2 = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless&trackingId=session-2`);
|
|
18
|
+
await fetch('http://localhost:3000/kill/all?token=browserless').then(async (res) => {
|
|
19
|
+
expect(res.status).to.equal(204);
|
|
20
|
+
});
|
|
21
|
+
let errorThrown1;
|
|
22
|
+
try {
|
|
23
|
+
await browser1.newPage();
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
errorThrown1 = e;
|
|
27
|
+
}
|
|
28
|
+
let errorThrown2;
|
|
29
|
+
try {
|
|
30
|
+
await browser2.newPage();
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
errorThrown2 = e;
|
|
34
|
+
}
|
|
35
|
+
expect(errorThrown1.message).contains('closed');
|
|
36
|
+
expect(errorThrown2.message).contains('closed');
|
|
37
|
+
});
|
|
38
|
+
it('Kill session by browserId', async () => {
|
|
39
|
+
await start();
|
|
40
|
+
const browser = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless`);
|
|
41
|
+
await fetch('http://localhost:3000/sessions?token=browserless').then(async (res) => {
|
|
42
|
+
const sessions = await res.json();
|
|
43
|
+
const browserId = sessions[0].browserId;
|
|
44
|
+
await fetch(`http://localhost:3000/kill/${browserId}?token=browserless`).then(async (res) => {
|
|
45
|
+
expect(res.status).to.equal(204);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
let errorThrown;
|
|
49
|
+
try {
|
|
50
|
+
await browser.newPage();
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
errorThrown = e;
|
|
54
|
+
}
|
|
55
|
+
expect(errorThrown.message).contains('closed');
|
|
56
|
+
});
|
|
57
|
+
it('Kill session by trackingId', async () => {
|
|
58
|
+
await start();
|
|
59
|
+
const browser = await webkit.connect(`ws://localhost:3000/webkit/playwright?token=browserless&trackingId=session-1`);
|
|
60
|
+
await fetch('http://localhost:3000/kill/session-1?token=browserless').then(async (res) => {
|
|
61
|
+
expect(res.status).to.equal(204);
|
|
62
|
+
});
|
|
63
|
+
let errorThrown;
|
|
64
|
+
try {
|
|
65
|
+
await browser.newPage();
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
errorThrown = e;
|
|
69
|
+
}
|
|
70
|
+
expect(errorThrown.message).contains('closed');
|
|
71
|
+
});
|
|
72
|
+
});
|
package/build/types.d.ts
CHANGED
|
@@ -520,6 +520,7 @@ export declare const BrowserlessWebKitRoutes: {
|
|
|
520
520
|
export declare const BrowserlessManagementRoutes: {
|
|
521
521
|
ActiveGetRoute: string;
|
|
522
522
|
ConfigGetRoute: string;
|
|
523
|
+
KillGetRoute: string;
|
|
523
524
|
MetaGetRoute: string;
|
|
524
525
|
MetricsGetRoute: string;
|
|
525
526
|
MetricsTotalGetRoute: string;
|
|
@@ -530,6 +531,7 @@ export declare const BrowserlessManagementRoutes: {
|
|
|
530
531
|
export declare const BrowserlessRoutes: {
|
|
531
532
|
ActiveGetRoute: string;
|
|
532
533
|
ConfigGetRoute: string;
|
|
534
|
+
KillGetRoute: string;
|
|
533
535
|
MetaGetRoute: string;
|
|
534
536
|
MetricsGetRoute: string;
|
|
535
537
|
MetricsTotalGetRoute: string;
|
package/build/types.js
CHANGED
|
@@ -190,6 +190,7 @@ export const BrowserlessWebKitRoutes = {
|
|
|
190
190
|
export const BrowserlessManagementRoutes = {
|
|
191
191
|
ActiveGetRoute: 'ActiveGetRoute',
|
|
192
192
|
ConfigGetRoute: 'ConfigGetRoute',
|
|
193
|
+
KillGetRoute: 'KillGetRoute',
|
|
193
194
|
MetaGetRoute: 'MetaGetRoute',
|
|
194
195
|
MetricsGetRoute: 'MetricsGetRoute',
|
|
195
196
|
MetricsTotalGetRoute: 'MetricsTotalGetRoute',
|
package/build/utils.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ export declare class Timeout extends Error {
|
|
|
126
126
|
export declare const bestAttemptCatch: (bestAttempt: boolean) => (err: Error) => void;
|
|
127
127
|
export declare const parseBooleanParam: (params: URLSearchParams, name: string, defaultValue: boolean) => boolean;
|
|
128
128
|
export declare const parseNumberParam: (params: URLSearchParams, name: string, defaultValue: number) => number;
|
|
129
|
-
export declare const parseStringParam: (params: URLSearchParams, name: string, defaultValue: string) =>
|
|
129
|
+
export declare const parseStringParam: (params: URLSearchParams, name: string, defaultValue: string) => string;
|
|
130
130
|
export declare const encrypt: (text: string, secret: Buffer) => string;
|
|
131
131
|
export declare const decrypt: (encryptedText: string, secret: Buffer) => string;
|
|
132
132
|
interface RequestInitTimeout extends RequestInit {
|
package/build/utils.js
CHANGED
|
@@ -538,16 +538,7 @@ export const parseStringParam = (params, name, defaultValue) => {
|
|
|
538
538
|
if (value === null) {
|
|
539
539
|
return defaultValue;
|
|
540
540
|
}
|
|
541
|
-
|
|
542
|
-
if (value === '') {
|
|
543
|
-
return true;
|
|
544
|
-
}
|
|
545
|
-
try {
|
|
546
|
-
return JSON.parse(value);
|
|
547
|
-
}
|
|
548
|
-
catch {
|
|
549
|
-
return value;
|
|
550
|
-
}
|
|
541
|
+
return value;
|
|
551
542
|
};
|
|
552
543
|
export const encrypt = (text, secret) => {
|
|
553
544
|
const iv = crypto.randomBytes(16);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@browserless.io/browserless",
|
|
3
|
-
"version": "2.24.0
|
|
3
|
+
"version": "2.24.0",
|
|
4
4
|
"license": "SSPL",
|
|
5
5
|
"description": "The browserless platform",
|
|
6
6
|
"author": "browserless.io",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"tsconfig.json"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"debug": "^4.
|
|
51
|
+
"debug": "^4.4.0",
|
|
52
52
|
"del": "^8.0.0",
|
|
53
53
|
"enjoi": "^9.0.1",
|
|
54
54
|
"file-type": "^19.6.0",
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
"playwright-1.47": "npm:playwright-core@1.47.2",
|
|
63
63
|
"playwright-1.48": "npm:playwright-core@1.48.2",
|
|
64
64
|
"playwright-core": "^1.49.0",
|
|
65
|
-
"puppeteer-core": "^23.
|
|
65
|
+
"puppeteer-core": "^23.10.1",
|
|
66
66
|
"puppeteer-extra": "^3.3.6",
|
|
67
67
|
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
68
68
|
"queue": "^7.0.0",
|
|
69
|
-
"systeminformation": "^5.23.
|
|
69
|
+
"systeminformation": "^5.23.6",
|
|
70
70
|
"tar-fs": "^3.0.6"
|
|
71
71
|
},
|
|
72
72
|
"optionalDependencies": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"marked": "^15.0.3",
|
|
93
93
|
"mocha": "^11.0.1",
|
|
94
94
|
"move-file": "^3.1.0",
|
|
95
|
-
"prettier": "^3.4.
|
|
95
|
+
"prettier": "^3.4.2",
|
|
96
96
|
"sinon": "^19.0.2",
|
|
97
97
|
"ts-node": "^10.9.2",
|
|
98
98
|
"typescript": "^5.7.2",
|
|
@@ -24,6 +24,7 @@ class BasePlaywright extends EventEmitter {
|
|
|
24
24
|
protected userDataDir: string | null;
|
|
25
25
|
protected running = false;
|
|
26
26
|
protected logger: Logger;
|
|
27
|
+
protected socket: Duplex | null = null;
|
|
27
28
|
protected proxy = httpProxy.createProxyServer();
|
|
28
29
|
protected browser: playwright.BrowserServer | null = null;
|
|
29
30
|
protected browserWSEndpoint: string | null = null;
|
|
@@ -78,6 +79,7 @@ class BasePlaywright extends EventEmitter {
|
|
|
78
79
|
this.logger.info(
|
|
79
80
|
`Closing ${this.constructor.name} process and all listeners`,
|
|
80
81
|
);
|
|
82
|
+
this.socket?.destroy();
|
|
81
83
|
this.emit('close');
|
|
82
84
|
this.cleanListeners();
|
|
83
85
|
this.browser.close();
|
|
@@ -167,6 +169,7 @@ class BasePlaywright extends EventEmitter {
|
|
|
167
169
|
socket: Duplex,
|
|
168
170
|
head: Buffer,
|
|
169
171
|
): Promise<void> {
|
|
172
|
+
this.socket = socket;
|
|
170
173
|
return new Promise((resolve, reject) => {
|
|
171
174
|
if (!this.browserWSEndpoint) {
|
|
172
175
|
throw new ServerError(
|
package/src/browsers/index.ts
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
Config,
|
|
17
17
|
FileSystem,
|
|
18
18
|
FirefoxPlaywright,
|
|
19
|
-
HTTPManagementRoutes,
|
|
20
19
|
Hooks,
|
|
21
20
|
Logger,
|
|
22
21
|
NotFound,
|
|
@@ -35,6 +34,7 @@ import {
|
|
|
35
34
|
} from '@browserless.io/browserless';
|
|
36
35
|
import { Page } from 'puppeteer-core';
|
|
37
36
|
import { deleteAsync } from 'del';
|
|
37
|
+
import micromatch from 'micromatch';
|
|
38
38
|
import path from 'path';
|
|
39
39
|
|
|
40
40
|
export class BrowserManager {
|
|
@@ -236,11 +236,7 @@ export class BrowserManager {
|
|
|
236
236
|
initialConnectURL: new URL(session.initialConnectURL, serverAddress)
|
|
237
237
|
.href,
|
|
238
238
|
killURL: session.id
|
|
239
|
-
? makeExternalURL(
|
|
240
|
-
serverAddress,
|
|
241
|
-
HTTPManagementRoutes.sessions,
|
|
242
|
-
session.id,
|
|
243
|
-
)
|
|
239
|
+
? makeExternalURL(serverAddress, '/kill/', session.id)
|
|
244
240
|
: null,
|
|
245
241
|
running: browser.isRunning(),
|
|
246
242
|
timeAliveMs: Date.now() - session.startedOn,
|
|
@@ -277,12 +273,13 @@ export class BrowserManager {
|
|
|
277
273
|
public async close(
|
|
278
274
|
browser: BrowserInstance,
|
|
279
275
|
session: BrowserlessSession,
|
|
276
|
+
force = false,
|
|
280
277
|
): Promise<void> {
|
|
281
278
|
const now = Date.now();
|
|
282
279
|
const keepUntil = browser.keepUntil();
|
|
283
280
|
const connected = session.numbConnected;
|
|
284
281
|
const hasKeepUntil = keepUntil > now;
|
|
285
|
-
const keepOpen = connected > 0 || hasKeepUntil;
|
|
282
|
+
const keepOpen = (connected > 0 || hasKeepUntil) && !force;
|
|
286
283
|
const cleanupACtions: Array<() => Promise<void>> = [];
|
|
287
284
|
const priorTimer = this.timers.get(session.id);
|
|
288
285
|
|
|
@@ -292,10 +289,10 @@ export class BrowserManager {
|
|
|
292
289
|
}
|
|
293
290
|
|
|
294
291
|
this.log.info(
|
|
295
|
-
`${session.numbConnected} Client(s) are currently connected, Keep-until: ${keepUntil}`,
|
|
292
|
+
`${session.numbConnected} Client(s) are currently connected, Keep-until: ${keepUntil}, force: ${force}`,
|
|
296
293
|
);
|
|
297
294
|
|
|
298
|
-
if (hasKeepUntil) {
|
|
295
|
+
if (!force && hasKeepUntil) {
|
|
299
296
|
const timeout = keepUntil - now;
|
|
300
297
|
this.log.trace(
|
|
301
298
|
`Setting timer ${timeout.toLocaleString()} for "${session.id}"`,
|
|
@@ -328,6 +325,28 @@ export class BrowserManager {
|
|
|
328
325
|
}
|
|
329
326
|
}
|
|
330
327
|
|
|
328
|
+
public async killSessions(target: string): Promise<void> {
|
|
329
|
+
this.log.info(`killSessions invoked target: "${target}"`);
|
|
330
|
+
const sessions = Array.from(this.browsers);
|
|
331
|
+
let closed = 0;
|
|
332
|
+
for (const [browser, session] of sessions) {
|
|
333
|
+
if (
|
|
334
|
+
session.trackingId === target ||
|
|
335
|
+
session.id === target ||
|
|
336
|
+
target === 'all'
|
|
337
|
+
) {
|
|
338
|
+
this.log.info(
|
|
339
|
+
`Closing browser via killSessions BrowserId: "${session.id}", trackingId: "${session.trackingId}"`,
|
|
340
|
+
);
|
|
341
|
+
this.close(browser, session, true);
|
|
342
|
+
closed++;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (closed === 0 && target !== 'all') {
|
|
346
|
+
throw new NotFound(`Couldn't locate session for id: "${target}"`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
331
350
|
public async getAllSessions(
|
|
332
351
|
trackingId?: string,
|
|
333
352
|
): Promise<BrowserlessSessionJSON[]> {
|
|
@@ -398,12 +417,14 @@ export class BrowserManager {
|
|
|
398
417
|
);
|
|
399
418
|
}
|
|
400
419
|
|
|
401
|
-
if (
|
|
402
|
-
['/', '.', '\\'].some((routeLike) => trackingId.includes(routeLike))
|
|
403
|
-
) {
|
|
420
|
+
if (!micromatch.isMatch(trackingId, '+([0-9a-zA-Z-_])')) {
|
|
404
421
|
throw new BadRequest(`trackingId contains invalid characters`);
|
|
405
422
|
}
|
|
406
423
|
|
|
424
|
+
if (trackingId === 'all') {
|
|
425
|
+
throw new BadRequest(`trackingId cannot be the reserved word "all"`);
|
|
426
|
+
}
|
|
427
|
+
|
|
407
428
|
this.log.info(`Assigning session trackingId "${trackingId}"`);
|
|
408
429
|
}
|
|
409
430
|
|
package/src/http.ts
CHANGED
|
@@ -126,6 +126,7 @@ export enum HTTPRoutes {
|
|
|
126
126
|
export enum HTTPManagementRoutes {
|
|
127
127
|
active = '/active?(/)',
|
|
128
128
|
config = '/config?(/)',
|
|
129
|
+
kill = '/kill/+([0-9a-zA-Z-_])?(/)',
|
|
129
130
|
meta = '/meta?(/)',
|
|
130
131
|
metrics = '/metrics?(/)',
|
|
131
132
|
metricsTotal = '/metrics/total?(/)',
|
|
@@ -174,4 +175,9 @@ export interface SystemQueryParameters {
|
|
|
174
175
|
* The authorization token
|
|
175
176
|
*/
|
|
176
177
|
token?: string;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Custom session identifier
|
|
181
|
+
*/
|
|
182
|
+
trackingId?: string;
|
|
177
183
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Browserless, Config, Metrics } from '@browserless.io/browserless';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import puppeteer from 'puppeteer-core';
|
|
4
|
+
|
|
5
|
+
describe('/kill API', function () {
|
|
6
|
+
let browserless: Browserless;
|
|
7
|
+
|
|
8
|
+
const start = ({
|
|
9
|
+
config = new Config(),
|
|
10
|
+
metrics = new Metrics(),
|
|
11
|
+
}: { config?: Config; metrics?: Metrics } = {}) => {
|
|
12
|
+
config.setToken('6R0W53R135510');
|
|
13
|
+
browserless = new Browserless({ config, metrics });
|
|
14
|
+
return browserless.start();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await browserless.stop();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('Kill all sessions', async () => {
|
|
22
|
+
await start();
|
|
23
|
+
const browser1 = await puppeteer.connect({
|
|
24
|
+
browserWSEndpoint: `ws://localhost:3000/chrome?token=6R0W53R135510`,
|
|
25
|
+
});
|
|
26
|
+
const browser2 = await puppeteer.connect({
|
|
27
|
+
browserWSEndpoint: `ws://localhost:3000/chrome?token=6R0W53R135510`,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await fetch('http://localhost:3000/kill/all?token=6R0W53R135510').then(
|
|
31
|
+
async (res) => {
|
|
32
|
+
expect(res.status).to.equal(204);
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
let errorThrown1;
|
|
37
|
+
try {
|
|
38
|
+
await browser1.newPage();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
errorThrown1 = e;
|
|
41
|
+
}
|
|
42
|
+
let errorThrown2;
|
|
43
|
+
try {
|
|
44
|
+
await browser2.newPage();
|
|
45
|
+
} catch (e) {
|
|
46
|
+
errorThrown2 = e;
|
|
47
|
+
}
|
|
48
|
+
expect((errorThrown1 as Error).message).contains('closed');
|
|
49
|
+
expect((errorThrown2 as Error).message).contains('closed');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Kill session by browserId', async () => {
|
|
53
|
+
await start();
|
|
54
|
+
const browser = await puppeteer.connect({
|
|
55
|
+
browserWSEndpoint: `ws://localhost:3000/chrome?token=6R0W53R135510`,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await fetch('http://localhost:3000/sessions?token=6R0W53R135510').then(
|
|
59
|
+
async (res) => {
|
|
60
|
+
const sessions = await res.json();
|
|
61
|
+
const browserId = sessions[0].browserId;
|
|
62
|
+
await fetch(
|
|
63
|
+
`http://localhost:3000/kill/${browserId}?token=6R0W53R135510`,
|
|
64
|
+
).then(async (res) => {
|
|
65
|
+
expect(res.status).to.equal(204);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
let errorThrown;
|
|
71
|
+
try {
|
|
72
|
+
await browser.newPage();
|
|
73
|
+
} catch (e) {
|
|
74
|
+
errorThrown = e;
|
|
75
|
+
}
|
|
76
|
+
expect((errorThrown as Error).message).contains('closed');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('Kill session by trackingId', async () => {
|
|
80
|
+
await start();
|
|
81
|
+
const browser = await puppeteer.connect({
|
|
82
|
+
browserWSEndpoint: `ws://localhost:3000/chrome?token=6R0W53R135510&trackingId=session-1`,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await fetch(
|
|
86
|
+
'http://localhost:3000/kill/session-1?token=6R0W53R135510',
|
|
87
|
+
).then(async (res) => {
|
|
88
|
+
expect(res.status).to.equal(204);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
let errorThrown;
|
|
92
|
+
try {
|
|
93
|
+
await browser.newPage();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
errorThrown = e;
|
|
96
|
+
}
|
|
97
|
+
expect((errorThrown as Error).message).contains('closed');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Browserless, Config, Metrics } from '@browserless.io/browserless';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import puppeteer from 'puppeteer-core';
|
|
4
|
+
|
|
5
|
+
describe('/kill API', function () {
|
|
6
|
+
let browserless: Browserless;
|
|
7
|
+
|
|
8
|
+
const start = ({
|
|
9
|
+
config = new Config(),
|
|
10
|
+
metrics = new Metrics(),
|
|
11
|
+
}: { config?: Config; metrics?: Metrics } = {}) => {
|
|
12
|
+
config.setToken('6R0W53R135510');
|
|
13
|
+
browserless = new Browserless({ config, metrics });
|
|
14
|
+
return browserless.start();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await browserless.stop();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('Kill all sessions', async () => {
|
|
22
|
+
await start();
|
|
23
|
+
const browser1 = await puppeteer.connect({
|
|
24
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?token=6R0W53R135510`,
|
|
25
|
+
});
|
|
26
|
+
const browser2 = await puppeteer.connect({
|
|
27
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?token=6R0W53R135510`,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await fetch('http://localhost:3000/kill/all?token=6R0W53R135510').then(
|
|
31
|
+
async (res) => {
|
|
32
|
+
expect(res.status).to.equal(204);
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
let errorThrown1;
|
|
37
|
+
try {
|
|
38
|
+
await browser1.newPage();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
errorThrown1 = e;
|
|
41
|
+
}
|
|
42
|
+
let errorThrown2;
|
|
43
|
+
try {
|
|
44
|
+
await browser2.newPage();
|
|
45
|
+
} catch (e) {
|
|
46
|
+
errorThrown2 = e;
|
|
47
|
+
}
|
|
48
|
+
expect((errorThrown1 as Error).message).contains('closed');
|
|
49
|
+
expect((errorThrown2 as Error).message).contains('closed');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Kill session by browserId', async () => {
|
|
53
|
+
await start();
|
|
54
|
+
const browser = await puppeteer.connect({
|
|
55
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?token=6R0W53R135510`,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await fetch('http://localhost:3000/sessions?token=6R0W53R135510').then(
|
|
59
|
+
async (res) => {
|
|
60
|
+
const sessions = await res.json();
|
|
61
|
+
const browserId = sessions[0].browserId;
|
|
62
|
+
await fetch(
|
|
63
|
+
`http://localhost:3000/kill/${browserId}?token=6R0W53R135510`,
|
|
64
|
+
).then(async (res) => {
|
|
65
|
+
expect(res.status).to.equal(204);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
let errorThrown;
|
|
71
|
+
try {
|
|
72
|
+
await browser.newPage();
|
|
73
|
+
} catch (e) {
|
|
74
|
+
errorThrown = e;
|
|
75
|
+
}
|
|
76
|
+
expect((errorThrown as Error).message).contains('closed');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('Kill session by trackingId', async () => {
|
|
80
|
+
await start();
|
|
81
|
+
const browser = await puppeteer.connect({
|
|
82
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?token=6R0W53R135510&trackingId=session-1`,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
await fetch(
|
|
86
|
+
'http://localhost:3000/kill/session-1?token=6R0W53R135510',
|
|
87
|
+
).then(async (res) => {
|
|
88
|
+
expect(res.status).to.equal(204);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
let errorThrown;
|
|
92
|
+
try {
|
|
93
|
+
await browser.newPage();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
errorThrown = e;
|
|
96
|
+
}
|
|
97
|
+
expect((errorThrown as Error).message).contains('closed');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -513,4 +513,33 @@ describe('Chromium WebSocket API', function () {
|
|
|
513
513
|
|
|
514
514
|
await browser.disconnect();
|
|
515
515
|
});
|
|
516
|
+
|
|
517
|
+
it('Throws an error while creating a session with invalid trackingId', async () => {
|
|
518
|
+
await start();
|
|
519
|
+
|
|
520
|
+
const didError = await puppeteer
|
|
521
|
+
.connect({
|
|
522
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?trackingId=all`,
|
|
523
|
+
})
|
|
524
|
+
.then(() => false)
|
|
525
|
+
.catch(() => true);
|
|
526
|
+
|
|
527
|
+
expect(didError).to.be.true;
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it('Throws an error while creating a session with duplicated trackingId', async () => {
|
|
531
|
+
await start();
|
|
532
|
+
|
|
533
|
+
await puppeteer.connect({
|
|
534
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?trackingId=duplicated`,
|
|
535
|
+
});
|
|
536
|
+
const didError = await puppeteer
|
|
537
|
+
.connect({
|
|
538
|
+
browserWSEndpoint: `ws://localhost:3000/chromium?trackingId=duplicated`,
|
|
539
|
+
})
|
|
540
|
+
.then(() => false)
|
|
541
|
+
.catch(() => true);
|
|
542
|
+
|
|
543
|
+
expect(didError).to.be.true;
|
|
544
|
+
});
|
|
516
545
|
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Browserless, Config, Metrics } from '@browserless.io/browserless';
|
|
2
|
+
import { expect } from 'chai';
|
|
3
|
+
import { firefox } from 'playwright-core';
|
|
4
|
+
|
|
5
|
+
describe('/kill API firefox', function () {
|
|
6
|
+
let browserless: Browserless;
|
|
7
|
+
|
|
8
|
+
const start = ({
|
|
9
|
+
config = new Config(),
|
|
10
|
+
metrics = new Metrics(),
|
|
11
|
+
}: { config?: Config; metrics?: Metrics } = {}) => {
|
|
12
|
+
config.setToken('browserless');
|
|
13
|
+
browserless = new Browserless({ config, metrics });
|
|
14
|
+
return browserless.start();
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
afterEach(async () => {
|
|
18
|
+
await browserless.stop();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('Kill all sessions', async () => {
|
|
22
|
+
await start();
|
|
23
|
+
const browser1 = await firefox.connect(
|
|
24
|
+
`ws://localhost:3000/playwright/firefox?token=browserless`,
|
|
25
|
+
);
|
|
26
|
+
const browser2 = await firefox.connect(
|
|
27
|
+
`ws://localhost:3000/playwright/firefox?token=browserless`,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
await fetch('http://localhost:3000/kill/all?token=browserless').then(
|
|
31
|
+
async (res) => {
|
|
32
|
+
expect(res.status).to.equal(204);
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
let errorThrown1;
|
|
37
|
+
try {
|
|
38
|
+
await browser1.newPage();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
errorThrown1 = e;
|
|
41
|
+
}
|
|
42
|
+
let errorThrown2;
|
|
43
|
+
try {
|
|
44
|
+
await browser2.newPage();
|
|
45
|
+
} catch (e) {
|
|
46
|
+
errorThrown2 = e;
|
|
47
|
+
}
|
|
48
|
+
expect((errorThrown1 as Error).message).contains('closed');
|
|
49
|
+
expect((errorThrown2 as Error).message).contains('closed');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('Kill session by browserId', async () => {
|
|
53
|
+
await start();
|
|
54
|
+
const browser = await firefox.connect(
|
|
55
|
+
`ws://localhost:3000/playwright/firefox?token=browserless`,
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
await fetch('http://localhost:3000/sessions?token=browserless').then(
|
|
59
|
+
async (res) => {
|
|
60
|
+
const sessions = await res.json();
|
|
61
|
+
const browserId = sessions[0].browserId;
|
|
62
|
+
await fetch(
|
|
63
|
+
`http://localhost:3000/kill/${browserId}?token=browserless`,
|
|
64
|
+
).then(async (res) => {
|
|
65
|
+
expect(res.status).to.equal(204);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
let errorThrown;
|
|
71
|
+
try {
|
|
72
|
+
await browser.newPage();
|
|
73
|
+
} catch (e) {
|
|
74
|
+
errorThrown = e;
|
|
75
|
+
}
|
|
76
|
+
expect((errorThrown as Error).message).contains('closed');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('Kill session by trackingId', async () => {
|
|
80
|
+
await start();
|
|
81
|
+
const browser = await firefox.connect(
|
|
82
|
+
`ws://localhost:3000/playwright/firefox?token=browserless&trackingId=session-1`,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
await fetch('http://localhost:3000/kill/session-1?token=browserless').then(
|
|
86
|
+
async (res) => {
|
|
87
|
+
expect(res.status).to.equal(204);
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
let errorThrown;
|
|
92
|
+
try {
|
|
93
|
+
await browser.newPage();
|
|
94
|
+
} catch (e) {
|
|
95
|
+
errorThrown = e;
|
|
96
|
+
}
|
|
97
|
+
expect((errorThrown as Error).message).contains('closed');
|
|
98
|
+
});
|
|
99
|
+
});
|