Skip to content

Commit f782e79

Browse files
fix: wait for CSS assertions in playwright base (#4386)
1 parent 00743c5 commit f782e79

File tree

1 file changed

+45
-20
lines changed

1 file changed

+45
-20
lines changed

playwright-e2e/common/base.ts

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -302,29 +302,54 @@ export class BaseMethods {
302302
isMultiple = false,
303303
isInclude = true,
304304
}: ElementPropertyOptions): Promise<void> {
305-
let locator = this.resolveLocator(selector, { parentSelector, text, index });
306-
307-
if (isMultiple) {
308-
const handles = await locator.elementHandles();
309-
for (const handle of handles) {
310-
const actual = await this.getProperty(handle, prop, attr);
311-
if (isInclude) {
312-
expect(actual).toContain(value);
313-
} else {
314-
expect(actual).not.toContain(value);
305+
const locator = this.resolveLocator(selector, { parentSelector, text, index });
306+
const expectationMessage =
307+
attr === 'attribute'
308+
? `Expected attribute "${prop}" on selector "${selector}" to ${isInclude ? '' : 'not '}include "${value}".`
309+
: `Expected CSS property "${prop}" on selector "${selector}" to ${isInclude ? '' : 'not '}include "${value}".`;
310+
311+
const doesMatch = (actual: string): boolean => (isInclude ? actual.includes(value) : !actual.includes(value));
312+
313+
await expect
314+
.poll(async () => {
315+
if (isMultiple) {
316+
const handles = await locator.elementHandles();
317+
if (handles.length === 0) {
318+
return false;
319+
}
320+
321+
try {
322+
const results = await Promise.all(
323+
handles.map(async handle => {
324+
try {
325+
return await this.getProperty(handle, prop, attr);
326+
} finally {
327+
await handle.dispose();
328+
}
329+
}),
330+
);
331+
332+
return results.every(doesMatch);
333+
} catch {
334+
return false;
335+
}
315336
}
316-
}
317337

318-
return;
319-
}
320-
321-
const actual = await this.getProperty(await locator.elementHandle(), prop, attr);
338+
const handle = await locator.elementHandle({ timeout: 0 });
339+
if (!handle) {
340+
return false;
341+
}
322342

323-
if (isInclude) {
324-
expect(actual).toContain(value);
325-
} else {
326-
expect(actual).not.toContain(value);
327-
}
343+
try {
344+
const actual = await this.getProperty(handle, prop, attr);
345+
return doesMatch(actual);
346+
} catch {
347+
return false;
348+
} finally {
349+
await handle.dispose();
350+
}
351+
}, { message: expectationMessage })
352+
.toBeTruthy();
328353
}
329354

330355
async checkUrlText(urlPart: string, isInclude: boolean = false): Promise<void> {

0 commit comments

Comments
 (0)