1
- import { expect , Locator , Page } from '@playwright/test' ;
1
+ import {
2
+ expect , JSHandle , Locator , Page ,
3
+ } from '@playwright/test' ;
2
4
3
5
export type SpecialSelector = { modifier : 'first' } | { modifier : 'last' } | {
4
6
modifier : 'contains' ,
@@ -93,6 +95,9 @@ export type Action = AssertActions | {
93
95
| 'port'
94
96
| 'protocol'
95
97
| 'search'
98
+ } | {
99
+ type : 'handle' ,
100
+ global : 'window' | 'document' ,
96
101
} ;
97
102
98
103
let queue : Array < Action > = [ ] ;
@@ -115,7 +120,10 @@ function resolveSelectorItem(parent: Locator | Page, selector: Selector[number])
115
120
}
116
121
}
117
122
118
- export type Subject = { type : 'locator' , value : Locator } | { type : 'value' , value : unknown } ;
123
+ export type Subject =
124
+ { type : 'locator' , value : Locator }
125
+ | { type : 'value' , value : unknown }
126
+ | { type : 'handle' , value : JSHandle } ;
119
127
120
128
export async function evaluateAction (
121
129
page : Page ,
@@ -124,6 +132,16 @@ export async function evaluateAction(
124
132
aliasMap : Record < string , Subject > ,
125
133
) : Promise < Subject > {
126
134
switch ( action . type ) {
135
+ case 'handle' : {
136
+ switch ( action . global ) {
137
+ case 'window' :
138
+ return { type : 'handle' , value : await page . evaluateHandle ( ( ) => window ) } ;
139
+ case 'document' :
140
+ return { type : 'handle' , value : await page . evaluateHandle ( ( ) => window . document ) } ;
141
+ default :
142
+ throw new Error ( 'Unknown handle value' ) ;
143
+ }
144
+ }
127
145
case 'alias' : {
128
146
// eslint-disable-next-line no-param-reassign
129
147
aliasMap [ action . name ] = subject ;
@@ -195,13 +213,30 @@ export async function evaluateAction(
195
213
} else {
196
214
expect ( subject . value ) . toContain ( action . value ) ;
197
215
}
198
- } else if ( action . negation ) {
199
- await expect ( subject . value ) . not . toContainText ( action . value ) ;
200
- } else {
201
- await expect ( subject . value ) . toContainText ( action . value ) ;
202
216
}
203
- break ;
217
+ if ( subject . type === 'locator' ) {
218
+ if ( action . negation ) {
219
+ await expect ( subject . value ) . not . toContainText ( action . value ) ;
220
+ } else {
221
+ await expect ( subject . value ) . toContainText ( action . value ) ;
222
+ }
223
+ break ;
224
+ }
225
+ throw new Error ( 'Handle subject is not implemented' ) ;
204
226
case 'property' :
227
+ if ( subject . type === 'handle' ) {
228
+ const result = await page . evaluate (
229
+ ( ctx ) => Object . prototype . hasOwnProperty . call ( ctx . subject , ctx . property ) ,
230
+ { subject : subject . value , property : action . value } ,
231
+ ) ;
232
+ if ( action . negation ) {
233
+ expect ( result ) . not . toBe ( true ) ;
234
+ } else {
235
+ expect ( result ) . toBe ( true ) ;
236
+ }
237
+ break ;
238
+ }
239
+
205
240
if ( action . negation ) {
206
241
expect ( subject . value ) . not . toHaveProperty ( action . value ) ;
207
242
} else {
@@ -229,13 +264,17 @@ export async function evaluateAction(
229
264
expect ( Object . keys ( subject . value as any ) ) . not . toHaveLength ( 0 ) ;
230
265
break ;
231
266
}
232
- } else if ( action . negation ) {
233
- await expect ( subject . value ) . not . toBeEmpty ( ) ;
267
+ }
268
+ if ( subject . type === 'locator' ) {
269
+ if ( action . negation ) {
270
+ await expect ( subject . value ) . not . toBeEmpty ( ) ;
271
+ break ;
272
+ } else {
273
+ await expect ( subject . value ) . toBeEmpty ( ) ;
274
+ }
234
275
break ;
235
- } else {
236
- await expect ( subject . value ) . toBeEmpty ( ) ;
237
276
}
238
- break ;
277
+ throw new Error ( 'Handle subject is not implemented' ) ;
239
278
case 'equal' :
240
279
if ( action . negation ) {
241
280
expect ( subject . value ) . not . toBe ( action . value ) ;
0 commit comments