@@ -302,29 +302,54 @@ export class BaseMethods {
302
302
isMultiple = false ,
303
303
isInclude = true ,
304
304
} : 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
+ }
315
336
}
316
- }
317
337
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
+ }
322
342
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 ( ) ;
328
353
}
329
354
330
355
async checkUrlText ( urlPart : string , isInclude : boolean = false ) : Promise < void > {
0 commit comments