diff --git a/blog/selectivity.mdx b/blog/selectivity.mdx new file mode 100644 index 0000000..297ae08 --- /dev/null +++ b/blog/selectivity.mdx @@ -0,0 +1,20 @@ +--- +title: Селективность запуска тестов +slug: selectivity-intro +hide_table_of_contents: false +date: 2025-12-03T14:00 +--- + +В Testplane добавлена селективность запуска тестов — возможность автоматически запускать только те тесты, для которых изменились файлы, от которых они зависят. + + + +Селективность позволяет значительно ускорить процесс тестирования, запуская только релевантные тесты вместо всего набора. Testplane отслеживает зависимости каждого теста от файлов проекта — как код самих тестов, так и код, выполняемый в браузере — и при изменении файла запускает только те тесты, которые от него зависят. + +### Как использовать + +Узнайте больше об этом в нашей документации [Как настроить селективность при запуске тестов](/docs/v8/guides/selectivity). + +### Заключение + +Обновляйтесь на последнюю версию Testplane и попробуйте селективность в своих проектах! В случае обнаружения проблем приходите в [issue github](https://github.com/gemini-testing/testplane/issues) — мы вам обязательно поможем! diff --git a/docs/config/browsers.mdx b/docs/config/browsers.mdx index 0d4115b..078acf0 100644 --- a/docs/config/browsers.mdx +++ b/docs/config/browsers.mdx @@ -1017,6 +1017,64 @@ export = { }; ``` +## Selectivity {#selectivity} + +This section allows you to configure Testplane's selective test execution, avoiding the launch of tests for which nothing has changed. + +The section has the following parameters: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
**Parameter****Type****Default****Description**
`enabled``boolean``false`Enables selective test execution.
`sourceRoot``string``""`Configures the path to the root of the source code files.
`testDependenciesPath``string``".testplane/selectivity"`The path to the directory where test dependency data will be saved.
`compression``"none" | "gz" | "br" | "zstd"``"gz"`The compression type applied to the test dependency data.
`disableSelectivityPatterns``string[]``[]` + A list of patterns. If a file matching one of these patterns is changed, selectivity + will be disabled. +
+ + + You should not specify `node_modules` in `disableSelectivityPatterns`, as this will cause a + significant slowdown. Instead, it is recommended to specify Testplane configuration files and + the application's backend source code. + + [desired-caps]: https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities [html-reporter]: ../../html-reporter/html-reporter-setup [got]: https://github.com/sindresorhus/got/ diff --git a/docs/guides/selectivity.mdx b/docs/guides/selectivity.mdx new file mode 100644 index 0000000..de58ef5 --- /dev/null +++ b/docs/guides/selectivity.mdx @@ -0,0 +1,256 @@ +import Admonition from "@theme/Admonition"; + +# How to configure selectivity when running tests + +## Introduction + +Selectivity allows you to significantly speed up the testing process by running only relevant tests instead of the entire test suite. Testplane tracks each test's dependencies on project files — both the test code itself and the code executed in the browser — and, when a file changes, runs only those tests that depend on it. + +## How does it work? + +On the first run with selectivity enabled, Testplane collects dependency information for each test: + +- which Node.js modules were loaded while the test was running; +- which source files were executed in the browser. + +After a file changes, on the next run only those tests that depend on the changed file will be executed. This saves a lot of time, especially in large projects with many tests. + + + If at least one test fails, then on the next run all the same tests will be executed again — + Testplane will "remember" the new state only after a fully successful run. + + +## Setup + +To enable selectivity, just add a [`selectivity`](/docs/v8/config/browsers#selectivity) section with `enabled: true` to your Testplane configuration: + +```typescript +// testplane.config.ts +export default { + gridUrl: "local", + baseUrl: "about:blank", + pageLoadTimeout: 20000, + httpTimeout: 20000, + testTimeout: 90000, + resetCursor: false, + sets: { + desktop: { + files: ["testplane-tests/**/*.testplane.(t|j)s"], + browsers: ["chrome", "firefox"], + }, + }, + browsers: { + chrome: { + headless: true, + desiredCapabilities: { + browserName: "chrome", + }, + }, + firefox: { + desiredCapabilities: { + browserName: "firefox", + }, + }, + }, + selectivity: { + enabled: true, + }, +} satisfies import("testplane").ConfigInput; +``` + +## Usage example + +Let’s enable selectivity in a project with `chrome` and `firefox` browsers. For convenience, we’ll also configure a [devServer][dev-server]: + +```ts +// testplane.config.ts +const DEV_SERVER_PORT = 3050; + +export default { + baseUrl: `http://127.0.0.1:${DEV_SERVER_PORT}`, + // ... Other settings + devServer: { + command: `npm run dev -- --port=${DEV_SERVER_PORT}`, + reuseExisting: true, + readinessProbe: { + url: `http://127.0.0.1:${DEV_SERVER_PORT}`, + }, + }, + selectivity: { + enabled: true, + }, +} satisfies import("testplane").ConfigInput; +``` + +We’ll also enable SourceMap generation in the Webpack config used by the project: + +```js +// webpack.config.js +module.exports = (env, argv) => { + return { + // ... + // Use multiple entry points + entry: { + main: './js/home.js', + about: './js/about.js', + contact: './js/contact.js', + shared: './js/shared.js' + }, + // Enable SourceMap generation + // Both external (`source-map`) and inline (`inline-source-map`) are suitable + devtool: 'source-map', + output: { + // Specify a template that Webpack will use to store paths to source files + // `[resource-path]` or `[absolute-resource-path]` will also work + devtoolModuleFilenameTemplate: "webpack://[resource-path]", + }, +``` + +For the example we’ll use a plain JavaScript project without React, with the following file structure: + +``` +. +|____css +| |____home.css +| |____shared.css +| |____about.css +|____js +| |____about.js +| |____home.js +| |____main.js +| |____contact.js +| |____shared.js +|____index.html +|____about.html +|____contact.html +|____webpack.config.js +|____testplane.config.ts +|____testplane-tests +| |____example.testplane.ts +| |____tsconfig.json +|____package.json +|____package-lock.json +``` + +Let’s write the following tests: + +```ts +describe("test examples", () => { + it("main page", async ({ browser }) => { + await browser.url("/"); + }); + + it("main page with navigation to about page", async ({ browser }) => { + await browser.url("/"); + await browser.$("#about-link").click(); + }); + + it("main page with navigation to contact page", async ({ browser }) => { + await browser.url("/"); + await browser.$("#contact-link").click(); + }); + + it("contact page", async ({ browser }) => { + await browser.url("/contact"); + }); +}); +``` + +And run Testplane. For clarity, we’ll use the `DEBUG=testplane:selectivity` environment variable: + +![First run log](/img/docs/guides/selectivity/first-run.png) + +Let’s try running it again: + +![Log with no changes](/img/docs/guides/selectivity/no-changes.png) + +When there are no changes, running all tests is skipped. + +Now let’s change a couple of source files that are executed in the browser: + +![Single test run log](/img/docs/guides/selectivity/single-test-run.png) + +Only one test that depends on the changed files was run. The rest were skipped by selectivity. + +The same applies to test code selectivity: let’s create `./testplane-tests/my-module.ts`: + +```ts +export const foo = () => { + throw new Error("bar"); +}; +``` + +And use it in the test file: + +```ts +import { foo } from "./my-module"; + +describe("test examples", () => { + it("main page", async ({ browser }) => { + foo(); + await browser.url("/"); + }); + // The rest of the tests +}); +``` + +Now run the tests: + +![Failed test log](/img/docs/guides/selectivity/test-fail.png) + +While processing the test file, Testplane noticed that it now depends on another file, which means the functionality might have changed, so all tests in this file were run. + +But since the tests failed, the new state was not saved, so re-running the tests will run the same set of tests again. + +## Important details + +### Collecting browser dependencies + +Testplane records browser dependencies only in the Chrome browser, because dependency collection works via the [Chrome Devtools Protocol](/docs/v8/reference/webdriver-vs-cdp). However, if you have multiple browsers (for example, Chrome and Firefox), Firefox will still be able to use the list of browser dependencies for a test that was collected in Chrome. + +### SourceMap requirement + +For selectivity to work correctly, **SourceMap generation is required**. Thanks to SourceMaps, the browser can understand which source file the executed code belongs to. If a SourceMap is not generated for a code file, Testplane won’t be able to determine which source file the executed code comes from, and selectivity will not work correctly. + +### Server-side code and disableSelectivityPatterns + +Testplane cannot track code that runs on your server, regardless of the language it’s written in. Therefore, it’s recommended to add your server-side code to the `disableSelectivityPatterns` option — any change to files matching these patterns will disable selectivity and run all tests. + +If you are using the [reactStrictMode](https://nextjs.org/docs/pages/api-reference/config/next-config-js/reactStrictMode) option of the [Next.js](https://nextjs.org/) framework, rendering pages in the browser as well will allow Testplane to account for these files as if this were a regular SPA application. However, code executed exclusively on the server (such as API request handlers) will not be considered by Testplane’s selectivity. + +You should also add your Testplane configuration files (for example, `testplane.config.ts`) to `disableSelectivityPatterns`, since changing them can affect the behavior of any test. + + + Do not add `node_modules` to `disableSelectivityPatterns` — this will significantly slow things + down. Testplane tracks the used modules from `node_modules` on its own. + + +Example `disableSelectivityPatterns` configuration: + +```typescript +selectivity: { + enabled: true, + disableSelectivityPatterns: [ + "testplane.config.ts", + "backend/**/*.py", // server-side code in Python + "server/**/*.go", // server-side code in Go + ] +} +``` + +### Manually disabling selectivity + +When you use other filtering methods when running Testplane (such as specifying a path to a test file or using the `--grep` and `--set` options), selectivity is automatically disabled. + +You can also disable selectivity manually using an environment variable: + +```bash +testplane_selectivity_enabled=false # disable +``` + +## Configuration + +Additional information about selectivity configuration is provided in the [browsers-selectivity][selectivity-config] section of the documentation. + +[dev-server]: ../../config/dev-server +[selectivity-config]: ../../config/browsers#selectivity diff --git a/i18n/en/docusaurus-plugin-content-blog/selectivity.mdx b/i18n/en/docusaurus-plugin-content-blog/selectivity.mdx new file mode 100644 index 0000000..788bb5e --- /dev/null +++ b/i18n/en/docusaurus-plugin-content-blog/selectivity.mdx @@ -0,0 +1,20 @@ +--- +title: Test run selectivity +slug: selectivity-intro +hide_table_of_contents: false +date: 2025-12-03T14:00 +--- + +Testplane now supports test run selectivity — the ability to automatically run only those tests whose dependency files have changed. + + + +Selectivity allows you to significantly speed up the testing process by running only relevant tests instead of the entire suite. Testplane tracks each test’s dependencies on project files — both the test code itself and the code executed in the browser — and, when a file changes, runs only those tests that depend on it. + +### How to use + +Learn more in our guide [How to configure selectivity when running tests](/docs/v8/guides/selectivity). + +### Conclusion + +Upgrade to the latest Testplane version and try selectivity in your projects! If you encounter any issues, feel free to open an [issue on GitHub](https://github.com/gemini-testing/testplane/issues) — we’ll be happy to help! diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/config/browsers.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/config/browsers.mdx index 3525102..bcfacee 100644 --- a/i18n/ru/docusaurus-plugin-content-docs/current/config/browsers.mdx +++ b/i18n/ru/docusaurus-plugin-content-docs/current/config/browsers.mdx @@ -1025,6 +1025,63 @@ export = { }; ``` +## Selectivity {#selectivity} + +Эта секция позволяет конфигурировать селективность запуска Testplane, избегая запуска тех тестов, для которых ничего не поменялось. + +Секция имеет следующие параметры: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
**Параметр****Тип****По умолчанию****Описание**
`enabled``boolean``false`Включает селективность запуска тестов.
`sourceRoot``string``""`Конфигурирует путь к корню файлов исходного кода.
`testDependenciesPath``string``".testplane/selectivity"`Путь к директории, куда будут сохраняться данные о зависимостях тестов.
`compression``"none" | "gz" | "br" | "zstd"``"gz"`Тип сжатия, применяемый к данным о зависимостях тестов.
`disableSelectivityPatterns``string[]``[]` + Список паттернов, при изменении файлов по которым селективность должна отключаться. +
+ + + В `disableSelectivityPatterns` не стоит указывать `node_modules` - это приведет к ощутимому + замедлению. Вместо этого, рекомендуется указать конфигурационные файлы Testplane и исходный код + серверной части приложения. + + [desired-caps]: https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities [html-reporter]: ../../html-reporter/html-reporter-setup [got]: https://github.com/sindresorhus/got/ diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/guides/selectivity.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/guides/selectivity.mdx new file mode 100644 index 0000000..ced8132 --- /dev/null +++ b/i18n/ru/docusaurus-plugin-content-docs/current/guides/selectivity.mdx @@ -0,0 +1,256 @@ +import Admonition from "@theme/Admonition"; + +# Как настроить селективность при запуске тестов + +## Введение + +Селективность позволяет значительно ускорить процесс тестирования, запуская только релевантные тесты вместо всего набора. Testplane отслеживает зависимости каждого теста от файлов проекта — как код самих тестов, так и код, выполняемый в браузере — и при изменении файла запускает только те тесты, которые от него зависят. + +## Как это работает? + +При первом запуске с включенной селективностью Testplane собирает информацию о зависимостях каждого теста: + +- какие модули Node.js были загружены во время выполнения теста; +- какие файлы исходного кода были выполнены в браузере. + +После изменения файла при следующем запуске будут выполнены только те тесты, которые зависят от измененного файла. Это значительно экономит время, особенно в больших проектах с большим количеством тестов. + + + Если хотя бы один тест упадет, то при следующем прогоне будут запущены все те же тесты — + Testplane "запомнит" новое состояние только после полностью успешного прогона. + + +## Настройка + +Для включения селективности достаточно добавить в конфигурацию Testplane секцию [`selectivity`](/docs/v8/config/browsers#selectivity) с параметром `enabled: true`: + +```typescript +// testplane.config.ts +export default { + gridUrl: "local", + baseUrl: "about:blank", + pageLoadTimeout: 20000, + httpTimeout: 20000, + testTimeout: 90000, + resetCursor: false, + sets: { + desktop: { + files: ["testplane-tests/**/*.testplane.(t|j)s"], + browsers: ["chrome", "firefox"], + }, + }, + browsers: { + chrome: { + headless: true, + desiredCapabilities: { + browserName: "chrome", + }, + }, + firefox: { + desiredCapabilities: { + browserName: "firefox", + }, + }, + }, + selectivity: { + enabled: true, + }, +} satisfies import("testplane").ConfigInput; +``` + +## Пример использования + +Включим селективность в проекте с браузерами `chrome` и `firefox`. Также для удобства настроим [devServer][dev-server]: + +```ts +// testplane.config.ts +const DEV_SERVER_PORT = 3050; + +export default { + baseUrl: `http://127.0.0.1:${DEV_SERVER_PORT}`, + // ... Остальные настройки + devServer: { + command: `npm run dev -- --port=${DEV_SERVER_PORT}`, + reuseExisting: true, + readinessProbe: { + url: `http://127.0.0.1:${DEV_SERVER_PORT}`, + }, + }, + selectivity: { + enabled: true, + }, +} satisfies import("testplane").ConfigInput; +``` + +Также включим генерацию SourceMap в конфиге используемого Webpack: + +```js +// webpack.config.js +module.exports = (env, argv) => { + return { + // ... + // Используем несколько входных точек + entry: { + main: './js/home.js', + about: './js/about.js', + contact: './js/contact.js', + shared: './js/shared.js' + }, + // Включаем генерацию SourceMap + // Подходят как внешние (`source-map`), так и встроенные (`inline-source-map`) + devtool: 'source-map', + output: { + // Указываем шаблон, по которому Webpack будет сохранять пути до файлов исходного кода + // Подойдут также значения `"[resource-path]"` или `"[absolute-resource-path]"` + devtoolModuleFilenameTemplate: "webpack://[resource-path]", + }, +``` + +Для примера будем использовать проект на чистом JavaScript без React со следующей файловой структурой: + +``` +. +|____css +| |____home.css +| |____shared.css +| |____about.css +|____js +| |____about.js +| |____home.js +| |____main.js +| |____contact.js +| |____shared.js +|____index.html +|____about.html +|____contact.html +|____webpack.config.js +|____testplane.config.ts +|____testplane-tests +| |____example.testplane.ts +| |____tsconfig.json +|____package.json +|____package-lock.json +``` + +Напишем следующие тесты: + +```ts +describe("test examples", () => { + it("main page", async ({ browser }) => { + await browser.url("/"); + }); + + it("main page with navigation to about page", async ({ browser }) => { + await browser.url("/"); + await browser.$("#about-link").click(); + }); + + it("main page with navigation to contact page", async ({ browser }) => { + await browser.url("/"); + await browser.$("#contact-link").click(); + }); + + it("contact page", async ({ browser }) => { + await browser.url("/contact"); + }); +}); +``` + +И запустим Testplane. Для наглядности будем использовать переменную среды `DEBUG=testplane:selectivity`: + +![Лог первого запуска](/img/docs/guides/selectivity/first-run.png) + +Попробуем запустить еще раз: + +![Лог без изменений](/img/docs/guides/selectivity/no-changes.png) + +При отсутствии изменений, запуск всех тестов был пропущен. + +Теперь попробуем внести изменение в пару файлов исходного кода, выполняемых в браузере: + +![Лог запуска одного теста](/img/docs/guides/selectivity/single-test-run.png) + +Был запущен только один тест, который затрагивал измененные файлы. Запуск остальных был пропущен селективностью. + +Аналогично с селективностью кода теста: опишем файл `./testplane-tests/my-module.ts`: + +```ts +export const foo = () => { + throw new Error("bar"); +}; +``` + +И добавим его использование в файл с тестами: + +```ts +import { foo } from "./my-module"; + +describe("test examples", () => { + it("main page", async ({ browser }) => { + foo(); + await browser.url("/"); + }); + // Остальные тесты +}); +``` + +После чего запустим тесты: + +![Лог упавших тестлв](/img/docs/guides/selectivity/test-fail.png) + +Testplane при обработке файла с тестом заметил, что теперь он зависит от другого файла, что значит, что функциональность могла поменяться, поэтому все тесты в этом файле были запущены. + +Но из-за того, что тесты упали, новое состояние не было сохранено, из-за чего повторный запуск тестов приведет к повторному запуску все тех же тестов. + +## Важные особенности + +### Сбор браузерных зависимостей + +Testplane записывает браузерные зависимости только в браузере Chrome, поскольку сбор зависимостей работает по [Chrome Devtools Protocol](/docs/v8/reference/webdriver-vs-cdp). Однако, если у вас несколько браузеров (например, Chrome и Firefox), то Firefox сможет использовать список браузерных зависимостей теста, собранных браузером Chrome. + +### Требование SourceMap + +Для корректной работы селективности **обязательна генерация SourceMap**. Благодаря SourceMap браузер может понять, к какому исходному файлу относится выполняемый код. Если SourceMap для файла с кодом не будет сгенерирован, Testplane не сможет определить, к какому файлу исходного кода относится выполняемый код, и селективность не будет работать корректно. + +### Серверный код и disableSelectivityPatterns + +Testplane не имеет возможности отслеживать код, выполняемый на стороне вашего сервера, вне зависимости от языка, на котором он написан. Поэтому серверный код рекомендуется добавить в параметр `disableSelectivityPatterns` — любое изменение в файлах, попадающих под эти паттерны, будет отключать селективность и запускать все тесты. + +В случае использования [reactStrictMode](https://nextjs.org/docs/pages/api-reference/config/next-config-js/reactStrictMode) фреймворка [Next.js](https://nextjs.org/), отрисовка страниц также и в браузере позволит Testplane учесть эти файлы, как если бы это было обычное SPA приложение, однако код, выполняемый исключительно на сервере (такой как обработка API-запросов) не будет учтен селективностью Testplane. + +Также в `disableSelectivityPatterns` стоит добавить файлы конфигурации Testplane (например, `testplane.config.ts`), так как их изменение может повлиять на поведение любого теста. + + + Не добавляйте `node_modules` в `disableSelectivityPatterns` — это приведет к значительному + замедлению. Testplane самостоятельно отслеживает используемые модули из `node_modules`. + + +Пример настройки `disableSelectivityPatterns`: + +```typescript +selectivity: { + enabled: true, + disableSelectivityPatterns: [ + "testplane.config.ts", + "backend/**/*.py", // серверный код на Python + "server/**/*.go", // серверный код на Go + ] +} +``` + +### Отключение селективности вручную + +При указании иных способов фильтрации при запуске Testplane (таких как указание пути до файла с тестом или использование опций `--grep` и `--set`) селективность автоматически отключается. + +Также можно отключить селективность вручную с помощью переменной среды: + +```bash +testplane_selectivity_enabled=false # отключить +``` + +## Конфигурация + +Дополнительная информация о конфигурации селективности описана в разделе [browsers-selectivity][selectivity-config] документации. + +[dev-server]: ../../config/dev-server +[selectivity-config]: ../../config/browsers#selectivity diff --git a/static/img/docs/guides/selectivity/first-run.png b/static/img/docs/guides/selectivity/first-run.png new file mode 100644 index 0000000..0625a76 Binary files /dev/null and b/static/img/docs/guides/selectivity/first-run.png differ diff --git a/static/img/docs/guides/selectivity/no-changes.png b/static/img/docs/guides/selectivity/no-changes.png new file mode 100644 index 0000000..7e10773 Binary files /dev/null and b/static/img/docs/guides/selectivity/no-changes.png differ diff --git a/static/img/docs/guides/selectivity/single-test-run.png b/static/img/docs/guides/selectivity/single-test-run.png new file mode 100644 index 0000000..977b188 Binary files /dev/null and b/static/img/docs/guides/selectivity/single-test-run.png differ diff --git a/static/img/docs/guides/selectivity/test-fail.png b/static/img/docs/guides/selectivity/test-fail.png new file mode 100644 index 0000000..143d3b1 Binary files /dev/null and b/static/img/docs/guides/selectivity/test-fail.png differ