Skip to content

Commit

Permalink
[webdriverio-v8] Fix issue wdio log is missing in standalone mode (#1…
Browse files Browse the repository at this point in the history
…2703)

* Fix issue wdio log is missing in standalone mode

* Create a help method for enabling file logging, add and fix unit tests
  • Loading branch information
nguyencuongabcxyz committed Apr 19, 2024
1 parent d4899d4 commit 1e99bb5
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 37 deletions.
1 change: 1 addition & 0 deletions __mocks__/@wdio/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,4 @@ export const startWebDriver = vi.fn((params) => {
})
export const setupBrowser = vi.fn()
export const setupDriver = vi.fn()
export const enableFileLogging = vi.fn()
10 changes: 2 additions & 8 deletions packages/wdio-cli/src/launcher.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import fs from 'node:fs/promises'
import path from 'node:path'
import exitHook from 'async-exit-hook'

import logger from '@wdio/logger'
import { validateConfig } from '@wdio/config'
import { ConfigParser } from '@wdio/config/node'
import { initializePlugin, initializeLauncherService, sleep } from '@wdio/utils'
import { initializePlugin, initializeLauncherService, sleep, enableFileLogging } from '@wdio/utils'
import { setupDriver, setupBrowser } from '@wdio/utils/node'
import type { Options, Capabilities, Services } from '@wdio/types'

Expand Down Expand Up @@ -82,11 +80,7 @@ class Launcher {
this.isMultiremote = this.isParallelMultiremote || !Array.isArray(capabilities)
validateConfig(TESTRUNNER_DEFAULTS, { ...config, capabilities })

if (config.outputDir) {
await fs.mkdir(path.join(config.outputDir), { recursive: true })
process.env.WDIO_LOG_PATH = path.join(config.outputDir, 'wdio.log')
}

await enableFileLogging(config.outputDir)
logger.setLogLevelsConfig(config.logLevels, config.logLevel)

/**
Expand Down
10 changes: 2 additions & 8 deletions packages/wdio-cli/tests/launcher.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import fs from 'node:fs/promises'
import path from 'node:path'
import { vi, describe, it, expect, afterEach, beforeEach } from 'vitest'
import logger from '@wdio/logger'
import { sleep } from '@wdio/utils'

vi.mocked(fs.access).mockResolvedValue()

import { sleep, enableFileLogging } from '@wdio/utils'
import Launcher from '../src/launcher.js'
// @ts-expect-error
import { Launcher as cjsLauncher, run as cjsRun } from '../src/cjs/index.js'
Expand Down Expand Up @@ -729,8 +725,7 @@ describe('launcher', () => {
expect(await launcher.run()).toEqual(0)
expect(launcher['configParser'].initialize).toBeCalledTimes(1)
expect(launcher.runner!.shutdown).toBeCalled()
expect(vi.mocked(fs.mkdir)).toHaveBeenCalled()
expect(vi.mocked(fs.mkdir)).toHaveBeenCalledWith('tempDir', { recursive: true })
expect(enableFileLogging).toHaveBeenCalledWith('tempDir')

expect(launcher.configParser.getCapabilities).toBeCalledTimes(2)
expect(launcher.configParser.getConfig).toBeCalledTimes(1)
Expand Down Expand Up @@ -772,7 +767,6 @@ describe('launcher', () => {

afterEach(() => {
vi.mocked(global.console.error).mockRestore()
vi.mocked(fs.mkdir).mockClear()
})
})

Expand Down
10 changes: 2 additions & 8 deletions packages/wdio-runner/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import path from 'node:path'

import { deepmerge } from 'deepmerge-ts'
import logger from '@wdio/logger'
import { remote, multiremote, attach } from 'webdriverio'
import { DEFAULTS } from 'webdriver'
import { DEFAULT_CONFIGS } from '@wdio/config'
import type { AsymmetricMatchers } from 'expect-webdriverio'
import type { Options, Capabilities } from '@wdio/types'
import { enableFileLogging } from '@wdio/utils'

const log = logger('@wdio/runner')

Expand Down Expand Up @@ -57,12 +56,7 @@ export async function initializeInstance (
capabilities: Capabilities.RemoteCapability,
isMultiremote?: boolean
): Promise<WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser> {
/**
* Store all log events in a file
*/
if (config.outputDir && !process.env.WDIO_LOG_PATH) {
process.env.WDIO_LOG_PATH = path.join(config.outputDir, 'wdio.log')
}
await enableFileLogging(config.outputDir)

/**
* check if config has sessionId and attach it to a running session if so
Expand Down
18 changes: 10 additions & 8 deletions packages/wdio-runner/tests/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {

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

process.send = vi.fn()

Expand All @@ -21,13 +22,13 @@ describe('utils', () => {
})

describe('initializeInstance', () => {
it('should attach to an existing session if sessionId is within config', () => {
it('should attach to an existing session if sessionId is within config', async () => {
const config: ConfigWithSessionId = {
sessionId: '123',
// @ts-ignore test invalid params
foo: 'bar'
}
initializeInstance(config, {
await initializeInstance(config, {
browserName: 'chrome',
maxInstances: 2,
hostname: 'foobar'
Expand All @@ -42,15 +43,16 @@ describe('utils', () => {
browserName: 'chrome'
}
}

expect(attach).toBeCalledWith({ ...attachParams, options: attachParams })
expect(config.capabilities).toEqual({ browserName: 'chrome' })
expect(multiremote).toHaveBeenCalledTimes(0)
expect(remote).toHaveBeenCalledTimes(0)
})

it('should run multiremote tests if flag is given', () => {
it('should run multiremote tests if flag is given', async () => {
const capabilities = { someBrowser: { browserName: 'chrome' } }
initializeInstance(
await initializeInstance(
// @ts-ignore test invalid params
{ foo: 'bar' },
capabilities,
Expand All @@ -66,8 +68,8 @@ describe('utils', () => {
expect(remote).toHaveBeenCalledTimes(0)
})

it('should create normal remote session', () => {
initializeInstance({
it('should create normal remote session', async () => {
await initializeInstance({
// @ts-ignore test invalid params
foo: 'bar'
},
Expand All @@ -84,14 +86,14 @@ describe('utils', () => {
})
})

it('should overwrite connection properties if set in capabilities', () => {
it('should overwrite connection properties if set in capabilities', async () => {
const caps = {
browserName: 'chrome',
hostname: 'barfoo',
port: 4321,
path: '/'
}
initializeInstance({
await initializeInstance({
hostname: 'foobar',
port: 1234,
path: '/some/path'
Expand Down
3 changes: 2 additions & 1 deletion packages/wdio-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { initializeWorkerService, initializeLauncherService } from './initialize
import {
commandCallStructure, isValidParameter, getArgumentType, safeImport,
isFunctionAsync, transformCommandLogResult, sleep, isAppiumCapability,
getBrowserObject
getBrowserObject, enableFileLogging,
} from './utils.js'
import { wrapCommand, executeHooksWithArgs, executeAsync } from './shim.js'
import * as asyncIterators from './pIteration.js'
Expand All @@ -33,6 +33,7 @@ export {
sleep,
isAppiumCapability,
getBrowserObject,
enableFileLogging,
asyncIterators,

/**
Expand Down
15 changes: 15 additions & 0 deletions packages/wdio-utils/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/// <reference types="@wdio/globals/types" />
import fs from 'node:fs/promises'
import path from 'node:path'
import type { Options, Services, Clients } from '@wdio/types'

import { SUPPORTED_BROWSERNAMES, DEFAULT_PROTOCOL, DEFAULT_HOSTNAME, DEFAULT_PATH } from './constants.js'
Expand Down Expand Up @@ -340,3 +342,16 @@ export function getBrowserObject (elem: WebdriverIO.Element | WebdriverIO.Browse
// @ts-ignore types are not loaded in time (fixed in v9)
return (elemObject as WebdriverIO.Element).parent ? getBrowserObject(elemObject.parent) : elem as WebdriverIO.Browser
}

/**
* Enables logging to a file in a specified directory.
* @param {string} outputDir Directory containing the log file
*/
export async function enableFileLogging (outputDir?: string): Promise<void> {
if (!outputDir) {
return
}

await fs.mkdir(path.join(outputDir), { recursive: true })
process.env.WDIO_LOG_PATH = path.join(outputDir, 'wdio.log')
}
39 changes: 37 additions & 2 deletions packages/wdio-utils/tests/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import path from 'node:path'
import fs from 'node:fs/promises'
import type { MockedFunction } from 'vitest'
import { vi, describe, it, expect } from 'vitest'
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'

import {
overwriteElementCommands, commandCallStructure, isValidParameter, definesRemoteDriver,
getArgumentType, isFunctionAsync, filterSpecArgs, isBase64, transformCommandLogResult,
getBrowserObject
getBrowserObject, enableFileLogging,
} from '../src/utils.js'

describe('utils', () => {
Expand Down Expand Up @@ -245,3 +247,36 @@ describe('getBrowserObject', () => {
} as any)).toEqual({ foo: 'bar' })
})
})

