expo-popcore-app/components/blocks/home/HeroSlider.test.tsx

124 lines
3.9 KiB
TypeScript

import { HeroSlider } from './HeroSlider'
const mockActivities = [
{
id: '1',
title: '活动标题1',
titleEn: 'Activity Title 1',
desc: '活动描述1',
descEn: 'Activity Description 1',
coverUrl: 'https://example.com/image1.jpg',
link: '/activity/1',
},
{
id: '2',
title: '活动标题2',
desc: '活动描述2',
coverUrl: 'https://example.com/image2.jpg',
link: '/activity/2',
},
]
describe('HeroSlider Component', () => {
describe('Component Export', () => {
it('should be defined', () => {
expect(HeroSlider).toBeDefined()
})
it('should be a function component', () => {
expect(typeof HeroSlider).toBe('function')
})
})
describe('Props Interface', () => {
it('should accept activities prop', () => {
const props = { activities: mockActivities }
expect(props.activities).toEqual(mockActivities)
expect(props.activities.length).toBe(2)
})
it('should accept onActivityPress callback', () => {
const onActivityPress = jest.fn()
expect(typeof onActivityPress).toBe('function')
})
it('should have activity with required fields', () => {
const activity = mockActivities[0]
expect(activity.id).toBeDefined()
expect(activity.title).toBeDefined()
expect(activity.desc).toBeDefined()
expect(activity.coverUrl).toBeDefined()
expect(activity.link).toBeDefined()
})
it('should have activity with optional fields', () => {
const activity = mockActivities[0]
expect(activity.titleEn).toBeDefined()
expect(activity.descEn).toBeDefined()
})
})
describe('Empty State', () => {
it('should return null when activities is empty array', () => {
const result = HeroSlider({ activities: [] })
expect(result).toBeNull()
})
it('should return null when activities is undefined', () => {
const result = HeroSlider({ activities: undefined as any })
expect(result).toBeNull()
})
})
describe('Render Behavior', () => {
it('should return JSX element when activities has items', () => {
const result = HeroSlider({ activities: mockActivities })
expect(result).not.toBeNull()
})
})
describe('Callback Behavior', () => {
it('should call onActivityPress with link when activity is pressed', () => {
const onActivityPress = jest.fn()
const props: { activities: typeof mockActivities; onActivityPress?: (link: string) => void } = {
activities: mockActivities,
onActivityPress,
}
// Verify callback can be invoked with link
props.onActivityPress(mockActivities[0].link)
expect(onActivityPress).toHaveBeenCalledWith('/activity/1')
})
it('should not throw when onActivityPress is not provided', () => {
const props: { activities: typeof mockActivities; onActivityPress?: (link: string) => void } = { activities: mockActivities }
expect(() => {
if (props.onActivityPress) {
props.onActivityPress(mockActivities[0].link)
}
}).not.toThrow()
})
})
describe('Slider Layout', () => {
it('should have fixed width for slide container to enable horizontal scrolling', () => {
const { StyleSheet } = require('react-native')
const { HeroSlider } = require('./HeroSlider')
// 读取组件文件内容来验证样式定义
const fs = require('fs')
const path = require('path')
const componentPath = path.join(__dirname, 'HeroSlider.tsx')
const componentContent = fs.readFileSync(componentPath, 'utf-8')
// 验证 heroMainSlide 样式包含固定宽度265
expect(componentContent).toContain('heroMainSlide: {')
expect(componentContent).toContain('width: 265')
// 验证不包含 width: '100%'
const heroMainSlideMatch = componentContent.match(/heroMainSlide:\s*{[^}]*}/s)
expect(heroMainSlideMatch).toBeTruthy()
expect(heroMainSlideMatch![0]).not.toContain("width: '100%'")
})
})
})