xiangyixiangqin/miniapp/__tests__/properties/chat.property.test.js
2026-01-02 18:00:49 +08:00

255 lines
7.9 KiB
JavaScript

/**
* Property-based tests for chat state management
* **Feature: miniapp-frontend, Property 22: Unread Badge Display**
* **Validates: Requirements 13.5**
*/
import { describe, it, expect, beforeEach } from 'vitest'
import * as fc from 'fast-check'
import { setActivePinia, createPinia } from 'pinia'
// Import mock before other modules
import '../mocks/uni.js'
import { useChatStore, MessageType, MessageStatus } from '../../store/chat.js'
describe('Chat Store Property Tests', () => {
beforeEach(() => {
// Create a fresh pinia instance for each test
setActivePinia(createPinia())
})
/**
* Property 22: Unread Badge Display
* *For any* unread message count > 0, the message tab SHALL display a red badge.
* **Validates: Requirements 13.5**
*/
it('Property 22: Unread Badge Display - badge should show when unread count > 0', () => {
fc.assert(
fc.property(
// Generate positive unread counts
fc.integer({ min: 1, max: 1000 }),
(unreadCount) => {
const chatStore = useChatStore()
// Use the pure function to test
const shouldShow = chatStore.shouldShowUnreadBadge(unreadCount)
// Badge should show for any positive count
return shouldShow === true
}
),
{ numRuns: 100 }
)
})
/**
* Property 22 (continued): Badge should NOT show when unread count is 0
*/
it('Property 22: Unread Badge Display - badge should not show when unread count is 0', () => {
const chatStore = useChatStore()
// Use the pure function to test
const shouldShow = chatStore.shouldShowUnreadBadge(0)
// Badge should not show for zero count
expect(shouldShow).toBe(false)
})
/**
* Property 22 (continued): Badge should NOT show for negative counts
*/
it('Property 22: Unread Badge Display - badge should not show for negative counts', () => {
fc.assert(
fc.property(
// Generate negative counts (edge case)
fc.integer({ min: -1000, max: -1 }),
(negativeCount) => {
const chatStore = useChatStore()
// Use the pure function to test
const shouldShow = chatStore.shouldShowUnreadBadge(negativeCount)
// Badge should not show for negative counts
return shouldShow === false
}
),
{ numRuns: 100 }
)
})
/**
* Property: Total unread count should equal sum of session unread counts
*/
it('Total unread count should equal sum of session unread counts', () => {
fc.assert(
fc.property(
// Generate array of sessions with unread counts
fc.array(
fc.record({
sessionId: fc.integer({ min: 1 }),
targetUserId: fc.integer({ min: 1 }),
targetNickname: fc.string({ minLength: 1 }),
targetAvatar: fc.string(),
lastMessage: fc.string(),
lastMessageTime: fc.string(),
unreadCount: fc.integer({ min: 0, max: 100 })
}),
{ minLength: 0, maxLength: 10 }
),
(sessions) => {
const chatStore = useChatStore()
// Set sessions
chatStore.setSessions(sessions)
// Calculate expected total
const expectedTotal = sessions.reduce(
(sum, s) => sum + (s.unreadCount || 0),
0
)
// Total should match
return chatStore.totalUnreadCount === expectedTotal
}
),
{ numRuns: 100 }
)
})
/**
* Property: hasUnreadMessages getter should match totalUnreadCount > 0
*/
it('hasUnreadMessages getter should match totalUnreadCount > 0', () => {
fc.assert(
fc.property(
fc.array(
fc.record({
sessionId: fc.integer({ min: 1 }),
targetUserId: fc.integer({ min: 1 }),
targetNickname: fc.string({ minLength: 1 }),
targetAvatar: fc.string(),
lastMessage: fc.string(),
lastMessageTime: fc.string(),
unreadCount: fc.integer({ min: 0, max: 100 })
}),
{ minLength: 0, maxLength: 10 }
),
(sessions) => {
const chatStore = useChatStore()
// Set sessions
chatStore.setSessions(sessions)
// hasUnreadMessages should match whether total > 0
const expectedHasUnread = chatStore.totalUnreadCount > 0
return chatStore.hasUnreadMessages === expectedHasUnread
}
),
{ numRuns: 100 }
)
})
/**
* Property: Marking session as read should decrease total unread count
*/
it('Marking session as read should decrease total unread count', () => {
fc.assert(
fc.property(
// Generate sessions with at least one having unread messages
fc.array(
fc.record({
sessionId: fc.integer({ min: 1, max: 100 }),
targetUserId: fc.integer({ min: 1 }),
targetNickname: fc.string({ minLength: 1 }),
targetAvatar: fc.string(),
lastMessage: fc.string(),
lastMessageTime: fc.string(),
unreadCount: fc.integer({ min: 0, max: 50 })
}),
{ minLength: 1, maxLength: 5 }
).filter(sessions => sessions.some(s => s.unreadCount > 0)),
(sessions) => {
const chatStore = useChatStore()
// Ensure unique session IDs
const uniqueSessions = sessions.map((s, i) => ({
...s,
sessionId: i + 1
}))
// Set sessions
chatStore.setSessions(uniqueSessions)
// Find a session with unread messages
const sessionWithUnread = uniqueSessions.find(s => s.unreadCount > 0)
if (!sessionWithUnread) return true // Skip if no unread
const totalBefore = chatStore.totalUnreadCount
const sessionUnread = sessionWithUnread.unreadCount
// Mark as read
chatStore.markSessionAsRead(sessionWithUnread.sessionId)
const totalAfter = chatStore.totalUnreadCount
// Total should decrease by the session's unread count
return totalAfter === totalBefore - sessionUnread
}
),
{ numRuns: 100 }
)
})
/**
* Property: Receiving message in non-current session should increment unread
*/
it('Receiving message in non-current session should increment unread count', () => {
fc.assert(
fc.property(
fc.integer({ min: 1, max: 100 }), // sessionId
fc.integer({ min: 101, max: 200 }), // different currentSessionId
fc.string({ minLength: 1 }), // message content
(sessionId, currentSessionId, content) => {
const chatStore = useChatStore()
// Set up session
chatStore.setSessions([{
sessionId,
targetUserId: 1,
targetNickname: 'Test',
targetAvatar: '',
lastMessage: '',
lastMessageTime: '',
unreadCount: 0
}])
// Set current session to a different one
chatStore.setCurrentSession(currentSessionId)
const unreadBefore = chatStore.totalUnreadCount
// Receive message in the non-current session
chatStore.receiveMessage({
id: 1,
sessionId,
senderId: 2,
receiverId: 1,
messageType: MessageType.TEXT,
content,
status: MessageStatus.DELIVERED,
createTime: new Date().toISOString(),
isMine: false
})
const unreadAfter = chatStore.totalUnreadCount
// Unread count should increase by 1
return unreadAfter === unreadBefore + 1
}
),
{ numRuns: 100 }
)
})
})