Skip to content

Commit d935b37

Browse files
store all available locators
1 parent a1c420b commit d935b37

29 files changed

+237
-193
lines changed

src/codegen/browser/convertEventsToActions.ts

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,68 @@
1-
import { AnyBrowserAction, ActionLocator } from '@/main/runner/schema'
1+
import { ActionLocator } from '@/main/runner/schema'
2+
import { BrowserTestAction, LocatorOptions } from '@/schemas/browserTest/v1'
23
import {
34
BrowserEvent,
45
BrowserEventTarget,
56
ElementSelector,
67
} from '@/schemas/recording'
78
import { exhaustive } from '@/utils/typescript'
89

9-
function toActionLocator(selector: ElementSelector): ActionLocator {
10-
if (selector.role !== undefined) {
11-
return {
12-
type: 'role',
13-
role: selector.role.role,
14-
options: selector.role.name
15-
? { name: selector.role.name, exact: true }
16-
: undefined,
17-
}
18-
}
10+
function toLocatorOptions(selector: ElementSelector): LocatorOptions {
11+
const values: Partial<Record<ActionLocator['type'], ActionLocator>> = {}
1912

20-
if (selector.label !== undefined) {
21-
return { type: 'label', label: selector.label }
13+
values.css = { type: 'css', selector: selector.css }
14+
15+
if (selector.testId !== undefined && selector.testId.trim() !== '') {
16+
values.testid = { type: 'testid', testId: selector.testId }
2217
}
2318

2419
if (selector.alt !== undefined) {
25-
return { type: 'alt', text: selector.alt }
20+
values.alt = { type: 'alt', text: selector.alt }
21+
}
22+
23+
if (selector.label !== undefined) {
24+
values.label = { type: 'label', label: selector.label }
2625
}
2726

2827
if (selector.placeholder !== undefined) {
29-
return { type: 'placeholder', placeholder: selector.placeholder }
28+
values.placeholder = {
29+
type: 'placeholder',
30+
placeholder: selector.placeholder,
31+
}
3032
}
3133

3234
if (selector.title !== undefined) {
33-
return { type: 'title', title: selector.title }
35+
values.title = { type: 'title', title: selector.title }
3436
}
3537

36-
if (selector.testId !== undefined && selector.testId.trim() !== '') {
37-
return { type: 'testid', testId: selector.testId }
38+
if (selector.role !== undefined) {
39+
values.role = {
40+
type: 'role',
41+
role: selector.role.role,
42+
options: selector.role.name
43+
? { name: selector.role.name, exact: true }
44+
: undefined,
45+
}
3846
}
3947

40-
return { type: 'css', selector: selector.css }
48+
const current = pickBestLocatorType(selector)
49+
50+
return { current, values }
51+
}
52+
53+
function pickBestLocatorType(selector: ElementSelector): ActionLocator['type'] {
54+
if (selector.role !== undefined) return 'role'
55+
if (selector.label !== undefined) return 'label'
56+
if (selector.alt !== undefined) return 'alt'
57+
if (selector.placeholder !== undefined) return 'placeholder'
58+
if (selector.title !== undefined) return 'title'
59+
if (selector.testId !== undefined && selector.testId.trim() !== '')
60+
return 'testid'
61+
return 'css'
4162
}
4263

43-
function getLocator(target: BrowserEventTarget): ActionLocator {
44-
return toActionLocator(target.selectors)
64+
function getLocatorOptions(target: BrowserEventTarget): LocatorOptions {
65+
return toLocatorOptions(target.selectors)
4566
}
4667

4768
function toClickModifiers(modifiers: {
@@ -58,7 +79,7 @@ function toClickModifiers(modifiers: {
5879
return result
5980
}
6081

61-
function toAction(event: BrowserEvent): AnyBrowserAction | null {
82+
function toAction(event: BrowserEvent): BrowserTestAction | null {
6283
switch (event.type) {
6384
case 'navigate-to-page':
6485
if (event.source === 'implicit') {
@@ -76,7 +97,7 @@ function toAction(event: BrowserEvent): AnyBrowserAction | null {
7697

7798
return {
7899
method: 'locator.click',
79-
locator: getLocator(event.target),
100+
locator: getLocatorOptions(event.target),
80101
...(hasNonDefaultOptions && {
81102
options: {
82103
button: event.button,
@@ -89,42 +110,47 @@ function toAction(event: BrowserEvent): AnyBrowserAction | null {
89110
case 'input-change':
90111
return {
91112
method: 'locator.fill',
92-
locator: getLocator(event.target),
113+
locator: getLocatorOptions(event.target),
93114
value: event.value,
94115
}
95116

96117
case 'check-change':
97118
return event.checked
98-
? { method: 'locator.check', locator: getLocator(event.target) }
99-
: { method: 'locator.uncheck', locator: getLocator(event.target) }
119+
? {
120+
method: 'locator.check',
121+
locator: getLocatorOptions(event.target),
122+
}
123+
: {
124+
method: 'locator.uncheck',
125+
locator: getLocatorOptions(event.target),
126+
}
100127

101128
case 'radio-change':
102129
return {
103130
method: 'locator.check',
104-
locator: getLocator(event.target),
131+
locator: getLocatorOptions(event.target),
105132
}
106133

107134
case 'select-change':
108135
return {
109136
method: 'locator.selectOption',
110-
locator: getLocator(event.target),
137+
locator: getLocatorOptions(event.target),
111138
values: event.selected.map((value) => ({ value })),
112139
}
113140

114141
case 'submit-form':
115142
return {
116143
method: 'locator.click',
117-
locator: getLocator(event.submitter),
144+
locator: getLocatorOptions(event.submitter),
118145
}
119146

120147
case 'assert':
121-
// TODO: Add assertion support
122148
return null
123149

124150
case 'wait-for':
125151
return {
126152
method: 'locator.waitFor',
127-
locator: getLocator(event.target),
153+
locator: getLocatorOptions(event.target),
128154
options: event.options,
129155
}
130156

@@ -135,8 +161,8 @@ function toAction(event: BrowserEvent): AnyBrowserAction | null {
135161

136162
export function convertEventsToActions(
137163
events: BrowserEvent[]
138-
): AnyBrowserAction[] {
139-
const actions: AnyBrowserAction[] = []
164+
): BrowserTestAction[] {
165+
const actions: BrowserTestAction[] = []
140166

141167
for (const event of events) {
142168
const action = toAction(event)

src/codegen/browser/test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
import { keyBy } from 'lodash-es'
22

3+
import { LocatorOptions } from '@/schemas/browserTest/v1'
34
import {
45
Assertion,
56
BrowserEvent,
67
BrowserEventTarget,
78
} from '@/schemas/recording'
89
import { exhaustive } from '@/utils/typescript'
9-
import {
10-
BrowserActionInstance,
11-
LocatorOptions,
12-
} from '@/views/BrowserTestEditor/types'
10+
import { BrowserActionInstance } from '@/views/BrowserTestEditor/types'
1311

1412
import { isSelectorEqual, getNodeSelector, toNodeSelector } from './selectors'
1513
import {

src/main/runner/schema.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const GetByTextLocatorSchema = z.object({
7070
options: TextLocatorOptions,
7171
})
7272

73-
const ActionLocatorSchema = z.discriminatedUnion('type', [
73+
export const ActionLocatorSchema = z.discriminatedUnion('type', [
7474
CssLocatorSchema,
7575
GetByRoleLocatorSchema,
7676
GetByTestIdLocatorSchema,
@@ -81,33 +81,33 @@ const ActionLocatorSchema = z.discriminatedUnion('type', [
8181
GetByTextLocatorSchema,
8282
])
8383

84-
const PageGotoActionSchema = z.object({
84+
export const PageGotoActionSchema = z.object({
8585
method: z.literal('page.goto'),
8686
url: z.string(),
8787
options: GenericOptions.optional(),
8888
})
8989

90-
const PageReloadActionSchema = z.object({
90+
export const PageReloadActionSchema = z.object({
9191
method: z.literal('page.reload'),
9292
options: GenericOptions.optional(),
9393
})
9494

95-
const PageWaitForNavigationActionSchema = z.object({
95+
export const PageWaitForNavigationActionSchema = z.object({
9696
method: z.literal('page.waitForNavigation'),
9797
options: GenericOptions.optional(),
9898
})
9999

100-
const PageCloseActionSchema = z.object({
100+
export const PageCloseActionSchema = z.object({
101101
method: z.literal('page.close'),
102102
})
103103

104-
const GenericPageActionSchema = z.object({
104+
export const GenericPageActionSchema = z.object({
105105
method: z.literal('page.*'),
106106
name: z.string(),
107107
args: z.array(z.unknown()),
108108
})
109109

110-
const LocatorClickOptionSchema = z
110+
export const LocatorClickOptionSchema = z
111111
.object({
112112
button: safe(
113113
z.union([z.literal('left'), z.literal('middle'), z.literal('right')])
@@ -125,38 +125,38 @@ const LocatorClickOptionSchema = z
125125
})
126126
.passthrough()
127127

128-
const LocatorClickActionSchema = z.object({
128+
export const LocatorClickActionSchema = z.object({
129129
method: z.literal('locator.click'),
130130
locator: ActionLocatorSchema,
131131
options: LocatorClickOptionSchema.optional(),
132132
})
133133

134-
const LocatorDoubleClickActionSchema = z.object({
134+
export const LocatorDoubleClickActionSchema = z.object({
135135
method: z.literal('locator.dblclick'),
136136
locator: ActionLocatorSchema,
137137
options: LocatorClickOptionSchema.optional(),
138138
})
139139

140-
const LocatorFillActionSchema = z.object({
140+
export const LocatorFillActionSchema = z.object({
141141
method: z.literal('locator.fill'),
142142
locator: ActionLocatorSchema,
143143
value: z.string(),
144144
options: GenericOptions.optional(),
145145
})
146146

147-
const LocatorCheckActionSchema = z.object({
147+
export const LocatorCheckActionSchema = z.object({
148148
method: z.literal('locator.check'),
149149
locator: ActionLocatorSchema,
150150
options: GenericOptions.optional(),
151151
})
152152

153-
const LocatorUncheckActionSchema = z.object({
153+
export const LocatorUncheckActionSchema = z.object({
154154
method: z.literal('locator.uncheck'),
155155
locator: ActionLocatorSchema,
156156
options: GenericOptions.optional(),
157157
})
158158

159-
const LocatorSelectOptionActionSchema = z.object({
159+
export const LocatorSelectOptionActionSchema = z.object({
160160
method: z.literal('locator.selectOption'),
161161
locator: ActionLocatorSchema,
162162
values: z.array(
@@ -169,7 +169,7 @@ const LocatorSelectOptionActionSchema = z.object({
169169
options: GenericOptions.optional(),
170170
})
171171

172-
const LocatorWaitForActionSchema = z.object({
172+
export const LocatorWaitForActionSchema = z.object({
173173
method: z.literal('locator.waitFor'),
174174
locator: ActionLocatorSchema,
175175
options: z
@@ -187,59 +187,59 @@ const LocatorWaitForActionSchema = z.object({
187187
.optional(),
188188
})
189189

190-
const LocatorHoverActionSchema = z.object({
190+
export const LocatorHoverActionSchema = z.object({
191191
method: z.literal('locator.hover'),
192192
locator: ActionLocatorSchema,
193193
options: GenericOptions.optional(),
194194
})
195195

196-
const LocatorSetCheckedActionSchema = z.object({
196+
export const LocatorSetCheckedActionSchema = z.object({
197197
method: z.literal('locator.setChecked'),
198198
locator: ActionLocatorSchema,
199199
checked: z.boolean(),
200200
options: GenericOptions.optional(),
201201
})
202202

203-
const LocatorTypeActionSchema = z.object({
203+
export const LocatorTypeActionSchema = z.object({
204204
method: z.literal('locator.type'),
205205
locator: ActionLocatorSchema,
206206
text: z.string(),
207207
options: GenericOptions.optional(),
208208
})
209209

210-
const LocatorPressActionSchema = z.object({
210+
export const LocatorPressActionSchema = z.object({
211211
method: z.literal('locator.press'),
212212
locator: ActionLocatorSchema,
213213
key: z.string(),
214214
options: GenericOptions.optional(),
215215
})
216216

217-
const LocatorClearActionSchema = z.object({
217+
export const LocatorClearActionSchema = z.object({
218218
method: z.literal('locator.clear'),
219219
locator: ActionLocatorSchema,
220220
options: GenericOptions.optional(),
221221
})
222222

223-
const LocatorTapActionSchema = z.object({
223+
export const LocatorTapActionSchema = z.object({
224224
method: z.literal('locator.tap'),
225225
locator: ActionLocatorSchema,
226226
options: GenericOptions.optional(),
227227
})
228228

229-
const LocatorFocusActionSchema = z.object({
229+
export const LocatorFocusActionSchema = z.object({
230230
method: z.literal('locator.focus'),
231231
locator: ActionLocatorSchema,
232232
options: GenericOptions.optional(),
233233
})
234234

235-
const GenericLocatorActionSchema = z.object({
235+
export const GenericLocatorActionSchema = z.object({
236236
method: z.literal('locator.*'),
237237
name: z.string(),
238238
locator: ActionLocatorSchema,
239239
args: z.array(z.unknown()),
240240
})
241241

242-
const GenericBrowserContextActionSchema = z.object({
242+
export const GenericBrowserContextActionSchema = z.object({
243243
method: z.literal('browserContext.*'),
244244
name: z.string(),
245245
args: z.array(z.unknown()),

0 commit comments

Comments
 (0)