Files
landing-api/tests/Feature/Panel/TaskStreamPanelTest.php
Josep Piguillem 3c119d425e
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
Tests / test-postgres (push) Has been cancelled
Tests / mcp (push) Has been cancelled
Open a TaskStream board for a project that has none yet
The project form gets «Crear en TaskStream» while the project has no
board, and `taskstream: true` on a PATCH does the same through the API.
A refusal leaves the edit unsaved; a project with a board keeps it, and
`taskstream_key` without the flag is still ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 20:21:38 +02:00

173 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature\Panel;
use App\Filament\Resources\Projects\Pages\CreateProject;
use App\Filament\Resources\Projects\Pages\EditProject;
use App\Models\Project;
use App\Services\Pireon\AccessToken;
use App\Services\Pireon\TokenStore;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\Test;
use Tests\FakesPireon;
use Tests\TestCase;
/**
* The panel's way to open a project's board in TaskStream, as the person
* signed in: a toggle on the create form, or an action on a project that
* has none yet.
*/
class TaskStreamPanelTest extends TestCase
{
use FakesPireon, RefreshDatabase;
protected string $taskstream = 'https://api.taskstream.test';
protected function setUp(): void
{
parent::setUp();
$this->seed(RolePermissionSeeder::class);
$this->actingAs($this->userWithRoles('editor'));
config([
'services.taskstream.api_url' => $this->taskstream,
'services.taskstream.web_url' => 'https://taskstream.test',
]);
// What signing in to the panel leaves in the session.
app(TokenStore::class)->put(new AccessToken('session-token', null, now()->addHour()->toImmutable()));
}
protected function fakeTaskStream(int $status = 201, array $body = []): void
{
Http::fake([
"{$this->taskstream}/api/projects" => fn (Request $request) => Http::response(
$status === 201 ? ['id' => 'ts-1', 'key' => $request['key'], 'version' => 1] : $body,
$status,
),
]);
}
#[Test]
public function the_toggle_opens_a_board_with_the_session_token(): void
{
$this->fakeTaskStream();
Livewire::test(CreateProject::class)
->fillForm([
'title' => ['es' => 'Catálogo abierto'],
'slug' => ['es' => 'catalogo'],
'taskstream' => true,
])
->assertFormFieldExists('taskstream_key')
->call('create')
->assertHasNoFormErrors()
->assertNotified();
Http::assertSent(fn (Request $request) => $request->url() === "{$this->taskstream}/api/projects"
&& $request->hasHeader('Authorization', 'Bearer session-token')
&& $request['key'] === 'CATALOGO'
&& $request['isPublic'] === true);
$project = Project::query()->sole();
$this->assertSame('CATALOGO', $project->taskstream_key);
Livewire::test(EditProject::class, ['record' => $project->getRouteKey()])
->assertActionVisible('taskstream')
->assertActionHasUrl('taskstream', 'https://taskstream.test/p/CATALOGO')
->assertFormFieldDoesNotExist('taskstream');
}
#[Test]
public function without_the_toggle_taskstream_is_left_alone(): void
{
$this->fakeTaskStream();
Livewire::test(CreateProject::class)
->fillForm(['title' => ['es' => 'Solo aquí'], 'slug' => ['es' => 'solo-aqui']])
->assertFormFieldHidden('taskstream_key')
->call('create')
->assertHasNoFormErrors();
Http::assertNothingSent();
Livewire::test(EditProject::class, ['record' => Project::query()->sole()->getRouteKey()])
->assertActionHidden('taskstream');
}
#[Test]
public function a_refusal_shows_on_the_key_and_saves_nothing(): void
{
$this->fakeTaskStream(409, ['statusCode' => 409, 'message' => 'Project key WEB is already in use']);
Livewire::test(CreateProject::class)
->fillForm([
'title' => ['es' => 'Web'],
'slug' => ['es' => 'web'],
'taskstream' => true,
'taskstream_key' => 'web',
])
->call('create')
->assertHasFormErrors(['taskstream_key']);
$this->assertSame(0, Project::withTrashed()->count());
}
#[Test]
public function taskstream_being_down_saves_nothing(): void
{
Http::fake(["{$this->taskstream}/*" => Http::failedConnection()]);
Livewire::test(CreateProject::class)
->fillForm(['title' => ['es' => 'Web'], 'slug' => ['es' => 'web'], 'taskstream' => true])
->call('create')
->assertNotified(__('rules.taskstream.unavailable'));
$this->assertSame(0, Project::withTrashed()->count());
}
#[Test]
public function a_project_without_a_board_can_get_one_later(): void
{
$this->fakeTaskStream();
$project = Project::factory()->create(['slug' => ['es' => 'catalogo']]);
Livewire::test(EditProject::class, ['record' => $project->getRouteKey()])
->assertActionHidden('taskstream')
->assertActionVisible('createInTaskStream')
->callAction('createInTaskStream', data: ['key' => 'cat'])
->assertHasNoActionErrors()
->assertNotified();
Http::assertSent(fn (Request $request) => $request->hasHeader('Authorization', 'Bearer session-token')
&& $request['key'] === 'CAT'
&& $request['isPublic'] === true);
$this->assertSame('CAT', $project->fresh()->taskstream_key);
Livewire::test(EditProject::class, ['record' => $project->getRouteKey()])
->assertActionVisible('taskstream')
->assertActionHidden('createInTaskStream');
}
#[Test]
public function a_refusal_later_keeps_the_project_without_a_board(): void
{
$this->fakeTaskStream(409, ['statusCode' => 409, 'message' => 'Project key WEB is already in use']);
$project = Project::factory()->create();
Livewire::test(EditProject::class, ['record' => $project->getRouteKey()])
->callAction('createInTaskStream', data: ['key' => 'WEB'])
->assertNotified(__('rules.taskstream.refused', ['reason' => 'Project key WEB is already in use']));
$this->assertNull($project->fresh()->taskstream_key);
}
}