test(automation-rules): cover apply job execution and failure branches

ApplySingleAutomationRuleJob was only ever asserted to be *pushed* under
Queue::fake() — its handle() body (chunked apply, progress accumulation)
and failed() branch had no coverage. ReEvaluateTransactionRulesJob's
failed() branch was likewise untested.

Add direct handle() and failed() tests for the apply job, and a failed()
test for the re-evaluate job, pinning the progress-cache payloads so the
'failed' status and preserved counts can't silently drift.
This commit is contained in:
Víctor Falcón 2026-07-03 13:27:56 +02:00
parent efe60282c8
commit a5697d886c
2 changed files with 68 additions and 0 deletions

View File

@ -290,6 +290,56 @@ test('apply endpoint queues a job when matches exceed threshold', function () {
Queue::assertPushed(ApplySingleAutomationRuleJob::class);
});
test('apply job applies the rule and records done progress', function () {
$t1 = Transaction::factory()->enableBanking()->create([
'user_id' => $this->user->id,
'account_id' => $this->account->id,
'description' => 'Grocery Store',
'amount' => -5000,
'category_id' => null,
]);
$t2 = Transaction::factory()->enableBanking()->create([
'user_id' => $this->user->id,
'account_id' => $this->account->id,
'description' => 'Grocery Store',
'amount' => -3000,
'category_id' => null,
]);
$jobId = 'apply-run-1';
(new ApplySingleAutomationRuleJob($this->rule, $jobId, [$t1->id, $t2->id]))
->handle(app(AutomationRuleService::class));
expect($t1->fresh()->category_id)->toBe($this->category->id)
->and($t2->fresh()->category_id)->toBe($this->category->id);
$progress = Cache::get(ApplySingleAutomationRuleJob::cacheKeyForJobId($this->user->id, $jobId));
expect($progress['status'])->toBe('done')
->and($progress['total'])->toBe(2)
->and($progress['processed'])->toBe(2)
->and($progress['applied'])->toBe(2)
->and($progress['updated'])->toBe(2);
});
test('apply job marks cache as failed and preserves counts', function () {
$jobId = 'apply-failed';
Cache::put(
ApplySingleAutomationRuleJob::cacheKeyForJobId($this->user->id, $jobId),
['status' => 'processing', 'processed' => 3, 'total' => 10, 'applied' => 3, 'updated' => 2],
now()->addHour(),
);
(new ApplySingleAutomationRuleJob($this->rule, $jobId, ['x', 'y']))
->failed(new RuntimeException('boom'));
$progress = Cache::get(ApplySingleAutomationRuleJob::cacheKeyForJobId($this->user->id, $jobId));
expect($progress['status'])->toBe('failed')
->and($progress['processed'])->toBe(3)
->and($progress['total'])->toBe(10)
->and($progress['applied'])->toBe(3)
->and($progress['updated'])->toBe(2);
});
test('apply endpoint returns done with zero matches when no transactions match', function () {
Transaction::factory()->enableBanking()->create([
'user_id' => $this->user->id,

View File

@ -337,6 +337,24 @@ test('job queries automation rules once regardless of transaction count', functi
expect($ruleQueries)->toBe(1);
});
test('job marks cache as failed and preserves counts', function () {
$jobId = 'reeval-failed';
Cache::put(
ReEvaluateTransactionRulesJob::cacheKeyForJobId($this->user->id, $jobId),
['status' => 'processing', 'processed' => 4, 'total' => 20, 'updated' => 2],
now()->addHour(),
);
(new ReEvaluateTransactionRulesJob($this->user, $jobId))
->failed(new RuntimeException('boom'));
$progress = Cache::get(ReEvaluateTransactionRulesJob::cacheKeyForJobId($this->user->id, $jobId));
expect($progress['status'])->toBe('failed')
->and($progress['processed'])->toBe(4)
->and($progress['total'])->toBe(20)
->and($progress['updated'])->toBe(2);
});
test('job skips encrypted transactions', function () {
AutomationRule::factory()->create([
'user_id' => $this->user->id,