🏡 index : quine-global/webdriverio.git

/// <reference path="../../webdriverio/src/@types/async.d.ts" />
import path from 'node:path'

import { describe, expect, it, vi, beforeEach, afterEach, beforeAll, afterAll } from 'vitest'
import logger from '@wdio/logger'
import type { StdLog } from '../src/index.js'

import InsightsHandler from '../src/insights-handler.js'
import * as utils from '../src/util.js'
import * as bstackLogger from '../src/bstackLogger.js'
import { TESTOPS_SCREENSHOT_ENV } from '../src/constants.js'

const log = logger('test')
let insightsHandler: InsightsHandler
let browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser

vi.mock('fetch')
vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger')))
vi.useFakeTimers().setSystemTime(new Date('2020-01-01'))
vi.mock('uuid', () => ({ v4: () => '123456789' }))

const bstackLoggerSpy = vi.spyOn(bstackLogger.BStackLogger, 'logToFile')
bstackLoggerSpy.mockImplementation(() => {})

beforeEach(() => {
    vi.mocked(log.info).mockClear()
    vi.mocked(fetch).mockClear()
    vi.mocked(fetch).mockReturnValue(Promise.resolve(Response.json({ automation_session: {
        browser_url: 'https://www.browserstack.com/automate/builds/1/sessions/2'
    } })))

    browser = {
        sessionId: 'session123',
        config: {},
        capabilities: {
            device: '',
            os: 'OS X',
            os_version: 'Sierra',
            browserName: 'chrome'
        },
        instances: ['browserA', 'browserB'],
        isMultiremote: false,
        browserA: {
            sessionId: 'session456',
            capabilities: { 'bstack:options': {
                device: '',
                os: 'Windows',
                osVersion: 10,
                browserName: 'chrome'
            } }
        },
        getInstance: vi.fn().mockImplementation((browserName: string) => browser[browserName]),
        browserB: {},
        execute: vi.fn(),
        on: vi.fn(),
    } as unknown as WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser
    insightsHandler = new InsightsHandler(browser, 'framework')
})

it('should initialize correctly', () => {
    insightsHandler = new InsightsHandler(browser, 'framework')
    expect(insightsHandler['_tests']).toEqual({})
    expect(insightsHandler['_hooks']).toEqual({})
    expect(insightsHandler['_commands']).toEqual({})
    expect(insightsHandler['_framework']).toEqual('framework')
})

describe('before', () => {
    const isBrowserstackSessionSpy = vi.spyOn(utils, 'isBrowserstackSession')

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        isBrowserstackSessionSpy.mockClear()
    })

    it('calls isBrowserstackSession', () => {
        insightsHandler.before()
        expect(isBrowserstackSessionSpy).toBeCalledTimes(1)
    })

    it('isBrowserstackSession returns true', () => {
        isBrowserstackSessionSpy.mockReturnValue(true)
        insightsHandler.before()
        expect(isBrowserstackSessionSpy).toBeCalledTimes(1)
    })
})

describe('beforeScenario', () => {
    let insightsHandler: InsightsHandler

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        vi.spyOn(utils, 'getUniqueIdentifierForCucumber').mockReturnValue('test title')
        insightsHandler['getTestRunDataForCucumber'] = vi.fn()
        insightsHandler['_tests'] = {}
    })

    it('sendTestRunEventForCucumber called', () => {
        insightsHandler.beforeScenario({
            pickle: {
                name: 'pickle-name',
                tags: []
            },
            gherkinDocument: {
                uri: '',
                feature: {
                    name: 'feature-name',
                    description: ''
                }
            }
        } as any)
        expect(insightsHandler['getTestRunDataForCucumber']).toBeCalledTimes(1)
    })
})

describe('afterScenario', () => {
    let insightsHandler: InsightsHandler

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        insightsHandler['getTestRunDataForCucumber'] = vi.fn()
        insightsHandler['_tests'] = {}
    })

    it('sendTestRunEventForCucumber called', () => {
        insightsHandler.afterScenario({
            pickle: {
                name: 'pickle-name',
                tags: []
            },
            gherkinDocument: {
                uri: '',
                feature: {
                    name: 'feature-name',
                    description: ''
                }
            }
        } as any)
        expect(insightsHandler['getTestRunDataForCucumber']).toBeCalledTimes(1)
    })
})

