diff --git a/.github/workflows/flarum-likes-backend.yml b/.github/workflows/flarum-likes-backend.yml index fefe1d25f..a3347bd12 100644 --- a/.github/workflows/flarum-likes-backend.yml +++ b/.github/workflows/flarum-likes-backend.yml @@ -6,6 +6,6 @@ jobs: run: uses: ./.github/workflows/REUSABLE_backend.yml with: - enable_backend_testing: false + enable_backend_testing: true backend_directory: ./extensions/likes diff --git a/extensions/likes/composer.json b/extensions/likes/composer.json index 5ff98d889..683fe3f89 100644 --- a/extensions/likes/composer.json +++ b/extensions/likes/composer.json @@ -51,7 +51,7 @@ "prettier": true, "typescript": false, "bundlewatch": false, - "backendTesting": false, + "backendTesting": true, "editorConfig": true, "styleci": true } @@ -64,5 +64,28 @@ } ], "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "autoload-dev": { + "psr-4": { + "Flarum\\Likes\\Tests\\": "tests/" + } + }, + "scripts": { + "test": [ + "@test:unit", + "@test:integration" + ], + "test:unit": "phpunit -c tests/phpunit.unit.xml", + "test:integration": "phpunit -c tests/phpunit.integration.xml", + "test:setup": "@php tests/integration/setup.php" + }, + "scripts-descriptions": { + "test": "Runs all tests.", + "test:unit": "Runs all unit tests.", + "test:integration": "Runs all integration tests.", + "test:setup": "Sets up a database for use with integration tests. Execute this only once." + }, + "require-dev": { + "flarum/testing": "^1.0.0" + } } diff --git a/extensions/likes/tests/fixtures/.gitkeep b/extensions/likes/tests/fixtures/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/extensions/likes/tests/integration/api/LikePostTest.php b/extensions/likes/tests/integration/api/LikePostTest.php new file mode 100644 index 000000000..61e113e58 --- /dev/null +++ b/extensions/likes/tests/integration/api/LikePostTest.php @@ -0,0 +1,144 @@ +extension('flarum-likes'); + + $this->prepareDatabase([ + 'users' => [ + ['id' => 1, 'username' => 'Muralf', 'email' => 'muralf@machine.local', 'is_email_confirmed' => 1], + $this->normalUser(), + ['id' => 3, 'username' => 'Acme', 'email' => 'acme@machine.local', 'is_email_confirmed' => 1], + ], + 'discussions' => [ + ['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 2], + ], + 'posts' => [ + ['id' => 1, 'number' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'], + ['id' => 3, 'number' => 2, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'], + ['id' => 5, 'number' => 3, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 3, 'type' => 'discussionRenamed', 'content' => '

something

'], + ['id' => 6, 'number' => 4, 'discussion_id' => 1, 'created_at' => Carbon::now(), 'user_id' => 1, 'type' => 'comment', 'content' => '

something

'], + ], + 'groups' => [ + ['id' => 5, 'name_singular' => 'Acme', 'name_plural' => 'Acme', 'is_hidden' => 0], + ['id' => 6, 'name_singular' => 'Acme1', 'name_plural' => 'Acme1', 'is_hidden' => 0] + ], + 'group_user' => [ + ['user_id' => 3, 'group_id' => 5] + ] + ]); + + $this->database()->table('group_permission')->where('permission', 'discussion.likePosts')->delete(); + $this->database()->table('group_permission')->insert(['permission' => 'discussion.likePosts', 'group_id' => 5]); + } + + /** + * @dataProvider allowedUsersToLike + * @test + */ + public function can_like_a_post_if_allowed(int $postId, ?int $authenticatedAs, string $message) + { + $response = $this->sendLikeRequest($postId, $authenticatedAs); + + $post = CommentPost::query()->find($postId); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertNotNull($post->likes->where('id', $authenticatedAs)->first(), $message); + } + + /** + * @dataProvider unallowedUsersToLike + * @test + */ + public function cannot_like_a_post_if_not_allowed(int $postId, ?int $authenticatedAs, string $message) + { + $response = $this->sendLikeRequest($postId, $authenticatedAs); + + $post = CommentPost::query()->find($postId); + + $this->assertEquals(403, $response->getStatusCode(), $message); + $this->assertNull($post->likes->where('id', $authenticatedAs)->first()); + } + + /** + * @dataProvider allowedUsersToLike + * @test + */ + public function can_dislike_a_post_if_liked_and_allowed(int $postId, ?int $authenticatedAs, string $message) + { + $this->sendLikeRequest($postId, $authenticatedAs); + $response = $this->sendLikeRequest($postId, $authenticatedAs, false); + + $post = CommentPost::query()->find($postId); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertNull($post->likes->where('id', $authenticatedAs)->first(), $message); + } + + public function allowedUsersToLike(): array + { + return [ + [1, 1, 'Admin can like any post'], + [1, 3, 'User with permission can like other posts'], + [6, 3, 'User with permission can like own post'] + ]; + } + + public function unallowedUsersToLike(): array + { + return [ + [1, null, 'Guest cannot like any post'], + [1, 2, 'User without permission cannot like any post'] + ]; + } + + protected function sendLikeRequest(int $postId, ?int $authenticatedAs, bool $liked = true): ResponseInterface + { + if (! isset($authenticatedAs)) { + $initial = $this->send( + $this->request('GET', '/') + ); + + $token = $initial->getHeaderLine('X-CSRF-Token'); + } + + $request = $this->request('PATCH', "/api/posts/$postId", [ + 'authenticatedAs' => $authenticatedAs, + 'cookiesFrom' => $initial ?? null, + 'json' => [ + 'data' => [ + 'attributes' => [ + 'isLiked' => $liked + ] + ] + ] + ]); + + if (! isset($authenticatedAs)) { + $request = $request->withHeader('X-CSRF-Token', $token); + } + + return $this->send($request); + } +} diff --git a/extensions/likes/tests/integration/setup.php b/extensions/likes/tests/integration/setup.php new file mode 100644 index 000000000..67039c083 --- /dev/null +++ b/extensions/likes/tests/integration/setup.php @@ -0,0 +1,16 @@ +run(); diff --git a/extensions/likes/tests/phpunit.integration.xml b/extensions/likes/tests/phpunit.integration.xml new file mode 100644 index 000000000..90fbbff37 --- /dev/null +++ b/extensions/likes/tests/phpunit.integration.xml @@ -0,0 +1,25 @@ + + + + + ../src/ + + + + + ./integration + ./integration/tmp + + + diff --git a/extensions/likes/tests/phpunit.unit.xml b/extensions/likes/tests/phpunit.unit.xml new file mode 100644 index 000000000..d3a4a3e3d --- /dev/null +++ b/extensions/likes/tests/phpunit.unit.xml @@ -0,0 +1,27 @@ + + + + + ../src/ + + + + + ./unit + + + + + + diff --git a/extensions/likes/tests/unit/.gitkeep b/extensions/likes/tests/unit/.gitkeep new file mode 100644 index 000000000..e69de29bb