@@ -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