🏡 index : quine-global/webdriverio.git

import path from 'node:path'
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
import type { Capabilities, Frameworks } from '@wdio/types'

import TestingBotService from '../src/service.js'

const uri = '/some/uri'
const featureObject = {
    name: 'Create a feature'
} as any

vi.mock('fetch')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))

describe('wdio-testingbot-service', () => {
    let browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser
    beforeEach(() => {
        browser = {
            executeScript: vi.fn(),
            sessionId: 'globalSessionId',
            requestHandler: {
                auth: {
                    user: 'user',
                    pass: 'pass'
                }
            },
            config: {},
            getInstance: vi.fn().mockImplementation((browserName: string) => {
                // @ts-expect-error
                return browser[browserName] as WebdriverIO.Browser
            }),
            chromeA: { sessionId: 'sessionChromeA', executeScript: vi.fn() },
            chromeB: { sessionId: 'sessionChromeB', executeScript: vi.fn() },
            chromeC: { sessionId: 'sessionChromeC', executeScript: vi.fn() },
            instances: ['chromeA', 'chromeB', 'chromeC'],
        } as unknown as WebdriverIO.MultiRemoteBrowser
    })

    afterEach(() => {
        vi.mocked(fetch).mockClear()
    })

    it('before', () => {
        const caps = {
            name: 'Test suite',
            tags: ['tag1', 'tag2'],
            public: true,
            build: 344
        } as Capabilities.RemoteCapability
        const tbService = new TestingBotService(
            {},
            caps,
            {
                user: 'foobar',
                key: 'fookey'
            }
        )
        expect(tbService['_capabilities']).toEqual(caps)
        expect(tbService['_tbUser']).toEqual('foobar')
        expect(tbService['_tbSecret']).toEqual('fookey')
        expect(tbService['_testCnt']).toEqual(0)
        expect(tbService['_failures']).toEqual(0)
    })

    it('beforeSuite', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        const suiteTitle = 'Test Suite Title'
        tbService.beforeSuite({ title: suiteTitle } as Frameworks.Suite)

        expect(tbService['_suiteTitle']).toEqual(suiteTitle)
    })

    it('beforeTest: setAnnotation not called', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        const test = {
            fullName: 'Test #1',
            parent: 'Test parent'
        } as Frameworks.Test
        tbService['_tbUser'] = undefined
        tbService['_tbSecret'] = undefined
        tbService['_suiteTitle'] = 'Test suite'
        tbService.beforeTest(test)

        expect(tbService.setAnnotation).not.toBeCalled()
        expect(tbService['_suiteTitle']).toEqual('Test suite')
    })

    it('beforeTest: setAnnotation called', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        const test: Frameworks.Test = {
            name: 'Test name',
            fullName: 'Test #1',
            title: 'Test title',
            parent: 'Test parent'
        } as any
        tbService.beforeSuite({ title: 'Test suite' } as Frameworks.Suite)
        await tbService.beforeTest(test)

        expect(tbService.setAnnotation).toBeCalledWith('tb:test-context=Test #1')
        expect(tbService['_suiteTitle']).toEqual('Test suite')
    })

    it('beforeTest: setAnnotation called for Jasmine tests', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        const test: Frameworks.Test = {
            name: 'Test name',
            fullName: 'Test #1',
            title: 'Test title',
            parent: 'Test parent'
        } as any

        tbService.beforeSuite({ title: 'Jasmine__TopLevel__Suite' } as Frameworks.Suite)
        await tbService.beforeTest(test)

        expect(tbService.setAnnotation).toBeCalledWith('tb:test-context=Test #1')
        expect(tbService['_suiteTitle']).toEqual('Test ')
    })

    it('beforeTest: setAnnotation called for Mocha test', () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        const test: Frameworks.Test = {
            name: 'Test name',
            title: 'Test title',
            parent: 'Test parent'
        } as any

        tbService.beforeSuite({} as Frameworks.Suite)
        tbService.beforeTest(test)

        expect(tbService.setAnnotation).toBeCalledWith('tb:test-context=Test parent - Test title')
    })

    it('afterTest: failed test', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        tbService['_failures'] = 0
        const testResult = {
            passed: true
        } as Frameworks.TestResult
        tbService.afterTest({} as Frameworks.Test, {}, testResult)

        expect(tbService['_failures']).toEqual(0)
    })

    it('afterTest: passed test', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        tbService['_failures'] = 0
        const testResult = {
            passed: false
        } as Frameworks.TestResult
        tbService.afterTest({} as Frameworks.Test, {}, testResult)

        expect(tbService['_failures']).toEqual(1)
    })

    it('beforeFeature: setAnnotation not called', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        tbService.beforeFeature(uri, featureObject)

        expect(tbService.setAnnotation).not.toBeCalled()
    })

    it('beforeFeature: setAnnotation called', () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        tbService.beforeFeature(uri, featureObject)

        expect(tbService['_suiteTitle']).toEqual('Create a feature')
        expect(tbService.setAnnotation).toBeCalledWith('tb:test-context=Feature: Create a feature')
    })

    it('afterScenario: exception happened', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        tbService['_failures'] = 0

        expect(tbService['_failures']).toBe(0)

        tbService.afterScenario({} as any, { passed: true })
        expect(tbService['_failures']).toBe(0)

        tbService.afterScenario({} as any, { passed: false })
        expect(tbService['_failures']).toBe(1)

        tbService.afterScenario({} as any, { passed: true })
        expect(tbService['_failures']).toBe(1)

        tbService.afterScenario({} as any, { passed: false })
        expect(tbService['_failures']).toBe(2)
    })

    it('beforeScenario: setAnnotation not called', () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: undefined
        })
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        tbService.beforeScenario({ pickle: {} })

        expect(tbService.setAnnotation).not.toBeCalled()
    })

    it('beforeScenario: setAnnotation called', () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        tbService.setAnnotation = vi.fn()
        tbService.beforeScenario({ pickle: { name: 'Scenario name' } })

        expect(tbService.setAnnotation).toBeCalledWith('tb:test-context=Scenario: Scenario name')
    })

    it('after: updatedJob not called', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: undefined,
            key: undefined
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')
        await tbService.after()

        expect(updateJobSpy).not.toBeCalled()
    })

    it('after: updatedJob called with passed params', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret',
            mochaOpts: { bail: true }
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')
        tbService['_browser'].sessionId = 'sessionId'

        tbService['_failures'] = 2
        await tbService.after()

        expect(updateJobSpy).toBeCalledWith('sessionId', 2)
    })

    it('after: updatedJob called when bailed', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret',
            mochaOpts: { bail: true }
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')
        tbService['_browser'].sessionId = 'sessionId'
        await tbService.after(10)

        expect(updateJobSpy).toBeCalledWith('sessionId', 1)
    })

    it('after: updatedJob called when status passed', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret',
            mochaOpts: { bail: true }
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')
        tbService['_browser'].sessionId = 'sessionId'

        tbService['_failures'] = 0
        await tbService.after()

        expect(updateJobSpy).toBeCalledWith('sessionId', 0)
    })

    it('after: with multi-remote: updatedJob called with passed params', async () => {
        const caps = {
            chromeA: { capabilities: {} },
            chromeB: { capabilities: {} },
            chromeC: { capabilities: {} }
        }
        const tbService = new TestingBotService({}, caps, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')

        tbService['_browser'].isMultiremote = true
        tbService['_browser'].sessionId = 'sessionId'
        tbService['_failures'] = 2
        await tbService.after()

        expect(updateJobSpy).toBeCalledWith('sessionChromeA', 2, false, 'chromeA')
        expect(updateJobSpy).toBeCalledWith('sessionChromeB', 2, false, 'chromeB')
        expect(updateJobSpy).toBeCalledWith('sessionChromeC', 2, false, 'chromeC')
    })

    it('onReload: updatedJob not called', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: undefined,
            key: undefined
        })
        tbService['_browser'] = browser
        const tbService2 = new TestingBotService({}, {}, {})
        tbService2['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService2, 'updateJob')

        tbService['_browser'].sessionId = 'sessionId'
        await tbService.onReload('oldSessionId', 'newSessionId')

        expect(updateJobSpy).not.toBeCalled()
    })

    it('onReload: updatedJob called with passed params', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')

        tbService['_browser'].sessionId = 'sessionId'
        tbService['_failures'] = 2
        await tbService.onReload('oldSessionId', 'newSessionId')

        expect(updateJobSpy).toBeCalledWith('oldSessionId', 2, true)
        expect(vi.mocked(fetch).mock.calls[0][1]?.method).toEqual('PUT')
    })

    it('onReload with multi-remote: updatedJob called with passed params', async () => {
        const tbService = new TestingBotService({}, {}, {
            user: 'user',
            key: 'secret'
        })
        tbService['_browser'] = browser
        const updateJobSpy = vi.spyOn(tbService, 'updateJob')

        tbService['_browser'].isMultiremote = true
        tbService['_browser'].sessionId = 'sessionId'
        tbService['_failures'] = 2
        await tbService.onReload('oldSessionId', 'sessionChromeA')

        expect(updateJobSpy).toBeCalledWith('oldSessionId', 2, true, 'chromeA')
        expect(vi.mocked(fetch).mock.calls[0][1]?.method).toEqual('PUT')
    })

    it('getRestUrl', () => {
        const tbService = new TestingBotService({}, {}, {})
        tbService['_browser'] = browser
        expect(tbService.getRestUrl('testSessionId'))
            .toEqual('https://api.testingbot.com/v1/tests/testSessionId')
    })

    it('getBody', () => {
        const caps = {
            name: 'Test suite',
            tags: ['tag1', 'tag2'],
            public: true,
            build: 344
        }
        const tbService = new TestingBotService({}, caps, {})
        tbService['_browser'] = browser
        tbService.beforeSuite({ title: 'Suite title' } as Frameworks.Suite)

        expect(tbService.getBody(0, false)).toEqual({
            test: {
                build: 344,
                name: 'Test suite',
                public: true,
                success: '1',
                tags: ['tag1', 'tag2']
            }
        })

        tbService['_testCnt'] = 2
        expect(tbService.getBody(2, true)).toEqual({
            test: {
                build: 344,
                name: 'Test suite',
                public: true,
                success: '0',
                tags: ['tag1', 'tag2']
            }
        })
    })

    it('getBody should contain browserName if passed', () => {
        const caps = {
            name: 'Test suite',
            tags: ['tag3', 'tag4'],
            public: true,
            build: 344
        }
        const tbService = new TestingBotService({}, caps, {})
        tbService['_browser'] = browser

        expect(tbService.getBody(0, false, 'internet explorer')).toEqual({
            test: {
                build: 344,
                name: 'internet explorer: Test suite',
                public: true,
                success: '1',
                tags: ['tag3', 'tag4']
            }
        })
    })

    it('updateJob success', async () => {
        const user = 'foobar'
        const key = '123'
        const service = new TestingBotService({}, {}, { user: user, key: key })
        service['_browser'] = browser
        service['_suiteTitle'] = 'my test'

        await service.updateJob('12345', 23, true)

        expect(service['_failures']).toBe(0)
        expect(vi.mocked(fetch).mock.calls[0][1]?.method).toEqual('PUT')
        const encodedAuth = Buffer.from(`${user}:${key}`, 'utf8').toString('base64')
        expect(vi.mocked(fetch).mock.calls[0][1]?.headers?.Authorization).toEqual(`Basic ${encodedAuth}`)
    })

    it('updateJob failure', async () => {
        const response: any = new Error('Failure')
        response.statusCode = 500
        vi.mocked(fetch).mockRejectedValue(response)

        const service = new TestingBotService({}, {}, { user: 'foobar', key: '123' })
        service['_browser'] = browser
        service['_suiteTitle'] = 'my test'
        const err: any = await service.updateJob('12345', 23, true).catch((err) => err)
        expect(err.message).toBe('Failure')

        expect(vi.mocked(fetch).mock.calls[0][1]?.method).toEqual('PUT')
        expect(service['_failures']).toBe(0)
    })

    it('afterSuite', () => {
        const service = new TestingBotService({}, {}, {})
        service['_browser'] = browser
        expect(service['_failures']).toBe(0)
        service.afterSuite({} as Frameworks.Suite)
        expect(service['_failures']).toBe(0)
        service.afterSuite({ error: new Error('boom!') } as Frameworks.Suite)
        expect(service['_failures']).toBe(1)
    })
})