diff --git a/composer.json b/composer.json
index 62fa8ff..2067fbc 100644
--- a/composer.json
+++ b/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\\Subscriptions\\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/src/Job/SendReplyNotification.php b/src/Job/SendReplyNotification.php
index 5d87e88..6f3d421 100644
--- a/src/Job/SendReplyNotification.php
+++ b/src/Job/SendReplyNotification.php
@@ -49,7 +49,7 @@ public function handle(NotificationSyncer $notifications)
$notify = $discussion->readers()
->where('users.id', '!=', $post->user_id)
->where('discussion_user.subscription', 'follow')
- ->where('discussion_user.last_read_post_number', $this->lastPostNumber)
+ ->where('discussion_user.last_read_post_number', $this->lastPostNumber - 1)
->get();
$notifications->sync(
diff --git a/tests/fixtures/.gitkeep b/tests/fixtures/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/tests/integration/api/discussions/ReplyNotificationTest.php b/tests/integration/api/discussions/ReplyNotificationTest.php
new file mode 100644
index 0000000..4dd4a8b
--- /dev/null
+++ b/tests/integration/api/discussions/ReplyNotificationTest.php
@@ -0,0 +1,142 @@
+extension('flarum-subscriptions');
+
+ $this->prepareDatabase([
+ 'users' => [
+ $this->normalUser(),
+ ],
+ 'discussions' => [
+ ['id' => 1, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 1, 'comment_count' => 1, 'last_post_number' => 1, 'last_post_id' => 1],
+ ['id' => 2, 'title' => __CLASS__, 'created_at' => Carbon::now(), 'last_posted_at' => Carbon::now(), 'user_id' => 1, 'first_post_id' => 2, 'comment_count' => 1, 'last_post_number' => 1, 'last_post_id' => 2],
+ ],
+ 'posts' => [
+ ['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::createFromDate(1975, 5, 21)->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => 'foo bar
', 'number' => 1],
+ ['id' => 2, 'discussion_id' => 2, 'created_at' => Carbon::createFromDate(1975, 5, 21)->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => 'foo bar
', 'number' => 1],
+ ],
+ 'discussion_user' => [
+ ['discussion_id' => 1, 'user_id' => 1, 'last_read_post_number' => 1, 'subscription' => 'follow'],
+ ['discussion_id' => 2, 'user_id' => 1, 'last_read_post_number' => 1, 'subscription' => 'follow'],
+ ]
+ ]);
+ }
+
+ /** @test */
+ public function replying_to_a_discussion_with_comment_post_as_last_post_sends_reply_notification()
+ {
+ $this->app();
+
+ /** @var User $mainUser */
+ $mainUser = User::query()->find(1);
+
+ $this->assertEquals(0, $this->getUnreadNotificationCount($mainUser));
+
+ $this->send(
+ $this->request('POST', '/api/posts', [
+ 'authenticatedAs' => 2,
+ 'json' => [
+ 'data' => [
+ 'attributes' => [
+ 'content' => 'reply with predetermined content for automated testing - too-obscure',
+ ],
+ 'relationships' => [
+ 'discussion' => ['data' => ['id' => 1]],
+ ],
+ ],
+ ],
+ ])
+ );
+
+ $this->assertEquals(1, $this->getUnreadNotificationCount($mainUser));
+ }
+
+ /** @test */
+ public function replying_to_a_discussion_with_event_post_as_last_post_sends_reply_notification()
+ {
+ $this->app();
+
+ /** @var User $mainUser */
+ $mainUser = User::query()->find(1);
+
+ // Rename the discussion to trigger an event post.
+ $this->send(
+ $this->request('POST', '/api/discussions/2', [
+ 'authenticatedAs' => 1,
+ 'json' => [
+ 'data' => [
+ 'attributes' => [
+ 'title' => 'ACME',
+ ],
+ ],
+ ],
+ ])
+ );
+
+ // Mark as read
+ $this->send(
+ $this->request('POST', '/api/discussions/2', [
+ 'authenticatedAs' => 1,
+ 'json' => [
+ 'data' => [
+ 'attributes' => [
+ 'lastReadPostNumber' => 2,
+ ],
+ ],
+ ],
+ ])
+ );
+
+ $this->assertEquals(0, $this->getUnreadNotificationCount($mainUser));
+
+ $this->send(
+ $this->request('POST', '/api/posts', [
+ 'authenticatedAs' => 2,
+ 'json' => [
+ 'data' => [
+ 'attributes' => [
+ 'content' => 'reply with predetermined content for automated testing - too-obscure',
+ ],
+ 'relationships' => [
+ 'discussion' => ['data' => ['id' => 2]],
+ ],
+ ],
+ ],
+ ])
+ );
+
+ $this->assertEquals(1, $this->getUnreadNotificationCount($mainUser));
+ }
+
+ /** @todo change after core no longer statically caches unread notification in the User class */
+ protected function getUnreadNotificationCount(User $user)
+ {
+ return $user->notifications()
+ ->where('type', 'newPost')
+ ->whereNull('read_at')
+ ->where('is_deleted', false)
+ ->whereSubjectVisibleTo($user)
+ ->count();
+ }
+}
diff --git a/tests/integration/setup.php b/tests/integration/setup.php
new file mode 100644
index 0000000..67039c0
--- /dev/null
+++ b/tests/integration/setup.php
@@ -0,0 +1,16 @@
+run();
diff --git a/tests/phpunit.integration.xml b/tests/phpunit.integration.xml
new file mode 100644
index 0000000..90fbbff
--- /dev/null
+++ b/tests/phpunit.integration.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ ../src/
+
+
+
+
+ ./integration
+ ./integration/tmp
+
+
+
diff --git a/tests/phpunit.unit.xml b/tests/phpunit.unit.xml
new file mode 100644
index 0000000..d3a4a3e
--- /dev/null
+++ b/tests/phpunit.unit.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ ../src/
+
+
+
+
+ ./unit
+
+
+
+
+
+
diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep
new file mode 100644
index 0000000..e69de29