🏡 index : quine-global/webdriverio.git

import { describe, it, beforeAll, afterEach, expect, vi } from 'vitest'
import path from 'node:path'
import logger from '@wdio/logger'

import { waitForExist } from '../src/commands/element/waitForExist.js'
import { remote } from '../src/index.js'

vi.mock('fetch')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.mock('../src/commands/element/waitUntil', () => ({
    __esModule: true,
    waitUntil: vi.fn().mockImplementation(() => { return true })
}))
vi.mock('../src/commands/element/waitForDisplayed', () => ({
    __esModule: true,
    waitForDisplayed: vi.fn().mockImplementation(() => { return true })
}))
vi.mock('../src/commands/element/waitForExist', () => ({
    __esModule: true,
    waitForExist: vi.fn().mockImplementation(() => { return true })
}))
vi.mock('../src/commands/element/waitForEnabled', () => ({
    __esModule: true,
    waitForEnabled: vi.fn().mockImplementation(() => { return true })
}))

const { warn } = logger('foobar')

describe('middleware', () => {
    let browser: WebdriverIO.Browser

    beforeAll(async () => {
        browser = await remote({
            baseUrl: 'http://foobar.com',
            capabilities: {
                browserName: 'foobar'
            },
            waitforInterval: 20,
            waitforTimeout: 100
        })
    })

    afterEach(() => {
        vi.mocked(warn).mockClear()
        vi.mocked(waitForExist).mockClear()
    })

    it('should throw an error if the element is never found', async () => {
        vi.mocked(waitForExist).mockImplementationOnce(() => {
            throw new Error('Promise was rejected with the following reason')
        })

        const elem = await browser.$('#foo')
        elem.elementId = undefined as any

        await expect(elem.click())
            .rejects.toThrow('Can\'t call click on element with selector "#foo" because element wasn\'t found')
    })

    it('should successfully click on an element that falls stale after being re-found', async () => {
        const elem = await browser.$('#foo')
        const subElem = await elem.$('#subfoo')
        const subSubElem = await subElem.$('#subsubfoo')
        subSubElem.elementId = undefined as any

        //Success returns null
        expect(await subSubElem.click()).toEqual(null)
        expect(vi.mocked(warn).mock.calls).toHaveLength(1)
        expect(vi.mocked(warn).mock.calls).toEqual([['Request encountered a stale element - terminating request']])
        // @ts-ignore mock feature
        vi.mocked(fetch).retryCnt = 0
    })

    it('should successfully getAttribute of an element that falls stale after being re-found in Safari', async () => {
        browser = await remote({
            baseUrl: 'http://foobar.com',
            capabilities: {
                browserName: 'safari',
                // @ts-expect-error mock feature
                keepBrowserName: true
            },
            waitforInterval: 20,
            waitforTimeout: 100
        })
        const elem = await browser.$('#foo').getElement()
        elem.selector = '#nonexisting'
        // @ts-ignore mock feature
        vi.mocked(fetch).setMockResponse([{ error: 'no such element', statusCode: 404 }, undefined, undefined, 'bar'])
        expect(await elem.getAttribute('foo')).toEqual('bar')
        expect(vi.mocked(waitForExist).mock.calls).toHaveLength(1)
        vi.mocked(fetch).mockClear()
    })

    it('should successfully click on a stale element', async () => {
        const elem = await browser.$('#foo')
        const subElem = await elem.$('#subfoo')
        const subSubElem = await subElem.$('#subsubfoo')

        //Success returns null
        expect(await subSubElem.click()).toEqual(null)
        expect(vi.mocked(warn).mock.calls).toHaveLength(1)
        expect(vi.mocked(warn).mock.calls).toEqual([['Request encountered a stale element - terminating request']])
    })

    it('should assign elementId and w3c identifier to element scope after re-found', async () => {
        const elem = await browser.$('#nonexisting').getElement()
        expect(elem.elementId).toEqual(undefined)
        expect(elem['element-6066-11e4-a52e-4f735466cecf']).toEqual(undefined)

        elem.selector = '#exists'
        elem.addCommand('getThis', function(this: any) { return this })
        // @ts-expect-error undefined custom command
        const elementThis = await elem.getThis()
        expect(elementThis.elementId).toEqual('some-elem-123')
        expect(elementThis['element-6066-11e4-a52e-4f735466cecf']).toEqual('some-elem-123')
    })

    describe('should NOT wait on element if', () => {
        // wdio default waitForExist command
        it('elem EXISTS and command = waitForExist', async () => {
            const elem = await browser.$('#exists')
            await elem.waitForExist()
            expect(vi.mocked(waitForExist).mock.calls).toHaveLength(1)
        })

        const commands = [
            // wdio default commands
            'waitUntil',
            'waitForDisplayed',
            'waitForEnabled',
            'isElementDisplayed',
            'isDisplayed',
            'isExisting',

            // custom commands
            'waitUntilFoo',
            'waitForFoo',
            'isExistingFoo',
            'isDisplayedFoo']

        commands.forEach(commandName => {
            it(`elem NOT_FOUND and command = ${commandName}`, async () => {
                browser.addCommand(commandName, () => {}, true)
                const elem = await browser.$('#nonexisting')
                await elem[commandName]()
                expect(vi.mocked(waitForExist).mock.calls).toHaveLength(0)
            })
        })

        it('elem EXISTS and command = foo', async () => {
            browser.addCommand('foo', () => {}, true)
            const elem = await browser.$('#exists')
            // @ts-expect-error undefined custom command
            await elem.foo()
            expect(vi.mocked(waitForExist).mock.calls).toHaveLength(0)
        })

        it('elem EXISTS and command = isExisting', async () => {
            const elem = await browser.$('#exists')
            await elem.isExisting()
            expect(vi.mocked(waitForExist).mock.calls).toHaveLength(0)
        })
    })

    describe('should wait on element if', () => {
        it('elem NOT_FOUND and command = foo', async () => {
            browser.addCommand('foo', () => {}, true)
            const elem = await browser.$('#nonexisting')
            // @ts-expect-error undefined custom command
            await elem.foo()
            expect(vi.mocked(waitForExist).mock.calls).toHaveLength(1)
        })
    })
})