From 1b7448b073c3ef8453bba167c2a923ff4dc4b25f Mon Sep 17 00:00:00 2001 From: shadowusr Date: Mon, 10 Mar 2025 19:07:33 +0300 Subject: [PATCH 1/4] docs: add custom commands guide --- .../_prepare-browser-add-browser-command.mdx | 25 ---- .../_prepare-browser-overwrite-command.mdx | 22 ---- docs/config/prepare-browser.mdx | 60 ++++----- docs/guides/custom-commands.mdx | 115 ++++++++++++++++++ .../current/config/prepare-browser.mdx | 58 ++++----- .../current/guides/custom-commands.mdx | 115 ++++++++++++++++++ src/scss/custom.scss | 5 + 7 files changed, 284 insertions(+), 116 deletions(-) delete mode 100644 docs/config/_partials/examples/_prepare-browser-add-browser-command.mdx delete mode 100644 docs/config/_partials/examples/_prepare-browser-overwrite-command.mdx create mode 100644 docs/guides/custom-commands.mdx create mode 100644 i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx diff --git a/docs/config/_partials/examples/_prepare-browser-add-browser-command.mdx b/docs/config/_partials/examples/_prepare-browser-add-browser-command.mdx deleted file mode 100644 index 4fb72ce..0000000 --- a/docs/config/_partials/examples/_prepare-browser-add-browser-command.mdx +++ /dev/null @@ -1,25 +0,0 @@ -```typescript title="testplane.config.ts" -import type { ConfigInput } from "testplane"; -import querystring from "querystring"; - -function toStoryKind(value) { - /* here goes some code */ -} -function toStoryId(value) { - /* here goes some code */ -} - -export default { - // ... - prepareBrowser: function (browser) { - browser.addCommand("openScenario", function openScenario(rawComponent, rawStory, params) { - const component = toStoryKind(rawComponent); - const story = toStoryId(rawStory); - const queryParams = querystring.stringify(params); - const url = `/storybook/iframe.html?id=components-${component}-testplane--${story}&${queryParams}`; - - return this.url(url); - }); - }, -} satisfies ConfigInput; -``` diff --git a/docs/config/_partials/examples/_prepare-browser-overwrite-command.mdx b/docs/config/_partials/examples/_prepare-browser-overwrite-command.mdx deleted file mode 100644 index 8c310d0..0000000 --- a/docs/config/_partials/examples/_prepare-browser-overwrite-command.mdx +++ /dev/null @@ -1,22 +0,0 @@ -```typescript title="testplane.config.ts" -import type { ConfigInput } from "testplane"; - -export default { - // ... - prepareBrowser: function (browser) { - browser.overwriteCommand("url", function (origUrlFunction, uri, query) { - if (!query) { - return origUrlFunction(uri); - } - - const parsedUrl = new URL(uri); - - for (const [key, value] of Object.entries(query)) { - parsedUrl.searchParams.set(key, value); - } - - return origUrlFunction(parsedUrl.href); - }); - }, -} satisfies ConfigInput; -``` diff --git a/docs/config/prepare-browser.mdx b/docs/config/prepare-browser.mdx index d589db8..4f30fea 100644 --- a/docs/config/prepare-browser.mdx +++ b/docs/config/prepare-browser.mdx @@ -1,7 +1,4 @@ import Admonition from "@theme/Admonition"; -import AddBrowserCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-add-browser-command.mdx"; -import AddElementCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-add-element-command.mdx"; -import OverwriteCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-overwrite-command.mdx"; import AddMultipleCommandsExample from "@site/docs/config/_partials/examples/_prepare-browser-add-multiple-commands.mdx"; # prepareBrowser @@ -10,44 +7,37 @@ import AddMultipleCommandsExample from "@site/docs/config/_partials/examples/_pr This parameter is a hook. The function specified for this parameter will be automatically called before running tests in the browser. The function receives a reference to the browser session as an argument. -Typically, new commands are added to the browser or the behavior of existing commands is extended within this function. +The `prepareBrowser` hook is a perfect place to set up all of your custom commands or overwrite existing ones. -## Usage Examples {#example} - -### Example 1: Adding a new command to the browser {#example_add_new_command_to_browser} - -To add a new command, use the [browser.addCommand()][add-command] function. - - - -### Example 2: Adding a new command to an element {#example_2_add_new_command_to_element} - -You can add a command not to the browser, but to an element. In this case, the third argument of the [browser.addCommand()][add-command] function should be set to `true`. - - - If a command is added to an element, not to the browser, the function is executed in the context - of the element! + + Read more about custom commands in [our guide](../guides/custom-commands.mdx). - - -Inside the function, the commands [getLocation()][get-location] and [getSize()][get-size], which are available for the element, are used. - -After adding the `getCoords()` command, it can be used in tests as follows: +## Usage Examples {#example} -```typescript -const { left, top, right, bottom } = await browser.$(".selector").getCoords(); +### Adding new browser commands or overwriting existing browser commands + +This is how you can add or overwrite browser commands: + +```typescript title="testplane.config.ts" +import type { ConfigInput } from "testplane"; +import { openScenario, customUrl } from "./testplane/browser-commands"; +import { getCoords } from "./testplane/element-commands"; + +export default { + // ... + prepareBrowser: function (browser) { + // Browser commands + browser.addCommand("openScenario", openScenario); + // Element commands + browser.addCommand("getCoords", getCoords, true); + // Browser command overwrites + browser.overwriteCommand("url", customUrl); + }, +} satisfies ConfigInput; ``` -### Example 3: Overwriting an existing command {#example_3_overwrite_command} - -To change an existing command, use the [browser.overwriteCommand()][overwrite-command] command. - -For example, we might want to pass an object with query parameters as a separate argument to the [browser.url()][url] command: - - - -### Example 4: Adding a set of commands from a folder {#example_4_add_commands_from_folder} +### Adding a set of commands from a folder If the project has many specific commands, it is convenient to store them in a separate folder, and add all commands at once in a unified manner in `prepareBrowser`. For example: diff --git a/docs/guides/custom-commands.mdx b/docs/guides/custom-commands.mdx new file mode 100644 index 0000000..d930ff6 --- /dev/null +++ b/docs/guides/custom-commands.mdx @@ -0,0 +1,115 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import Admonition from "@theme/Admonition"; +import AddElementCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-add-element-command.mdx"; + +# Custom Commands + +Testplane allows you to enhance your test suites by adding custom commands. These commands can streamline repetitive tasks, encapsulate complex actions, and improve code readability. + + + +- How to add custom commands to the browser object. +- How to add custom commands to elements. +- Ways to overwrite existing commands. +- Make custom commands work in a TypeScript environment. + + + +## Adding Custom Commands to the Browser Object + + + A good place to add all of your custom commands is + [`prepareBrowser`](../config/prepare-browser.mdx) hook. + + +To add a custom command to the `browser` object, use the `addCommand` method. Here's how you can define a command that retrieves both the URL and title of the current page: + +```typescript +browser.addCommand("getUrlAndTitle", async function () { + return { + url: await this.getUrl(), + title: await this.getTitle(), + }; +}); +``` + +You can then use this custom command in your tests: + +```typescript +it("should fetch URL and title", async function () { + const result = await browser.getUrlAndTitle(); + console.log(result); // { url: 'https://example.com', title: 'Example Domain' } +}); +``` + +## Adding Custom Commands to Elements + +Custom commands can also be added to element instances. For instance, to create a command that gets element position: + + + +Note the last, third parameter is set to `true` — it means that this command should be added to element instances. + +## Overwriting Existing Commands + +There might be scenarios where you need to modify the behavior of existing commands. Testplane allows you to overwrite these commands using the `overwriteCommand` method. For example, to add logging to the `click` command: + +```typescript +browser.overwriteCommand("click", async function (this: WebdriverIO.Element, origClick, options) { + console.log("Element clicked:", this.selector); + await origClick(options); +}); +``` + +In this example, before executing the original `click` function, a message is logged to the console. + +## Using Custom Commands with TypeScript + +To ensure TypeScript recognizes your custom commands, you need to augment the WebdriverIO types. To do that, follow these simple steps: + +1. Create a `custom-commands.d.ts` file in your project. + +2. Make sure TypeScript compiler "sees" this file during build: you might need to include it in your `tsconfig.json`. + +3. Write your type definitions as follows. Note that there are two file contexts in TypeScript: module and ambient. If you have at least one import/export in your file, the file is in "module" mode, otherwise it's in ambient. Choose declaration style accordingly. + + + + + ```typescript + import 'webdriverio'; // Can be any import, not necessarily webdriverio + + declare global { + declare namespace WebdriverIO { + interface Browser { + customCommand: (arg: any) => Promise + } + + interface Element { + elementCustomCommand: (arg: any) => Promise + } + } + } + ``` + + + + + ```typescript + declare namespace WebdriverIO { + interface Browser { + customCommand: (arg: any) => Promise + } + + interface Element { + elementCustomCommand: (arg: any) => Promise + } + } + ``` + + + + + +This declaration extends the `Browser` and `Element` interfaces to include your custom commands, allowing TypeScript to recognize them without errors. diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/config/prepare-browser.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/config/prepare-browser.mdx index 1e059d9..270d36c 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/config/prepare-browser.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/config/prepare-browser.mdx @@ -1,7 +1,4 @@ import Admonition from "@theme/Admonition"; -import AddBrowserCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-add-browser-command.mdx"; -import AddElementCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-add-element-command.mdx"; -import OverwriteCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-overwrite-command.mdx"; import AddMultipleCommandsExample from "@site/docs/config/_partials/examples/_prepare-browser-add-multiple-commands.mdx"; # prepareBrowser @@ -12,42 +9,35 @@ import AddMultipleCommandsExample from "@site/docs/config/_partials/examples/_pr Обычно внутри данной функции к браузеру добавляют новые команды, или расширяют поведение уже существующих команд. -## Примеры использования {#example} - -### Пример 1: добавляем новую команду для браузера {#example_add_new_command_to_browser} - -Для добавления новой команды воспользуемся функцией [browser.addCommand()][add-command]. - - - -### Пример 2: добавляем новую команду для элемента {#example_2_add_new_command_to_element} - -Можно добавить команду не для браузера, а для элемента. Тогда третьим аргументом функции [browser.addCommand()][add-command] надо указать `true`. - - - Если добавляется команда для элемента, а не для браузера, то функция выполняется в контексте - элемента! + + Узнайте больше о кастомных командах в [нашем рецепте](../guides/custom-commands.mdx). - - -Внутри функции применяются команды [getLocation()][get-location] и [getSize()][get-size], которые доступны для элемента. - -После добавления команды `getCoords()`, её можно использовать в тестах следующим образом: +## Примеры использования {#example} -```typescript -const { left, top, right, bottom } = await browser.$(‘.selector’).getCoords(); +### Добавление новых команд и перезапись существующих команд браузера + +Так вы можете добавлять и перезаписывать браузерные команды: + +```typescript title="testplane.config.ts" +import type { ConfigInput } from "testplane"; +import { openScenario, customUrl } from "./testplane/browser-commands"; +import { getCoords } from "./testplane/element-commands"; + +export default { + // ... + prepareBrowser: function (browser) { + // Browser commands + browser.addCommand("openScenario", openScenario); + // Element commands + browser.addCommand("getCoords", getCoords, true); + // Browser command overwrites + browser.overwriteCommand("url", customUrl); + }, +} satisfies ConfigInput; ``` -### Пример 3: меняем уже существующую команду {#example_3_overwrite_command} - -Чтобы изменить уже существующую команду, воспользуемся командой [browser.overwriteCommand()][overwrite-command]. - -Например, мы можем захотеть передавать в команду [browser.url()][url] отдельным аргументом объект с query-параметрами: - - - -### Пример 4: добавляем набор команд из папки {#example_4_add_commands_from_folder} +### Добавление набора команд из папки Если в проекте много своих специфических команд, то их удобно хранить в отдельной папке, а в `prepareBrowser` добавлять все команды сразу унифицированным образом. Например: diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx new file mode 100644 index 0000000..2a50c5e --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx @@ -0,0 +1,115 @@ +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import Admonition from "@theme/Admonition"; +import AddElementCommandExample from "@site/docs/config/_partials/examples/_prepare-browser-add-element-command.mdx"; + +# Кастомные команды + +Для удобства тестирования Testplane позволяет расширять интерфейс браузера и элементов пользовательскими командами. Эти команды могут упростить повторяющиеся задачи, инкапсулировать сложные действия и повысить читаемость кода. + + + + - Как добавлять пользовательские команды в объект браузера. + - Как добавлять пользовательские команды в элементы. + - Способы переопределения существующих команд. + - Как использовать кастомные команды вместе с TypeScript. + + + +## Добавление пользовательских команд в объект браузера + + + Отличное место для добавления всех ваших пользовательских команд — хук + [`prepareBrowser`](../config/prepare-browser.mdx). + + +Чтобы добавить пользовательскую команду в объект `browser`, используйте метод `addCommand`. Так можно определить команду, которая получает URL и заголовок текущей страницы: + +```typescript +browser.addCommand("getUrlAndTitle", async function () { + return { + url: await this.getUrl(), + title: await this.getTitle(), + }; +}); +``` + +Затем вы можете использовать эту пользовательскую команду в своих тестах: + +```typescript +it("should fetch URL and title", async function () { + const result = await browser.getUrlAndTitle(); + console.log(result); // { url: 'https://example.com', title: 'Example Domain' } +}); +``` + +## Добавление пользовательских команд к элементам + +Пользовательские команды также можно добавлять к экземплярам элементов. Например, для создания команды, которая получает позицию элемента: + + + +Обратите внимание, что третий параметр установлен в `true` — это означает, что команда должна быть добавлена к экземплярам элементов. + +## Переопределение существующих команд + +В некоторых случаях может потребоваться изменить поведение существующих команд. Testplane позволяет переопределять эти команды с помощью метода `overwriteCommand`. Например, так можно добавить логирование к команде `click`: + +```typescript +browser.overwriteCommand("click", async function (this: WebdriverIO.Element, origClick, options) { + console.log("Element clicked:", this.selector); + await origClick(options); +}); +``` + +В этом примере перед выполнением оригинальной функции `click` в консоль выводится сообщение. + +## Использование пользовательских команд с TypeScript + +Чтобы TypeScript распознавал ваши пользовательские команды, необходимо дополнить типы WebdriverIO. Для этого выполните следующие шаги: + +1. Создайте файл `custom-commands.d.ts` в своем проекте. + +2. Убедитесь, что компилятор TypeScript "видит" этот файл во время сборки: возможно, потребуется включить его в `tsconfig.json`. + +3. Определите типы следующим образом. Обратите внимание, что в TypeScript есть два контекста файлов: module и ambient. Если в файле есть хотя бы один `import`/`export`, он находится в "module" режиме, иначе — в ambient. Выберите стиль объявления соответственно. + + + + + ```typescript + import 'webdriverio'; // Может быть любой импорт, не обязательно webdriverio + + declare global { + declare namespace WebdriverIO { + interface Browser { + customCommand: (arg: any) => Promise + } + + interface Element { + elementCustomCommand: (arg: any) => Promise + } + } + } + ``` + + + + + ```typescript + declare namespace WebdriverIO { + interface Browser { + customCommand: (arg: any) => Promise + } + + interface Element { + elementCustomCommand: (arg: any) => Promise + } + } + ``` + + + + + +Это объявление расширяет интерфейсы `Browser` и `Element`, включая ваши пользовательские команды, позволяя TypeScript распознавать их без ошибок. diff --git a/src/scss/custom.scss b/src/scss/custom.scss index d447fb9..d9d08f0 100644 --- a/src/scss/custom.scss +++ b/src/scss/custom.scss @@ -43,6 +43,11 @@ text-decoration: none !important; } } + + ol { + list-style: auto; + padding-left: 30px; + } } @tailwind components; From 08e0096091fb5aae3ecc5057a4a0f1466382c192 Mon Sep 17 00:00:00 2001 From: shadowusr Date: Mon, 10 Mar 2025 19:27:02 +0300 Subject: [PATCH 2/4] fix: fix formatting --- docs/guides/custom-commands.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/custom-commands.mdx b/docs/guides/custom-commands.mdx index d930ff6..acd97a8 100644 --- a/docs/guides/custom-commands.mdx +++ b/docs/guides/custom-commands.mdx @@ -75,7 +75,7 @@ To ensure TypeScript recognizes your custom commands, you need to augment the We 3. Write your type definitions as follows. Note that there are two file contexts in TypeScript: module and ambient. If you have at least one import/export in your file, the file is in "module" mode, otherwise it's in ambient. Choose declaration style accordingly. - + ```typescript import 'webdriverio'; // Can be any import, not necessarily webdriverio From fe2c75d81281eacd95045ca0def1d671e49d702e Mon Sep 17 00:00:00 2001 From: shadowusr Date: Mon, 10 Mar 2025 19:40:50 +0300 Subject: [PATCH 3/4] fix: fix mdx --- docs/guides/custom-commands.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/custom-commands.mdx b/docs/guides/custom-commands.mdx index acd97a8..dcf8050 100644 --- a/docs/guides/custom-commands.mdx +++ b/docs/guides/custom-commands.mdx @@ -74,8 +74,8 @@ To ensure TypeScript recognizes your custom commands, you need to augment the We 3. Write your type definitions as follows. Note that there are two file contexts in TypeScript: module and ambient. If you have at least one import/export in your file, the file is in "module" mode, otherwise it's in ambient. Choose declaration style accordingly. - - + + ```typescript import 'webdriverio'; // Can be any import, not necessarily webdriverio @@ -110,6 +110,6 @@ To ensure TypeScript recognizes your custom commands, you need to augment the We - + This declaration extends the `Browser` and `Element` interfaces to include your custom commands, allowing TypeScript to recognize them without errors. From f7284d53440bf7d8927b06a1b4798b93f4238dd5 Mon Sep 17 00:00:00 2001 From: shadowusr Date: Sun, 16 Mar 2025 23:23:47 +0300 Subject: [PATCH 4/4] fix: add comment about this in custom commands --- docs/guides/custom-commands.mdx | 1 + .../current/guides/custom-commands.mdx | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/guides/custom-commands.mdx b/docs/guides/custom-commands.mdx index dcf8050..7b921c8 100644 --- a/docs/guides/custom-commands.mdx +++ b/docs/guides/custom-commands.mdx @@ -27,6 +27,7 @@ To add a custom command to the `browser` object, use the `addCommand` method. He ```typescript browser.addCommand("getUrlAndTitle", async function () { + // this in the context of custom commands points to browser object return { url: await this.getUrl(), title: await this.getTitle(), diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx index 2a50c5e..e3de96f 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/custom-commands.mdx @@ -27,6 +27,7 @@ import AddElementCommandExample from "@site/docs/config/_partials/examples/_prep ```typescript browser.addCommand("getUrlAndTitle", async function () { + // this в контексте кастомных команд указывает на объект браузера return { url: await this.getUrl(), title: await this.getTitle(),