diff --git a/docs/basic-guides/authorization.mdx b/docs/basic-guides/authorization.mdx
new file mode 100644
index 0000000..ff2933a
--- /dev/null
+++ b/docs/basic-guides/authorization.mdx
@@ -0,0 +1,3 @@
+# Authorization
+
+Draft
diff --git a/i18n/ru/docusaurus-plugin-content-docs/current/basic-guides/authorization.mdx b/i18n/ru/docusaurus-plugin-content-docs/current/basic-guides/authorization.mdx
new file mode 100644
index 0000000..1aac15b
--- /dev/null
+++ b/i18n/ru/docusaurus-plugin-content-docs/current/basic-guides/authorization.mdx
@@ -0,0 +1,318 @@
+import Admonition from "@theme/Admonition";
+
+# Авторизация в тестах
+
+
+
+- Как работают команды `saveState` и `restoreState`
+- Как сохранить сессию авторизации и переиспользовать её в тестах
+- Как работать с несколькими аккаунтами и ролями
+- Лучшие практики хранения состояния и работы с параллельными тестами
+
+
+
+## Введение
+
+При запуске тестов браузер не содержит данных авторизации. Выполнять вход в каждом тесте неэффективно: это увеличивает время прогона и создаёт зависимость от стабильности формы логина.
+
+Команды [`saveState`](../commands/browser/saveState.mdx) и [`restoreState`](../commands/browser/restoreState.mdx) позволяют сохранить состояние браузера (cookies, localStorage, sessionStorage) после однократной авторизации и восстанавливать его в последующих тестах.
+
+## Как работают команды
+
+### saveState
+
+Команда [`saveState`](../commands/browser/saveState.mdx) сохраняет текущее состояние браузера: cookies, localStorage и sessionStorage. Данные можно сохранить в файл или в переменную.
+
+```typescript
+// Сохранение в файл
+await browser.saveState({ path: "./state.json" });
+
+// Сохранение в переменную
+const state = await browser.saveState();
+```
+
+Для страниц с iframe данные storage сохраняются отдельно для каждого origin. IndexedDB в сохраняемое состояние не входит.
+
+### restoreState
+
+Команда [`restoreState`](../commands/browser/restoreState.mdx) восстанавливает ранее сохранённое состояние.
+
+```typescript
+// Восстановление из файла
+await browser.restoreState({ path: "./state.json" });
+
+// Восстановление из переменной
+await browser.restoreState({ data: state });
+```
+
+
+ Перед вызовом `restoreState` откройте страницу нужного домена командой
+ [`url`](../commands/browser/url.mdx). Это техническое ограничение браузера: localStorage и
+ sessionStorage привязаны к origin, а cookies можно установить только для текущего домена.
+
+
+По умолчанию после восстановления состояния страница перезагружается (`refresh: true`). Это нужно, чтобы приложение «увидело» восстановленные данные.
+
+### Работа с cookies напрямую
+
+Если авторизация хранится только в cookies и localStorage/sessionStorage не нужны, можно использовать команды [`getCookies`](../commands/browser/getCookies.mdx), [`setCookies`](../commands/browser/setCookies.mdx) и [`deleteCookies`](../commands/browser/deleteCookies.mdx):
+
+```typescript
+// Получить cookies
+const cookies = await browser.getCookies();
+
+// Установить cookies
+await browser.setCookies([{ name: "session", value: "abc123", domain: ".example.com" }]);
+
+// Удалить конкретный cookie
+await browser.deleteCookies("session");
+```
+
+## Базовый сценарий: один аккаунт
+
+В этом варианте авторизация выполняется один раз в `beforeAll`, после чего состояние сохраняется в файл. Перед каждым тестом плагин [`@testplane/global-hook`](../plugins/testplane-global-hook.mdx) открывает приложение и восстанавливает сохранённое состояние, чтобы тесты начинались уже с готовой авторизацией.
+
+
+
+ Пример конфигурации
+
+ ```typescript title="testplane.config.ts"
+
+ import path from "node:path";
+ import type { ConfigInput, WdioBrowser } from "testplane";
+ import { launchBrowser } from "testplane/unstable";
+
+ const baseUrl = "http://localhost:3000";
+ const statePath = path.resolve(process.cwd(), ".testplane", "states", "user.json");
+
+ async function login(browser: WdioBrowser) {
+ await browser.url(`${baseUrl}/login`);
+ await browser.$("#email").setValue(process.env.E2E_USER_EMAIL);
+ await browser.$("#password").setValue(process.env.E2E_USER_PASSWORD);
+ await browser.$("#submit").click();
+ await browser.$("#welcome").waitForDisplayed();
+ }
+
+ export default {
+ gridUrl: "local",
+
+ browsers: {
+ chrome: {
+ desiredCapabilities: {
+ browserName: "chrome"
+ }
+ }
+ },
+
+ sets: {
+ desktop: {
+ files: ["testplane/**/*.e2e.ts"],
+ browsers: ["chrome"]
+ }
+ },
+
+ beforeAll: async ({ config }) => {
+ const browser = await launchBrowser(config.browsers.chrome!);
+
+ await login(browser);
+ await browser.saveState({ path: statePath });
+
+ await browser.deleteSession();
+ },
+
+ plugins: {
+ "@testplane/global-hook": {
+ enabled: true,
+
+ beforeEach: async ({ browser }: { browser: WdioBrowser }) => {
+ await browser.url(baseUrl);
+ await browser.restoreState({ path: statePath });
+ }
+ }
+ }
+
+ } satisfies ConfigInput;
+ ```
+
+
+
+
+
+ Пример теста
+
+ ```typescript title="example.testplane.ts"
+ const baseUrl = "http://localhost:3000";
+
+ describe("авторизованный пользователь", () => {
+ it("открывает дашборд без повторного логина", async ({ browser }) => {
+ await browser.url(`${baseUrl}/dashboard`);
+
+ await expect(browser.$("#role")).toHaveTextContaining("user");
+ });
+
+ it("восстанавливает localStorage и sessionStorage", async ({ browser }) => {
+ await browser.url(`${baseUrl}/dashboard`);
+
+ const email = await browser.execute(() => localStorage.getItem("auth.email"));
+ const role = await browser.execute(() => localStorage.getItem("auth.role"));
+ const bannerDismissed = await browser.execute(() =>
+ sessionStorage.getItem("feature.bannerDismissed")
+ );
+
+ expect(email).toBe(process.env.E2E_USER_EMAIL);
+ expect(role).toBe("user");
+ expect(bannerDismissed).toBe("true");
+ });
+ });
+ ```
+
+
+
+- `beforeAll` выполняет логин только один раз и сохраняет снимок браузера в файл.
+- `@testplane/global-hook` выносит повторяющуюся логику восстановления состояния из самих тестов в общий `beforeEach`.
+- Перед `restoreState` обязательно вызывается `browser.url(baseUrl)`, иначе браузер не сможет корректно восстановить cookies и storage для нужного origin.
+
+## Несколько аккаунтов (admin + user)
+
+В этом варианте в `beforeAll` подготавливаются два снимка состояния: один для обычного пользователя, второй для администратора. Нужный снимок выбирается в `beforeEach`, а в тестах можно проверять различия в правах доступа и элементах интерфейса.
+
+
+
+ Пример конфигурации
+
+ ```typescript title="testplane.config.ts"
+
+ import path from "node:path";
+ import type { ConfigInput, WdioBrowser } from "testplane";
+ import { launchBrowser } from "testplane/unstable";
+
+ const baseUrl = "http://localhost:3000";
+ const stateDir = path.resolve(process.cwd(), ".testplane", "states");
+ const userStatePath = path.join(stateDir, "user.json");
+ const adminStatePath = path.join(stateDir, "admin.json");
+
+ async function login(browser: WdioBrowser, email: string, password: string) {
+ await browser.url(`${baseUrl}/login`);
+ await browser.$("#email").setValue(email);
+ await browser.$("#password").setValue(password);
+ await browser.$("#submit").click();
+ await browser.$("#welcome").waitForDisplayed();
+ }
+
+ async function clearClientState(browser: WdioBrowser) {
+ await browser.url(`${baseUrl}/login`);
+ await browser.execute(() => {
+ localStorage.clear();
+ sessionStorage.clear();
+ });
+ await browser.deleteCookies();
+ }
+
+ export default {
+ gridUrl: "local",
+
+ browsers: {
+ chrome: {
+ desiredCapabilities: {
+ browserName: "chrome"
+ }
+ }
+ },
+
+ sets: {
+ desktop: {
+ files: ["testplane/**/*.e2e.ts"],
+ browsers: ["chrome"]
+ }
+ },
+
+ beforeAll: async ({ config }) => {
+ const browser = await launchBrowser(config.browsers.chrome!);
+
+ await login(
+ browser,
+ process.env.E2E_USER_EMAIL,
+ process.env.E2E_USER_PASSWORD
+ );
+ await browser.saveState({ path: userStatePath });
+
+ await clearClientState(browser);
+
+ await login(
+ browser,
+ process.env.E2E_ADMIN_EMAIL,
+ process.env.E2E_ADMIN_PASSWORD
+ );
+ await browser.saveState({ path: adminStatePath });
+
+ await browser.deleteSession();
+ },
+
+ plugins: {
+ "@testplane/global-hook": {
+ enabled: true,
+
+ beforeEach: async ({ browser, currentTest }: {
+ browser: WdioBrowser;
+ currentTest: { title: string };
+ }) => {
+ const statePath = currentTest.title.includes("[admin]")
+ ? adminStatePath
+ : userStatePath;
+
+ await browser.url(baseUrl);
+ await browser.restoreState({ path: statePath });
+ }
+ }
+ }
+ } satisfies ConfigInput;
+ ```
+
+
+
+
+
+ Пример теста
+
+ ```typescript title="example.testplane.ts"
+ const baseUrl = "http://localhost:3000";
+
+ describe("аккаунты с разными ролями", () => {
+ it("открывает дашборд для обычного пользователя", async ({ browser }) => {
+ await browser.url(`${baseUrl}/dashboard`);
+
+ await expect(browser.$("#role")).toHaveTextContaining("user");
+ await expect(browser.$("#no-admin-message")).toBeDisplayed();
+ });
+
+ it("[admin] открывает дашборд для администратора", async ({ browser }) => {
+ await browser.url(`${baseUrl}/dashboard`);
+
+ await expect(browser.$("#role")).toHaveTextContaining("admin");
+ await expect(browser.$("#admin-link")).toBeDisplayed();
+ });
+
+ it("запрещает пользователю доступ к странице администратора", async ({ browser }) => {
+ await browser.url(`${baseUrl}/admin`);
+ await expect(browser.$("#forbidden-message")).toBeDisplayed();
+ });
+
+ it("[admin] разрешает администратору доступ к странице администратора", async ({ browser }) => {
+ await browser.url(`${baseUrl}/admin`);
+ await expect(browser.$("#manage-users")).toBeDisplayed();
+ });
+ });
+ ```
+
+
+
+- В `beforeAll` сохраняются два отдельных state-файла — по одному на роль, чтобы затем переиспользовать их в тестах.
+- В `beforeEach` выбирается нужный снимок состояния; в примере выбор завязан на название теста, но в реальном проекте это может быть любая удобная схема .
+- Такой подход позволяет наглядно показать, что один и тот же набор тестов можно запускать под разными ролями без повторного логина перед каждым кейсом.
+
+## Best practices
+
+- Не коммитьте state-файлы в репозиторий: в них могут содержаться cookies и другие чувствительные данные.
+- Храните логины и пароли в переменных окружения, а не в коде тестов.
+- Учитывайте срок жизни сессии: если снимок состояния устарел, его придётся пересоздать.
+- Если тесты изменяют данные на стороне сервера, один и тот же аккаунт может стать источником конфликтов при параллельном запуске. В таких случаях лучше готовить отдельные аккаунты на каждый конфликтующий сценарий.