true, 'matched' => 437, 'actualCostRub' => '201.60', ]); expect($r->actualCostRub)->toBe('201.60'); expect($r->ok)->toBeTrue(); }); it('приводит числовой actualCostRub к строке', function () { $r = RobotResult::fromRobotJson([ 'ok' => true, 'actualCostRub' => 201.6, ]); expect($r->actualCostRub)->toBe('201.6'); expect($r->actualCostRub)->not->toBeNull(); }); it('без поля actualCostRub оставляет null и не ломает остальные поля', function () { $r = RobotResult::fromRobotJson([ 'ok' => true, 'matched' => 12, 'campaignId' => '555', ]); expect($r->actualCostRub)->toBeNull(); expect($r->ok)->toBeTrue(); expect($r->matched)->toBe(12); expect($r->campaignId)->toBe('555'); }); it('failed() не выставляет actualCostRub', function () { $r = RobotResult::failed('таймаут'); expect($r->actualCostRub)->toBeNull(); expect($r->ok)->toBeFalse(); expect($r->reason)->toBe('таймаут'); }); it('конструктор без actualCostRub даёт null по умолчанию', function () { $r = new RobotResult(ok: true); expect($r->actualCostRub)->toBeNull(); }); test('сырое слово кабинета доезжает до портала', function () { // 🔴 Без него запись «кабинет показал незнакомое слово» приходит БЕЗ самого слова. $r = RobotResult::fromRobotJson([ 'ok' => true, 'campaignId' => '2237821', 'status' => null, 'rowText' => '06.08 Telegram по своей базе Посмотреть настройки Приостановлена', ]); expect($r->rowText)->toContain('Приостановлена'); }); test('признак остановки читается', function () { expect(RobotResult::fromRobotJson(['ok' => true, 'stopped' => true])->stopped)->toBeTrue(); expect(RobotResult::fromRobotJson(['ok' => true])->stopped)->toBeFalse(); });