11import { Locator , expect } from '@playwright/test' ;
2- import { throwTimeoutError } from './utils/utils' ;
2+
3+ class SoftAssertionError extends Error {
4+ name = 'SoftAssertionError' ;
5+ }
36
47export const conditionValidations = {
58 PRESENT : 'present' ,
6- // CLICKABLE: 'clickable',
9+ CLICKABLE : 'clickable' ,
710 VISIBLE : 'visible' ,
811 INVISIBLE : 'invisible' ,
912 IN_VIEWPORT : 'in viewport' ,
@@ -13,57 +16,58 @@ export const conditionValidations = {
1316
1417const notClause = '(not )?' ;
1518const toBeClause = 'to (?:be )?' ;
19+ const softClause = '(softly )?'
1620const validationClause = `(${ Object . values ( conditionValidations ) . join ( '|' ) } )` ;
1721
18- export const conditionWaitExtractRegexp = new RegExp ( `^${ notClause } ${ toBeClause } ${ validationClause } $` ) ;
19- export const conditionWaitRegexp = new RegExp ( `(${ notClause } ${ toBeClause } ${ validationClause } )` ) ;
22+ export const conditionWaitExtractRegexp = new RegExp ( `^${ notClause } ${ toBeClause } ${ softClause } ${ validationClause } $` ) ;
2023
24+ const makeExpect = ( element : Locator , reverse : boolean , message : string ) => {
25+ const eMessage = expect ( element , message ) ;
26+ return reverse ? eMessage . not : eMessage ;
27+ }
2128const waits = {
2229 [ conditionValidations . PRESENT ] : (
2330 element : Locator ,
2431 reverse : boolean ,
2532 timeout : number ,
2633 timeoutMsg : string
27- ) => element . waitFor ( { state : reverse ? 'detached' : 'attached' , timeout } ) ,
34+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeAttached ( { timeout } ) ,
2835 [ conditionValidations . VISIBLE ] : (
2936 element : Locator ,
3037 reverse : boolean ,
3138 timeout : number ,
3239 timeoutMsg : string
33- ) => element . waitFor ( { state : reverse ? 'hidden' : 'visible' , timeout } ) ,
40+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeVisible ( { timeout } ) ,
3441 [ conditionValidations . INVISIBLE ] : (
3542 element : Locator ,
3643 reverse : boolean ,
3744 timeout : number ,
3845 timeoutMsg : string
39- ) => element . waitFor ( { state : reverse ? 'visible' : 'hidden' , timeout } ) ,
46+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeHidden ( { timeout } ) ,
4047 [ conditionValidations . IN_VIEWPORT ] : (
4148 element : Locator ,
4249 reverse : boolean ,
4350 timeout : number ,
4451 timeoutMsg : string
45- ) => throwTimeoutError ( ( ) => expect ( async ( ) => {
46- const e = reverse ? expect ( element ) . not : expect ( element ) ;
47- await e . toBeInViewport ( ) ;
48- } ) . toPass ( { timeout } ) , timeoutMsg ) ,
52+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeInViewport ( { timeout } ) ,
4953 [ conditionValidations . ENABLED ] : (
5054 element : Locator ,
5155 reverse : boolean ,
5256 timeout : number ,
5357 timeoutMsg : string
54- ) => throwTimeoutError ( ( ) => expect ( async ( ) => {
55- const e = reverse ? expect ( element ) . not : expect ( element ) ;
56- await e . toBeEnabled ( ) ;
57- } ) . toPass ( { timeout } ) , timeoutMsg ) ,
58+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeEnabled ( { timeout } ) ,
5859 [ conditionValidations . DISABLED ] : (
5960 element : Locator ,
6061 reverse : boolean ,
6162 timeout : number ,
6263 timeoutMsg : string
63- ) => throwTimeoutError ( ( ) => expect ( async ( ) => {
64- const e = reverse ? expect ( element ) . not : expect ( element ) ;
65- await e . toBeDisabled ( ) ;
66- } ) . toPass ( { timeout } ) , timeoutMsg )
64+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeDisabled ( { timeout } ) ,
65+ [ conditionValidations . CLICKABLE ] : (
66+ element : Locator ,
67+ reverse : boolean ,
68+ timeout : number ,
69+ timeoutMsg : string
70+ ) => makeExpect ( element , reverse , timeoutMsg ) . toBeEnabled ( { timeout } ) ,
6771}
6872/**
6973 * Wait for condition
@@ -78,8 +82,22 @@ export async function conditionWait(
7882 validationType : string ,
7983 timeout : number = 10000 ,
8084 reverse : boolean = false
81- ) {
85+ ) : Promise < void > {
8286 const timeoutMsg : string = `Element is${ reverse ? '' : ' not' } ${ validationType } ` ;
8387 const waitFn = waits [ validationType ] ;
8488 await waitFn ( element , reverse , timeout , timeoutMsg ) ;
8589}
90+
91+ export function getConditionWait ( condition : string ) : Function {
92+ const match = condition . match ( conditionWaitExtractRegexp ) as RegExpMatchArray ;
93+ if ( ! match ) throw new Error ( `${ condition } wait is not implemented` ) ;
94+ const [ _ , reverse , soft , validation ] = match ;
95+ return async function ( element : Locator , timeout : number ) {
96+ try {
97+ await conditionWait ( element , validation , timeout , Boolean ( reverse ) )
98+ } catch ( error ) {
99+ if ( soft && error instanceof Error ) throw new SoftAssertionError ( error . message , { cause : error } ) ;
100+ throw error ;
101+ }
102+ }
103+ }
0 commit comments