test(web): e2e голоса различает отсутствие пользователя и лимит частоты

Регистрация тестового пользователя выполнялась на любой неудачный вход, из-за
чего при `rate_limited` прогон падал на попытке регистрации. Теперь:
- 401 → пользователя нет, регистрируем; 429 → ждём `retry_after_ms` и повторяем;
- 409 при регистрации (аккаунт уже есть) → просто входим;
- число повторов увеличено до шести.
Прогон зелёный, аккаунт `voiceprobe` переиспользуется.
This commit is contained in:
2026-09-20 20:57:54 +03:00
parent 197c3d1a82
commit 8ae8ca1a1d
+23 -17
View File
@@ -127,7 +127,7 @@ async function postWithRetry(
api: APIRequestContext, api: APIRequestContext,
path: string, path: string,
data: Record<string, unknown>, data: Record<string, unknown>,
attempts = 4, attempts = 6,
): Promise<Awaited<ReturnType<APIRequestContext['post']>>> { ): Promise<Awaited<ReturnType<APIRequestContext['post']>>> {
let response = await api.post(path, { data }); let response = await api.post(path, { data });
for (let attempt = 1; attempt < attempts && response.status() === 429; attempt += 1) { for (let attempt = 1; attempt < attempts && response.status() === 429; attempt += 1) {
@@ -144,29 +144,35 @@ async function postWithRetry(
* нет — регистрирует. Один и тот же аккаунт переиспользуется между прогонами: * нет — регистрирует. Один и тот же аккаунт переиспользуется между прогонами:
* иначе каждый запуск оставлял бы в базе нового пользователя, а удалять * иначе каждый запуск оставлял бы в базе нового пользователя, а удалять
* пользователей API пока не умеет (это задача админ-панели Фазы 5). * пользователей API пока не умеет (это задача админ-панели Фазы 5).
*
* Важно различать «пользователя нет» (401 — тогда регистрируем) и «сработал
* лимит частоты» (429 — ждём и повторяем, иначе тест падал бы из-за защиты,
* которая обязана работать).
*/ */
async function ensureProbeGuest( async function ensureProbeGuest(
guest: APIRequestContext, guest: APIRequestContext,
): Promise<{ id: string; email: string; password: string }> { ): Promise<{ id: string; email: string; password: string }> {
const email = `${PROBE_LOGIN}@gl.mhspx.su`; const email = `${PROBE_LOGIN}@gl.mhspx.su`;
const password = 'Voice-Probe-Password-9x'; const password = 'Voice-Probe-Password-9x';
const login = await postWithRetry(guest, '/api/v1/auth/login', { email, password }); const credentials = { email, password };
if (login.ok()) { let login = await postWithRetry(guest, '/api/v1/auth/login', credentials);
const payload = (await login.json()) as { user: { id: string } }; if (login.status() === 429) {
await finishOnboarding(guest); throw new Error(`вход тестового пользователя упёрся в лимит частоты: ${await login.text()}`);
return { id: payload.user.id, email, password };
} }
const registered = await postWithRetry(guest, '/api/v1/auth/register', { if (!login.ok()) {
username: PROBE_LOGIN, const registered = await postWithRetry(guest, '/api/v1/auth/register', {
email, username: PROBE_LOGIN,
password, ...credentials,
}); });
expect( expect(
registered.ok(), registered.ok() || registered.status() === 409,
`тестовый пользователь ${PROBE_LOGIN} не найден и не зарегистрирован ` + `тестовый пользователь ${PROBE_LOGIN} не зарегистрирован: ${await registered.text()}`,
`(регистрация выключена?): ${await registered.text()}`, ).toBeTruthy();
).toBeTruthy(); // 409 — аккаунт уже существует (например, гонка прогонов): просто входим.
const payload = (await registered.json()) as { user: { id: string } }; login = await postWithRetry(guest, '/api/v1/auth/login', credentials);
}
expect(login.ok(), `вход тестового пользователя: ${await login.text()}`).toBeTruthy();
const payload = (await login.json()) as { user: { id: string } };
await finishOnboarding(guest); await finishOnboarding(guest);
return { id: payload.user.id, email, password }; return { id: payload.user.id, email, password };
} }