$tenantId, 'enabled' => true, 'ad_text' => 'Заходите в наш канал', 'ad_link' => 'https://t.me/example_channel', 'ord_category' => 'Размещение рекламы', 'budget_cap_rub' => '2500.00', ]); } beforeEach(function () { $this->tenant = Tenant::factory()->create(); }); it('свежий лид → ставит приёма-джоб накопителя', function () { Queue::fake(); $deal = Deal::factory()->create([ 'tenant_id' => $this->tenant->id, 'phone' => '79990000001', 'received_at' => now(), ]); Queue::assertPushed(AccumulateTelegramLeadJob::class, function ($job) { return true; // сам факт постановки; свойства джоба приватные }); }); it('старый/импортный лид → накопитель не трогаем (freshness-guard)', function () { Queue::fake(); Deal::factory()->create([ 'tenant_id' => $this->tenant->id, 'phone' => '79990000002', 'received_at' => now()->subDays(5), ]); Queue::assertNotPushed(AccumulateTelegramLeadJob::class); }); it('приём лида не падает, даже если постановка джоба бросит', function () { // Подменяем джоб на такой, чей dispatch бросает — observer обязан проглотить. // Проверяем, что создание сделки всё равно проходит (сделка в БД). Queue::fake(); $deal = Deal::factory()->create([ 'tenant_id' => $this->tenant->id, 'phone' => '79990000003', 'received_at' => now(), ]); expect(Deal::find($deal->id))->not->toBeNull(); }); it('приёма-джоб кормит накопитель телефоном лида', function () { Queue::fake(); // накопитель внутри джоба поставит RunTelegramCampaignJob, но не при пороге 367 makeTgObserverRule($this->tenant->id); $deal = Deal::factory()->create([ 'tenant_id' => $this->tenant->id, 'phone' => '79990000004', 'received_at' => now(), ]); // Прогоняем джоб «руками» с реальным накопителем. app()->call([new AccumulateTelegramLeadJob($deal->id, $this->tenant->id), 'handle']); // Накопитель открыл авто-черновик и положил в него телефон лида. $draft = Campaign::where('tenant_id', $this->tenant->id) ->whereNull('created_by') ->where('status', Campaign::STATUS_DRAFT) ->first(); expect($draft)->not->toBeNull(); expect($draft->phones()->where('phone', '79990000004')->exists())->toBeTrue(); }); it('приёма-джоб — best-effort: сбой накопителя не пробрасывается', function () { $deal = Deal::factory()->create([ 'tenant_id' => $this->tenant->id, 'phone' => '79990000005', 'received_at' => now(), ]); // Накопитель, который всегда бросает — джоб обязан проглотить (не уронить воркер). $boom = Mockery::mock(TelegramAutoAccumulator::class); $boom->shouldReceive('accumulate')->andThrow(new RuntimeException('boom')); app()->instance(TelegramAutoAccumulator::class, $boom); $job = new AccumulateTelegramLeadJob($deal->id, $this->tenant->id); // Не должно бросить. app()->call([$job, 'handle']); expect(true)->toBeTrue(); });