describe('beforeStep', () => {
    let insightsHandler: InsightsHandler

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        vi.spyOn(utils, 'getUniqueIdentifierForCucumber').mockReturnValue('test title')
        insightsHandler['getHierarchy'] = vi.fn().mockImplementation(() => { return [] })
    })

    it('update test data', () => {
        insightsHandler['_tests'] = {
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' }
            }
        }
        insightsHandler.beforeStep({ id: 'step_id', text: 'this is step', keyword: 'Given' } as any, {} as any)
        expect(insightsHandler['_tests']).toEqual({
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' },
                steps: [{
                    id: 'step_id',
                    text: 'this is step',
                    keyword: 'Given',
                    started_at: '2020-01-01T00:00:00.000Z'
                }]
            }
        })
    })

    it('add test data', () => {
        insightsHandler['_tests'] = { }
        insightsHandler.beforeStep({ id: 'step_id', text: 'this is step', keyword: 'Given' } as any, {} as any)
        expect(insightsHandler['_tests']).toEqual({
            'test title': {
                steps: [{
                    id: 'step_id',
                    text: 'this is step',
                    keyword: 'Given',
                    started_at: '2020-01-01T00:00:00.000Z'
                }]
            }
        })
    })
})

describe('afterStep', () => {
    let insightsHandler: InsightsHandler

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        vi.spyOn(utils, 'getUniqueIdentifierForCucumber').mockReturnValue('test title')
        insightsHandler['getHierarchy'] = vi.fn().mockImplementation(() => { return [] })
    })

    it('update test data - passed case', () => {
        insightsHandler['_tests'] = {
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' }
            }
        }
        insightsHandler.afterStep({ id: 'step_id', text: 'this is step', keyword: 'Given' } as any, {} as any, {
            passed: true,
            duration: 10,
            error: undefined
        })
        expect(insightsHandler['_tests']).toEqual({
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' },
                steps: [{
                    id: 'step_id',
                    text: 'this is step',
                    keyword: 'Given',
                    'result': 'PASSED',
                    duration: 10,
                    failure: undefined,
                    finished_at: '2020-01-01T00:00:00.000Z'
                }]
            }
        })
    })

    it('update test data - step present', () => {
        insightsHandler['_tests'] = {
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' },
                steps: [{ id: 'step_id' }]
            }
        }
        insightsHandler.afterStep({ id: 'step_id', text: 'this is step', keyword: 'Given' } as any, {} as any, {
            passed: true,
            duration: 10,
            error: undefined
        })
        expect(insightsHandler['_tests']).toEqual({
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' },
                steps: [{
                    id: 'step_id',
                    result: 'PASSED',
                    duration: 10,
                    failure: undefined,
                    finished_at: '2020-01-01T00:00:00.000Z'
                }]
            }
        })
    })

    it('add test data', () => {
        insightsHandler['_tests'] = { }
        insightsHandler.afterStep({ id: 'step_id', text: 'this is step', keyword: 'Given' } as any, {} as any, {
            passed: true,
            duration: 10,
            error: undefined
        })
        expect(insightsHandler['_tests']).toEqual({ 'test title': { steps: [] } })
    })

    it('failed case', () => {
        insightsHandler['_tests'] = {
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' },
                steps: [{ id: 'step_id' }]
            }
        }
        insightsHandler.afterStep({ id: 'step_id', text: 'this is step', keyword: 'Given' } as any, {} as any, {
            passed: false,
            duration: 10,
            error: 'this is a error'
        })
        expect(insightsHandler['_tests']).toEqual({
            'test title': {
                uuid: 'uuid',
                startedAt: '',
                finishedAt: '',
                feature: { name: 'name', path: 'path', description: 'description' },
                scenario: { name: 'name' },
                steps: [{
                    id: 'step_id',
                    result: 'FAILED',
                    duration: 10,
                    failure: 'this is a error',
                    finished_at: '2020-01-01T00:00:00.000Z'
                }]
            }
        })
    })
})

describe('attachHookData', () => {
    let insightsHandler: InsightsHandler

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })

    it('add hooks data in test', () => {
        insightsHandler['_hooks'] = {}
        insightsHandler['attachHookData']({
            currentTest: {
                title: 'test',
                parent: {
                    title: 'parent'
                }
            }
        } as any, 'hook_id')
        expect(insightsHandler['_hooks']).toEqual({ 'parent - test': ['hook_id'] })
    })

    it('push hooks data in test', () => {
        insightsHandler['_hooks'] = { 'parent - test': ['hook_id_old'] }
        insightsHandler['attachHookData']({
            currentTest: {
                title: 'test',
                parent: {
                    title: 'parent'
                }
            }
        } as any, 'hook_id')
        expect(insightsHandler['_hooks']).toEqual({ 'parent - test': ['hook_id_old', 'hook_id'] })
    })

    it('add hook data in test from suite tests', () =>{
        insightsHandler['_hooks'] = {}
        insightsHandler['attachHookData']({
            test: {
                parent: {
                    tests: [{
                        title: 'test',
                        parent: 'parent'
                    }],
                }
            }
        } as any, 'hook_id_from_test')
        expect(insightsHandler['_hooks']).toEqual({ 'parent - test': ['hook_id_from_test'] })
    })

})

