File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -38,12 +38,16 @@ export function string(value: string): ts.StringLiteral {
3838
3939export function literal ( {
4040 value,
41- } : NodeOptions < ts . Literal , 'value' > ) : ts . Literal {
41+ } : NodeOptions < ts . Literal , 'value' > ) : ts . Expression {
4242 switch ( typeof value ) {
4343 case 'string' :
4444 return string ( value )
4545
4646 case 'number' :
47+ if ( isNaN ( value ) ) {
48+ return identifier ( 'NaN' )
49+ }
50+
4751 return {
4852 ...baseProps ,
4953 type : NodeType . Literal ,
Original file line number Diff line number Diff line change 1+ import { Popover , TextField } from '@radix-ui/themes'
2+ import { useState } from 'react'
3+
4+ import { FieldGroup } from '@/components/Form'
5+
6+ import { ValuePopoverBadge } from '../components'
7+
8+ import { toFieldErrors } from './utils'
9+
10+ interface TimeoutForm {
11+ timeout : number
12+ onChange : ( timeout : number ) => void
13+ }
14+
15+ export function TimeoutForm ( { timeout, onChange } : TimeoutForm ) {
16+ const [ isPopoverOpen , setIsPopoverOpen ] = useState ( false )
17+ const [ isTouched , setIsTouched ] = useState ( false )
18+
19+ const error = validateTimeout ( timeout )
20+
21+ return (
22+ < Popover . Root
23+ open = { isPopoverOpen }
24+ onOpenChange = { ( open ) => {
25+ setIsPopoverOpen ( open )
26+ if ( ! open ) {
27+ setIsTouched ( true )
28+ }
29+ } }
30+ >
31+ < Popover . Trigger >
32+ < ValuePopoverBadge
33+ displayValue = {
34+ < > { isNaN ( timeout ) ? 'Enter a timeout' : `${ timeout } ms` } </ >
35+ }
36+ error = { error }
37+ />
38+ </ Popover . Trigger >
39+ < Popover . Content align = "start" size = "1" width = "300px" >
40+ < FieldGroup
41+ name = "timeout"
42+ label = "Timeout (ms)"
43+ labelSize = "1"
44+ mb = "0"
45+ errors = { toFieldErrors ( 'timeout' , isTouched ? error : undefined ) }
46+ >
47+ < TextField . Root
48+ size = "1"
49+ name = "timeout"
50+ type = "number"
51+ value = { isNaN ( timeout ) ? '' : timeout }
52+ onChange = { ( e ) => {
53+ const trimmed = e . target . value . trim ( )
54+
55+ if ( ! trimmed ) {
56+ onChange ( NaN )
57+
58+ return
59+ }
60+
61+ onChange ( Number ( trimmed ) )
62+ } }
63+ onBlur = { ( ) => setIsTouched ( true ) }
64+ />
65+ </ FieldGroup >
66+ </ Popover . Content >
67+ </ Popover . Root >
68+ )
69+ }
70+
71+ function validateTimeout ( value : number ) {
72+ if ( isNaN ( value ) ) {
73+ return 'Timeout must be a number'
74+ }
75+
76+ if ( value < 0 ) {
77+ return 'Timeout must be >= 0'
78+ }
79+ }
Original file line number Diff line number Diff line change 1+ import { Grid } from '@radix-ui/themes'
2+
3+ import { PageWaitForTimeoutAction } from '@/main/runner/schema'
4+
5+ import { TimeoutForm } from '../../ActionForms/forms/TimeoutForm'
6+ import { WithEditorMetadata } from '../../types'
7+
8+ interface WaitForTimeoutActionBodyProps {
9+ action : WithEditorMetadata < PageWaitForTimeoutAction >
10+ onChange : ( action : WithEditorMetadata < PageWaitForTimeoutAction > ) => void
11+ }
12+
13+ export function WaitForTimeoutActionBody ( {
14+ action,
15+ onChange,
16+ } : WaitForTimeoutActionBodyProps ) {
17+ const handleTimeoutChange = ( timeout : number ) => {
18+ onChange ( { ...action , timeout } )
19+ }
20+
21+ return (
22+ < Grid columns = "max-content auto max-content" gap = "2" align = "center" >
23+ Wait for
24+ < TimeoutForm timeout = { action . timeout } onChange = { handleTimeoutChange } />
25+ </ Grid >
26+ )
27+ }
Original file line number Diff line number Diff line change 1+ export * from './WaitForTimeoutActionBody'
Original file line number Diff line number Diff line change @@ -4,4 +4,5 @@ export * from './FillAction'
44export * from './GoToAction'
55export * from './PageReloadAction'
66export * from './UncheckAction'
7+ export * from './WaitForTimeoutAction'
78export * from './WaitForAction'
Original file line number Diff line number Diff line change @@ -106,14 +106,20 @@ function NewActionMenu({ onAddAction }: NewActionMenuProps) {
106106 Uncheck input
107107 </ DropdownMenu . Item >
108108 < DropdownMenu . Separator />
109-
110109 < DropdownMenu . Item
111110 onClick = { ( ) => {
112111 onAddAction ( 'locator.waitFor' )
113112 } }
114113 >
115114 Wait for element
116115 </ DropdownMenu . Item >
116+ < DropdownMenu . Item
117+ onClick = { ( ) => {
118+ onAddAction ( 'page.waitForTimeout' )
119+ } }
120+ >
121+ Wait for timeout
122+ </ DropdownMenu . Item >
117123 < DropdownMenu . Separator />
118124 < DropdownMenu . Item
119125 onClick = { ( ) => {
Original file line number Diff line number Diff line change 11import { Code } from '@radix-ui/themes'
22import {
33 CircleQuestionMarkIcon ,
4+ ClockIcon ,
45 GlobeIcon ,
56 MousePointerClickIcon ,
67 RefreshCwIcon ,
@@ -19,6 +20,7 @@ import {
1920 PageReloadActionBody ,
2021 UncheckActionBody ,
2122 WaitForActionBody ,
23+ WaitForTimeoutActionBody ,
2224} from './Actions'
2325import { BrowserActionInstance } from './types'
2426import { createDefaultLocatorOptions } from './utils'
@@ -150,6 +152,17 @@ const actionEditors: ActionEditorRegistry = {
150152 method : 'page.reload' ,
151153 } ) ,
152154 } ,
155+ 'page.waitForTimeout' : {
156+ icon : < ClockIcon aria-hidden = "true" /> ,
157+ render : ( { action, onChange } ) => (
158+ < WaitForTimeoutActionBody action = { action } onChange = { onChange } />
159+ ) ,
160+ create : ( ) => ( {
161+ id : crypto . randomUUID ( ) ,
162+ method : 'page.waitForTimeout' ,
163+ timeout : 1000 ,
164+ } ) ,
165+ } ,
153166 'locator.waitFor' : {
154167 icon : < TimerIcon aria-hidden = "true" /> ,
155168 render : ( { action, onChange } ) => (
You can’t perform that action at this time.
0 commit comments