🏡 index : quine-global/webdriverio.git

import path from 'node:path'
import assert from 'node:assert'

describe('Mocha smoke test', () => {
    const testJs = path.join('tests', 'mocha', 'test.ts')

    it('has globals set up', async () => {
        expect(1).toBe(1) // has non wdio matcher support
        expect(global.browser).toBeDefined()
        expect(global.driver).toBeDefined()
        expect(global.$).toBeDefined()
        expect(global.$$).toBeDefined()
        expect(global.expect).toBeDefined()
    })

    it('should allow to use WebdriverIO assertions', async () => {
        await expect(browser).toHaveTitle('Mock Page Title')
    })

    it('should allow to use asymmetric matchers', async () => {
        await expect(browser).toHaveTitle(
            expect.stringContaining('Page'))
        await expect(browser).toHaveTitle(
            expect.not.stringContaining('foobar'))
        await expect(browser).toHaveUrl(
            expect.stringContaining('mymockpage'))
        await expect(browser).toHaveUrl(
            expect.not.stringContaining('mymock_page.'))
    })

    it('has a testrunner config object', () => {
        const opts = browser.options as WebdriverIO.Config
        expect(Array.isArray(opts.services)).toBe(true)
        expect(opts).toHaveProperty('mochaOpts')
        expect(opts).toHaveProperty('jasmineOpts')
        expect(opts).toHaveProperty('cucumberOpts')
        expect(opts).toHaveProperty('specs')
    })

    let hasRun = false
    it('should retry', function (this: WebdriverIO.Browser) {
        if (!hasRun) {
            hasRun = true
            assert.equal(this.wdioRetries, 0)
            throw new Error('booom!')
        }

        assert.equal(this.wdioRetries, 1)
    }, 1)

    it('should chain properly', async () => {
        // @ts-expect-error custom command
        await browser.isExistingScenario()

        const el = browser.$('body')
        assert.equal(await el.$('.selector-1').isExisting(), true)
        assert.equal(await el.$('.selector-2').isExisting(), true)
    })

    it('should allow to use then/catch/finally', async () => {
        // @ts-expect-error custom command
        await browser.isExistingScenario()
        const val = await browser.$('body').$('.selector-1').then(() => 123)
        expect(val).toBe(123)

        // @ts-expect-error custom command
        await browser.isExistingScenario()
        let anotherVal
        const elem = await browser.$('body').$('.selector-1').finally(() => {
            anotherVal = 321
        })
        expect(elem.selector).toBe('.selector-1')
        expect(anotherVal).toBe(321)

        // @ts-expect-error custom command
        await browser.isNotExistingScenario()
        const errorVal = await browser.$('body').$('.fooobar').catch(() => 42)
        expect(errorVal).toBe(42)
    })

    it('should allow chaining of custom$', async () => {
        browser.addLocatorStrategy('someSelector', () => global.document.body)
        // @ts-expect-error custom command
        await browser.customSelectorScenario()
        const el = await browser.$('body').custom$('someSelector', 'foo').$('div#foobar')
        expect(el.selector).toBe('div#foobar')
    })

    it('should allow to chain custom commands', async () => {
        // @ts-expect-error custom command
        await browser.isExistingScenario()
        browser.addCommand(
            'foo',
            function (this: WebdriverIO.Element) {
                return Promise.resolve('foo').then((r) => `${r}_${this.selector}_bar`)
            },
            true
        )

        // @ts-expect-error invalid type assertion
        expect(browser.foo).not.toBeDefined()
        // @ts-expect-error invalid type assertion
        expect(await browser.$('body').$('.selector-1').foo()).toBe('foo_.selector-1_bar')
    })

    it('should allow to reload a session', async () => {
        const sessionIdBefore = browser.sessionId
        await browser.reloadSession()
        expect(sessionIdBefore).not.toBe(browser.sessionId)
    })

    it('should handle promises in waitUntil callback funciton using async code', async () => {
        const results: string[] = []
        const result = await browser.waitUntil(async () => {
            results.push(await browser.getUrl())
            return results.length > 1
        })
        assert.strictEqual(result, true)
        assert.deepEqual(results, ['https://mymockpage.com', 'https://mymockpage.com'])
    })

    it('should handle waitUntil timeout', async () => {
        // @ts-expect-error custom command
        await browser.staleElementRefetchScenario()
        const elem = await $('elem')
        try {
            await browser.waitUntil(async () => {
                await elem.click()
                return false
            }, { timeout: 1000 })
        } catch {
            // ignored
        }
        assert.equal(JSON.stringify(await elem.getSize()), JSON.stringify({ width: 1, height: 2 }))
    })

    describe('isDisplayed', () => {
        it('should return false if element is never found', async () => {
            // @ts-expect-error custom command
            await browser.isNeverDisplayedScenario()
            const elem = await $('elem')

            assert.equal(await elem.isDisplayed(), false)
        })

        it('should reFetch the element once', async () => {
            // @ts-expect-error custom command
            await browser.isEventuallyDisplayedScenario()
            const elem = await $('elem')

            assert.equal(await elem.isDisplayed(), true)
        })
    })

    describe('add customCommands', () => {
        it('should allow to call nested custom commands', async () => {
            browser.addCommand('myCustomCommand', async function (param) {
                const result = {
                    url: await browser.getUrl(),
                    title: await browser.getTitle()
                }

                return { param, ...result }
            })

            assert.equal(
                // @ts-expect-error custom command
                JSON.stringify(await browser.myCustomCommand('foobar')),
                JSON.stringify({
                    param: 'foobar',
                    url: 'https://mymockpage.com',
                    title: 'Mock Page Title'
                })
            )
        })

        it('allows to create custom commands on elements', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            const elem = await $('elem')
            elem.addCommand('myCustomCommand', async function (this: WebdriverIO.Element, param) {
                const result = await this.getSize()
                return { selector: this.selector, result, param }
            })

            assert.equal(
                // @ts-expect-error custom command
                JSON.stringify(await elem.myCustomCommand('foobar')),
                JSON.stringify({
                    selector: 'elem',
                    result: { width: 1, height: 2 },
                    param: 'foobar'
                })
            )
        })

        it('should keep the scope', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.addCommand('customFn', async function (this: WebdriverIO.Element, elem: WebdriverIO.Element) {
                return (await this.execute('1+1')) + '-' + elem.selector
            })

            // @ts-expect-error custom command
            assert.equal(await browser.customFn(await $('body')), '2-body')
        })

        it('should respect promises', async () => {
            browser.addCommand('customFn', () => {
                return Promise.resolve('foobar')
            })

            // @ts-expect-error custom command
            assert.equal(await browser.customFn(), 'foobar')
        })

        it('should throw if promise rejects', async () => {
            browser.addCommand('customFn', () => {
                return Promise.reject(new Error('Boom!'))
            })

            await assert.rejects(
                async () => {
                    // @ts-expect-error custom command
                    await browser.customFn()
                },
                error => {
                    const err = error as Error

                    assert.equal(err?.message, 'Boom!')
                    assert.equal(err?.stack?.includes(testJs), true)

                    return true
                }
            )
        })

        it('allows to create custom commands on elements that respects promises', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.addCommand('myCustomPromiseCommand', function () {
                return Promise.resolve('foobar')
            }, true)
            const elem = await $('elem')

            // @ts-expect-error custom command
            assert.equal(await elem.myCustomPromiseCommand(), 'foobar')
        })
    })

    describe('overwrite native commands', () => {
        it('should allow to overwrite browser commands', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('getTitle' as any, async function (origCommand, pre = '') {
                return pre + await origCommand()
            })

            // @ts-expect-error custom command
            assert.equal(await browser.getTitle('Foo '), 'Foo Mock Page Title')
        })

        it('should allow to overwrite element commands', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('getSize', (async (origCommand: Function, ratio = 1) => {
                const { width, height } = await origCommand()
                return { width: width * ratio, height: height * ratio }
            }) as any, true)
            const elem = await $('elem')

            assert.equal(
                // @ts-expect-error custom command
                JSON.stringify(await elem.getSize(2)),
                JSON.stringify({ width: 2, height: 4 })
            )
        })

        it('should allow to invoke native command on different element', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('getSize', (async function (origCommand: Function, ratio = 1) {
                const elemAlt = await $('elemAlt')
                const { width, height } = await origCommand.call(elemAlt)
                return { width: width * ratio, height: height * ratio }
            }) as any, true)
            const elem = await $('elem')

            assert.equal(
                // @ts-expect-error custom command
                JSON.stringify(await elem.getSize(2)),
                JSON.stringify({ width: 20, height: 40 })
            )
        })

        it('should keep the scope', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('saveRecordingScreen', (async function (
                this: WebdriverIO.Browser,
                origCommand: Function,
                filepath: string,
                elem: WebdriverIO.Element
            ) {
                if (elem) {
                    return (await this.execute('1+1')) + '-' + elem.selector
                }
                return origCommand(filepath)
            }) as any)

            // @ts-expect-error custom command
            assert.equal(await browser.saveRecordingScreen(null, await $('body')), '2-body')
        })

        it('should respect promises - browser', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('getUrl' as any, async function (origCommand, append = '') {
                return Promise.resolve((await origCommand()) + append)
            })

            // @ts-expect-error custom command
            assert.equal(await browser.getUrl('/foobar'), 'https://mymockpage.com/foobar')
        })

        it('should respect promises - element', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('getHTML', async function (origCommand) {
                return Promise.resolve(await origCommand())
            }, true)
            const elem = await $('elem')

            assert.equal(await elem.getHTML(), '2')
        })

        it('should throw if promise rejects', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('deleteCookies', (async (origCommand: Function) => {
                await origCommand()
                return Promise.reject(new Error('deleteAllCookies'))
            }) as any)

            await assert.rejects(
                async () => {
                    // @ts-expect-error custom command
                    await browser.deleteCookies(true)
                },
                error => {
                    const err = error as Error

                    assert.equal(err?.message, 'deleteAllCookies')
                    assert.equal(err?.stack?.includes(testJs), true)

                    return true
                }
            )
        })

        it('should throw if promise rejects (async execution)', async () => {
            // @ts-expect-error custom command
            await browser.customCommandScenario()
            browser.overwriteCommand('deleteCookies', async (origCommand: Function) => {
                await origCommand()
                return Promise.reject(new Error('deleteAllCookies'))
            })

            await assert.rejects(
                async () => {
                    // @ts-expect-error custom command
                    await browser.deleteCookies(true)
                },
                error => {
                    const err = error as Error

                    assert.equal(err?.message, 'deleteAllCookies')
                    assert.equal(err?.stack?.includes(testJs), true)

                    return true
                }
            )
        })
    })

    describe('supports async iteration', () => {
        beforeEach(async () => {
            // @ts-expect-error custom command
            await browser.asyncIterationScenario()
        })

        it('by chaining commands', async () => {
            expect(await $$('elem').map((el) => el.getText())).toEqual(
                ['some element text', 'some other element text'])
        })

        it('by defining vars first', async () => {
            const elements = await $$('elem')
            expect(await elements.map((el) => el.getText())).toEqual(
                ['some element text', 'some other element text'])
        })
    })

    describe('supports refetching elements', () => {
        it('should refetch elements', async () => {
            // @ts-expect-error mock feature
            await browser.refetchElementScenario()
            expect(await browser.$$('.foo')[3].getText()).toBe('some element text 4')
        })
    })

    describe('request retries', () => {
        it('should retry request', async () => {
            // @ts-expect-error mock feature
            await browser.requestRetryScenario()
            await browser.url('https://mymockpage.com')
        })
    })

    describe('waitForExist', () => {
        it('should return true if element exists', async () => {
            // @ts-expect-error custom command
            await browser.waitForExistScenario()
            const elem = await $('elem')
            expect(elem.error).toBeDefined()
            expect(elem.elementId).toBeUndefined()
            expect(await elem.waitForExist()).toBe(true)
            expect(elem.error).toBeUndefined()
            expect(elem.elementId).toBeDefined()
        })
    })

    it('supports inline snapshots', () => {
        expect({ deep: { foo: 'bar' } }).toMatchInlineSnapshot(`
          {
            "deep": {
              "foo": "bar",
            },
          }
        `)
    })
})