xiangyixiangqin/miniapp/__tests__/properties/config.property.test.js
2026-01-06 22:08:53 +08:00

243 lines
8.4 KiB
JavaScript

/**
* Property-based tests for config state management
* **Feature: miniapp-frontend, Property 5: Popup Priority Logic**
* **Feature: miniapp-frontend, Property 6: Daily Popup Display**
* **Feature: miniapp-frontend, Property 7: Member Ad Visibility**
* **Validates: Requirements 3.1, 3.2, 3.3, 3.4**
*/
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 { useConfigStore, getTodayDateString } from '../../store/config.js'
describe('Config Store Property Tests', () => {
beforeEach(() => {
// Create a fresh pinia instance for each test
setActivePinia(createPinia())
// Clear storage
uni._clearStorage()
})
/**
* Property 5: Popup Priority Logic
* *For any* user state where genderPreference is not set AND isProfileCompleted is false,
* the gender selection popup SHALL have highest display priority over other popups.
* **Validates: Requirements 3.1**
*/
it('Property 5: Popup Priority Logic - gender popup has highest priority when conditions met', () => {
fc.assert(
fc.property(
// Generate user states where gender is not set (0) and profile is not completed
fc.record({
genderPreference: fc.constant(0),
isProfileCompleted: fc.constant(false),
isMember: fc.boolean()
}),
(userState) => {
const configStore = useConfigStore()
// Set up daily popup to ensure it would show if gender popup didn't take priority
configStore.setDailyPopup({ id: 1, title: 'Test Popup' })
configStore.lastPopupDate = '' // Ensure daily popup would show
// Check popup display
configStore.checkPopupDisplay(userState)
// Gender popup should be shown
const genderPopupShown = configStore.showGenderPopup === true
// Other popups should NOT be shown (gender has priority)
const dailyPopupNotShown = configStore.showDailyPopup === false
const memberAdNotShown = configStore.showMemberAd === false
return genderPopupShown && dailyPopupNotShown && memberAdNotShown
}
),
{ numRuns: 100 }
)
})
/**
* Property 5 (continued): Gender popup should NOT show when gender is selected OR profile is completed
*/
it('Property 5: Gender popup should not show when gender is selected or profile is completed', () => {
fc.assert(
fc.property(
fc.oneof(
// Gender is selected (1 or 2)
fc.record({
genderPreference: fc.integer({ min: 1, max: 2 }),
isProfileCompleted: fc.boolean(),
isMember: fc.boolean()
}),
// Profile is completed
fc.record({
genderPreference: fc.integer({ min: 0, max: 2 }),
isProfileCompleted: fc.constant(true),
isMember: fc.boolean()
})
),
(userState) => {
const configStore = useConfigStore()
// Check popup display
configStore.checkPopupDisplay(userState)
// Gender popup should NOT be shown
return configStore.showGenderPopup === false
}
),
{ numRuns: 100 }
)
})
/**
* Property 6: Daily Popup Display
* *For any* date comparison where the last shown date is before today,
* the daily popup SHALL be displayed; otherwise it SHALL NOT be displayed.
* **Validates: Requirements 3.2**
*/
it('Property 6: Daily Popup Display - should show when last shown date is before today', () => {
fc.assert(
fc.property(
// Generate dates that are NOT today
fc.date({ min: new Date('2020-01-01'), max: new Date('2025-12-30') })
.map(d => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`)
.filter(dateStr => dateStr !== getTodayDateString()),
(lastShownDate) => {
const configStore = useConfigStore()
const today = getTodayDateString()
// Use the pure function to test
const shouldShow = configStore.shouldShowDailyPopup(lastShownDate, today)
// Should show because last shown date is not today
return shouldShow === true
}
),
{ numRuns: 100 }
)
})
/**
* Property 6 (continued): Should NOT show when already shown today
*/
it('Property 6: Daily Popup Display - should not show when already shown today', () => {
const configStore = useConfigStore()
const today = getTodayDateString()
// When last shown date is today, should not show
const shouldShow = configStore.shouldShowDailyPopup(today, today)
expect(shouldShow).toBe(false)
})
/**
* Property 7: Member Ad Visibility
* *For any* user state where isMember is false AND member ad has not been closed today,
* the member advertisement SHALL be visible.
* **Validates: Requirements 3.3, 3.4**
*/
it('Property 7: Member Ad Visibility - should show for non-members who have not closed ad today', () => {
fc.assert(
fc.property(
// Generate dates that are NOT today (ad was closed on a different day)
fc.oneof(
fc.constant(''), // Never closed
fc.date({ min: new Date('2020-01-01'), max: new Date('2025-12-30') })
.map(d => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`)
.filter(dateStr => dateStr !== getTodayDateString())
),
(adClosedDate) => {
const configStore = useConfigStore()
const today = getTodayDateString()
// Non-member, ad not closed today
const shouldShow = configStore.shouldShowMemberAd(false, adClosedDate, today)
return shouldShow === true
}
),
{ numRuns: 100 }
)
})
/**
* Property 7 (continued): Should NOT show for members
*/
it('Property 7: Member Ad Visibility - should not show for members', () => {
fc.assert(
fc.property(
fc.string(), // Any ad closed date
(adClosedDate) => {
const configStore = useConfigStore()
const today = getTodayDateString()
// Member should never see ad
const shouldShow = configStore.shouldShowMemberAd(true, adClosedDate, today)
return shouldShow === false
}
),
{ numRuns: 100 }
)
})
/**
* Property 7 (continued): Should NOT show when ad was closed today
*/
it('Property 7: Member Ad Visibility - should not show when ad was closed today', () => {
const configStore = useConfigStore()
const today = getTodayDateString()
// Non-member but ad was closed today
const shouldShow = configStore.shouldShowMemberAd(false, today, today)
expect(shouldShow).toBe(false)
})
/**
* Property: Closing member ad should prevent it from showing again today
* Note: This test uses displayMode 2 (close for today) behavior
*/
it('Closing member ad should prevent it from showing again today', () => {
fc.assert(
fc.property(
fc.record({
genderPreference: fc.integer({ min: 1, max: 2 }), // Gender selected
isProfileCompleted: fc.constant(true), // Profile completed
isMember: fc.constant(false) // Non-member
}),
(userState) => {
const configStore = useConfigStore()
const today = getTodayDateString()
// Setup: Configure member ad with displayMode 2 (close for today)
configStore.setMemberAdConfig({ status: 1, displayMode: 2 })
configStore.lastPopupDate = today // Daily popup already shown
configStore.memberAdClosedDate = '' // Ad not closed
configStore.memberAdClosedForever = false
// First check - ad should show
configStore.checkPopupDisplay(userState)
const adShownFirst = configStore.showMemberAd === true
// Close the ad
configStore.closeMemberAd()
// Check again - ad should not show
configStore.checkPopupDisplay(userState)
const adNotShownAfterClose = configStore.showMemberAd === false
return adShownFirst && adNotShownAfterClose
}
),
{ numRuns: 100 }
)
})
})