test: add authenticated staging smoke helper
This commit is contained in:
@@ -137,3 +137,11 @@ just ui-e2e
|
|||||||
```bash
|
```bash
|
||||||
just staging-smoke https://<domain>
|
just staging-smoke https://<domain>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Для browser-authenticated smoke на реальном стенде:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export CRANK_STAGING_ADMIN_EMAIL=owner@example.com
|
||||||
|
export CRANK_STAGING_ADMIN_PASSWORD=secret
|
||||||
|
just authenticated-staging-smoke https://<domain>
|
||||||
|
```
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
## Current
|
## Current
|
||||||
|
|
||||||
### `feat/authenticated-staging-pass`
|
### `feat/authenticated-staging-smoke-helper`
|
||||||
|
|
||||||
Status: completed
|
Status: completed
|
||||||
|
|
||||||
DoD:
|
DoD:
|
||||||
- authenticated staging pass template exists
|
- browser-authenticated staging smoke can be run against a real domain through env vars
|
||||||
- deploy smoke and staging notes docs link to the authenticated pass
|
- Playwright skips local webServer for remote runs
|
||||||
- README exposes the authenticated pass doc as the canonical next step after helper smoke
|
- docs and justfile expose the authenticated smoke helper
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
const { defineConfig, devices } = require('@playwright/test');
|
const { defineConfig, devices } = require('@playwright/test');
|
||||||
|
|
||||||
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:3300';
|
||||||
|
const skipWebServer = process.env.PLAYWRIGHT_SKIP_WEB_SERVER === '1';
|
||||||
|
|
||||||
module.exports = defineConfig({
|
module.exports = defineConfig({
|
||||||
testDir: './tests/e2e',
|
testDir: './tests/e2e',
|
||||||
fullyParallel: false,
|
fullyParallel: false,
|
||||||
@@ -13,15 +16,17 @@ module.exports = defineConfig({
|
|||||||
? [['github'], ['html', { open: 'never' }]]
|
? [['github'], ['html', { open: 'never' }]]
|
||||||
: [['list'], ['html', { open: 'never' }]],
|
: [['list'], ['html', { open: 'never' }]],
|
||||||
use: {
|
use: {
|
||||||
baseURL: process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:3300',
|
baseURL,
|
||||||
trace: 'on-first-retry',
|
trace: 'on-first-retry',
|
||||||
screenshot: 'only-on-failure',
|
screenshot: 'only-on-failure',
|
||||||
video: 'retain-on-failure',
|
video: 'retain-on-failure',
|
||||||
},
|
},
|
||||||
webServer: {
|
webServer: skipWebServer
|
||||||
|
? undefined
|
||||||
|
: {
|
||||||
command: 'bash scripts/playwright-stack.sh',
|
command: 'bash scripts/playwright-stack.sh',
|
||||||
cwd: __dirname,
|
cwd: __dirname,
|
||||||
url: (process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:3300') + '/login',
|
url: `${baseURL}/login`,
|
||||||
timeout: 600_000,
|
timeout: 600_000,
|
||||||
reuseExistingServer: false,
|
reuseExistingServer: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ function mapRoute(urlPath) {
|
|||||||
if (urlPath === '/api-keys') {
|
if (urlPath === '/api-keys') {
|
||||||
return path.join(ROOT_DIR, 'html', 'api-keys.html');
|
return path.join(ROOT_DIR, 'html', 'api-keys.html');
|
||||||
}
|
}
|
||||||
|
if (urlPath === '/secrets') {
|
||||||
|
return path.join(ROOT_DIR, 'html', 'secrets.html');
|
||||||
|
}
|
||||||
if (urlPath === '/logs') {
|
if (urlPath === '/logs') {
|
||||||
return path.join(ROOT_DIR, 'html', 'logs.html');
|
return path.join(ROOT_DIR, 'html', 'logs.html');
|
||||||
}
|
}
|
||||||
@@ -156,6 +159,10 @@ const server = http.createServer((request, response) => {
|
|||||||
redirect(response, '/api-keys');
|
redirect(response, '/api-keys');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (urlPath === '/html/secrets.html') {
|
||||||
|
redirect(response, '/secrets');
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (urlPath === '/html/logs.html') {
|
if (urlPath === '/html/logs.html') {
|
||||||
redirect(response, '/logs');
|
redirect(response, '/logs');
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
const { test, expect } = require('@playwright/test');
|
||||||
|
const { getSession, localized, login } = require('./helpers');
|
||||||
|
|
||||||
|
const CORE_PAGES = [
|
||||||
|
{ path: '/', heading: localized('Operations', 'Операции') },
|
||||||
|
{ path: '/agents', heading: localized('Agents', 'Агенты') },
|
||||||
|
{ path: '/api-keys', heading: localized('API Keys', 'API ключи') },
|
||||||
|
{ path: '/secrets', heading: localized('Secrets', 'Секреты') },
|
||||||
|
{ path: '/logs', heading: localized('Logs', 'Логи') },
|
||||||
|
{ path: '/usage', heading: localized('Usage', 'Использование') },
|
||||||
|
{ path: '/workspace-setup', heading: localized('Workspace', 'Воркспейс') },
|
||||||
|
{ path: '/settings', heading: localized('Settings', 'Настройки') },
|
||||||
|
{ path: '/stream-sessions', heading: localized('Stream Sessions', 'Stream Sessions') },
|
||||||
|
{ path: '/async-jobs', heading: localized('Async Jobs', 'Async Jobs') },
|
||||||
|
{ path: '/wizard/', heading: localized('Create', 'Создать') },
|
||||||
|
];
|
||||||
|
|
||||||
|
test('authenticated staging smoke logs in and exposes session json', async ({ page }) => {
|
||||||
|
await login(page);
|
||||||
|
|
||||||
|
const session = await getSession(page);
|
||||||
|
expect(session.user).toBeTruthy();
|
||||||
|
expect(Array.isArray(session.memberships)).toBe(true);
|
||||||
|
expect(session.memberships.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('authenticated staging smoke opens core pages without console errors', async ({ page }) => {
|
||||||
|
const pageErrors = [];
|
||||||
|
page.on('pageerror', (error) => {
|
||||||
|
pageErrors.push(error.message);
|
||||||
|
});
|
||||||
|
|
||||||
|
await login(page);
|
||||||
|
|
||||||
|
for (const pageSpec of CORE_PAGES) {
|
||||||
|
await page.goto(pageSpec.path);
|
||||||
|
await expect(page.locator('#login-form')).toHaveCount(0);
|
||||||
|
await expect(page.locator('body')).toContainText(pageSpec.heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(pageErrors).toEqual([]);
|
||||||
|
});
|
||||||
@@ -22,12 +22,22 @@
|
|||||||
|
|
||||||
- свежий deploy уже прошел helper smoke:
|
- свежий deploy уже прошел helper smoke:
|
||||||
- `just staging-smoke https://<domain>`
|
- `just staging-smoke https://<domain>`
|
||||||
|
- automated browser-authenticated smoke при необходимости запускается так:
|
||||||
|
- `CRANK_STAGING_ADMIN_EMAIL=... CRANK_STAGING_ADMIN_PASSWORD=... just authenticated-staging-smoke https://<domain>`
|
||||||
- известны bootstrap admin credentials;
|
- известны bootstrap admin credentials;
|
||||||
- на стенде есть demo data или подготовленный disposable workspace;
|
- на стенде есть demo data или подготовленный disposable workspace;
|
||||||
- браузер открыт с devtools, чтобы фиксировать network/console findings.
|
- браузер открыт с devtools, чтобы фиксировать network/console findings.
|
||||||
|
|
||||||
## 3. Канонический проход
|
## 3. Канонический проход
|
||||||
|
|
||||||
|
Перед ручным проходом можно прогнать automated baseline:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export CRANK_STAGING_ADMIN_EMAIL=owner@example.com
|
||||||
|
export CRANK_STAGING_ADMIN_PASSWORD=secret
|
||||||
|
just authenticated-staging-smoke https://<domain>
|
||||||
|
```
|
||||||
|
|
||||||
### 3.1. Login and shell
|
### 3.1. Login and shell
|
||||||
|
|
||||||
1. Открыть `/login`
|
1. Открыть `/login`
|
||||||
|
|||||||
@@ -29,3 +29,6 @@ ui-e2e:
|
|||||||
|
|
||||||
staging-smoke base_url:
|
staging-smoke base_url:
|
||||||
bash scripts/staging-smoke.sh {{base_url}}
|
bash scripts/staging-smoke.sh {{base_url}}
|
||||||
|
|
||||||
|
authenticated-staging-smoke base_url:
|
||||||
|
bash scripts/authenticated-staging-smoke.sh {{base_url}}
|
||||||
|
|||||||
@@ -9,3 +9,20 @@ Usage:
|
|||||||
```bash
|
```bash
|
||||||
./scripts/staging-smoke.sh https://rmcp.itexp.me
|
./scripts/staging-smoke.sh https://rmcp.itexp.me
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## authenticated-staging-smoke.sh
|
||||||
|
|
||||||
|
Browser-authenticated smoke helper for staging/production-like environments.
|
||||||
|
|
||||||
|
Required environment variables:
|
||||||
|
|
||||||
|
- `CRANK_STAGING_ADMIN_EMAIL`
|
||||||
|
- `CRANK_STAGING_ADMIN_PASSWORD`
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CRANK_STAGING_ADMIN_EMAIL=owner@example.com \
|
||||||
|
CRANK_STAGING_ADMIN_PASSWORD=secret \
|
||||||
|
./scripts/authenticated-staging-smoke.sh https://rmcp.itexp.me
|
||||||
|
```
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "usage: $0 <base-url>" >&2
|
||||||
|
echo "example: $0 https://rmcp.itexp.me" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${CRANK_STAGING_ADMIN_EMAIL:-}" ]]; then
|
||||||
|
echo "CRANK_STAGING_ADMIN_EMAIL is required" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "${CRANK_STAGING_ADMIN_PASSWORD:-}" ]]; then
|
||||||
|
echo "CRANK_STAGING_ADMIN_PASSWORD is required" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
|
||||||
|
BASE_URL="${1%/}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||||
|
|
||||||
|
echo "authenticated staging smoke: ${BASE_URL}"
|
||||||
|
|
||||||
|
cd "${REPO_ROOT}/apps/ui"
|
||||||
|
PLAYWRIGHT_BASE_URL="${BASE_URL}" \
|
||||||
|
PLAYWRIGHT_SKIP_WEB_SERVER=1 \
|
||||||
|
CRANK_E2E_ADMIN_EMAIL="${CRANK_STAGING_ADMIN_EMAIL}" \
|
||||||
|
CRANK_E2E_ADMIN_PASSWORD="${CRANK_STAGING_ADMIN_PASSWORD}" \
|
||||||
|
npx playwright test tests/e2e/staging-authenticated.spec.js
|
||||||
Reference in New Issue
Block a user