describe('setHooksFromSuite', () => {
    let insightsHandler: InsightsHandler
    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        insightsHandler['_hooks'] = {}
    })

    it('should return false if parent is null', () => {
        const result = insightsHandler['setHooksFromSuite'](null, 'hook_id')
        expect(result).toEqual(false)
        expect(insightsHandler['_hooks']).toEqual({})
    })

    it('should add hook data from nested suite tests', () => {
        const result = insightsHandler['setHooksFromSuite']({
            suites: [{
                tests: [{
                    title: 'test inside suite',
                    parent: 'parent'
                }],
            }],
        } as any, 'hook_id_from_test')
        expect(result).toEqual(true)
        expect(insightsHandler['_hooks']).toEqual({ 'parent - test inside suite': ['hook_id_from_test'] })
    })
})

describe('getHierarchy', () => {
    let insightsHandler

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })

    it('return array of getHierarchy when context present', () => {
        expect(insightsHandler['getHierarchy']({
            ctx: {
                test: {
                    parent: {
                        title: 'test 2',
                        parent: {
                            title: 'test 1'
                        }
                    }
                }
            }
        } as any)).toEqual(['test 1', 'test 2'])
    })

    it('return empty array when no context present', () => {
        expect(insightsHandler['getHierarchy']({} as any)).toEqual([])
    })
})

describe('getTestRunId', function () {
    let insightsHandler: InsightsHandler
    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })

    it('should return if null context', () => {
        expect(insightsHandler['getTestRunId'](null)).toEqual(undefined)
    })

    it('return test id from current test', () => {
        const identifier = 'parent title - some title'
        insightsHandler['_tests'] = { [identifier]: { uuid: '1234' } }
        expect(insightsHandler['getTestRunId']({
            currentTest: {
                title: 'some title',
                parent: 'parent title'
            }
        })).toEqual('1234')
    })

    it('return test id from test', () => {
        const identifier = 'parent title - child title'
        insightsHandler['_tests'] = { [identifier]: { uuid: 'some_uuid' } }
        expect(insightsHandler['getTestRunId']({
            test: {
                parent: {
                    tests: [{
                        title: 'child title',
                        parent: 'parent title'
                    }]
                },
            }
        })).toEqual('some_uuid')
    })
})

describe('getTestRunIdFromSuite', function () {
    let insightsHandler: InsightsHandler
    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })

    it('should return null if parent null', function () {
        expect(insightsHandler['getTestRunIdFromSuite'](null)).toEqual(undefined)
    })

    it('should return test run id from nested suite', () => {
        insightsHandler['_tests'] = { ['suite title - nested test title']: { uuid: 'some_nested_uuid' } }
        expect(insightsHandler['getTestRunIdFromSuite']({
            tests: [],
            suites: [{
                tests: [{
                    title: 'nested test title',
                    parent: 'suite title'
                }]
            }]
        })).toEqual('some_nested_uuid')
    })
})

describe('beforeTest', () => {
    let insightsHandler: InsightsHandler

    describe('mocha', () => {
        beforeEach(() => {
            insightsHandler = new InsightsHandler(browser, 'mocha')
            insightsHandler['getRunData'] = vi.fn().mockImplementation(() => { return [] })
            vi.spyOn(utils, 'getUniqueIdentifier').mockReturnValue('test title')
            insightsHandler['_tests'] = {}
            insightsHandler['_hooks'] = {
                'test title': ['hook_id']
            }
        })

        it('update test data', async () => {
            await insightsHandler.beforeTest({ parent: 'parent', title: 'test' } as any)
            expect(insightsHandler['_tests']).toEqual({ 'test title': { uuid: '123456789', startedAt: '2020-01-01T00:00:00.000Z' } })
            expect(insightsHandler['getRunData']).toBeCalledTimes(1)
        })
    })

    describe('jasmine', () => {
        beforeEach(() => {
            insightsHandler = new InsightsHandler(browser, 'jasmine')
            insightsHandler['getRunData'] = vi.fn().mockImplementation(() => { return [] })
            insightsHandler['_tests'] = {}
        })

        it('shouldn\'t update test data', async () => {
            await insightsHandler.beforeTest({ parent: 'parent', fullName: 'parent test' } as any)
            expect(insightsHandler['_tests']).toEqual({})
            expect(insightsHandler['getRunData']).toBeCalledTimes(0)
        })
    })
})

