91 lines
2.6 KiB
JavaScript
91 lines
2.6 KiB
JavaScript
/**
|
|
* Property-based tests for authentication handling
|
|
* **Feature: miniapp-frontend, Property 2: Auth Redirect on Invalid Token**
|
|
* **Validates: Requirements 1.4**
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach } from 'vitest'
|
|
import * as fc from 'fast-check'
|
|
|
|
// Import mock before other modules
|
|
import '../mocks/uni.js'
|
|
import { setToken, getToken } from '../../utils/storage.js'
|
|
import { handleUnauthorized } from '../../api/request.js'
|
|
|
|
describe('Auth Property Tests', () => {
|
|
beforeEach(() => {
|
|
// Clear storage and reset redirect state before each test
|
|
uni._clearStorage()
|
|
uni._resetRedirectState()
|
|
})
|
|
|
|
/**
|
|
* Property 2: Auth Redirect on Invalid Token
|
|
* *For any* API response with 401 status code, the application SHALL
|
|
* clear the stored token.
|
|
* Note: Redirect is handled by the caller, not handleUnauthorized itself
|
|
* **Validates: Requirements 1.4**
|
|
*/
|
|
it('Property 2: Auth Redirect on Invalid Token - 401 should clear token', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
// Generate any token that might be stored
|
|
fc.string({ minLength: 1 }).filter(s => s.trim().length > 0),
|
|
(token) => {
|
|
// Setup: Store a token (simulating logged-in state)
|
|
setToken(token)
|
|
|
|
// Verify token is stored
|
|
const storedToken = getToken()
|
|
if (storedToken !== token) return false
|
|
|
|
// Action: Handle unauthorized (simulating 401 response)
|
|
handleUnauthorized()
|
|
|
|
// Verify: Token should be cleared
|
|
const tokenAfterUnauth = getToken()
|
|
const tokenCleared = tokenAfterUnauth === ''
|
|
|
|
// Reset for next iteration
|
|
uni._clearStorage()
|
|
|
|
return tokenCleared
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
)
|
|
})
|
|
|
|
/**
|
|
* Property: handleUnauthorized should be idempotent
|
|
* Calling it multiple times should have the same effect as calling once
|
|
*/
|
|
it('handleUnauthorized should be idempotent', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.string({ minLength: 1 }).filter(s => s.trim().length > 0),
|
|
fc.integer({ min: 1, max: 5 }),
|
|
(token, callCount) => {
|
|
// Setup
|
|
setToken(token)
|
|
|
|
// Call handleUnauthorized multiple times
|
|
for (let i = 0; i < callCount; i++) {
|
|
handleUnauthorized()
|
|
}
|
|
|
|
// Token should still be cleared
|
|
const tokenAfter = getToken()
|
|
const tokenCleared = tokenAfter === ''
|
|
|
|
// Cleanup
|
|
uni._clearStorage()
|
|
|
|
return tokenCleared
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
)
|
|
})
|
|
})
|