243 lines
8.4 KiB
JavaScript
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 }
|
|
)
|
|
})
|
|
})
|