diff --git a/app/game-frontend/e2e/mainNavigation.spec.ts b/app/game-frontend/e2e/mainNavigation.spec.ts index edbe8e46..2cbfbddc 100644 --- a/app/game-frontend/e2e/mainNavigation.spec.ts +++ b/app/game-frontend/e2e/mainNavigation.spec.ts @@ -1158,6 +1158,7 @@ test('scopes the new-survey notice cursor to the reset-specific server ID', asyn generalMeCalls: 0, operations: [], }; + await installRealtimeHarness(page); await installFixture(page, state); await page.addInitScript(() => { localStorage.setItem('state.che.lastVote', '99'); @@ -1170,6 +1171,14 @@ test('scopes the new-survey notice cursor to the reset-specific server ID', asyn .poll(() => page.evaluate(() => localStorage.getItem('state.che_260819_new_season.lastVote'))) .toBe('1'); expect(await page.evaluate(() => localStorage.getItem('state.che.lastVote'))).toBe('99'); + + await waitForMainRealtime(page); + const operationsBeforeDuplicate = state.operations.length; + await emitReadModelInvalidation(page, readModelInvalidation({ frontStatus: true })); + await expect + .poll(() => state.operations.slice(operationsBeforeDuplicate), { timeout: 3_000 }) + .toEqual(['dashboard.getContextBundleDelta', 'general.getFrontStatus']); + await expect(page.locator('.survey-notice')).toContainText('새로운 설문조사가 있습니다.'); }); test('desktop menus preserve ref columns, prefix-safe routes, and controlled dropdown behavior', async ({ diff --git a/app/game-frontend/src/stores/mainDashboard.ts b/app/game-frontend/src/stores/mainDashboard.ts index 43d406ca..8fbd5447 100644 --- a/app/game-frontend/src/stores/mainDashboard.ts +++ b/app/game-frontend/src/stores/mainDashboard.ts @@ -306,7 +306,13 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => { const storageKey = `state.${serverId}.lastVote`; const lastSeenVoteId = Number.parseInt(window.localStorage.getItem(storageKey) ?? '0', 10); if (latestVote.id <= (Number.isFinite(lastSeenVoteId) ? lastSeenVoteId : 0)) { - surveyNotice.value = null; + // Initial mounting, general creation and realtime invalidation can fetch + // the same front status in quick succession. The first response records + // the cursor; a duplicate response must not immediately dismiss the + // notice that response just opened. + if (surveyNotice.value?.id !== latestVote.id) { + surveyNotice.value = null; + } return; } window.localStorage.setItem(storageKey, latestVote.id.toString());