diff --git a/.eslintrc.yaml b/.eslintrc.yaml index e4a94bbf..98c2a542 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -15,7 +15,7 @@ parserOptions: sourceType: module plugins: [simple-import-sort, typescript-sort-keys] root: true -ignorePatterns: [bin/forks/*/package, build, local] +ignorePatterns: [build, local] rules: class-methods-use-this: off complexity: [error, {max: 10}] @@ -74,7 +74,7 @@ rules: import/no-unassigned-import: error import/no-unresolved: - error - - {commonjs: true, ignore: [autotests, e2ed/testcafe]} + - {commonjs: true, ignore: [autotests]} import/no-unused-modules: - error - ignoreExports: @@ -109,7 +109,7 @@ rules: - ':not(MethodDefinition, Property) > FunctionExpression' no-return-await: off no-shadow: off - no-underscore-dangle: [error, {allow: [_onConfigureResponse]}] + no-underscore-dangle: error no-unused-expressions: off no-useless-constructor: off no-use-before-define: off diff --git a/LICENSE b/LICENSE index 6a9ec3d2..733c44ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2021-2024 SIA Joom +Copyright (c) 2021-2025 SIA Joom Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/autotests/packs/allTests.ts b/autotests/packs/allTests.ts index f5353dfc..9380d586 100644 --- a/autotests/packs/allTests.ts +++ b/autotests/packs/allTests.ts @@ -1,7 +1,7 @@ /** * @file Pack file (file with configuration of pack). * Do not import anything (from `utils`, etc) into this file other than - * the types and values from `../configurator`, `e2ed/configurator`, `e2ed/constants` + * the types and values from `../configurator`, `e2ed/configurator` * or other packs (because the pack is compiled separately from the tests themselves * and has separate TypeScript scope). */ diff --git a/autotests/packs/local.example.ts b/autotests/packs/local.example.ts index a4d9d363..c9ec679a 100644 --- a/autotests/packs/local.example.ts +++ b/autotests/packs/local.example.ts @@ -1,3 +1,11 @@ +/** + * @file Pack for local development. + * Do not import anything (from `utils`, etc) into this file other than + * the types and values from `../configurator`, `e2ed/configurator` + * or other packs (because the pack is compiled separately from the tests themselves + * and has separate TypeScript scope). + */ + import {pack as allTestsPack} from './allTests'; import type {Pack} from 'autotests/configurator'; diff --git a/autotests/pageObjects/pages/E2edReportExample/E2edReportExample.ts b/autotests/pageObjects/pages/E2edReportExample/E2edReportExample.ts index 4772930a..2b8dc584 100644 --- a/autotests/pageObjects/pages/E2edReportExample/E2edReportExample.ts +++ b/autotests/pageObjects/pages/E2edReportExample/E2edReportExample.ts @@ -28,8 +28,7 @@ export class E2edReportExample extends Page { /** * Button tabs in navigation bar with test retries. */ - readonly navigationRetriesButton: Selector = - this.navigationRetries.findByLocatorId('RetryButton'); + readonly navigationRetriesButton: Selector = this.navigationRetries.findByTestId('RetryButton'); /** * Selected button tab in navigation bar with test retries. @@ -52,7 +51,7 @@ export class E2edReportExample extends Page { /** * Test run button. */ - readonly testRunButton: Selector = this.testRunsList.findByLocatorId('TestRunButton'); + readonly testRunButton: Selector = this.testRunsList.findByTestId('TestRunButton'); /** * List of test runs of retry. diff --git a/autotests/pageObjects/pages/E2edReportExample/TestRunButton.ts b/autotests/pageObjects/pages/E2edReportExample/TestRunButton.ts index 317df8b9..02b6fe21 100644 --- a/autotests/pageObjects/pages/E2edReportExample/TestRunButton.ts +++ b/autotests/pageObjects/pages/E2edReportExample/TestRunButton.ts @@ -1,4 +1,4 @@ -import {cssSelector} from 'autotests/selectors'; +import {getCssSelector} from 'autotests/selectors'; import type {Selector} from 'e2ed/types'; @@ -8,7 +8,7 @@ const testId = 'TestRunButton'; * `TestRun` button. */ export class TestRunButton { - static readonly parameters: string = cssSelector(testId, 'parameters'); + static readonly parameters: string = getCssSelector(testId, 'parameters'); readonly selector: Selector; diff --git a/autotests/selectors/createSelector.ts b/autotests/selectors/createSelector.ts index 190adcf0..0f5aa8de 100644 --- a/autotests/selectors/createSelector.ts +++ b/autotests/selectors/createSelector.ts @@ -1,20 +1,9 @@ +import {attributesOptions} from 'autotests/constants'; import {createSelectorFunction} from 'e2ed/selectors'; import type {CreateSelector} from 'e2ed/types'; /** - * Main functions for creating selectors and working with selectors. + * Main function for creating selectors and working with selectors. */ -export const createSelector: CreateSelector = createSelectorFunction({ - getLocatorAttributeName: (parameter) => { - if (parameter === 'id') { - return 'data-testid'; - } - - if (parameter === 'runhash') { - return 'data-runhash'; - } - - return `data-test-${parameter}`; - }, -}); +export const createSelector: CreateSelector = createSelectorFunction(attributesOptions); diff --git a/autotests/selectors/index.ts b/autotests/selectors/index.ts index 5fc06703..71822fc5 100644 --- a/autotests/selectors/index.ts +++ b/autotests/selectors/index.ts @@ -1,4 +1,4 @@ export {createSelector} from './createSelector'; export {htmlElementSelector} from './htmlElementSelector'; export {inputSelector} from './inputSelector'; -export {cssSelector, locator, testId} from './locator'; +export {getCssSelector, getTestId, locator} from './locator'; diff --git a/autotests/selectors/locator.ts b/autotests/selectors/locator.ts index a58406aa..562f5b34 100644 --- a/autotests/selectors/locator.ts +++ b/autotests/selectors/locator.ts @@ -1,5 +1,5 @@ import {attributesOptions} from 'autotests/constants'; -import {createTestUtils} from 'e2ed/createLocator'; +import {createTestLocator} from 'e2ed/createLocator'; import {createSelector} from './createSelector'; @@ -7,9 +7,10 @@ import type {LocatorFunction} from 'create-locator'; import type {Selector} from 'e2ed/types'; /** - * Test utils, that produce `Selector`, CSS selector string and `testId` string. + * Locator kit with `locator` function, that produce `Selector`, + * and additional `getSelector` and `getTestId` functions. */ -const utils = createTestUtils({ +const locatorKit = createTestLocator({ attributesOptions, createLocatorByCssSelector: (selector) => createSelector(selector.replace('data-test-runhash', 'data-runhash')), @@ -19,14 +20,14 @@ const utils = createTestUtils({ /** * Locator, that produce `Selector`. */ -export const locator: LocatorFunction = utils.locator; +export const locator: LocatorFunction = locatorKit.locator; /** - * Locator, that produce CSS selector string. + * Get CSS selector string. */ -export const cssSelector: LocatorFunction = utils.selector; +export const getCssSelector: LocatorFunction = locatorKit.getSelector; /** - * Locator, that produce `testId` string. + * Get `testId` string. */ -export const testId: LocatorFunction = utils.testId; +export const getTestId: LocatorFunction = locatorKit.getTestId; diff --git a/autotests/tests/e2edReportExample/selectorCustomMethods.ts b/autotests/tests/e2edReportExample/selectorCustomMethods.ts index bd29d115..40c4e43b 100644 --- a/autotests/tests/e2edReportExample/selectorCustomMethods.ts +++ b/autotests/tests/e2edReportExample/selectorCustomMethods.ts @@ -54,7 +54,7 @@ test('selector custom methods', {meta: {testId: '15'}}, async () => { reportPage.navigationRetriesButtonSelected.getDescription(), 'selector has apropriate description', ).eql( - '[data-testid="RetriesButtons"].findByLocatorId(RetryButton).filterByLocatorParameter(selected, true)', + '[data-testid="RetriesButtons"].findByTestId(RetryButton).filterByLocatorParameter(selected, true)', ); await click(reportPage.navigationRetriesButton.nth(0)); diff --git a/autotests/tests/internalTypeTests/selectors.skip.ts b/autotests/tests/internalTypeTests/selectors.skip.ts index a0a98762..6df051fd 100644 --- a/autotests/tests/internalTypeTests/selectors.skip.ts +++ b/autotests/tests/internalTypeTests/selectors.skip.ts @@ -3,29 +3,29 @@ import {createSelector, htmlElementSelector, locator} from 'autotests/selectors' import type {Selector} from 'e2ed/types'; // @ts-expect-error: wrong number of arguments -htmlElementSelector.findByLocatorId(); +htmlElementSelector.findByTestId(); // @ts-expect-error: wrong type of arguments -htmlElementSelector.findByLocatorId(0); +htmlElementSelector.findByTestId(0); // ok -htmlElementSelector.findByLocatorId('id') satisfies Selector; +htmlElementSelector.findByTestId('id') satisfies Selector; // ok -htmlElementSelector.findByLocatorId('id').findByLocatorId('id2') satisfies Selector; +htmlElementSelector.findByTestId('id').findByTestId('id2') satisfies Selector; // ok -htmlElementSelector.findByLocatorId('id').find('.test-children') satisfies Selector; +htmlElementSelector.findByTestId('id').find('.test-children') satisfies Selector; // ok -htmlElementSelector.find('body').findByLocatorId('id') satisfies Selector; +htmlElementSelector.find('body').findByTestId('id') satisfies Selector; // ok -createSelector('id').findByLocatorId('id').find('body').findByLocatorId('id') satisfies Selector; +createSelector('id').findByTestId('id').find('body').findByTestId('id') satisfies Selector; // ok -locator('id').findByLocatorId('id').find('body').findByLocatorId('id') satisfies Selector; +locator('id').findByTestId('id').find('body').findByTestId('id') satisfies Selector; // @ts-expect-error: wrong number of arguments locator(); // ok -htmlElementSelector.filterByLocatorId('id') satisfies Selector; +htmlElementSelector.filterByTestId('id') satisfies Selector; // ok htmlElementSelector.filterByLocatorParameter('prop', 'value') satisfies Selector; @@ -33,16 +33,16 @@ htmlElementSelector.filterByLocatorParameter('prop', 'value') satisfies Selector htmlElementSelector.findByLocatorParameter('prop', 'value') satisfies Selector; // ok -void htmlElementSelector.getLocatorId(); +void htmlElementSelector.getTestId(); // @ts-expect-error: wrong number of arguments -void htmlElementSelector.getLocatorId('id'); +void htmlElementSelector.getTestId('id'); // @ts-expect-error: TODO: should be ok -void htmlElementSelector.hasLocatorId() satisfies Promise; +void htmlElementSelector.hasTestId() satisfies Promise; // @ts-expect-error: wrong number of arguments -void htmlElementSelector.hasLocatorId('id'); +void htmlElementSelector.hasTestId('id'); // @ts-expect-error: wrong number of arguments void htmlElementSelector.hasLocatorParameter(); diff --git a/package-lock.json b/package-lock.json index 5be6621e..69608303 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@playwright/test": "1.49.1", - "create-locator": "0.0.25", + "create-locator": "0.0.27", "get-modules-graph": "0.0.11", "globby": "11.1.0" }, @@ -21,7 +21,7 @@ }, "devDependencies": { "@playwright/browser-chromium": "1.49.1", - "@types/node": "22.10.2", + "@types/node": "22.10.5", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "assert-modules-support-case-insensitive-fs": "1.0.1", @@ -34,7 +34,7 @@ "eslint-plugin-typescript-sort-keys": "3.3.0", "husky": "9.1.7", "prettier": "3.4.2", - "typescript": "5.7.2" + "typescript": "5.7.3" }, "engines": { "node": ">=20.16.0" @@ -228,9 +228,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", - "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "dev": true, "license": "MIT", "dependencies": { @@ -745,9 +745,9 @@ "dev": true }, "node_modules/create-locator": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/create-locator/-/create-locator-0.0.25.tgz", - "integrity": "sha512-61QqonzNO46no75YwhCtL3E2C0Br2sGW0d2HY1Yrx8obBtmySdmW94cahN7YrJO3XTuxN4aiwl7iGUDwjfFHAw==", + "version": "0.0.27", + "resolved": "https://registry.npmjs.org/create-locator/-/create-locator-0.0.27.tgz", + "integrity": "sha512-kBF8t5J2H1gqbgpvZWRYLvDjcQr4ofrYXdS19EKapD2W040JYZmxG13t4mZChWdCYqKifcobYSS8pXCTK9BwFw==", "license": "MIT" }, "node_modules/cross-spawn": { @@ -3306,9 +3306,9 @@ } }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 1635a045..0adf74b8 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ }, "dependencies": { "@playwright/test": "1.49.1", - "create-locator": "0.0.25", + "create-locator": "0.0.27", "get-modules-graph": "0.0.11", "globby": "11.1.0" }, "devDependencies": { "@playwright/browser-chromium": "1.49.1", - "@types/node": "22.10.2", + "@types/node": "22.10.5", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "assert-modules-support-case-insensitive-fs": "1.0.1", @@ -45,7 +45,7 @@ "eslint-plugin-typescript-sort-keys": "3.3.0", "husky": "9.1.7", "prettier": "3.4.2", - "typescript": "5.7.2" + "typescript": "5.7.3" }, "peerDependencies": { "@types/node": ">=20", diff --git a/src/constants/attributesOptions.ts b/src/constants/attributesOptions.ts index 030798c1..0a965f33 100644 --- a/src/constants/attributesOptions.ts +++ b/src/constants/attributesOptions.ts @@ -4,8 +4,8 @@ import type {AttributesOptions} from 'create-locator'; * Attributes options for locators. * @internal */ -export const attributesOptions = { +export const attributesOptions: AttributesOptions = { parameterAttributePrefix: 'data-test-', testIdAttribute: 'data-testid', testIdSeparator: '-', -} as const satisfies AttributesOptions; +}; diff --git a/src/createLocator.ts b/src/createLocator.ts index 18e39306..be4792d7 100644 --- a/src/createLocator.ts +++ b/src/createLocator.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line no-restricted-syntax export * from 'create-locator'; // eslint-disable-next-line import/no-internal-modules -export {createTestUtils} from 'create-locator/createTestUtils'; +export {createTestLocator} from 'create-locator/createTestLocator'; export type {PARAMETERS} from 'create-locator/oldTypes'; // eslint-disable-next-line import/no-internal-modules export {getCssSelectorFromAttributesChain} from 'create-locator/getCssSelectorFromAttributesChain'; diff --git a/src/selectors/createSelectorFunction.ts b/src/selectors/createSelectorFunction.ts index 4e94dcae..af0aa789 100644 --- a/src/selectors/createSelectorFunction.ts +++ b/src/selectors/createSelectorFunction.ts @@ -1,19 +1,25 @@ -import {setCustomInspectOnFunction} from '../utils/fn'; +import {DESCRIPTION_KEY} from '../constants/internal'; import {generalLog} from '../utils/generalLog'; -import {createSelectorCreator} from '../utils/selectors'; +import {createCustomMethods, createGetTrap, Selector as SelectorClass} from '../utils/selectors'; +import {setReadonlyProperty} from '../utils/setReadonlyProperty'; -import type {CreateSelector, CreateSelectorFunctionOptions} from '../types/internal'; +import type {CreateSelector, CreateSelectorFunctionOptions, Selector} from '../types/internal'; /** * Creates `createSelector` function. */ -export const createSelectorFunction = ({ - getLocatorAttributeName, -}: CreateSelectorFunctionOptions): CreateSelector => { - setCustomInspectOnFunction(getLocatorAttributeName); - generalLog('Create selector functions', {getLocatorAttributeName}); +export const createSelectorFunction = ( + attributesOptions: CreateSelectorFunctionOptions, +): CreateSelector => { + generalLog('Create selector function', {attributesOptions}); - const createSelector = createSelectorCreator(getLocatorAttributeName); + const customMethods = createCustomMethods(attributesOptions); - return createSelector; + return (locator) => { + const selector = new SelectorClass(locator) as unknown as Selector; + + setReadonlyProperty(selector, DESCRIPTION_KEY, locator); + + return new Proxy(selector, {get: createGetTrap(customMethods)}); + }; }; diff --git a/src/types/index.ts b/src/types/index.ts index 8582d665..33a744e3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -47,7 +47,12 @@ export type { PageClassType, PageClassTypeArgs, } from './pages'; -export type {FilePathFromRoot, TestFilePath} from './paths'; +export type { + AbsolutePathToDirectory, + DirectoryPathFromRoot, + FilePathFromRoot, + TestFilePath, +} from './paths'; export type {AsyncVoid, MaybePromise, Thenable} from './promise'; export type { AnyObject, @@ -63,12 +68,7 @@ export type { WebSocketRouteClassType, WebSocketRouteClassTypeWithGetParamsFromUrl, } from './routes'; -export type { - CreateSelector, - CreateSelectorFunctionOptions, - GetLocatorAttributeNameFn, - Selector, -} from './selectors'; +export type {CreateSelector, CreateSelectorFunctionOptions, Selector} from './selectors'; export type {StackFrame} from './stackTrace'; export type {PackageInfo, StartInfo} from './startInfo'; export type {StringForLogs} from './string'; diff --git a/src/types/internal.ts b/src/types/internal.ts index 9b3cf3d7..5c43290d 100644 --- a/src/types/internal.ts +++ b/src/types/internal.ts @@ -121,7 +121,6 @@ export type {RawRunLabelObject} from './runLabel'; export type { CreateSelector, CreateSelectorFunctionOptions, - GetLocatorAttributeNameFn, Selector, SelectorCustomMethods, } from './selectors'; diff --git a/src/types/selectors.ts b/src/types/selectors.ts index ec45f74f..537fe873 100644 --- a/src/types/selectors.ts +++ b/src/types/selectors.ts @@ -1,4 +1,5 @@ import type {DESCRIPTION_KEY} from '../constants/internal'; +import type {AttributesOptions} from '../createLocator'; // eslint-disable-next-line import/no-internal-modules import type {Selector as SelectorClass} from '../utils/selectors/Selector'; @@ -44,14 +45,7 @@ type ReplaceObjectSelectors = Readonly<{ /** * Options of `createSelectorFunction` function. */ -export type CreateSelectorFunctionOptions = Readonly<{ - getLocatorAttributeName: GetLocatorAttributeNameFn; -}>; - -/** - * Type of `getLocatorAttributeName` function. - */ -export type GetLocatorAttributeNameFn = (this: void, parameter: string) => string; +export type CreateSelectorFunctionOptions = AttributesOptions; /** * Creates selector by locator and optional parameters. @@ -69,9 +63,6 @@ export type Selector = ReplaceObjectSelectors & * Custom methods that `e2ed` adds to selector. */ export type SelectorCustomMethods = Readonly<{ - /** Creates a selector that filters a matching set by locatorId. */ - filterByLocatorId: (this: SelectorClass, locatorId: string) => SelectorClass; - /** Creates a selector that filters a matching set by locator parameter. */ filterByLocatorParameter: ( this: SelectorClass, @@ -79,26 +70,29 @@ export type SelectorCustomMethods = Readonly<{ value: string, ) => SelectorClass; - /** Finds all descendants of all nodes in the matching set and filters them by locatorId. */ - findByLocatorId: (this: SelectorClass, locatorId: string) => SelectorClass; + /** Creates a selector that filters a matching set by testId. */ + filterByTestId: (this: SelectorClass, testId: string) => SelectorClass; /** Finds all descendants of all nodes in the matching set and filters them by locator parameter. */ findByLocatorParameter: (this: SelectorClass, parameter: string, value: string) => SelectorClass; + /** Finds all descendants of all nodes in the matching set and filters them by testId. */ + findByTestId: (this: SelectorClass, testId: string) => SelectorClass; + /** Get string description of selector if any. */ getDescription: (this: SelectorClass) => string | undefined; - /** Returns the value of the locator id. */ - getLocatorId: (this: SelectorClass) => Promise; - /** Returns the value of the locator parameter. */ getLocatorParameter: (this: SelectorClass, parameter: string) => Promise; - /** true if the element has the locator id. */ - hasLocatorId: (this: SelectorClass) => Promise; + /** Returns the value of the test id. */ + getTestId: (this: SelectorClass) => Promise; /** true if the element has the locator parameter. */ hasLocatorParameter: (this: SelectorClass, parameter: string) => Promise; + + /** true if the element has the test id. */ + hasTestId: (this: SelectorClass) => Promise; }>; /** diff --git a/src/utils/events/registerEndE2edRunEvent.ts b/src/utils/events/registerEndE2edRunEvent.ts index 7da261b8..7bb63def 100644 --- a/src/utils/events/registerEndE2edRunEvent.ts +++ b/src/utils/events/registerEndE2edRunEvent.ts @@ -9,7 +9,7 @@ import {getReports} from './getReports'; import {runAfterPackFunctions} from './runAfterPackFunctions'; import {writeReports} from './writeReports'; -import type {LiteReport, ReportData} from '../../types/internal'; +import type {LiteReport, ReportData, UtcTimeInMs} from '../../types/internal'; let isEndAlreadyCalled = false; @@ -56,6 +56,11 @@ export const registerEndE2edRunEvent = async (): Promise => { setReadonlyProperty(reportData, 'customReportProperties', customReportProperties); } + const endTimeInMs = Date.now() as UtcTimeInMs; + + setReadonlyProperty(liteReport, 'endTimeInMs', endTimeInMs); + setReadonlyProperty(reportData, 'endTimeInMs', endTimeInMs); + await writeReports({liteReport, reportData}); } catch (error) { generalLog( diff --git a/src/utils/report/client/initialScript.ts b/src/utils/report/client/initialScript.ts index fea9da34..08ea5c9a 100644 --- a/src/utils/report/client/initialScript.ts +++ b/src/utils/report/client/initialScript.ts @@ -34,7 +34,7 @@ const setReadJsonReportDataObservers = clientSetReadJsonReportDataObservers; * @internal */ export const initialScript = (): void => { - const locatorAttributes = createSimpleLocator(createLocatorOptions); + const {locator: locatorAttributes} = createSimpleLocator(createLocatorOptions); locator = (...args): SafeHtml => renderAttributes(locatorAttributes(...(args as [string]))); diff --git a/src/utils/report/render/locator.ts b/src/utils/report/render/locator.ts index 95591904..96c3272c 100644 --- a/src/utils/report/render/locator.ts +++ b/src/utils/report/render/locator.ts @@ -10,7 +10,7 @@ const isProduction = e2edEnvironment.E2ED_ORIGIN !== 'https://google.com'; const createLocatorOptions: CreateLocatorOptions = {attributesOptions, isProduction}; -const locatorAttributes = createSimpleLocator(createLocatorOptions); +const {locator: locatorAttributes} = createSimpleLocator(createLocatorOptions); export {createLocatorOptions}; diff --git a/src/utils/selectors/createCustomMethods.ts b/src/utils/selectors/createCustomMethods.ts index cff42316..f5a264e8 100644 --- a/src/utils/selectors/createCustomMethods.ts +++ b/src/utils/selectors/createCustomMethods.ts @@ -1,57 +1,49 @@ +import {getAttributeCssSelector} from './getAttributeCssSelector'; import {getDescriptionFromSelector} from './getDescriptionFromSelector'; -import type { - GetLocatorAttributeNameFn, - Selector, - SelectorCustomMethods, -} from '../../types/internal'; +import type {AttributesOptions} from '../../createLocator'; +import type {Selector, SelectorCustomMethods} from '../../types/internal'; /** * Creates custom `e2ed` methods of selector (additional to selector's own methods). * @internal */ -export const createCustomMethods = ( - getLocatorAttributeName: GetLocatorAttributeNameFn, -): SelectorCustomMethods => { - const getName: GetLocatorAttributeNameFn = (parameter) => - getLocatorAttributeName(parameter).toLowerCase(); - - const locatorIdAttributeName = getName('id'); +export const createCustomMethods = ({ + parameterAttributePrefix, + testIdAttribute, +}: AttributesOptions): SelectorCustomMethods => { + const getParameterAttribute = (parameter: string): string => parameterAttributePrefix + parameter; return { - /* eslint-disable sort-keys */ - - filterByLocatorId(locatorId) { - return this.filter(`[${locatorIdAttributeName}="${locatorId}"]`); + filterByLocatorParameter(parameter, value) { + return this.filter(getAttributeCssSelector(getParameterAttribute(parameter), value)); }, - findByLocatorId(locatorId) { - return this.find(`[${locatorIdAttributeName}="${locatorId}"]`); + filterByTestId(testId) { + return this.filter(getAttributeCssSelector(testIdAttribute, testId)); }, - filterByLocatorParameter(parameter, value) { - return this.filter(`[${getName(parameter)}="${value}"]`); - }, findByLocatorParameter(parameter, value) { - return this.find(`[${getName(parameter)}="${value}"]`); + return this.find(getAttributeCssSelector(getParameterAttribute(parameter), value)); }, - - getLocatorId() { - return this.getAttribute(locatorIdAttributeName); + findByTestId(testId) { + return this.find(getAttributeCssSelector(testIdAttribute, testId)); }, - hasLocatorId() { - return this.hasAttribute(locatorIdAttributeName); + + getDescription(): string | undefined { + return getDescriptionFromSelector(this as unknown as Selector); }, getLocatorParameter(parameter) { - return this.getAttribute(getName(parameter)); + return this.getAttribute(getParameterAttribute(parameter)); }, - hasLocatorParameter(parameter) { - return this.hasAttribute(getName(parameter)); + getTestId() { + return this.getAttribute(testIdAttribute); }, - getDescription(): string | undefined { - return getDescriptionFromSelector(this as unknown as Selector); + hasLocatorParameter(parameter) { + return this.hasAttribute(getParameterAttribute(parameter)); + }, + hasTestId() { + return this.hasAttribute(testIdAttribute); }, - - /* eslint-enable sort-keys */ }; }; diff --git a/src/utils/selectors/createSelectorCreator.ts b/src/utils/selectors/createSelectorCreator.ts deleted file mode 100644 index fa5a1295..00000000 --- a/src/utils/selectors/createSelectorCreator.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {DESCRIPTION_KEY} from '../../constants/internal'; - -import {setReadonlyProperty} from '../setReadonlyProperty'; - -import {createCustomMethods} from './createCustomMethods'; -import {createGetTrap} from './createGetTrap'; -import {Selector as SelectorClass} from './Selector'; - -import type {CreateSelector, GetLocatorAttributeNameFn, Selector} from '../../types/internal'; - -/** - * Creates `createSelector` function. - * @internal - */ -export const createSelectorCreator = ( - getLocatorAttributeName: GetLocatorAttributeNameFn, -): CreateSelector => { - const customMethods = createCustomMethods(getLocatorAttributeName); - - const createSelector: CreateSelector = (locator) => { - const selector = new SelectorClass(locator) as unknown as Selector; - - setReadonlyProperty(selector, DESCRIPTION_KEY, locator); - - return new Proxy(selector, {get: createGetTrap(customMethods)}); - }; - - return createSelector; -}; diff --git a/src/utils/selectors/getAttributeCssSelector.ts b/src/utils/selectors/getAttributeCssSelector.ts new file mode 100644 index 00000000..78681f58 --- /dev/null +++ b/src/utils/selectors/getAttributeCssSelector.ts @@ -0,0 +1,6 @@ +/** + * Get CSS selector string for attribute by attribute name and value. + * @internal + */ +export const getAttributeCssSelector = (name: string, value: string): string => + `[${name}="${value}"]`; diff --git a/src/utils/selectors/index.ts b/src/utils/selectors/index.ts index 302c6237..fe961585 100644 --- a/src/utils/selectors/index.ts +++ b/src/utils/selectors/index.ts @@ -1,4 +1,6 @@ /** @internal */ -export {createSelectorCreator} from './createSelectorCreator'; +export {createCustomMethods} from './createCustomMethods'; +/** @internal */ +export {createGetTrap} from './createGetTrap'; export {getDescriptionFromSelector} from './getDescriptionFromSelector'; export {Selector} from './Selector';