import path from 'node:path' import logger from '@wdio/logger' import { describe, expect, it, vi, beforeEach, afterEach, beforeAll, afterAll } from 'vitest' import type { StdLog } from '../src/index.js' import TestReporter from '../src/reporter.js' import * as utils from '../src/util.js' import * as bstackLogger from '../src/bstackLogger.js' const log = logger('test') vi.useFakeTimers().setSystemTime(new Date('2020-01-01')) vi.mock('uuid', () => ({ v4: () => '123456789' })) vi.mock('@wdio/reporter', () => import(path.join(process.cwd(), '__mocks__', '@wdio/reporter'))) vi.mock('@wdio/logger', () => import(path.join(process.cwd(), '__mocks__', '@wdio/logger'))) const bstackLoggerSpy = vi.spyOn(bstackLogger.BStackLogger, 'logToFile') bstackLoggerSpy.mockImplementation(() => {}) describe('test-reporter', () => { const runnerConfig = { type: 'runner', start: new Date('2018-05-14T15:17:18.901Z'), _duration: 0, cid: '0-0', capabilities: { browserName: 'chrome', browserVersion: '68' }, // session capabilities sanitizedCapabilities: 'chrome.66_0_3359_170.linux', config: { capabilities: { browserName: 'chrome', browserVersion: '68' }, framework: 'mocha', hostname: 'browserstack.com' }, // user capabilities specs: ['/tmp/user/spec.js'], sessionId: 'sessionId' } const testStats = { type: 'test', start: new Date('2018-05-14T15:17:18.901Z'), _duration: 0, uid: '23', cid: '0-0', title: 'Given the title is "Google1"', fullTitle: 'TestDesc.TestRun.it', output: [], argument: undefined, retries: 0, parent: '1', state: 'skipped' } beforeEach(() => { vi.mocked(log.debug).mockClear() }) describe('on create', () => { const reporter = new TestReporter({}) it('should verify initial properties', () => { expect(reporter['_capabilities']).toEqual({}) expect(reporter['_observability']).toBe(true) expect(reporter['_sessionId']).toEqual(undefined) expect(reporter['_suiteName']).toEqual(undefined) }) }) describe('onSuiteStart', () => { let reporter: TestReporter const suite = { title: 'suite title', file: 'filename', } beforeEach(() => { reporter = new TestReporter({}) reporter.onSuiteStart(suite as any) }) it('should set _suiteName', () => { expect(reporter['_suiteName']).toEqual('filename') }) it ('should store suite in stack', () => { expect(reporter['_suites']).toEqual([suite]) reporter.onSuiteStart(suite as any) expect(reporter['_suites']).toEqual([suite, suite]) }) }) describe('onSuiteEnd', function () { let reporter: TestReporter const suite = { title: 'suite title', file: 'filename', } beforeEach(() => { reporter = new TestReporter({}) }) it('should pop from suites', () => { expect(reporter['_suites']).toEqual([]) reporter.onSuiteStart(suite as any) reporter.onSuiteStart(suite as any) expect(reporter['_suites']).toEqual([suite, suite]) reporter.onSuiteEnd() expect(reporter['_suites']).toEqual([suite]) reporter.onSuiteEnd() expect(reporter['_suites']).toEqual([]) }) }) describe('onRunnerStart', () => { const reporter = new TestReporter({}) it('should set properties', () => { reporter.onRunnerStart(runnerConfig as any) expect(reporter['_capabilities']).toEqual({ browserName: 'chrome', browserVersion: '68' }) expect(reporter['_observability']).toEqual(true) }) it('should set properties - handle false', () => { reporter.onRunnerStart({ type: 'runner', start: '2018-05-14T15:17:18.901Z', _duration: 0, cid: '0-0', capabilities: { browserName: 'chrome', browserVersion: '68' }, // session capabilities sanitizedCapabilities: 'chrome.66_0_3359_170.linux', config: { testObservability: false, capabilities: { browserName: 'chrome', browserVersion: '68' }, framework: 'mocha', hostname: 'browserstack.com' }, // user capabilities specs: ['/tmp/user/spec.js'], sessionId: 'sessionId' } as any) expect(reporter['_capabilities']).toEqual({ browserName: 'chrome', browserVersion: '68' }) expect(reporter['_observability']).toEqual(false) }) }) describe('onTestSkip', () => { const reporter = new TestReporter({}) const uploadEventDataSpy = vi.spyOn(reporter['listener'], 'testFinished').mockImplementation(() => {}) const getCloudProviderSpy = vi.spyOn(utils, 'getCloudProvider').mockReturnValue('browserstack') let getPlatformVersionSpy: any beforeAll(() => { getPlatformVersionSpy = vi.spyOn(utils, 'getPlatformVersion').mockImplementation(() => { return 'some version' }) }) afterAll(() => { getPlatformVersionSpy.mockReset() }) beforeEach(() => { uploadEventDataSpy.mockClear() getCloudProviderSpy.mockClear() reporter.onRunnerStart(runnerConfig as any) }) it('uploadEventData called', async () => { reporter['_observability'] = true reporter['_config'] = { capabilities: { browserName: 'chrome', browserVersion: '68' }, framework: 'mocha', hostname: 'browserstack.com' } await reporter.onTestSkip(testStats as any) expect(uploadEventDataSpy).toBeCalledTimes(1) expect(log.debug).toHaveBeenCalledTimes(0) }) it('uploadEventData not called for cucumber', async () => { reporter['_config'] = { framework: 'cucumber' } as any await reporter.onTestSkip(testStats as any) expect(uploadEventDataSpy).toBeCalledTimes(0) expect(log.debug).toHaveBeenCalledTimes(0) }) afterEach(() => { uploadEventDataSpy.mockClear() getCloudProviderSpy.mockClear() }) }) describe('needToSendData', function () { const reporter = new TestReporter({}) beforeEach(() => { reporter['_observability'] = true }) it('should return if not observability', () => { reporter['_observability'] = false expect(reporter.needToSendData('test', 'some event')).toBe(false) }) it('should return false for cucumber', () => { reporter['_config'] = { framework: 'cucumber' } as any expect(reporter.needToSendData('test', 'some event')).toBe(false) }) it('should return true for mocha is skip event', () => { reporter['_config'] = { framework: 'mocha' } as any expect(reporter.needToSendData('test', 'skip')).toBe(true) }) it('should return true for jasmine if type is test', () => { reporter['_config'] = { framework: 'jasmine' } as any expect(reporter.needToSendData('test', 'some event')).toBe(true) }) }) describe('onTestStart', function () { let reporter: TestReporter let uploadEventDataSpy: any vi.spyOn(utils, 'getCloudProvider').mockReturnValue('browserstack') let testStartStats = { ...testStats } let getPlatformVersionSpy beforeAll(() => { getPlatformVersionSpy = vi.spyOn(utils, 'getPlatformVersion').mockImplementation(() => { return 'some version' }) }) afterAll(() => { getPlatformVersionSpy.mockReset() }) beforeEach(() => { reporter = new TestReporter({}) reporter['_observability'] = true reporter.onRunnerStart(runnerConfig as any) testStartStats = { ...testStats } uploadEventDataSpy = vi.spyOn(reporter['listener'], 'testStarted').mockImplementation(() => {}) }) afterEach(() => { uploadEventDataSpy.mockClear() }) describe('mocha', () => { beforeEach(() => { // @ts-ignore reporter['_config'].framework = 'mocha' }) it ("uploadEventData shouldn't get called", async () => { await reporter.onTestStart(testStartStats as any) expect(uploadEventDataSpy).toBeCalledTimes(0) }) }) describe('jasmine', function () { beforeEach(() => { // @ts-ignore reporter['_config'].framework = 'jasmine' testStartStats.state = 'pending' }) it('uploadEventData called for jasmine', async () => { await reporter.onTestStart(testStartStats as any) expect(uploadEventDataSpy).toBeCalledTimes(1) }) }) }) describe('onTestEnd', function () { let reporter: TestReporter, uploadEventDataSpy: any vi.spyOn(utils, 'getCloudProvider').mockReturnValue('browserstack') let testEndStats = { ...testStats } let getPlatformVersionSpy beforeAll(() => { getPlatformVersionSpy = vi.spyOn(utils, 'getPlatformVersion').mockImplementation(() => { return 'some version' }) }) afterAll(() => { getPlatformVersionSpy.mockReset() }) beforeEach(() => { reporter = new TestReporter({}) reporter['_observability'] = true reporter.onRunnerStart(runnerConfig as any) testEndStats = { ...testStats } uploadEventDataSpy = vi.spyOn(reporter['listener'], 'testFinished') }) afterEach(() => { uploadEventDataSpy.mockClear() }) describe('mocha', () => { beforeEach(() => { // @ts-ignore reporter['_config'].framework = 'mocha' }) it ("uploadEventData shouldn't get called", async () => { await reporter.onTestEnd(testEndStats as any) expect(uploadEventDataSpy).toBeCalledTimes(0) }) }) describe('jasmine', function () { beforeEach(() => { // @ts-ignore reporter['_config'].framework = 'jasmine' testEndStats.state = 'passed' }) it('uploadEventData called for passed tests', async () => { testEndStats.state = 'passed' await reporter.onTestEnd(testEndStats as any) expect(uploadEventDataSpy).toBeCalledTimes(1) }) it('uploadEventData called for failed tests', async () => { testEndStats.state = 'failed' await reporter.onTestEnd(testEndStats as any) expect(uploadEventDataSpy).toBeCalledTimes(1) }) }) }) describe('appendTestItemLog', function () { let reporter: TestReporter let sendDataSpy: any const logObj: StdLog = { timestamp: new Date().toISOString(), level: 'INFO', message: 'some log', kind: 'TEST_LOG', http_response: {} } let testLogObj: StdLog beforeEach(() => { reporter = new TestReporter({}) reporter['_observability'] = true sendDataSpy = vi.spyOn(reporter['listener'], 'logCreated').mockImplementation(() => { return [] as any }) testLogObj = { ...logObj } }) it('should upload with current test uuid for log', function () { TestReporter['currentTest'] = { uuid: 'some_uuid' } reporter['appendTestItemLog'](testLogObj) expect(testLogObj.test_run_uuid).toBe('some_uuid') expect(sendDataSpy).toBeCalledTimes(1) }) it('should upload with current hook uuid for log', function () { reporter['_currentHook'] = { uuid: 'some_uuid' } reporter['appendTestItemLog'](testLogObj) expect(testLogObj.hook_run_uuid).toBe('some_uuid') expect(sendDataSpy).toBeCalledTimes(1) }) it('should not upload log if hook is finished', function () { TestReporter['currentTest'] = {} reporter['_currentHook'] = { uuid: 'some_uuid', finished: true } reporter['appendTestItemLog'](testLogObj) expect(testLogObj.hook_run_uuid).toBe(undefined) expect(testLogObj.test_run_uuid).toBe(undefined) expect(sendDataSpy).toBeCalledTimes(0) }) }) })