chore: turn on rulesdir/use-using (#10806)

This commit is contained in:
jrandolf 2023-08-30 12:02:59 +02:00 committed by GitHub
parent a540085176
commit 900a1f227d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 605 additions and 642 deletions

View File

@ -144,7 +144,7 @@ module.exports = {
// Keeps comments formatted.
'rulesdir/prettier-comments': 'error',
// Enforces clean up of used resources.
'rulesdir/use-using': 'off',
'rulesdir/use-using': 'error',
// Brackets keep code readable.
curly: ['error', 'all'],
// Brackets keep code readable and `return` intentions clear.

View File

@ -28,11 +28,7 @@ import {
NodeFor,
} from '../common/types.js';
import {KeyInput} from '../common/USKeyboardLayout.js';
import {
debugError,
isString,
withSourcePuppeteerURLIfNone,
} from '../common/util.js';
import {isString, withSourcePuppeteerURLIfNone} from '../common/util.js';
import {assert} from '../util/assert.js';
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
@ -336,15 +332,13 @@ export abstract class ElementHandle<
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
const elementHandle = await this.$(selector);
using elementHandle = await this.$(selector);
if (!elementHandle) {
throw new Error(
`Error: failed to find element matching selector "${selector}"`
);
}
const result = await elementHandle.evaluate(pageFunction, ...args);
await elementHandle.dispose();
return result;
return await elementHandle.evaluate(pageFunction, ...args);
}
/**
@ -394,7 +388,7 @@ export abstract class ElementHandle<
): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
const results = await this.$$(selector);
const elements = await this.evaluateHandle(
using elements = await this.evaluateHandle(
(_, ...elements) => {
return elements;
},
@ -406,7 +400,6 @@ export abstract class ElementHandle<
return results.dispose();
}),
]);
await elements.dispose();
return result;
}
@ -480,21 +473,17 @@ export abstract class ElementHandle<
}
async #checkVisibility(visibility: boolean): Promise<boolean> {
const element = await this.frame.isolatedRealm().adoptHandle(this);
try {
return await this.frame.isolatedRealm().evaluate(
async (PuppeteerUtil, element, visibility) => {
return Boolean(PuppeteerUtil.checkVisibility(element, visibility));
},
LazyArg.create(context => {
return context.puppeteerUtil;
}),
element,
visibility
);
} finally {
await element.dispose();
}
using element = await this.frame.isolatedRealm().adoptHandle(this);
return await this.frame.isolatedRealm().evaluate(
async (PuppeteerUtil, element, visibility) => {
return Boolean(PuppeteerUtil.checkVisibility(element, visibility));
},
LazyArg.create(context => {
return context.puppeteerUtil;
}),
element,
visibility
);
}
/**
@ -630,7 +619,8 @@ export abstract class ElementHandle<
* Returns the middle point within an element unless a specific offset is provided.
*/
async clickablePoint(offset?: Offset): Promise<Point> {
const box = await this.#clickableBox();
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
const box = await adoptedThis.#clickableBox();
if (!box) {
throw new Error('Node is either not clickable or not an Element');
}
@ -903,8 +893,7 @@ export abstract class ElementHandle<
}
async #clickableBox(): Promise<BoundingBox | null> {
const adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
const boxes = await adoptedThis.evaluate(element => {
const boxes = await this.evaluate(element => {
if (!(element instanceof Element)) {
return null;
}
@ -912,46 +901,44 @@ export abstract class ElementHandle<
return {x: rect.x, y: rect.y, width: rect.width, height: rect.height};
});
});
void adoptedThis.dispose().catch(debugError);
if (!boxes?.length) {
return null;
}
await this.#intersectBoundingBoxesWithFrame(boxes);
let frame: Frame | null | undefined = this.frame;
let element: HandleFor<HTMLIFrameElement> | null | undefined;
while ((element = await frame?.frameElement())) {
try {
element = await element.frame.isolatedRealm().transferHandle(element);
const parentBox = await element.evaluate(element => {
// Element is not visible.
if (element.getClientRects().length === 0) {
return null;
}
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return {
left:
rect.left +
parseInt(style.paddingLeft, 10) +
parseInt(style.borderLeftWidth, 10),
top:
rect.top +
parseInt(style.paddingTop, 10) +
parseInt(style.borderTopWidth, 10),
};
});
if (!parentBox) {
let frame = this.frame;
let parentFrame: Frame | null | undefined;
while ((parentFrame = frame?.parentFrame())) {
using handle = await frame.frameElement();
if (!handle) {
throw new Error('Unsupported frame type');
}
const parentBox = await handle.evaluate(element => {
// Element is not visible.
if (element.getClientRects().length === 0) {
return null;
}
for (const box of boxes) {
box.x += parentBox.left;
box.y += parentBox.top;
}
await element.#intersectBoundingBoxesWithFrame(boxes);
frame = frame?.parentFrame();
} finally {
void element.dispose().catch(debugError);
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return {
left:
rect.left +
parseInt(style.paddingLeft, 10) +
parseInt(style.borderLeftWidth, 10),
top:
rect.top +
parseInt(style.paddingTop, 10) +
parseInt(style.borderTopWidth, 10),
};
});
if (!parentBox) {
return null;
}
for (const box of boxes) {
box.x += parentBox.left;
box.y += parentBox.top;
}
await handle.#intersectBoundingBoxesWithFrame(boxes);
frame = parentFrame;
}
const box = boxes.find(box => {
return box.width >= 1 && box.height >= 1;
@ -986,7 +973,7 @@ export abstract class ElementHandle<
* or `null` if the element is not visible.
*/
async boundingBox(): Promise<BoundingBox | null> {
const adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
const box = await adoptedThis.evaluate(element => {
if (!(element instanceof Element)) {
return null;
@ -998,11 +985,10 @@ export abstract class ElementHandle<
const rect = element.getBoundingClientRect();
return {x: rect.x, y: rect.y, width: rect.width, height: rect.height};
});
void adoptedThis.dispose().catch(debugError);
if (!box) {
return null;
}
const offset = await this.#getTopLeftCornerOfFrame();
const offset = await adoptedThis.#getTopLeftCornerOfFrame();
if (!offset) {
return null;
}
@ -1023,80 +1009,81 @@ export abstract class ElementHandle<
* Each Point is an object `{x, y}`. Box points are sorted clock-wise.
*/
async boxModel(): Promise<BoxModel | null> {
const adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
const model = await adoptedThis.evaluate(element => {
if (!(element instanceof Element)) {
return null;
}
// Element is not visible.
if (element.getClientRects().length === 0) {
return null;
}
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
const offsets = {
padding: {
left: parseInt(style.paddingLeft, 10),
top: parseInt(style.paddingTop, 10),
right: parseInt(style.paddingRight, 10),
bottom: parseInt(style.paddingBottom, 10),
},
margin: {
left: -parseInt(style.marginLeft, 10),
top: -parseInt(style.marginTop, 10),
right: -parseInt(style.marginRight, 10),
bottom: -parseInt(style.marginBottom, 10),
},
border: {
left: parseInt(style.borderLeft, 10),
top: parseInt(style.borderTop, 10),
right: parseInt(style.borderRight, 10),
bottom: parseInt(style.borderBottom, 10),
},
};
const border: Quad = [
{x: rect.left, y: rect.top},
{x: rect.left + rect.width, y: rect.top},
{x: rect.left + rect.width, y: rect.top + rect.bottom},
{x: rect.left, y: rect.top + rect.bottom},
];
const padding = transformQuadWithOffsets(border, offsets.border);
const content = transformQuadWithOffsets(padding, offsets.padding);
const margin = transformQuadWithOffsets(border, offsets.margin);
return {
content,
padding,
border,
margin,
width: rect.width,
height: rect.height,
};
function transformQuadWithOffsets(
quad: Quad,
offsets: {top: number; left: number; right: number; bottom: number}
): Quad {
return [
{
x: quad[0].x + offsets.left,
y: quad[0].y + offsets.top,
const model = await (async () => {
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
return await adoptedThis.evaluate(element => {
if (!(element instanceof Element)) {
return null;
}
// Element is not visible.
if (element.getClientRects().length === 0) {
return null;
}
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
const offsets = {
padding: {
left: parseInt(style.paddingLeft, 10),
top: parseInt(style.paddingTop, 10),
right: parseInt(style.paddingRight, 10),
bottom: parseInt(style.paddingBottom, 10),
},
{
x: quad[1].x - offsets.right,
y: quad[1].y + offsets.top,
margin: {
left: -parseInt(style.marginLeft, 10),
top: -parseInt(style.marginTop, 10),
right: -parseInt(style.marginRight, 10),
bottom: -parseInt(style.marginBottom, 10),
},
{
x: quad[2].x - offsets.right,
y: quad[2].y - offsets.bottom,
},
{
x: quad[3].x + offsets.left,
y: quad[3].y - offsets.bottom,
border: {
left: parseInt(style.borderLeft, 10),
top: parseInt(style.borderTop, 10),
right: parseInt(style.borderRight, 10),
bottom: parseInt(style.borderBottom, 10),
},
};
const border: Quad = [
{x: rect.left, y: rect.top},
{x: rect.left + rect.width, y: rect.top},
{x: rect.left + rect.width, y: rect.top + rect.bottom},
{x: rect.left, y: rect.top + rect.bottom},
];
}
});
void adoptedThis.dispose().catch(debugError);
const padding = transformQuadWithOffsets(border, offsets.border);
const content = transformQuadWithOffsets(padding, offsets.padding);
const margin = transformQuadWithOffsets(border, offsets.margin);
return {
content,
padding,
border,
margin,
width: rect.width,
height: rect.height,
};
function transformQuadWithOffsets(
quad: Quad,
offsets: {top: number; left: number; right: number; bottom: number}
): Quad {
return [
{
x: quad[0].x + offsets.left,
y: quad[0].y + offsets.top,
},
{
x: quad[1].x - offsets.right,
y: quad[1].y + offsets.top,
},
{
x: quad[2].x - offsets.right,
y: quad[2].y - offsets.bottom,
},
{
x: quad[3].x + offsets.left,
y: quad[3].y - offsets.bottom,
},
];
}
});
})();
if (!model) {
return null;
}
@ -1120,38 +1107,37 @@ export abstract class ElementHandle<
async #getTopLeftCornerOfFrame() {
const point = {x: 0, y: 0};
let frame: Frame | null | undefined = this.frame;
let element: HandleFor<HTMLIFrameElement> | null | undefined;
while ((element = await frame?.frameElement())) {
try {
element = await element.frame.isolatedRealm().transferHandle(element);
const parentBox = await element.evaluate(element => {
// Element is not visible.
if (element.getClientRects().length === 0) {
return null;
}
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return {
left:
rect.left +
parseInt(style.paddingLeft, 10) +
parseInt(style.borderLeftWidth, 10),
top:
rect.top +
parseInt(style.paddingTop, 10) +
parseInt(style.borderTopWidth, 10),
};
});
if (!parentBox) {
let frame = this.frame;
let parentFrame: Frame | null | undefined;
while ((parentFrame = frame?.parentFrame())) {
using handle = await frame.frameElement();
if (!handle) {
throw new Error('Unsupported frame type');
}
const parentBox = await handle.evaluate(element => {
// Element is not visible.
if (element.getClientRects().length === 0) {
return null;
}
point.x += parentBox.left;
point.y += parentBox.top;
frame = frame?.parentFrame();
} finally {
void element.dispose().catch(debugError);
const rect = element.getBoundingClientRect();
const style = window.getComputedStyle(element);
return {
left:
rect.left +
parseInt(style.paddingLeft, 10) +
parseInt(style.borderLeftWidth, 10),
top:
rect.top +
parseInt(style.paddingTop, 10) +
parseInt(style.borderTopWidth, 10),
};
});
if (!parentBox) {
return null;
}
point.x += parentBox.left;
point.y += parentBox.top;
frame = parentFrame;
}
return point;
}
@ -1173,17 +1159,15 @@ export abstract class ElementHandle<
* @internal
*/
protected async assertConnectedElement(): Promise<void> {
const error = await this.evaluate(
async (element): Promise<string | undefined> => {
if (!element.isConnected) {
return 'Node is detached from document';
}
if (element.nodeType !== Node.ELEMENT_NODE) {
return 'Node is not of type HTMLElement';
}
return;
const error = await this.evaluate(async element => {
if (!element.isConnected) {
return 'Node is detached from document';
}
);
if (element.nodeType !== Node.ELEMENT_NODE) {
return 'Node is not of type HTMLElement';
}
return;
});
if (error) {
throw new Error(error);
@ -1216,20 +1200,16 @@ export abstract class ElementHandle<
*/
async isIntersectingViewport(
this: ElementHandle<Element>,
options?: {
options: {
threshold?: number;
}
} = {}
): Promise<boolean> {
await this.assertConnectedElement();
const {threshold = 0} = options ?? {};
const svgHandle = await this.#asSVGElementHandle(this);
const intersectionTarget: ElementHandle<Element> = svgHandle
? await this.#getOwnerSVGElement(svgHandle)
: this;
try {
return await intersectionTarget.evaluate(async (element, threshold) => {
// eslint-disable-next-line rulesdir/use-using -- Returns `this`.
const handle = await this.#asSVGElementHandle();
using target = handle && (await handle.#getOwnerSVGElement());
return await ((target ?? this) as ElementHandle<Element>).evaluate(
async (element, threshold) => {
const visibleRatio = await new Promise<number>(resolve => {
const observer = new IntersectionObserver(entries => {
resolve(entries[0]!.intersectionRatio);
@ -1238,12 +1218,9 @@ export abstract class ElementHandle<
observer.observe(element);
});
return threshold === 1 ? visibleRatio === 1 : visibleRatio > threshold;
}, threshold);
} finally {
if (intersectionTarget !== this) {
await intersectionTarget.dispose();
}
}
},
options.threshold ?? 0
);
}
/**
@ -1251,8 +1228,9 @@ export abstract class ElementHandle<
* or by calling element.scrollIntoView.
*/
async scrollIntoView(this: ElementHandle<Element>): Promise<void> {
await this.assertConnectedElement();
await this.evaluate(async (element): Promise<void> => {
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
await adoptedThis.assertConnectedElement();
await adoptedThis.evaluate(async (element): Promise<void> => {
element.scrollIntoView({
block: 'center',
inline: 'center',
@ -1266,24 +1244,24 @@ export abstract class ElementHandle<
* etc.).
*/
async #asSVGElementHandle(
handle: ElementHandle<Element>
this: ElementHandle<Element>
): Promise<ElementHandle<SVGElement> | null> {
if (
await handle.evaluate(element => {
await this.evaluate(element => {
return element instanceof SVGElement;
})
) {
return handle as ElementHandle<SVGElement>;
return this as ElementHandle<SVGElement>;
} else {
return null;
}
}
async #getOwnerSVGElement(
handle: ElementHandle<SVGElement>
this: ElementHandle<SVGElement>
): Promise<ElementHandle<SVGSVGElement>> {
// SVGSVGElement.ownerSVGElement === null.
return await handle.evaluateHandle(element => {
return await this.evaluateHandle(element => {
if (element instanceof SVGSVGElement) {
return element;
}

View File

@ -37,12 +37,12 @@ import {
InnerLazyParams,
NodeFor,
} from '../common/types.js';
import {debugError, importFSPromises} from '../common/util.js';
import {importFSPromises} from '../common/util.js';
import {TaskManager} from '../common/WaitTask.js';
import {KeyboardTypeOptions} from './Input.js';
import {JSHandle} from './JSHandle.js';
import {Locator, FunctionLocator, NodeLocator} from './locators/locators.js';
import {FunctionLocator, Locator, NodeLocator} from './locators/locators.js';
/**
* @internal
@ -389,15 +389,14 @@ export class Frame extends EventEmitter {
if (!parentFrame) {
return null;
}
const list = await parentFrame.isolatedRealm().evaluateHandle(() => {
using list = await parentFrame.isolatedRealm().evaluateHandle(() => {
return document.querySelectorAll('iframe');
});
for await (const iframe of transposeIterableHandle(list)) {
for await (using iframe of transposeIterableHandle(list)) {
const frame = await iframe.contentFrame();
if (frame._id === this._id) {
return iframe;
return iframe.move();
}
void iframe.dispose().catch(debugError);
}
return null;
}

View File

@ -692,12 +692,8 @@ export abstract class Locator<T> extends EventEmitter {
* @public
*/
async wait(options?: Readonly<ActionOptions>): Promise<T> {
const handle = await this.waitHandle(options);
try {
return await handle.jsonValue();
} finally {
void handle.dispose().catch(debugError);
}
using handle = await this.waitHandle(options);
return await handle.jsonValue();
}
/**

View File

@ -32,11 +32,11 @@ export class Binding {
args: unknown[],
isTrivial: boolean
): Promise<void> {
const garbage = [];
const stack = new DisposableStack();
try {
if (!isTrivial) {
// Getting non-trivial arguments.
const handles = await context.evaluateHandle(
using handles = await context.evaluateHandle(
(name, seq) => {
// @ts-expect-error Code is evaluated in a different context.
return globalThis[name].args.get(seq);
@ -44,25 +44,21 @@ export class Binding {
this.#name,
id
);
try {
const properties = await handles.getProperties();
for (const [index, handle] of properties) {
// This is not straight-forward since some arguments can stringify, but
// aren't plain objects so add subtypes when the use-case arises.
if (index in args) {
switch (handle.remoteObject().subtype) {
case 'node':
args[+index] = handle;
break;
default:
garbage.push(handle.dispose());
}
} else {
garbage.push(handle.dispose());
const properties = await handles.getProperties();
for (const [index, handle] of properties) {
// This is not straight-forward since some arguments can stringify, but
// aren't plain objects so add subtypes when the use-case arises.
if (index in args) {
switch (handle.remoteObject().subtype) {
case 'node':
args[+index] = handle;
break;
default:
stack.use(handle);
}
} else {
stack.use(handle);
}
} finally {
await handles.dispose();
}
}
@ -80,7 +76,7 @@ export class Binding {
for (const arg of args) {
if (arg instanceof JSHandle) {
garbage.push(arg.dispose());
stack.use(arg);
}
}
} catch (error) {
@ -116,8 +112,6 @@ export class Binding {
)
.catch(debugError);
}
} finally {
await Promise.all(garbage);
}
}
}

View File

@ -31,7 +31,7 @@ async function* fastTransposeIteratorHandle<T>(
iterator: JSHandle<AwaitableIterator<T>>,
size: number
) {
const array = await iterator.evaluateHandle(async (iterator, size) => {
using array = await iterator.evaluateHandle(async (iterator, size) => {
const results = [];
while (results.length < size) {
const result = await iterator.next();
@ -43,8 +43,14 @@ async function* fastTransposeIteratorHandle<T>(
return results;
}, size);
const properties = (await array.getProperties()) as Map<string, HandleFor<T>>;
await array.dispose();
yield* properties.values();
const handles = properties.values();
using stack = new DisposableStack();
stack.defer(() => {
for (using handle of handles) {
handle[Symbol.dispose]();
}
});
yield* handles;
return properties.size === 0;
}
@ -57,12 +63,8 @@ async function* transposeIteratorHandle<T>(
iterator: JSHandle<AwaitableIterator<T>>
) {
let size = DEFAULT_BATCH_SIZE;
try {
while (!(yield* fastTransposeIteratorHandle(iterator, size))) {
size <<= 1;
}
} finally {
await iterator.dispose();
while (!(yield* fastTransposeIteratorHandle(iterator, size))) {
size <<= 1;
}
}
@ -74,11 +76,10 @@ type AwaitableIterator<T> = Iterator<T> | AsyncIterator<T>;
export async function* transposeIterableHandle<T>(
handle: JSHandle<AwaitableIterable<T>>
): AsyncIterableIterator<HandleFor<T>> {
yield* transposeIteratorHandle(
await handle.evaluateHandle(iterable => {
return (async function* () {
yield* iterable;
})();
})
);
using generatorHandle = await handle.evaluateHandle(iterable => {
return (async function* () {
yield* iterable;
})();
});
yield* transposeIteratorHandle(generatorHandle);
}

View File

@ -104,7 +104,6 @@ export interface IsolatedWorldChart {
*/
export class IsolatedWorld implements Realm {
#frame: Frame;
#document?: ElementHandle<Document>;
#context = Deferred.create<ExecutionContext>();
#detached = false;
@ -149,7 +148,6 @@ export class IsolatedWorld implements Realm {
}
clearContext(): void {
this.#document = undefined;
this.#context = Deferred.create();
}
@ -216,31 +214,27 @@ export class IsolatedWorld implements Realm {
async $<Selector extends string>(
selector: Selector
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const document = await this.document();
return document.$(selector);
using document = await this.document();
return await document.$(selector);
}
async $$<Selector extends string>(
selector: Selector
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
const document = await this.document();
return document.$$(selector);
using document = await this.document();
return await document.$$(selector);
}
async document(): Promise<ElementHandle<Document>> {
if (this.#document) {
return this.#document;
}
const context = await this.executionContext();
this.#document = await context.evaluateHandle(() => {
// TODO(#10813): Implement document caching.
return await this.evaluateHandle(() => {
return document;
});
return this.#document;
}
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
const document = await this.document();
return document.$x(expression);
using document = await this.document();
return await document.$x(expression);
}
async $eval<
@ -256,8 +250,8 @@ export class IsolatedWorld implements Realm {
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
const document = await this.document();
return document.$eval(selector, pageFunction, ...args);
using document = await this.document();
return await document.$eval(selector, pageFunction, ...args);
}
async $$eval<
@ -273,8 +267,8 @@ export class IsolatedWorld implements Realm {
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
const document = await this.document();
return document.$$eval(selector, pageFunction, ...args);
using document = await this.document();
return await document.$$eval(selector, pageFunction, ...args);
}
async content(): Promise<string> {
@ -315,39 +309,34 @@ export class IsolatedWorld implements Realm {
selector: string,
options?: Readonly<ClickOptions>
): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.click(options);
await handle.dispose();
}
async focus(selector: string): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.focus();
await handle.dispose();
}
async hover(selector: string): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.hover();
await handle.dispose();
}
async select(selector: string, ...values: string[]): Promise<string[]> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
const result = await handle.select(...values);
await handle.dispose();
return result;
return await handle.select(...values);
}
async tap(selector: string): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.tap();
await handle.dispose();
}
async type(
@ -355,10 +344,9 @@ export class IsolatedWorld implements Realm {
text: string,
options?: Readonly<KeyboardTypeOptions>
): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.type(text, options);
await handle.dispose();
}
// If multiple waitFor are set up asynchronously, we need to wait for the

View File

@ -433,11 +433,11 @@ export class CDPPage extends Page {
assert(frame, 'This should never happen.');
// This is guaranteed to be an HTMLInputElement handle by the event.
const handle = (await frame.worlds[MAIN_WORLD].adoptBackendNode(
using handle = (await frame.worlds[MAIN_WORLD].adoptBackendNode(
event.backendNodeId
)) as ElementHandle<HTMLInputElement>;
const fileChooser = new FileChooser(handle, event);
const fileChooser = new FileChooser(handle.move(), event);
for (const promise of this.#fileChooserDeferreds) {
promise.resolve(fileChooser);
}
@ -885,6 +885,8 @@ export class CDPPage extends Page {
return;
}
const textTokens = [];
// eslint-disable-next-line max-len -- The comment is long.
// eslint-disable-next-line rulesdir/use-using -- These are not owned by this function.
for (const arg of args) {
const remoteObject = arg.remoteObject();
if (remoteObject.objectId) {

View File

@ -107,7 +107,7 @@ export class QueryHandler {
selector: string
): AwaitableIterable<ElementHandle<Node>> {
element.assertElementHasWorld();
const handle = await element.evaluateHandle(
using handle = await element.evaluateHandle(
this._querySelectorAll,
selector,
LazyArg.create(context => {
@ -127,7 +127,7 @@ export class QueryHandler {
selector: string
): Promise<ElementHandle<Node> | null> {
element.assertElementHasWorld();
const result = await element.evaluateHandle(
using result = await element.evaluateHandle(
this._querySelector,
selector,
LazyArg.create(context => {
@ -135,10 +135,9 @@ export class QueryHandler {
})
);
if (!(result instanceof ElementHandle)) {
await result.dispose();
return null;
}
return result;
return result.move();
}
/**
@ -153,21 +152,22 @@ export class QueryHandler {
selector: string,
options: WaitForSelectorOptions
): Promise<ElementHandle<Node> | null> {
let frame: Frame;
let element: ElementHandle<Node> | undefined;
if (!(elementOrFrame instanceof ElementHandle)) {
frame = elementOrFrame;
} else {
let frame!: Frame;
using element = await (async () => {
if (!(elementOrFrame instanceof ElementHandle)) {
frame = elementOrFrame;
return;
}
frame = elementOrFrame.frame;
element = await frame.isolatedRealm().adoptHandle(elementOrFrame);
}
return await frame.isolatedRealm().adoptHandle(elementOrFrame);
})();
const {visible = false, hidden = false, timeout, signal} = options;
try {
signal?.throwIfAborted();
const handle = await frame.isolatedRealm().waitForFunction(
using handle = await frame.isolatedRealm().waitForFunction(
async (PuppeteerUtil, query, selector, root, visible) => {
const querySelector = PuppeteerUtil.createFunction(
query
@ -195,15 +195,13 @@ export class QueryHandler {
);
if (signal?.aborted) {
await handle.dispose();
throw signal.reason;
}
if (!(handle instanceof ElementHandle)) {
await handle.dispose();
return null;
}
return frame.mainRealm().transferHandle(handle);
return await frame.mainRealm().transferHandle(handle);
} catch (error) {
if (!isErrorLike(error)) {
throw error;
@ -213,10 +211,6 @@ export class QueryHandler {
}
error.message = `Waiting for selector \`${selector}\` failed: ${error.message}`;
throw error;
} finally {
if (element) {
await element.dispose();
}
}
}
}

View File

@ -20,7 +20,6 @@ import {
AutofillData,
ElementHandle as BaseElementHandle,
} from '../../api/ElementHandle.js';
import {debugError} from '../util.js';
import {Frame} from './Frame.js';
import {JSHandle as BidiJSHandle, JSHandle} from './JSHandle.js';
@ -86,15 +85,13 @@ export class ElementHandle<
this: ElementHandle<HTMLIFrameElement>
): Promise<Frame>;
override async contentFrame(): Promise<Frame | null> {
const adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
const handle = (await adoptedThis.evaluateHandle(element => {
using adoptedThis = await this.frame.isolatedRealm().adoptHandle(this);
using handle = (await adoptedThis.evaluateHandle(element => {
if (element instanceof HTMLIFrameElement) {
return element.contentWindow;
}
return;
})) as BidiJSHandle;
void handle.dispose().catch(debugError);
void adoptedThis.dispose().catch(debugError);
const value = handle.remoteValue();
if (value.type === 'window') {
return this.frame.page().frame(value.value.context);

View File

@ -106,9 +106,9 @@ export class JSHandle<T = unknown> extends BaseJSHandle<T> {
);
for (const [key, value] of Object.entries(keys)) {
const handle = results[key as any];
using handle = results[key as any];
if (handle) {
map.set(value, handle);
map.set(value, handle.move());
}
}

View File

@ -56,8 +56,7 @@ export class Realm extends EventEmitter {
const promise = this.internalPuppeteerUtil;
this.internalPuppeteerUtil = undefined;
try {
const util = await promise;
await util?.dispose();
await (await promise)?.dispose();
} catch (error) {
debugError(error);
}

View File

@ -96,8 +96,7 @@ export class Sandbox implements RealmBase {
}
async document(): Promise<ElementHandle<Document>> {
// TODO(jrandolf): We should try to cache this because we need to dispose
// this when it's unused.
// TODO(#10813): Implement document caching.
return await this.#realm.evaluateHandle(() => {
return document;
});
@ -106,15 +105,15 @@ export class Sandbox implements RealmBase {
async $<Selector extends string>(
selector: Selector
): Promise<ElementHandle<NodeFor<Selector>> | null> {
const document = await this.document();
return document.$(selector);
using document = await this.document();
return await document.$(selector);
}
async $$<Selector extends string>(
selector: Selector
): Promise<Array<ElementHandle<NodeFor<Selector>>>> {
const document = await this.document();
return document.$$(selector);
using document = await this.document();
return await document.$$(selector);
}
async $eval<
@ -130,8 +129,8 @@ export class Sandbox implements RealmBase {
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(this.$eval.name, pageFunction);
const document = await this.document();
return document.$eval(selector, pageFunction, ...args);
using document = await this.document();
return await document.$eval(selector, pageFunction, ...args);
}
async $$eval<
@ -147,13 +146,13 @@ export class Sandbox implements RealmBase {
...args: Params
): Promise<Awaited<ReturnType<Func>>> {
pageFunction = withSourcePuppeteerURLIfNone(this.$$eval.name, pageFunction);
const document = await this.document();
return document.$$eval(selector, pageFunction, ...args);
using document = await this.document();
return await document.$$eval(selector, pageFunction, ...args);
}
async $x(expression: string): Promise<Array<ElementHandle<Node>>> {
const document = await this.document();
return document.$x(expression);
using document = await this.document();
return await document.$x(expression);
}
async evaluateHandle<
@ -249,39 +248,34 @@ export class Sandbox implements RealmBase {
selector: string,
options?: Readonly<ClickOptions>
): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.click(options);
await handle.dispose();
}
async focus(selector: string): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.focus();
await handle.dispose();
}
async hover(selector: string): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.hover();
await handle.dispose();
}
async select(selector: string, ...values: string[]): Promise<string[]> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
const result = await handle.select(...values);
await handle.dispose();
return result;
}
async tap(selector: string): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.tap();
await handle.dispose();
}
async type(
@ -289,9 +283,8 @@ export class Sandbox implements RealmBase {
text: string,
options?: Readonly<KeyboardTypeOptions>
): Promise<void> {
const handle = await this.$(selector);
using handle = await this.$(selector);
assert(handle, `No element found for selector: ${selector}`);
await handle.type(text, options);
await handle.dispose();
}
}

View File

@ -149,6 +149,7 @@ export class BidiSerializer {
if (arg instanceof LazyArg) {
arg = await arg.get(context);
}
// eslint-disable-next-line rulesdir/use-using -- We want this to continue living.
const objectHandle =
arg && (arg instanceof JSHandle || arg instanceof ElementHandle)
? arg

View File

@ -200,7 +200,7 @@ describe('Accessibility', function () {
async function getAccessibleName(page: any, element: any) {
return (await page.accessibility.snapshot({root: element})).name;
}
const button = await page.$('button');
using button = await page.$('button');
expect(await getAccessibleName(page, button)).toEqual('Show');
await button?.click();
await page.waitForSelector('aria/Hide');
@ -483,7 +483,7 @@ describe('Accessibility', function () {
await page.setContent(`<button>My Button</button>`);
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
expect(await page.accessibility.snapshot({root: button})).toEqual({
role: 'button',
name: 'My Button',
@ -494,7 +494,7 @@ describe('Accessibility', function () {
await page.setContent(`<input title="My Input" value="My Value">`);
const input = (await page.$('input'))!;
using input = (await page.$('input'))!;
expect(await page.accessibility.snapshot({root: input})).toEqual({
role: 'textbox',
name: 'My Input',
@ -512,7 +512,7 @@ describe('Accessibility', function () {
</div>
`);
const menu = (await page.$('div[role="menu"]'))!;
using menu = (await page.$('div[role="menu"]'))!;
expect(await page.accessibility.snapshot({root: menu})).toEqual({
role: 'menu',
name: 'My Menu',
@ -528,7 +528,7 @@ describe('Accessibility', function () {
const {page} = await getTestState();
await page.setContent(`<button>My Button</button>`);
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await page.$eval('button', button => {
return button.remove();
});
@ -538,7 +538,7 @@ describe('Accessibility', function () {
const {page} = await getTestState();
await page.setContent(`<div><button>My Button</button></div>`);
const div = (await page.$('div'))!;
using div = (await page.$('div'))!;
expect(await page.accessibility.snapshot({root: div})).toEqual(null);
expect(
await page.accessibility.snapshot({

View File

@ -39,49 +39,67 @@ describe('AriaQueryHandler', () => {
});
expect(id).toBe('btn');
};
let button = await page.$(
'aria/Submit button and some spaces[role="button"]'
);
await expectFound(button);
button = await page.$(
"aria/Submit button and some spaces[role='button']"
);
await expectFound(button);
button = await page.$(
{
using button = await page.$(
'aria/Submit button and some spaces[role="button"]'
);
await expectFound(button);
}
{
using button = await page.$(
"aria/Submit button and some spaces[role='button']"
);
await expectFound(button);
}
using button = await page.$(
'aria/ Submit button and some spaces[role="button"]'
);
await expectFound(button);
button = await page.$(
'aria/Submit button and some spaces [role="button"]'
);
await expectFound(button);
button = await page.$(
'aria/Submit button and some spaces [ role = "button" ] '
);
await expectFound(button);
button = await page.$(
'aria/[role="button"]Submit button and some spaces'
);
await expectFound(button);
button = await page.$(
'aria/Submit button [role="button"]and some spaces'
);
await expectFound(button);
button = await page.$(
'aria/[name=" Submit button and some spaces"][role="button"]'
);
await expectFound(button);
button = await page.$(
"aria/[name=' Submit button and some spaces'][role='button']"
);
await expectFound(button);
button = await page.$(
'aria/ignored[name="Submit button and some spaces"][role="button"]'
);
await expectFound(button);
await expect(page.$('aria/smth[smth="true"]')).rejects.toThrow(
'Unknown aria attribute "smth" in selector'
);
{
using button = await page.$(
'aria/Submit button and some spaces [role="button"]'
);
await expectFound(button);
}
{
using button = await page.$(
'aria/Submit button and some spaces [ role = "button" ] '
);
await expectFound(button);
}
{
using button = await page.$(
'aria/[role="button"]Submit button and some spaces'
);
await expectFound(button);
}
{
using button = await page.$(
'aria/Submit button [role="button"]and some spaces'
);
await expectFound(button);
}
{
using button = await page.$(
'aria/[name=" Submit button and some spaces"][role="button"]'
);
await expectFound(button);
}
{
using button = await page.$(
"aria/[name=' Submit button and some spaces'][role='button']"
);
await expectFound(button);
}
{
using button = await page.$(
'aria/ignored[name="Submit button and some spaces"][role="button"]'
);
await expectFound(button);
await expect(page.$('aria/smth[smth="true"]')).rejects.toThrow(
'Unknown aria attribute "smth" in selector'
);
}
});
});
@ -91,7 +109,7 @@ describe('AriaQueryHandler', () => {
await page.setContent(
'<div id="div"><button id="btn" role="button">Submit</button></div>'
);
const button = (await page.$(
using button = (await page.$(
'aria/[role="button"]'
)) as ElementHandle<HTMLButtonElement>;
const id = await button!.evaluate(button => {
@ -105,7 +123,7 @@ describe('AriaQueryHandler', () => {
await page.setContent(
'<div id="div"><button id="btn" role="button">Submit</button></div>'
);
const button = (await page.$(
using button = (await page.$(
'aria/Submit[role="button"]'
)) as ElementHandle<HTMLButtonElement>;
const id = await button!.evaluate(button => {
@ -122,7 +140,7 @@ describe('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu div"></div>
`
);
const div = (await page.$(
using div = (await page.$(
'aria/menu div'
)) as ElementHandle<HTMLDivElement>;
const id = await div!.evaluate(div => {
@ -139,7 +157,7 @@ describe('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu-label2">menu div</div>
`
);
const menu = (await page.$(
using menu = (await page.$(
'aria/menu-label1'
)) as ElementHandle<HTMLDivElement>;
const id = await menu!.evaluate(div => {
@ -156,7 +174,7 @@ describe('AriaQueryHandler', () => {
<div role="menu" id="mnu2" aria-label="menu-label2">menu div</div>
`
);
const menu = (await page.$(
using menu = (await page.$(
'aria/menu-label2'
)) as ElementHandle<HTMLDivElement>;
const id = await menu!.evaluate(div => {
@ -230,7 +248,7 @@ describe('AriaQueryHandler', () => {
await page.evaluate(() => {
return (document.body.innerHTML = `<div><button>test</button></div>`);
});
const element = (await page.$('div'))!;
using element = (await page.$('div'))!;
await element!.waitForSelector('aria/test');
});
@ -299,7 +317,7 @@ describe('AriaQueryHandler', () => {
const watchdog = frame.waitForSelector('aria/[role="heading"]');
await frame.evaluate(addElement, 'br');
await frame.evaluate(addElement, 'h1');
const elementHandle = (await watchdog)!;
using elementHandle = (await watchdog)!;
const tagName = await (
await elementHandle.getProperty('tagName')
).jsonValue();
@ -328,7 +346,7 @@ describe('AriaQueryHandler', () => {
const watchdog = page.waitForSelector('aria/[role="button"]');
await otherFrame!.evaluate(addElement, 'button');
await page.evaluate(addElement, 'button');
const elementHandle = await watchdog;
using elementHandle = await watchdog;
expect(elementHandle!.frame).toBe(page.mainFrame());
});
@ -344,7 +362,7 @@ describe('AriaQueryHandler', () => {
);
await frame1!.evaluate(addElement, 'button');
await frame2!.evaluate(addElement, 'button');
const elementHandle = await waitForSelectorPromise;
using elementHandle = await waitForSelectorPromise;
expect(elementHandle!.frame).toBe(frame2);
});
@ -517,7 +535,7 @@ describe('AriaQueryHandler', () => {
it('should return null if waiting to hide non-existing element', async () => {
const {page} = await getTestState();
const handle = await page.waitForSelector('aria/non-existing', {
using handle = await page.waitForSelector('aria/non-existing', {
hidden: true,
});
expect(handle).toBe(null);

View File

@ -24,7 +24,7 @@ describe('Autofill', function () {
it('should fill out a credit card', async () => {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/credit-card.html');
const name = await page.waitForSelector('#name');
using name = await page.waitForSelector('#name');
await name!.autofill({
creditCard: {
number: '4444444444444444',

View File

@ -117,7 +117,7 @@ describe('Page.click', function () {
await page.setJavaScriptEnabled(false);
await page.goto(server.PREFIX + '/wrappedlink.html');
const body = await page.waitForSelector('body');
using body = await page.waitForSelector('body');
await body!.evaluate(el => {
el.style.paddingTop = '3000px';
});
@ -332,7 +332,7 @@ describe('Page.click', function () {
(globalThis as any).double = true;
});
});
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await button!.click({count: 2});
expect(await page.evaluate('double')).toBe(true);
expect(await page.evaluate('result')).toBe('Clicked');
@ -428,7 +428,7 @@ describe('Page.click', function () {
server.PREFIX + '/input/button.html'
);
const frame = page.frames()[1];
const button = await frame!.$('button');
using button = await frame!.$('button');
await button!.click();
expect(
await frame!.evaluate(() => {
@ -477,7 +477,7 @@ describe('Page.click', function () {
server.PREFIX + '/input/button.html'
);
const frame = page.frames()[1];
const button = await frame!.$('button');
using button = await frame!.$('button');
await button!.click();
expect(
await frame!.evaluate(() => {

View File

@ -25,7 +25,7 @@ describe('Input.drag', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/drag-and-drop.html');
const draggable = (await page.$('#drag'))!;
using draggable = (await page.$('#drag'))!;
try {
await draggable!.drag({x: 1, y: 1});
@ -42,7 +42,7 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!;
using draggable = (await page.$('#drag'))!;
const data = await draggable.drag({x: 1, y: 1});
expect(data.items).toHaveLength(1);
@ -59,9 +59,9 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!;
using draggable = (await page.$('#drag'))!;
const data = await draggable.drag({x: 1, y: 1});
const dropzone = (await page.$('#drop'))!;
using dropzone = (await page.$('#drop'))!;
await dropzone.dragEnter(data);
expect(
@ -82,9 +82,9 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!;
using draggable = (await page.$('#drag'))!;
const data = await draggable.drag({x: 1, y: 1});
const dropzone = (await page.$('#drop'))!;
using dropzone = (await page.$('#drop'))!;
await dropzone.dragEnter(data);
await dropzone.dragOver(data);
@ -111,8 +111,8 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!;
const dropzone = (await page.$('#drop'))!;
using draggable = (await page.$('#drag'))!;
using dropzone = (await page.$('#drop'))!;
const data = await draggable.drag({x: 1, y: 1});
await dropzone.dragEnter(data);
await dropzone.dragOver(data);
@ -146,8 +146,8 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!;
const dropzone = (await page.$('#drop'))!;
using draggable = (await page.$('#drag'))!;
using dropzone = (await page.$('#drop'))!;
await draggable.dragAndDrop(dropzone);
expect(
@ -178,7 +178,7 @@ describe('Input.drag', function () {
expect(page.isDragInterceptionEnabled()).toBe(false);
await page.setDragInterception(true);
expect(page.isDragInterceptionEnabled()).toBe(true);
const draggable = (await page.$('#drag'))!;
using draggable = (await page.$('#drag'))!;
await draggable.drag({x: 1, y: 1});
await page.setDragInterception(false);

View File

@ -35,7 +35,7 @@ describe('ElementHandle specs', function () {
await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/grid.html');
const elementHandle = (await page.$('.box:nth-of-type(13)'))!;
using elementHandle = (await page.$('.box:nth-of-type(13)'))!;
const box = await elementHandle.boundingBox();
expect(box).toEqual({x: 100, y: 50, width: 50, height: 50});
});
@ -45,7 +45,7 @@ describe('ElementHandle specs', function () {
await page.setViewport({width: 500, height: 500});
await page.goto(server.PREFIX + '/frames/nested-frames.html');
const nestedFrame = page.frames()[1]!.childFrames()[1]!;
const elementHandle = (await nestedFrame.$('div'))!;
using elementHandle = (await nestedFrame.$('div'))!;
const box = await elementHandle.boundingBox();
if (isChrome) {
expect(box).toEqual({x: 28, y: 182, width: 264, height: 18});
@ -57,7 +57,7 @@ describe('ElementHandle specs', function () {
const {page} = await getTestState();
await page.setContent('<div style="display:none">hi</div>');
const element = (await page.$('div'))!;
using element = (await page.$('div'))!;
expect(await element.boundingBox()).toBe(null);
});
it('should force a layout', async () => {
@ -67,7 +67,7 @@ describe('ElementHandle specs', function () {
await page.setContent(
'<div style="width: 100px; height: 100px">hello</div>'
);
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
await page.evaluate((element: HTMLElement) => {
return (element.style.height = '200px');
}, elementHandle);
@ -82,7 +82,7 @@ describe('ElementHandle specs', function () {
<rect id="theRect" x="30" y="50" width="200" height="300"></rect>
</svg>
`);
const element = (await page.$(
using element = (await page.$(
'#therect'
)) as ElementHandle<SVGRectElement>;
const pptrBoundingBox = await element.boundingBox();
@ -111,7 +111,7 @@ describe('ElementHandle specs', function () {
// Step 2: Add div and position it absolutely inside frame.
const frame = page.frames()[1]!;
const divHandle = (
using divHandle = (
await frame.evaluateHandle(() => {
const div = document.createElement('div');
document.body.appendChild(div);
@ -154,7 +154,7 @@ describe('ElementHandle specs', function () {
const {page} = await getTestState();
await page.setContent('<div style="display:none">hi</div>');
const element = (await page.$('div'))!;
using element = (await page.$('div'))!;
expect(await element.boxModel()).toBe(null);
});
});
@ -165,7 +165,7 @@ describe('ElementHandle specs', function () {
await page.goto(server.EMPTY_PAGE);
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
const elementHandle = (await page.$('#frame1'))!;
using elementHandle = (await page.$('#frame1'))!;
const frame = await elementHandle.contentFrame();
expect(frame).toBe(page.frames()[1]);
});
@ -175,7 +175,7 @@ describe('ElementHandle specs', function () {
it('should work', async () => {
const {page} = await getTestState();
await page.setContent('<div style="display: none">text</div>');
const element = (await page.waitForSelector('div'))!;
using element = (await page.waitForSelector('div'))!;
await expect(element.isVisible()).resolves.toBeFalsy();
await expect(element.isHidden()).resolves.toBeTruthy();
await element.evaluate(e => {
@ -191,7 +191,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await button.click();
expect(
await page.evaluate(() => {
@ -219,7 +219,7 @@ describe('ElementHandle specs', function () {
});
});
const divHandle = (await page.$('div'))!;
using divHandle = (await page.$('div'))!;
await divHandle.click();
await divHandle.click({
offset: {
@ -237,7 +237,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/shadow.html');
const buttonHandle = await page.evaluateHandle(() => {
using buttonHandle = await page.evaluateHandle(() => {
// @ts-expect-error button is expected to be in the page's scope.
return button as HTMLButtonElement;
});
@ -253,7 +253,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/button.html');
const buttonTextNode = await page.evaluateHandle(() => {
using buttonTextNode = await page.evaluateHandle(() => {
return document.querySelector('button')!.firstChild as HTMLElement;
});
let error!: Error;
@ -269,7 +269,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await page.evaluate((button: HTMLElement) => {
return button.remove();
}, button);
@ -286,7 +286,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await page.evaluate((button: HTMLElement) => {
return (button.style.display = 'none');
}, button);
@ -302,7 +302,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await page.evaluate((button: HTMLElement) => {
return (button.parentElement!.style.display = 'none');
}, button);
@ -318,7 +318,7 @@ describe('ElementHandle specs', function () {
const {page} = await getTestState();
await page.setContent('hello<br>goodbye');
const br = (await page.$('br'))!;
using br = (await page.$('br'))!;
const error = await br.click().catch(error_ => {
return error_;
});
@ -345,7 +345,7 @@ describe('ElementHandle specs', function () {
return window.requestAnimationFrame(resolve);
});
});
const divHandle = (await page.$('div'))!;
using divHandle = (await page.$('div'))!;
expect(await divHandle.clickablePoint()).toEqual({
x: 45 + 60, // margin + middle point offset
y: 45 + 30, // margin + middle point offset
@ -367,25 +367,25 @@ describe('ElementHandle specs', function () {
await page.setContent(
'<button style="width: 10px; height: 10px; position: absolute; left: -20px"></button>'
);
const handle = await page.locator('button').waitHandle();
using handle = await page.locator('button').waitHandle();
await expect(handle.clickablePoint()).rejects.toBeInstanceOf(Error);
await page.setContent(
'<button style="width: 10px; height: 10px; position: absolute; right: -20px"></button>'
);
const handle2 = await page.locator('button').waitHandle();
using handle2 = await page.locator('button').waitHandle();
await expect(handle2.clickablePoint()).rejects.toBeInstanceOf(Error);
await page.setContent(
'<button style="width: 10px; height: 10px; position: absolute; top: -20px"></button>'
);
const handle3 = await page.locator('button').waitHandle();
using handle3 = await page.locator('button').waitHandle();
await expect(handle3.clickablePoint()).rejects.toBeInstanceOf(Error);
await page.setContent(
'<button style="width: 10px; height: 10px; position: absolute; bottom: -20px"></button>'
);
const handle4 = await page.locator('button').waitHandle();
using handle4 = await page.locator('button').waitHandle();
await expect(handle4.clickablePoint()).rejects.toBeInstanceOf(Error);
});
@ -399,7 +399,7 @@ describe('ElementHandle specs', function () {
return frame.name() === 'frame';
});
const handle = await frame.locator('button').waitHandle();
using handle = await frame.locator('button').waitHandle();
await expect(handle.clickablePoint()).rejects.toBeInstanceOf(Error);
await page.setContent(
@ -409,7 +409,7 @@ describe('ElementHandle specs', function () {
return frame.name() === 'frame2';
});
const handle2 = await frame2.locator('button').waitHandle();
using handle2 = await frame2.locator('button').waitHandle();
await expect(handle2.clickablePoint()).rejects.toBeInstanceOf(Error);
});
@ -428,7 +428,7 @@ describe('ElementHandle specs', function () {
});
});
const frame = page.frames()[1]!;
const divHandle = (await frame.$('div'))!;
using divHandle = (await frame.$('div'))!;
expect(await divHandle.clickablePoint()).toEqual({
x: 20 + 45 + 60, // iframe pos + margin + middle point offset
y: 20 + 45 + 30, // iframe pos + margin + middle point offset
@ -455,7 +455,7 @@ describe('ElementHandle specs', function () {
await page.setContent(
'<div id="not-foo"></div><div class="bar">bar2</div><div class="foo">Foo1</div>'
);
let element = (await waitFor)!;
using element = (await waitFor)!;
if (element instanceof Error) {
throw element;
}
@ -467,13 +467,13 @@ describe('ElementHandle specs', function () {
await element.evaluate(el => {
el.innerHTML = '<div class="bar">bar1</div>';
});
element = (await innerWaitFor)!;
if (element instanceof Error) {
throw element;
using element2 = (await innerWaitFor)!;
if (element2 instanceof Error) {
throw element2;
}
expect(element).toBeDefined();
expect(element2).toBeDefined();
expect(
await element.evaluate(el => {
await element2.evaluate(el => {
return (el as HTMLElement).innerText;
})
).toStrictEqual('bar1');
@ -496,12 +496,12 @@ describe('ElementHandle specs', function () {
</div>`
);
const el1 = (await page.waitForSelector(
using el1 = (await page.waitForSelector(
'#el1'
)) as ElementHandle<HTMLDivElement>;
for (const path of ['//div', './/div']) {
const e = (await el1.waitForXPath(
using e = (await el1.waitForXPath(
path
)) as ElementHandle<HTMLDivElement>;
expect(
@ -518,7 +518,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/scrollable.html');
const button = (await page.$('#button-6'))!;
using button = (await page.$('#button-6'))!;
await button.hover();
expect(
await page.evaluate(() => {
@ -533,7 +533,7 @@ describe('ElementHandle specs', function () {
const {page, server} = await getTestState();
async function getVisibilityForButton(selector: string) {
const button = (await page.$(selector))!;
using button = (await page.$(selector))!;
return await button.isIntersectingViewport();
}
@ -557,7 +557,7 @@ describe('ElementHandle specs', function () {
await page.goto(server.PREFIX + '/offscreenbuttons.html');
// a button almost cannot be seen
// sometimes we expect to return false by isIntersectingViewport1
const button = (await page.$('#btn11'))!;
using button = (await page.$('#btn11'))!;
expect(
await button.isIntersectingViewport({
threshold: 0.001,
@ -570,7 +570,7 @@ describe('ElementHandle specs', function () {
await page.goto(server.PREFIX + '/offscreenbuttons.html');
// a button almost cannot be seen
// sometimes we expect to return false by isIntersectingViewport1
const button = (await page.$('#btn0'))!;
using button = (await page.$('#btn0'))!;
expect(
await button.isIntersectingViewport({
threshold: 1,
@ -615,7 +615,7 @@ describe('ElementHandle specs', function () {
const [invisibleCircle, invisibleSvg] = await Promise.all([
page.$('div circle'),
await page.$('div svg'),
page.$('div svg'),
]);
// Firefox seems slow when using `isIntersectingViewport`
@ -661,7 +661,7 @@ describe('ElementHandle specs', function () {
return document.querySelector(`[id="${selector}"]`);
},
});
const element = (await page.$(
using element = (await page.$(
'getById/foo'
)) as ElementHandle<HTMLDivElement>;
expect(
@ -780,7 +780,7 @@ describe('ElementHandle specs', function () {
await page.setContent(
'<div id="not-foo"></div><div class="bar">bar2</div><div class="foo">Foo1</div>'
);
let element = (await waitFor)!;
using element = (await waitFor)!;
if (element instanceof Error) {
throw element;
}
@ -796,13 +796,13 @@ describe('ElementHandle specs', function () {
el.innerHTML = '<div class="bar">bar1</div>';
});
element = (await innerWaitFor)!;
if (element instanceof Error) {
throw element;
using element2 = (await innerWaitFor)!;
if (element2 instanceof Error) {
throw element2;
}
expect(element).toBeDefined();
expect(element2).toBeDefined();
expect(
await element.evaluate(el => {
await element2.evaluate(el => {
return el.innerText;
})
).toStrictEqual('bar1');
@ -847,7 +847,7 @@ describe('ElementHandle specs', function () {
},
});
const element = (await page.$('getByClass/foo'))!;
using element = (await page.$('getByClass/foo'))!;
expect(element).toBeDefined();
const elements = await page.$$('getByClass/foo');
@ -893,7 +893,7 @@ describe('ElementHandle specs', function () {
},
});
const element = (await page.$(
using element = (await page.$(
'getById/foo'
)) as ElementHandle<HTMLDivElement>;
expect(
@ -908,8 +908,8 @@ describe('ElementHandle specs', function () {
it('should work', async () => {
const {page} = await getTestState();
await page.setContent('<div class="foo">Foo1</div>');
const element = await page.$('.foo');
const div = await element?.toElement('div');
using element = await page.$('.foo');
using div = await element?.toElement('div');
expect(div).toBeDefined();
});
});
@ -917,7 +917,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle[Symbol.dispose]', () => {
it('should work', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle('document');
using handle = await page.evaluateHandle('document');
const spy = sinon.spy(handle, Symbol.dispose);
{
using _ = handle;
@ -931,7 +931,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle[Symbol.asyncDispose]', () => {
it('should work', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle('document');
using handle = await page.evaluateHandle('document');
const spy = sinon.spy(handle, Symbol.asyncDispose);
{
await using _ = handle;
@ -945,7 +945,7 @@ describe('ElementHandle specs', function () {
describe('ElementHandle.move', () => {
it('should work', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle('document');
using handle = await page.evaluateHandle('document');
const spy = sinon.spy(handle, Symbol.dispose);
{
using _ = handle;

View File

@ -167,7 +167,7 @@ describe('Emulation', () => {
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/button.html');
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await page.evaluate((button: HTMLElement) => {
return (button.style.marginTop = '200px');
}, button);

View File

@ -367,7 +367,7 @@ describe('Evaluation specs', function () {
const {page} = await getTestState();
await page.setContent('<section>42</section>');
const element = (await page.$('section'))!;
using element = (await page.$('section'))!;
const text = await page.evaluate(e => {
return e.textContent;
}, element);
@ -377,8 +377,9 @@ describe('Evaluation specs', function () {
const {page} = await getTestState();
await page.setContent('<section>39</section>');
const element = (await page.$('section'))!;
using element = (await page.$('section'))!;
expect(element).toBeTruthy();
// We want to dispose early.
await element.dispose();
let error!: Error;
await page
@ -394,7 +395,7 @@ describe('Evaluation specs', function () {
const {page, server} = await getTestState();
await attachFrame(page, 'frame1', server.EMPTY_PAGE);
const bodyHandle = await page.frames()[1]!.$('body');
using bodyHandle = await page.frames()[1]!.$('body');
let error!: Error;
await page
.evaluate(body => {

View File

@ -73,7 +73,7 @@ describe('Frame specs', function () {
await page.goto(server.EMPTY_PAGE);
const mainFrame = page.mainFrame();
const windowHandle = await mainFrame.evaluateHandle(() => {
using windowHandle = await mainFrame.evaluateHandle(() => {
return window;
});
expect(windowHandle).toBeTruthy();

View File

@ -24,7 +24,7 @@ describe('Emulate idle state', () => {
setupTestBrowserHooks();
async function getIdleState(page: Page) {
const stateElement = (await page.$('#state')) as ElementHandle<HTMLElement>;
using stateElement = (await page.$('#state')) as ElementHandle<HTMLElement>;
return await page.evaluate(element => {
return element.innerText;
}, stateElement);

View File

@ -33,7 +33,7 @@ describe('input tests', function () {
await page.goto(server.PREFIX + '/input/fileupload.html');
const filePath = path.relative(process.cwd(), FILE_TO_UPLOAD);
const input = (await page.$('input'))!;
using input = (await page.$('input'))!;
await page.evaluate((e: HTMLElement) => {
(globalThis as any)._inputEvents = [];
e.addEventListener('change', ev => {

View File

@ -27,7 +27,7 @@ describe('JSHandle', function () {
it('should work', async () => {
const {page} = await getTestState();
const windowHandle = await page.evaluateHandle(() => {
using windowHandle = await page.evaluateHandle(() => {
return window;
});
expect(windowHandle).toBeTruthy();
@ -35,7 +35,7 @@ describe('JSHandle', function () {
it('should return the RemoteObject', async () => {
const {page} = await getTestState();
const windowHandle = await page.evaluateHandle(() => {
using windowHandle = await page.evaluateHandle(() => {
return window;
});
expect(windowHandle.remoteObject()).toBeTruthy();
@ -43,7 +43,7 @@ describe('JSHandle', function () {
it('should accept object handle as an argument', async () => {
const {page} = await getTestState();
const navigatorHandle = await page.evaluateHandle(() => {
using navigatorHandle = await page.evaluateHandle(() => {
return navigator;
});
const text = await page.evaluate(e => {
@ -54,7 +54,7 @@ describe('JSHandle', function () {
it('should accept object handle to primitive types', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return 5;
});
const isFive = await page.evaluate(e => {
@ -80,7 +80,7 @@ describe('JSHandle', function () {
it('should accept object handle to unserializable value', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return Infinity;
});
expect(
@ -92,7 +92,7 @@ describe('JSHandle', function () {
it('should use the same JS wrappers', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
(globalThis as any).FOO = 123;
return window;
});
@ -108,14 +108,14 @@ describe('JSHandle', function () {
it('should work', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return {
one: 1,
two: 2,
three: 3,
};
});
const twoHandle = await aHandle.getProperty('two');
using twoHandle = await aHandle.getProperty('two');
expect(await twoHandle.jsonValue()).toEqual(2);
});
});
@ -124,7 +124,7 @@ describe('JSHandle', function () {
it('should work', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return {foo: 'bar'};
});
const json = await aHandle.jsonValue();
@ -134,7 +134,7 @@ describe('JSHandle', function () {
it('works with jsonValues that are not objects', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return ['a', 'b'];
});
const json = await aHandle.jsonValue();
@ -144,12 +144,12 @@ describe('JSHandle', function () {
it('works with jsonValues that are primitives', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return 'foo';
});
expect(await aHandle.jsonValue()).toEqual('foo');
const bHandle = await page.evaluateHandle(() => {
using bHandle = await page.evaluateHandle(() => {
return undefined;
});
expect(await bHandle.jsonValue()).toEqual(undefined);
@ -158,7 +158,7 @@ describe('JSHandle', function () {
it('should work with dates', async () => {
const {page} = await getTestState();
const dateHandle = await page.evaluateHandle(() => {
using dateHandle = await page.evaluateHandle(() => {
return new Date('2017-09-26T00:00:00.000Z');
});
const date = await dateHandle.jsonValue();
@ -168,7 +168,7 @@ describe('JSHandle', function () {
it('should not throw for circular objects', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle(() => {
using handle = await page.evaluateHandle(() => {
const t: {t?: unknown; g: number} = {g: 1};
t.t = t;
return t;
@ -181,20 +181,20 @@ describe('JSHandle', function () {
it('should work', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return {
foo: 'bar',
};
});
const properties = await aHandle.getProperties();
const foo = properties.get('foo')!;
using foo = properties.get('foo')!;
expect(foo).toBeTruthy();
expect(await foo.jsonValue()).toBe('bar');
});
it('should return even non-own properties', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
class A {
a: string;
constructor() {
@ -220,29 +220,29 @@ describe('JSHandle', function () {
it('should work', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return document.body;
});
const element = aHandle.asElement();
using element = aHandle.asElement();
expect(element).toBeTruthy();
});
it('should return null for non-elements', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return 2;
});
const element = aHandle.asElement();
using element = aHandle.asElement();
expect(element).toBeFalsy();
});
it('should return ElementHandle for TextNodes', async () => {
const {page} = await getTestState();
await page.setContent('<div>ee!</div>');
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return document.querySelector('div')!.firstChild;
});
const element = aHandle.asElement();
using element = aHandle.asElement();
expect(element).toBeTruthy();
expect(
await page.evaluate(e => {
@ -256,11 +256,11 @@ describe('JSHandle', function () {
it('should work for primitives', async () => {
const {page} = await getTestState();
const numberHandle = await page.evaluateHandle(() => {
using numberHandle = await page.evaluateHandle(() => {
return 2;
});
expect(numberHandle.toString()).toBe('JSHandle:2');
const stringHandle = await page.evaluateHandle(() => {
using stringHandle = await page.evaluateHandle(() => {
return 'a';
});
expect(stringHandle.toString()).toBe('JSHandle:a');
@ -268,7 +268,7 @@ describe('JSHandle', function () {
it('should work for complicated objects', async () => {
const {page} = await getTestState();
const aHandle = await page.evaluateHandle(() => {
using aHandle = await page.evaluateHandle(() => {
return window;
});
expect(aHandle.toString()).atLeastOneToContain([
@ -337,7 +337,7 @@ describe('JSHandle', function () {
describe('JSHandle[Symbol.dispose]', () => {
it('should work', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle('new Set()');
using handle = await page.evaluateHandle('new Set()');
const spy = sinon.spy(handle, Symbol.dispose);
{
using _ = handle;
@ -351,7 +351,7 @@ describe('JSHandle', function () {
describe('JSHandle[Symbol.asyncDispose]', () => {
it('should work', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle('new Set()');
using handle = await page.evaluateHandle('new Set()');
const spy = sinon.spy(handle, Symbol.asyncDispose);
{
await using _ = handle;
@ -365,7 +365,7 @@ describe('JSHandle', function () {
describe('JSHandle.move', () => {
it('should work', async () => {
const {page} = await getTestState();
const handle = await page.evaluateHandle('new Set()');
using handle = await page.evaluateHandle('new Set()');
const spy = sinon.spy(handle, Symbol.dispose);
{
using _ = handle;

View File

@ -119,7 +119,7 @@ describe('Keyboard', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/textarea.html');
const textarea = (await page.$('textarea'))!;
using textarea = (await page.$('textarea'))!;
await textarea.press('a');
expect(
await page.evaluate(() => {
@ -148,7 +148,7 @@ describe('Keyboard', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/textarea.html');
const textarea = (await page.$('textarea'))!;
using textarea = (await page.$('textarea'))!;
await textarea.press('a', {text: 'ё'});
expect(
await page.evaluate(() => {
@ -444,7 +444,7 @@ describe('Keyboard', function () {
true
);
});
const textarea = (await page.$('textarea'))!;
using textarea = (await page.$('textarea'))!;
await textarea.press('Digit5');
expect(await page.evaluate('keyLocation')).toBe(0);
@ -490,7 +490,7 @@ describe('Keyboard', function () {
server.PREFIX + '/input/textarea.html'
);
const frame = page.frames()[1]!;
const textarea = (await frame.$('textarea'))!;
using textarea = (await frame.$('textarea'))!;
await textarea.type('👹 Tokyo street Japan 🇯🇵');
expect(
await frame.$eval('textarea', textarea => {

View File

@ -863,10 +863,9 @@ describe('Launcher specs', function () {
return page.url() === server.EMPTY_PAGE;
})!;
await pageTwo.reload();
const bodyHandle = await pageTwo.waitForSelector('body', {
using _ = await pageTwo.waitForSelector('body', {
timeout: 10000,
});
await bodyHandle!.dispose();
await browserTwo.close();
} finally {
await close();

View File

@ -42,7 +42,7 @@ describe('Locator', function () {
willClick = true;
})
.click();
const button = await page.$('button');
using button = await page.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -69,7 +69,7 @@ describe('Locator', function () {
willClick = true;
})
.click();
const button = await page.$('button');
using button = await page.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -92,7 +92,7 @@ describe('Locator', function () {
willClick = true;
})
.click();
const button = await page.$('button');
using button = await page.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -114,7 +114,7 @@ describe('Locator', function () {
clicked = true;
})
.click();
const button = await page.$('button');
using button = await page.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -130,7 +130,7 @@ describe('Locator', function () {
<button style="margin-top: 600px;" onclick="this.innerText = 'clicked';">test</button>
`);
await page.locator('button').click();
const button = await page.$('button');
using button = await page.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -144,7 +144,7 @@ describe('Locator', function () {
await page.setContent(`
<button style="display: none;" onclick="this.innerText = 'clicked';">test</button>
`);
const button = await page.$('button');
using button = await page.$('button');
const result = page
.locator('button')
.click()
@ -177,7 +177,7 @@ describe('Locator', function () {
await page.setContent(`
<button disabled onclick="this.innerText = 'clicked';">test</button>
`);
const button = await page.$('button');
using button = await page.$('button');
const result = page.locator('button').click();
expect(
await button?.evaluate(el => {
@ -202,7 +202,7 @@ describe('Locator', function () {
await page.setContent(`
<button style="margin-top: 600px;" style="display: none;" disabled onclick="this.innerText = 'clicked';">test</button>
`);
const button = await page.$('button');
using button = await page.$('button');
const result = page.locator('button').click();
expect(
await button?.evaluate(el => {
@ -308,7 +308,7 @@ describe('Locator', function () {
willClick = true;
})
.click();
const button = await frame.$('button');
using button = await frame.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -332,7 +332,7 @@ describe('Locator', function () {
hovered = true;
})
.hover();
const button = await page.$('button');
using button = await page.$('button');
const text = await button?.evaluate(el => {
return el.innerText;
});
@ -361,7 +361,7 @@ describe('Locator', function () {
scrollTop: 500,
scrollLeft: 500,
});
const scrollable = await page.$('div');
using scrollable = await page.$('div');
const scroll = await scrollable?.evaluate(el => {
return el.scrollTop + ' ' + el.scrollLeft;
});
@ -435,7 +435,7 @@ describe('Locator', function () {
await page.setContent(`
<input disabled>
`);
const input = await page.$('input');
using input = await page.$('input');
const result = page.locator('input').fill('test');
expect(
await input?.evaluate(el => {

View File

@ -212,7 +212,7 @@ describe('Mouse', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/input/wheel.html');
const elem = (await page.$('div'))!;
using elem = (await page.$('div'))!;
const boundingBoxBefore = (await elem.boundingBox())!;
expect(boundingBoxBefore).toMatchObject({
width: 115,

View File

@ -378,7 +378,7 @@ describeWithDebugLogs('OOPIF', function () {
button.innerText = 'click';
document.body.appendChild(button);
});
const button = (await frame.waitForSelector('#test-button', {
using button = (await frame.waitForSelector('#test-button', {
visible: true,
}))!;
const result = await button.clickablePoint();

View File

@ -530,7 +530,7 @@ describe('Page', function () {
const {page} = await getTestState();
// Create a custom class
const classHandle = await page.evaluateHandle(() => {
using classHandle = await page.evaluateHandle(() => {
return class CustomClass {};
});
@ -541,10 +541,10 @@ describe('Page', function () {
}, classHandle);
// Validate only one has been added.
const prototypeHandle = await page.evaluateHandle(CustomClass => {
using prototypeHandle = await page.evaluateHandle(CustomClass => {
return CustomClass.prototype;
}, classHandle);
const objectsHandle = await page.queryObjects(prototypeHandle);
using objectsHandle = await page.queryObjects(prototypeHandle);
await expect(
page.evaluate(objects => {
return objects.length;
@ -564,7 +564,7 @@ describe('Page', function () {
await page.goto(server.EMPTY_PAGE);
// Create a custom class
const classHandle = await page.evaluateHandle(() => {
using classHandle = await page.evaluateHandle(() => {
return class CustomClass {};
});
@ -575,10 +575,10 @@ describe('Page', function () {
}, classHandle);
// Validate only one has been added.
const prototypeHandle = await page.evaluateHandle(CustomClass => {
using prototypeHandle = await page.evaluateHandle(CustomClass => {
return CustomClass.prototype;
}, classHandle);
const objectsHandle = await page.queryObjects(prototypeHandle);
using objectsHandle = await page.queryObjects(prototypeHandle);
await expect(
page.evaluate(objects => {
return objects.length;
@ -596,9 +596,10 @@ describe('Page', function () {
it('should fail for disposed handles', async () => {
const {page} = await getTestState();
const prototypeHandle = await page.evaluateHandle(() => {
using prototypeHandle = await page.evaluateHandle(() => {
return HTMLBodyElement.prototype;
});
// We want to dispose early.
await prototypeHandle.dispose();
let error!: Error;
await page.queryObjects(prototypeHandle).catch(error_ => {
@ -609,7 +610,7 @@ describe('Page', function () {
it('should fail primitive values as prototypes', async () => {
const {page} = await getTestState();
const prototypeHandle = await page.evaluateHandle(() => {
using prototypeHandle = await page.evaluateHandle(() => {
return 42;
});
let error!: Error;
@ -1160,7 +1161,7 @@ describe('Page', function () {
await page.goto(server.PREFIX + '/abort-request.html');
const element = await page.$(`#abort`);
using element = await page.$(`#abort`);
await element!.click();
let error = false;
@ -1733,7 +1734,7 @@ describe('Page', function () {
const {page, server} = await getTestState();
await page.goto(server.EMPTY_PAGE);
const scriptHandle = await page.addScriptTag({url: '/injectedfile.js'});
using scriptHandle = await page.addScriptTag({url: '/injectedfile.js'});
expect(scriptHandle.asElement()).not.toBeNull();
expect(
await page.evaluate(() => {
@ -1811,7 +1812,7 @@ describe('Page', function () {
const {page, server} = await getTestState();
await page.goto(server.EMPTY_PAGE);
const scriptHandle = await page.addScriptTag({
using scriptHandle = await page.addScriptTag({
path: path.join(__dirname, '../assets/injectedfile.js'),
});
expect(scriptHandle.asElement()).not.toBeNull();
@ -1839,7 +1840,7 @@ describe('Page', function () {
const {page, server} = await getTestState();
await page.goto(server.EMPTY_PAGE);
const scriptHandle = await page.addScriptTag({
using scriptHandle = await page.addScriptTag({
content: 'window.__injected = 35;',
});
expect(scriptHandle.asElement()).not.toBeNull();
@ -1907,7 +1908,7 @@ describe('Page', function () {
const {page, server} = await getTestState();
await page.goto(server.EMPTY_PAGE);
const styleHandle = await page.addStyleTag({url: '/injectedstyle.css'});
using styleHandle = await page.addStyleTag({url: '/injectedstyle.css'});
expect(styleHandle.asElement()).not.toBeNull();
expect(
await page.evaluate(
@ -1937,7 +1938,7 @@ describe('Page', function () {
const {page, server} = await getTestState();
await page.goto(server.EMPTY_PAGE);
const styleHandle = await page.addStyleTag({
using styleHandle = await page.addStyleTag({
path: path.join(__dirname, '../assets/injectedstyle.css'),
});
expect(styleHandle.asElement()).not.toBeNull();
@ -1955,7 +1956,7 @@ describe('Page', function () {
await page.addStyleTag({
path: path.join(__dirname, '../assets/injectedstyle.css'),
});
const styleHandle = (await page.$('style'))!;
using styleHandle = (await page.$('style'))!;
const styleContent = await page.evaluate((style: HTMLStyleElement) => {
return style.innerHTML;
}, styleHandle);
@ -1966,7 +1967,7 @@ describe('Page', function () {
const {page, server} = await getTestState();
await page.goto(server.EMPTY_PAGE);
const styleHandle = await page.addStyleTag({
using styleHandle = await page.addStyleTag({
content: 'body { background-color: green; }',
});
expect(styleHandle.asElement()).not.toBeNull();

View File

@ -25,10 +25,10 @@ describe('Prerender', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
using button = await page.waitForSelector('button');
await button?.click();
const link = await page.waitForSelector('a');
using link = await page.waitForSelector('a');
await Promise.all([page.waitForNavigation(), link?.click()]);
expect(
await page.evaluate(() => {
@ -41,7 +41,7 @@ describe('Prerender', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
using button = await page.waitForSelector('button');
await button?.click();
await page.goto(server.PREFIX + '/prerender/target.html');
@ -57,11 +57,11 @@ describe('Prerender', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
using button = await page.waitForSelector('button');
await button?.click();
const mainFrame = page.mainFrame();
const link = await mainFrame.waitForSelector('a');
using link = await mainFrame.waitForSelector('a');
await Promise.all([mainFrame.waitForNavigation(), link?.click()]);
expect(mainFrame).toBe(page.mainFrame());
expect(
@ -76,7 +76,7 @@ describe('Prerender', function () {
const {page, server} = await getTestState();
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
using button = await page.waitForSelector('button');
await button?.click();
const mainFrame = page.mainFrame();
@ -100,10 +100,10 @@ describe('Prerender', function () {
});
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
using button = await page.waitForSelector('button');
await button?.click();
const mainFrame = page.mainFrame();
const link = await mainFrame.waitForSelector('a');
using link = await mainFrame.waitForSelector('a');
await Promise.all([mainFrame.waitForNavigation(), link?.click()]);
expect(mainFrame).toBe(page.mainFrame());
expect(
@ -138,9 +138,9 @@ describe('Prerender', function () {
height: 400,
});
await page.goto(server.PREFIX + '/prerender/index.html');
const button = await page.waitForSelector('button');
using button = await page.waitForSelector('button');
await button?.click();
const link = await page.waitForSelector('a');
using link = await page.waitForSelector('a');
await Promise.all([page.waitForNavigation(), link?.click()]);
const result = await page.evaluate(() => {
return {

View File

@ -46,7 +46,7 @@ describe('Query handler tests', function () {
}
it('should find first element in shadow', async () => {
const {page} = await setUpPage();
const div = (await page.$('pierce/.foo')) as ElementHandle<HTMLElement>;
using div = (await page.$('pierce/.foo')) as ElementHandle<HTMLElement>;
const text = await div.evaluate(element => {
return element.textContent;
});
@ -68,8 +68,8 @@ describe('Query handler tests', function () {
});
it('should find first child element', async () => {
const {page} = await setUpPage();
const parentElement = (await page.$('html > div'))!;
const childElement = (await parentElement.$(
using parentElement = (await page.$('html > div'))!;
using childElement = (await parentElement.$(
'pierce/div'
)) as ElementHandle<HTMLElement>;
const text = await childElement.evaluate(element => {
@ -79,7 +79,7 @@ describe('Query handler tests', function () {
});
it('should find all child elements', async () => {
const {page} = await setUpPage();
const parentElement = (await page.$('html > div'))!;
using parentElement = (await page.$('html > div'))!;
const childElements = (await parentElement.$$('pierce/div')) as Array<
ElementHandle<HTMLElement>
>;
@ -115,7 +115,7 @@ describe('Query handler tests', function () {
await page.setContent('<div id="1">a</div><div>a</div>');
const element = await page.$('text/a');
using element = await page.$('text/a');
expect(
await element?.evaluate(e => {
return e.id;
@ -145,7 +145,7 @@ describe('Query handler tests', function () {
document.body.append(div);
});
const element = await page.$('text/a');
using element = await page.$('text/a');
expect(
await element?.evaluate(e => {
return e.textContent;
@ -157,7 +157,7 @@ describe('Query handler tests', function () {
await page.setContent('<div><div>a</div><div>b</div></div>');
const element = await page.$('text/a');
using element = await page.$('text/a');
expect(
await element?.evaluate(e => {
return e.textContent;
@ -169,7 +169,7 @@ describe('Query handler tests', function () {
await page.setContent('<input value="a">');
const element = (await page.$(
using element = (await page.$(
'text/a'
)) as ElementHandle<HTMLInputElement>;
expect(
@ -190,7 +190,7 @@ describe('Query handler tests', function () {
await page.setContent('<div><span>a</span> <span>b</span><div>');
const element = await page.$('text/a b');
using element = await page.$('text/a b');
expect(
await element?.evaluate(e => {
return e.textContent;
@ -203,8 +203,8 @@ describe('Query handler tests', function () {
await page.setContent(
'<div id=target1>text</div><input id=target2 value=text><div id=target3>text</div>'
);
const div = (await page.$('#target1')) as ElementHandle<HTMLDivElement>;
const input = (await page.$(
using div = (await page.$('#target1')) as ElementHandle<HTMLDivElement>;
using input = (await page.$(
'#target2'
)) as ElementHandle<HTMLInputElement>;
@ -271,7 +271,7 @@ describe('Query handler tests', function () {
await page.setContent('<div class="a"><span>a</span></div>');
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
expect(await elementHandle.$(`text/a`)).toBeTruthy();
expect(await elementHandle.$$(`text/a`)).toHaveLength(1);
});
@ -281,7 +281,7 @@ describe('Query handler tests', function () {
await page.setContent('<div class="a"></div>');
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
expect(await elementHandle.$(`text/a`)).toBeFalsy();
expect(await elementHandle.$$(`text/a`)).toHaveLength(0);
});
@ -313,7 +313,7 @@ describe('Query handler tests', function () {
await page.setContent('<div>a</div><div></div>');
const element = await page.$('xpath/html/body/div');
using element = await page.$('xpath/html/body/div');
expect(
await element?.evaluate(e => {
return e.textContent === 'a';
@ -335,7 +335,7 @@ describe('Query handler tests', function () {
await page.setContent('<div class="a">a<span></span></div>');
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
expect(await elementHandle.$(`xpath/span`)).toBeTruthy();
expect(await elementHandle.$$(`xpath/span`)).toHaveLength(1);
});
@ -345,7 +345,7 @@ describe('Query handler tests', function () {
await page.setContent('<div class="a">a</div>');
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
expect(await elementHandle.$(`xpath/span`)).toBeFalsy();
expect(await elementHandle.$$(`xpath/span`)).toHaveLength(0);
});
@ -360,7 +360,7 @@ describe('Query handler tests', function () {
it('should work with CSS selectors', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('div > button');
using element = await page.$('div > button');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -383,7 +383,7 @@ describe('Query handler tests', function () {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
{
const element = await page.$('div >>>> div');
using element = await page.$('div >>>> div');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -423,7 +423,7 @@ describe('Query handler tests', function () {
it('should work with text selectors', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('div ::-p-text(world)');
using element = await page.$('div ::-p-text(world)');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -435,7 +435,7 @@ describe('Query handler tests', function () {
it('should work ARIA selectors', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('div ::-p-aria(world)');
using element = await page.$('div ::-p-aria(world)');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -447,7 +447,7 @@ describe('Query handler tests', function () {
it('should work for ARIA selectors in multiple isolated worlds', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
let element = await page.waitForSelector('::-p-aria(world)');
using element = await page.waitForSelector('::-p-aria(world)');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -456,10 +456,10 @@ describe('Query handler tests', function () {
).toBeTruthy();
// $ would add ARIA query handler to the main world.
await element.$('::-p-aria(world)');
element = await page.waitForSelector('::-p-aria(world)');
assert(element, 'Could not find element');
using element2 = await page.waitForSelector('::-p-aria(world)');
assert(element2, 'Could not find element');
expect(
await element.evaluate(element => {
await element2.evaluate(element => {
return element.id === 'b';
})
).toBeTruthy();
@ -468,7 +468,7 @@ describe('Query handler tests', function () {
it('should work ARIA selectors with role', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('::-p-aria(world[role="button"])');
using element = await page.$('::-p-aria(world[role="button"])');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -480,7 +480,7 @@ describe('Query handler tests', function () {
it('should work ARIA selectors with name and role', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('::-p-aria([name="world"][role="button"])');
using element = await page.$('::-p-aria([name="world"][role="button"])');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -492,7 +492,7 @@ describe('Query handler tests', function () {
it('should work XPath selectors', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('div ::-p-xpath(//button)');
using element = await page.$('div ::-p-xpath(//button)');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -510,7 +510,7 @@ describe('Query handler tests', function () {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
const element = await page.$('::-p-div');
using element = await page.$('::-p-div');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -533,7 +533,7 @@ describe('Query handler tests', function () {
});
{
const element = await page.$('::-p-div(true)');
using element = await page.$('::-p-div(true)');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -542,7 +542,7 @@ describe('Query handler tests', function () {
).toBeTruthy();
}
{
const element = await page.$('::-p-div("true")');
using element = await page.$('::-p-div("true")');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -551,7 +551,7 @@ describe('Query handler tests', function () {
).toBeTruthy();
}
{
const element = await page.$("::-p-div('true')");
using element = await page.$("::-p-div('true')");
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -560,7 +560,7 @@ describe('Query handler tests', function () {
).toBeTruthy();
}
{
const element = await page.$('::-p-div');
using element = await page.$('::-p-div');
assert(element, 'Could not find element');
expect(
await element.evaluate(element => {
@ -573,14 +573,13 @@ describe('Query handler tests', function () {
it('should work with :hover', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
let button = await page.$('div ::-p-text(world)');
using button = await page.$('div ::-p-text(world)');
assert(button, 'Could not find element');
await button.hover();
await button.dispose();
button = await page.$('div ::-p-text(world):hover');
assert(button, 'Could not find element');
const value = await button.evaluate(span => {
using button2 = await page.$('div ::-p-text(world):hover');
assert(button2, 'Could not find element');
const value = await button2.evaluate(span => {
return {textContent: span.textContent, tagName: span.tagName};
});
expect(value).toMatchObject({textContent: 'world', tagName: 'BUTTON'});
@ -643,22 +642,22 @@ describe('Query handler tests', function () {
it('should handle escapes', async () => {
const {server, page} = await getTestState();
await page.goto(`${server.PREFIX}/p-selectors.html`);
let element = await page.$(
using element = await page.$(
':scope >>> ::-p-text(My name is Jun \\(pronounced like "June"\\))'
);
expect(element).toBeTruthy();
element = await page.$(
using element2 = await page.$(
':scope >>> ::-p-text("My name is Jun (pronounced like \\"June\\")")'
);
expect(element).toBeTruthy();
element = await page.$(
expect(element2).toBeTruthy();
using element3 = await page.$(
':scope >>> ::-p-text(My name is Jun \\(pronounced like "June"\\)")'
);
expect(element).toBeFalsy();
element = await page.$(
expect(element3).toBeFalsy();
using element4 = await page.$(
':scope >>> ::-p-text("My name is Jun \\(pronounced like "June"\\))'
);
expect(element).toBeFalsy();
expect(element4).toBeFalsy();
});
});
});

View File

@ -49,7 +49,7 @@ describe('querySelector', function () {
const {page} = await getTestState();
await page.setContent('<section>hello</section><div> world</div>');
const divHandle = (await page.$('div'))!;
using divHandle = (await page.$('div'))!;
const text = await page.$eval(
'section',
(e, div) => {
@ -111,7 +111,7 @@ describe('querySelector', function () {
await page.setContent(
'<section>2</section><section>2</section><section>1</section><div>3</div>'
);
const divHandle = (await page.$('div'))!;
using divHandle = (await page.$('div'))!;
const sum = await page.$$eval(
'section',
(sections, div) => {
@ -152,13 +152,13 @@ describe('querySelector', function () {
const {page} = await getTestState();
await page.setContent('<section>test</section>');
const element = (await page.$('section'))!;
using element = (await page.$('section'))!;
expect(element).toBeTruthy();
});
it('should return null for non-existing element', async () => {
const {page} = await getTestState();
const element = (await page.$('non-existing-element'))!;
using element = (await page.$('non-existing-element'))!;
expect(element).toBe(null);
});
});
@ -218,9 +218,9 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div class="second"><div class="inner">A</div></div></body></html>'
);
const html = (await page.$('html'))!;
const second = (await html.$('.second'))!;
const inner = await second.$('.inner');
using html = (await page.$('html'))!;
using second = (await html.$('.second'))!;
using inner = await second.$('.inner');
const content = await page.evaluate(e => {
return e?.textContent;
}, inner);
@ -233,8 +233,8 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div class="second"><div class="inner">B</div></div></body></html>'
);
const html = (await page.$('html'))!;
const second = await html.$('.third');
using html = (await page.$('html'))!;
using second = await html.$('.third');
expect(second).toBe(null);
});
});
@ -245,7 +245,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div class="tweet"><div class="like">100</div><div class="retweets">10</div></div></body></html>'
);
const tweet = (await page.$('.tweet'))!;
using tweet = (await page.$('.tweet'))!;
const content = await tweet.$eval('.like', node => {
return (node as HTMLElement).innerText;
});
@ -258,7 +258,7 @@ describe('querySelector', function () {
const htmlContent =
'<div class="a">not-a-child-div</div><div id="myId"><div class="a">a-child-div</div></div>';
await page.setContent(htmlContent);
const elementHandle = (await page.$('#myId'))!;
using elementHandle = (await page.$('#myId'))!;
const content = await elementHandle.$eval('.a', node => {
return (node as HTMLElement).innerText;
});
@ -271,7 +271,7 @@ describe('querySelector', function () {
const htmlContent =
'<div class="a">not-a-child-div</div><div id="myId"></div>';
await page.setContent(htmlContent);
const elementHandle = (await page.$('#myId'))!;
using elementHandle = (await page.$('#myId'))!;
const errorMessage = await elementHandle
.$eval('.a', node => {
return (node as HTMLElement).innerText;
@ -291,7 +291,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div class="tweet"><div class="like">100</div><div class="like">10</div></div></body></html>'
);
const tweet = (await page.$('.tweet'))!;
using tweet = (await page.$('.tweet'))!;
const content = await tweet.$$eval('.like', nodes => {
return (nodes as HTMLElement[]).map(n => {
return n.innerText;
@ -306,7 +306,7 @@ describe('querySelector', function () {
const htmlContent =
'<div class="a">not-a-child-div</div><div id="myId"><div class="a">a1-child-div</div><div class="a">a2-child-div</div></div>';
await page.setContent(htmlContent);
const elementHandle = (await page.$('#myId'))!;
using elementHandle = (await page.$('#myId'))!;
const content = await elementHandle.$$eval('.a', nodes => {
return (nodes as HTMLElement[]).map(n => {
return n.innerText;
@ -321,7 +321,7 @@ describe('querySelector', function () {
const htmlContent =
'<div class="a">not-a-child-div</div><div id="myId"></div>';
await page.setContent(htmlContent);
const elementHandle = (await page.$('#myId'))!;
using elementHandle = (await page.$('#myId'))!;
const nodesLength = await elementHandle.$$eval('.a', nodes => {
return nodes.length;
});
@ -336,7 +336,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div>A</div><br/><div>B</div></body></html>'
);
const html = (await page.$('html'))!;
using html = (await page.$('html'))!;
const elements = await html.$$('div');
expect(elements).toHaveLength(2);
const promises = elements.map(element => {
@ -353,7 +353,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><span>A</span><br/><span>B</span></body></html>'
);
const html = (await page.$('html'))!;
using html = (await page.$('html'))!;
const elements = await html.$$('div');
expect(elements).toHaveLength(0);
});
@ -367,7 +367,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div class="second"><div class="inner">A</div></div></body></html>'
);
const html = (await page.$('html'))!;
using html = (await page.$('html'))!;
const second = await html.$x(`./body/div[contains(@class, 'second')]`);
const inner = await second[0]!.$x(`./div[contains(@class, 'inner')]`);
const content = await page.evaluate(e => {
@ -382,7 +382,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div class="second"><div class="inner">B</div></div></body></html>'
);
const html = (await page.$('html'))!;
using html = (await page.$('html'))!;
const second = await html.$x(`/div[contains(@class, 'third')]`);
expect(second).toEqual([]);
});
@ -411,7 +411,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><div>A</div><br/><div>B</div></body></html>'
);
const html = (await page.$('html'))!;
using html = (await page.$('html'))!;
const elements = await html.$$('allArray/div');
expect(elements).toHaveLength(2);
const promises = elements.map(element => {
@ -428,7 +428,7 @@ describe('querySelector', function () {
await page.setContent(
'<html><body><span>A</span><br/><span>B</span></body></html>'
);
const html = (await page.$('html'))!;
using html = (await page.$('html'))!;
const elements = await html.$$('allArray/div');
expect(elements).toHaveLength(0);
});
@ -463,7 +463,7 @@ describe('querySelector', function () {
await page.setContent(
'<section>2</section><section>2</section><section>1</section><div>3</div>'
);
const divHandle = (await page.$('div'))!;
using divHandle = (await page.$('div'))!;
const sum = await page.$$eval(
'allArray/section',
(sections, div) => {

View File

@ -921,7 +921,7 @@ describe('request interception', function () {
return (img.onload = fulfill);
});
}, server.PREFIX);
const img = (await page.$('img'))!;
using img = (await page.$('img'))!;
expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
});
it('should stringify intercepted request response headers', async () => {

View File

@ -868,7 +868,7 @@ describe('request interception', function () {
return (img.onload = fulfill);
});
}, server.PREFIX);
const img = (await page.$('img'))!;
using img = (await page.$('img'))!;
expect(await img.screenshot()).toBeGolden('mock-binary-response.png');
});
it('should stringify intercepted request response headers', async () => {

View File

@ -14,6 +14,8 @@
* limitations under the License.
*/
import assert from 'assert';
import expect from 'expect';
import {getTestState, launch, setupTestBrowserHooks} from './mocha-utils.js';
@ -213,7 +215,7 @@ describe('Screenshots', function () {
await page.evaluate(() => {
return window.scrollBy(50, 100);
});
const elementHandle = (await page.$('.box:nth-of-type(3)'))!;
using elementHandle = (await page.$('.box:nth-of-type(3)'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden('screenshot-element-bounding-box.png');
});
@ -231,7 +233,8 @@ describe('Screenshots', function () {
await page.evaluate(() => {
return window.scrollBy(50, 100);
});
const elementHandle = (await page.$('.box:nth-of-type(3)'))!;
using elementHandle = await page.$('.box:nth-of-type(3)');
assert(elementHandle);
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeTruthy();
} finally {
@ -253,7 +256,7 @@ describe('Screenshots', function () {
</style>
<div></div>
`);
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden('screenshot-element-padding-border.png');
});
@ -277,7 +280,7 @@ describe('Screenshots', function () {
</style>
<div class="to-screenshot"></div>
`);
const elementHandle = (await page.$('div.to-screenshot'))!;
using elementHandle = (await page.$('div.to-screenshot'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden(
'screenshot-element-larger-than-viewport.png'
@ -313,7 +316,7 @@ describe('Screenshots', function () {
<div class="above"></div>
<div class="to-screenshot"></div>
`);
const elementHandle = (await page.$('div.to-screenshot'))!;
using elementHandle = (await page.$('div.to-screenshot'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden(
'screenshot-element-scrolled-into-view.png'
@ -330,7 +333,7 @@ describe('Screenshots', function () {
height: 100px;
background: green;
transform: rotateZ(200deg);">&nbsp;</div>`);
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden('screenshot-element-rotate.png');
});
@ -338,7 +341,7 @@ describe('Screenshots', function () {
const {page} = await getTestState();
await page.setContent('<h1>remove this</h1>');
const elementHandle = (await page.$('h1'))!;
using elementHandle = (await page.$('h1'))!;
await page.evaluate((element: HTMLElement) => {
return element.remove();
}, elementHandle);
@ -353,7 +356,7 @@ describe('Screenshots', function () {
const {page} = await getTestState();
await page.setContent('<div style="width: 50px; height: 0"></div>');
const div = (await page.$('div'))!;
using div = (await page.$('div'))!;
const error = await div.screenshot().catch(error_ => {
return error_;
});
@ -365,7 +368,7 @@ describe('Screenshots', function () {
await page.setContent(
'<div style="width:48.51px;height:19.8px;border:1px solid black;"></div>'
);
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden('screenshot-element-fractional.png');
});
@ -375,7 +378,7 @@ describe('Screenshots', function () {
await page.setContent(
'<div style="position:absolute; top: 10.3px; left: 20.4px;width:50.3px;height:20.2px;border:1px solid black;"></div>'
);
const elementHandle = (await page.$('div'))!;
using elementHandle = (await page.$('div'))!;
const screenshot = await elementHandle.screenshot();
expect(screenshot).toBeGolden('screenshot-element-fractional-offset.png');
});

View File

@ -84,7 +84,7 @@ describe('Stack trace', function () {
it('should work with contiguous evaluation', async () => {
const {page} = await getTestState();
const thrower = await page.evaluateHandle(() => {
using thrower = await page.evaluateHandle(() => {
return () => {
throw new Error('Test');
};

View File

@ -40,7 +40,7 @@ describe('Touchscreen', function () {
const iPhone = KnownDevices['iPhone 6']!;
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/touches.html');
const button = (await page.$('button'))!;
using button = (await page.$('button'))!;
await button.tap();
expect(
await page.evaluate(() => {
@ -54,7 +54,7 @@ describe('Touchscreen', function () {
const iPhone = KnownDevices['iPhone 6']!;
await page.emulate(iPhone);
await page.goto(server.PREFIX + '/input/touches-move.html');
const touch = (await page.$('#touch'))!;
using touch = (await page.$('#touch'))!;
const touchObj = (await touch.boundingBox()) as BoundingBox;
await page.touchscreen.touchStart(touchObj.x, touchObj.y);
const movePosx = 100;

View File

@ -73,7 +73,7 @@ export const attachFrame = async (
frameId: string,
url: string
): Promise<Frame | undefined> => {
const handle = await pageOrFrame.evaluateHandle(attachFrame, frameId, url);
using handle = await pageOrFrame.evaluateHandle(attachFrame, frameId, url);
return (await handle.asElement()?.contentFrame()) ?? undefined;
async function attachFrame(frameId: string, url: string) {

View File

@ -221,11 +221,11 @@ describe('waittask specs', function () {
const {page} = await getTestState();
await page.setContent('<div></div>');
const div = (await page.$('div'))!;
using div = (await page.$('div'))!;
let resolved = false;
const waitForFunction = page
.waitForFunction(
(element: Element) => {
element => {
return element.localName === 'div' && !element.parentElement;
},
{},
@ -432,7 +432,7 @@ describe('waittask specs', function () {
const watchdog = frame.waitForSelector('div');
await frame.evaluate(addElement, 'br');
await frame.evaluate(addElement, 'div');
const eHandle = (await watchdog)!;
using eHandle = (await watchdog)!;
const tagName = await (await eHandle.getProperty('tagName')).jsonValue();
expect(tagName).toBe('DIV');
});
@ -459,7 +459,7 @@ describe('waittask specs', function () {
const watchdog = page.waitForSelector('div');
await otherFrame.evaluate(addElement, 'div');
await page.evaluate(addElement, 'div');
const eHandle = await watchdog;
using eHandle = await watchdog;
expect(eHandle?.frame).toBe(page.mainFrame());
});
@ -473,7 +473,7 @@ describe('waittask specs', function () {
const waitForSelectorPromise = frame2.waitForSelector('div');
await frame1.evaluate(addElement, 'div');
await frame2.evaluate(addElement, 'div');
const eHandle = await waitForSelectorPromise;
using eHandle = await waitForSelectorPromise;
expect(eHandle?.frame).toBe(frame2);
});
@ -513,7 +513,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {visible: true});
await page.setContent('<div style="display: none">text</div>');
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -529,7 +529,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {visible: true});
await page.setContent('<div style="visibility: hidden">text</div>');
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -551,7 +551,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {visible: true});
await page.setContent('<div style="width: 0">text</div>');
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -578,7 +578,7 @@ describe('waittask specs', function () {
await page.setContent(
`<div style='display: none; visibility: hidden;'><div id="inner">hi</div></div>`
);
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -600,7 +600,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {hidden: true});
await page.setContent(`<div style='display: block;'>text</div>`);
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -616,7 +616,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {hidden: true});
await page.setContent(`<div style='display: block;'>text</div>`);
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -632,7 +632,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {hidden: true});
await page.setContent('<div>text</div>');
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -648,7 +648,7 @@ describe('waittask specs', function () {
const promise = page.waitForSelector('div', {hidden: true});
await page.setContent(`<div>text</div>`);
const element = await page.evaluateHandle(() => {
using element = await page.evaluateHandle(() => {
return document.getElementsByTagName('div')[0]!;
});
await expect(
@ -662,7 +662,7 @@ describe('waittask specs', function () {
it('should return null if waiting to hide non-existing element', async () => {
const {page} = await getTestState();
const handle = await page.waitForSelector('non-existing', {
using handle = await page.waitForSelector('non-existing', {
hidden: true,
});
expect(handle).toBe(null);
@ -779,7 +779,7 @@ describe('waittask specs', function () {
const waitForXPathPromise = frame2.waitForXPath('//div');
await frame1.evaluate(addElement, 'div');
await frame2.evaluate(addElement, 'div');
const eHandle = await waitForXPathPromise;
using eHandle = await waitForXPathPromise;
expect(eHandle?.frame).toBe(frame2);
});
it('should throw when frame is detached', async () => {
@ -823,7 +823,7 @@ describe('waittask specs', function () {
it('hidden should return null if the element is not found', async () => {
const {page} = await getTestState();
const waitForXPath = await page.waitForXPath('//div', {hidden: true});
using waitForXPath = await page.waitForXPath('//div', {hidden: true});
expect(waitForXPath).toBe(null);
});
@ -832,7 +832,7 @@ describe('waittask specs', function () {
await page.setContent(`<div style='display: none;'>text</div>`);
const waitForXPath = await page.waitForXPath('//div', {hidden: true});
using waitForXPath = await page.waitForXPath('//div', {hidden: true});
expect(waitForXPath).toBeInstanceOf(ElementHandle);
});
@ -854,7 +854,7 @@ describe('waittask specs', function () {
const {page} = await getTestState();
await page.setContent(`<div>some text</div>`);
const text = await page.waitForXPath('//div/text()');
using text = await page.waitForXPath('//div/text()');
expect(await (await text!.getProperty('nodeType')!).jsonValue()).toBe(
3 /* Node.TEXT_NODE */
);

View File

@ -47,11 +47,11 @@ describe('Workers', function () {
const {page} = await getTestState();
const workerCreatedPromise = waitEvent<WebWorker>(page, 'workercreated');
const workerObj = await page.evaluateHandle(() => {
using workerObj = await page.evaluateHandle(() => {
return new Worker('data:text/javascript,1');
});
const worker = await workerCreatedPromise;
const workerThisObj = await worker.evaluateHandle(() => {
using workerThisObj = await worker.evaluateHandle(() => {
return this;
});
const workerDestroyedPromise = waitEvent(page, 'workerdestroyed');