-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
fix(backend): 表示されない通知が残り通知数として表示されるバグの修正 #17530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
fruitriin
wants to merge
4
commits into
misskey-dev:develop
Choose a base branch
from
fruitriin:fix/notification-unread-count
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+159
−10
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
f14ca24
test(backend): 通知の未読カウントと表示の不一致を検出する e2e テストを追加
fruitriin 4b60085
fix(backend): 通知の未読バッジが通常操作で消えなくなる問題を修正 (#17427)
fruitriin 946a1a6
test(backend): UserEntityService テストで NotificationEntityService を pro…
fruitriin a2a81d7
test(backend): UserEntityService テストで NotificationEntityService の推移的依…
fruitriin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: syuilo and misskey-project | ||
| * SPDX-License-Identifier: AGPL-3.0-only | ||
| */ | ||
|
|
||
| process.env.NODE_ENV = 'test'; | ||
|
|
||
| import * as assert from 'node:assert'; | ||
| import { setTimeout } from 'node:timers/promises'; | ||
| import { beforeAll, beforeEach, describe, test } from 'vitest'; | ||
| import { api, post, signup } from '../utils.js'; | ||
| import type * as misskey from 'misskey-js'; | ||
|
|
||
| // このテストは https://github.com/misskey-dev/misskey/issues/17427 | ||
| // 「通知バルーンが消えない問題」の回帰防止。 | ||
| // | ||
| // 旧 UserEntityService.getNotificationsInfo() は Redis Stream の生エントリ数で | ||
| // 未読カウントを返していたため、packMany で除外される通知 (解決済みフォロー | ||
| // リクエスト・削除済みノート・サスペンドされた notifier 等) もカウントに含まれ、 | ||
| // 「通知ページを開いても何もないのにバッジだけ残る」状態を引き起こしていた。 | ||
| // | ||
| // 修正後は packMany 相当のバリデータを通した件数を返すため、 | ||
| // API レスポンスとバッジカウントは常に一致する。 | ||
| describe('Notification unread count consistency (misskey-dev/misskey#17427)', () => { | ||
| let alice: misskey.entities.SignupResponse; | ||
| let bob: misskey.entities.SignupResponse; | ||
|
|
||
| beforeAll(async () => { | ||
| alice = await signup({ username: 'alice_n17427' }); | ||
| bob = await signup({ username: 'bob_n17427' }); | ||
| }, 1000 * 60 * 2); | ||
|
|
||
| // 各テスト間で Stream エントリ自体を破棄してテスト間の汚染を防ぐ。 | ||
| // mark-all-as-read だと latestReadNotificationId を進めるだけで Stream は残る。 | ||
| beforeEach(async () => { | ||
| await api('notifications/flush', {}, alice); | ||
| await api('notifications/flush', {}, bob); | ||
| await setTimeout(500); | ||
| }); | ||
|
|
||
| test('承認済みフォローリクエスト通知は表示されず、カウントにも含まれない', async () => { | ||
| // alice をロックする → bob がフォローするとフォローリクエストになる | ||
| await api('i/update', { isLocked: true }, alice); | ||
|
|
||
| // bob → alice フォローリクエスト発生 (alice に receiveFollowRequest 通知) | ||
| await api('following/create', { userId: alice.id }, bob); | ||
|
|
||
| // createNotification の setTimeout(2000) 後に unreadNotification が発火するため待機 | ||
| await setTimeout(2500); | ||
|
|
||
| // 承認前: 通知が 1 件未読として見える状態 | ||
| const beforeAccept = await api('i', {}, alice); | ||
| assert.strictEqual(beforeAccept.status, 200); | ||
| assert.strictEqual(beforeAccept.body.unreadNotificationsCount, 1, | ||
| '承認前: フォローリクエスト通知でカウント 1'); | ||
| assert.strictEqual(beforeAccept.body.hasUnreadNotification, true); | ||
|
|
||
| // alice 側で承認 → receiveFollowRequest が解決済みになる & | ||
| // 同時に follow 通知が新規発生する (フォロワー追加の通知) | ||
| await api('following/requests/accept', { userId: bob.id }, alice); | ||
| await setTimeout(200); | ||
|
|
||
| // 承認後の状態を観測する。 | ||
| // markAsRead=false で内部の readAllNotification を呼ばないようにする | ||
| const afterAcceptI = await api('i', {}, alice); | ||
| const notificationsRes = await api('i/notifications', { markAsRead: false }, alice); | ||
| assert.strictEqual(notificationsRes.status, 200); | ||
|
|
||
| // receiveFollowRequest 通知は packMany で除外されているはず | ||
| const remainingReceiveFollowRequest = notificationsRes.body.filter( | ||
| (n: { type: string }) => n.type === 'receiveFollowRequest', | ||
| ); | ||
| assert.strictEqual(remainingReceiveFollowRequest.length, 0, | ||
| '承認後: 解決済みの receiveFollowRequest 通知は API レスポンスに現れない'); | ||
|
|
||
| // 修正の本旨: バッジカウントは API レスポンスの件数と一致する | ||
| assert.strictEqual(afterAcceptI.body.unreadNotificationsCount, notificationsRes.body.length, | ||
| 'unreadNotificationsCount は packMany フィルタ後の件数と一致する (Stream の生件数ではなく)'); | ||
|
|
||
| // 後片付け | ||
| await api('i/update', { isLocked: false }, alice); | ||
| await api('following/delete', { userId: alice.id }, bob); | ||
| }, 1000 * 30); | ||
|
|
||
| test('mention 通知が来たときは API 件数 = バッジカウントが揃う', async () => { | ||
| await post(bob, { text: `@alice_n17427 hi ${Date.now()}` }); | ||
| // createNotificationInternal の setTimeout(2000) 経過待ち | ||
| await setTimeout(2500); | ||
|
|
||
| const userInfo = await api('i', {}, alice); | ||
| const notificationsRes = await api('i/notifications', { markAsRead: false }, alice); | ||
|
|
||
| assert.strictEqual(userInfo.body.unreadNotificationsCount, notificationsRes.body.length, | ||
| 'unreadNotificationsCount は packMany フィルタ後の件数と一致する'); | ||
| assert.ok(userInfo.body.unreadNotificationsCount >= 1, | ||
| 'mention 通知 1 件以上で unreadNotificationsCount >= 1'); | ||
| }, 1000 * 30); | ||
|
|
||
| test('元のメンション元ノートが削除されると、その通知はカウントから除外される', async () => { | ||
| // bob から alice にメンション → alice に通知が立つ | ||
| const bobNote = await post(bob, { text: `@alice_n17427 will be deleted ${Date.now()}` }); | ||
| await setTimeout(2500); | ||
|
|
||
| // 通知が立った状態を確認 | ||
| const beforeDelete = await api('i', {}, alice); | ||
| assert.ok(beforeDelete.body.unreadNotificationsCount >= 1, 'ノート削除前はカウント >= 1'); | ||
|
|
||
| // bob がノートを削除する → packMany で「ノート無し」として除外されるはず | ||
| await api('notes/delete', { noteId: bobNote.id }, bob); | ||
| await setTimeout(500); | ||
|
|
||
| const afterDelete = await api('i', {}, alice); | ||
| const notificationsRes = await api('i/notifications', { markAsRead: false }, alice); | ||
|
|
||
| // API レスポンスから該当通知が消えていることを確認 | ||
| const stillVisible = notificationsRes.body.filter( | ||
| (n: { type: string; note?: { id: string } }) => n.type === 'mention' && n.note?.id === bobNote.id, | ||
| ); | ||
| assert.strictEqual(stillVisible.length, 0, | ||
| 'ノート削除後: mention 通知は packMany で除外され API レスポンスに現れない'); | ||
|
|
||
| // バッジカウントも同様に減っているはず (修正前は Stream に残っていたのでカウントだけ残る現象が出た) | ||
| assert.strictEqual(afterDelete.body.unreadNotificationsCount, notificationsRes.body.length, | ||
| 'ノート削除後: unreadNotificationsCount は API レスポンス件数と一致する'); | ||
| }, 1000 * 30); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.