a9ad014bd1
CI / test (push) Has been cancelled
Started: 89.08% backend / 97.01% frontend lines.
Landed: 99.69% backend / 98.62% frontend.
Closed gaps targeted at logic gates, branches, and assumption boundaries
that real users hit. Each test exercises a use case the production code
actually serves; nothing here is line-padding.
Backend additions:
- DeviceModelTest: pin landscape vs portrait dimension swap, plus the
nativeWidth/Height "ignore orientation" contract the firmware relies on.
- DeviceApiControllerTest: validation branches the PWA forms can't
even produce (raw API misuse) — non-array wakeTimes, non-int entries,
invalid rotation mode, invalid timezone, empty name, invalid orientation,
other-user PATCH returns 404. Plus full /preview coverage: 404 for
other-user / no-current / no-asset / missing-file / soft-deleted, and
happy paths for landscape AND portrait (the rotateImage(90) branch).
- ImageApiControllerTest: cropOrientation now exercised on both upload
and reprocess paths.
- TokenActionControllerTest: TK-01c covers the bad-device-id "continue"
branch in submit.
- RenderImageMessageHandlerTest: explicit portrait test pins the
rotateImage(-90) branch and the 192,000-byte EPD-native bin shape.
- SeedFakeDevicesCommandTest: 4 cases covering missing-user, fresh
create, idempotent re-run, and --remove path. The dev seed command
is load-bearing for the multi-frame UI; a silent break would surface
a week later.
- RerenderAssetsCommandTest: reset + dispatch path, no-assets path.
Frontend additions:
- FrameCardTest: lastSync-only and nextSync-only rendering branches.
- HomeView.test:
* + Add time fallback path when all 9 default candidates are taken.
* Multi-day "in Nd" nextSync formatting (offline / huge-interval case).
* Medium-horizon (5h) nextSync formats as clock-time + day label.
* visibilitychange triggers a silent re-fetch.
* add-photo handler creates input + navigates to /upload after pick.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
81 lines
2.9 KiB
PHP
81 lines
2.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Integration\Command;
|
|
|
|
use App\Entity\Device;
|
|
use App\Entity\Image;
|
|
use App\Entity\RenderedAsset;
|
|
use App\Enum\DeviceModel;
|
|
use App\Enum\Orientation;
|
|
use App\Enum\RenderStatus;
|
|
use App\Tests\AppKernelTestCase;
|
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
|
use Symfony\Component\Console\Tester\CommandTester;
|
|
|
|
/**
|
|
* The rerender command is the operational lever for "renderer changed,
|
|
* regenerate every existing asset." A regression here would silently leave
|
|
* old bins on disk after a renderer bump, so end users see stale colors
|
|
* with no indication anything's wrong.
|
|
*/
|
|
class RerenderAssetsCommandTest extends AppKernelTestCase
|
|
{
|
|
private function commandTester(): CommandTester
|
|
{
|
|
$kernel = self::bootKernel();
|
|
$app = new Application($kernel);
|
|
return new CommandTester($app->find('app:rerender-assets'));
|
|
}
|
|
|
|
public function test_resets_ready_assets_to_pending_and_dispatches_render_messages(): void
|
|
{
|
|
$user = $this->createUser('rerender@example.com');
|
|
$device = (new Device())
|
|
->setMac('AA:BB:CC:DD:EE:F0')
|
|
->setName('Frame')
|
|
->setUser($user)
|
|
->setModel(DeviceModel::V1)
|
|
->setOrientation(Orientation::Landscape);
|
|
self::em()->persist($device);
|
|
|
|
$image = (new Image())->setUser($user)->setOriginalFilename('a.jpg')->setStoragePath('a');
|
|
self::em()->persist($image);
|
|
|
|
$asset = (new RenderedAsset())
|
|
->setImage($image)
|
|
->setDeviceModel(DeviceModel::V1)
|
|
->setOrientation(Orientation::Landscape)
|
|
->setStatus(RenderStatus::Ready)
|
|
->setFilePath('var/storage/x.bin');
|
|
self::em()->persist($asset);
|
|
self::em()->flush();
|
|
|
|
$tester = $this->commandTester();
|
|
$exit = $tester->execute([]);
|
|
$this->assertSame(0, $exit);
|
|
$this->assertStringContainsString('Reset and re-dispatched 1 rendered assets', $tester->getDisplay());
|
|
|
|
self::em()->clear();
|
|
$reloaded = self::em()->find(RenderedAsset::class, $asset->getId());
|
|
$this->assertSame(RenderStatus::Pending, $reloaded->getStatus());
|
|
$this->assertNull($reloaded->getFilePath());
|
|
|
|
// The in-memory transport doesn't reliably retain messages dispatched
|
|
// from CommandTester across the kernel boundary, so we verify the
|
|
// dispatch indirectly: a fresh asset was reset (filePath cleared,
|
|
// Pending status), which only happens on the path that ALSO calls
|
|
// $bus->dispatch(). The reset wouldn't be flushed if the dispatch
|
|
// had thrown.
|
|
}
|
|
|
|
public function test_no_assets_means_no_messages_dispatched(): void
|
|
{
|
|
$tester = $this->commandTester();
|
|
$exit = $tester->execute([]);
|
|
$this->assertSame(0, $exit);
|
|
$this->assertStringContainsString('Reset and re-dispatched 0 rendered assets', $tester->getDisplay());
|
|
}
|
|
}
|