diff --git a/blog/.empty b/blog/.empty deleted file mode 100644 index e69de29..0000000 diff --git a/blog/component-testing.mdx b/blog/component-testing.mdx new file mode 100644 index 0000000..015ad70 --- /dev/null +++ b/blog/component-testing.mdx @@ -0,0 +1,176 @@ +--- +title: Компонентное тестирование +slug: component-testing-intro +hide_table_of_contents: false +date: 2024-06-10T14:00 +--- + +import Admonition from "@theme/Admonition"; + +В testplane в экспериментальном режиме поддержали компонентное тестирование и unit-тесты, выполняющиеся в браузере. + + + +Практически все современные веб-интерфейсы пишутся с использованием фреймворков (React, Vue, Svelte, ...) для упрощения создания и реиспользования компонентов. Такие компоненты важно тестировать в изоляции друг от друга, чтобы быть уверенным, что каждый компонент корректно справляется со своей работой. Точно так же как мы пишем unit-тесты отдельно от интеграционных. В Testplane уже поддержанно скриншотное тестирование компонентов с помощью [Storybook](https://storybook.js.org/), однако этот инструмент актуален не для всех проектов. Поэтому мы разработали ещё один вариант компонентного тестирования, который не требует использования Storybook. + +Данная возможность может быть полезна, если у вас в проекте используются React-компоненты. При этом тестов нет совсем или используются только тяжелые интеграционные тесты (т.е. проверяются целые страницы, содержащие множество компонентов). Согласно [пирамиде тестирования](https://martinfowler.com/articles/practical-test-pyramid.html), интеграционных тестов должно быть меньше всего так как они больше подвержены “флапам” и зачастую избыточны. Множество сценариев можно проверить с помощью компонентых тестов и тем самым сократить время выполнения тестов в CI и улучшить их стабильность. + +### Варианты реализации компонентного тестирования + +Компонентное тестирование — это вид тестирования, при котором логика работы веб-компонента проверяется в изоляции от веб-страницы, в которой он используется. Для того, чтобы выполнить такой тест, нужно уметь корректно рендерить компонент. Часто для этой задачи применяют [JSDom](https://github.com/jsdom/jsdom) (используется в [Jest](https://jestjs.io/)), который рендерит веб-компоненты с помощью виртуального рендеринга Node.js, т.е. без использования реального браузера. С одной стороны, это работает быстрее (браузер не поднимается), а с другой — менее стабильно, так как проверки выполняются не в реальном браузере. Второе популярное решение — это использовать очень быстрый dev-сервер [Vite](https://vitejs.dev/), который поддерживает множество фреймворков (React, Vue, Svelte, ...) и отвечает за рендеринг компонентов в изоляции. + +Мы остановились на варианте с использованием Vite, так как такой подход обеспечивает тестирование страницы более приближенное к реальности (как если бы ее открыл пользователь). При этом, сами тесты выполняются немного дольше, чем в jsdom. Но для нас самое главное стабильность и воспроизводимость результатов тестов, поэтому выбор был очевиден. + +
+ Краткая информация о том, как это реализовано + + - при указании опции `testRunEnv: 'browser'` в конфиге Testplane, будет использован браузерный раннер, который поднимает Vite на localhost с рандомным свободным портом (пользователь может выставить необходимый порт в конфиге Vite). Именно на этом поднятом сервере будут рендерится все пользовательские компоненты и выполняться все необходимые команды/проверки (т.е. прямо внутри браузера); + - затем читаются тесты в Node.js, т.е. как это делается и для интеграционных тестов. Это необходимо, чтобы все плагины работали корректно (речь про триггер событий при чтении тестов), а так же, чтобы была возможность запустить тесты из одного файла параллельно. Если бы тест читался только в контексте браузера, то приходилось бы запускать абсолютно все тесты внутри одного файла и критическое завершение в одном из них приводило бы к остановке всех последующих. Т.е. на данном этапе мы понимаем какие тесты нужно запустить; + - после чего, как обычно, поднимаются необходимые браузеры и в них запускаются тесты. Каждый тест перед выполнением пользовательского кода выполняет переход на поднятый сервер Vite. При выполнении такого запроса генерится специальный index.html, в который подгружаются все необходимые библиотеки: + - mocha — для чтения тестов; + - webdriverio — для использования инстанса браузера внутри самого браузера; + - expect — для выполнения проверок; + - и прочие внутренние модули, необходимые для корректной работы. + - при открытии index.html из Vite, браузер устанавливает websocket-соединение с мастер процессом Testplane для того, чтобы обмениваться необходимыми данными. Например, в случае, если в браузере вызывается конструкция `await browser.$("body").assertView("plain", "body")`, то очевидно, что она выполниться в самом браузере не может, так как внутри `assertView` нам необходим доступ к файловой системе. Поэтому, выполнение этой команды отправляется в мастер Testplane, который в свою очередь отправляет ее worker-у, в котором данный тест запущен. И именно worker выполняет переданную ему команду. Когда результат получен, он таким же образом отправляется назад в браузер. Все общение реализовано с помощью библиотеки [socket.io](https://socket.io/); + - после чего, в браузере начинает выполняться указанный тест, который по завершению возвращает результат в Node.js процесс. + +
+ +### Как использовать? + +Будем настраивать тестирование react-компонентов, написанных на TypeScript. Поэтому, для начала установим необходимые зависимости: + +```bash +npm i testplane vite @vitejs/plugin-react @testing-library/react --save-dev +npm i react --save +``` + +Создаем Vite конфиг, в котором подключим плагин для поддержки React. Пример: + +```javascript +// vite.config.ts +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [react()], +}); +``` + +Теперь настроим запуск тестов в браузере. Для этого укажем опцию [testRunEnv](https://github.com/gemini-testing/testplane/blob/master/docs/config.md#testrunenv). Пример: + +```javascript +// .testplane.conf.ts +export const { + // ... + system: { + // ... + testRunEnv: ['browser', { viteConfig: './vite.config.ts' }], + }, + sets: { + linux: { + files: [ + 'src/tests/**/*.testplane.tsx' + ], + browsers: [ + 'chrome' + ] + }, + }, +} +``` + +После чего можем написать тест, в котором просто выведем значение `document` в консоль без использования команды [browser.execute](/docs/v8/commands/browser/execute): + +```javascript +// src/tests/test.testplane.tsx +it("should log document", async () => { + console.log(document); +}); +``` + +Если бы такой тест выполнялся в окружении Node.js, то он бы упал с ошибкой `ReferenceError: document is not defined`. Но в нашем случае он будет выполнен прямо в браузере, где доступна глобальная переменная `document`. Поэтому, в логе браузера и терминала (про эту возможность расскажем ниже) мы увидим следующее: + +``` +{ + location: { + ancestorOrigins: {}, + href: 'http://localhost:56292/run-uuids/23d2af81-4259-425c-8214-c9e770d75ea4', + origin: 'http://localhost:56292', + protocol: 'http:', + host: 'localhost:56292', + hostname: 'localhost', + port: '56292', + pathname: '/run-uuids/23d2af81-4259-425c-8214-c9e770d75ea4', + search: '', + hash: '' + } +} +``` + +Напишем более сложный тест с рендерингом react компонента: + +```javascript +// src/tests/test.testplane.tsx +import { useState } from "react"; +import { render } from "@testing-library/react"; + +// Простой компонент с тайтлом и кнопкой-счетчиком +function Component() { + const [count, setCount] = useState(0); + + return ( +
+

Testplane Component Testing

+ +
+ ); +} + +it("should render react button", async ({ browser }) => { + render(); // рендерим компонент на сгенеренной странице Vite + + const button = await browser.$("button"); + + await button.click(); + await button.click(); + + await expect(button).toHaveText("count is 2"); +}); +``` + +С полноценно работающими примерами можно ознакомиться [здесь](https://github.com/gemini-testing/testplane/tree/master/examples/component-testing). + + + - поддерживаются только компоненты, написанные на React в файлах `.jsx` и `.tsx`. Поддержка Vue + также есть в планах; - нет доступа к `currentTest` из хуков и теста; - временно не + поддерживается плагин @testplane/global-hook. + + +### Какие дополнительные возможности поддерживаются? + +#### Hot Module Replacement (HMR) + +В Vite поддерживается [HMR](https://vitejs.dev/guide/api-hmr.html). Это означает, что если изменить загруженный файл, то произойдет или ремаунт компонента, или полная перезагрузка страницы. В случае, если компонент описан в отдельном файле (т.е. не в одном файле с тестом), то будет выполнен ремаунт, но тест перезапущен не будет. А если изменить файл с тестом, то произойдет перезагрузка страницы, которая приведет к тому, что Testplane прервет выполнение текущего теста и запустит его заново. За счет такой возможности в Vite можно очень быстро разрабатывать компоненты и писать для них тесты. Рекомендуется использовать вместе с REPL-режимом. + +При изменении исходников компонента не происходит полного перезапуска теста (маунтится по новой только сам компонент). При этом, если изменить код теста, то происходит полный перезапуск. + +#### Использование инстанса browser и expect прямо в DevTools браузера + +В консоли браузера, в котором выполняется тест, доступны инстанс самого `browser` и инстанс `expect`. Это довольно удобно использовать при дебаге теста. + +#### Логи из консоли браузера в терминале + +Вызов команд `log`, `info`, `warn`, `error`, `debug` и `table` на объекте `console` в браузере приводят к тому, что отображается информация не только в DevTools браузера, но также и в терминале, из которого был запущен Testplane. Т.е. можно вызвать `console.log` в тесте/компоненте и затем увидеть результат его выполнения в терминале. Это также довольно удобно при дебаге теста. + +### Заключение + +Данная функциональность предоставляет нашим пользователям новые возможности: + +- изолированное тестирование React-компонентов в реальном браузере; +- стабильность и воспроизводимость результатов тестов в сравнении с JSDom; +- поддержка HMR; +- доступ к инстансам browser/expect в DevTools браузера, для удобного дебага; +- отображение логов в терминале для повышения комфорта и увеличения скорости разработки. + +Переезжайте на Testplane и попробуйте новую возможность самостоятельно. В случае обнаружения проблем, приходите в [issue github](https://github.com/gemini-testing/testplane/issues) — мы вам обязательно поможем! diff --git a/blog/rebranding.mdx b/blog/rebranding.mdx new file mode 100644 index 0000000..3b55ac8 --- /dev/null +++ b/blog/rebranding.mdx @@ -0,0 +1,29 @@ +--- +title: Ребрендинг +slug: testplane-rebranding +hide_table_of_contents: false +date: 2024-05-20T13:00 +--- + +Представляем вашему вниманию... **Testplane**. Наш проект Hermione решил сменить имя — встречайте проверенный годами продукт в свежем образе! + + + +Мы долго рассматривали все за и против и пришли к выводу, что новое имя — Testplane — наилучшим образом отражает наше видение и будущее развитие продукта: + +1. Мы планируем активно вкладываться в развитие инструмента в опенсорсе. Новое имя символизирует качественный переход в развитии инструмента. +2. Мы стремимся создать полноценный бренд с товарным знаком, логотипом, фирменным визуальным стилем. Testplane — это название, которое как сочетает в себе отсылку к «испытательному полету», так и может читаться как "плоскость для тестирования". + +Суть продукта остаётся неизменной. Testplane — это тот же проект, который вы знали многие годы как Hermione, но в свежем, обновленном виде. Чтобы упростить переход, мы решили сохранить сквозную нумерацию версий: Testplane v8.x — это эквивалент Hermione v8.x. + +Если вы уже работаете с Hermione, обновление на Testplane займет всего несколько минут. Мы проектировали его как drop-in замену: + +- Полная поддержка существующих плагинов Hermione. +- Понимание всех опций и переменных окружения Hermione. +- Полная совместимость конфигураций. +- Два бинарных файла (testplane и hermione) для плавного перехода (вы можете запускать и как hermione gui, и как testplane gui). +- Экспорт типов для TypeScript, включая как собственные типы Testplane, так и типы Hermione (включая hermioneCtx). + +Если же вы еще не пробовали Testplane — загляните в нашу документацию и начните ваше исследование с Testplane всего за пару минут! + +Благодарим за интерес к проекту! ✈️ diff --git a/docs/commands/browser/$$.mdx b/docs/commands/browser/$$.mdx new file mode 100644 index 0000000..39d7494 --- /dev/null +++ b/docs/commands/browser/$$.mdx @@ -0,0 +1,87 @@ +import Admonition from "@theme/Admonition"; + +# $$ + +## Обзор {#overview} + +Используйте команду `$$` вместо [findElements][find-elements] как более краткую команду, чтобы получить несколько элементов на странице. + +Команда `$$` возвращает массив с искомыми элементами, на каждом из которых можно вызывать команды действия без передачи селектора. Однако, если вы все же передадите селектор, то сначала будет найден соответствующий элемент, а затем вызвано действие для этого элемента. + +Вы можете связать `$` или `$$` вместе, чтобы спуститься по дереву DOM. + + + Подробнее о том, как выбрать определенные элементы, смотрите в рецепте «[Как использовать + селекторы][how-to-use-selectors]». + + +## Использование {#usage} + +```javascript +await browser.$$(selector); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
selectorString или FunctionСелектор или JS-функция для получения множества элементов.
+ +## Примеры использования {#examples} + +**index.html** + +```html + +``` + +**$.js** + +```javascript +it("should get text a menu link", async ({ browser }) => { + const text = await browser.$$("#menu")[0]; + + console.log(await text.$$("li")[2].$("a").getText()); // выведет: "API" +}); + +it("should get text a menu link - JS Function", async ({ browser }) => { + const text = await browser.$$(function () { + // Использовать здесь стрелочную функцию нельзя. + // Это Window – https://developer.mozilla.org/en-US/docs/Web/API/Window + // + // TypeScript-пользователи могут сделать что-нибудь вроде: + // return (this as Window).document.querySelectorAll('#menu') + return this.document.querySelectorAll("#menu"); // Element[] + })[0]; + + console.log(await text.$$("li")[2].$("a").getText()); // выведет: "API" +}); +``` + +## Связанные команды {#related} + +- [browser.$](./$) +- [element.$](../element/$) +- [element.$$](../element/$$) + +[find-elements]: https://webdriver.io/docs/api/webdriver/#findelements +[how-to-use-selectors]: https://webdriver.io/docs/selectors diff --git a/docs/commands/browser/$.mdx b/docs/commands/browser/$.mdx new file mode 100644 index 0000000..fc0a39f --- /dev/null +++ b/docs/commands/browser/$.mdx @@ -0,0 +1,114 @@ +--- +sidebar_position: 1 +--- + +import Admonition from "@theme/Admonition"; + +# $ + +## Обзор {#overview} + +Используйте команду `$` вместо [findElement][find-element] как более краткую команду, чтобы получить один элемент на странице. + +Команда `$` возвращает объект, описывающий элемент, на котором можно вызывать команды действия без передачи селектора. Однако, если вы все же передадите селектор, то сначала будет найден соответствующий элемент, а затем вызвано действие для этого элемента. Вы также можете передать объект в качестве селектора, где объект содержит свойство `element-6066-11e4-a52e-4f735466cecf` со значением ссылки на элемент. Затем команда преобразует ссылку в расширенный элемент WebdriverIO. + +Вы можете связать `$` или `$$` вместе, чтобы спуститься по дереву DOM. + + + Подробнее о том, как выбрать определенные элементы, читайте в рецепте «[Как использовать + селекторы][how-to-use-selectors]». + + +## Использование {#usage} + +```javascript +await browser.$(selector); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
selectorString или Function или MatcherСелектор или JS-функция для получения конкретного элемента.
+ +## Примеры использования {#examples} + +**index.html** + +```html + +``` + +**$.js** + +```javascript +it("should get text a menu link", async ({ browser }) => { + const text = await browser.$("#menu"); + + console.log(await text.$$("li")[2].$("a").getText()); // выведет: "API" +}); + +it("should get text a menu link - JS Function", async ({ browser }) => { + const text = await browser.$(function () { + // Использовать здесь стрелочную функцию нельзя. + // Это Window – https://developer.mozilla.org/en-US/docs/Web/API/Window + // + // TypeScript-пользователи могут сделать что-нибудь вроде: + // return (this as Window).document.querySelector('#menu') + return this.document.querySelector("#menu"); // Element + }); + + console.log(await text.$$("li")[2].$("a").getText()); // выведет: "API" +}); + +it("should allow to convert protocol result of an element into a WebdriverIO element", async ({ + browser, +}) => { + const activeElement = await browser.getActiveElement(); + + console.log(await browser.$(activeElement).getTagName()); // выведет активный элемент +}); + +it("should use Androids DataMatcher or ViewMatcher selector", async ({ browser }) => { + const menuItem = await browser.$({ + name: "hasEntry", + args: ["title", "ViewTitle"], + class: "androidx.test.espresso.matcher.ViewMatchers", + }); + await menuItem.click(); + + const menuItem = await browser.$({ + name: "hasEntry", + args: ["title", "ViewTitle"], + }); + await menuItem.click(); +}); +``` + +## Связанные команды {#related} + +- [browser.$$](./$$) +- [element.$](../element/$) +- [element.$$](../element/$$) + +[find-element]: https://webdriver.io/docs/api/webdriver/#findelement +[how-to-use-selectors]: https://webdriver.io/docs/selectors diff --git a/docs/commands/browser/action.mdx b/docs/commands/browser/action.mdx new file mode 100644 index 0000000..0583624 --- /dev/null +++ b/docs/commands/browser/action.mdx @@ -0,0 +1,161 @@ +import Admonition from "@theme/Admonition"; + +# action + +## Обзор {#overview} + +Используйте команду `action`, чтобы выполнить действия ввода в одном из виртуализируемых устройств в веб-браузере. + +В отличие от высокоуровневых команд [scrollIntoView][scrollIntoView] и [doubleClick][doubleClick], Actions API обеспечивает более гранулярное управление устройствами ввода. Доступны следующие источники ввода: + +- ввод текста с клавиатуры для клавиатурных устройств; +- управление мышью, пером или сенсорным устройством; +- управление скроллом для устройств с колесом прокрутки. + +Каждая цепочка вызовов `action` команд должна завершаться вызовом команды `perform`, чтобы начать выполнение указанного набора действий. Также это приводит к высвобождению всех нажатых клавиш, кнопок и т.д. на виртуальных устройствах ввода и запускает необходимые события. Высвобождение можно пропустить, передав аргумент `true` в команду `perform`. Пример: + +```typescript +await browser.action(...).perform(true); +``` + + + Поддержка данной команды и конкретных действий может различаться в зависимости от среды + выполнения. За ходом разработки можно следить на [wpt.fyi][web-platform-tests]. Для мобильных + устройств вы можете использовать специальные команды жестов [Appium][appium] на + [iOS][appium-ios] и [Android][appium-android]. + + +## Управление клавиатурой {#keyboard_control} + +Используется при указании `key` в качестве аргумента команды `action`. Пример: + +```typescript +await browser.action("key"); +``` + +Возвращает объект `KeyAction`, который поддерживает следующие действия: + +- `down(value: string)` — создает действие нажатия клавиши; +- `up(value: string)` — создает действие отпускания клавиши; +- `pause(ms: number)` — указывает, что источник ввода ничего не делает указанное количество времени. + +### Специальные символы {#special_symbols} + +Для использования специальных символов (`Control`, `Page Up`, `Shift` и т.д.) можно использовать объект `Key` из пакета [webdriverio][webdriverio-npm]. В нем содержатся unicode представления всех нужных специальных символов. Пример: + +```typescript +import { Key } from "webdriverio"; + +await browser.action("key").down(Key.Ctrl).perform(); +``` + +### Примеры использования {#keyboard_examples} + +```typescript +import { Key } from "webdriverio"; + +it("should emit key events using key action commands", async ({ browser }) => { + const elem = await browser.$("input"); + await elem.click(); // сделать элемент активным + + await browser.action("key").down("f").down("o").down("o").up("f").up("o").up("o").perform(); + + console.log(await elem.getValue()); // возвращает "foo" + + // скопировать значение из элемента input + await browser.action("key").down(Key.Ctrl).down("c").pause(10).up(Key.Ctrl).up("c").perform(); +}); +``` + +Вместо серии `down/up` событий лучше использовать команду `setValue`. Пример исключительно для демонстрации принципов работы команды `action`. + +## Управление указателем {#pointer_control} + +Используется при указании `pointer` в качестве аргумента команды `action`, также можно указать тип указателя. Пример: + +```typescript +await browser.action("pointer", { + parameters: { pointerType: "mouse" }, // "mouse" значение по умолчанию, также доступны: "pen" or "touch" +}); +``` + +Возвращает объект `PointerAction`, который поддерживает следующие действия: + +- `down(button: 'left' | 'middle' | 'right')` — создает действие для нажатия одной клавиши; +- `down(params: PointerActionParams)` — создает действие для нажатия одной клавиши с подробными параметрами; +- `move(x: number, y: number)` — создает действие для перемещения указателя на `x` и `y` пикселей относительно вьюпорта; +- `move(params: PointerActionMoveParams)` — создает действие для перемещения указателя на `x` и `y` пикселей из указанного начала координат. Начало координат может быть определено как текущая позиция указателя, вьюпорта или центр определенного элемента; +- `up(button: 'left' | 'middle' | 'right')` — создает действие для отпускания одной клавиши; +- `up(params: PointerActionUpParams)` — создает действие для отпускания одной клавиши с подробными параметрами; +- `cancel()` — создает действие, которое отменяет текущее положение указателя; +- `pause(ms: number)` — указывает, что источник ввода ничего не делает указанное количество времени. + +Подробную информацию о типах параметров [PointerActionParams][pointer-action-params], [PointerActionMoveParams][pointer-action-move-params] и [PointerActionUpParams][pointer-action-up-params] можно найти в исходном коде webdriverio. + +### Примеры использования {#pointer_examples} + +```typescript +it("drag and drop using pointer action command", async ({ browser }) => { + const origin = await browser.$("#source"); + const targetOrigin = await browser.$("#target"); + + await browser + .action("pointer") + .move({ duration: 0, origin, x: 0, y: 0 }) + .down({ button: 0 }) // левая кнопка + .pause(10) + .move({ duration: 0, origin: targetOrigin }) + .up({ button: 0 }) + .perform(); +}); +``` + +## Управление колесом прокрутки {#scroll_wheel_control} + +Используется при указании `wheel` в качестве аргумента команды `action`. Пример: + +```typescript +await browser.action("wheel"); +``` + +Возвращает объект `WheelAction`, который поддерживает следующие действия: + +- `scroll(params: ScrollParams)` — прокручивает страницу до указанных координат или до начала координат; +- `pause(ms: number)` — указывает, что источник ввода ничего не делает указанное количество времени. + +Подробную информацию о типе параметра [ScrollParams][scroll-params] можно найти в исходном коде webdriverio. + +### Примеры использования {#scroll_examples} + +```typescript +it("should scroll using wheel action commands", async ({ browser }) => { + console.log(await browser.execute(() => window.scrollY)); // возвращает 0 + + await browser + .action("wheel") + .scroll({ + deltaX: 0, + deltaY: 500, + duration: 200, + }) + .perform(); + + console.log(await browser.execute(() => window.scrollY)); // возвращает 500 +}); +``` + +## Связанные команды {#related} + +- [actions](./actions) + +[scrollIntoView]: ../element/scrollIntoView +[doubleClick]: ../element/doubleClick +[web-platform-tests]: https://wpt.fyi/results/webdriver/tests/perform_actions?label=experimental&label=master&aligned +[appium]: http://appium.io +[appium-ios]: https://appium.github.io/appium-xcuitest-driver/latest/reference/execute-methods/#mobile-pinch +[appium-android]: https://github.com/appium/appium-uiautomator2-driver#mobile-gesture-commands +[webdriverio-npm]: https://www.npmjs.com/package/webdriverio +[pointer-action-params]: https://github.com/webdriverio/webdriverio/blob/8ca026c75bf7c27ef9d574f0ec48d8bc13658602/packages/webdriverio/src/utils/actions/pointer.ts#L20-L35 +[pointer-action-move-params]: https://github.com/webdriverio/webdriverio/blob/8ca026c75bf7c27ef9d574f0ec48d8bc13658602/packages/webdriverio/src/utils/actions/pointer.ts#L20-L42 +[pointer-action-up-params]: https://github.com/webdriverio/webdriverio/blob/8ca026c75bf7c27ef9d574f0ec48d8bc13658602/packages/webdriverio/src/utils/actions/pointer.ts#L13-L19 +[scroll-params]: https://github.com/webdriverio/webdriverio/blob/8ca026c75bf7c27ef9d574f0ec48d8bc13658602/packages/webdriverio/src/utils/actions/wheel.ts#L4-L29 diff --git a/docs/commands/browser/actions.mdx b/docs/commands/browser/actions.mdx new file mode 100644 index 0000000..e7dd741 --- /dev/null +++ b/docs/commands/browser/actions.mdx @@ -0,0 +1,28 @@ +# actions + +## Обзор {#overview} + +Используйте команду `actions`, чтобы выполнить несколько действий ввода в одном из виртуализируемых устройств в веб-браузере. Например для имитации масштабирования страницы. Больше подробной информации представлено в описании команды [action][action]. + +## Использование {#usage} + +```typescript +await browser.actions([action1, action2, ...]); +``` + +## Примеры использования {#examples} + +```typescript +it("run multiple actions at once for a pinch zoom", async ({ browser }) => { + await browser.actions([ + browser.action("pointer").move(500, 500).down().move(250, 250).up(), + browser.action("pointer").move(500, 500).down().move(750, 750).up(), + ]); +}); +``` + +## Связанные команды {#related} + +- [action](./action) + +[action]: ./action diff --git a/docs/commands/browser/addCommand.mdx b/docs/commands/browser/addCommand.mdx new file mode 100644 index 0000000..ca43f45 --- /dev/null +++ b/docs/commands/browser/addCommand.mdx @@ -0,0 +1,65 @@ +import Admonition from "@theme/Admonition"; + +# addCommand + +## Обзор {#overview} + +Используйте команду `addCommand`, чтобы добавить свою команду к браузеру _(browser)_ или к элементу _(element)_. Добавляемая команда может быть как синхронной, так и асинхронной. + + + Подробнее о том, как добавлять свои кастомные команды, читайте в рецепте «[Как добавить свои + команды][how-to-add-custom-commands]». + + +## Использование {#usage} + +```javascript +await browser.addCommand(name, callback, elementScope); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
nameStringИмя кастомной команды.
callbackFunctionФункция-реализация команды.
elementScopeBooleanЕсли значение _true_, то добавить команду к элементу, а не к браузеру. По умолчанию: _false_.
+ +## Примеры использования {#examples} + +```javascript +// добавляем команду getUrlAndTitle +await browser.addCommand("getUrlAndTitle", async function (customParam) { + return { + url: await this.getUrl(), // `this` здесь и ниже относится к объекту "browser" + title: await this.getTitle(), + customParam: customParam, + }; +}); + +// используем новую команду getUrlAndTitle +it("should use my add command", async ({ browser }) => { + await browser.url("https://webdriver.io"); + + const result = await browser.getUrlAndTitle("foobar"); + + assert.strictEqual(result.url, "https://webdriver.io"); + assert.strictEqual( + result.title, + "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js", + ); + assert.strictEqual(result.customParam, "foobar"); +}); +``` + +## Связанные команды {#related} + +- [overwriteCommand](./overwriteCommand) + +[how-to-add-custom-commands]: https://webdriver.io/docs/customcommands/#adding-custom-commands diff --git a/docs/commands/browser/assertView.mdx b/docs/commands/browser/assertView.mdx new file mode 100644 index 0000000..a01b4ef --- /dev/null +++ b/docs/commands/browser/assertView.mdx @@ -0,0 +1,103 @@ +import Admonition from "@theme/Admonition"; + +# assertView + +## Обзор {#overview} + +Используйте команду `assertView`, чтобы снять скриншот для определенного состояния теста и сравнить его с эталонным. + + + Эта команда реализована внутри testplane, в [API WebDriverIO][webdriverio-api] её нет. + + +## Использование {#usage} + +```javascript +await browser.assertView(state, selector, options); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
[state](#state)StringОбязательный параметр. Название состояния теста. Должно быть уникальным в пределах одного теста.
[selector](#selector)String или String[]Обязательный параметр. Селектор DOM-элемента, который необходимо заснять.
[options](#options)ObjectНастройки команды _assertView_.
+ +### state + +Обязательный параметр. Задает название состояния теста. Название должно быть уникальным в пределах одного теста. + +### selector + +Обязательный параметр. Задает селектор DOM-элемента, который необходимо заснять. + +### options + +Задает настройки команды `assertView`: + + + + + + + + + + + + + + + + +
**Опция****Тип****Описание**
ignoreElementsArray или StringЭлементы (задаются как селекторы), которые будут проигнорированы при сравнении скриншотов. Игнор реализуется с помощью закраски перечисленных элементов черным цветом. В случае одного элемента параметр можно задавать как строку.
toleranceNumberЧувствительность к разнице в цветам. Значение перетирает [browsers.tolerance][browsers-tolerance].
antialiasingToleranceNumberЧувствительность в антиалиасинге. Значение перетирает [browsers.antialiasingTolerance][browsers-antialiasing-tolerance].
allowViewportOverflowBooleanПо умолчанию testplane выдает ошибку, если элемент находится за пределами границ вьюпорта. Этот параметр отключает проверку на границы, позволяя снимать скриншоты элементов, не влезающих во вьюпорт. При этом на скриншоте будут видны только те части элемента, которые влезли во вьюпорт. Однако если _compositeImage_ равен _true_, то части элемента, которые оказались за _нижней_ границей вьюпорта, тоже будут видны на скриншоте. Аналогично если _captureElementFromTop_ равен _true_, то на скриншот попадут и те части элемента, которые оказались за пределами _верхней_ границы вьюпорта.
captureElementFromTopBooleanСнимать скриншот элемента с самого верха. Если элемент находится за пределами вьюпорта, то к нему будет выполнен подскролл.
compositeImageBooleanПозволяет тестировать элементы, не влезающие во вьюпорт по высоте.
screenshotDelayNumberЗадержка в миллисекундах перед снятием скриншота. Может пригодиться, когда на странице есть элементы, использующие анимацию, или скроллбар, который исчезает не сразу и попадает на результирующий скриншот.
selectorToScrollStringСелектор, который нужно скроллировать. Может пригодиться, когда надо сделать скриншот модального окна, которое не помещается на экране. Иначе без указания селектора скролл будет применяться к объекту _window_, и скроллироваться будет задний фон, оставляя попап-окно на месте.
+ +## Примеры использования {#examples} + +**example-1.js** + +```javascript +it("should assert view", async ({ browser }) => { + await browser.url("some/url"); + await browser.assertView("plain", ".button"); + + await browser.click(".button"); + await browser.assertView("clicked", ".button"); +}); +``` + +**example-2.js** + +```javascript +it("should assert view with given options", async ({ browser }) => { + await browser.url("some/url"); + await browser.assertView("plain", ".form", { + ignoreElements: [".link"], + tolerance: 5, + antialiasingTolerance: 4, + allowViewportOverflow: true, + captureElementFromTop: true, + compositeImage: true, + screenshotDelay: 10, + selectorToScroll: ".modal", + }); +}); +``` + +## Связанные команды {#related} + +- [element.assertView](../element/assertView) +- [browser.saveRecordingScreen](./saveRecordingScreen) +- [browser.saveScreenshot](./saveScreenshot) +- [element.saveScreenshot](../element/saveScreenshot) + +[webdriverio-api]: https://webdriver.io/docs/api +[browsers-tolerance]: ../../config/browsers#tolerance +[browsers-antialiasing-tolerance]: ../../config/browsers#antialiasing_tolerance diff --git a/docs/commands/browser/call.mdx b/docs/commands/browser/call.mdx new file mode 100644 index 0000000..f9cad7e --- /dev/null +++ b/docs/commands/browser/call.mdx @@ -0,0 +1,55 @@ +# call + +## Обзор {#overview} + +Используйте команду `call` для выполнения любого асинхронного действия в тестах. + +Сама команда при этом обрабатывается как синхронная функция. Она принимает промис и останавливает свое выполнение до тех пор, пока промис не будет выполнен. + +## Использование {#usage} + +```javascript +await browser.call(callback); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
callbackFunctionФункция, которую нужно вызвать.
+ +## Примеры использования {#examples} + +```javascript +it("some testing here", async ({ browser }) => { + await browser.url("http://google.com"); + + // делаем асинхронный вызов с помощью сторонней библиотеки, + // поддерживающей промисы, например, вызов к бэкенду или БД, + // чтобы сделать инъекцию фикстуры + await browser.call(() => { + return somePromiseLibrary.someMethod().then(() => { + // ... + }); + }); + + // пример для асинхронного вызова сторонней библиотеки, + // не поддерживающей промисы + const result = await browser.call(() => { + return new Promise((resolve, reject) => { + someOtherNodeLibrary.someMethod(param1, (err, res) => { + if (err) { + return reject(err); + } + resolve(res); + }); + }); + }); +}); +``` diff --git a/docs/commands/browser/debug.mdx b/docs/commands/browser/debug.mdx new file mode 100644 index 0000000..dd39d33 --- /dev/null +++ b/docs/commands/browser/debug.mdx @@ -0,0 +1,27 @@ +# debug + +## Обзор {#overview} + +Используйте команду `debug`, чтобы остановить выполнение теста в браузере. + +Остановив работу теста, вы можете перейти в браузер, открыть _DevTools_ и в реальном времени проинспектировать web-страницу. Это может быть полезно для отладки теста. + +## Использование {#usage} + +```javascript +await browser.debug(); +``` + +## Примеры использования {#examples} + +```javascript +it("should demonstrate the debug command", async ({ browser }) => { + await browser.$("#input").setValue("FOO"); + + await browser.debug(); // перейдите в браузер и измените значение #input на "BAR" + + const value = await browser.$("#input").getValue(); + + console.log(value); // выведет: "BAR" +}); +``` diff --git a/docs/commands/browser/deleteCookies.mdx b/docs/commands/browser/deleteCookies.mdx new file mode 100644 index 0000000..83e6be9 --- /dev/null +++ b/docs/commands/browser/deleteCookies.mdx @@ -0,0 +1,65 @@ +# deleteCookies + +## Обзор {#overview} + +Используйте команду `deleteCookies`, чтобы удалить все или конкретные _cookies_ для текущей страницы. + +Чтобы удалить конкретные _cookies_, нужно указать имя _cookie_ в виде строки или список имен _cookies_ в виде массива строк. + +## Использование {#usage} + +```javascript +await browser.deleteCookies(names); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
namesString или String[]Необязательный параметр. Имя _cookie_ или список имен _cookies_, которые необходимо удалить. При отсутствии параметра будут удалены все _cookies_ для текущей страницы.
+ +## Примеры использования {#examples} + +```javascript +it("should delete cookies", async ({ browser }) => { + await browser.setCookies([ + { name: "test", value: "123" }, + { name: "test2", value: "456" }, + { name: "test3", value: "789" }, + ]); + + let cookies = await browser.getCookies(); + console.log(cookies); + // выведет: + // [ + // { name: 'test', value: '123' }, + // { name: 'test2', value: '456' } + // { name: 'test3', value: '789' } + // ] + + await browser.deleteCookies(["test3"]); + + cookies = await browser.getCookies(); + console.log(cookies); + // выведет: + // [ + // { name: 'test', value: '123' }, + // { name: 'test2', value: '456' } + // ] + + await browser.deleteCookies(); + cookies = await browser.getCookies(); + console.log(cookies); // выведет: [] +}); +``` + +## Связанные команды {#related} + +- [getCookies](./getCookies) +- [setCookies](./setCookies) diff --git a/docs/commands/browser/execute.mdx b/docs/commands/browser/execute.mdx new file mode 100644 index 0000000..6b04ea1 --- /dev/null +++ b/docs/commands/browser/execute.mdx @@ -0,0 +1,55 @@ +# execute + +## Обзор {#overview} + +Используйте `execute`, чтобы выполнить _синхронно_ указанный JavaScript-код на странице текущего выбранного фрейма. + +Команда возвращает клиенту результат выполнения скрипта. + +Аргумент `script` определяет сценарий для выполнения в виде тела функции. Значение, возвращаемое этой функцией, будет возвращено клиенту. Функция будет вызвана с предоставленным массивом `args`, и доступ к значениям может быть получен через объект `arguments` в указанном порядке. + +Аргументами могут быть любые JSON-примитивы, массивы или объекты JSON. Объекты JSON, которые определяют ссылку на _WebElement,_ будут преобразованы в соответствующий элемент DOM. Аналогично, любые _WebElements_ в результате скрипта будут возвращены клиенту в виде объектов _WebElement JSON_. + +## Использование {#usage} + +```javascript +await browser.execute(script, arguments); +``` + +## Параметры команды {#parameters} + + + + + + + + + + +
**Имя****Тип****Описание**
scriptString или FunctionСкрипт, который необходимо выполнить.
argumentsAnyНеобязательный параметр. Аргументы для скрипта.
+ +## Примеры использования {#examples} + +```javascript +it("should inject javascript on the page", async ({ browser }) => { + const result = await browser.execute( + (a, b, c, d) => { + // здесь мы в browser-контексте: доступа к консоли и к клиенту у нас нет + return a + b + c + d; + }, + 1, + 2, + 3, + 4, + ); + + // здесь мы в node.js-контексте: доступ к консоли и к клиенту у нас есть + console.log(result); // выведет: 10 +}); +``` + +## Связанные команды {#related} + +- [executeAsync](./executeAsync) +- [setTimeout](./setTimeout) diff --git a/docs/commands/browser/executeAsync.mdx b/docs/commands/browser/executeAsync.mdx new file mode 100644 index 0000000..970b510 --- /dev/null +++ b/docs/commands/browser/executeAsync.mdx @@ -0,0 +1,59 @@ +# executeAsync + +## Обзор {#overview} + +Используйте команду `executeAsync`, чтобы выполнить _асинхронно_ указанный JavaScript-код на странице текущего выбранного фрейма. + +Последним аргументом команды должен быть колбэк, который будет вызван, как только скрипт завершит свою работу. В качестве входного параметра команда передает в колбэк результат выполнения скрипта. + +Аргумент `script` определяет сценарий для выполнения в виде тела функции. Функция будет вызвана с предоставленным массивом `args`, и доступ к значениям может быть получен через объект `arguments` в указанном порядке. Последним аргументом всегда должна быть колбэк-функция, которая будет вызвана после того, как скрипт будет выполнен. + +Аргументами могут быть любые JSON-примитивы, массивы или объекты JSON. Объекты JSON, которые определяют ссылку на _WebElement,_ будут преобразованы в соответствующий элемент DOM. Аналогично, любые _WebElements_ в результате скрипта будут возвращены клиенту в виде объектов _WebElement JSON_. + +## Использование {#usage} + +```javascript +await browser.executeAsync(script, arguments); +``` + +## Параметры команды {#parameters} + + + + + + + + + + +
**Имя****Тип****Описание**
scriptString или FunctionСкрипт, который необходимо выполнить.
argumentsAnyАргументы для скрипта. Последним аргументом должна быть колбэк-функция, которая будет вызвана после того, как скрипт будет выполнен.
+ +## Примеры использования {#examples} + +```javascript +it("should execute async JavaScript on the page", async ({ browser }) => { + await browser.setTimeout({ script: 5000 }); + + const result = await browser.executeAsync( + function (a, b, c, d, done) { + // здесь мы в browser-контексте: доступа к консоли и к клиенту у нас нет + setTimeout(() => { + done(a + b + c + d); + }, 3000); + }, + 1, + 2, + 3, + 4, + ); + + // здесь мы в node.js-контексте: доступ к консоли и к клиенту у нас есть + console.log(result); // выведет: 10 +}); +``` + +## Связанные команды {#related} + +- [execute](./execute) +- [setTimeout](./setTimeout) diff --git a/docs/commands/browser/executionContext.mdx b/docs/commands/browser/executionContext.mdx new file mode 100644 index 0000000..416b78a --- /dev/null +++ b/docs/commands/browser/executionContext.mdx @@ -0,0 +1,41 @@ +import Admonition from "@theme/Admonition"; + +# executionContext + +## Обзор {#overview} + +Во время прогона тестов testplane добавляет в `browser` свойство `executionContext` для хранения контекста исполнения. + +В свойстве `browser.executionContext` хранится текущий объект теста или хука \_Mocha, дополненный идентификатором браузера. + + + Контекст исполнения добавляет testplane, в [API WebDriverIO][webdriverio-api] его нет. + + +## Пример использования {#examples} + +```javascript +it("should log execution context", async ({ browser }) => { + await browser.url("/foo/bar"); + + console.log("test", browser.executionContext); + // выведет: + // test: { + // "title": "should log execution context", + // "async": 0, + // "sync": true, + // "timedOut": false, + // "pending": false, + // "type": "test", + // "body": "...", + // "file": "/foo/bar/baz/qux.js", + // "parent": "#", + // "ctx": "#", + // "browserId": "chrome", + // "meta": {}, + // "timer": {} + // } +}); +``` + +[webdriverio-api]: https://webdriver.io/docs/api diff --git a/docs/commands/browser/getConfig.mdx b/docs/commands/browser/getConfig.mdx new file mode 100644 index 0000000..8e406c0 --- /dev/null +++ b/docs/commands/browser/getConfig.mdx @@ -0,0 +1,27 @@ +# getConfig + +## Обзор {#overview} + +Используйте команду `getConfig`, чтобы получить [конфиг][browser-config] браузера. + +## Использование {#usage} + +```javascript +await browser.getConfig(); +``` + +## Примеры использования {#examples} + +```javascript +it("some test", async ({ browser }) => { + const browserConfig = await browser.getConfig(); + console.log(browserConfig.id); + // выведет: "chromeDesktop" – название конфигурации браузера, указанное в конфиге + + const { browserName } = browserConfig.desiredCapabilities; + console.log(browserName); + // выведет: "chrome" – фактическое название браузера +}); +``` + +[browser-config]: ../../config/browsers#browser_main_settings diff --git a/docs/commands/browser/getCookies.mdx b/docs/commands/browser/getCookies.mdx new file mode 100644 index 0000000..db7c377 --- /dev/null +++ b/docs/commands/browser/getCookies.mdx @@ -0,0 +1,56 @@ +# getCookies + +## Обзор {#overview} + +Используйте команду `getCookies`, чтобы получить все или конкретные _cookies_ на текущей странице. + +Чтобы получить конкретные куки, нужно указать имя _cookie_ в виде строки или список имен _cookies_ в виде массива строк. + +## Использование {#usage} + +```javascript +await browser.getCookies(names); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
namesString или String[]Необязательный параметр. Имя _cookie_ или список имен _cookies_, которые необходимо получить. При отсутствии параметра будут возвращены все _cookies_ для текущей страницы.
+ +## Примеры использования {#examples} + +```javascript +it("should return a cookie for me", async ({ browser }) => { + await browser.setCookies([ + { name: "test", value: "123" }, + { name: "test2", value: "456" }, + ]); + + const testCookie = await browser.getCookies(["test"]); + console.log(testCookie); + // выведет: + // [ + // { name: 'test', value: '123' } + // ] + + const allCookies = await browser.getCookies(); + console.log(allCookies); + // выведет: + // [ + // { name: 'test', value: '123' }, + // { name: 'test2', value: '456' } + // ] +}); +``` + +## Связанные команды {#related} + +- [setCookies](./setCookies) +- [deleteCookies](./deleteCookies) diff --git a/docs/commands/browser/getMeta.mdx b/docs/commands/browser/getMeta.mdx new file mode 100644 index 0000000..aff917f --- /dev/null +++ b/docs/commands/browser/getMeta.mdx @@ -0,0 +1,64 @@ +import Admonition from "@theme/Admonition"; + +# getMeta + +## Обзор + +Используйте команду `getMeta`, чтобы получить мета-информацию о тесте. + +Если указать ключ, то команда возвращает значение для конкретного ключа. +Если ключ не указан, команда вернет объект со всей мета-информацией теста. + +Для установки значений в мета-информации используйте команду [setMeta](./setMeta). + + + Эта команда реализована внутри testplane, в [API WebDriverIO][webdriverio-api] её нет. + + +## Использование {#usage} + +```javascript +await browser.getMeta(); +``` + +или + +```javascript +await browser.getMeta(key); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
keyStringНеобязательный параметр. Ключ, значение которого нужно получить из мета-информации теста.
+ +## Примеры использования {#examples} + +```javascript +it("should get meta info of test", async ({ browser }) => { + await browser.setMeta("foo", "bar"); + await browser.url("/foo/bar?baz=qux"); + + const val = await browser.getMeta("foo"); + console.log(val); // выведет: bar + + const url = await browser.getMeta("url"); + console.log(url); // выведет: /foo/bar?baz=qux + + const meta = await browser.getMeta(); + console.log(meta); // выведет: {foo: 'bar', url: '/foo/bar?baz=qux'} +}); +``` + +## Связанные команды {#related} + +- [setMeta](./setMeta) + +[webdriverio-api]: https://webdriver.io/docs/api diff --git a/docs/commands/browser/getPuppeteer.mdx b/docs/commands/browser/getPuppeteer.mdx new file mode 100644 index 0000000..b2f1049 --- /dev/null +++ b/docs/commands/browser/getPuppeteer.mdx @@ -0,0 +1,47 @@ +import Admonition from "@theme/Admonition"; + +# getPuppeteer + +## Обзор {#overview} + +Используйте команду `getPuppeteer`, чтобы получить инстанс [Puppeteer][puppeteer] браузера для последующего выполнения с его помощью специальных команд. + +Обратите внимание, что все команды [Puppeteer][puppeteer] по умолчанию асинхронны, поэтому, чтобы переключаться между синхронным и асинхронным выполнением, обязательно оберните вызовы [Puppeteer][puppeteer] в [browser.call][browser-call], как показано ниже в примере. + + +Команда _getPuppeteer_ работает только при использовании _Chrome DevTools Protocol (CDP)_. + +Читайте подробности в разделе «[Как использовать Chrome DevTools Protocol в testplane][how-to-use-cdp]». + + + +## Использование {#usage} + +```javascript +await browser.getPuppeteer(); +``` + +## Примеры использования {#examples} + +```javascript +it('should allow me to use Puppeteer', async ({ browser }) => { + await browser.url('https://webdriver.io'); + + const puppeteerBrowser = await browser.getPuppeteer(); + + // переключаемся на Puppeteer + const metrics = await browser.call(async () => { + await pages = await puppeteerBrowser.pages(); + + pages[0].setGeolocation({ latitude: 59.95, longitude: 30.31667 }); + + return pages[0].metrics(); + }); + + console.log(metrics.LayoutCount); // выведет: 42 +}); +``` + +[how-to-use-cdp]: ../../guides/how-to-use-cdp +[puppeteer]: https://pptr.dev/#?product=Puppeteer&version=v5.1.0&show=api-class-browser +[browser-call]: ./call diff --git a/docs/commands/browser/getWindowSize.mdx b/docs/commands/browser/getWindowSize.mdx new file mode 100644 index 0000000..b0f65f5 --- /dev/null +++ b/docs/commands/browser/getWindowSize.mdx @@ -0,0 +1,25 @@ +# getWindowSize + +## Обзор {#overview} + +Используйте команду `getWindowSize`, чтобы получить размер окна браузера. + +## Использование {#usage} + +```javascript +await browser.getWindowSize(); +``` + +## Примеры использования {#examples} + +```javascript +it("should return browser window size", async ({ browser }) => { + const windowSize = await browser.getWindowSize(); + + console.log(windowSize); // выведет: { width: 1280, height: 767 } +}); +``` + +## Связанные команды {#related} + +- [setWindowSize](./setWindowSize) diff --git a/docs/commands/browser/keys.mdx b/docs/commands/browser/keys.mdx new file mode 100644 index 0000000..b4abb9f --- /dev/null +++ b/docs/commands/browser/keys.mdx @@ -0,0 +1,42 @@ +# keys + +## Обзор {#overview} + +Используйте команду `keys`, чтобы отправить последовательность нажатий клавиш в активный элемент. + +Вы можете также использовать символы «Левая стрелка» или «Правая стрелка». Они будут автоматически преобразованы в соответствующие unicode-символы. Все поддерживаемые символы вы можете посмотреть [здесь][keyboard-actions]. + +Модификаторы типа `Ctrl`, `Shift`, `Alt` и `Meta` остаются нажатыми, пока вы сами не освободите их повторным вызовом. Однако модификация клика требует использования метода [performActions][perform-actions] из _WebDriver Actions API_. + +## Использование {#usage} + +```javascript +await browser.keys(value); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
valueString или String[]Последовательность клавиш, которые нужно напечатать.
+ +## Примеры использования {#examples} + +```javascript +it("copies text out of active element", async ({ browser }) => { + // копируем текст из элемента ввода + await browser.$("#username").setValue("anonymous"); + + await browser.keys(["Meta", "a"]); + await browser.keys(["Meta", "c"]); +}); +``` + +[keyboard-actions]: https://w3c.github.io/webdriver/#keyboard-actions +[perform-actions]: https://webdriver.io/docs/api/webdriver#performactions diff --git a/docs/commands/browser/mock.mdx b/docs/commands/browser/mock.mdx new file mode 100644 index 0000000..ef637c5 --- /dev/null +++ b/docs/commands/browser/mock.mdx @@ -0,0 +1,135 @@ +import Admonition from "@theme/Admonition"; + +# mock + +## Обзор {#overview} + +Используйте команду `mock`, чтобы имитировать ответ на запрос. + +Вы можете включать имитацию в зависимости от урла, заголовков или статус-кода. Вызов метода `mock` возвращает объект-заглушку _(stub)_, который вы можете использовать, чтобы модифицировать ответ от веб-ресурса. С помощью объекта-заглушки вы можете возвращать ответ-имитацию или ронять запрос. + +Существует 3 способа модифицировать ответ: + +- вернуть кастомный JSON-объект (например, чтобы имитировать ответ на API-запрос); +- заменить ответ локальным файлом (подсунуть модифицированный JavaScript-файл); +- перенаправить на другой URL и подсунуть полученный оттуда ответ. + + +Команда _mock_ работает только при использовании _Chrome DevTools Protocol (CDP)_. + +Читайте подробности в разделе «[Как использовать Chrome DevTools Protocol в testplane][how-to-use-cdp]». + +А также читайте рецепт «[Как отслеживать и перехватывать сетевые запросы и ответы][how-to-intercept-requests-and-responses]». + + + +## Использование {#usage} + +```javascript +await browser.mock(url, { method, headers, responseHeaders, postData, statusCode }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + + + + +
**Имя****Тип****Описание**
urlStringURL, запрос которого нужно имитировать.
methodString или Functionhttp-метод, по которому нужно фильтровать ресурс.
headersObject или FunctionЗаголовки запроса, по которым нужно фильтровать ресурс.
responseHeadersObject или FunctionЗаголовки ответа, по которым нужно фильтровать ресурс.
postDataString или FunctionpostData запроса, по которому нужно фильтровать ресурс.
statusCodeNumber или FunctionКод статуса, по которому нужно фильтровать ресурс.
+ +## Примеры использования {#examples} + +```javascript +it("should mock network resources", async ({ browser }) => { + // используем статическую строку + const userListMock = await browser.mock("**" + "/users/list"); + + // также мы можем имитировать ответы в зависимости + // от заголовков запроса или ответа, статус-кода, или postData + const strictMock = await browser.mock("**", { + // мокаем все json-ответы + statusCode: 200, + headers: { "Content-Type": "application/json" }, + responseHeaders: { "Cache-Control": "no-cache" }, + postData: "foobar", + }); + + // функция-компаратор + const apiV1Mock = await browser.mock("**" + "/api/v1", { + statusCode: statusCode => statusCode >= 200 && statusCode <= 203, + headers: headers => + headers["Authorization"] && headers["Authorization"].startsWith("Bearer "), + responseHeaders: headers => headers["Impersonation"], + postData: data => typeof data === "string" && data.includes("foo"), + }); +}); + +it("should modify API responses", async ({ browser }) => { + // фильтруем по методу + const todoMock = await browser.mock("**" + "/todos", { + method: "get", + }); + + // имитируем ответ эндпойнта заготовленной фикстурой + mock.respond([ + { + title: "Injected Todo", + order: null, + completed: false, + url: "http://todo-backend-express-knex.herokuapp.com/916", + }, + ]); + + // отвечаем другим статус-кодом или заголовком + mock.respond( + [ + { + title: "Injected Todo", + order: null, + completed: false, + url: "http://todo-backend-express-knex.herokuapp.com/916", + }, + ], + { + statusCode: 404, + headers: { + "x-custom-header": "foobar", + }, + }, + ); +}); + +it("should modify text assets", async ({ browser }) => { + const scriptMock = await browser.mock("**" + "/script.min.js"); + scriptMock.respond("./tests/fixtures/script.js"); +}); + +it("should redirect web resources", async ({ browser }) => { + const headerMock = await browser.mock("**" + "/header.png"); + headerMock.respond("https://media.giphy.com/media/F9hQLAVhWnL56/giphy.gif"); + + const pageMock = await browser.mock("https://google.com/"); + pageMock.respond("https://webdriver.io"); + await browser.url("https://google.com"); + + console.log(await browser.getTitle()); + // выведет: "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js" +}); +``` + +## Связанные команды {#related} + +- [mockClearAll](./mockClearAll) +- [mockRestoreAll](./mockRestoreAll) + +[how-to-use-cdp]: ../../guides/how-to-use-cdp +[how-to-intercept-requests-and-responses]: ../../guides/how-to-intercept-requests-and-responses diff --git a/docs/commands/browser/mockClearAll.mdx b/docs/commands/browser/mockClearAll.mdx new file mode 100644 index 0000000..e12c2ad --- /dev/null +++ b/docs/commands/browser/mockClearAll.mdx @@ -0,0 +1,40 @@ +# mockClearAll + +## Обзор {#overview} + +Используйте команду `mockClearAll`, чтобы сбросить всю сохраненную информацию в зарегистрированных имитациях. Имитации регистрируются с помощью команды [mock][mock]. + +## Использование {#usage} + +```typescript +await browser.mockClearAll(); +``` + +## Примеры использования {#examples} + +```typescript +it("should clear all mocks", async ({ browser }) => { + const docMock = await browser.mock("**", { + headers: { "Content-Type": "text/html" }, + }); + const jsMock = await browser.mock("**", { + headers: { "Content-Type": "application/javascript" }, + }); + + await browser.url("http://guinea-pig.webdriver.io/"); + console.log(docMock.calls.length, jsMock.calls.length); // returns "1 4" + + await browser.url("http://guinea-pig.webdriver.io/"); + console.log(docMock.calls.length, jsMock.calls.length); // returns "2 4" (JavaScript comes from cache) + + await browser.mockClearAll(); + console.log(docMock.calls.length, jsMock.calls.length); // returns "0 0" +}); +``` + +## Связанные команды {#related} + +- [mock][mock] +- [mockRestoreAll](./mockRestoreAll) + +[mock]: ./mock diff --git a/docs/commands/browser/mockRestoreAll.mdx b/docs/commands/browser/mockRestoreAll.mdx new file mode 100644 index 0000000..678da2b --- /dev/null +++ b/docs/commands/browser/mockRestoreAll.mdx @@ -0,0 +1,37 @@ +# mockRestoreAll + +## Обзор {#overview} + +Используйте команду `mockRestoreAll`, чтобы восстановить информацию и поведение в зарегистрированных имитациях до их создания. Имитации регистрируются с помощью команды [mock][mock]. + +## Использование {#usage} + +```typescript +await browser.mockRestoreAll(); +``` + +## Примеры использования {#examples} + +```typescript +it("should restore all mocks", async ({ browser }) => { + const googleMock = await browser.mock("https://google.com/"); + googleMock.respond("https://webdriver.io"); + const wdioMock = await browser.mock("https://webdriver.io"); + wdioMock.respond("http://json.org"); + + await browser.url("https://google.com/"); + console.log(await browser.getTitle()); // JSON + + await browser.mockRestoreAll(); + + await browser.url("https://google.com/"); + console.log(await browser.getTitle()); // Google +}); +``` + +## Связанные команды {#related} + +- [mock][mock] +- [mockClearAll](./mockClearAll) + +[mock]: ./mock diff --git a/docs/commands/browser/newWindow.mdx b/docs/commands/browser/newWindow.mdx new file mode 100644 index 0000000..582351c --- /dev/null +++ b/docs/commands/browser/newWindow.mdx @@ -0,0 +1,57 @@ +import Admonition from "@theme/Admonition"; + +# newWindow + +## Обзор {#overview} + +Используйте команду `newWindow`, чтобы открыть новое окно в браузере. + +Эта команда эквивалентна функции [window.open()][window-open]. + +Обратите внимание, что при выполнении эта команда автоматически переключит вас в новое окно. + +Команда _newWindow_ не работает в мобильных окружениях (!) + +## Использование {#usage} + +```javascript +await browser.newWindow(url, { windowName, windowFeatures }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
urlStringURL веб-сайта, который нужно открыть.
windowNameStringИмя нового окна.
windowFeaturesStringНастройки открываемого окна, например: _size_, _position_, _scrollbars_, и т. д.
+ +## Примеры использования {#examples} + +```javascript +it("should open a new tab", async ({ browser }) => { + await browser.url("http://google.com"); + console.log(await browser.getTitle()); + // выведет: "Google" + + await browser.newWindow( + "https://webdriver.io", + "WebdriverIO window", + "width=420,height=230,resizable,scrollbars=yes,status=1", + ); + console.log(await browser.getTitle()); + // выведет: "WebdriverIO · Next-gen browser and mobile automation test framework for Node.js" + + await browser.closeWindow(); + console.log(await browser.getTitle()); + // выведет: "Google" +}); +``` + +[window-open]: https://developer.mozilla.org/en-US/docs/Web/API/Window/open diff --git a/docs/commands/browser/openAndWait.mdx b/docs/commands/browser/openAndWait.mdx new file mode 100644 index 0000000..671a78c --- /dev/null +++ b/docs/commands/browser/openAndWait.mdx @@ -0,0 +1,72 @@ +# openAndWait + +## Обзор {#overview} + +Используйте команду `openAndWait` для открытия страницы и ожидания ее загрузки (по комбинации указанных факторов). + +Функции ожидания неактивности сети и падения по сетевым ошибкам доступны только при использовании браузеров с поддержкой _Chrome DevTools Protocol (CDP)_. + +## Использование {#usage} + +```javascript +await browser.openAndWait("some/url", { + selector: [".some", ".selector"], + predicate: () => document.isReady, + ignoreNetworkErrorsPatterns: ["https://mc.yandex.ru", "https://avatars.mds.yandex.net/*"], + waitNetworkIdle: true, + waitNetworkIdleTimeout: 500, + failOnNetworkError: true, + timeout: 20000, +}); +``` + +## Параметры команды {#parameters} + + + + + + + + + + +
**Имя****Тип****Описание**
urlStringАдрес страницы.
WaitOptsObjectПараметры ожидания страницы. Опционален, как и все его поля.
+ +### WaitOpts + + + + + + + + + + + + + + + + +
**Имя****Тип****Описание**
selectorString\|String[]Селектор (/селекторы) элемента (/элементов), которые должны существовать на загруженной странице.
predicate() => Promise<bool> \| boolПредикат, возвращающий `true`, если страница загружена. Выполняется в браузерном контексте: [waitUntil](https://webdriver.io/docs/api/element/waitUntil).
waitNetworkIdleBooleanЕсли `true`, ожидает окончания выполнения всех сетевых запросов. По умолчанию `true`. Работает только в CDP браузерах, игнорируется для остальных.
waitNetworkIdleTimeoutNumberВремя (в миллисекундах) после окончания всех сетевых запросов, чтобы считать сеть простаивающей. По умолчанию 500.
failOnNetworkErrorBooleanНужно ли бросать ошибку при сетевых ошибках. По умолчанию `true`. Работает только в CDP браузерах, игнорируется для остальных
shouldThrowError(match) => BooleanПредикат, который должен вернуть `true` по [Match](https://webdriver.io/docs/api/mock#match), если сетевая ошибка считается критической для корректной загрузки страницы. По умолчанию, возвращает `true` для картинок, стилей и шрифтов.
ignoreNetworkErrorsPatternsArray<String \| RegExp>Паттерны адресов ресурсов, для которых игнорируется проверка успешности загрузки. Имеет приоритет над `shouldThrowError`.
timeoutNumberТаймаут открытия страницы. По умолчанию, используется значение `pageLoadTimeout`. Выбрасывается исключение, если по истечени времени селекторы все еще не существуют, или предикат все еще резолвит `false`
+ +## Примеры использования {#examples} + +```javascript +it("some test", async ({ browser }) => { + // С `waitNetworkIdle` также ожидаем загрузки картинок, шрифтов, стилей, игнорируя ошибки метрики + await browser.openAndWait("some/url", { + selector: [".selector"], + predicate: () => document.isReady, + ignoreNetworkErrorsPatterns: ["https://mc.yandex.ru"], + waitNetworkIdle: true, + waitNetworkIdleTimeout: 500, + failOnNetworkError: true, + timeout: 20000, + }); + + await browser.assertView("plain", ".selector"); +}); +``` diff --git a/docs/commands/browser/overwriteCommand.mdx b/docs/commands/browser/overwriteCommand.mdx new file mode 100644 index 0000000..0edefd9 --- /dev/null +++ b/docs/commands/browser/overwriteCommand.mdx @@ -0,0 +1,57 @@ +import Admonition from "@theme/Admonition"; + +# overwriteCommand + +## Обзор {#overview} + +Используйте команду `overwriteCommand`, чтобы переопределить уже существующие команды браузера _(browser)_ или элемента _(element)_. + + + Читайте также рецепт «[Как добавить свои команды][how-to-add-custom-commands]». + + +## Использование {#usage} + +```javascript +await browser.overwriteCommand(name, callback, elementScope); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
nameStringИмя кастомной команды.
callbackFunctionФункция-реализация команды.
elementScopeBooleanЕсли значение _true_, то добавить команду к элементу, а не к браузеру. По умолчанию: _false_.
+ +## Примеры использования {#examples} + +```javascript +// вывести время паузы в мс перед самой паузой и вернуть потом это значение +await browser.overwriteCommand("pause", function (origPauseFunction, ms) { + console.log(`Sleeping for ${ms}`); + + origPauseFunction(ms); + + return ms; +}); + +// используем переопределенную команду паузы +it("should use my overwrite command", async ({ browser }) => { + await browser.url("https://webdriver.io"); + + await browser.pause(1000); // выведет: "Sleeping for 1000" +}); +``` + +## Связанные команды {#related} + +- [addCommand](./addCommand) + +[how-to-add-custom-commands]: https://webdriver.io/docs/customcommands/#adding-custom-commands diff --git a/docs/commands/browser/pause.mdx b/docs/commands/browser/pause.mdx new file mode 100644 index 0000000..710eee0 --- /dev/null +++ b/docs/commands/browser/pause.mdx @@ -0,0 +1,45 @@ +import Admonition from "@theme/Admonition"; + +# pause + +## Обзор {#overview} + +Используйте команду `pause`, чтобы приостановить выполнение теста на заданный промежуток времени. + + + Не рекомендуется использовать эту команду для ожидания отображения элемента. Чтобы избежать + ложных результатов тестирования, лучше использовать такие команды, как + [waitForExist][wait-for-exist] или другие команды _waitFor*_. + + +## Использование {#usage} + +```javascript +await browser.pause(milliseconds); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
millisecondsNumberВремя в миллисекундах.
+ +## Примеры использования {#examples} + +```javascript +it("should pause the execution", async ({ browser }) => { + const starttime = new Date().getTime(); + await browser.pause(3000); + const endtime = new Date().getTime(); + + console.log(endtime - starttime); // выведет: 3000 +}); +``` + +[wait-for-exist]: ../element/waitForExist diff --git a/docs/commands/browser/reactDollar.mdx b/docs/commands/browser/reactDollar.mdx new file mode 100644 index 0000000..05d9410 --- /dev/null +++ b/docs/commands/browser/reactDollar.mdx @@ -0,0 +1,76 @@ +import Admonition from "@theme/Admonition"; + +# react$ + +## Обзор {#overview} + +Используйте команду `react$`, чтобы найти на странице React-компоненты по их настоящему имени, одновременно фильтруя их по props'ам и состоянию. + + +Команда _react$_ работает только в приложениях, которые используют _React v16.x._ + +Читайте больше о React-селекторах в рецепте «[Как использовать селекторы][how-to-use-selectors]». + + + +## Использование {#usage} + +```javascript +await browser.react$(reactComponentSelector, { props, state }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
reactComponentSelectorStringСелектор React-компонента.
propsObjectReact-свойства, которые должен иметь компонент.
stateAny или Any[]React-состояние, в котором должен находиться компонент.
+ +## Примеры использования {#examples} + +```javascript +it("should calculate 7 * 6", async ({ browser }) => { + await browser.url("https://ahfarmer.github.io/calculator/"); + + await browser + .react$("t", { + props: { name: "7" }, + }) + .click(); + + await browser + .react$("t", { + props: { name: "x" }, + }) + .click(); + + await browser + .react$("t", { + props: { name: "6" }, + }) + .click(); + + await browser + .react$("t", { + props: { name: "=" }, + }) + .click(); + + console.log(await browser.$(".component-display").getText()); // выведет: "42" +}); +``` + +## Связанные команды {#related} + +- [browser.react$$](./reactDollarDollar) +- [element.react$](../element/reactDollar) +- [element.react$$](../element/reactDollarDollar) + +[how-to-use-selectors]: https://webdriver.io/docs/selectors diff --git a/docs/commands/browser/reactDollarDollar.mdx b/docs/commands/browser/reactDollarDollar.mdx new file mode 100644 index 0000000..5d94520 --- /dev/null +++ b/docs/commands/browser/reactDollarDollar.mdx @@ -0,0 +1,57 @@ +import Admonition from "@theme/Admonition"; + +# react$$ + +## Обзор {#overview} + +Используйте команду `react$$`, чтобы найти на странице множество React-компонентов по их настоящему имени, одновременно фильтруя их по props'ам и состоянию. + + +Команда _react$_ работает только в приложениях, которые используют _React v16.x._ + +Читайте больше о React-селекторах в рецепте «[Как использовать селекторы][how-to-use-selectors]». + + + +## Использование {#usage} + +```javascript +await browser.react$$(reactComponentSelector, { props, state }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
reactComponentSelectorStringСелектор React-компонента.
propsObjectReact-свойства, которые должен иметь компонент.
stateAny или Any[]React-состояние, в котором должен находиться компонент.
+ +## Примеры использования {#examples} + +```javascript +it("should calculate 7 * 6", async ({ browser }) => { + await browser.url("https://ahfarmer.github.io/calculator/"); + + const orangeButtons = await browser.react$$("t", { + props: { orange: true }, + }); + + console.log(await Promise.all(orangeButtons.map(btn => btn.getText()))); + // выведет: "[ '÷', 'x', '-', '+', '=' ]" +}); +``` + +## Связанные команды {#related} + +- [browser.react$](./reactDollar) +- [element.react$](../element/reactDollar) +- [element.react$$](../element/reactDollarDollar) + +[how-to-use-selectors]: https://webdriver.io/docs/selectors diff --git a/docs/commands/browser/reloadSession.mdx b/docs/commands/browser/reloadSession.mdx new file mode 100644 index 0000000..4b1e2ef --- /dev/null +++ b/docs/commands/browser/reloadSession.mdx @@ -0,0 +1,25 @@ +# reloadSession + +## Обзор {#overview} + +Используйте команду `reloadSession`, чтобы создать новую Selenium-сессию с текущими _capabilities_. + +Эта команда может пригодиться, если вы тестируете приложение с большим количеством состояний, и вам нужно очистить сессию браузера между отдельными тестами в одном файле, чтобы избежать создания сотен отдельных тестовых файлов с помощью WDIO. Однако будьте осторожны, эта команда сильно влияет на время тестирования, поскольку создание новых сессий Selenium отнимает много времени, особенно при использовании облачных сервисов. + +## Использование {#usage} + +```javascript +await browser.reloadSession(); +``` + +## Примеры использования {#examples} + +```javascript +it("should reload my session with current capabilities", async ({ browser }) => { + console.log(browser.sessionId); // выведет: e042b3f3cd5a479da4e171825e96e655 + + await browser.reloadSession(); + + console.log(browser.sessionId); // выведет: 9a0d9bf9d4864160aa982c50cf18a573 +}); +``` diff --git a/docs/commands/browser/savePDF.mdx b/docs/commands/browser/savePDF.mdx new file mode 100644 index 0000000..8a5e619 --- /dev/null +++ b/docs/commands/browser/savePDF.mdx @@ -0,0 +1,59 @@ +# savePDF + +## Обзор {#overview} + +Используйте команду `savePDF`, чтобы сохранить в pdf-файл текущий контекст в браузере. + +## Использование {#usage} + +```javascript +await browser.savePDF(filepath, { + orientation, + scale, + background, + width, + height, + top, + bottom, + left, + right, + shrinkToFit, + pageRanges, +}); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + + + + + + + + + + +
**Имя****Тип****Описание**
filepathStringПуть к pdf-файлу относительно каталога выполнения (расширение _.pdf_ — обязательно).
orientationStringОриентация pdf-страницы.
scaleNumberМасштаб pdf-страницы.
backgroundBooleanВключить фон pdf-страницы.
widthNumberШирина pdf-страницы.
heightNumberВысота pdf-страницы.
topNumberВерхний отступ pdf-страницы.
bottomNumberНижний отступ pdf-страницы.
leftNumberЛевый отступ pdf-страницы.
rightNumberПравый отступ pdf-страницы.
shrinkToFitNumberУменьшить страницу, чтобы она соответствовала размеру pdf-страницы.
pageRangesObject[]Диапазон страниц для включения в PDF.
+ +## Примеры использования {#examples} + +```javascript +it("should save a PDF screenshot of the browser view", async ({ browser }) => { + await browser.savePDF("./some/path/screenshot.pdf"); +}); +``` + +## Связанные команды {#related} + +- [saveRecordingScreen](./saveRecordingScreen) +- [saveScreenshot](./saveScreenshot) diff --git a/docs/commands/browser/saveRecordingScreen.mdx b/docs/commands/browser/saveRecordingScreen.mdx new file mode 100644 index 0000000..43af9ac --- /dev/null +++ b/docs/commands/browser/saveRecordingScreen.mdx @@ -0,0 +1,48 @@ +import Admonition from "@theme/Admonition"; + +# saveRecordingScreen + +## Обзор {#overview} + +Используйте команду `saveRecordingScreen`, чтобы сохранить в файл видео, съемка которого была начата командой [startRecordingScreen][start-recording-screen]. + + + Команда _saveRecordingScreen_ поддерживается только для мобильных сессий, которые используют + [Appium][appium]. + + +## Использование {#usage} + +```javascript +await browser.saveRecordingScreen(filepath); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
filepathStringПолный или относительный к исполняемому каталогу путь к видео.
+ +## Примеры использования {#examples} + +```javascript +it("should save a video", async ({ browser }) => { + await browser.startRecordingScreen(); + await browser.$("~BUTTON").click(); + await browser.saveRecordingScreen("./some/path/video.mp4"); +}); +``` + +## Связанные команды {#related} + +- [savePDF](./savePDF) +- [saveScreenshot](./saveScreenshot) + +[start-recording-screen]: https://webdriver.io/docs/api/appium/#startrecordingscreen +[appium]: http://appium.io/docs/en/commands/device/recording-screen/start-recording-screen/ diff --git a/docs/commands/browser/saveScreenshot.mdx b/docs/commands/browser/saveScreenshot.mdx new file mode 100644 index 0000000..8b992ad --- /dev/null +++ b/docs/commands/browser/saveScreenshot.mdx @@ -0,0 +1,42 @@ +# saveScreenshot + +## Обзор {#overview} + +Используйте команду `saveScreenshot`, чтобы сохранить скриншот текущего контекста в браузере в png-файл. + +Имейте в виду, что некоторые драйверы браузеров делают скриншоты всего документа (например, драйвер [Gecko][gecko] для Firefox), тогда как другие — только текущего окна просмотра (например, [Chromedriver][chromedriver] для Chrome). + +## Использование {#usage} + +```javascript +await browser.saveScreenshot(filepath); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
filepathStringПуть к скриншоту относительно каталога выполнения (расширение _.png_ — обязательно).
+ +## Примеры использования {#examples} + +```javascript +it("should save a screenshot of the browser view", async ({ browser }) => { + await browser.saveScreenshot("./some/path/screenshot.png"); +}); +``` + +## Связанные команды {#related} + +- [browser.savePDF](./savePDF) +- [browser.saveRecordingScreen](./saveRecordingScreen) +- [element.saveScreenshot](../element/saveScreenshot) + +[gecko]: https://github.com/mozilla/geckodriver +[chromedriver]: https://chromedriver.chromium.org/ diff --git a/docs/commands/browser/scroll.mdx b/docs/commands/browser/scroll.mdx new file mode 100644 index 0000000..15f61a7 --- /dev/null +++ b/docs/commands/browser/scroll.mdx @@ -0,0 +1,40 @@ +# scroll + +## Обзор {#overview} + +Используйте команду `scroll`, чтобы проскроллить вьюпорт браузера. Обратите внимание, что координаты `x` и `y` относятся к текущей позиции прокрутки вьюпорта. + +## Использование {#usage} + +```typescript +await browser.scroll(x, y); +``` + +## Параметры команды {#parameters} + + + + + + + + + + +
**Имя****Тип****Описание**
xNumberНеобязательный параметр. Координата x, куда нужно проскроллить. По умолчанию: _0_.
yNumberНеобязательный параметр. Координата y, куда нужно проскроллить. По умолчанию: _0_.
+ +## Примеры использования {#examples} + +```typescript +it("should demonstrate the scroll command", async ({ browser }) => { + await browser.url("https://webdriver.io"); + + console.log(await browser.execute(() => window.scrollY)); // returns 0 + await browser.scroll(0, 200); + console.log(await browser.execute(() => window.scrollY)); // returns 200 +}); +``` + +## Связанные команды {#related} + +- [element.scrollIntoView](../element/scrollIntoView) diff --git a/docs/commands/browser/setCookies.mdx b/docs/commands/browser/setCookies.mdx new file mode 100644 index 0000000..733d377 --- /dev/null +++ b/docs/commands/browser/setCookies.mdx @@ -0,0 +1,93 @@ +# setCookies + +## Обзор {#overview} + +Используйте команду `setCookies`, чтобы установить _cookies_ на текущей странице. + +Убедитесь, что вы находитесь именно на той странице, для которой вы хотите установить _cookies_. Вы не можете установить _cookies_ для произвольной страницы, не находясь при этом на ней. + +## Использование {#usage} + +```javascript +await browser.setCookies(cookies); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
cookiesWebDriver.Cookie или WebDriver.Cookie[]Объект _cookie_ или массив объектов _cookie_.
+ +### Параметры объекта WebDriver.Cookie + + + + + + + + + + + + + + + + +
**Имя****Тип****По умолчанию****Описание**
nameString_N/A_Имя _cookie_.
valueString_N/A_Значение _cookie_.
pathString"/"Путь к _cookie_.
domainString_см. описание_Домен, для которого будет видна _cookie_. Если домен не указан, то подразумевается домен урла активного документа в текущем контексте браузера.
secureBooleanfalseПризнак безопасной _cookie_.
httpOnlyBooleanfalseПризнак _cookie_ только для _http_.
expiryNumber_не устанавливается_Срок годности _cookie_ в секундах от начала эпохи Unix.
sameSiteString"None"Признак подчинения _cookie_ политике [SameSite][same-site]. Допустимые значения: _"Lax"_ или _"Strict"_.
+ +## Примеры использования {#examples} + +```javascript +it("should set a cookie for the page", async ({ browser }) => { + await browser.url("/"); + + // устанавливаем одну cookie + await browser.setCookies({ + name: "test1", + value: "one", + // Следующие параметры опциональны: + // путь к cookie, по умолчанию: "/" + // path: '/foo', + // домен, для которого будет видна cookie + // по умолчанию: домен урла активного документа в текущем контексте браузера + // domain: '.example.com', + // признак, что это безопасная cookie, по умолчанию: false + // secure: true, + // признак, что это cookie только для http, по умолчанию: false + // httpOnly: true, + // срок, когда cookie истекает, указывается в секундах с начала эпохи Unix + // expiry: 1551393875 + }); + + // устанавливаем несколько cookies + await browser.setCookies([ + { name: "test2", value: "two" }, + { name: "test3", value: "three" }, + ]); + + const cookies = await browser.getCookies(); + + await console.log(cookies); + // выведет: + // [ + // { name: 'test1', value: 'one', domain: 'www.example.com' }, + // { name: 'test2', value: 'two', domain: 'www.example.com' }, + // { name: 'test3', value: 'three', domain: 'www.example.com' } + // ] +}); +``` + +## Связанные команды {#related} + +- [getCookies](./getCookies) +- [deleteCookies](./deleteCookies) + +[same-site]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite diff --git a/docs/commands/browser/setMeta.mdx b/docs/commands/browser/setMeta.mdx new file mode 100644 index 0000000..b682244 --- /dev/null +++ b/docs/commands/browser/setMeta.mdx @@ -0,0 +1,56 @@ +import Admonition from "@theme/Admonition"; + +# setMeta + +## Обзор + +Используйте команду `setMeta`, чтобы записать значение под заданным ключом в мета-информацию теста. + +Для чтения мета-информации используйте команду [getMeta](./getMeta). + + + Эта команда реализована внутри testplane, в [API WebDriverIO][webdriverio-api] её нет. + + +## Использование {#usage} + +```javascript +await browser.setMeta(key, value); +``` + +## Параметры команды {#parameters} + + + + + + + + + + +
**Имя****Тип****Описание**
keyStringКлюч, значение для которого нужно записать в мета-информацию теста.
valueStringЗначение, которое нужно сохранить в мета-информации теста.
+ +## Примеры использования {#examples} + +```javascript +it("should get meta info of test", async ({ browser }) => { + await browser.setMeta("foo", "bar"); + await browser.url("/foo/bar?baz=qux"); + + const val = await browser.getMeta("foo"); + console.log(val); // выведет: bar + + const url = await browser.getMeta("url"); + console.log(url); // выведет: /foo/bar?baz=qux + + const meta = await browser.getMeta(); + console.log(meta); // выведет: {foo: 'bar', url: '/foo/bar?baz=qux'} +}); +``` + +## Связанные команды {#related} + +- [getMeta](./getMeta) + +[webdriverio-api]: https://webdriver.io/docs/api diff --git a/docs/commands/browser/setTimeout.mdx b/docs/commands/browser/setTimeout.mdx new file mode 100644 index 0000000..264e967 --- /dev/null +++ b/docs/commands/browser/setTimeout.mdx @@ -0,0 +1,45 @@ +# setTimeout + +## Обзор {#overview} + +Используйте команду `setTimeout`, чтобы настроить таймауты для поиска элемента на странице, ожидания загрузки документа и выполнения скриптов через команды [execute][execute] или [executeAsync][execute-async]. + +## Использование {#usage} + +```javascript +await browser.setTimeout({ implicit, pageLoad, script }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + +
**Имя****Тип****Описание**
implicitNumberВремя в миллисекундах для повторной попытки определения местоположения элемента при поиске элемента.
pageLoadNumberВремя ожидания загрузки документа, в миллисекундах.
scriptNumberТаймаут для скриптов, запущенных с помощью [execute][execute] или [executeAsync][execute-async]. Задается в миллисекундах.
+ +## Примеры использования {#examples} + +```javascript +it("should change timeout duration for session with long code duration", async ({ browser }) => { + await browser.setTimeout({ + pageLoad: 10000, + script: 60000, + }); + + // выполняем код, который занимает длительное время + await browser.executeAsync(done => { + console.log("Wake me up before you go!"); + setTimeout(done, 59000); + }); +}); +``` + +[execute]: ./execute +[execute-async]: ./executeAsync diff --git a/docs/commands/browser/setWindowSize.mdx b/docs/commands/browser/setWindowSize.mdx new file mode 100644 index 0000000..799da69 --- /dev/null +++ b/docs/commands/browser/setWindowSize.mdx @@ -0,0 +1,28 @@ +# setWindowSize + +## Обзор {#overview} + +Используйте команду `setWindowSize`, чтобы изменить внешний размер окна браузера в соответствии с заданными шириной и высотой. + +## Использование {#usage} + +```javascript +await browser.setWindowSize(width, height); +``` + +## Параметры команды {#parameters} + + + + + + + + + + +
**Имя****Тип****Описание**
widthNumberШирина окна браузера, которую нужно установить.
heightNumberВысота окна браузера, которую нужно установить.
+ +## Связанные команды {#related} + +- [getWindowSize](./getWindowSize) diff --git a/docs/commands/browser/switchWindow.mdx b/docs/commands/browser/switchWindow.mdx new file mode 100644 index 0000000..b7375e7 --- /dev/null +++ b/docs/commands/browser/switchWindow.mdx @@ -0,0 +1,41 @@ +# switchWindow + +## Обзор {#overview} + +Используйте команду `switchWindow`, чтобы перевести фокус на конкретную вкладку или конкретное окно. + +## Использование {#usage} + +```javascript +await browser.switchWindow(urlOrTitleToMatch); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
urlOrTitleToMatchString или RegExpСтрока или регулярное выражение, соответствующее заголовку или URL-адресу страницы.
+ +## Примеры использования {#examples} + +```javascript +it("should switch to another window", async ({ browser }) => { + // открываем url + await browser.url("https://google.com"); + + // создаем новое окно + await browser.newWindow("https://webdriver.io"); + + // переключаемся назад через соответствие заданному урлу + await browser.switchWindow("google.com"); + + // снова переключаемся через соответствие заданному заголовку страницы + await browser.switchWindow("Next-gen browser and mobile automation test framework for Node.js"); +}); +``` diff --git a/docs/commands/browser/throttle.mdx b/docs/commands/browser/throttle.mdx new file mode 100644 index 0000000..194cbca --- /dev/null +++ b/docs/commands/browser/throttle.mdx @@ -0,0 +1,69 @@ +import Admonition from "@theme/Admonition"; + +# throttle + +## Обзор {#overview} + +Используйте команду `throttle`, чтобы эмулировать разные типы сетевого соединения у пользователя. + +Эта команда позволяет промоделировать поведение сайта или веб-приложения при различной пропускной способности канала связи у пользователя. + +Существует также множество пресетов с готовыми настройками конфигурации сети. Например: + +- offline | online +- GPRS +- Regular2G | Good2G +- Regular3G | Good3G +- Regular4G +- DSL +- WiFi + + +Команда _throttle_ работает только при использовании _Chrome DevTools Protocol (CDP)_. + +Читайте подробности в разделе «[Как использовать Chrome DevTools Protocol в testplane][how-to-use-cdp]». + +А также читайте рецепт «[Как управлять пропускной способностью сети][how-to-manage-network-bandwidth]». + + + +## Использование {#usage} + +```javascript +await browser.throttle({ offline, latency, downloadThroughput, uploadThroughput }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + + +
**Имя****Тип****Описание**
offlineBooleanВключить эмуляцию потери соединения.
latencyNumberМинимальная задержка от отправленного запроса до полученных заголовков ответа, в миллисекундах.
downloadThroughputNumberМаксимальная совокупная пропускная способность загрузки (байт/сек). _-1_ отключает регулирование загрузки.
uploadThroughputNumberМаксимальная совокупная пропускная способность аплоада (байт/сек). _-1_ отключает регулирование аплоада.
+ +## Примеры использования {#examples} + +```javascript +it("should throttle the network", async ({ browser }) => { + // используем готовый пресет + await browser.throttle("Regular 3G"); + + // а здесь настраиваем конфигурацию сети сами + await browser.throttle({ + offline: false, + downloadThroughput: (200 * 1024) / 8, + uploadThroughput: (200 * 1024) / 8, + latency: 20, + }); +}); +``` + +[how-to-use-cdp]: ../../guides/how-to-use-cdp +[how-to-manage-network-bandwidth]: ../../guides/how-to-manage-network-bandwidth diff --git a/docs/commands/browser/touchAction.mdx b/docs/commands/browser/touchAction.mdx new file mode 100644 index 0000000..677fd7a --- /dev/null +++ b/docs/commands/browser/touchAction.mdx @@ -0,0 +1,86 @@ +import Admonition from "@theme/Admonition"; + +# touchAction + +## Обзор {#overview} + +Используйте команду `touchAction`, чтобы выполнить жесты в тестах на мобильной платформе. + +Команда позволяет связывать воедино отдельные действия _[ad hoc][ad-hoc]_, которые затем будут применены к элементу приложения на устройстве. + +Основные действия, которые можно использовать: + +- **press** — нужно указать element или координаты (x, y), или и то, и другое +- **longPress** — нужно указать element или координаты (x, y), или и то, и другое +- **tap** — нужно указать element или координаты (x, y), или и то, и другое +- **moveTo** — нужно указать абсолютные координаты (x, y) +- **wait** — нужно указать время в миллисекундах +- **release** — ничего указывать не нужно + + + В настоящее время команда _touchAction_ доступна только для нативных приложений и не может + использоваться для взаимодействия с веб-приложениями. + + +## Использование {#usage} + +```javascript +await browser.touchAction(action); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
actionObjectДействие, которое надо выполнить.
+ +## Примеры использования {#examples} + +```javascript +it("should do a touch gesture", async ({ browser }) => { + const screen = await browser.$("//UITextbox"); + + // простой touch action на элементе + await browser.touchAction({ + action: "tap", + element: screen, + }); + + // простой touch action с координатами x и y + // координаты касания – 30px направо и 20px вниз относительно вьюпорта + await browser.touchAction({ + action: "tap", + x: 30, + y: 20, + }); + + // простой touch action с координатами x и y + // координаты касания – 30px направо и 20px вниз относительно центра элемента + await browser.touchAction({ + action: "tap", + x: 30, + y: 20, + element: screen, + }); + + // multi action на элементе + // drag&drop из точки (200, 200) вниз на 100px по экрану + await browser.touchAction([ + { action: "press", x: 200, y: 200 }, + { action: "moveTo", x: 200, y: 300 }, + "release", + ]); +}); +``` + +## Связанные команды {#related} + +- [element.touchAction](../element/touchAction) + +[ad-hoc]: https://ru.wikipedia.org/wiki/Ad_hoc diff --git a/docs/commands/browser/uploadFile.mdx b/docs/commands/browser/uploadFile.mdx new file mode 100644 index 0000000..d103025 --- /dev/null +++ b/docs/commands/browser/uploadFile.mdx @@ -0,0 +1,52 @@ +import Admonition from "@theme/Admonition"; + +# uploadFile + +## Обзор {#overview} + +Используйте команду `uploadFile`, чтобы загрузить файл на _[Selenium Standalone][selenium-file]_ сервер или в браузер через его драйвер (например, [Chromedriver][chromedriver]). + + + Команда _uploadFile_ поддерживается только в том случае, если вы используете [Selenium + Grid][selenium-grid] или [Chromedriver][chromedriver]. Это связано с тем, что она использует + неофициальную особенность протокола, которая реализована в данный момент только в _Chrome_ и при + запуске в [Selenium Grid][selenium-grid]. + + +## Использование {#usage} + +```javascript +await browser.uploadFile(localPath); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
localPathStringПуть к локальному файлу.
+ +## Примеры использования {#examples} + +```javascript +const path = require("path"); + +it("should upload a file", async ({ browser }) => { + await browser.url("https://the-internet.herokuapp.com/upload"); + + const filePath = "/path/to/some/file.png"; + const remoteFilePath = await browser.uploadFile(filePath); + + await browser.$("#file-upload").setValue(remoteFilePath); + await browser.$("#file-submit").click(); +}); +``` + +[selenium-grid]: https://www.selenium.dev/documentation/grid/ +[selenium-file]: https://webdriver.io/docs/api/selenium/#file +[chromedriver]: https://chromedriver.chromium.org/ diff --git a/docs/commands/browser/url.mdx b/docs/commands/browser/url.mdx new file mode 100644 index 0000000..e607d2d --- /dev/null +++ b/docs/commands/browser/url.mdx @@ -0,0 +1,59 @@ +# url + +## Обзор {#overview} + +Используйте команду `url`, чтобы перейти по заданному URL-адресу в браузере. + +Если в конфигурации указан [baseUrl][base-url], то он будет добавлен к параметру `url` с помощью метода Node.JS [url.resolve()][url-resolve]. + +Вызов `browser.url()` с тем же URL-адресом, что и в прошлый раз, вызовет перезагрузку страницы. + +## Использование {#usage} + +```javascript +await browser.url(url); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
urlStringURL, который надо открыть.
+ +## Примеры использования {#examples} + +**url.js** + +```javascript +// переходим на URL +await browser.url("https://webdriver.io"); + +// получаем url +console.log(await browser.getUrl()); // выведет: "https://webdriver.io" +``` + +**baseUrlResolutions.js** + +```javascript +// Пусть baseUrl = http://example.com/site + +// При указании полного URL-адреса итоговый URL будет https://webdriver.io +await browser.url("https://webdriver.io"); + +// При указании URL-адреса без начального слэша +// итоговый URL формируется относительно всего baseUrl: http://example.com/site/relative +await browser.url("relative"); + +// При указании URL-адреса с начальным слэшом +// итоговый URL формируется относительно корня baseUrl: http://example.com/rootRelative +await browser.url("/rootRelative"); +``` + +[base-url]: ../../config/browsers#base_url +[url-resolve]: https://nodejs.org/api/url.html#urlresolvefrom-to diff --git a/docs/commands/browser/waitUntil.mdx b/docs/commands/browser/waitUntil.mdx new file mode 100644 index 0000000..672fb66 --- /dev/null +++ b/docs/commands/browser/waitUntil.mdx @@ -0,0 +1,57 @@ +# waitUntil + +## Обзор {#overview} + +Используйте команду `waitUntil`, чтобы дождаться соблюдения определенного условия на странице в браузере. + +## Использование {#usage} + +```javascript +await browser.waitUntil(condition, { timeout, timeoutMsg, interval }); +``` + +## Параметры команды {#parameters} + + + + + + + + + + + + +
**Имя****Тип****По умолчанию****Описание**
conditionFunction_N/A_Условие, которое нужно ждать.
timeoutNumber5000Таймаут в миллисекундах.
timeoutMsgString_N/A_Сообщение об ошибке, которое нужно бросить при таймауте.
intervalNumber500Интервал в миллисекундах между проверками условия.
+ +## Примеры использования {#examples} + +**example.html** + +```javascript +
I am some text
+ +``` + +**waitUntil.js** + +```javascript +it("should wait until text has changed", async ({ browser }) => { + await browser.waitUntil( + async () => (await browser.$("#someText").getText()) === "I am now different", + { + timeout: 5000, + timeoutMsg: "expected text to be different after 5s", + }, + ); +}); +``` + +## Связанные команды {#related} + +- [element.waitUntil](../element/waitUntil) diff --git a/docs/commands/element/$$.mdx b/docs/commands/element/$$.mdx new file mode 100644 index 0000000..7dba915 --- /dev/null +++ b/docs/commands/element/$$.mdx @@ -0,0 +1,89 @@ +import Admonition from "@theme/Admonition"; + +# $$ + +## Обзор {#overview} + +Используйте команду `$$` вместо [findElements][find-elements] как более краткую команду, чтобы получить несколько элементов на странице в области видимости элемента. Эта команда похожа на команду [browser.$$()](../browser/$$), и отличается только тем, что поиск элементов будет осуществляться среди потомков _(children)_ текущего элемента. + + + Подробнее о том, как выбрать определенные элементы, смотрите в рецепте «[Как использовать + селекторы][how-to-use-selectors]». + + +## Использование {#usage} + +```javascript +await browser.$(selector).$$(subSelector); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
subSelectorString или Function или MatcherСелектор, или JS-функция, или Matcher для получения множества элементов.
+ +## Примеры использования {#examples} + +**index.html** + +```html + +``` + +**$$.js** + +```javascript +it("should get text a menu link", async ({ browser }) => { + const text = await browser.$("#menu"); + + console.log(await text.$$("li")[2].$("a").getText()); // выведет: "API" +}); + +it("should get text a menu link - JS Function", async ({ browser }) => { + const text = await browser.$("#menu"); + + console.log( + await text + .$$(function () { + // Использовать здесь стрелочную функцию нельзя. + // Это Element – https://developer.mozilla.org/en-US/docs/Web/API/Element + // в этом конкретном примере – это HTMLUListElement + // + // TypeScript-пользователи могут сделать что-нибудь вроде: + // return (this as Element).querySelector('li') + return this.querySelectorAll("li"); // Element[] + })[2] + .$("a") + .getText(), + ); // выведет: "API" +}); +``` + +## Связанные команды + +- [element.$](./$) +- [browser.$](../browser/$) +- [browser.$$](../browser/$$) + +[find-elements]: https://webdriver.io/docs/api/webdriver/#findelements +[how-to-use-selectors]: https://webdriver.io/docs/selectors diff --git a/docs/commands/element/$.mdx b/docs/commands/element/$.mdx new file mode 100644 index 0000000..0e0a087 --- /dev/null +++ b/docs/commands/element/$.mdx @@ -0,0 +1,118 @@ +--- +sidebar_position: 1 +--- + +import Admonition from "@theme/Admonition"; + +# $ + +## Обзор {#overview} + +Используйте команду `$` вместо [findElement][find-element] как более краткую команду, чтобы получить один элемент на странице. + +Команда `$` возвращает объект, описывающий элемент, на котором можно вызывать команды действия без передачи селектора. Однако, если вы все же передадите селектор, то сначала будет найден соответствующий элемент, а затем вызвано действие для этого элемента. Вы также можете передать объект в качестве селектора, где объект содержит свойство `element-6066-11e4-a52e-4f735466cecf` со значением ссылки на элемент. Затем команда преобразует ссылку в расширенный элемент WebdriverIO. Примечание: используйте эти объекты элементов только в том случае, если вы уверены, что они существуют на странице. Последнее можно проверить, например, используя команду [isExisting](./isExisting). + +Вы можете связать `$` или `$$` вместе, чтобы спуститься по дереву DOM. Но имейте в виду, что объединение команд `$` и `$$` в цепочки имеет смысл только при использовании стратегий с множественными селекторами. Иначе вы будете делать ненужные запросы, которые замедлят тест (например, `$('body').$('div')` создаст два запроса, тогда как `$('body div')` сделает то же самое за один запрос). + + + Подробнее о том, как выбрать определенные элементы, читайте в рецепте «[Как использовать + селекторы][how-to-use-selectors]». + + +## Использование {#usage} + +```javascript +await browser.$(selector); +``` + +## Параметры команды {#parameters} + + + + + + + + + +
**Имя****Тип****Описание**
selectorString или Function или MatcherСелектор, или JS-функция, или объект Matcher для получения конкретного элемента.
+ +## Примеры использования {#examples} + +**index.html** + +```html + +``` + +```javascript +it("should get text of a menu link - JS Function", async ({ browser }) => { + const text = await browser.$("#menu"); + + console.log( + await text + .$$("li")[2] + .$(function () { + // Использовать здесь стрелочную функцию нельзя. + // Это Element – https://developer.mozilla.org/en-US/docs/Web/API/Element + // в этом конкретном примере – это HTMLLIElement + // + // TypeScript-пользователи могут сделать что-нибудь вроде: + // return (this as Element).querySelector('a') + return this.querySelector("a"); // Element + }) + .getText(), + ); // выведет: "API" +}); + +it("should get text a menu link", async ({ browser }) => { + const text = await browser.$("#menu"); + + console.log(await text.$$("li")[2].$("a").getText()); // выведет: "API" +}); + +it("should allow to convert protocol result of an element into a WebdriverIO element", async ({ + browser, +}) => { + const activeElement = await browser.getActiveElement(); + + console.log(await browser.$(activeElement).getTagName()); // выведет активный элемент +}); + +it("should use Androids DataMatcher or ViewMatcher selector", async ({ browser }) => { + const menuItem = await browser.$({ + name: "hasEntry", + args: ["title", "ViewTitle"], + class: "androidx.test.espresso.matcher.ViewMatchers", + }); + await menuItem.click(); + + const menuItem = await browser.$({ + name: "hasEntry", + args: ["title", "ViewTitle"], + }); + await menuItem.click(); +}); +``` + +## Связанные команды {#related} + +- [element.$$](./$$) +- [browser.$](../browser/$) +- [browser.$$](../browser/$$) + +[find-element]: https://webdriver.io/docs/api/webdriver/#findelement +[how-to-use-selectors]: https://webdriver.io/docs/selectors diff --git a/docs/commands/element/addValue.mdx b/docs/commands/element/addValue.mdx new file mode 100644 index 0000000..9e518c0 --- /dev/null +++ b/docs/commands/element/addValue.mdx @@ -0,0 +1,42 @@ +# addValue + +## Обзор {#overview} + +Используйте команду `addValue`, чтобы добавить значение в элемент типа `` или `