124 lines
3.9 KiB
TypeScript
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%'")
|
|
})
|
|
})
|
|
})
|