Skip to content
This repository was archived by the owner on Sep 17, 2024. It is now read-only.

Commit f13374e

Browse files
committed
fix: added waitForElement step and pierceSelector
1 parent 094cf5a commit f13374e

File tree

3 files changed

+103
-0
lines changed

3 files changed

+103
-0
lines changed

src/OwloopsStringifyExtension.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Schema,
44
StringifyExtension,
55
StepType,
6+
WaitForElementStep,
67
} from "@puppeteer/replay";
78

89
import {
@@ -53,6 +54,8 @@ export class OwloopsStringifyExtension extends StringifyExtension {
5354
return this.#appendKeyDownStep(out, step);
5455
case StepType.Hover:
5556
return this.#appendHoverStep(out, step, flow);
57+
case StepType.WaitForElement:
58+
return this.#appendWaitForElementStep(out, step, flow);
5659
}
5760
}
5861

@@ -65,6 +68,7 @@ export class OwloopsStringifyExtension extends StringifyExtension {
6568
const ariaSelector = ariaSelectors(step.selectors);
6669
const xpathSelector = xpathSelectors(step.selectors);
6770
const textSelector = textSelectors(step.selectors);
71+
const pierceSelector = pierceSelectors(step.selectors);
6872

6973
if (cySelector) {
7074
const props = [];
@@ -81,6 +85,9 @@ export class OwloopsStringifyExtension extends StringifyExtension {
8185
if (textSelector) {
8286
props.push(["textSelector", textSelector]);
8387
}
88+
if (pierceSelector) {
89+
props.push(["pierceSelector", pierceSelector]);
90+
}
8491
formatOwlJson(out, "input", props);
8592
}
8693

@@ -97,6 +104,7 @@ export class OwloopsStringifyExtension extends StringifyExtension {
97104
const ariaSelector = ariaSelectors(step.selectors);
98105
const xpathSelector = xpathSelectors(step.selectors);
99106
const textSelector = textSelectors(step.selectors);
107+
const pierceSelector = pierceSelectors(step.selectors);
100108

101109
const props = [];
102110
props.push(["querySelector", cySelector]);
@@ -111,6 +119,9 @@ export class OwloopsStringifyExtension extends StringifyExtension {
111119
if (textSelector) {
112120
props.push(["textSelector", textSelector]);
113121
}
122+
if (pierceSelector) {
123+
props.push(["pierceSelector", pierceSelector]);
124+
}
114125
if (step.offsetX) {
115126
props.push(["offsetX", step.offsetX]);
116127
}
@@ -137,6 +148,7 @@ export class OwloopsStringifyExtension extends StringifyExtension {
137148
const ariaSelector = ariaSelectors(step.selectors);
138149
const xpathSelector = xpathSelectors(step.selectors);
139150
const textSelector = textSelectors(step.selectors);
151+
const pierceSelector = pierceSelectors(step.selectors);
140152

141153
const props = [];
142154
props.push(["querySelector", cySelector]);
@@ -151,6 +163,9 @@ export class OwloopsStringifyExtension extends StringifyExtension {
151163
if (textSelector) {
152164
props.push(["textSelector", textSelector]);
153165
}
166+
if (pierceSelector) {
167+
props.push(["pierceSelector", pierceSelector]);
168+
}
154169
if (step.offsetX) {
155170
props.push(["offsetX", step.offsetX]);
156171
}
@@ -183,6 +198,27 @@ export class OwloopsStringifyExtension extends StringifyExtension {
183198
out.appendLine("");
184199
}
185200

201+
#appendWaitForElementStep(out: LineWriter, step: WaitForElementStep, flow: Schema.UserFlow): void {
202+
const cySelector = handleSelectorsForWaitForElementStep(step.selectors as any, flow);
203+
const props = [];
204+
props.push(["for", `"querySelector"`]);
205+
props.push(["querySelector", cySelector]);
206+
if (cySelector) {
207+
formatOwlJson(out, "wait", props);
208+
} else {
209+
console.log(
210+
`Warning: The click on ${step.selectors[0]} was not able to be exported to Owloops. Please adjust your selectors and try again.`
211+
);
212+
}
213+
214+
out.appendLine("");
215+
// out.appendLine(
216+
// `await waitForElement(${formatJSONAsJS(step, out.getIndent())}, ${
217+
// step.frame ? 'frame' : 'targetPage'
218+
// }, timeout);`
219+
// );
220+
}
221+
186222
#appendKeyDownStep(out: LineWriter, step: Schema.KeyDownStep): void {
187223
const pressedKey = step.key.toLowerCase() as SupportedRecorderKeysKeys;
188224

@@ -245,6 +281,14 @@ function filterArrayByString(selectors: Schema.Selector[], value: string) {
245281
);
246282
}
247283

284+
function filterArrayByStringForWaitForElementStep(selectors: string[], value: string) {
285+
return selectors.filter((selector) =>
286+
value === "aria/"
287+
? !selector.includes(value)
288+
: selector.includes(value)
289+
);
290+
}
291+
248292
function handleSelectors(
249293
selectors: Schema.Selector[],
250294
flow?: Schema.UserFlow
@@ -267,6 +311,30 @@ function handleSelectors(
267311
}
268312
}
269313

314+
function handleSelectorsForWaitForElementStep(
315+
selectors: string[],
316+
flow?: Schema.UserFlow
317+
): string | undefined {
318+
// Remove Aria selectors in favor of DOM selectors
319+
const nonAriaSelectors = filterArrayByStringForWaitForElementStep(selectors, "aria/");
320+
321+
let preferredSelector;
322+
323+
// Give preference to user-specified selectors
324+
if (flow?.selectorAttribute) {
325+
preferredSelector = filterArrayByStringForWaitForElementStep(
326+
nonAriaSelectors,
327+
flow.selectorAttribute
328+
);
329+
}
330+
331+
if (preferredSelector && preferredSelector.length > 0) {
332+
return formatAsJSLiteral(preferredSelector[0]);
333+
} else {
334+
return formatAsJSLiteral(nonAriaSelectors[0]);
335+
}
336+
}
337+
270338
function ariaSelectors(selectors: Schema.Selector[]): string | undefined {
271339
const ariaSelectors = selectors.filter((selector) =>
272340
selector[0].includes("aria/")
@@ -300,6 +368,17 @@ function textSelectors(selectors: Schema.Selector[]): string | undefined {
300368
return textSelector;
301369
}
302370

371+
function pierceSelectors(selectors: Schema.Selector[]): string | undefined {
372+
const pierceSelectors = selectors.filter((selector) =>
373+
selector[0].includes("pierce/")
374+
);
375+
let pierceSelector;
376+
if (pierceSelectors.length > 0) {
377+
pierceSelector = formatAsJSLiteral(pierceSelectors[0][0]);
378+
}
379+
return pierceSelector;
380+
}
381+
303382
function assertAllValidStepTypesAreHandled(step: Schema.Step): void {
304383
console.log(
305384
`Warning: Owloops does not currently handle migrating steps of type: ${step.type}. Please check the output to see how this might affect your test.`

src/test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { owloopsStringifyChromeRecording } from "./main.js";
2+
3+
const stringifiedFile = await owloopsStringifyChromeRecording(JSON.stringify({"title":"Recording 12/16/2023 at 1:39:01 AM","steps":[{"type":"setViewport","width":1374,"height":294,"deviceScaleFactor":1,"isMobile":false,"hasTouch":false,"isLandscape":false},{"type":"navigate","url":"https://duckduckgo.com/","assertedEvents":[{"type":"navigation","url":"https://duckduckgo.com/","title":"DuckDuckGo — Privacy, simplified."}]},{"type":"change","value":"owloops","selectors":[["#searchbox_input"],["xpath///*[@id=\"searchbox_input\"]"],["pierce/#searchbox_input"]],"target":"main"},{"type":"click","target":"main","selectors":[["button.searchbox_searchButton__F5Bwq"],["xpath///*[@id=\"searchbox_homepage\"]/div[1]/div/button[2]"],["pierce/button.searchbox_searchButton__F5Bwq"]],"offsetY":22.56818389892578,"offsetX":8.1448974609375,"assertedEvents":[{"type":"navigation","url":"https://duckduckgo.com/?hps=1&q=owloops&atb=v298-1","title":""}]},{"type":"waitForElement","target":"main","selectors":["li:nth-of-type(1) div.ikg2IXiCD14iVX7AdZo1 span","xpath///*[@data-testid=\"result-title-a\"]/span","pierce/li:nth-of-type(1) div.ikg2IXiCD14iVX7AdZo1 span"]}]}));
4+
5+
console.log(stringifiedFile);

test/OwloopsStringifyExtension_test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,25 @@ describe("OwloopsStringifyExtension", function () {
145145
);
146146
});
147147

148+
it("correctly exports Chrome Recorder waitForElement step", async function () {
149+
const step = {
150+
type: StepType.WaitForElement as const,
151+
selectors: [
152+
'li:nth-of-type(1) div.ikg2IXiCD14iVX7AdZo1 span',
153+
'xpath///*[@data-testid="result-title-a"]/span',
154+
'pierce/li:nth-of-type(1) div.ikg2IXiCD14iVX7AdZo1 span'
155+
],
156+
};
157+
const result = await stringifyStep(step, {
158+
extension,
159+
});
160+
161+
assert.equal(
162+
result.toString(),
163+
`{\n\"action\": \"wait\",\n\"options\": {\n\"for\": "querySelector",\n\"querySelector\": "li:nth-of-type(1) div.ikg2IXiCD14iVX7AdZo1 span",\n}\n},\n\n`
164+
);
165+
});
166+
148167
it("correctly exports Chrome Recorder change step", async function () {
149168
const step = {
150169
type: StepType.Change as const,

0 commit comments

Comments
 (0)