add auth
This commit is contained in:
25
tests/e2e/auth.setup.ts
Normal file
25
tests/e2e/auth.setup.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { test as setup, expect } from '@playwright/test';
|
||||
|
||||
const authFile = 'playwright/.auth/user.json';
|
||||
|
||||
setup('authenticate', async ({ page }) => {
|
||||
// Переходим на главную - редирект на Keycloak
|
||||
await page.goto('/');
|
||||
|
||||
// Ждём страницу логина Keycloak
|
||||
await page.waitForURL(/auth\.vigdorov\.ru/, { timeout: 10000 });
|
||||
|
||||
// Вводим креды
|
||||
await page.getByRole('textbox', { name: 'Username or email' }).fill('testuser');
|
||||
await page.getByRole('textbox', { name: 'Password' }).fill('0');
|
||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||
|
||||
// Ждём редирект обратно на приложение
|
||||
await page.waitForURL('http://localhost:4000/', { timeout: 15000 });
|
||||
|
||||
// Ждём загрузки таблицы (значит авторизация прошла)
|
||||
await page.waitForSelector('table', { timeout: 10000 });
|
||||
|
||||
// Сохраняем состояние авторизации
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
155
tests/e2e/phase1.spec.ts
Normal file
155
tests/e2e/phase1.spec.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* E2E тесты для Фазы 1 Team Planner
|
||||
* - Базовая загрузка страницы
|
||||
* - Таблица идей
|
||||
* - Фильтры
|
||||
* - Создание идей
|
||||
* - Inline-редактирование
|
||||
* - Удаление
|
||||
*/
|
||||
|
||||
test.describe('Фаза 1: Базовый функционал', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
// Ждём загрузки таблицы
|
||||
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('Страница загружается', async ({ page }) => {
|
||||
await expect(page.locator('body')).toBeVisible();
|
||||
await expect(page).toHaveTitle(/.*/);
|
||||
});
|
||||
|
||||
test('Таблица идей отображается', async ({ page }) => {
|
||||
const table = page.locator('table, [role="grid"]');
|
||||
await expect(table).toBeVisible();
|
||||
});
|
||||
|
||||
test('Таблица имеет заголовки колонок', async ({ page }) => {
|
||||
const headers = page.locator('th, [role="columnheader"]');
|
||||
const count = await headers.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
|
||||
// Проверяем что есть хотя бы несколько важных колонок
|
||||
const headerTexts = await headers.allTextContents();
|
||||
expect(headerTexts.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('Фильтры присутствуют на странице', async ({ page }) => {
|
||||
// Ищем элементы фильтров (inputs, selects, MUI компоненты)
|
||||
const filterElements = page.locator('input, [role="combobox"], .MuiSelect-select');
|
||||
const count = await filterElements.count();
|
||||
expect(count).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
test('Поле поиска работает', async ({ page }) => {
|
||||
const searchInput = page.locator('input[placeholder*="Поиск"]');
|
||||
await expect(searchInput).toBeVisible();
|
||||
|
||||
await searchInput.fill('test');
|
||||
await expect(searchInput).toHaveValue('test');
|
||||
|
||||
// Очищаем
|
||||
await searchInput.clear();
|
||||
});
|
||||
|
||||
test('Кнопка создания идеи существует', async ({ page }) => {
|
||||
const buttons = page.locator('button');
|
||||
const createButton = buttons.filter({
|
||||
hasText: /создать|добавить|новая|\+/i,
|
||||
});
|
||||
|
||||
await expect(createButton.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Модалка создания открывается', async ({ page }) => {
|
||||
// Находим и кликаем кнопку создания
|
||||
const createButton = page
|
||||
.locator('button')
|
||||
.filter({ hasText: /создать|добавить|новая/i })
|
||||
.first();
|
||||
|
||||
await createButton.click();
|
||||
|
||||
// Проверяем что модалка открылась (используем .first() т.к. MUI создаёт вложенные элементы)
|
||||
const modal = page.locator('[role="dialog"]').first();
|
||||
await expect(modal).toBeVisible();
|
||||
|
||||
// Закрываем модалку
|
||||
await page.keyboard.press('Escape');
|
||||
await expect(modal).toBeHidden();
|
||||
});
|
||||
|
||||
test('Таблица показывает данные или empty state', async ({ page }) => {
|
||||
const rows = page.locator('tbody tr, [role="row"]');
|
||||
const rowCount = await rows.count();
|
||||
|
||||
if (rowCount > 1) {
|
||||
// Есть данные
|
||||
expect(rowCount).toBeGreaterThan(1);
|
||||
} else {
|
||||
// Ищем empty state
|
||||
const emptyState = page.locator('text=/нет|пусто|Нет идей/i');
|
||||
const hasEmptyState = (await emptyState.count()) > 0;
|
||||
expect(hasEmptyState || rowCount >= 1).toBeTruthy();
|
||||
}
|
||||
});
|
||||
|
||||
test('Пагинация присутствует', async ({ page }) => {
|
||||
const pagination = page.locator(
|
||||
'.MuiTablePagination-root, [aria-label*="pagination"], nav[aria-label*="pagination"]'
|
||||
);
|
||||
await expect(pagination.first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Inline-редактирование работает (double-click)', async ({ page }) => {
|
||||
// Находим ячейки таблицы (пропускаем первую - drag handle)
|
||||
const cells = page.locator('tbody td');
|
||||
const cellCount = await cells.count();
|
||||
|
||||
if (cellCount > 1) {
|
||||
// Пробуем double-click на ячейках (начиная со второй)
|
||||
for (let i = 1; i < Math.min(cellCount, 6); i++) {
|
||||
const cell = cells.nth(i);
|
||||
const text = await cell.textContent();
|
||||
|
||||
if (text && text.trim()) {
|
||||
await cell.dblclick();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Проверяем появился ли input для редактирования
|
||||
const input = page.locator(
|
||||
'.MuiInputBase-input, input.MuiInput-input, tbody input, [role="combobox"]'
|
||||
);
|
||||
const inputCount = await input.count();
|
||||
|
||||
if (inputCount > 0) {
|
||||
// Отменяем редактирование
|
||||
await page.keyboard.press('Escape');
|
||||
return; // Тест прошёл
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Если нет данных для inline-редактирования - это ОК
|
||||
expect(true).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Кнопка удаления в таблице', async ({ page }) => {
|
||||
// Ищем иконки/кнопки удаления в строках
|
||||
const deleteButtons = page.locator(
|
||||
'tbody button[aria-label*="delete"], tbody button[aria-label*="удалить"], tbody [data-testid="DeleteIcon"], tbody svg'
|
||||
);
|
||||
|
||||
const count = await deleteButtons.count();
|
||||
// Если есть данные, должны быть кнопки удаления
|
||||
const rows = await page.locator('tbody tr').count();
|
||||
|
||||
if (rows > 0) {
|
||||
expect(count).toBeGreaterThanOrEqual(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
208
tests/e2e/phase2.spec.ts
Normal file
208
tests/e2e/phase2.spec.ts
Normal file
@ -0,0 +1,208 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* E2E тесты для Фазы 2 Team Planner
|
||||
* - Drag & Drop
|
||||
* - Цветовая маркировка
|
||||
* - Комментарии
|
||||
* - Управление командой
|
||||
*/
|
||||
|
||||
test.describe('Фаза 2: Drag & Drop', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('Drag handle присутствует в таблице', async ({ page }) => {
|
||||
// Ждём загрузки строк таблицы
|
||||
await page.waitForSelector('tbody tr', { timeout: 10000 });
|
||||
|
||||
// Drag handle — это div с aria-roledescription="sortable" (dnd-kit)
|
||||
const handles = page.locator('[aria-roledescription="sortable"]');
|
||||
|
||||
// Ждём появления хотя бы одного handle
|
||||
await expect(handles.first()).toBeVisible({ timeout: 5000 });
|
||||
|
||||
const count = await handles.count();
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('Строки имеют drag handle для сортировки', async ({ page }) => {
|
||||
// Ждём загрузки строк таблицы
|
||||
await page.waitForSelector('tbody tr', { timeout: 10000 });
|
||||
|
||||
// dnd-kit добавляет aria-roledescription="sortable" на drag handle
|
||||
const handles = page.locator('[aria-roledescription="sortable"]');
|
||||
await expect(handles.first()).toBeVisible({ timeout: 5000 });
|
||||
|
||||
const count = await handles.count();
|
||||
const totalRows = await page.locator('tbody tr').count();
|
||||
|
||||
// Все строки должны иметь drag handle
|
||||
expect(count).toBe(totalRows);
|
||||
});
|
||||
|
||||
test('Визуальное перетаскивание работает', async ({ page }) => {
|
||||
const rows = page.locator('tbody tr');
|
||||
const rowCount = await rows.count();
|
||||
|
||||
if (rowCount >= 2) {
|
||||
const firstRow = rows.first();
|
||||
const handle = firstRow.locator('td:first-child svg, td:first-child').first();
|
||||
|
||||
// Начинаем перетаскивание
|
||||
const box = await handle.boundingBox();
|
||||
if (box) {
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2 + 50);
|
||||
await page.waitForTimeout(300);
|
||||
|
||||
// Проверяем появление визуальной индикации
|
||||
const overlay = page.locator(
|
||||
'[data-dnd-kit-drag-overlay], ' + '.drag-overlay, ' + '[style*="position: fixed"]'
|
||||
);
|
||||
|
||||
await page.mouse.up();
|
||||
|
||||
// Drag action выполнен успешно
|
||||
expect(true).toBeTruthy();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Фаза 2: Цветовая маркировка', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('Колонка цвета присутствует', async ({ page }) => {
|
||||
const headers = page.locator('th, [role="columnheader"]');
|
||||
const headerTexts = await headers.allTextContents();
|
||||
|
||||
const hasColorColumn = headerTexts.some(
|
||||
(text) => text.toLowerCase().includes('цвет') || text.toLowerCase().includes('color')
|
||||
);
|
||||
|
||||
// Фича может быть ещё не реализована - отмечаем как skip
|
||||
test.skip(!hasColorColumn, 'Колонка цвета ещё не реализована');
|
||||
expect(hasColorColumn).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Color picker или индикаторы доступны', async ({ page }) => {
|
||||
const colorElements = page.locator(
|
||||
'input[type="color"], ' +
|
||||
'.color-picker, ' +
|
||||
'[aria-label*="цвет" i], ' +
|
||||
'[aria-label*="color" i], ' +
|
||||
'tbody [style*="background"]'
|
||||
);
|
||||
|
||||
const count = await colorElements.count();
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(count === 0, 'Color picker ещё не реализован');
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('Строки могут иметь цветной фон', async ({ page }) => {
|
||||
const rows = page.locator('tbody tr');
|
||||
const rowCount = await rows.count();
|
||||
let coloredRows = 0;
|
||||
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
const row = rows.nth(i);
|
||||
const bg = await row.evaluate((el) => getComputedStyle(el).backgroundColor);
|
||||
|
||||
// Проверяем что фон не прозрачный и не белый
|
||||
if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'rgb(255, 255, 255)') {
|
||||
coloredRows++;
|
||||
}
|
||||
}
|
||||
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(coloredRows === 0, 'Цветные строки ещё не реализованы');
|
||||
expect(coloredRows).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Фаза 2: Комментарии', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('table, [role="grid"]', { timeout: 10000 });
|
||||
});
|
||||
|
||||
test('Кнопка комментариев присутствует', async ({ page }) => {
|
||||
const commentButtons = page.locator(
|
||||
'[aria-label*="комментар" i], ' +
|
||||
'[aria-label*="comment" i], ' +
|
||||
'button svg[data-testid*="Comment"], ' +
|
||||
'[data-testid="CommentIcon"], ' +
|
||||
'[data-testid="ChatBubbleIcon"]'
|
||||
);
|
||||
|
||||
const count = await commentButtons.count();
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(count === 0, 'Комментарии ещё не реализованы');
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test('Секция комментариев существует', async ({ page }) => {
|
||||
const commentsSection = page.locator(
|
||||
'.comments-section, ' +
|
||||
'[class*="comment"], ' +
|
||||
'[data-testid*="comment"], ' +
|
||||
'textarea[placeholder*="комментар" i]'
|
||||
);
|
||||
|
||||
const count = await commentsSection.count();
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(count === 0, 'Секция комментариев ещё не реализована');
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Фаза 2: Управление командой', () => {
|
||||
test('Страница /team существует', async ({ page }) => {
|
||||
await page.goto('/team');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const bodyText = await page.locator('body').textContent();
|
||||
const is404 =
|
||||
bodyText?.toLowerCase().includes('404') || bodyText?.toLowerCase().includes('not found');
|
||||
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(is404, 'Страница /team ещё не реализована');
|
||||
expect(is404).toBeFalsy();
|
||||
});
|
||||
|
||||
test('Ссылка на команду в навигации', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('body');
|
||||
|
||||
const teamLinks = page.locator('a[href*="team"], nav a, [role="navigation"] a');
|
||||
const allLinks = await teamLinks.allTextContents();
|
||||
|
||||
const hasTeamLink = allLinks.some(
|
||||
(text) => text.toLowerCase().includes('команд') || text.toLowerCase().includes('team')
|
||||
);
|
||||
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(!hasTeamLink, 'Навигация на команду ещё не реализована');
|
||||
expect(hasTeamLink).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Таблица участников команды', async ({ page }) => {
|
||||
await page.goto('/team');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const table = page.locator('table, [role="grid"]');
|
||||
const count = await table.count();
|
||||
|
||||
// Фича может быть ещё не реализована
|
||||
test.skip(count === 0, 'Таблица команды ещё не реализована');
|
||||
expect(count).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
78
tests/package-lock.json
generated
Normal file
78
tests/package-lock.json
generated
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"name": "team-planner-e2e",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "team-planner-e2e",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.40.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.57.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz",
|
||||
"integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.57.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.57.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz",
|
||||
"integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.57.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.57.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz",
|
||||
"integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
tests/package.json
Normal file
16
tests/package.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "team-planner-e2e",
|
||||
"version": "1.0.0",
|
||||
"description": "E2E тесты для Team Planner",
|
||||
"scripts": {
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui",
|
||||
"test:headed": "playwright test --headed",
|
||||
"test:phase1": "playwright test phase1.spec.ts",
|
||||
"test:phase2": "playwright test phase2.spec.ts",
|
||||
"report": "playwright show-report"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.40.0"
|
||||
}
|
||||
}
|
||||
34
tests/playwright.config.ts
Normal file
34
tests/playwright.config.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './e2e',
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: 'html',
|
||||
|
||||
use: {
|
||||
baseURL: 'http://localhost:4000',
|
||||
trace: 'on-first-retry',
|
||||
screenshot: 'only-on-failure',
|
||||
},
|
||||
|
||||
projects: [
|
||||
// Setup project - авторизация
|
||||
{
|
||||
name: 'setup',
|
||||
testMatch: /.*\.setup\.ts/,
|
||||
},
|
||||
|
||||
// Основные тесты - используют сохранённую авторизацию
|
||||
{
|
||||
name: 'chromium',
|
||||
use: {
|
||||
...devices['Desktop Chrome'],
|
||||
storageState: 'playwright/.auth/user.json',
|
||||
},
|
||||
dependencies: ['setup'],
|
||||
},
|
||||
],
|
||||
});
|
||||
45
tests/playwright/.auth/user.json
Normal file
45
tests/playwright/.auth/user.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"cookies": [
|
||||
{
|
||||
"name": "AUTH_SESSION_ID",
|
||||
"value": "MkdCeDFEb21wOHQ5Q19seWs2ZlNZaGVELkZyajNfUDlQMGZlMWlqWUVVNkxQTXZ5NEQ3U2NaLW8zeXR3Tk1nTjNLdTVtcVZTY3JxWnduV01Cc0xodmJnLVd2a1E4SHVJbWJWcDlieEdOU1dYSm5B.keycloak-keycloakx-0-27122",
|
||||
"domain": "auth.vigdorov.ru",
|
||||
"path": "/realms/team-planner/",
|
||||
"expires": -1,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "None"
|
||||
},
|
||||
{
|
||||
"name": "KC_AUTH_SESSION_HASH",
|
||||
"value": "\"pLzIGfYFD8RX7GW+uEm+YT/ECPbJUQyFtcksML49rHY\"",
|
||||
"domain": "auth.vigdorov.ru",
|
||||
"path": "/realms/team-planner/",
|
||||
"expires": 1768340584.145523,
|
||||
"httpOnly": false,
|
||||
"secure": true,
|
||||
"sameSite": "None"
|
||||
},
|
||||
{
|
||||
"name": "KEYCLOAK_IDENTITY",
|
||||
"value": "eyJhbGciOiJIUzUxMiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2ZDRjMWU2My1hNTllLTQ0NjAtYThkYy05YTRiZjFjMTRjMDMifQ.eyJleHAiOjE3NjgzNzY1MjcsImlhdCI6MTc2ODM0MDUyNywianRpIjoiODAyMWRlMzQtYWIzMy0wOGE1LTEwMGUtMzcyNDZiNTQwZTRmIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLnZpZ2Rvcm92LnJ1L3JlYWxtcy90ZWFtLXBsYW5uZXIiLCJzdWIiOiIyZDJiOTRmMC0xZWQ1LTQ0MTUtYmM4MC1jZTRlZWMxNDQ1NGQiLCJ0eXAiOiJTZXJpYWxpemVkLUlEIiwic2lkIjoiMkdCeDFEb21wOHQ5Q19seWs2ZlNZaGVEIiwic3RhdGVfY2hlY2tlciI6Im1KMW5ReHlVNVBvdUlPV0NXc1otMWlzYmpfejAxa21qTWt2U2xTVEx6RVkifQ.GBtVMik4s9okAtfiDRj-E12VoQL4RKb11QVO8zSXCMguz0Hmu4gL3n8BgZLS4nkhqIUmPGbijdNgrPaoyebyMQ",
|
||||
"domain": "auth.vigdorov.ru",
|
||||
"path": "/realms/team-planner/",
|
||||
"expires": -1,
|
||||
"httpOnly": true,
|
||||
"secure": true,
|
||||
"sameSite": "None"
|
||||
},
|
||||
{
|
||||
"name": "KEYCLOAK_SESSION",
|
||||
"value": "pLzIGfYFD8RX7GW-uEm-YT_ECPbJUQyFtcksML49rHY",
|
||||
"domain": "auth.vigdorov.ru",
|
||||
"path": "/realms/team-planner/",
|
||||
"expires": 1768376527.37812,
|
||||
"httpOnly": false,
|
||||
"secure": true,
|
||||
"sameSite": "None"
|
||||
}
|
||||
],
|
||||
"origins": []
|
||||
}
|
||||
4
tests/test-results/.last-run.json
Normal file
4
tests/test-results/.last-run.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"failedTests": []
|
||||
}
|
||||
Reference in New Issue
Block a user