describe('beforeHook', () => {
    let insightsHandler: InsightsHandler

    describe('mocha', () => {
        beforeEach(() => {
            insightsHandler = new InsightsHandler(browser, 'mocha')
            insightsHandler['getRunData'] = vi.fn().mockImplementation(() => { return [] })
            insightsHandler['attachHookData'] = vi.fn().mockImplementation(() => { return [] })
            insightsHandler['_tests'] = {}
            insightsHandler['_framework'] = 'mocha'
        })

        beforeEach(() => {
            vi.mocked(insightsHandler['getRunData']).mockClear()
            vi.mocked(insightsHandler['attachHookData']).mockClear()
            vi.spyOn(utils, 'getUniqueIdentifier').mockReturnValue('parent - test')
        })

        it('update hook data', async () => {
            await insightsHandler.beforeHook({ parent: 'parent', title: 'test' } as any, {} as any)
            expect(insightsHandler['_tests']).toEqual({ 'parent - test': { uuid: '123456789', startedAt: '2020-01-01T00:00:00.000Z' } })
            expect(insightsHandler['getRunData']).toBeCalledTimes(1)
        })
    })

    describe('cucumber', () => {
        beforeEach(() => {
            insightsHandler = new InsightsHandler(browser, 'cucumber')
            insightsHandler['processCucumberHook'] = vi.fn().mockImplementation(() => { return [] })
            insightsHandler['_framework'] = 'cucumber'
        })

        it('should call cucumber hook processor', async () => {
            await insightsHandler.beforeHook(undefined as any, {} as any)
            expect(insightsHandler['processCucumberHook']).toBeCalledTimes(1)
        })
    })
})

describe('afterHook', () => {
    let insightsHandler: InsightsHandler

    describe('mocha', () => {
        beforeEach(() => {
            insightsHandler = new InsightsHandler(browser, 'mocha')
            insightsHandler['getRunData'] = vi.fn().mockImplementation(() => { return [] })
            insightsHandler['attachHookData'] = vi.fn().mockImplementation(() => { return [] })

            vi.spyOn(utils, 'getUniqueIdentifier').mockReturnValue('test title')
            vi.spyOn(utils, 'getUniqueIdentifierForCucumber').mockReturnValue('test title')
            vi.mocked(insightsHandler['getRunData']).mockClear()
            vi.mocked(insightsHandler['attachHookData']).mockClear()
        })

        it('add hook data', async () => {
            insightsHandler['_tests'] = {}
            await insightsHandler.afterHook({ parent: 'parent', title: 'test' } as any, {} as any)
            expect(insightsHandler['_tests']).toEqual({ 'test title': { finishedAt: '2020-01-01T00:00:00.000Z', } })
            expect(insightsHandler['getRunData']).toBeCalledTimes(1)
        })

        it('update hook data', async () => {
            insightsHandler['_tests'] = { 'test title': {} }
            await insightsHandler.afterHook({ parent: 'parent', title: 'test' } as any, {} as any)
            expect(insightsHandler['_tests']).toEqual({ 'test title': { finishedAt: '2020-01-01T00:00:00.000Z', } })
            expect(insightsHandler['getRunData']).toBeCalledTimes(1)
        })
    })

    describe('cucumber', () => {
        beforeEach(() => {
            insightsHandler = new InsightsHandler(browser, 'cucumber')
            insightsHandler['processCucumberHook'] = vi.fn().mockImplementation(() => { return [] })
        })

        it('should call cucumber hook processor', async () => {
            await insightsHandler.afterHook(undefined as any, {} as any)
            expect(insightsHandler['processCucumberHook']).toBeCalledTimes(1)
        })
    })
})

describe('getIntegrationsObject', () => {
    let insightsHandler: InsightsHandler
    let getPlatformVersionSpy

    beforeAll(() => {
        getPlatformVersionSpy = vi.spyOn(utils, 'getPlatformVersion').mockImplementation(() => { return 'some version' })
    })

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        insightsHandler['_platformMeta'] = { caps: {},  sessionId: '', browserName: '', browserVersion: '', platformName: '', product: '' }
    })

    it('return hash', () => {
        const integrationsObject = insightsHandler['getIntegrationsObject']()
        expect(integrationsObject).toBeInstanceOf(Object)
        expect(integrationsObject.platform_version).toEqual('some version')
    })

    it('should fetch latest details', () => {
        const existingSessionId = browser.sessionId
        const existingOs = browser.capabilities.os
        browser.sessionId = 'session-new'
        browser.capabilities.os = 'Windows'
        const integrationsObject = insightsHandler['getIntegrationsObject']()
        expect(integrationsObject.session_id).toEqual('session-new')
        expect(integrationsObject.capabilities.os).toEqual('Windows')
        browser.sessionId = existingSessionId
        browser.capabilities.os = existingOs
    })

    afterAll(() => {
        getPlatformVersionSpy.mockReset()
    })
})

