Skip to content

Commit 95894d3

Browse files
author
DavertMik
committed
added json as string
1 parent 7747f4c commit 95894d3

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

lib/locator.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ class Locator {
4040
return
4141
}
4242

43+
// Try to parse JSON strings that look like objects
44+
if (this.parsedJsonAsString(locator)) {
45+
return
46+
}
47+
4348
this.type = defaultType || 'fuzzy'
4449
this.output = locator
4550
this.value = locator
@@ -89,6 +94,33 @@ class Locator {
8994
return { [this.type]: this.value }
9095
}
9196

97+
parsedJsonAsString(locator) {
98+
if (typeof locator !== 'string') {
99+
return false
100+
}
101+
102+
const trimmed = locator.trim()
103+
if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) {
104+
return false
105+
}
106+
107+
try {
108+
const parsed = JSON.parse(trimmed)
109+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
110+
this.locator = parsed
111+
this.type = Object.keys(parsed)[0]
112+
this.value = parsed[this.type]
113+
this.strict = true
114+
115+
Locator.filters.forEach(f => f(parsed, this))
116+
return true
117+
}
118+
} catch (e) {
119+
// continue with normal string processing
120+
}
121+
return false
122+
}
123+
92124
/**
93125
* @returns {string}
94126
*/

test/unit/locator_test.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,97 @@ describe('Locator', () => {
290290
})
291291
})
292292

293+
describe('JSON string parsing', () => {
294+
it('should parse JSON string to css locator', () => {
295+
const jsonStr = '{"css": "#button"}'
296+
const l = new Locator(jsonStr)
297+
expect(l.type).to.equal('css')
298+
expect(l.value).to.equal('#button')
299+
})
300+
301+
it('should parse JSON string to xpath locator', () => {
302+
const jsonStr = '{"xpath": "//div[@class=\\"test\\"]"}'
303+
const l = new Locator(jsonStr)
304+
expect(l.type).to.equal('xpath')
305+
expect(l.value).to.equal('//div[@class="test"]')
306+
})
307+
308+
it('should parse JSON string to id locator', () => {
309+
const jsonStr = '{"id": "my-element"}'
310+
const l = new Locator(jsonStr)
311+
expect(l.type).to.equal('id')
312+
expect(l.value).to.equal('my-element')
313+
})
314+
315+
it('should parse JSON string to custom locator', () => {
316+
const jsonStr = '{"byRole": "button"}'
317+
const l = new Locator(jsonStr)
318+
expect(l.type).to.equal('byRole')
319+
expect(l.value).to.equal('button')
320+
})
321+
322+
it('should handle whitespace around JSON string', () => {
323+
const jsonStr = ' { "css": ".test" } '
324+
const l = new Locator(jsonStr)
325+
expect(l.type).to.equal('css')
326+
expect(l.value).to.equal('.test')
327+
})
328+
329+
it('should reject invalid JSON and treat as string', () => {
330+
const l = new Locator('{ invalid json')
331+
expect(l.type).to.equal('fuzzy')
332+
expect(l.value).to.equal('{ invalid json')
333+
})
334+
335+
it('should handle aria-style locators with multiple properties', () => {
336+
// This tests that only the first property is used (as per simple key-value requirement)
337+
const jsonStr = '{"role": "button", "text": "Save"}'
338+
const l = new Locator(jsonStr)
339+
expect(l.type).to.equal('role')
340+
expect(l.value).to.equal('button')
341+
expect(l.strict).to.equal(true)
342+
})
343+
344+
it('should ignore non-object JSON', () => {
345+
const jsonStr = '"just a string"'
346+
const l = new Locator(jsonStr)
347+
expect(l.type).to.equal('fuzzy')
348+
expect(l.value).to.equal('"just a string"')
349+
})
350+
351+
it('should work with array values for certain locators', () => {
352+
const jsonStr = '{"shadow": ["app", "component", "button"]}'
353+
const l = new Locator(jsonStr)
354+
expect(l.type).to.equal('shadow')
355+
expect(l.value).to.eql(['app', 'component', 'button'])
356+
})
357+
358+
it('should mark parsed locators as strict', () => {
359+
const jsonStr = '{"css": "#test"}'
360+
const l = new Locator(jsonStr)
361+
expect(l.strict).to.equal(true)
362+
})
363+
364+
it('should demonstrate equivalence between object and JSON string locators', () => {
365+
// Same locator, different formats
366+
const objectLocator = new Locator({ css: '#main-button' })
367+
const jsonLocator = new Locator('{"css": "#main-button"}')
368+
369+
expect(objectLocator.type).to.equal(jsonLocator.type)
370+
expect(objectLocator.value).to.equal(jsonLocator.value)
371+
expect(objectLocator.strict).to.equal(jsonLocator.strict)
372+
})
373+
374+
it('should work with complex xpath in JSON', () => {
375+
const jsonStr = '{"xpath": "//div[contains(@class, \\"container\\")]//button"}'
376+
const l = new Locator(jsonStr)
377+
378+
expect(l.type).to.equal('xpath')
379+
expect(l.value).to.equal('//div[contains(@class, "container")]//button')
380+
expect(l.simplify()).to.equal('//div[contains(@class, "container")]//button')
381+
})
382+
})
383+
293384
it('should transform CSS to xpath', () => {
294385
const l = new Locator('p > #user', 'css')
295386
const nodes = xpath.select(l.toXPath(), doc)

0 commit comments

Comments
 (0)