From dd8305338962596188d6496a72cdedf8685c1e87 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Thu, 2 Nov 2023 23:16:03 +0600 Subject: [PATCH 1/9] add: debug with selector option added --- src/api/test-controller/index.js | 7 ++++--- src/client/driver/driver.js | 4 ++-- .../ui/selector-inspector-panel/index.js | 10 ++++++---- .../selector-input-container.js | 14 +++++++++++++- .../utils/get-elements-by-selector.js | 2 +- src/test-run/commands/actions.js | 18 ++++++++++++++++++ src/test-run/commands/base.d.ts | 1 + src/test-run/commands/service.js | 3 ++- src/test-run/index.ts | 8 ++++---- 9 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/api/test-controller/index.js b/src/api/test-controller/index.js index ba84d564f10..50dfda1a117 100644 --- a/src/api/test-controller/index.js +++ b/src/api/test-controller/index.js @@ -57,6 +57,7 @@ import { AddRequestHooksCommand, RemoveRequestHooksCommand, ReportCommand, + DebugCommand, } from '../../test-run/commands/actions'; import { @@ -67,7 +68,7 @@ import { MaximizeWindowCommand, } from '../../test-run/commands/browser-manipulation'; -import { WaitCommand, DebugCommand } from '../../test-run/commands/observation'; +import { WaitCommand } from '../../test-run/commands/observation'; import { createExecutionContext as createContext } from './execution-context'; import { isSelector } from '../../client-functions/types'; @@ -602,8 +603,8 @@ export default class TestController { return new Assertion(actual, this, callsite); } - [delegatedAPI(DebugCommand.methodName)] () { - return this.enqueueCommand(DebugCommand); + [delegatedAPI(DebugCommand.methodName)] (selector) { + return this.enqueueCommand(DebugCommand, { selector }); } [delegatedAPI(SetTestSpeedCommand.methodName)] (speed) { diff --git a/src/client/driver/driver.js b/src/client/driver/driver.js index 703f3f5018e..3d5ddc9ed5d 100644 --- a/src/client/driver/driver.js +++ b/src/client/driver/driver.js @@ -1481,10 +1481,10 @@ export default class Driver extends serviceUtils.EventEmitter { }); } - _onSetBreakpointCommand ({ isTestError }) { + _onSetBreakpointCommand ({ isTestError, selector }) { const showDebuggingStatusPromise = this.statusBar.showDebuggingStatus(isTestError); - this.selectorInspectorPanel.show(); + this.selectorInspectorPanel.show(selector); showDebuggingStatusPromise.then(debug => { const stopAfterNextAction = debug === STATUS_BAR_DEBUG_ACTION.step; diff --git a/src/client/ui/selector-inspector-panel/index.js b/src/client/ui/selector-inspector-panel/index.js index 465f3f8a9c5..b799993240e 100644 --- a/src/client/ui/selector-inspector-panel/index.js +++ b/src/client/ui/selector-inspector-panel/index.js @@ -17,16 +17,18 @@ export default class SelectorInspectorPanel { this.element = createElementFromDescriptor(panel); const pickButton = new PickButton(); - const selectorInputContainer = new SelectorInputContainer(); - const copyButton = new CopyButton(selectorInputContainer); - const container = new MainContainer(pickButton.element, selectorInputContainer.element, copyButton.element); + + this.selectorInputContainer = new SelectorInputContainer(); + const copyButton = new CopyButton(this.selectorInputContainer); + const container = new MainContainer(pickButton.element, this.selectorInputContainer.element, copyButton.element); const hideButton = new HideButton(this.element); this.element.appendChild(container.element); this.element.appendChild(hideButton.element); } - show () { + show (selector) { + this.selectorInputContainer._debugSelector(selector); if (!this.element.parentElement) uiRoot.insertFirstChildToPanelsContainer(this.element); diff --git a/src/client/ui/selector-inspector-panel/selector-input-container.js b/src/client/ui/selector-inspector-panel/selector-input-container.js index bb669a8304e..feff4ed6b54 100644 --- a/src/client/ui/selector-inspector-panel/selector-input-container.js +++ b/src/client/ui/selector-inspector-panel/selector-input-container.js @@ -3,7 +3,7 @@ import hammerhead from './../deps/hammerhead'; import testCafeCore from './../deps/testcafe-core'; import { createElementFromDescriptor } from './utils/create-element-from-descriptor'; -import { getElementsBySelector } from './utils/get-elements-by-selector'; +import { getElementsBySelector, executeSelector } from './utils/get-elements-by-selector'; import * as descriptors from './descriptors'; import { elementPicker, ELEMENT_PICKED } from './element-picker'; @@ -159,4 +159,16 @@ export class SelectorInputContainer { this._indicateMatches(elements); this._highlightElements(elements); } + + async _debugSelector (selector) { + highlighter.stopHighlighting(); + const selectorValue = selector.apiFnChain.join(''); + + this.value = selectorValue; + let elements = await executeSelector(selector).catch(() => null); + + elements = nativeMethods.isArray(elements) ? elements : [elements]; + this._indicateMatches(elements); + this._highlightElements(elements); + } } diff --git a/src/client/ui/selector-inspector-panel/utils/get-elements-by-selector.js b/src/client/ui/selector-inspector-panel/utils/get-elements-by-selector.js index 5a554d075c4..711a452daf3 100644 --- a/src/client/ui/selector-inspector-panel/utils/get-elements-by-selector.js +++ b/src/client/ui/selector-inspector-panel/utils/get-elements-by-selector.js @@ -20,7 +20,7 @@ async function parseSelector (selector) { return browser.parseSelector(communicationUrls.parseSelector, createNativeXHR, selector); } -async function executeSelector (parsedSelector) { +export async function executeSelector (parsedSelector) { const startTime = nativeMethods.date(); const selectorExecutor = new SelectorExecutor(parsedSelector, GLOBAL_TIMEOUT, startTime, createNotFoundError, createIsInvisibleError); const elements = await selectorExecutor.getResult(); diff --git a/src/test-run/commands/actions.js b/src/test-run/commands/actions.js index 630135a91b3..f9fb3466c9e 100644 --- a/src/test-run/commands/actions.js +++ b/src/test-run/commands/actions.js @@ -175,6 +175,24 @@ export class ClickCommand extends ActionCommandBase { } } +export class DebugCommand extends ActionCommandBase { + static methodName = camelCase(TYPE.debug); + + constructor (obj, testRun,) { + super(obj, testRun, TYPE.debug); + } + + getAssignableProperties () { + return [ + { name: 'selector', init: (name, val, options) => { + return initSelector(name, val, Object.assign({}, options, + { skipVisibilityCheck: true, collectionMode: true } + )); + }, required: false }, + ]; + } +} + export class RightClickCommand extends ActionCommandBase { static methodName = camelCase(TYPE.rightClick); diff --git a/src/test-run/commands/base.d.ts b/src/test-run/commands/base.d.ts index c61e7150aaf..dbb24c61d8b 100644 --- a/src/test-run/commands/base.d.ts +++ b/src/test-run/commands/base.d.ts @@ -4,6 +4,7 @@ export class CommandBase { public constructor(obj?: object, testRun?: TestRun, type?: string, validateProperties?: boolean); public actionId: string; public type: string; + public selector: object; [key: string]: unknown; public getAssignableProperties(): { name: string }[]; public getAllAssignableProperties(): { name: string }[]; diff --git a/src/test-run/commands/service.js b/src/test-run/commands/service.js index 2dd4ac9006e..b87756533ef 100644 --- a/src/test-run/commands/service.js +++ b/src/test-run/commands/service.js @@ -16,9 +16,10 @@ export class HideAssertionRetriesStatusCommand { } export class SetBreakpointCommand { - constructor (isTestError) { + constructor (isTestError, selector) { this.type = TYPE.setBreakpoint; this.isTestError = isTestError; + this.selector = selector; } } diff --git a/src/test-run/index.ts b/src/test-run/index.ts index a228fa975fb..dae82e699d3 100644 --- a/src/test-run/index.ts +++ b/src/test-run/index.ts @@ -698,7 +698,7 @@ export default class TestRun extends AsyncEventEmitter { if (this.errs.length && this.debugOnFail) { const errStr = this.debugReporterPluginHost.formatError(this.errs[0]); - await this._enqueueSetBreakpointCommand(void 0, errStr); + await this._enqueueSetBreakpointCommand(void 0, null, errStr); } await this.emit('before-done'); @@ -821,11 +821,11 @@ export default class TestRun extends AsyncEventEmitter { return this.cookieProvider.deleteCookies(cookies, urls); } - private async _enqueueSetBreakpointCommand (callsite: CallsiteRecord | undefined, error?: string): Promise { + private async _enqueueSetBreakpointCommand (callsite: CallsiteRecord | undefined, selector?: object | null, error?: string): Promise { if (this.debugLogger) this.debugLogger.showBreakpoint(this.session.id, this.browserConnection.userAgent, callsite, error); - this.debugging = await this._internalExecuteCommand(new serviceCommands.SetBreakpointCommand(!!error), callsite) as boolean; + this.debugging = await this._internalExecuteCommand(new serviceCommands.SetBreakpointCommand(!!error, selector), callsite) as boolean; } private _removeAllNonServiceTasks (): void { @@ -1154,7 +1154,7 @@ export default class TestRun extends AsyncEventEmitter { const canDebug = !this.browserConnection.isHeadlessBrowser(); if (canDebug) - return await this._enqueueSetBreakpointCommand(callsite as CallsiteRecord, void 0); + return await this._enqueueSetBreakpointCommand(callsite as CallsiteRecord, command?.selector, void 0); this.debugging = false; From f8c19fde0a8e4239c435b1af383765ec9f597ea7 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Thu, 2 Nov 2023 23:27:45 +0600 Subject: [PATCH 2/9] fix: test error fixed --- test/server/compiler-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/server/compiler-test.js b/test/server/compiler-test.js index 8a522c4c047..2e716efaf26 100644 --- a/test/server/compiler-test.js +++ b/test/server/compiler-test.js @@ -1011,7 +1011,7 @@ describe('Compiler', function () { }); it('Should raise an error if test file has a TypeScript error', function () { - const testfile = posixResolve('test/server/data/test-suites/typescript-compile-errors/testfile.ts'); + const testfile = posixResolve('test/server/data/test-suites/typescript-compile-errors/testfile.ts').toLowerCase(); return compile(testfile) .then(function () { From 8a481acd77b2cdf87d692f1e0786c98423147f6e Mon Sep 17 00:00:00 2001 From: Bayheck Date: Mon, 6 Nov 2023 17:57:47 +0600 Subject: [PATCH 3/9] refactoring and testing: added tests for debug with selector, refactored DebugCommand and execute-client-function --- src/api/skip-js-errors/index.ts | 2 +- src/api/test-controller/index.js | 3 +- .../client-function-builder.js | 2 +- .../selectors/selector-builder.js | 2 +- .../action-executor/elements-retriever.ts | 2 +- .../client-function-executor.ts | 2 +- .../selector-executor/index.ts | 2 +- src/reporter/command/command-formatter.ts | 2 +- src/shared/types.d.ts | 2 +- src/test-run/bookmark.ts | 2 +- src/test-run/commands/actions.d.ts | 2 +- src/test-run/commands/actions.js | 20 +------ .../commands/execute-client-function.d.ts | 24 +++++++++ .../commands/execute-client-function.js | 44 +++++++++++++++ src/test-run/commands/observation.d.ts | 24 +-------- src/test-run/commands/observation.js | 53 +++++-------------- .../commands/validations/initializers.js | 2 +- src/test-run/index.ts | 6 +-- .../selector-inspector-test.js | 30 +++++++++++ 19 files changed, 127 insertions(+), 99 deletions(-) create mode 100644 src/test-run/commands/execute-client-function.d.ts create mode 100644 src/test-run/commands/execute-client-function.js diff --git a/src/api/skip-js-errors/index.ts b/src/api/skip-js-errors/index.ts index 423ef645053..e2dc969952b 100644 --- a/src/api/skip-js-errors/index.ts +++ b/src/api/skip-js-errors/index.ts @@ -2,7 +2,7 @@ import { Dictionary, SkipJsErrorsCallback, SkipJsErrorsCallbackWithOptionsObject, SkipJsErrorsOptionsObject, } from '../../configuration/interfaces'; import { parseRegExpString } from '../../utils/make-reg-exp'; -import { ExecuteClientFunctionCommand } from '../../test-run/commands/observation'; +import { ExecuteClientFunctionCommand } from '../../test-run/commands/execute-client-function'; import ClientFunctionBuilder from '../../client-functions/client-function-builder'; const SKIP_JS_ERRORS_OBJECT_FUNCTION = ` diff --git a/src/api/test-controller/index.js b/src/api/test-controller/index.js index 50dfda1a117..87055fe3bbc 100644 --- a/src/api/test-controller/index.js +++ b/src/api/test-controller/index.js @@ -57,7 +57,6 @@ import { AddRequestHooksCommand, RemoveRequestHooksCommand, ReportCommand, - DebugCommand, } from '../../test-run/commands/actions'; import { @@ -68,7 +67,7 @@ import { MaximizeWindowCommand, } from '../../test-run/commands/browser-manipulation'; -import { WaitCommand } from '../../test-run/commands/observation'; +import { WaitCommand, DebugCommand } from '../../test-run/commands/observation'; import { createExecutionContext as createContext } from './execution-context'; import { isSelector } from '../../client-functions/types'; diff --git a/src/client-functions/client-function-builder.js b/src/client-functions/client-function-builder.js index 42807fcf9ba..53063783425 100644 --- a/src/client-functions/client-function-builder.js +++ b/src/client-functions/client-function-builder.js @@ -2,7 +2,7 @@ import { isNil as isNullOrUndefined, assign } from 'lodash'; import testRunTracker from '../api/test-run-tracker'; import functionBuilderSymbol from './builder-symbol'; import { createReplicator, FunctionTransform } from './replicator'; -import { ExecuteClientFunctionCommand } from '../test-run/commands/observation'; +import { ExecuteClientFunctionCommand } from '../test-run/commands/execute-client-function'; import compileClientFunction from '../compiler/compile-client-function'; import { APIError, ClientFunctionAPIError } from '../errors/runtime'; import { assertType, is } from '../errors/runtime/type-assertions'; diff --git a/src/client-functions/selectors/selector-builder.js b/src/client-functions/selectors/selector-builder.js index 89af395b4c9..11e7fc17b19 100644 --- a/src/client-functions/selectors/selector-builder.js +++ b/src/client-functions/selectors/selector-builder.js @@ -6,7 +6,7 @@ import { ClientFunctionAPIError } from '../../errors/runtime'; import functionBuilderSymbol from '../builder-symbol'; import { RUNTIME_ERRORS } from '../../errors/types'; import { assertType, is } from '../../errors/runtime/type-assertions'; -import { ExecuteSelectorCommand } from '../../test-run/commands/observation'; +import { ExecuteSelectorCommand } from '../../test-run/commands/execute-client-function'; import defineLazyProperty from '../../utils/define-lazy-property'; import { addAPI, addCustomMethods } from './add-api'; import createSnapshotMethods from './create-snapshot-methods'; diff --git a/src/client/driver/command-executors/action-executor/elements-retriever.ts b/src/client/driver/command-executors/action-executor/elements-retriever.ts index 50e4d62d66c..afd3890da25 100644 --- a/src/client/driver/command-executors/action-executor/elements-retriever.ts +++ b/src/client/driver/command-executors/action-executor/elements-retriever.ts @@ -1,4 +1,4 @@ -import { ExecuteSelectorCommand } from '../../../../test-run/commands/observation'; +import { ExecuteSelectorCommand } from '../../../../test-run/commands/execute-client-function'; import { ExecuteSelectorFn } from '../../../../shared/types'; import NODE_TYPE_DESCRIPTIONS from '../../node-type-descriptions'; import { diff --git a/src/client/driver/command-executors/client-functions/client-function-executor.ts b/src/client/driver/command-executors/client-functions/client-function-executor.ts index c2df8aeebd6..3a1effc6e2b 100644 --- a/src/client/driver/command-executors/client-functions/client-function-executor.ts +++ b/src/client/driver/command-executors/client-functions/client-function-executor.ts @@ -4,7 +4,7 @@ import ClientFunctionNodeTransform from './replicator/transforms/client-function import evalFunction from './eval-function'; import { UncaughtErrorInClientFunctionCode } from '../../../../shared/errors/index'; import Replicator from 'replicator'; -import { ExecuteClientFunctionCommand, ExecuteClientFunctionCommandBase } from '../../../../test-run/commands/observation'; +import { ExecuteClientFunctionCommand, ExecuteClientFunctionCommandBase } from '../../../../test-run/commands/execute-client-function'; import { Dictionary } from '../../../../configuration/interfaces'; // @ts-ignore import { Promise } from '../../deps/hammerhead'; diff --git a/src/client/driver/command-executors/client-functions/selector-executor/index.ts b/src/client/driver/command-executors/client-functions/selector-executor/index.ts index 72f6dcbced7..2907be829e7 100644 --- a/src/client/driver/command-executors/client-functions/selector-executor/index.ts +++ b/src/client/driver/command-executors/client-functions/selector-executor/index.ts @@ -2,7 +2,7 @@ import ClientFunctionExecutor from '../client-function-executor'; import createReplicator from '../replicator/index'; import FunctionTransform from '../replicator/transforms/function-transform'; import SelectorNodeTransform from '../replicator/transforms/selector-node-transform'; -import { ExecuteSelectorCommand } from '../../../../../test-run/commands/observation'; +import { ExecuteSelectorCommand } from '../../../../../test-run/commands/execute-client-function'; import { SelectorErrorParams, SelectorDependencies, diff --git a/src/reporter/command/command-formatter.ts b/src/reporter/command/command-formatter.ts index b75f00b6076..e87a7c349a1 100644 --- a/src/reporter/command/command-formatter.ts +++ b/src/reporter/command/command-formatter.ts @@ -1,5 +1,5 @@ import { isEmpty } from 'lodash'; -import { ExecuteSelectorCommand, ExecuteClientFunctionCommand } from '../../test-run/commands/observation'; +import { ExecuteSelectorCommand, ExecuteClientFunctionCommand } from '../../test-run/commands/execute-client-function'; import { NavigateToCommand, PressKeyCommand, diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 401684901b3..f6fca23f716 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -1,6 +1,6 @@ /* global globalThis */ -import { ExecuteSelectorCommand } from '../test-run/commands/observation'; +import { ExecuteSelectorCommand } from '../test-run/commands/execute-client-function'; export interface NativeMethods { setTimeout: typeof globalThis.setTimeout; diff --git a/src/test-run/bookmark.ts b/src/test-run/bookmark.ts index 68e63b9aa4e..82489ca98a5 100644 --- a/src/test-run/bookmark.ts +++ b/src/test-run/bookmark.ts @@ -12,7 +12,7 @@ import { import { CurrentIframeNotFoundError, CurrentIframeIsNotLoadedError } from '../errors/test-run'; import TestRun from './index'; -import { ExecuteClientFunctionCommand, ExecuteSelectorCommand } from './commands/observation'; +import { ExecuteClientFunctionCommand, ExecuteSelectorCommand } from './commands/execute-client-function'; import Role, { RedirectUrl } from '../role/role'; import { DEFAULT_SPEED_VALUE } from '../configuration/default-values'; import BrowserConsoleMessages from './browser-console-messages'; diff --git a/src/test-run/commands/actions.d.ts b/src/test-run/commands/actions.d.ts index b9dd7c8ee85..07b07fe8d94 100644 --- a/src/test-run/commands/actions.d.ts +++ b/src/test-run/commands/actions.d.ts @@ -1,5 +1,5 @@ import { ActionCommandBase, CommandBase } from './base'; -import { ExecuteClientFunctionCommand, ExecuteSelectorCommand } from './observation'; +import { ExecuteClientFunctionCommand, ExecuteSelectorCommand } from './execute-client-function'; import { ActionOptions, diff --git a/src/test-run/commands/actions.js b/src/test-run/commands/actions.js index f9fb3466c9e..df4a55df651 100644 --- a/src/test-run/commands/actions.js +++ b/src/test-run/commands/actions.js @@ -48,7 +48,7 @@ import { } from './validations/argument'; import { SetNativeDialogHandlerCodeWrongTypeError } from '../../errors/test-run'; -import { ExecuteClientFunctionCommand } from './observation'; +import { ExecuteClientFunctionCommand } from './execute-client-function'; import { camelCase } from 'lodash'; import { prepareSkipJsErrorsOptions, @@ -175,24 +175,6 @@ export class ClickCommand extends ActionCommandBase { } } -export class DebugCommand extends ActionCommandBase { - static methodName = camelCase(TYPE.debug); - - constructor (obj, testRun,) { - super(obj, testRun, TYPE.debug); - } - - getAssignableProperties () { - return [ - { name: 'selector', init: (name, val, options) => { - return initSelector(name, val, Object.assign({}, options, - { skipVisibilityCheck: true, collectionMode: true } - )); - }, required: false }, - ]; - } -} - export class RightClickCommand extends ActionCommandBase { static methodName = camelCase(TYPE.rightClick); diff --git a/src/test-run/commands/execute-client-function.d.ts b/src/test-run/commands/execute-client-function.d.ts new file mode 100644 index 00000000000..176f4e2b8d5 --- /dev/null +++ b/src/test-run/commands/execute-client-function.d.ts @@ -0,0 +1,24 @@ +import { CommandBase } from './base'; +import TestRun from '../index'; + +declare class ExecuteClientFunctionCommandBase extends CommandBase { + public constructor(obj: object, testRun: TestRun, type: string); + public instantiationCallsiteName: string; + public fnCode: string; + public args: string[]; + public dependencies: string[]; +} + +export class ExecuteClientFunctionCommand extends ExecuteClientFunctionCommandBase { + public constructor(obj: object, testRun: TestRun); +} + +export class ExecuteSelectorCommand extends ExecuteClientFunctionCommandBase { + public constructor(obj: object, testRun: TestRun); + public visibilityCheck: boolean; + public timeout?: number; + public apiFnChain: string[]; + public needError: boolean; + public index: number; + public strictError: boolean; +} diff --git a/src/test-run/commands/execute-client-function.js b/src/test-run/commands/execute-client-function.js new file mode 100644 index 00000000000..02fde995bd7 --- /dev/null +++ b/src/test-run/commands/execute-client-function.js @@ -0,0 +1,44 @@ +import TYPE from './type'; +import { ActionCommandBase } from './base'; + +export class ExecuteClientFunctionCommandBase extends ActionCommandBase { + constructor (obj, testRun, type) { + super(obj, testRun, type, false); + } + + getAssignableProperties () { + return [ + { name: 'instantiationCallsiteName', defaultValue: '' }, + { name: 'fnCode', defaultValue: '' }, + { name: 'args', defaultValue: [] }, + { name: 'dependencies', defaultValue: [] }, + ]; + } +} + +export class ExecuteClientFunctionCommand extends ExecuteClientFunctionCommandBase { + static methodName = TYPE.executeClientFunction; + + constructor (obj, testRun) { + super(obj, testRun, TYPE.executeClientFunction); + } +} + +export class ExecuteSelectorCommand extends ExecuteClientFunctionCommandBase { + static methodName = TYPE.executeSelector; + + constructor (obj, testRun) { + super(obj, testRun, TYPE.executeSelector); + } + + getAssignableProperties () { + return [ + { name: 'visibilityCheck', defaultValue: false }, + { name: 'timeout', defaultValue: null }, + { name: 'apiFnChain' }, + { name: 'needError' }, + { name: 'index', defaultValue: 0 }, + { name: 'strictError' }, + ]; + } +} diff --git a/src/test-run/commands/observation.d.ts b/src/test-run/commands/observation.d.ts index 6cd97edfec9..212a0f4f130 100644 --- a/src/test-run/commands/observation.d.ts +++ b/src/test-run/commands/observation.d.ts @@ -1,28 +1,6 @@ -import { CommandBase, ActionCommandBase } from './base'; +import { ActionCommandBase } from './base'; import TestRun from '../index'; -declare class ExecuteClientFunctionCommandBase extends CommandBase { - public constructor(obj: object, testRun: TestRun, type: string); - public instantiationCallsiteName: string; - public fnCode: string; - public args: string[]; - public dependencies: string[]; -} - -export class ExecuteClientFunctionCommand extends ExecuteClientFunctionCommandBase { - public constructor(obj: object, testRun: TestRun); -} - -export class ExecuteSelectorCommand extends ExecuteClientFunctionCommandBase { - public constructor(obj: object, testRun: TestRun); - public visibilityCheck: boolean; - public timeout?: number; - public apiFnChain: string[]; - public needError: boolean; - public index: number; - public strictError: boolean; -} - export class WaitCommand extends ActionCommandBase { public constructor(obj: object, testRun: TestRun); public timeout: number; diff --git a/src/test-run/commands/observation.js b/src/test-run/commands/observation.js index e86267b70f5..1c28716dfee 100644 --- a/src/test-run/commands/observation.js +++ b/src/test-run/commands/observation.js @@ -2,6 +2,9 @@ import TYPE from './type'; import { ActionCommandBase } from './base'; import { positiveIntegerArgument } from './validations/argument'; import { camelCase } from 'lodash'; +import { + initSelector, +} from './validations/initializers'; // Commands export class WaitCommand extends ActionCommandBase { @@ -18,52 +21,20 @@ export class WaitCommand extends ActionCommandBase { } } -export class ExecuteClientFunctionCommandBase extends ActionCommandBase { - constructor (obj, testRun, type) { - super(obj, testRun, type, false); - } - - getAssignableProperties () { - return [ - { name: 'instantiationCallsiteName', defaultValue: '' }, - { name: 'fnCode', defaultValue: '' }, - { name: 'args', defaultValue: [] }, - { name: 'dependencies', defaultValue: [] }, - ]; - } -} - -export class ExecuteClientFunctionCommand extends ExecuteClientFunctionCommandBase { - static methodName = TYPE.executeClientFunction; - - constructor (obj, testRun) { - super(obj, testRun, TYPE.executeClientFunction); - } -} - -export class ExecuteSelectorCommand extends ExecuteClientFunctionCommandBase { - static methodName = TYPE.executeSelector; +export class DebugCommand extends ActionCommandBase { + static methodName = camelCase(TYPE.debug); - constructor (obj, testRun) { - super(obj, testRun, TYPE.executeSelector); + constructor (obj, testRun,) { + super(obj, testRun, TYPE.debug); } getAssignableProperties () { return [ - { name: 'visibilityCheck', defaultValue: false }, - { name: 'timeout', defaultValue: null }, - { name: 'apiFnChain' }, - { name: 'needError' }, - { name: 'index', defaultValue: 0 }, - { name: 'strictError' }, + { name: 'selector', init: (name, val, options) => { + return initSelector(name, val, Object.assign({}, options, + { skipVisibilityCheck: true, collectionMode: true } + )); + }, required: false }, ]; } } - -export class DebugCommand extends ActionCommandBase { - static methodName = camelCase(TYPE.debug); - - constructor () { - super(null, null, TYPE.debug); - } -} diff --git a/src/test-run/commands/validations/initializers.js b/src/test-run/commands/validations/initializers.js index e1c2e2335ae..9e4905ce014 100644 --- a/src/test-run/commands/validations/initializers.js +++ b/src/test-run/commands/validations/initializers.js @@ -1,7 +1,7 @@ import SelectorBuilder from '../../../client-functions/selectors/selector-builder'; import { ActionSelectorError } from '../../../errors/test-run'; import { APIError } from '../../../errors/runtime'; -import { ExecuteSelectorCommand } from '../observation'; +import { ExecuteSelectorCommand } from '../execute-client-function'; import { executeJsExpression } from '../../execute-js-expression'; import { isJSExpression } from '../utils'; diff --git a/src/test-run/index.ts b/src/test-run/index.ts index dae82e699d3..ecd93d9e703 100644 --- a/src/test-run/index.ts +++ b/src/test-run/index.ts @@ -107,7 +107,7 @@ import TestRunPhase from './phase'; import { ExecuteClientFunctionCommand, ExecuteSelectorCommand, -} from './commands/observation'; +} from './commands/execute-client-function'; import addRenderedWarning from '../notifications/add-rendered-warning'; import getBrowser from '../utils/get-browser'; @@ -142,7 +142,7 @@ const TestRunBookmark = lazyRequire('./bookmark'); const actionCommands = lazyRequire('./commands/actions'); const browserManipulationCommands = lazyRequire('./commands/browser-manipulation'); const serviceCommands = lazyRequire('./commands/service'); -const observationCommands = lazyRequire('./commands/observation'); +const executeClientFunctionCommands = lazyRequire('./commands/execute-client-function'); const { executeJsExpression, executeAsyncJsExpression } = lazyRequire('./execute-js-expression'); @@ -880,7 +880,7 @@ export default class TestRun extends AsyncEventEmitter { private _shouldResolveCurrentDriverTask (driverStatus: DriverStatus): boolean { const currentCommand = this.currentDriverTask.command; - const isExecutingObservationCommand = currentCommand instanceof observationCommands.ExecuteSelectorCommand || + const isExecutingObservationCommand = currentCommand instanceof executeClientFunctionCommands.ExecuteSelectorCommand || currentCommand instanceof ExecuteClientFunctionCommand; const isDebugActive = currentCommand instanceof serviceCommands.SetBreakpointCommand; diff --git a/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js b/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js index e35b9a92e8c..1c060103714 100644 --- a/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js +++ b/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js @@ -283,3 +283,33 @@ test('should hide panel', async t => { await t.debug(); }); + +test('should indicate the correct number of elements matching the TestCafe selector passed in debug', async t => { + + await ClientFunction(() => { + const { getMatchIndicatorInnerText, resumeTest } = window; + + getMatchIndicatorInnerText() + .then(text => { + if (text === 'Found: 5') + resumeTest(); + }); + })(); + + await t.debug('p'); +}); + +test('should indicate single element matching the TestCafe selector passed in debug', async t => { + + await ClientFunction(() => { + const { getMatchIndicatorInnerText, resumeTest } = window; + + getMatchIndicatorInnerText() + .then(text => { + if (text === 'Found: 1') + resumeTest(); + }); + })(); + + await t.debug('#container'); +}); From f310de371786f73d97ecd881a12c8f22bc518087 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Mon, 6 Nov 2023 19:01:46 +0600 Subject: [PATCH 4/9] fix: test fixed --- test/server/data/test-controller-reporter-expected/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/server/data/test-controller-reporter-expected/index.js b/test/server/data/test-controller-reporter-expected/index.js index 4c4710fd8a1..865ee0899a2 100644 --- a/test/server/data/test-controller-reporter-expected/index.js +++ b/test/server/data/test-controller-reporter-expected/index.js @@ -747,6 +747,7 @@ module.exports = { name: 'debug', command: { type: 'debug', + selector: undefined, actionId: 'DebugCommand', }, test: { From 66b789af9f46eb58ec3407e8216434cd0bde17b7 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Tue, 7 Nov 2023 18:44:49 +0600 Subject: [PATCH 5/9] refactor: debugCommand selector type refactored --- src/test-run/commands/base.d.ts | 1 - src/test-run/commands/observation.d.ts | 6 +++++- src/test-run/index.ts | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test-run/commands/base.d.ts b/src/test-run/commands/base.d.ts index dbb24c61d8b..c61e7150aaf 100644 --- a/src/test-run/commands/base.d.ts +++ b/src/test-run/commands/base.d.ts @@ -4,7 +4,6 @@ export class CommandBase { public constructor(obj?: object, testRun?: TestRun, type?: string, validateProperties?: boolean); public actionId: string; public type: string; - public selector: object; [key: string]: unknown; public getAssignableProperties(): { name: string }[]; public getAllAssignableProperties(): { name: string }[]; diff --git a/src/test-run/commands/observation.d.ts b/src/test-run/commands/observation.d.ts index 212a0f4f130..ab9c9924e78 100644 --- a/src/test-run/commands/observation.d.ts +++ b/src/test-run/commands/observation.d.ts @@ -1,4 +1,5 @@ import { ActionCommandBase } from './base'; +import { ExecuteClientFunctionCommand } from './execute-client-function'; import TestRun from '../index'; export class WaitCommand extends ActionCommandBase { @@ -6,4 +7,7 @@ export class WaitCommand extends ActionCommandBase { public timeout: number; } -export class DebugCommand extends ActionCommandBase { } +export class DebugCommand extends ActionCommandBase { + public constructor(obj: object, testRun: TestRun, validateProperties?: boolean); + public selector?: ExecuteClientFunctionCommand; +} diff --git a/src/test-run/index.ts b/src/test-run/index.ts index ecd93d9e703..43db9f01136 100644 --- a/src/test-run/index.ts +++ b/src/test-run/index.ts @@ -75,6 +75,7 @@ import { RemoveRequestHooksCommand, RunCustomActionCommand, } from './commands/actions'; +import { DebugCommand } from './commands/observation'; import { RUNTIME_ERRORS, TEST_RUN_ERRORS } from '../errors/types'; import processTestFnError from '../errors/process-test-fn-error'; @@ -1154,7 +1155,7 @@ export default class TestRun extends AsyncEventEmitter { const canDebug = !this.browserConnection.isHeadlessBrowser(); if (canDebug) - return await this._enqueueSetBreakpointCommand(callsite as CallsiteRecord, command?.selector, void 0); + return await this._enqueueSetBreakpointCommand(callsite as CallsiteRecord, (command as DebugCommand)?.selector, void 0); this.debugging = false; From 48bea1ee01aba8ab0d93fba0999d65e95ed2fb50 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Wed, 8 Nov 2023 16:23:11 +0600 Subject: [PATCH 6/9] remove fix test --- test/server/compiler-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/server/compiler-test.js b/test/server/compiler-test.js index 2e716efaf26..8a522c4c047 100644 --- a/test/server/compiler-test.js +++ b/test/server/compiler-test.js @@ -1011,7 +1011,7 @@ describe('Compiler', function () { }); it('Should raise an error if test file has a TypeScript error', function () { - const testfile = posixResolve('test/server/data/test-suites/typescript-compile-errors/testfile.ts').toLowerCase(); + const testfile = posixResolve('test/server/data/test-suites/typescript-compile-errors/testfile.ts'); return compile(testfile) .then(function () { From bf679c83beba8887354f3cf84830b3c597ea8160 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Fri, 10 Nov 2023 18:16:30 +0600 Subject: [PATCH 7/9] fix: pr comments fixed --- .../ui/selector-inspector-panel/index.js | 4 ++-- .../selector-input-container.js | 9 ++++----- .../utils/cast-array.js | 7 +++++++ src/test-run/commands/observation.js | 19 ++++++++++--------- src/test-run/commands/service.js | 2 +- src/test-run/index.ts | 14 +++++++------- test/functional/fixtures/ui/test.js | 4 ++++ .../selector-inspector-test.js | 2 -- 8 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 src/client/ui/selector-inspector-panel/utils/cast-array.js diff --git a/src/client/ui/selector-inspector-panel/index.js b/src/client/ui/selector-inspector-panel/index.js index b799993240e..dcec31319ec 100644 --- a/src/client/ui/selector-inspector-panel/index.js +++ b/src/client/ui/selector-inspector-panel/index.js @@ -15,7 +15,6 @@ export default class SelectorInspectorPanel { constructor () { this.element = createElementFromDescriptor(panel); - const pickButton = new PickButton(); this.selectorInputContainer = new SelectorInputContainer(); @@ -28,7 +27,8 @@ export default class SelectorInspectorPanel { } show (selector) { - this.selectorInputContainer._debugSelector(selector); + this.selectorInputContainer.debugSelector(selector); + if (!this.element.parentElement) uiRoot.insertFirstChildToPanelsContainer(this.element); diff --git a/src/client/ui/selector-inspector-panel/selector-input-container.js b/src/client/ui/selector-inspector-panel/selector-input-container.js index feff4ed6b54..5a010e3dc50 100644 --- a/src/client/ui/selector-inspector-panel/selector-input-container.js +++ b/src/client/ui/selector-inspector-panel/selector-input-container.js @@ -4,6 +4,7 @@ import testCafeCore from './../deps/testcafe-core'; import { createElementFromDescriptor } from './utils/create-element-from-descriptor'; import { getElementsBySelector, executeSelector } from './utils/get-elements-by-selector'; +import { castArray } from './utils/cast-array'; import * as descriptors from './descriptors'; import { elementPicker, ELEMENT_PICKED } from './element-picker'; @@ -160,14 +161,12 @@ export class SelectorInputContainer { this._highlightElements(elements); } - async _debugSelector (selector) { + async debugSelector (selector) { highlighter.stopHighlighting(); - const selectorValue = selector.apiFnChain.join(''); - this.value = selectorValue; - let elements = await executeSelector(selector).catch(() => null); + this.value = selector.apiFnChain.join(''); + const elements = castArray(await executeSelector(selector)); - elements = nativeMethods.isArray(elements) ? elements : [elements]; this._indicateMatches(elements); this._highlightElements(elements); } diff --git a/src/client/ui/selector-inspector-panel/utils/cast-array.js b/src/client/ui/selector-inspector-panel/utils/cast-array.js new file mode 100644 index 00000000000..63a9f792177 --- /dev/null +++ b/src/client/ui/selector-inspector-panel/utils/cast-array.js @@ -0,0 +1,7 @@ +import hammerhead from '../../deps/hammerhead'; + +const nativeMethods = hammerhead.nativeMethods; + +export function castArray (elements) { + return nativeMethods.isArray(elements) ? elements : [elements]; +} diff --git a/src/test-run/commands/observation.js b/src/test-run/commands/observation.js index 1c28716dfee..c496e5c31d2 100644 --- a/src/test-run/commands/observation.js +++ b/src/test-run/commands/observation.js @@ -2,9 +2,14 @@ import TYPE from './type'; import { ActionCommandBase } from './base'; import { positiveIntegerArgument } from './validations/argument'; import { camelCase } from 'lodash'; -import { - initSelector, -} from './validations/initializers'; +import { initSelector } from './validations/initializers'; + +// Initializers +function initDebugOptions (name, val, options) { + return initSelector(name, val, Object.assign({}, options, + { skipVisibilityCheck: true, collectionMode: true } + )); +} // Commands export class WaitCommand extends ActionCommandBase { @@ -24,17 +29,13 @@ export class WaitCommand extends ActionCommandBase { export class DebugCommand extends ActionCommandBase { static methodName = camelCase(TYPE.debug); - constructor (obj, testRun,) { + constructor (obj, testRun) { super(obj, testRun, TYPE.debug); } getAssignableProperties () { return [ - { name: 'selector', init: (name, val, options) => { - return initSelector(name, val, Object.assign({}, options, - { skipVisibilityCheck: true, collectionMode: true } - )); - }, required: false }, + { name: 'selector', init: initDebugOptions, required: false }, ]; } } diff --git a/src/test-run/commands/service.js b/src/test-run/commands/service.js index b87756533ef..b283f9b43f7 100644 --- a/src/test-run/commands/service.js +++ b/src/test-run/commands/service.js @@ -19,7 +19,7 @@ export class SetBreakpointCommand { constructor (isTestError, selector) { this.type = TYPE.setBreakpoint; this.isTestError = isTestError; - this.selector = selector; + this.selector = selector; } } diff --git a/src/test-run/index.ts b/src/test-run/index.ts index 43db9f01136..82a952d816e 100644 --- a/src/test-run/index.ts +++ b/src/test-run/index.ts @@ -137,13 +137,13 @@ import NativeAutomationRequestPipeline from '../native-automation/request-pipeli import NativeAutomation from '../native-automation'; import ReportDataLog from '../reporter/report-data-log'; -const lazyRequire = require('import-lazy')(require); -const ClientFunctionBuilder = lazyRequire('../client-functions/client-function-builder'); -const TestRunBookmark = lazyRequire('./bookmark'); -const actionCommands = lazyRequire('./commands/actions'); -const browserManipulationCommands = lazyRequire('./commands/browser-manipulation'); -const serviceCommands = lazyRequire('./commands/service'); -const executeClientFunctionCommands = lazyRequire('./commands/execute-client-function'); +const lazyRequire = require('import-lazy')(require); +const ClientFunctionBuilder = lazyRequire('../client-functions/client-function-builder'); +const TestRunBookmark = lazyRequire('./bookmark'); +const actionCommands = lazyRequire('./commands/actions'); +const browserManipulationCommands = lazyRequire('./commands/browser-manipulation'); +const serviceCommands = lazyRequire('./commands/service'); +const executeClientFunctionCommands = lazyRequire('./commands/execute-client-function'); const { executeJsExpression, executeAsyncJsExpression } = lazyRequire('./execute-js-expression'); diff --git a/test/functional/fixtures/ui/test.js b/test/functional/fixtures/ui/test.js index e9ffa9a7d1b..f398b477d98 100644 --- a/test/functional/fixtures/ui/test.js +++ b/test/functional/fixtures/ui/test.js @@ -43,5 +43,9 @@ describe('TestCafe UI', () => { runTestCafeTest('should copy selector'); runTestCafeTest('should hide panel'); + + runTestCafeTest('should indicate the correct number of elements matching the TestCafe selector passed in debug'); + + runTestCafeTest('should indicate single element matching the TestCafe selector passed in debug'); }); }); diff --git a/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js b/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js index 1c060103714..11386736fe7 100644 --- a/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js +++ b/test/functional/fixtures/ui/testcafe-fixtures/selector-inspector-test.js @@ -285,7 +285,6 @@ test('should hide panel', async t => { }); test('should indicate the correct number of elements matching the TestCafe selector passed in debug', async t => { - await ClientFunction(() => { const { getMatchIndicatorInnerText, resumeTest } = window; @@ -300,7 +299,6 @@ test('should indicate the correct number of elements matching the TestCafe selec }); test('should indicate single element matching the TestCafe selector passed in debug', async t => { - await ClientFunction(() => { const { getMatchIndicatorInnerText, resumeTest } = window; From 66c10f7925e6052b583bbf6fd204b08ff2df6d1b Mon Sep 17 00:00:00 2001 From: Bayheck Date: Mon, 13 Nov 2023 14:03:07 +0600 Subject: [PATCH 8/9] fix: pr comments fix --- src/client/ui/selector-inspector-panel/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/client/ui/selector-inspector-panel/index.js b/src/client/ui/selector-inspector-panel/index.js index dcec31319ec..ee8ed1b29a4 100644 --- a/src/client/ui/selector-inspector-panel/index.js +++ b/src/client/ui/selector-inspector-panel/index.js @@ -14,10 +14,9 @@ export default class SelectorInspectorPanel { elementPicker = elementPicker; constructor () { - this.element = createElementFromDescriptor(panel); + this.element = createElementFromDescriptor(panel); + this.selectorInputContainer = new SelectorInputContainer(); const pickButton = new PickButton(); - - this.selectorInputContainer = new SelectorInputContainer(); const copyButton = new CopyButton(this.selectorInputContainer); const container = new MainContainer(pickButton.element, this.selectorInputContainer.element, copyButton.element); const hideButton = new HideButton(this.element); From 67d8b9437d78a7f12bea69736c71058be6690dd9 Mon Sep 17 00:00:00 2001 From: Bayheck Date: Mon, 13 Nov 2023 14:11:29 +0600 Subject: [PATCH 9/9] fix: pr comments fixed --- .../ui/selector-inspector-panel/selector-input-container.js | 2 +- src/test-run/commands/observation.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/ui/selector-inspector-panel/selector-input-container.js b/src/client/ui/selector-inspector-panel/selector-input-container.js index 5a010e3dc50..9866f535094 100644 --- a/src/client/ui/selector-inspector-panel/selector-input-container.js +++ b/src/client/ui/selector-inspector-panel/selector-input-container.js @@ -164,7 +164,7 @@ export class SelectorInputContainer { async debugSelector (selector) { highlighter.stopHighlighting(); - this.value = selector.apiFnChain.join(''); + this.value = selector.apiFnChain.join(''); const elements = castArray(await executeSelector(selector)); this._indicateMatches(elements); diff --git a/src/test-run/commands/observation.js b/src/test-run/commands/observation.js index c496e5c31d2..c362467c11e 100644 --- a/src/test-run/commands/observation.js +++ b/src/test-run/commands/observation.js @@ -4,6 +4,7 @@ import { positiveIntegerArgument } from './validations/argument'; import { camelCase } from 'lodash'; import { initSelector } from './validations/initializers'; + // Initializers function initDebugOptions (name, val, options) { return initSelector(name, val, Object.assign({}, options,