diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 90e94a80..cd1a5283 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -187,7 +187,7 @@ rules: - {selector: [objectLiteralProperty, typeProperty], format: null, modifiers: [requiresQuotes]} - {selector: [classProperty, typeMethod], filter: '^toJSON$', format: null} '@typescript-eslint/no-import-type-side-effects': error - '@typescript-eslint/no-inferrable-types': error + '@typescript-eslint/no-inferrable-types': off '@typescript-eslint/no-invalid-void-type': [error, {allowInGenericTypeArguments: true, allowAsThisParameter: true}] '@typescript-eslint/no-loop-func': error diff --git a/autotests/configurator/doAfterPack.ts b/autotests/configurator/doAfterPack.ts index 0e414c3f..919cadd3 100644 --- a/autotests/configurator/doAfterPack.ts +++ b/autotests/configurator/doAfterPack.ts @@ -20,7 +20,7 @@ const assertExternalPackRunId: DoAfterPack = ({customReportProperties, endTimeIn * An array of functions that will be run after the pack. * This is an implementation for internal tests. You must remove it from your project. */ -export const doAfterPack = [ +export const doAfterPack: readonly DoAfterPack[] = [ setExternalPackRunId, incrementExternalPackRunId, assertExternalPackRunId, diff --git a/autotests/configurator/doBeforePack.ts b/autotests/configurator/doBeforePack.ts index 7ea256ba..457fc975 100644 --- a/autotests/configurator/doBeforePack.ts +++ b/autotests/configurator/doBeforePack.ts @@ -26,7 +26,7 @@ const assertInternalPackRunId: DoBeforePack = ({fullPackConfig, startTimeInMs}) * An array of functions that will be run before the pack. * This is an implementation for internal tests. You must remove it from your project. */ -export const doBeforePack = [ +export const doBeforePack: readonly DoBeforePack[] = [ setInternalPackRunId, incrementInternalPackRunId, assertInternalPackRunId, diff --git a/autotests/configurator/index.ts b/autotests/configurator/index.ts index 5be1fda1..dbdbcc52 100644 --- a/autotests/configurator/index.ts +++ b/autotests/configurator/index.ts @@ -25,5 +25,6 @@ export type { MapLogPayloadInReport, Pack, SkipTests, + TestFunction, TestMeta, } from './types'; diff --git a/autotests/configurator/types/index.ts b/autotests/configurator/types/index.ts index 8360652d..29aecba9 100644 --- a/autotests/configurator/types/index.ts +++ b/autotests/configurator/types/index.ts @@ -15,6 +15,7 @@ export type { MapLogPayloadInLogFile, MapLogPayloadInReport, Pack, + TestFunction, } from './packSpecific'; export type {SkipTests} from './skipTests'; export type {TestMeta} from './testMeta'; diff --git a/autotests/configurator/types/packSpecific.ts b/autotests/configurator/types/packSpecific.ts index 90c6d6da..c4ccc859 100644 --- a/autotests/configurator/types/packSpecific.ts +++ b/autotests/configurator/types/packSpecific.ts @@ -22,4 +22,5 @@ export type MapBackendResponseToLog = PackSpecificTypes['MapBackendResponseToLog export type MapLogPayloadInConsole = PackSpecificTypes['MapLogPayloadInConsole']; export type MapLogPayloadInLogFile = PackSpecificTypes['MapLogPayloadInLogFile']; export type MapLogPayloadInReport = PackSpecificTypes['MapLogPayloadInReport']; +export type TestFunction = PackSpecificTypes['TestFunction']; export type {Pack}; diff --git a/autotests/constants/attributesOptions.ts b/autotests/constants/attributesOptions.ts index 6fe24a27..d9a4bc49 100644 --- a/autotests/constants/attributesOptions.ts +++ b/autotests/constants/attributesOptions.ts @@ -3,8 +3,8 @@ import type {AttributesOptions} from 'create-locator'; /** * Attributes options for locators. */ -export const attributesOptions = { +export const attributesOptions: AttributesOptions = { parameterAttributePrefix: 'data-test-', testIdAttribute: 'data-testid', testIdSeparator: '-', -} as const satisfies AttributesOptions; +}; diff --git a/autotests/context/pageCookies.ts b/autotests/context/pageCookies.ts index f3edc9e9..768ed736 100644 --- a/autotests/context/pageCookies.ts +++ b/autotests/context/pageCookies.ts @@ -1,8 +1,22 @@ import {useContext} from 'e2ed'; -import type {Cookie} from 'e2ed/types'; +import type {ClearContext, Cookie, GetContext, SetContext} from 'e2ed/types'; + +type Cookies = readonly Cookie[]; + +const [get, set, clear] = useContext(); + +/** + * Get page cookies, that will be added when navigating to the page. + */ +export const getPageCookies: GetContext = get; + +/** + * Set page cookies, that will be added when navigating to the page. + */ +export const setPageCookies: SetContext = set; /** - * Get, set and clear page cookies, that will be added when navigating to the page. + * Clear page cookies, that will be added when navigating to the page. */ -export const [getPageCookies, setPageCookies, clearPageCookies] = useContext(); +export const clearPageCookies: ClearContext = clear; diff --git a/autotests/context/pageRequestHeaders.ts b/autotests/context/pageRequestHeaders.ts index 4216fbd3..bc433cf3 100644 --- a/autotests/context/pageRequestHeaders.ts +++ b/autotests/context/pageRequestHeaders.ts @@ -1,9 +1,20 @@ import {useContext} from 'e2ed'; -import type {Headers} from 'e2ed/types'; +import type {ClearContext, GetContext, Headers, SetContext} from 'e2ed/types'; + +const [get, set, clear] = useContext(); + +/** + * Get additional page request headers, that will be added when navigating to the page. + */ +export const getPageRequestHeaders: GetContext = get; + +/** + * Set additional page request headers, that will be added when navigating to the page. + */ +export const setPageRequestHeaders: SetContext = set; /** - * Get, set and clear additional page request headers, that will be added when navigating to the page. + * Clear additional page request headers, that will be added when navigating to the page. */ -export const [getPageRequestHeaders, setPageRequestHeaders, clearPageRequestHeaders] = - useContext(); +export const clearPageRequestHeaders: ClearContext = clear; diff --git a/autotests/entities/product.ts b/autotests/entities/product.ts index 5ecda081..fc4c5b67 100644 --- a/autotests/entities/product.ts +++ b/autotests/entities/product.ts @@ -1,11 +1,12 @@ import {createClientFunction} from 'e2ed'; import type {ApiProduct, Product} from 'autotests/types'; +import type {ClientFunction} from 'e2ed/types'; /** * Adds product. */ -export const addProduct = createClientFunction( +export const addProduct: ClientFunction<[Product], Promise> = createClientFunction( (product: Product) => fetch(`https://reqres.in/api/product/${product.id}?size=${product.size}`, { body: JSON.stringify({ diff --git a/autotests/entities/worker.ts b/autotests/entities/worker.ts index a8f8cb66..f209b235 100644 --- a/autotests/entities/worker.ts +++ b/autotests/entities/worker.ts @@ -2,6 +2,7 @@ import {createClientFunction} from 'e2ed'; import {log} from 'e2ed/utils'; import type {UserWorker} from 'autotests/types'; +import type {ClientFunction} from 'e2ed/types'; const clientGetUsers = createClientFunction( (delay: number) => @@ -12,13 +13,13 @@ const clientGetUsers = createClientFunction( /** * Adds user-worker. */ -export const addUser = createClientFunction( +export const addUser: ClientFunction<[UserWorker, number?], Promise> = createClientFunction( (user: UserWorker, delay?: number) => fetch(`https://reqres.in/api/users${delay !== undefined ? `?delay=${delay}` : ''}`, { body: JSON.stringify(user), headers: {'Content-Type': 'application/json; charset=UTF-8'}, method: 'POST', - }).then((res) => res.json()), + }), {name: 'addUser', timeout: 3_000}, ); diff --git a/autotests/pageObjects/pages/Main.ts b/autotests/pageObjects/pages/Main.ts index 7ca6588f..3f038c27 100644 --- a/autotests/pageObjects/pages/Main.ts +++ b/autotests/pageObjects/pages/Main.ts @@ -1,9 +1,7 @@ import {Input} from 'autotests/pageObjects/components'; import {Main as MainRoute} from 'autotests/routes/pageRoutes'; -import {createSelectorByCss} from 'autotests/selectors'; -import {createRootLocator, type Locator} from 'create-locator'; +import {createSelector} from 'autotests/selectors'; import {Page} from 'e2ed'; -import {getCssSelectorFromAttributesChain} from 'e2ed/createLocator'; import {setReadonlyProperty} from 'e2ed/utils'; import type {Language} from 'autotests/types'; @@ -12,17 +10,6 @@ import type {GetParamsType, Selector} from 'e2ed/types'; type RouteParams = GetParamsType; type CustomPageParams = Partial | undefined; -type MainLocator = Locator<{header: {}}>; - -const mainPageLocator = createRootLocator('google', { - mapAttributesChain: (attributesChain) => { - const cssSelector = getCssSelectorFromAttributesChain(attributesChain); - - return createSelectorByCss(cssSelector); - }, - pathAttribute: 'data-testid', -}); - /** * The Main (index) page. */ @@ -30,12 +17,12 @@ export class Main extends Page { /** * Body selector. */ - readonly body = createSelectorByCss('body'); + readonly body: Selector = createSelector('body'); /** * Header selector. */ - readonly header = mainPageLocator.header(); + readonly header: Selector = createSelector('[role=navigation]'); /** * Page language. @@ -45,7 +32,7 @@ export class Main extends Page { /** * Search input. */ - readonly searchInput = new Input('q'); + readonly searchInput: Input = new Input('q'); /** * Current value of search query. diff --git a/autotests/selectors/selectorFunctions.ts b/autotests/selectors/createSelector.ts similarity index 63% rename from autotests/selectors/selectorFunctions.ts rename to autotests/selectors/createSelector.ts index 84214049..190adcf0 100644 --- a/autotests/selectors/selectorFunctions.ts +++ b/autotests/selectors/createSelector.ts @@ -1,9 +1,11 @@ -import {createSelectorFunctions} from 'e2ed/selectors'; +import {createSelectorFunction} from 'e2ed/selectors'; + +import type {CreateSelector} from 'e2ed/types'; /** * Main functions for creating selectors and working with selectors. */ -export const {createSelector, createSelectorByCss, htmlElementSelector} = createSelectorFunctions({ +export const createSelector: CreateSelector = createSelectorFunction({ getLocatorAttributeName: (parameter) => { if (parameter === 'id') { return 'data-testid'; diff --git a/autotests/selectors/htmlElementSelector.ts b/autotests/selectors/htmlElementSelector.ts new file mode 100644 index 00000000..dd29bb2a --- /dev/null +++ b/autotests/selectors/htmlElementSelector.ts @@ -0,0 +1,8 @@ +import {createSelector} from './createSelector'; + +import type {Selector} from 'e2ed/types'; + +/** + * Selector of HTML element. + */ +export const htmlElementSelector: Selector = createSelector('html'); diff --git a/autotests/selectors/index.ts b/autotests/selectors/index.ts index 3b2d5f2d..5fc06703 100644 --- a/autotests/selectors/index.ts +++ b/autotests/selectors/index.ts @@ -1,3 +1,4 @@ +export {createSelector} from './createSelector'; +export {htmlElementSelector} from './htmlElementSelector'; export {inputSelector} from './inputSelector'; export {cssSelector, locator, testId} from './locator'; -export {createSelector, createSelectorByCss, htmlElementSelector} from './selectorFunctions'; diff --git a/autotests/selectors/inputSelector.ts b/autotests/selectors/inputSelector.ts index 965de33a..c69718bd 100644 --- a/autotests/selectors/inputSelector.ts +++ b/autotests/selectors/inputSelector.ts @@ -1,8 +1,8 @@ -import {createSelectorByCss} from 'autotests/selectors'; +import {createSelector} from './createSelector'; import type {Selector} from 'e2ed/types'; /** * Selector of input (or textarea) element by name. */ -export const inputSelector = (name: string): Selector => createSelectorByCss(`[name="${name}"]`); +export const inputSelector = (name: string): Selector => createSelector(`[name="${name}"]`); diff --git a/autotests/selectors/locator.ts b/autotests/selectors/locator.ts index cea74432..a58406aa 100644 --- a/autotests/selectors/locator.ts +++ b/autotests/selectors/locator.ts @@ -1,18 +1,32 @@ import {attributesOptions} from 'autotests/constants'; import {createTestUtils} from 'e2ed/createLocator'; -import {createSelectorByCss} from './selectorFunctions'; +import {createSelector} from './createSelector'; + +import type {LocatorFunction} from 'create-locator'; +import type {Selector} from 'e2ed/types'; /** - * Test utils, that produce `Selector`. + * Test utils, that produce `Selector`, CSS selector string and `testId` string. */ -export const { - locator, - selector: cssSelector, - testId, -} = createTestUtils({ +const utils = createTestUtils({ attributesOptions, createLocatorByCssSelector: (selector) => - createSelectorByCss(selector.replace('data-test-runhash', 'data-runhash')), + createSelector(selector.replace('data-test-runhash', 'data-runhash')), supportWildcardsInCssSelectors: true, }); + +/** + * Locator, that produce `Selector`. + */ +export const locator: LocatorFunction = utils.locator; + +/** + * Locator, that produce CSS selector string. + */ +export const cssSelector: LocatorFunction = utils.selector; + +/** + * Locator, that produce `testId` string. + */ +export const testId: LocatorFunction = utils.testId; diff --git a/autotests/test.ts b/autotests/test.ts index 5f816b31..0dd601ec 100644 --- a/autotests/test.ts +++ b/autotests/test.ts @@ -2,10 +2,10 @@ import {createTestFunction} from 'e2ed'; import * as hooks from './hooks'; -import type {Pack} from 'autotests/configurator'; +import type {Pack, TestFunction} from 'autotests/configurator'; /** * Test function that describes the test or the task * (test does not necessarily contain checks). */ -export const test = createTestFunction(hooks); +export const test: TestFunction = createTestFunction(hooks); diff --git a/autotests/tests/expect.ts b/autotests/tests/expect.ts index 98f00157..0c9b366f 100644 --- a/autotests/tests/expect.ts +++ b/autotests/tests/expect.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-magic-numbers */ import {test} from 'autotests'; -import {createSelectorByCss} from 'autotests/selectors'; +import {htmlElementSelector} from 'autotests/selectors'; import {getFullPackConfig} from 'autotests/utils'; import {expect} from 'e2ed'; import {assertFunctionThrows, getTimeoutPromise} from 'e2ed/utils'; @@ -41,8 +41,6 @@ test('expect function works correctly', {meta: {testId: '16'}}, async () => { // eslint-disable-next-line @typescript-eslint/await-thenable await expect(1, 'should be an eslint error when we do not call the assertion method'); - const htmlSelector = createSelectorByCss('html'); - // @ts-expect-error: expect function should not accept a selector as a actual value - await expect(htmlSelector, 'should be type error when actual value is a selector').ok(); + await expect(htmlElementSelector, 'should be type error when actual value is a selector').ok(); }); diff --git a/autotests/tests/internalTypeTests/selectors.skip.ts b/autotests/tests/internalTypeTests/selectors.skip.ts index 99734a16..a0a98762 100644 --- a/autotests/tests/internalTypeTests/selectors.skip.ts +++ b/autotests/tests/internalTypeTests/selectors.skip.ts @@ -1,9 +1,4 @@ -import { - createSelector, - createSelectorByCss, - htmlElementSelector, - locator, -} from 'autotests/selectors'; +import {createSelector, htmlElementSelector, locator} from 'autotests/selectors'; import type {Selector} from 'e2ed/types'; @@ -22,11 +17,7 @@ htmlElementSelector.find('body').findByLocatorId('id') satisfies Selector; // ok createSelector('id').findByLocatorId('id').find('body').findByLocatorId('id') satisfies Selector; -// ok -createSelectorByCss('id') - .findByLocatorId('id') - .find('body') - .findByLocatorId('id') satisfies Selector; + // ok locator('id').findByLocatorId('id').find('body').findByLocatorId('id') satisfies Selector; diff --git a/package-lock.json b/package-lock.json index 3669d9a8..cb121cca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.18.14", "license": "MIT", "dependencies": { - "@playwright/test": "1.47.2", + "@playwright/test": "1.48.1", "create-locator": "0.0.25", "get-modules-graph": "0.0.9", "globby": "11.1.0" @@ -19,8 +19,8 @@ "e2ed-init": "bin/init.js" }, "devDependencies": { - "@playwright/browser-chromium": "1.47.2", - "@types/node": "22.7.4", + "@playwright/browser-chromium": "1.48.1", + "@types/node": "22.7.6", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "assert-modules-support-case-insensitive-fs": "1.0.1", @@ -30,10 +30,10 @@ "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-simple-import-sort": "12.1.1", - "eslint-plugin-typescript-sort-keys": "3.2.0", + "eslint-plugin-typescript-sort-keys": "3.3.0", "husky": "9.1.6", "prettier": "3.3.3", - "typescript": "5.6.2" + "typescript": "5.6.3" }, "engines": { "node": ">=16.11.1" @@ -179,26 +179,26 @@ } }, "node_modules/@playwright/browser-chromium": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.47.2.tgz", - "integrity": "sha512-tsk9bLcGzIu4k4xI2ixlwDrdJhMqCalUCsSj7TRI8VuvK7cLiJIa5SR0dprKbX+wkku/JMR4EN6g9DMHvfna+Q==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@playwright/browser-chromium/-/browser-chromium-1.48.1.tgz", + "integrity": "sha512-WNpIE+CpO4XNhdNTC/mVE8m/1gYR/hPswL8dnIZzElqxsOPm7qxIBdAChWm/7q1kkMiQ+gEGAaXXQfqL0vR28w==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.47.2" + "playwright-core": "1.48.1" }, "engines": { "node": ">=18" } }, "node_modules/@playwright/test": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.2.tgz", - "integrity": "sha512-jTXRsoSPONAs8Za9QEQdyjFn+0ZQFjCiIztAIF6bi1HqhBzG9Ma7g1WotyiGqFSBRZjIEqMdT8RUlbk1QVhzCQ==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz", + "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==", "license": "Apache-2.0", "dependencies": { - "playwright": "1.47.2" + "playwright": "1.48.1" }, "bin": { "playwright": "cli.js" @@ -227,9 +227,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.7.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.4.tgz", - "integrity": "sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==", + "version": "22.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", + "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", "dev": true, "license": "MIT", "dependencies": { @@ -1256,10 +1256,11 @@ } }, "node_modules/eslint-plugin-typescript-sort-keys": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-typescript-sort-keys/-/eslint-plugin-typescript-sort-keys-3.2.0.tgz", - "integrity": "sha512-GutszvriaVtwmn7pQjuj9/9o0iXhD7XZs0/424+zsozdRr/fdg5e8206t478Vnqnqi1GjuxcAolj1kf74KnhPA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-typescript-sort-keys/-/eslint-plugin-typescript-sort-keys-3.3.0.tgz", + "integrity": "sha512-bRW3Rc/VNdrSP9OoY5wgjjaXCOOkZKpzvl/Mk6l8Sg8CMehVIcg9K4y33l+ZcZiknpl0aR6rKusxuCJNGZWmVw==", "dev": true, + "license": "ISC", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "json-schema": "^0.4.0", @@ -1269,7 +1270,7 @@ "node": ">= 16" }, "peerDependencies": { - "@typescript-eslint/parser": "^6 || ^7", + "@typescript-eslint/parser": ">=6", "eslint": "^7 || ^8", "typescript": "^3 || ^4 || ^5" } @@ -2728,12 +2729,12 @@ } }, "node_modules/playwright": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz", - "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz", + "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==", "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.47.2" + "playwright-core": "1.48.1" }, "bin": { "playwright": "cli.js" @@ -2746,9 +2747,9 @@ } }, "node_modules/playwright-core": { - "version": "1.47.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz", - "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz", + "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==", "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" @@ -3299,9 +3300,9 @@ } }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 844b5869..77042d28 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,14 @@ "url": "git+https://github.com/joomcode/e2ed.git" }, "dependencies": { - "@playwright/test": "1.47.2", + "@playwright/test": "1.48.1", "create-locator": "0.0.25", "get-modules-graph": "0.0.9", "globby": "11.1.0" }, "devDependencies": { - "@playwright/browser-chromium": "1.47.2", - "@types/node": "22.7.4", + "@playwright/browser-chromium": "1.48.1", + "@types/node": "22.7.6", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", "assert-modules-support-case-insensitive-fs": "1.0.1", @@ -41,10 +41,10 @@ "eslint-config-prettier": "9.1.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-simple-import-sort": "12.1.1", - "eslint-plugin-typescript-sort-keys": "3.2.0", + "eslint-plugin-typescript-sort-keys": "3.3.0", "husky": "9.1.6", "prettier": "3.3.3", - "typescript": "5.6.2" + "typescript": "5.6.3" }, "peerDependencies": { "@types/node": ">=20", diff --git a/src/ApiRoute.ts b/src/ApiRoute.ts index e677210d..2178a3b1 100644 --- a/src/ApiRoute.ts +++ b/src/ApiRoute.ts @@ -1,23 +1,6 @@ import {Route} from './Route'; -import type { - Method, - Request, - RequestKeyType, - Response, - ResponseKeyType, - Url, -} from './types/internal'; - -/** - * Inner key for request type. - */ -declare const REQUEST_KEY: RequestKeyType; - -/** - * Inner key for response type. - */ -declare const RESPONSE_KEY: ResponseKeyType; +import type {Method, Request, Response, Url} from './types/internal'; /** * Abstract route for API requests. @@ -30,12 +13,14 @@ export abstract class ApiRoute< /** * Request type of API route. */ - declare readonly [REQUEST_KEY]: SomeRequest; + // eslint-disable-next-line @typescript-eslint/naming-convention + declare readonly __REQUEST_KEY: SomeRequest; /** * Response type of API route. */ - declare readonly [RESPONSE_KEY]: SomeResponse; + // eslint-disable-next-line @typescript-eslint/naming-convention + declare readonly __RESPONSE_KEY: SomeResponse; /** * Returns `true`, if the request body is in JSON format. diff --git a/src/Page.ts b/src/Page.ts index 96431674..9c072029 100644 --- a/src/Page.ts +++ b/src/Page.ts @@ -7,12 +7,7 @@ import {reloadDocument} from './utils/document'; import {getPlaywrightPage} from './useContext'; import type {PageRoute} from './PageRoute'; -import type {AsyncVoid, PageClassTypeArgs, ParamsKeyType, Url} from './types/internal'; - -/** - * Inner key for parameters type. - */ -declare const PARAMS_KEY: ParamsKeyType; +import type {AsyncVoid, PageClassTypeArgs, Url} from './types/internal'; /** * Abstract page with base methods. @@ -21,7 +16,8 @@ export abstract class Page { /** * Type of page parameters. */ - declare readonly [PARAMS_KEY]: PageParams; + // eslint-disable-next-line @typescript-eslint/naming-convention + declare readonly __PARAMS_KEY: PageParams; /** * Default maximum interval (in milliseconds) between requests. diff --git a/src/Route.ts b/src/Route.ts index 70f8fcb2..e44c4094 100644 --- a/src/Route.ts +++ b/src/Route.ts @@ -1,8 +1,6 @@ import {SLASHES_AT_THE_END_REGEXP, SLASHES_AT_THE_START_REGEXP} from './constants/internal'; -import type {Method, ParamsKeyType, Url, ZeroOrOneArg} from './types/internal'; - -declare const PARAMS_KEY: ParamsKeyType; +import type {Method, Url, ZeroOrOneArg} from './types/internal'; /** * Abstract route with base methods. @@ -11,7 +9,8 @@ export abstract class Route { /** * Type of route parameters. */ - declare readonly [PARAMS_KEY]: RouteParams; + // eslint-disable-next-line @typescript-eslint/naming-convention + declare readonly __PARAMS_KEY: RouteParams; /** * Immutable route parameters. diff --git a/src/actions/index.ts b/src/actions/index.ts index 8c705213..2c57ce06 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -32,6 +32,7 @@ export {pressKey} from './pressKey'; export {resizeWindow} from './resizeWindow'; export {scroll} from './scroll'; export {scrollIntoView} from './scrollIntoView'; +export {selectOption} from './selectOption'; export {selectText} from './selectText'; export {setCookies} from './setCookies'; export {setFilesToUpload} from './setFilesToUpload'; diff --git a/src/actions/selectOption.ts b/src/actions/selectOption.ts new file mode 100644 index 00000000..918bc360 --- /dev/null +++ b/src/actions/selectOption.ts @@ -0,0 +1,29 @@ +import {LogEventType} from '../constants/internal'; +import {log} from '../utils/log'; +import {getDescriptionFromSelector} from '../utils/selectors'; + +import type {Locator} from '@playwright/test'; + +import type {Selector} from '../types/internal'; + +type Options = Parameters[1]; + +/** + * Selects an `option` in `select` element. + */ +export const selectOption = async ( + selector: Selector, + value: string | readonly string[], + options: Options = {}, +): Promise => { + const description = getDescriptionFromSelector(selector); + const withDescription = description !== undefined ? ` with description ${description}` : ''; + + log( + `Select an option with value "${String(value)}" in