describe('browserCommand', () => {
    let insightsHandler: InsightsHandler
    let uploadEventDataSpy
    let commandSpy

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        insightsHandler['getIdentifier'] = vi.fn().mockImplementation(() => { return 'test title' })
        insightsHandler['_tests'] = { 'test title': { 'uuid': 'uuid' } }
        insightsHandler['_commands'] = { 's_m_e': {} as any }

        uploadEventDataSpy = vi.spyOn(insightsHandler['listener'], 'onScreenshot').mockImplementation(() => { return [] as any })
        commandSpy = vi.spyOn(utils, 'isScreenshotCommand')
    })

    it('client:beforeCommand', () => {
        insightsHandler.browserCommand('client:beforeCommand', {} as any, {} as any)
        expect(uploadEventDataSpy).toBeCalledTimes(0)
    })

    it('client:afterCommand - test not defined', () => {
        insightsHandler.browserCommand('client:afterCommand', { sessionId: 's', method: 'm', endpoint: 'e', result: {} } as any, undefined)
        expect(uploadEventDataSpy).toBeCalledTimes(0)
    })

    it('client:afterCommand - screenshot', () => {
        process.env[TESTOPS_SCREENSHOT_ENV] = 'true'
        commandSpy.mockImplementation(() => { return true })
        insightsHandler.browserCommand('client:afterCommand', { sessionId: 's', method: 'm', endpoint: 'e', result: { value: 'random' } } as any, {} as any)
        expect(uploadEventDataSpy).toBeCalled()
        delete process.env[TESTOPS_SCREENSHOT_ENV]
    })

    it('return if test not in _tests', () => {
        insightsHandler.browserCommand('client:afterCommand', { sessionId: 's', method: 'm', endpoint: 'e', result: { value: 'random' } } as any, {} as any)
        insightsHandler['_tests'] = { 'test title not there': { 'uuid': 'uuid' } }
        expect(uploadEventDataSpy).toBeCalledTimes(0)
    })

    it('return if command not in _commands', () => {
        insightsHandler['_commands'] = { 'command not here': {} }
        insightsHandler.browserCommand('client:afterCommand', { sessionId: 's', method: 'm', endpoint: 'e', result: { value: 'random' } }, {})
        expect(uploadEventDataSpy).toBeCalledTimes(0)
    })
})

describe('getIdentifier', () => {
    let insightsHandler: InsightsHandler
    let getUniqueIdentifierSpy
    let getUniqueIdentifierForCucumberSpy

    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
        insightsHandler['_tests'] = { 'test title': { 'uuid': 'uuid' } }

        getUniqueIdentifierSpy = vi.spyOn(utils, 'getUniqueIdentifier')
        getUniqueIdentifierForCucumberSpy = vi.spyOn(utils, 'getUniqueIdentifierForCucumber')
    })

    it('non cucumber', () => {
        insightsHandler['getIdentifier']({ parent: 'parent', title: 'title' } as any)
        expect(getUniqueIdentifierSpy).toBeCalledTimes(1)
    })

    it('cucumber', () => {
        insightsHandler['getIdentifier']({ pickle: { uri: 'uri', astNodeIds: ['9', '8'] } } as any)
        expect(getUniqueIdentifierForCucumberSpy).toBeCalledTimes(1)
    })

    afterEach(() => {
        getUniqueIdentifierSpy.mockReset()
        getUniqueIdentifierForCucumberSpy.mockReset()
    })
})

describe('getCucumberHookType', function () {
    it('should return BEFORE_ALL', function () {
        expect(insightsHandler['getCucumberHookType'](undefined)).toEqual('BEFORE_ALL')
    })

    it('should return AFTER_ALL', function () {
        insightsHandler['_cucumberData'].scenariosStarted = true
        expect(insightsHandler['getCucumberHookType'](undefined)).toEqual('AFTER_ALL')
    })

    it('should return BEFORE_EACH', function () {
        expect(insightsHandler['getCucumberHookType']({ id: '1', hookId: '2' })).toEqual('BEFORE_EACH')
    })

    it('should return AFTER_EACH', function () {
        insightsHandler['_cucumberData'].scenariosStarted = true
        insightsHandler['_cucumberData'].stepsStarted = true
        expect(insightsHandler['getCucumberHookType']({ id: '1', hookId: '2' })).toEqual('AFTER_EACH')
    })

    it('should return null if step hook', function () {
        Object.assign(insightsHandler['_cucumberData'], {
            scenariosStarted: true,
            stepsStarted: true,
            steps: [{}]
        })
        expect(insightsHandler['getCucumberHookType']({ id: '1', hookId: '2' })).toEqual(null)
    })
})

