272 lines
8.0 KiB
TypeScript
272 lines
8.0 KiB
TypeScript
import React from 'react'
|
|
import { render, waitFor, fireEvent } from '@testing-library/react-native'
|
|
import MembershipScreen from '../membership'
|
|
|
|
// Mock react-native-safe-area-context FIRST
|
|
jest.mock('react-native-safe-area-context', () => ({
|
|
SafeAreaProvider: ({ children }: any) => children,
|
|
SafeAreaView: ({ children }: any) => children,
|
|
useSafeAreaInsets: () => ({ top: 0, right: 0, bottom: 0, left: 0 }),
|
|
}))
|
|
|
|
// Mock expo-linear-gradient
|
|
jest.mock('expo-linear-gradient', () => ({
|
|
LinearGradient: 'LinearGradient',
|
|
}))
|
|
|
|
// Mock expo-image
|
|
jest.mock('expo-image', () => ({
|
|
Image: 'Image',
|
|
}))
|
|
|
|
// Mock expo-status-bar
|
|
jest.mock('expo-status-bar', () => ({
|
|
StatusBar: 'StatusBar',
|
|
}))
|
|
|
|
// Mock react-native-svg
|
|
jest.mock('react-native-svg', () => ({
|
|
Svg: 'Svg',
|
|
Path: 'Path',
|
|
Defs: 'Defs',
|
|
LinearGradient: 'LinearGradient',
|
|
Stop: 'Stop',
|
|
}))
|
|
|
|
// Mock react-native-reanimated-carousel
|
|
jest.mock('react-native-reanimated-carousel', () => {
|
|
const React = require('react')
|
|
return {
|
|
__esModule: true,
|
|
default: ({ data, renderItem, onSnapToItem }: any) => {
|
|
return React.createElement(
|
|
'View',
|
|
{ testID: 'carousel' },
|
|
data.map((item: any, index: number) =>
|
|
React.createElement(
|
|
'View',
|
|
{ key: index, testID: `carousel-item-${index}` },
|
|
renderItem({ item, index })
|
|
)
|
|
)
|
|
)
|
|
},
|
|
}
|
|
})
|
|
|
|
// Mock icons
|
|
jest.mock('@/components/icon', () => ({
|
|
CheckIcon: () => 'CheckIcon',
|
|
LeftArrowIcon: () => 'LeftArrowIcon',
|
|
OmitIcon: () => 'OmitIcon',
|
|
UncheckedIcon: () => 'UncheckedIcon',
|
|
TermsIcon: () => 'TermsIcon',
|
|
PrivacyIcon: () => 'PrivacyIcon',
|
|
}))
|
|
|
|
jest.mock('@/components/icon/checkMark', () => ({
|
|
CheckMarkIcon: () => 'CheckMarkIcon',
|
|
}))
|
|
|
|
// Mock components
|
|
jest.mock('@/components/drawer/PointsDrawer', () => {
|
|
const React = require('react')
|
|
return {
|
|
__esModule: true,
|
|
default: () => null,
|
|
}
|
|
})
|
|
jest.mock('@/components/ui/dropdown', () => {
|
|
const React = require('react')
|
|
return {
|
|
__esModule: true,
|
|
default: ({ renderTrigger }: any) => {
|
|
return renderTrigger ? renderTrigger(null, false, jest.fn()) : null
|
|
},
|
|
}
|
|
})
|
|
jest.mock('@/components/GradientText', () => {
|
|
const React = require('react')
|
|
return {
|
|
__esModule: true,
|
|
default: ({ children }: any) => children,
|
|
}
|
|
})
|
|
|
|
// Mock expo-router
|
|
jest.mock('expo-router', () => ({
|
|
useRouter: jest.fn(() => ({
|
|
push: jest.fn(),
|
|
back: jest.fn(),
|
|
})),
|
|
}))
|
|
|
|
// Mock react-i18next
|
|
jest.mock('react-i18next', () => ({
|
|
useTranslation: () => ({
|
|
t: (key: string) => key,
|
|
}),
|
|
}))
|
|
|
|
// Mock hooks - 默认返回空广告数据
|
|
const mockLoadActivates = jest.fn()
|
|
const mockActivatesData = {
|
|
activities: [],
|
|
}
|
|
|
|
jest.mock('@/hooks/use-activates', () => ({
|
|
useActivates: jest.fn(() => ({
|
|
load: mockLoadActivates,
|
|
data: mockActivatesData,
|
|
})),
|
|
}))
|
|
|
|
jest.mock('@/hooks/use-membership', () => ({
|
|
useMembership: jest.fn(() => ({
|
|
creditPlans: [
|
|
{
|
|
name: 'Plus',
|
|
amountInCents: 999,
|
|
popular: false,
|
|
credits: 100,
|
|
currency: 'USD',
|
|
featureList: ['feature1', 'feature2'],
|
|
},
|
|
],
|
|
creditBalance: 50,
|
|
selectedPlanIndex: 0,
|
|
setSelectedPlanIndex: jest.fn(),
|
|
isLoadingSubscriptions: false,
|
|
isStripePricingLoading: false,
|
|
createSubscription: jest.fn(),
|
|
upgradeSubscription: jest.fn(),
|
|
restoreSubscription: jest.fn(),
|
|
rechargeToken: jest.fn(),
|
|
activeAuthSubscription: null,
|
|
hasActiveSubscription: false,
|
|
stripePricingData: null,
|
|
})),
|
|
}))
|
|
|
|
describe('MembershipScreen - Advertisement Carousel', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
describe('广告轮播显示', () => {
|
|
it('当广告数据为空时,应该隐藏轮播图', () => {
|
|
const { queryByTestId } = render(<MembershipScreen />)
|
|
|
|
// 轮播图不应该显示
|
|
expect(queryByTestId('carousel')).toBeNull()
|
|
})
|
|
|
|
it('当广告数据存在时,应该显示轮播图', () => {
|
|
// 设置有广告数据的mock
|
|
const { useActivates } = require('@/hooks/use-activates')
|
|
useActivates.mockReturnValue({
|
|
load: mockLoadActivates,
|
|
data: {
|
|
activities: [
|
|
{
|
|
id: '1',
|
|
title: 'Test Ad 1',
|
|
desc: 'Description 1',
|
|
coverUrl: 'https://example.com/ad1.jpg',
|
|
link: '/ad1',
|
|
},
|
|
{
|
|
id: '2',
|
|
title: 'Test Ad 2',
|
|
desc: 'Description 2',
|
|
coverUrl: 'https://example.com/ad2.jpg',
|
|
link: '/ad2',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const { getByTestId } = render(<MembershipScreen />)
|
|
|
|
// 轮播图应该显示
|
|
expect(getByTestId('carousel')).toBeTruthy()
|
|
})
|
|
|
|
it('应该在组件挂载时加载广告数据', () => {
|
|
render(<MembershipScreen />)
|
|
|
|
// 应该调用 loadActivates
|
|
expect(mockLoadActivates).toHaveBeenCalled()
|
|
})
|
|
})
|
|
|
|
describe('广告点击跳转', () => {
|
|
it('点击广告时应该跳转到正确的链接', () => {
|
|
const mockPush = jest.fn()
|
|
const { useRouter } = require('expo-router')
|
|
useRouter.mockReturnValue({
|
|
push: mockPush,
|
|
back: jest.fn(),
|
|
})
|
|
|
|
const { useActivates } = require('@/hooks/use-activates')
|
|
useActivates.mockReturnValue({
|
|
load: mockLoadActivates,
|
|
data: {
|
|
activities: [
|
|
{
|
|
id: '1',
|
|
title: 'Test Ad',
|
|
desc: 'Description',
|
|
coverUrl: 'https://example.com/ad.jpg',
|
|
link: '/test-link',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const { getByTestId } = render(<MembershipScreen />)
|
|
|
|
// 点击第一个广告
|
|
const carouselItem = getByTestId('carousel-item-0')
|
|
fireEvent.press(carouselItem)
|
|
|
|
// 应该跳转到广告链接
|
|
expect(mockPush).toHaveBeenCalledWith('/test-link')
|
|
})
|
|
})
|
|
|
|
describe('广告轮播指示点', () => {
|
|
it('当有多个广告时,应该显示指示点', () => {
|
|
const { useActivates } = require('@/hooks/use-activates')
|
|
useActivates.mockReturnValue({
|
|
load: mockLoadActivates,
|
|
data: {
|
|
activities: [
|
|
{
|
|
id: '1',
|
|
title: 'Ad 1',
|
|
desc: 'Desc 1',
|
|
coverUrl: 'https://example.com/ad1.jpg',
|
|
link: '/ad1',
|
|
},
|
|
{
|
|
id: '2',
|
|
title: 'Ad 2',
|
|
desc: 'Desc 2',
|
|
coverUrl: 'https://example.com/ad2.jpg',
|
|
link: '/ad2',
|
|
},
|
|
],
|
|
},
|
|
})
|
|
|
|
const { getAllByTestId } = render(<MembershipScreen />)
|
|
|
|
// 应该有2个指示点
|
|
const dots = getAllByTestId(/^dot-/)
|
|
expect(dots).toHaveLength(2)
|
|
})
|
|
})
|
|
})
|