Skip to content

Commit

Permalink
Implement Backend Testing & Logic Fixes (#79)
Browse files Browse the repository at this point in the history
* test: add boilerplate testing infra

* Apply fixes from StyleCI

* test: add reusable traits

* Apply fixes from StyleCI

* chore: change colocation

* test: add boilerplate data

* Apply fixes from StyleCI

* test: more test data

* test: first test

* Apply fixes from StyleCI

* chore: enable backend testing in workflows

* chore: fix some testing setup issues

* test: fix more setup issues

* test: finally resolve setup issues

* test: write tests

* test: more tests

* chore: for completeness sake

* test: add testing for mentions

* fix: change condition when mentions are notified

* test: more tests

* Apply fixes from StyleCI

* test: write tests for amount of notifications received

* fix: prevent duplicate notifications being sent (#80)

* Apply fixes from StyleCI

---------

Co-authored-by: StyleCI Bot <bot@styleci.io>
  • Loading branch information
DavideIadeluca and StyleCIBot authored Jan 27, 2025
1 parent 0834d19 commit 9439702
Show file tree
Hide file tree
Showing 16 changed files with 794 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
run:
uses: flarum/framework/.github/workflows/REUSABLE_backend.yml@main
with:
enable_backend_testing: false
enable_backend_testing: true
enable_phpstan: true
php_versions: '["8.0", "8.1", "8.2", "8.3"]'
backend_directory: .
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules
vendor
composer.lock
js/dist
.phpunit.result.cache
25 changes: 22 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,32 @@
"flarum/subscriptions": "*",
"flarum/phpstan": "*",
"flarum/mentions": "*",
"flarum/gdpr": "dev-main"
"flarum/gdpr": "dev-main",
"flarum/testing": "^1.0.0",
"flarum/tags":"*",
"fof/extend": "*"
},
"autoload-dev": {
"psr-4": {
"FoF\\FollowTags\\Tests\\": "tests/"
}
},
"scripts": {
"analyse:phpstan": "phpstan analyse",
"clear-cache:phpstan": "phpstan clear-result-cache"
"clear-cache:phpstan": "phpstan clear-result-cache",
"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": {
"analyse:phpstan": "Run static analysis"
"analyse:phpstan": "Run static analysis",
"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."
}
}
1 change: 1 addition & 0 deletions src/Jobs/SendNotificationWhenDiscussionIsReTagged.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public function handle(NotificationSyncer $notifications)
->whereIn('tag_user.tag_id', $tagIds->all())
->whereIn('tag_user.subscription', ['follow', 'lurk'])
->get()
->unique()
->reject(function ($user) use ($firstPost, $tags) {
return $tags->map->stateFor($user)->map->subscription->contains('ignore')
|| !$this->discussion->newQuery()->whereVisibleTo($user)->find($this->discussion->id)
Expand Down
1 change: 1 addition & 0 deletions src/Jobs/SendNotificationWhenDiscussionIsStarted.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public function handle(NotificationSyncer $notifications)
->whereIn('tag_user.tag_id', $tagIds->all())
->whereIn('tag_user.subscription', ['follow', 'lurk'])
->get()
->unique()
->reject(function ($user) use ($firstPost, $tags) {
return $tags->map->stateFor($user)->map->subscription->contains('ignore')
|| !$this->discussion->newQuery()->whereVisibleTo($user)->find($this->discussion->id)
Expand Down
1 change: 1 addition & 0 deletions src/Jobs/SendNotificationWhenReplyIsPosted.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public function handle(NotificationSyncer $notifications)
->where('tag_user.subscription', 'lurk')
->where('discussion_user.last_read_post_number', '>=', $this->lastPostNumber - 1)
->get()
->unique()
->reject(function (User $user) use ($tags) {
return $tags->map->stateFor($user)->map->subscription->contains('ignore')
|| !$this->post->isVisibleTo($user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function __invoke(BlueprintInterface $blueprint, array $recipients): arra

$ids = TagState::whereIn('tag_id', $tags)
->whereIn('user_id', $ids)
->where('subscription', 'hide')
->where('subscription', 'ignore')
->pluck('user_id');

if ($ids->isEmpty()) {
Expand Down
Empty file added tests/fixtures/.gitkeep
Empty file.
22 changes: 22 additions & 0 deletions tests/integration/ExtensionDepsTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of fof/follow-tags.
*
* Copyright (c) FriendsOfFlarum.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FoF\FollowTags\Tests\integration;

trait ExtensionDepsTrait
{
public function extensionDeps(): void
{
$this->extension('flarum-tags');
$this->extension('flarum-mentions');
$this->extension('fof-follow-tags');
}
}
28 changes: 28 additions & 0 deletions tests/integration/TagsDefinitionTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/*
* This file is part of fof/follow-tags.
*
* Copyright (c) FriendsOfFlarum.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FoF\FollowTags\Tests\integration;

trait TagsDefinitionTrait
{
public function tags(): array
{
return [
['id' => 1, 'name' => 'General', 'slug' => 'general', 'position' => 0, 'parent_id' => null],
['id' => 2, 'name' => 'Testing', 'slug' => 'testing', 'position' => 1, 'parent_id' => null],
['id' => 3, 'name' => 'Playground', 'slug' => 'playground', 'position' => 1, 'parent_id' => null],
['id' => 4, 'name' => 'Archive', 'slug' => 'archive', 'position' => 2, 'parent_id' => null, 'is_restricted' => true],
['id' => 5, 'name' => 'General Child', 'slug' => 'general-child', 'position' => 0, 'parent_id' => 1],
['id' => 6, 'name' => 'Testing Child', 'slug' => 'testing-child', 'position' => 0, 'parent_id' => 2],

];
}
}
204 changes: 204 additions & 0 deletions tests/integration/notifications/NotificationsCountTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
<?php

/*
* This file is part of fof/follow-tags.
*
* Copyright (c) FriendsOfFlarum.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FoF\FollowTags\Tests\integration\notifications;

use Carbon\Carbon;
use Flarum\Notification\Notification;
use Flarum\Testing\integration\RetrievesAuthorizedUsers;
use Flarum\Testing\integration\TestCase;
use Flarum\User\User;
use FoF\FollowTags\Tests\integration\ExtensionDepsTrait;
use FoF\FollowTags\Tests\integration\TagsDefinitionTrait;

class NotificationsCountTest extends TestCase
{
use RetrievesAuthorizedUsers;
use ExtensionDepsTrait;
use TagsDefinitionTrait;

public function setUp(): void
{
parent::setUp();

$this->extensionDeps();

$this->prepareDatabase([
'users' => [
$this->normalUser(),
],
'tags' => $this->tags(),
'tag_user' => [
['user_id' => 2, 'tag_id' => 1, 'is_hidden' => 0, 'subscription' => 'follow', 'created_at' => Carbon::now()->toDateTimeString()],
['user_id' => 2, 'tag_id' => 5, 'is_hidden' => 0, 'subscription' => 'follow', 'created_at' => Carbon::now()->toDateTimeString()],
['user_id' => 2, 'tag_id' => 2, 'is_hidden' => 0, 'subscription' => 'lurk', 'created_at' => Carbon::now()->toDateTimeString()],
['user_id' => 2, 'tag_id' => 6, 'is_hidden' => 0, 'subscription' => 'lurk', 'created_at' => Carbon::now()->toDateTimeString()],
],
'discussion_tag' => [
['discussion_id' => 1, 'tag_id' => 2, 'created_at' => Carbon::now()->toDateTimeString()],
['discussion_id' => 1, 'tag_id' => 6, 'created_at' => Carbon::now()->toDateTimeString()],
],
'discussion_user' => [
['user_id' => 2, 'discussion_id' => 1, 'last_read_post_number' => 1, 'last_read_at' => Carbon::now()->toDateTimeString()],
],
'discussions' => [
['id' => 1, 'title' => 'The quick brown fox jumps over the lazy dog', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'participant_count' => 1],
],
'posts' => [
['id' => 1, 'discussion_id' => 1, 'user_id' => 2, 'type' => 'comment', 'content' => '<t><p>Following</p></t>', 'is_private' => 0, 'number' => 1],
],
]);
}

/**
* @test
*/
public function single_notification_sent_when_following_tag_and_subtag()
{
$response = $this->send(
$this->request('POST', '/api/discussions', [
'authenticatedAs' => 1,
'json' => [
'data' => [
'attributes' => [
'title' => 'New discussion',
'content' => '<t><p>New Post</p></t>',
],
'relationships' => [
'tags' => [
'data' => [
['type' => 'tags', 'id' => 1],
['type' => 'tags', 'id' => 5],
],
],
],
],
],
])
);

$this->assertEquals(201, $response->getStatusCode());

$notificationRecipient = 2;

$response = $this->send(
$this->request('GET', '/api/notifications', [
'authenticatedAs' => $notificationRecipient,
])
);

$this->assertEquals(200, $response->getStatusCode());

$response = json_decode($response->getBody(), true);

$this->assertEquals(1, count($response['data']));
$this->assertEquals('newDiscussionInTag', $response['data'][0]['attributes']['contentType']);
$this->assertEquals(1, User::query()->find($notificationRecipient)->notifications()->count());
$this->assertEquals(1, Notification::query()->count());
$this->assertEquals(1, Notification::query()->first()->from_user_id);
$this->assertEquals(2, Notification::query()->first()->user_id);
}

/**
* @test
*/
public function single_notification_sent_when_lurking_tag_and_subtag()
{
$response = $this->send(
$this->request('POST', '/api/posts', [
'authenticatedAs' => 1,
'json' => [
'data' => [
'attributes' => [
'content' => '<t><p>New Post</p></t>',
],
'relationships' => [
'discussion' => [
'data' => [
'type' => 'discussions',
'id' => 1,
],
],
],
],
],
])
);

$this->assertEquals(201, $response->getStatusCode());

$notificationRecipient = 2;

$response = $this->send(
$this->request('GET', '/api/notifications', [
'authenticatedAs' => $notificationRecipient,
])
);

$this->assertEquals(200, $response->getStatusCode());

$response = json_decode($response->getBody(), true);

$this->assertEquals(1, count($response['data']));
$this->assertEquals('newPostInTag', $response['data'][0]['attributes']['contentType']);
$this->assertEquals(1, User::query()->find($notificationRecipient)->notifications()->count());
$this->assertEquals(1, Notification::query()->count());
$this->assertEquals(1, Notification::query()->first()->from_user_id);
$this->assertEquals(2, Notification::query()->first()->user_id);
}

/**
* @test
*/
public function single_notification_sent_when_following_tag_and_subtag_and_discussion_retagged()
{
$response = $this->send(
$this->request('PATCH', '/api/discussions/1', [
'authenticatedAs' => 1,
'json' => [
'data' => [
'attributes' => [],
'relationships' => [
'tags' => [
'data' => [
['type' => 'tags', 'id' => 1],
['type' => 'tags', 'id' => 5],
],
],
],
],
],
])
);

$this->assertEquals(200, $response->getStatusCode());

$notificationRecipient = 2;

$response = $this->send(
$this->request('GET', '/api/notifications', [
'authenticatedAs' => $notificationRecipient,
])
);

$this->assertEquals(200, $response->getStatusCode());

$response = json_decode($response->getBody(), true);

$this->assertEquals(1, count($response['data']));
$this->assertEquals('newDiscussionTag', $response['data'][0]['attributes']['contentType']);

$this->assertEquals(1, User::query()->find($notificationRecipient)->notifications()->count());
$this->assertEquals(1, Notification::query()->count());
$this->assertEquals(1, Notification::query()->first()->from_user_id);
$this->assertEquals(2, Notification::query()->first()->user_id);
}
}
Loading

0 comments on commit 9439702

Please sign in to comment.