From 9fe32a8d47b07b2dcef6a1c69894687f9b2ad7d9 Mon Sep 17 00:00:00 2001 From: P-Courteille Date: Sun, 13 Jul 2025 12:00:57 +0200 Subject: [PATCH] issue_657_and_983 --- .changeset/spotty-bananas-glow.md | 9 +++++ packages/ocr-service/src/service.ts | 39 +++++++++++-------- packages/visual-reporter/package.json | 2 +- packages/visual-service/src/service.ts | 27 +++++++------ packages/visual-service/src/utils.ts | 5 ++- .../src/methods/methods.interfaces.ts | 12 +++--- 6 files changed, 54 insertions(+), 40 deletions(-) create mode 100644 .changeset/spotty-bananas-glow.md diff --git a/.changeset/spotty-bananas-glow.md b/.changeset/spotty-bananas-glow.md new file mode 100644 index 00000000..fd3370f2 --- /dev/null +++ b/.changeset/spotty-bananas-glow.md @@ -0,0 +1,9 @@ +--- +"@wdio/ocr-service": minor +--- + +\- improve typing for executor (as previously done in webdriverio package) + +\- For both ocr-service and visual-service, the functions are now first add to the browser object and then to each instances to avoid having the loop for each instance in the command of a single instance (function with the loop no longer call itself like in the issue 657 and are now correctly declared to the correct element to fix issue 983) + +\- Update the clean script for visual-reporter to work with Windows \ No newline at end of file diff --git a/packages/ocr-service/src/service.ts b/packages/ocr-service/src/service.ts index e9aa408a..49d5a83d 100644 --- a/packages/ocr-service/src/service.ts +++ b/packages/ocr-service/src/service.ts @@ -24,11 +24,14 @@ export default class WdioOcrService { private _ocrDir: string private _ocrLanguage: string private _ocrContrast: number + private _isTesseractAvailable: boolean constructor(options: OcrOptions) { this._ocrDir = createOcrDir(options?.imagesFolder || DEFAULT_IMAGES_FOLDER) this._ocrLanguage = options?.language || SUPPORTED_LANGUAGES.ENGLISH this._ocrContrast = options?.contrast || CONTRAST + this._ocrLanguage = options?.language || SUPPORTED_LANGUAGES.ENGLISH + this._isTesseractAvailable = isSystemTesseractAvailable() } /** @@ -58,24 +61,19 @@ export default class WdioOcrService { const browserNames = Object.keys(capabilities) const self = this log.info(`Adding commands to Multi Browser: ${browserNames.join(', ')}`) - - for (const browserName of browserNames) { - const multiremoteBrowser = browser as WebdriverIO.MultiRemoteBrowser - const browserInstance = multiremoteBrowser.getInstance(browserName) - await this.#addCommandsToBrowser(browserInstance) - } - /** - * Add all OCR commands to the global browser object that will execute - * on each browser in the Multi Remote. + * Add all commands to the global browser object that will execute on each browser in the Multi Remote. */ - for (const command of Object.keys(ocrCommands)) { - browser.addCommand(command, async function (...args: unknown[]) { + for (const commandName of Object.keys(ocrCommands)) { + browser.addCommand(commandName, async function (...args: unknown[]) { const returnData: Record = {} if (typeof args[0] === 'object' && args[0] !== null) { const options = args[0] as Record + options.ocrImagesPath = options?.imagesFolder || self._ocrDir options.contrast = options?.contrast || self._ocrContrast + options.language = options?.language || self._ocrLanguage + options.isTesseractAvailable = self._isTesseractAvailable args[0] = options } @@ -83,20 +81,27 @@ export default class WdioOcrService { const multiremoteBrowser = browser as WebdriverIO.MultiRemoteBrowser const browserInstance = multiremoteBrowser.getInstance(browserName) as WebdriverIO.Browser & Record - if (typeof browserInstance[command] === 'function') { - returnData[browserName] = await browserInstance[command].apply(browserInstance, args) + if (typeof browserInstance[commandName] === 'function') { + returnData[browserName] = await browserInstance[commandName].apply(browserInstance, args) } else { - throw new Error(`Command ${command} is not a function on the browser instance ${browserName}`) + throw new Error(`Command ${commandName} is not a function on the browser instance ${browserName}`) } } return returnData }) } + /** + * Add all commands to each instance (but Single Remote version) + */ + for (const browserName of browserNames) { + const multiremoteBrowser = browser as WebdriverIO.MultiRemoteBrowser + const browserInstance = multiremoteBrowser.getInstance(browserName) + await this.#addCommandsToBrowser(browserInstance) + } } async #addCommandsToBrowser(currentBrowser: WebdriverIO.Browser) { - const isTesseractAvailable = isSystemTesseractAvailable() const self = this for (const [commandName, command] of Object.entries(ocrCommands)) { @@ -106,10 +111,10 @@ export default class WdioOcrService { function (this: typeof currentBrowser, options) { return command.bind(this)({ ...options, + ocrImagesPath: self._ocrDir, contrast: options?.contrast || self._ocrContrast, - isTesseractAvailable, language: options?.language || self._ocrLanguage, - ocrImagesPath: self._ocrDir, + isTesseractAvailable: self._isTesseractAvailable }) } ) diff --git a/packages/visual-reporter/package.json b/packages/visual-reporter/package.json index 792d2e34..5b35d4ef 100644 --- a/packages/visual-reporter/package.json +++ b/packages/visual-reporter/package.json @@ -17,7 +17,7 @@ "build": "run-s clean build:*", "build:report": "remix vite:build", "build:scripts": "tsc -p tsconfig.scripts.json", - "clean": "rimraf coverage build *.tsbuildinfo", + "clean": "rimraf coverage build --glob *.tsbuildinfo", "dev": "cross-env VISUAL_REPORT_LOCAL_DEV=true run-s build:scripts script:prepare.report && run-p watch:scripts dev:remix", "dev:remix": "remix vite:dev", "script:prepare.report": "node ./dist/prepareReportAssets.js", diff --git a/packages/visual-service/src/service.ts b/packages/visual-service/src/service.ts index 2a1bf723..a8fece7f 100644 --- a/packages/visual-service/src/service.ts +++ b/packages/visual-service/src/service.ts @@ -2,6 +2,7 @@ import logger from '@wdio/logger' import { expect } from '@wdio/globals' import { dirname, normalize, resolve } from 'node:path' import type { Capabilities, Frameworks } from '@wdio/types' +import type { TransformElement } from 'webdriverio' import { BaseClass, checkElement, @@ -142,7 +143,14 @@ export default class WdioImageComparisonService extends BaseClass { const browserNames = Object.keys(capabilities) /** - * Add all the commands to each browser in the Multi Remote + * Add all commands to the global browser object that will execute on each browser in the Multi Remote. + */ + for (const [commandName, command] of Object.entries(pageCommands)) { + this.#addMultiremoteCommand(browser, browserNames, commandName, command) + } + + /** + * Add all commands to each instance (but Single Remote version) */ for (const browserName of browserNames) { log.info(`Adding commands to Multi Browser: ${browserName}`) @@ -155,15 +163,6 @@ export default class WdioImageComparisonService extends BaseClass { await this.#addCommandsToBrowser(browserInstance) } - /** - * Add all the commands to the global browser object that will execute - * on each browser in the Multi Remote - * Start with the page commands - */ - for (const [commandName, command] of Object.entries(pageCommands)) { - this.#addMultiremoteCommand(browser, browserNames, commandName, command) - } - /** * Add all the element commands to the global browser object that will execute * on each browser in the Multi Remote @@ -234,7 +233,7 @@ export default class WdioImageComparisonService extends BaseClass { methods: { bidiScreenshot: isBiDiScreenshotSupported(browser) ? this.browsingContextCaptureScreenshot.bind(browser) : undefined, executor: ( - fn: string | ((...args: InnerArguments) => ReturnValue), + fn: string | ((...innerArgs: TransformElement) => ReturnValue), ...args: InnerArguments ): Promise => { return this.execute(fn, ...args) as Promise @@ -311,7 +310,7 @@ export default class WdioImageComparisonService extends BaseClass { methods: { bidiScreenshot: isBiDiScreenshotSupported(browser) ? this.browsingContextCaptureScreenshot.bind(browser) : undefined, executor: ( - fn: string | ((...args: InnerArguments) => ReturnValue), + fn: string | ((...innerArgs: TransformElement) => ReturnValue), ...args: InnerArguments ): Promise => { return this.execute(fn, ...args) as Promise @@ -387,7 +386,7 @@ export default class WdioImageComparisonService extends BaseClass { methods: { bidiScreenshot: isBiDiScreenshotSupported(browserInstance) ? browserInstance.browsingContextCaptureScreenshot.bind(browserInstance) : undefined, executor: ( - fn: string | ((...args: InnerArguments) => ReturnValue), + fn: string | ((...innerArgs: TransformElement) => ReturnValue), ...args: InnerArguments ): Promise => { return browserInstance.execute(fn, ...args) as Promise @@ -480,7 +479,7 @@ export default class WdioImageComparisonService extends BaseClass { methods: { bidiScreenshot: isBiDiScreenshotSupported(browserInstance) ? browserInstance.browsingContextCaptureScreenshot.bind(browserInstance) : undefined, executor: ( - fn: string | ((...args: InnerArguments) => ReturnValue), + fn: string | ((...innerArgs: TransformElement) => ReturnValue), ...args: InnerArguments ): Promise => { return browserInstance.execute(fn, ...args) as Promise diff --git a/packages/visual-service/src/utils.ts b/packages/visual-service/src/utils.ts index 2563e49a..f34eb79b 100644 --- a/packages/visual-service/src/utils.ts +++ b/packages/visual-service/src/utils.ts @@ -2,6 +2,7 @@ import type { Capabilities } from '@wdio/types' import type { AppiumCapabilities } from 'node_modules/@wdio/types/build/Capabilities.js' import { getMobileScreenSize, getMobileViewPortPosition, IOS_OFFSETS, NOT_KNOWN } from 'webdriver-image-comparison' import type { Folders, InstanceData, TestContext } from 'webdriver-image-comparison' +import type { TransformElement, TransformReturn } from 'webdriverio' import type { EnrichTestContextOptions, getFolderMethodOptions, @@ -70,8 +71,8 @@ async function getMobileInstanceData({ if (isMobile) { const executor = ( - fn: string | ((...args: InnerArguments) => ReturnValue), - ...args: InnerArguments) => currentBrowser.execute(fn, ...args) as Promise + fn: string | ((...innerArgs: TransformElement) => ReturnValue), + ...args: InnerArguments) => currentBrowser.execute(fn, ...args) as Promise> const getUrl = () => currentBrowser.getUrl() const url = (arg:string) => currentBrowser.url(arg) const currentDriverCapabilities = currentBrowser.capabilities diff --git a/packages/webdriver-image-comparison/src/methods/methods.interfaces.ts b/packages/webdriver-image-comparison/src/methods/methods.interfaces.ts index 38ad4a2e..a36ad4dd 100644 --- a/packages/webdriver-image-comparison/src/methods/methods.interfaces.ts +++ b/packages/webdriver-image-comparison/src/methods/methods.interfaces.ts @@ -1,15 +1,15 @@ import type { RectanglesOutput } from './rectangles.interfaces.js' - +import type { TransformReturn, TransformElement } from 'webdriverio' // There a multiple ways to call the executor method, for mobile and web -type ExecuteScript = ( - fn: (...args: Args) => ReturnValue, - ...args: Args - ) => Promise; +type ExecuteScript = ( + fn: (...innerArgs: TransformElement) => ReturnValue, + ...args: InnerArguments + ) => Promise>; type ExecuteMobile = ( fn: string, args?: Record -) => Promise; +) => Promise>; interface BrowsingContextCaptureScreenshotParameters { context: string; origin?: 'viewport' | 'document';