describe('enableFileLogging', () => {
beforeEach(() => {
vi.mock('node:fs/promises', () => ({
default: {
mkdir: vi.fn(),
}
}))

delete process.env.WDIO_LOG_PATH
})

afterEach(() => {
vi.clearAllMocks()
})

it ('should do nothing if outputDir is not provided', async () => {
await enableFileLogging()

expect(fs.mkdir).not.toHaveBeenCalled()
expect(process.env.WDIO_LOG_PATH).toBeUndefined()
})

it('should create a directory and set WDIO_LOG_PATH to the directory path if outputDir is provided', async () => {
const outputDir = '/path/to/log/directory'
const expectedLogPath = path.join(outputDir, 'wdio.log')

await enableFileLogging(outputDir)

expect(fs.mkdir).toHaveBeenCalledWith(path.join(outputDir), { recursive: true })
expect(process.env.WDIO_LOG_PATH).toBe(expectedLogPath)
})
})
7 changes: 5 additions & 2 deletions packages/webdriverio/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import logger from '@wdio/logger'

import WebDriver, { DEFAULTS } from 'webdriver'
import { validateConfig } from '@wdio/config'
import { wrapCommand } from '@wdio/utils'
import { enableFileLogging, wrapCommand } from '@wdio/utils'
import type { Options, Capabilities } from '@wdio/types'
import type * as WebDriverTypes from 'webdriver'

Expand Down Expand Up @@ -36,9 +36,12 @@ export const remote = async function(
params: RemoteOptions,
remoteModifier?: (client: WebDriverTypes.Client, options: Options.WebdriverIO) => WebDriverTypes.Client
): Promise<WebdriverIO.Browser> {
logger.setLogLevelsConfig(params.logLevels as any, params.logLevel)
const keysToKeep = Object.keys(process.env.WDIO_WORKER_ID ? params : DEFAULTS) as (keyof RemoteOptions)[]
const config = validateConfig<RemoteOptions>(WDIO_DEFAULTS, params, keysToKeep)

await enableFileLogging(config.outputDir)
logger.setLogLevelsConfig(config.logLevels, config.logLevel)

const modifier = (client: WebDriverTypes.Client, options: Options.WebdriverIO) => {
/**
* overwrite instance options with default values of the protocol
Expand Down

0 comments on commit 1e99bb5

Please sign in to comment.