Skip to content

Commit f9e95a6

Browse files
wip
1 parent 4e17c1c commit f9e95a6

File tree

10 files changed

+92
-20
lines changed

10 files changed

+92
-20
lines changed

src/codegen/browser/code/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ function isBrowserScenario(scenario: ir.Scenario) {
5757
case 'Identifier':
5858
case 'StringLiteral':
5959
case 'NullLiteral':
60+
case 'SelectOptionValueExpression':
6061
case 'PromiseAllExpression':
6162
return false
6263

src/codegen/browser/code/scenario.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,16 @@ function emitSelectOptionsExpression(
298298
.done()
299299
}
300300

301+
function emitSelectOptionValueExpression(
302+
expression: ir.SelectOptionValueExpression
303+
): ts.Expression {
304+
return fromObjectLiteral({
305+
value: expression.value,
306+
label: expression.label,
307+
index: expression.index,
308+
})
309+
}
310+
301311
function emitExpectExpression(
302312
context: ScenarioContext,
303313
expression: ir.ExpectExpression
@@ -527,6 +537,9 @@ function emitExpression(
527537
case 'CheckExpression':
528538
return emitCheckExpression(context, expression)
529539

540+
case 'SelectOptionValueExpression':
541+
return emitSelectOptionValueExpression(expression)
542+
530543
case 'SelectOptionsExpression':
531544
return emitSelectOptionsExpression(context, expression)
532545

src/codegen/browser/intermediate/ast.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ export interface CheckExpression {
116116
checked: boolean
117117
}
118118

119+
export interface SelectOptionValueExpression {
120+
type: 'SelectOptionValueExpression'
121+
value?: string
122+
label?: string
123+
index?: number
124+
}
125+
119126
export interface SelectOptionsExpression {
120127
type: 'SelectOptionsExpression'
121128
locator: Expression
@@ -218,6 +225,7 @@ export type Expression =
218225
| ClickOptionsExpression
219226
| FillTextExpression
220227
| CheckExpression
228+
| SelectOptionValueExpression
221229
| SelectOptionsExpression
222230
| ExpectExpression
223231
| WaitForExpression

src/codegen/browser/intermediate/index.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -288,10 +288,19 @@ function emitSelectOptionsNode(
288288
expression: {
289289
type: 'SelectOptionsExpression',
290290
locator,
291-
selected: node.selected.map((value) => ({
292-
type: 'StringLiteral',
293-
value,
294-
})),
291+
selected: node.selected.map((value) => {
292+
if (typeof value === 'string') {
293+
return {
294+
type: 'StringLiteral',
295+
value,
296+
}
297+
}
298+
299+
return {
300+
type: 'SelectOptionValueExpression',
301+
...value,
302+
}
303+
}),
295304
multiple: node.multiple,
296305
},
297306
})

src/codegen/browser/intermediate/variables.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ function substituteExpression(
170170
locator: substituteExpression(node.locator, substitutions),
171171
}
172172

173+
case 'SelectOptionValueExpression':
174+
return node
175+
173176
case 'SelectOptionsExpression':
174177
return {
175178
type: 'SelectOptionsExpression',

src/codegen/browser/test.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -423,18 +423,24 @@ function buildBrowserNodeGraphFromActions(
423423
locator: getLocator(action.locator),
424424
},
425425
}
426-
case 'locator.selectOption':
426+
case 'locator.selectOption': {
427+
const nonEmpty = action.values.filter(
428+
(v) =>
429+
(v.value !== undefined && v.value !== '') ||
430+
(v.label !== undefined && v.label !== '') ||
431+
v.index !== undefined
432+
)
433+
const selected = nonEmpty.length > 0 ? nonEmpty : ['']
427434
return {
428435
type: 'select-options',
429436
nodeId: crypto.randomUUID(),
430-
selected: action.values.map(
431-
(v) => v.value ?? v.label ?? String(v.index ?? '')
432-
),
433-
multiple: action.values.length > 1,
437+
selected,
438+
multiple: nonEmpty.length > 1,
434439
inputs: {
435440
locator: getLocator(action.locator),
436441
},
437442
}
443+
}
438444
case 'page.waitForNavigation':
439445
case 'page.close':
440446
case 'page.*':

src/codegen/browser/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export interface TypeTextNode extends NodeBase {
7070

7171
export interface SelectOptionsNode extends NodeBase {
7272
type: 'select-options'
73-
selected: string[]
73+
selected: (string | { value?: string; label?: string; index?: number })[]
7474
multiple: boolean
7575
inputs: {
7676
previous?: NodeRef

src/views/BrowserTestEditor/ActionForms/forms/SelectOptionValuesForm.tsx

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ type SelectOptionValue = LocatorSelectOptionAction['values'][number]
2121

2222
type MatchType = 'value' | 'label' | 'index'
2323

24+
function isNonEmptyValue(entry: SelectOptionValue): boolean {
25+
if (entry.label !== undefined) return entry.label !== ''
26+
if (entry.index !== undefined) return true
27+
return (entry.value ?? '') !== ''
28+
}
29+
2430
function getMatchType(entry: SelectOptionValue): MatchType {
2531
if (entry.label !== undefined) return 'label'
2632
if (entry.index !== undefined) return 'index'
@@ -54,6 +60,14 @@ export function SelectOptionValuesForm({
5460
onChange,
5561
}: SelectOptionValuesFormProps) {
5662
const [isPopoverOpen, setIsPopoverOpen] = useState(false)
63+
const [isTouched, setIsTouched] = useState(false)
64+
65+
const handlePopoverOpenChange = (open: boolean) => {
66+
setIsPopoverOpen(open)
67+
if (!open) {
68+
setIsTouched(true)
69+
}
70+
}
5771

5872
const handleChangeType = (index: number, type: MatchType) => {
5973
const current = values[index]
@@ -81,14 +95,24 @@ export function SelectOptionValuesForm({
8195
onChange(values.filter((_, i) => i !== index))
8296
}
8397

98+
const nonEmptyValues = values.filter(isNonEmptyValue)
99+
84100
return (
85-
<Popover.Root open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
101+
<Popover.Root open={isPopoverOpen} onOpenChange={handlePopoverOpenChange}>
86102
<Popover.Trigger>
87103
<ValuePopoverBadge
88104
displayValue={
89-
values.length === 0 ? '(none)' : <SelectOptions options={values} />
105+
nonEmptyValues.length === 0 ? (
106+
'option(s)'
107+
) : (
108+
<SelectOptions options={nonEmptyValues} />
109+
)
110+
}
111+
error={
112+
isTouched && nonEmptyValues.length === 0
113+
? 'At least one option is required'
114+
: null
90115
}
91-
error={values.length === 0 ? 'At least one option is required' : null}
92116
/>
93117
</Popover.Trigger>
94118
<Popover.Content align="start" size="1" width="360px">

src/views/BrowserTestEditor/Actions/SelectOptionAction/SelectOptionActionBody.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,16 @@ export function SelectOptionActionBody({
3333
width="100%"
3434
>
3535
Select
36-
<LocatorForm
37-
state={action.locator}
38-
onChange={handleChangeLocator}
39-
suggestedRoles={['combobox', 'listbox']}
40-
/>
41-
with
4236
<SelectOptionValuesForm
4337
values={action.values}
4438
onChange={handleChangeValues}
4539
/>
40+
in
41+
<LocatorForm
42+
state={action.locator}
43+
onChange={handleChangeLocator}
44+
suggestedRoles={['combobox', 'listbox', 'menu', 'radiogroup']}
45+
/>
4646
</Grid>
4747
)
4848
}

src/views/BrowserTestEditor/actionEditorRegistry.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,15 @@ const actionEditors: ActionEditorRegistry = {
142142
id: crypto.randomUUID(),
143143
method: 'locator.selectOption',
144144
values: [{ value: '' }],
145-
locator: createDefaultLocatorOptions(),
145+
locator: {
146+
current: 'role',
147+
values: {
148+
role: {
149+
type: 'role',
150+
role: 'combobox',
151+
},
152+
},
153+
},
146154
}),
147155
},
148156
'page.goto': {

0 commit comments

Comments
 (0)