import { describe, it, vi, expect, beforeEach } from 'vitest'import { getShadowRootManager, ShadowRootTree } from '../src/session/shadowRoot.js'const defaultBrowser = {sessionId: '123',sessionSubscribe: vi.fn().mockResolvedValue({}),on: vi.fn(),scriptAddPreloadScript: vi.fn(),capabilities: {}}describe('ShadowRootManager', () => {beforeEach(() => {vi.clearAllMocks()})it('should get shadow root manager per browser session', () => {const browserA = { ...defaultBrowser } as anyconst browserB = { ...defaultBrowser } as anyconst managerA = getShadowRootManager(browserA)const managerB = getShadowRootManager(browserB)const managerC = getShadowRootManager(browserA)expect(managerA).not.toBe(managerB)expect(managerA).toBe(managerC)})it('registers correct event listeners', async () => {const wid = process.env.WDIO_UNIT_TESTSdelete process.env.WDIO_UNIT_TESTSconst browser = { ...defaultBrowser, isBidi: true, options: { capabilities: { webSocketUrl: './' } } } as anybrowser.sessionId = '234'const manager = getShadowRootManager(browser)process.env.WDIO_UNIT_TESTS = widexpect(await manager.initialize()).toBe(true)expect(browser.sessionSubscribe).toBeCalledTimes(1)expect(browser.on).toBeCalledTimes(4)expect(browser.scriptAddPreloadScript).toBeCalledTimes(1)})it('should not register event listeners if not in bidi mode', async () => {const browser = { ...defaultBrowser } as anybrowser.sessionId = '345'const manager = getShadowRootManager(browser)expect(await manager.initialize()).toBe(true)expect(browser.sessionSubscribe).toBeCalledTimes(0)expect(browser.on).toBeCalledTimes(1)expect(browser.scriptAddPreloadScript).toBeCalledTimes(0)})it('should not register event listeners if not using webdriver as automation protocol', async () => {const browser = { ...defaultBrowser, isBidi: true, automationProtocol: './protocol-stub.js' } as anybrowser.sessionId = '456'const manager = getShadowRootManager(browser)expect(await manager.initialize()).toBe(true)expect(browser.sessionSubscribe).toBeCalledTimes(0)expect(browser.on).toBeCalledTimes(1)expect(browser.scriptAddPreloadScript).toBeCalledTimes(0)})it('should capture shadow root elements', () => {const browser = { ...defaultBrowser } as anyconst manager = getShadowRootManager(browser)manager.handleLogEntry({level: 'debug',args: [{ type: 'string', value: '[WDIO]' },{ type: 'string', value: 'newShadowRoot' },{ type: 'node', sharedId: 'foobar', value: {shadowRoot: {sharedId: 'shadowFoobar',value: {nodeType: 11,mode: 'closed'}}} },{ type: 'node', sharedId: 'barfoo' }],source: { context: 'foobarContext' }} as any)expect(manager.getShadowElementsByContextId('foobarContext')).toEqual(['barfoo', 'shadowFoobar'])expect(manager.getShadowRootModeById('foobarContext', 'foobar')).toBe('closed')expect(manager.getShadowElementPairsByContextId('foobarContext')).toEqual([['barfoo', undefined],['foobar', 'shadowFoobar']])})it('should ignore log entries that are not of interest', () => {const browser = { ...defaultBrowser } as anyconst manager = getShadowRootManager(browser)manager.handleLogEntry({level: 'debug',args: [{ type: 'string', value: 'foobar' },{ type: 'string', value: 'newShadowRoot' },{ type: 'node', sharedId: 'foobar' },{ type: 'node', sharedId: 'barfoo' }],source: { context: 'foobarContext' }} as any)expect(manager.getShadowElementsByContextId('foobarContext')).toEqual([])})it('should throw if log entry is invalid', () => {const browser = { ...defaultBrowser } as anyconst manager = getShadowRootManager(browser)expect(() => manager.handleLogEntry({level: 'debug',args: [{ type: 'string', value: '[WDIO]' },{ type: 'string', value: 'foobar' },{ type: 'node', sharedId: 'foobar' },{ type: 'node', sharedId: 'barfoo' }],source: { context: 'foobar' }} as any)).toThrow()})})describe('ShadowRootTree', () => {const root = new ShadowRootTree('1')root.addShadowElement(new ShadowRootTree('2', '3'))root.addShadowElement(new ShadowRootTree('4', '5'))root.addShadowElement(new ShadowRootTree('6', '7'))root.addShadowElement('4', new ShadowRootTree('8', '9'))root.addShadowElement('8', new ShadowRootTree('10', '11'))root.addShadowElement('8', new ShadowRootTree('12', '13'))root.addShadowElement('12', new ShadowRootTree('14', '15'))root.addShadowElement(new ShadowRootTree('16', '17'))root.addShadowElement('16', new ShadowRootTree('18', '19'))root.addShadowElement('16', new ShadowRootTree('18', '19'))root.addShadowElement('18', new ShadowRootTree('20', '21'))it('can find the root of a tree', () => {const tree = root.find('8')expect(tree?.shadowRoot).toBe('9')expect(tree?.children.size).toBe(2)expect(root.find('1234')).toBe(undefined)})it('can findByShadowId', () => {expect(root.findByShadowId('9')?.element).toBe('8')expect(root.findByShadowId('15')?.element).toBe('14')expect(root.findByShadowId('1234')).toBe(undefined)})it('can get all trees', () => {expect(root.getAllLookupScopes()).toMatchInlineSnapshot(`["1","3","5","9","11","13","15","7","17","19","21","19",]`)expect(root.find('8')?.getAllLookupScopes()).toMatchInlineSnapshot(`["9","11","13","15",]`)})it('can delete children and sub trees', () => {const child = root.find('6')expect(child?.remove('8')).toBe(false)expect(root.remove('8')).toBe(true)expect(root.getAllLookupScopes()).toMatchInlineSnapshot(`["1","3","5","7","17","19","21","19",]`)})it('can delete children in the right order', () => {expect(root.remove('18')).toBe(true)const child = root.find('16')expect(child?.getAllLookupScopes()).toMatchInlineSnapshot(`["17","19","21",]`)})})