mirror of
https://github.com/microsoft/playwright.git
synced 2025-01-05 19:04:43 +03:00
chore: support await using for close() and dispose() (#27766)
This change assumes that the user has Node 18 with Symbol.dispose available. Fixes https://github.com/microsoft/playwright/issues/27141
This commit is contained in:
parent
c8134bca5d
commit
7de0ccd36e
@ -65,6 +65,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher {
|
||||
browserServer.process = () => browser.options.browserProcess.process!;
|
||||
browserServer.wsEndpoint = () => wsEndpoint;
|
||||
browserServer.close = () => browser.options.browserProcess.close();
|
||||
browserServer[Symbol.asyncDispose] = browserServer.close;
|
||||
browserServer.kill = () => browser.options.browserProcess.kill();
|
||||
(browserServer as any)._disconnectForTest = () => server.close();
|
||||
(browserServer as any)._userDataDirForTest = (browser as any)._userDataDirForTest;
|
||||
|
@ -234,6 +234,10 @@ export class AndroidDevice extends ChannelOwner<channels.AndroidDeviceChannel> i
|
||||
return binary;
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async close() {
|
||||
try {
|
||||
if (this._shouldCloseConnectionOnClose)
|
||||
@ -307,6 +311,10 @@ export class AndroidSocket extends ChannelOwner<channels.AndroidSocketChannel> i
|
||||
async close(): Promise<void> {
|
||||
await this._channel.close();
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFile(file: string | Buffer): Promise<Buffer> {
|
||||
|
@ -131,6 +131,10 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
||||
return buffer;
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async close(options: { reason?: string } = {}): Promise<void> {
|
||||
this._closeReason = options.reason;
|
||||
try {
|
||||
|
@ -387,6 +387,10 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
||||
this.emit(Events.BrowserContext.Close, this);
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async close(options: { reason?: string } = {}): Promise<void> {
|
||||
if (this._closeWasCalled)
|
||||
return;
|
||||
|
@ -108,6 +108,10 @@ export class ElectronApplication extends ChannelOwner<channels.ElectronApplicati
|
||||
return this._context;
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this._isClosed)
|
||||
return;
|
||||
|
@ -95,6 +95,10 @@ export class APIRequestContext extends ChannelOwner<channels.APIRequestContextCh
|
||||
this._tracing = Tracing.from(initializer.tracing);
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
await this._instrumentation.onWillCloseRequestContext(this);
|
||||
await this._channel.dispose();
|
||||
@ -302,6 +306,10 @@ export class APIResponse implements api.APIResponse {
|
||||
return JSON.parse(content);
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
|
||||
async dispose(): Promise<void> {
|
||||
await this._request._channel.disposeAPIResponse({ fetchUid: this._fetchUid() });
|
||||
}
|
||||
|
@ -93,6 +93,10 @@ export class HarRouter {
|
||||
page.once(Events.Page.Close, () => this.dispose());
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._localUtils._channel.harClose({ harId: this._harId }).catch(() => {});
|
||||
}
|
||||
|
@ -63,6 +63,10 @@ export class JSHandle<T = any> extends ChannelOwner<channels.JSHandleChannel> im
|
||||
return null as any;
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.dispose();
|
||||
}
|
||||
|
||||
async dispose() {
|
||||
return await this._channel.dispose();
|
||||
}
|
||||
|
@ -517,6 +517,10 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
||||
await this._channel.bringToFront();
|
||||
}
|
||||
|
||||
async [Symbol.asyncDispose]() {
|
||||
await this.close();
|
||||
}
|
||||
|
||||
async close(options: { runBeforeUnload?: boolean, reason?: string } = {}) {
|
||||
this._closeReason = options.reason;
|
||||
try {
|
||||
|
98
packages/playwright-core/types/types.d.ts
vendored
98
packages/playwright-core/types/types.d.ts
vendored
@ -4707,6 +4707,8 @@ export interface Page {
|
||||
request: APIRequestContext;
|
||||
|
||||
touchscreen: Touchscreen;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7632,12 +7634,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
on(event: 'page', listener: (page: Page) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
on(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To
|
||||
* only listen for requests from a particular page, use
|
||||
@ -7683,6 +7679,12 @@ export interface BrowserContext {
|
||||
*/
|
||||
on(event: 'serviceworker', listener: (worker: Worker) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
on(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event.
|
||||
*/
|
||||
@ -7708,11 +7710,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
once(event: 'page', listener: (page: Page) => void): this;
|
||||
|
||||
/**
|
||||
* Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event.
|
||||
*/
|
||||
once(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event.
|
||||
*/
|
||||
@ -7738,6 +7735,11 @@ export interface BrowserContext {
|
||||
*/
|
||||
once(event: 'serviceworker', listener: (worker: Worker) => void): this;
|
||||
|
||||
/**
|
||||
* Adds an event listener that will be automatically removed after it is triggered once. See `addListener` for more information about this event.
|
||||
*/
|
||||
once(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* **NOTE** Only works with Chromium browser's persistent context.
|
||||
*
|
||||
@ -7824,12 +7826,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
addListener(event: 'page', listener: (page: Page) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
addListener(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To
|
||||
* only listen for requests from a particular page, use
|
||||
@ -7875,6 +7871,12 @@ export interface BrowserContext {
|
||||
*/
|
||||
addListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
addListener(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
@ -7900,11 +7902,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
removeListener(event: 'page', listener: (page: Page) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
removeListener(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
@ -7930,6 +7927,11 @@ export interface BrowserContext {
|
||||
*/
|
||||
removeListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
removeListener(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
@ -7955,11 +7957,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
off(event: 'page', listener: (page: Page) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
off(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
@ -7985,6 +7982,11 @@ export interface BrowserContext {
|
||||
*/
|
||||
off(event: 'serviceworker', listener: (worker: Worker) => void): this;
|
||||
|
||||
/**
|
||||
* Removes an event listener added by `on` or `addListener`.
|
||||
*/
|
||||
off(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* **NOTE** Only works with Chromium browser's persistent context.
|
||||
*
|
||||
@ -8071,12 +8073,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
prependListener(event: 'page', listener: (page: Page) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
prependListener(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To
|
||||
* only listen for requests from a particular page, use
|
||||
@ -8122,6 +8118,12 @@ export interface BrowserContext {
|
||||
*/
|
||||
prependListener(event: 'serviceworker', listener: (worker: Worker) => void): this;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
prependListener(event: 'weberror', listener: (webError: WebError) => void): this;
|
||||
|
||||
/**
|
||||
* Adds cookies into this browser context. All pages within this context will have these cookies installed. Cookies
|
||||
* can be obtained via
|
||||
@ -8670,12 +8672,6 @@ export interface BrowserContext {
|
||||
*/
|
||||
waitForEvent(event: 'page', optionsOrPredicate?: { predicate?: (page: Page) => boolean | Promise<boolean>, timeout?: number } | ((page: Page) => boolean | Promise<boolean>)): Promise<Page>;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
waitForEvent(event: 'weberror', optionsOrPredicate?: { predicate?: (webError: WebError) => boolean | Promise<boolean>, timeout?: number } | ((webError: WebError) => boolean | Promise<boolean>)): Promise<WebError>;
|
||||
|
||||
/**
|
||||
* Emitted when a request is issued from any pages created through this context. The [request] object is read-only. To
|
||||
* only listen for requests from a particular page, use
|
||||
@ -8721,6 +8717,12 @@ export interface BrowserContext {
|
||||
*/
|
||||
waitForEvent(event: 'serviceworker', optionsOrPredicate?: { predicate?: (worker: Worker) => boolean | Promise<boolean>, timeout?: number } | ((worker: Worker) => boolean | Promise<boolean>)): Promise<Worker>;
|
||||
|
||||
/**
|
||||
* Emitted when exception is unhandled in any of the pages in this context. To listen for errors from a particular
|
||||
* page, use [page.on('pageerror')](https://playwright.dev/docs/api/class-page#page-event-page-error) instead.
|
||||
*/
|
||||
waitForEvent(event: 'weberror', optionsOrPredicate?: { predicate?: (webError: WebError) => boolean | Promise<boolean>, timeout?: number } | ((webError: WebError) => boolean | Promise<boolean>)): Promise<WebError>;
|
||||
|
||||
|
||||
/**
|
||||
* API testing helper associated with this context. Requests made with this API will use context cookies.
|
||||
@ -8728,6 +8730,8 @@ export interface BrowserContext {
|
||||
request: APIRequestContext;
|
||||
|
||||
tracing: Tracing;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -8992,6 +8996,8 @@ export interface JSHandle<T = any> {
|
||||
* @param propertyName property to get
|
||||
*/
|
||||
getProperty(propertyName: string): Promise<JSHandle>;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -13747,6 +13753,8 @@ export interface ElectronApplication {
|
||||
* Convenience method that returns all the opened windows.
|
||||
*/
|
||||
windows(): Array<Page>;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
export type AndroidElementInfo = {
|
||||
@ -14806,6 +14814,8 @@ export interface AndroidDevice {
|
||||
webViews(): Array<AndroidWebView>;
|
||||
|
||||
input: AndroidInput;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
export interface AndroidInput {
|
||||
@ -14941,6 +14951,8 @@ export interface AndroidSocket {
|
||||
* @param data Data to write.
|
||||
*/
|
||||
write(data: Buffer): Promise<void>;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15880,6 +15892,8 @@ export interface APIRequestContext {
|
||||
}>;
|
||||
}>;
|
||||
}>;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15950,6 +15964,8 @@ export interface APIResponse {
|
||||
* Contains the URL of the response.
|
||||
*/
|
||||
url(): string;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -16545,6 +16561,8 @@ export interface Browser extends EventEmitter {
|
||||
* Returns the browser version.
|
||||
*/
|
||||
version(): string;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
export interface BrowserServer {
|
||||
@ -16601,6 +16619,8 @@ export interface BrowserServer {
|
||||
* to establish connection to the browser.
|
||||
*/
|
||||
wsEndpoint(): string;
|
||||
|
||||
[Symbol.asyncDispose](): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,10 +34,12 @@ This project incorporates components from the projects listed below. The origina
|
||||
- @babel/highlight@7.22.5 (https://github.com/babel/babel)
|
||||
- @babel/parser@7.23.0 (https://github.com/babel/babel)
|
||||
- @babel/plugin-proposal-decorators@7.23.2 (https://github.com/babel/babel)
|
||||
- @babel/plugin-proposal-explicit-resource-management@7.23.0 (https://github.com/babel/babel)
|
||||
- @babel/plugin-syntax-async-generators@7.8.4 (https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-async-generators)
|
||||
- @babel/plugin-syntax-class-static-block@7.14.5 (https://github.com/babel/babel)
|
||||
- @babel/plugin-syntax-decorators@7.22.10 (https://github.com/babel/babel)
|
||||
- @babel/plugin-syntax-dynamic-import@7.8.3 (https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-dynamic-import)
|
||||
- @babel/plugin-syntax-explicit-resource-management@7.22.5 (https://github.com/babel/babel)
|
||||
- @babel/plugin-syntax-export-namespace-from@7.8.3 (https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-export-namespace-from)
|
||||
- @babel/plugin-syntax-import-assertions@7.22.5 (https://github.com/babel/babel)
|
||||
- @babel/plugin-syntax-json-strings@7.8.3 (https://github.com/babel/babel/tree/master/packages/babel-plugin-syntax-json-strings)
|
||||
@ -1140,6 +1142,33 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
=========================================
|
||||
END OF @babel/plugin-proposal-decorators@7.23.2 AND INFORMATION
|
||||
|
||||
%% @babel/plugin-proposal-explicit-resource-management@7.23.0 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
=========================================
|
||||
END OF @babel/plugin-proposal-explicit-resource-management@7.23.0 AND INFORMATION
|
||||
|
||||
%% @babel/plugin-syntax-async-generators@7.8.4 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
@ -1248,6 +1277,33 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
=========================================
|
||||
END OF @babel/plugin-syntax-dynamic-import@7.8.3 AND INFORMATION
|
||||
|
||||
%% @babel/plugin-syntax-explicit-resource-management@7.22.5 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
=========================================
|
||||
END OF @babel/plugin-syntax-explicit-resource-management@7.22.5 AND INFORMATION
|
||||
|
||||
%% @babel/plugin-syntax-export-namespace-from@7.8.3 NOTICES AND INFORMATION BEGIN HERE
|
||||
=========================================
|
||||
MIT License
|
||||
@ -4351,6 +4407,6 @@ END OF yallist@3.1.1 AND INFORMATION
|
||||
|
||||
SUMMARY BEGIN HERE
|
||||
=========================================
|
||||
Total Packages: 149
|
||||
Total Packages: 151
|
||||
=========================================
|
||||
END OF SUMMARY
|
47
packages/playwright/bundles/babel/package-lock.json
generated
47
packages/playwright/bundles/babel/package-lock.json
generated
@ -13,6 +13,7 @@
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.23.2",
|
||||
"@babel/plugin-proposal-explicit-resource-management": "^7.23.0",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.22.5",
|
||||
"@babel/plugin-syntax-json-strings": "^7.8.3",
|
||||
@ -380,6 +381,21 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-proposal-explicit-resource-management": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-explicit-resource-management/-/plugin-proposal-explicit-resource-management-7.23.0.tgz",
|
||||
"integrity": "sha512-wu5/1COnSuGj78UBhTpxmESzV/xEcWIjkM54PZ8mhmwHrDBriro0o8LAkbbTXDAsQjwlqkqvIyXzOSykHrDiSg==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-explicit-resource-management": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-async-generators": {
|
||||
"version": "7.8.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
|
||||
@ -430,6 +446,20 @@
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-explicit-resource-management": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-explicit-resource-management/-/plugin-syntax-explicit-resource-management-7.22.5.tgz",
|
||||
"integrity": "sha512-vokH/rTR4m9hlcxXXL0CPnpoGHUbZ6gfI3kq/UZSwrF9qGo/LxWqEP0qWYqkt5kc6/jrCOTaBeYw+lYleEFtLA==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-syntax-export-namespace-from": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
|
||||
@ -1449,6 +1479,15 @@
|
||||
"@babel/plugin-syntax-decorators": "^7.22.10"
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-explicit-resource-management": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-explicit-resource-management/-/plugin-proposal-explicit-resource-management-7.23.0.tgz",
|
||||
"integrity": "sha512-wu5/1COnSuGj78UBhTpxmESzV/xEcWIjkM54PZ8mhmwHrDBriro0o8LAkbbTXDAsQjwlqkqvIyXzOSykHrDiSg==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/plugin-syntax-explicit-resource-management": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/plugin-syntax-async-generators": {
|
||||
"version": "7.8.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
|
||||
@ -1481,6 +1520,14 @@
|
||||
"@babel/helper-plugin-utils": "^7.8.0"
|
||||
}
|
||||
},
|
||||
"@babel/plugin-syntax-explicit-resource-management": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-explicit-resource-management/-/plugin-syntax-explicit-resource-management-7.22.5.tgz",
|
||||
"integrity": "sha512-vokH/rTR4m9hlcxXXL0CPnpoGHUbZ6gfI3kq/UZSwrF9qGo/LxWqEP0qWYqkt5kc6/jrCOTaBeYw+lYleEFtLA==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/plugin-syntax-export-namespace-from": {
|
||||
"version": "7.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
|
||||
|
@ -14,6 +14,7 @@
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.23.2",
|
||||
"@babel/plugin-proposal-explicit-resource-management": "^7.23.0",
|
||||
"@babel/plugin-syntax-async-generators": "^7.8.4",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.22.5",
|
||||
"@babel/plugin-syntax-json-strings": "^7.8.3",
|
||||
|
@ -33,6 +33,7 @@ function babelTransformOptions(isTypeScript: boolean, isModule: boolean, plugins
|
||||
if (isTypeScript) {
|
||||
plugins.push(
|
||||
[require('@babel/plugin-proposal-decorators'), { version: '2023-05' }],
|
||||
[require('@babel/plugin-proposal-explicit-resource-management')],
|
||||
[require('@babel/plugin-transform-class-properties')],
|
||||
[require('@babel/plugin-transform-class-static-block')],
|
||||
[require('@babel/plugin-transform-numeric-separator')],
|
||||
|
@ -68,6 +68,9 @@ let success = true;
|
||||
for (const method of api) {
|
||||
if (coveredMethods.has(method))
|
||||
continue;
|
||||
// [Symbol.asyncDispose]
|
||||
if (method.endsWith('.undefined'))
|
||||
continue;
|
||||
success = false;
|
||||
console.log(`ERROR: Missing coverage for "${method}"`)
|
||||
}
|
||||
|
@ -198,7 +198,7 @@ export const test = _test
|
||||
});
|
||||
},
|
||||
tsc: async ({ exec }, use) => {
|
||||
await exec('npm i typescript@5.2.2 @types/node@16');
|
||||
await exec('npm i typescript@5.2.2 @types/node@18');
|
||||
await use((args: string) => exec('npx', 'tsc', args, { shell: process.platform === 'win32' }));
|
||||
},
|
||||
});
|
||||
|
@ -42,7 +42,7 @@ test('npm: @playwright/test plugin should work', async ({ exec, tmpWorkspace })
|
||||
expect(output).toContain('plugin value: hello from plugin');
|
||||
expect(output).toContain('1 passed');
|
||||
|
||||
await exec('npm i typescript@5.2.2 @types/node@16');
|
||||
await exec('npm i typescript@5.2.2 @types/node@18');
|
||||
await exec('npx tsc playwright-test-plugin-types.ts');
|
||||
});
|
||||
|
||||
@ -56,7 +56,7 @@ test('pnpm: @playwright/test plugin should work', async ({ exec, tmpWorkspace })
|
||||
expect(output).toContain('plugin value: hello from plugin');
|
||||
expect(output).toContain('1 passed');
|
||||
|
||||
await exec('pnpm add typescript@5.2.2 @types/node@16');
|
||||
await exec('pnpm add typescript@5.2.2 @types/node@18');
|
||||
await exec('pnpm exec tsc playwright-test-plugin-types.ts');
|
||||
});
|
||||
|
||||
@ -70,6 +70,6 @@ test('yarn: @playwright/test plugin should work', async ({ exec, tmpWorkspace })
|
||||
expect(output).toContain('plugin value: hello from plugin');
|
||||
expect(output).toContain('1 passed');
|
||||
|
||||
await exec('yarn add typescript@5.2.2 @types/node@16');
|
||||
await exec('yarn add typescript@5.2.2 @types/node@18');
|
||||
await exec('yarn tsc playwright-test-plugin-types.ts');
|
||||
});
|
||||
|
@ -16,62 +16,64 @@
|
||||
*/
|
||||
|
||||
import { playwrightTest as it, expect } from '../config/browserTest';
|
||||
import type { Browser, BrowserContext, Page } from '@playwright/test';
|
||||
import { kTargetClosedErrorMessage } from '../config/errors';
|
||||
|
||||
it('should reject all promises when browser is closed', async ({ browserType }) => {
|
||||
const browser = await browserType.launch();
|
||||
const page = await (await browser.newContext()).newPage();
|
||||
let error = null;
|
||||
let error: Error | undefined;
|
||||
const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e);
|
||||
await page.evaluate(() => new Promise(f => setTimeout(f, 0)));
|
||||
await browser.close();
|
||||
await neverResolves;
|
||||
// WebKit under task-set -c 1 is giving browser, rest are giving target.
|
||||
expect(error.message).toContain(' closed');
|
||||
expect(error!.message).toContain(' closed');
|
||||
});
|
||||
|
||||
it('should throw if userDataDir option is passed', async ({ browserType }) => {
|
||||
let waitError = null;
|
||||
let waitError: Error | undefined;
|
||||
await browserType.launch({ userDataDir: 'random-path' } as any).catch(e => waitError = e);
|
||||
expect(waitError.message).toContain('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||
expect(waitError!.message).toContain('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistentContext` instead');
|
||||
});
|
||||
|
||||
it('should throw if userDataDir is passed as an argument', async ({ browserType }) => {
|
||||
let waitError = null;
|
||||
let waitError: Error | undefined;
|
||||
await browserType.launch({ args: ['--user-data-dir=random-path', '--profile=random-path'] } as any).catch(e => waitError = e);
|
||||
expect(waitError.message).toContain(`Pass userDataDir parameter to 'browserType.launchPersistentContext`);
|
||||
expect(waitError!.message).toContain(`Pass userDataDir parameter to 'browserType.launchPersistentContext`);
|
||||
});
|
||||
|
||||
it('should throw if port option is passed', async ({ browserType }) => {
|
||||
const error = await browserType.launch({ port: 1234 } as any).catch(e => e);
|
||||
expect(error.message).toContain('Cannot specify a port without launching as a server.');
|
||||
expect(error!.message).toContain('Cannot specify a port without launching as a server.');
|
||||
});
|
||||
|
||||
it('should throw if port option is passed for persistent context', async ({ browserType }) => {
|
||||
const error = await browserType.launchPersistentContext('foo', { port: 1234 } as any).catch(e => e);
|
||||
expect(error.message).toContain('Cannot specify a port without launching as a server.');
|
||||
expect(error!.message).toContain('Cannot specify a port without launching as a server.');
|
||||
});
|
||||
|
||||
it('should throw if page argument is passed', async ({ browserType, browserName }) => {
|
||||
it.skip(browserName === 'firefox');
|
||||
|
||||
let waitError = null;
|
||||
let waitError: Error | undefined;
|
||||
await browserType.launch({ args: ['http://example.com'] }).catch(e => waitError = e);
|
||||
expect(waitError.message).toContain('can not specify page');
|
||||
expect(waitError!.message).toContain('can not specify page');
|
||||
});
|
||||
|
||||
it('should reject if launched browser fails immediately', async ({ mode, browserType, asset, isWindows }) => {
|
||||
it.skip(mode.startsWith('service'));
|
||||
|
||||
let waitError = null;
|
||||
let waitError: Error | undefined;
|
||||
await browserType.launch({ executablePath: asset('dummy_bad_browser_executable.js') }).catch(e => waitError = e);
|
||||
expect(waitError.message).toContain(isWindows ? 'browserType.launch: spawn UNKNOWN' : 'Browser logs:');
|
||||
expect(waitError!.message).toContain(isWindows ? 'browserType.launch: spawn UNKNOWN' : 'Browser logs:');
|
||||
});
|
||||
|
||||
it('should reject if executable path is invalid', async ({ browserType, mode }) => {
|
||||
it.skip(mode.startsWith('service'), 'on service mode we dont allow passing custom executable path');
|
||||
let waitError = null;
|
||||
let waitError: Error | undefined;
|
||||
await browserType.launch({ executablePath: 'random-invalid-path' }).catch(e => waitError = e);
|
||||
expect(waitError.message).toContain('Failed to launch');
|
||||
expect(waitError!.message).toContain('Failed to launch');
|
||||
});
|
||||
|
||||
it('should handle timeout', async ({ browserType, mode }) => {
|
||||
@ -79,9 +81,9 @@ it('should handle timeout', async ({ browserType, mode }) => {
|
||||
|
||||
const options: any = { timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
|
||||
const error = await browserType.launch(options).catch(e => e);
|
||||
expect(error.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`);
|
||||
expect(error.message).toContain(`<launching>`);
|
||||
expect(error.message).toContain(`<launched> pid=`);
|
||||
expect(error!.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`);
|
||||
expect(error!.message).toContain(`<launching>`);
|
||||
expect(error!.message).toContain(`<launched> pid=`);
|
||||
});
|
||||
|
||||
it('should handle exception', async ({ browserType, mode }) => {
|
||||
@ -90,7 +92,7 @@ it('should handle exception', async ({ browserType, mode }) => {
|
||||
const e = new Error('Dummy');
|
||||
const options = { __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
|
||||
const error = await browserType.launch(options).catch(e => e);
|
||||
expect(error.message).toContain('Dummy');
|
||||
expect(error!.message).toContain('Dummy');
|
||||
});
|
||||
|
||||
it('should report launch log', async ({ browserType, mode }) => {
|
||||
@ -99,7 +101,7 @@ it('should report launch log', async ({ browserType, mode }) => {
|
||||
const e = new Error('Dummy');
|
||||
const options = { __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
|
||||
const error = await browserType.launch(options).catch(e => e);
|
||||
expect(error.message).toContain('<launching>');
|
||||
expect(error!.message).toContain('<launching>');
|
||||
});
|
||||
|
||||
it('should accept objects as options', async ({ mode, browserType }) => {
|
||||
@ -127,3 +129,27 @@ it('should be callable twice', async ({ browserType }) => {
|
||||
]);
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should allow await using', async ({ browserType }) => {
|
||||
const nodeVersion = +process.versions.node.split('.')[0];
|
||||
it.skip(nodeVersion < 18);
|
||||
|
||||
let b: Browser;
|
||||
let c: BrowserContext;
|
||||
let p: Page;
|
||||
{
|
||||
await using browser = await browserType.launch();
|
||||
b = browser;
|
||||
{
|
||||
await using context = await browser.newContext();
|
||||
c = context;
|
||||
{
|
||||
await using page = await context.newPage();
|
||||
p = page;
|
||||
}
|
||||
expect(p.isClosed()).toBeTruthy();
|
||||
}
|
||||
expect(await c.clearCookies().catch(e => e.message)).toContain(kTargetClosedErrorMessage);
|
||||
}
|
||||
expect(b.isConnected()).toBeFalsy();
|
||||
});
|
||||
|
@ -55,8 +55,8 @@ const md = require('../markdown');
|
||||
* @typedef {{
|
||||
* langs: Langs,
|
||||
* since: string,
|
||||
* deprecated: string | undefined,
|
||||
* discouraged: string | undefined,
|
||||
* deprecated?: string | undefined,
|
||||
* discouraged?: string | undefined,
|
||||
* experimental: boolean
|
||||
* }} Metainfo
|
||||
*/
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
const toKebabCase = require('lodash/kebabCase')
|
||||
const devices = require('../../packages/playwright-core/lib/server/deviceDescriptors');
|
||||
const md = require('../markdown');
|
||||
const docs = require('../doclint/documentation');
|
||||
@ -54,6 +53,27 @@ class TypesGenerator {
|
||||
if (!options.includeExperimental)
|
||||
this.documentation.filterOutExperimental();
|
||||
this.documentation.copyDocsFromSuperclasses([]);
|
||||
this.injectDisposeAsync();
|
||||
}
|
||||
|
||||
injectDisposeAsync() {
|
||||
for (const [name, clazz] of this.documentation.classes.entries()) {
|
||||
/** @type {docs.Member | undefined} */
|
||||
let newMember = undefined;
|
||||
for (const [memberName, member] of clazz.members) {
|
||||
if (memberName !== 'close' && memberName !== 'dispose')
|
||||
continue;
|
||||
if (!member.async)
|
||||
continue;
|
||||
newMember = new docs.Member('method', { langs: {}, since: '1.0', experimental: false }, '[Symbol.asyncDispose]', null, []);
|
||||
newMember.async = true;
|
||||
break;
|
||||
}
|
||||
if (newMember) {
|
||||
clazz.membersArray = [...clazz.membersArray, newMember];
|
||||
clazz.index();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"target": "ES2019",
|
||||
"target": "ESNext",
|
||||
"noEmit": true,
|
||||
"moduleResolution": "node",
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user