From 0a116cd04c387d0f4c7417bacde4e10131a93353 Mon Sep 17 00:00:00 2001 From: James Cole Date: Mon, 25 Aug 2025 17:17:51 +0200 Subject: [PATCH] Add API autocomplete tests. --- .../Autocomplete/RuleGroupController.php | 1 + .../Api/Autocomplete/RuleControllerTest.php | 157 ++++++++++++++++++ .../Autocomplete/RuleGroupControllerTest.php | 146 ++++++++++++++++ .../Api/Autocomplete/TagControllerTest.php | 143 ++++++++++++++++ 4 files changed, 447 insertions(+) create mode 100644 tests/integration/Api/Autocomplete/RuleControllerTest.php create mode 100644 tests/integration/Api/Autocomplete/RuleGroupControllerTest.php create mode 100644 tests/integration/Api/Autocomplete/TagControllerTest.php diff --git a/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php b/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php index d5e42b6733..6882d76618 100644 --- a/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php +++ b/app/Api/V1/Controllers/Autocomplete/RuleGroupController.php @@ -69,6 +69,7 @@ class RuleGroupController extends Controller 'id' => (string) $group->id, 'name' => $group->title, 'description' => $group->description, + 'active' => $group->active, ]; } diff --git a/tests/integration/Api/Autocomplete/RuleControllerTest.php b/tests/integration/Api/Autocomplete/RuleControllerTest.php new file mode 100644 index 0000000000..3e650adf12 --- /dev/null +++ b/tests/integration/Api/Autocomplete/RuleControllerTest.php @@ -0,0 +1,157 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\integration\Api\Autocomplete; + +use FireflyIII\Models\Recurrence; +use FireflyIII\Models\Rule; +use FireflyIII\Models\RuleGroup; +use FireflyIII\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\integration\TestCase; + +/** + * @internal + * + * @coversNothing + */ +final class RuleControllerTest extends TestCase +{ + /** + * @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController + */ + use RefreshDatabase; + + private function createTestRules(int $count, User $user): void + { + $ruleGroup = RuleGroup::create( + [ + 'user_id' => $user->id, + 'user_group_id' => $user->user_group_id, + 'title' => 'RuleGroup 1', + 'description' => 'RuleGroup 1', + 'order' => 1, + 'active' => 1, + 'stop_processing' => 0, + ] + ); + for ($i = 1; $i <= $count; ++$i) { + $rule = Rule::create([ + 'user_id' => $user->id, + 'user_group_id' => $user->user_group_id, + 'rule_group_id' => $ruleGroup->id, + 'title' => 'Rule ' . $i, + 'description' => 'Rule ' . $i, + 'order' => 1, + 'active' => 1, + 'stop_processing' => 0, + 'strict' => 0, + ]); + } + } + + public function testUnauthenticatedCall(): void + { + // test API + $response = $this->get(route('api.v1.autocomplete.rules'), ['Accept' => 'application/json']); + $response->assertStatus(401); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}'); + } + + public function testAuthenticatedCall(): void + { + // act as a user + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $response = $this->get(route('api.v1.autocomplete.rules'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + } + + public function testGivenAuthenticatedRequestWithItems(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestRules(5, $user); + $response = $this->get(route('api.v1.autocomplete.rules'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertJsonCount(5); + $response->assertJsonFragment(['name' => 'Rule 1']); + $response->assertJsonStructure([ + '*' => [ + 'id', + 'name', + 'active', + ], + ]); + + } + + public function testGivenAuthenticatedRequestWithItemsLimited(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestRules(5, $user); + $response = $this->get(route('api.v1.autocomplete.rules', [ + 'query' => 'Rule', + 'limit' => 3, + ]), ['Accept' => 'application/json']); + + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertJsonCount(3); + $response->assertJsonFragment(['name' => 'Rule 1']); + $response->assertJsonStructure([ + '*' => [ + 'id', + 'name', + 'active', + ], + ]); + + } + + public function testGivenAuthenticatedRequestWithItemsLots(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestRules(20, $user); + $response = $this->get(route('api.v1.autocomplete.rules', [ + 'query' => 'Rule 1', + 'limit' => 20, + ]), ['Accept' => 'application/json']); + + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + // Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11) + $response->assertJsonCount(11); + $response->assertJsonMissing(['name' => 'Rule 2']); + } +} diff --git a/tests/integration/Api/Autocomplete/RuleGroupControllerTest.php b/tests/integration/Api/Autocomplete/RuleGroupControllerTest.php new file mode 100644 index 0000000000..570adaad5f --- /dev/null +++ b/tests/integration/Api/Autocomplete/RuleGroupControllerTest.php @@ -0,0 +1,146 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\integration\Api\Autocomplete; + +use FireflyIII\Models\Rule; +use FireflyIII\Models\RuleGroup; +use FireflyIII\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\integration\TestCase; + +/** + * @internal + * + * @coversNothing + */ +final class RuleGroupControllerTest extends TestCase +{ + /** + * @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController + */ + use RefreshDatabase; + + private function createTestRuleGroups(int $count, User $user): void + { + + for ($i = 1; $i <= $count; ++$i) { + $ruleGroup = RuleGroup::create( + [ + 'user_id' => $user->id, + 'user_group_id' => $user->user_group_id, + 'title' => 'RuleGroup ' . $i, + 'description' => 'RuleGroup '. $i, + 'order' => 1, + 'active' => 1, + 'stop_processing' => 0, + ] + ); + } + } + + public function testUnauthenticatedCall(): void + { + // test API + $response = $this->get(route('api.v1.autocomplete.rule-groups'), ['Accept' => 'application/json']); + $response->assertStatus(401); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}'); + } + + public function testAuthenticatedCall(): void + { + // act as a user + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $response = $this->get(route('api.v1.autocomplete.rule-groups'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + } + + public function testGivenAuthenticatedRequestWithItems(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestRuleGroups(5, $user); + $response = $this->get(route('api.v1.autocomplete.rule-groups'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertJsonCount(5); + $response->assertJsonFragment(['name' => 'RuleGroup 1']); + $response->assertJsonStructure([ + '*' => [ + 'id', + 'name', + 'active', + ], + ]); + + } + + public function testGivenAuthenticatedRequestWithItemsLimited(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestRuleGroups(5, $user); + $response = $this->get(route('api.v1.autocomplete.rule-groups', [ + 'query' => 'RuleGroup', + 'limit' => 3, + ]), ['Accept' => 'application/json']); + + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertJsonCount(3); + $response->assertJsonFragment(['name' => 'RuleGroup 1']); + $response->assertJsonStructure([ + '*' => [ + 'id', + 'name', + 'active', + ], + ]); + + } + + public function testGivenAuthenticatedRequestWithItemsLots(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestRuleGroups(20, $user); + $response = $this->get(route('api.v1.autocomplete.rule-groups', [ + 'query' => 'RuleGroup 1', + 'limit' => 20, + ]), ['Accept' => 'application/json']); + + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + // Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11) + $response->assertJsonCount(11); + $response->assertJsonMissing(['name' => 'RuleGroup 2']); + } +} diff --git a/tests/integration/Api/Autocomplete/TagControllerTest.php b/tests/integration/Api/Autocomplete/TagControllerTest.php new file mode 100644 index 0000000000..33f0caaa3b --- /dev/null +++ b/tests/integration/Api/Autocomplete/TagControllerTest.php @@ -0,0 +1,143 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\integration\Api\Autocomplete; + +use FireflyIII\Models\RuleGroup; +use FireflyIII\Models\Tag; +use FireflyIII\User; +use Illuminate\Foundation\Testing\RefreshDatabase; +use Tests\integration\TestCase; + +/** + * @internal + * + * @coversNothing + */ +final class TagControllerTest extends TestCase +{ + /** + * @covers \FireflyIII\Api\V1\Controllers\Autocomplete\RecurrenceController + */ + use RefreshDatabase; + + private function createTestTags(int $count, User $user): void + { + + for ($i = 1; $i <= $count; ++$i) { + $tag = Tag::create( + [ + 'user_id' => $user->id, + 'user_group_id' => $user->user_group_id, + 'tag' => 'Tag ' . $i, + 'tag_mode' => 'nothing', + ] + ); + } + } + + public function testUnauthenticatedCall(): void + { + // test API + $response = $this->get(route('api.v1.autocomplete.tags'), ['Accept' => 'application/json']); + $response->assertStatus(401); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertContent('{"message":"Unauthenticated.","exception":"AuthenticationException"}'); + } + + public function testAuthenticatedCall(): void + { + // act as a user + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $response = $this->get(route('api.v1.autocomplete.tags'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + } + + public function testGivenAuthenticatedRequestWithItems(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestTags(5, $user); + $response = $this->get(route('api.v1.autocomplete.tags'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertJsonCount(5); + $response->assertJsonFragment(['name' => 'Tag 1']); + $response->assertJsonStructure([ + '*' => [ + 'id', + 'name', + 'tag', + ], + ]); + + } + + public function testGivenAuthenticatedRequestWithItemsLimited(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestTags(5, $user); + $response = $this->get(route('api.v1.autocomplete.tags', [ + 'query' => 'Tag', + 'limit' => 3, + ]), ['Accept' => 'application/json']); + + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + $response->assertJsonCount(3); + $response->assertJsonFragment(['name' => 'Tag 1']); + $response->assertJsonStructure([ + '*' => [ + 'id', + 'name', + 'tag', + ], + ]); + + } + + public function testGivenAuthenticatedRequestWithItemsLots(): void + { + $user = $this->createAuthenticatedUser(); + $this->actingAs($user); + + $this->createTestTags(20, $user); + $response = $this->get(route('api.v1.autocomplete.tags', [ + 'query' => 'Tag 1', + 'limit' => 20, + ]), ['Accept' => 'application/json']); + + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + // Bill 1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 (11) + $response->assertJsonCount(11); + $response->assertJsonMissing(['name' => 'Tag 2']); + } +}