describe('getCucumberHookUniqueId', function () {
    let insightsHandler: InsightsHandler
    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })

    it('should return hookId for each hooks', function () {
        expect(insightsHandler['getCucumberHookUniqueId']('BEFORE_EACH', { id: '1', hookId: '2' })).toBe('2')
    })

    it('should return unique id with feature for all hooks', function () {
        Object.assign(insightsHandler['_cucumberData'], {
            uri: 'filename',
            feature: { name: 'some name' }
        })
        const hookUniqueId = 'AFTER_ALL for filename:some name'
        expect(insightsHandler['getCucumberHookUniqueId']('AFTER_ALL', undefined)).toBe(hookUniqueId)
    })
})

describe('appendTestItemLog', function () {
    let insightsHandler: InsightsHandler
    let sendDataSpy
    const logObj: StdLog = {
        timestamp: new Date().toISOString(),
        level: 'INFO',
        message: 'some log',
        kind: 'TEST_LOG',
        http_response: {}
    }
    let testLogObj: StdLog
    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'mocha')
        sendDataSpy = vi.spyOn(insightsHandler['listener'], 'logCreated').mockImplementation(() => { return [] as any })
        testLogObj = { ...logObj }
    })

    it('should upload with current test uuid for log', function () {
        InsightsHandler['currentTest'] = { uuid: 'some_uuid' }
        insightsHandler['appendTestItemLog'](testLogObj)
        expect(testLogObj.test_run_uuid).toBe('some_uuid')
        expect(sendDataSpy).toBeCalledTimes(1)
    })

    it('should upload with current hook uuid for log', function () {
        insightsHandler['_currentHook'] = { uuid: 'some_uuid' }
        insightsHandler['appendTestItemLog'](testLogObj)
        expect(testLogObj.hook_run_uuid).toBe('some_uuid')
        expect(sendDataSpy).toBeCalledTimes(1)
    })

    it('should not upload log if hook is finished', function () {
        InsightsHandler['currentTest'] = {}
        insightsHandler['_currentHook'] = { uuid: 'some_uuid', finished: true }
        insightsHandler['appendTestItemLog'](testLogObj)
        expect(testLogObj.hook_run_uuid).toBe(undefined)
        expect(testLogObj.test_run_uuid).toBe(undefined)
        expect(sendDataSpy).toBeCalledTimes(0)
    })
})

describe('processCucumberHook', function () {
    let insightsHandler: InsightsHandler
    let sendHookRunEventSpy, cucumberHookTypeSpy, cucumberHookUniqueIdSpy
    beforeEach(() => {
        insightsHandler = new InsightsHandler(browser, 'mocha')
        sendHookRunEventSpy = vi.spyOn(insightsHandler, 'getHookRunDataForCucumber').mockImplementation(() => { return [] as any })
        cucumberHookTypeSpy = vi.spyOn(insightsHandler, 'getCucumberHookType')
        cucumberHookTypeSpy.mockImplementation(() => { return 'hii' })
        cucumberHookUniqueIdSpy = vi.spyOn(insightsHandler, 'getCucumberHookUniqueId')
    })

    it('should not update if no hook type', function () {
        cucumberHookTypeSpy.mockReturnValue(null)
        insightsHandler['processCucumberHook'](undefined, { event: 'before' })
        expect(sendHookRunEventSpy).toBeCalledTimes(0)
    })

    it ('should send data for before event', function () {
        cucumberHookTypeSpy.mockReturnValue('BEFORE_ALL')
        InsightsHandler['currentTest'].uuid = 'test_uuid'
        insightsHandler['processCucumberHook'](undefined, { event: 'before', hookUUID: 'hook_uuid' })
        expect(sendHookRunEventSpy).toBeCalledWith(expect.objectContaining({
            uuid: 'hook_uuid',
            testRunId: 'test_uuid',
            hookType: 'BEFORE_ALL'
        }), 'HookRunStarted')
    })

    it('should send data for after event', function () {
        cucumberHookTypeSpy.mockReturnValue('AFTER_ALL')
        cucumberHookUniqueIdSpy.mockReturnValue('hook_unique_id')
        const hookObj = { uuid: 'hook_uuid' }
        const resultObj = { passed: true }
        insightsHandler['_tests']['hook_unique_id'] = hookObj
        insightsHandler['processCucumberHook'](undefined, { event: 'after' }, resultObj as any)
        expect(sendHookRunEventSpy).toBeCalledWith(hookObj, 'HookRunFinished', resultObj)
    })
})

