tenant = Tenant::factory()->create(); $this->token = app(ClientSmsUnsubscribeLinkService::class) ->tokenFor($this->tenant->id, '79990000067'); }); it('человек по ссылке отказывается — и попадает в стоп-лист того клиента', function () { $this->post("/s/{$this->token}")->assertRedirect(); $row = ClientSmsOptout::where('tenant_id', $this->tenant->id) ->where('phone', '79990000067') ->first(); expect($row)->not->toBeNull() ->and($row->source)->toBe(ClientSmsOptout::SOURCE_RECIPIENT); }); it('повторный отказ по той же ссылке не ломается', function () { $this->post("/s/{$this->token}")->assertRedirect(); $this->post("/s/{$this->token}")->assertRedirect(); expect(ClientSmsOptout::where('tenant_id', $this->tenant->id)->count())->toBe(1); }); it('страница не показывает номер целиком — только маской', function () { $this->get("/s/{$this->token}") ->assertOk() ->assertDontSee('79990000067') ->assertSee('** 67', false); }); it('неизвестный токен не выдаёт, существует он или нет', function () { $this->get('/s/zzzzzzzzzzzz')->assertNotFound(); }); it('перебор ссылок упирается в ограничение частоты', function () { $status = 200; foreach (range(1, 30) as $i) { $status = $this->get('/s/aaaaaaaaaaaa')->status(); if ($status === 429) { break; } } expect($status)->toBe(429); });