feat(visitors): события регистрации и входа пишет backend, гость связывается с клиентом
Три точки: обычный вход, вход через 2FA (оба пути — код и резервный), подтверждение почты (именно там клиент реально создаётся, а не на /register). Учёт в try/catch — ошибка учёта не может уронить вход. Регресс авторизации 114/114. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use App\Services\Tracking\VisitTracker;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Tests\Concerns\SharesSupplierPdo;
|
||||
|
||||
uses(DatabaseTransactions::class);
|
||||
// VisitTracker пишет через pgsql_supplier — шарим PDO, иначе записи не видны под транзакцией.
|
||||
uses(SharesSupplierPdo::class);
|
||||
|
||||
beforeEach(function () {
|
||||
DB::table('site_events')->delete();
|
||||
DB::table('site_visitors')->delete();
|
||||
$this->tenant = Tenant::factory()->create();
|
||||
});
|
||||
|
||||
/** Гость, который уже был на лендинге (пришёл по смс). */
|
||||
function landingGuest(): string
|
||||
{
|
||||
return app(VisitTracker::class)->ensureVisitor(null, [
|
||||
'ip' => '176.59.133.176',
|
||||
'user_agent' => 'Mozilla/5.0 (Linux; Android 10; K)',
|
||||
'path' => '/',
|
||||
'utm' => ['utm_source' => 'sms'],
|
||||
]);
|
||||
}
|
||||
|
||||
test('успешный вход пишет login_done и связывает гостя с клиентом', function () {
|
||||
$vid = landingGuest();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'tenant_id' => $this->tenant->id,
|
||||
'email' => 'track-login@example.ru',
|
||||
'password_hash' => Hash::make('secret-pass-123'),
|
||||
'totp_enabled' => false,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$this->withCredentials()->withCookie('lid_vid', $vid)
|
||||
->postJson('/api/auth/login', [
|
||||
'email' => 'track-login@example.ru',
|
||||
'password' => 'secret-pass-123',
|
||||
])->assertOk();
|
||||
|
||||
expect(DB::table('site_events')->where('event', 'login_done')->count())->toBe(1);
|
||||
|
||||
$v = DB::table('site_visitors')->where('id', $vid)->first();
|
||||
expect((int) $v->user_id)->toBe($user->id);
|
||||
expect((int) $v->tenant_id)->toBe($this->tenant->id);
|
||||
expect((bool) $v->is_human)->toBeTrue();
|
||||
// Канал первого захода не перетёрся — именно он привёл клиента.
|
||||
expect($v->channel)->toBe('sms');
|
||||
});
|
||||
|
||||
test('вход без куки гостя не ломается и ничего не пишет', function () {
|
||||
User::factory()->create([
|
||||
'tenant_id' => $this->tenant->id,
|
||||
'email' => 'track-nocookie@example.ru',
|
||||
'password_hash' => Hash::make('secret-pass-123'),
|
||||
'totp_enabled' => false,
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$this->postJson('/api/auth/login', [
|
||||
'email' => 'track-nocookie@example.ru',
|
||||
'password' => 'secret-pass-123',
|
||||
])->assertOk();
|
||||
|
||||
expect(DB::table('site_events')->count())->toBe(0);
|
||||
expect(DB::table('site_visitors')->count())->toBe(0);
|
||||
});
|
||||
|
||||
test('подтверждение почты пишет register_done — регистрация состоялась', function () {
|
||||
$vid = landingGuest();
|
||||
|
||||
// Регистрация: код подтверждения в dev-режиме возвращается в ответе.
|
||||
$reg = $this->withCredentials()->withCookie('lid_vid', $vid)
|
||||
->postJson('/api/auth/register', [
|
||||
'email' => 'track-reg@example.ru',
|
||||
'password' => 'fresh-pass-123',
|
||||
'accept_offer' => true,
|
||||
'accept_pdn' => true,
|
||||
'captcha_token' => 'tok-123',
|
||||
]);
|
||||
|
||||
$code = $reg->json('_dev_plain_code');
|
||||
expect($code)->not->toBeNull('регистрация должна вернуть dev-код подтверждения');
|
||||
|
||||
$this->withCredentials()->withCookie('lid_vid', $vid)
|
||||
->postJson('/api/auth/confirm-email', [
|
||||
'email' => 'track-reg@example.ru',
|
||||
'code' => $code,
|
||||
])->assertOk();
|
||||
|
||||
expect(DB::table('site_events')->where('event', 'register_done')->count())->toBe(1);
|
||||
|
||||
$v = DB::table('site_visitors')->where('id', $vid)->first();
|
||||
expect($v->user_id)->not->toBeNull();
|
||||
expect($v->channel)->toBe('sms');
|
||||
});
|
||||
Reference in New Issue
Block a user