describe('sendCBTInfo', () => {
    beforeAll(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })
    it('should not call cbtSessionCreated', () => {
        const cbtSessionCreatedSpy = vi.spyOn(insightsHandler['listener'], 'cbtSessionCreated').mockImplementation(() => { return [] as any })
        insightsHandler.sendCBTInfo()
        expect(cbtSessionCreatedSpy).toBeCalledTimes(0)
    })
    it('should call cbtSessionCreated', () => {
        insightsHandler.currentTestId = 'abc'
        const cbtSessionCreatedSpy = vi.spyOn(insightsHandler['listener'], 'cbtSessionCreated').mockImplementation(() => { return [] as any })
        insightsHandler.sendCBTInfo()
        expect(cbtSessionCreatedSpy).toBeCalled()
    })
})

describe('flushCBTDataQueue', () => {
    beforeAll(() => {
        insightsHandler = new InsightsHandler(browser, 'framework')
    })
    it('flushCBTDataQueue should not call cbtSessionCreated', () => {
        insightsHandler.cbtQueue = [{ uuid: 'abc', integrations: {} }]
        const cbtSessionCreatedSpy = vi.spyOn(insightsHandler['listener'], 'cbtSessionCreated').mockImplementation(() => { return [] as any })
        insightsHandler.flushCBTDataQueue()
        expect(cbtSessionCreatedSpy).toBeCalledTimes(0)
    })
    it('flushCBTDataQueue should call cbtSessionCreated', () => {
        insightsHandler.currentTestId = 'abc'
        insightsHandler.cbtQueue = [{ uuid: 'abc', integrations: {} }]
        const cbtSessionCreatedSpy = vi.spyOn(insightsHandler['listener'], 'cbtSessionCreated').mockImplementation(() => { return [] as any })
        insightsHandler.flushCBTDataQueue()
        expect(cbtSessionCreatedSpy).toBeCalled()
    })
})

describe('hasTestStepFailures for ignoreHooksStatus feature', () => {
    beforeAll(() => {
        insightsHandler = new InsightsHandler(browser, 'cucumber')
    })

    it('should return false when world.pickle is null/undefined', () => {
        const world = null as any
        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(false)
    })

    it('should return false when world.pickle exists but no test data found', () => {
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(false)
    })

    it('should return false when test data exists but no steps', () => {
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        // Mock the uniqueId generation and add test data without steps
        const uniqueId = 'test-unique-id'
        vi.doMock('../src/util.js', () => ({
            getUniqueIdentifierForCucumber: vi.fn().mockReturnValue(uniqueId)
        }))

        insightsHandler['_tests'][uniqueId] = {
            uuid: 'test-uuid',
            startedAt: '2020-01-01T00:00:00.000Z'
            // No steps property
        }

        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(false)
    })

    it('should return false when test data exists with steps but none failed', () => {
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        const uniqueId = 'test-unique-id-pass'
        vi.doMock('../src/util.js', () => ({
            getUniqueIdentifierForCucumber: vi.fn().mockReturnValue(uniqueId)
        }))

        insightsHandler['_tests'][uniqueId] = {
            uuid: 'test-uuid',
            startedAt: '2020-01-01T00:00:00.000Z',
            steps: [
                { id: 'step1', text: 'Step 1', result: 'PASSED' },
                { id: 'step2', text: 'Step 2', result: 'PASSED' },
                { id: 'step3', text: 'Step 3', result: 'SKIPPED' }
            ]
        }

        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(false)
    })

    it('should return true when test data exists with at least one failed step', () => {
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        const uniqueId = 'test-unique-id-fail'
        const getUniqueIdentifierForCucumberSpy = vi.spyOn(utils, 'getUniqueIdentifierForCucumber')
        getUniqueIdentifierForCucumberSpy.mockReturnValue(uniqueId)

        insightsHandler['_tests'][uniqueId] = {
            uuid: 'test-uuid',
            startedAt: '2020-01-01T00:00:00.000Z',
            steps: [
                { id: 'step1', text: 'Step 1', result: 'PASSED' },
                { id: 'step2', text: 'Step 2', result: 'FAILED' },
                { id: 'step3', text: 'Step 3', result: 'PASSED' }
            ]
        }

        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(true)

        getUniqueIdentifierForCucumberSpy.mockRestore()
    })

    it('should return true when multiple steps failed', () => {
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        const uniqueId = 'test-unique-id-multi-fail'
        const getUniqueIdentifierForCucumberSpy = vi.spyOn(utils, 'getUniqueIdentifierForCucumber')
        getUniqueIdentifierForCucumberSpy.mockReturnValue(uniqueId)

        insightsHandler['_tests'][uniqueId] = {
            uuid: 'test-uuid',
            startedAt: '2020-01-01T00:00:00.000Z',
            steps: [
                { id: 'step1', text: 'Step 1', result: 'FAILED' },
                { id: 'step2', text: 'Step 2', result: 'PASSED' },
                { id: 'step3', text: 'Step 3', result: 'FAILED' }
            ]
        }

        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(true)

        getUniqueIdentifierForCucumberSpy.mockRestore()
    })

    it('should handle empty steps array', () => {
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        const uniqueId = 'test-unique-id-empty'
        vi.doMock('../src/util.js', () => ({
            getUniqueIdentifierForCucumber: vi.fn().mockReturnValue(uniqueId)
        }))

        insightsHandler['_tests'][uniqueId] = {
            uuid: 'test-uuid',
            startedAt: '2020-01-01T00:00:00.000Z',
            steps: []
        }

        const result = insightsHandler.hasTestStepFailures(world)
        expect(result).toBe(false)
    })
})

