seed(RolePermissionSeeder::class); Notification::fake(); } protected function actingWithRole(string $role): User { $user = User::factory()->create(); $user->syncRoles([$role]); $this->withHeaders($this->apiHeadersFor($user)); return $user; } #[Test] public function the_history_lists_each_change_with_who_made_it(): void { $editor = $this->actingWithRole('editor'); $project = Project::factory()->create(['status' => 'active']); $this->patchJson("/api/v1/projects/{$project->id}", ['status' => 'paused'])->assertOk(); $this->getJson("/api/v1/projects/{$project->id}/revisions") ->assertOk() ->assertJsonPath('data.0.event', 'updated') ->assertJsonPath('data.0.author.id', $editor->id) ->assertJsonPath('data.0.changes.status.new', 'paused'); } #[Test] public function a_change_is_undone_and_the_undoing_is_recorded(): void { $this->actingWithRole('editor'); $service = Service::factory()->create(['tagline' => ['es' => 'Antes']]); $this->patchJson("/api/v1/services/{$service->id}", ['tagline' => ['es' => 'Después']])->assertOk(); $revision = $service->revisions()->first(); $this->postJson("/api/v1/revisions/{$revision->id}/restore") ->assertOk() ->assertJsonPath('data.changes.tagline.new.es', 'Antes'); $this->assertSame('Antes', $service->fresh()->getTranslation('tagline', 'es')); $this->assertSame(3, $service->revisions()->count()); } #[Test] public function undoing_a_publication_takes_the_publish_permission(): void { $page = Page::factory()->draft()->create(); $this->actingAs($editor = User::factory()->create()->syncRoles(['editor'])); $page->update(['status' => PageStatus::Published, 'published_at' => now()]); $this->actingWithRole('writer'); $this->postJson('/api/v1/revisions/'.$page->revisions()->first()->id.'/restore') ->assertUnprocessable() ->assertJsonValidationErrors('revision'); $this->assertSame(PageStatus::Published, $page->fresh()->status); } #[Test] public function a_writer_asks_for_review_and_an_editor_sees_it_waiting(): void { $writer = $this->actingWithRole('writer'); $page = Page::factory()->draft()->create(); $this->postJson("/api/v1/pages/{$page->id}/review", ['note' => 'Lista para revisar.']) ->assertOk() ->assertJsonPath('data.awaiting_review', true) ->assertJsonPath('data.requested_by.id', $writer->id); $this->assertSame(PageStatus::Review, $page->fresh()->status); $this->postJson("/api/v1/pages/{$page->id}/review")->assertUnprocessable(); $this->actingWithRole('editor'); $this->getJson('/api/v1/reviews') ->assertOk() ->assertJsonCount(1, 'data') ->assertJsonPath('data.0.type', 'pages') ->assertJsonPath('data.0.id', $page->id); $this->getJson("/api/v1/pages/{$page->id}/reviews") ->assertJsonPath('data.0.event', 'requested') ->assertJsonPath('data.0.body', 'Lista para revisar.'); } #[Test] public function an_editor_returns_it_with_a_reason(): void { $this->actingAs(User::factory()->create()->syncRoles(['writer'])); $page = Page::factory()->draft()->create(); $page->requestReview(); $this->actingWithRole('editor'); $this->postJson("/api/v1/pages/{$page->id}/return", [])->assertUnprocessable(); $this->postJson("/api/v1/pages/{$page->id}/return", ['note' => 'Falta la imagen.']) ->assertOk() ->assertJsonPath('data.awaiting_review', false); $this->assertSame(PageStatus::Draft, $page->fresh()->status); } #[Test] public function publishing_later_answers_the_review_now(): void { $this->actingAs(User::factory()->create()->syncRoles(['writer'])); $project = Project::factory()->draft()->create(); $project->requestReview(); $this->actingWithRole('editor'); $at = now()->addDays(3)->startOfMinute(); $this->postJson("/api/v1/projects/{$project->id}/publish", ['at' => $at->toIso8601String()]) ->assertOk() ->assertJsonPath('data.published', false) ->assertJsonPath('data.awaiting_review', false) ->assertJsonPath('data.published_at', $at->toIso8601String()); // A date in the future is neither live nor taken down, and the // history says so. $this->assertSame('scheduled', $project->revisions()->first()->event); $this->postJson("/api/v1/projects/{$project->id}/unpublish") ->assertOk() ->assertJsonPath('data.published_at', null); } #[Test] public function a_writer_cannot_publish_or_return(): void { $this->actingWithRole('writer'); $service = Service::factory()->create(['is_published' => false]); $this->postJson("/api/v1/services/{$service->id}/publish")->assertForbidden(); $this->postJson("/api/v1/services/{$service->id}/return", ['note' => 'x'])->assertForbidden(); $this->assertFalse($service->fresh()->is_published); } #[Test] public function preview_links_open_that_draft_only(): void { config(['site.url' => 'https://pireon.test']); $this->actingWithRole('writer'); $page = Page::factory()->draft()->create(); $links = $this->postJson("/api/v1/pages/{$page->id}/preview") ->assertCreated() ->json('data.links'); $this->assertArrayHasKey('es', $links); $this->assertStringStartsWith('https://pireon.test/', $links['es']); parse_str((string) parse_url($links['es'], PHP_URL_QUERY), $query); $this->assertSame(['type' => 'page', 'id' => $page->id, 'locale' => 'es'], PreviewLink::open($query['preview'])); } #[Test] public function comments_join_the_thread(): void { $this->actingWithRole('editor'); $page = Page::factory()->create(); $this->postJson("/api/v1/pages/{$page->id}/comments", ['body' => '¿Revisamos el título?']) ->assertCreated() ->assertJsonPath('data.event', 'commented'); } }