From 95894d3ae6d58835aee09658334a98a2b085881b Mon Sep 17 00:00:00 2001 From: DavertMik Date: Wed, 17 Dec 2025 01:45:43 +0200 Subject: [PATCH] added json as string --- lib/locator.js | 32 ++++++++++++++ test/unit/locator_test.js | 91 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+) diff --git a/lib/locator.js b/lib/locator.js index b8eda835c..5ddb3bd7d 100644 --- a/lib/locator.js +++ b/lib/locator.js @@ -40,6 +40,11 @@ class Locator { return } + // Try to parse JSON strings that look like objects + if (this.parsedJsonAsString(locator)) { + return + } + this.type = defaultType || 'fuzzy' this.output = locator this.value = locator @@ -89,6 +94,33 @@ class Locator { return { [this.type]: this.value } } + parsedJsonAsString(locator) { + if (typeof locator !== 'string') { + return false + } + + const trimmed = locator.trim() + if (!trimmed.startsWith('{') || !trimmed.endsWith('}')) { + return false + } + + try { + const parsed = JSON.parse(trimmed) + if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) { + this.locator = parsed + this.type = Object.keys(parsed)[0] + this.value = parsed[this.type] + this.strict = true + + Locator.filters.forEach(f => f(parsed, this)) + return true + } + } catch (e) { + // continue with normal string processing + } + return false + } + /** * @returns {string} */ diff --git a/test/unit/locator_test.js b/test/unit/locator_test.js index c6ec86ecd..f16600635 100644 --- a/test/unit/locator_test.js +++ b/test/unit/locator_test.js @@ -290,6 +290,97 @@ describe('Locator', () => { }) }) + describe('JSON string parsing', () => { + it('should parse JSON string to css locator', () => { + const jsonStr = '{"css": "#button"}' + const l = new Locator(jsonStr) + expect(l.type).to.equal('css') + expect(l.value).to.equal('#button') + }) + + it('should parse JSON string to xpath locator', () => { + const jsonStr = '{"xpath": "//div[@class=\\"test\\"]"}' + const l = new Locator(jsonStr) + expect(l.type).to.equal('xpath') + expect(l.value).to.equal('//div[@class="test"]') + }) + + it('should parse JSON string to id locator', () => { + const jsonStr = '{"id": "my-element"}' + const l = new Locator(jsonStr) + expect(l.type).to.equal('id') + expect(l.value).to.equal('my-element') + }) + + it('should parse JSON string to custom locator', () => { + const jsonStr = '{"byRole": "button"}' + const l = new Locator(jsonStr) + expect(l.type).to.equal('byRole') + expect(l.value).to.equal('button') + }) + + it('should handle whitespace around JSON string', () => { + const jsonStr = ' { "css": ".test" } ' + const l = new Locator(jsonStr) + expect(l.type).to.equal('css') + expect(l.value).to.equal('.test') + }) + + it('should reject invalid JSON and treat as string', () => { + const l = new Locator('{ invalid json') + expect(l.type).to.equal('fuzzy') + expect(l.value).to.equal('{ invalid json') + }) + + it('should handle aria-style locators with multiple properties', () => { + // This tests that only the first property is used (as per simple key-value requirement) + const jsonStr = '{"role": "button", "text": "Save"}' + const l = new Locator(jsonStr) + expect(l.type).to.equal('role') + expect(l.value).to.equal('button') + expect(l.strict).to.equal(true) + }) + + it('should ignore non-object JSON', () => { + const jsonStr = '"just a string"' + const l = new Locator(jsonStr) + expect(l.type).to.equal('fuzzy') + expect(l.value).to.equal('"just a string"') + }) + + it('should work with array values for certain locators', () => { + const jsonStr = '{"shadow": ["app", "component", "button"]}' + const l = new Locator(jsonStr) + expect(l.type).to.equal('shadow') + expect(l.value).to.eql(['app', 'component', 'button']) + }) + + it('should mark parsed locators as strict', () => { + const jsonStr = '{"css": "#test"}' + const l = new Locator(jsonStr) + expect(l.strict).to.equal(true) + }) + + it('should demonstrate equivalence between object and JSON string locators', () => { + // Same locator, different formats + const objectLocator = new Locator({ css: '#main-button' }) + const jsonLocator = new Locator('{"css": "#main-button"}') + + expect(objectLocator.type).to.equal(jsonLocator.type) + expect(objectLocator.value).to.equal(jsonLocator.value) + expect(objectLocator.strict).to.equal(jsonLocator.strict) + }) + + it('should work with complex xpath in JSON', () => { + const jsonStr = '{"xpath": "//div[contains(@class, \\"container\\")]//button"}' + const l = new Locator(jsonStr) + + expect(l.type).to.equal('xpath') + expect(l.value).to.equal('//div[contains(@class, "container")]//button') + expect(l.simplify()).to.equal('//div[contains(@class, "container")]//button') + }) + }) + it('should transform CSS to xpath', () => { const l = new Locator('p > #user', 'css') const nodes = xpath.select(l.toXPath(), doc)