describe('hasTestStepFailures and ignoreHooksStatus integration', () => {
    let testInsightsHandler: InsightsHandler

    beforeEach(() => {
        testInsightsHandler = new InsightsHandler(browser, 'cucumber', {}, {
            testObservabilityOptions: { ignoreHooksStatus: true }
        })
    })

    it('should test hasTestStepFailures method directly', () => {
        // Test that hasTestStepFailures correctly identifies step failures
        const world = {
            pickle: { name: 'Test scenario' }
        } as any

        const uniqueId = 'test-unique-id-for-step-failures'
        const getUniqueIdentifierForCucumberSpy = vi.spyOn(utils, 'getUniqueIdentifierForCucumber')
        getUniqueIdentifierForCucumberSpy.mockReturnValue(uniqueId)

        // Test: No steps - should return false
        testInsightsHandler['_tests'][uniqueId] = {
            uuid: 'test-uuid',
            startedAt: '2020-01-01T00:00:00.000Z',
            steps: undefined
        }
        expect(testInsightsHandler.hasTestStepFailures(world)).toBe(false)

        // Test: Empty steps - should return false
        testInsightsHandler['_tests'][uniqueId].steps = []
        expect(testInsightsHandler.hasTestStepFailures(world)).toBe(false)

        // Test: All steps passed - should return false
        testInsightsHandler['_tests'][uniqueId].steps = [
            { id: 'step1', text: 'Step 1', result: 'PASSED' },
            { id: 'step2', text: 'Step 2', result: 'PASSED' }
        ]
        expect(testInsightsHandler.hasTestStepFailures(world)).toBe(false)

        // Test: One step failed - should return true
        testInsightsHandler['_tests'][uniqueId].steps = [
            { id: 'step1', text: 'Step 1', result: 'PASSED' },
            { id: 'step2', text: 'Step 2', result: 'FAILED' }
        ]
        expect(testInsightsHandler.hasTestStepFailures(world)).toBe(true)

        // Test: Multiple steps failed - should return true
        testInsightsHandler['_tests'][uniqueId].steps = [
            { id: 'step1', text: 'Step 1', result: 'FAILED' },
            { id: 'step2', text: 'Step 2', result: 'FAILED' }
        ]
        expect(testInsightsHandler.hasTestStepFailures(world)).toBe(true)

        // Test: Mixed results with failure - should return true
        testInsightsHandler['_tests'][uniqueId].steps = [
            { id: 'step1', text: 'Step 1', result: 'PASSED' },
            { id: 'step2', text: 'Step 2', result: 'FAILED' },
            { id: 'step3', text: 'Step 3', result: 'PASSED' }
        ]
        expect(testInsightsHandler.hasTestStepFailures(world)).toBe(true)

        getUniqueIdentifierForCucumberSpy.mockRestore()
    })

    it('should verify ignoreHooksStatus configuration is properly set', () => {
        // Test that the configuration is correctly passed through
        expect(testInsightsHandler['_options']?.testObservabilityOptions?.ignoreHooksStatus).toBe(true)

        const testInsightsHandlerDisabled = new InsightsHandler(browser, 'cucumber', {}, {
            testObservabilityOptions: { ignoreHooksStatus: false }
        })
        expect(testInsightsHandlerDisabled['_options']?.testObservabilityOptions?.ignoreHooksStatus).toBe(false)

        const testInsightsHandlerDefault = new InsightsHandler(browser, 'cucumber', {}, {})
        expect(testInsightsHandlerDefault['_options']?.testObservabilityOptions?.ignoreHooksStatus).toBeUndefined()
    })
})