diff --git a/components/blocks/ui/VideoSocialButton.test.tsx b/components/blocks/ui/VideoSocialButton.test.tsx new file mode 100644 index 0000000..9ad16e5 --- /dev/null +++ b/components/blocks/ui/VideoSocialButton.test.tsx @@ -0,0 +1,193 @@ +import React from 'react' +import { render, fireEvent } from '@testing-library/react-native' +import { VideoSocialButton } from './VideoSocialButton' + +describe('VideoSocialButton Component', () => { + describe('组件导出', () => { + it('应该被定义', () => { + expect(VideoSocialButton).toBeDefined() + }) + + it('应该使用 React.memo 包装', () => { + expect(typeof VideoSocialButton).toBe('object') + }) + }) + + describe('Props 接口', () => { + it('应该接受 templateId 属性', () => { + const props = { templateId: 'test-template-1' } + expect(props.templateId).toBe('test-template-1') + }) + + it('应该接受 liked 属性', () => { + const props = { liked: true } + expect(props.liked).toBe(true) + }) + + it('应该接受 favorited 属性', () => { + const props = { favorited: true } + expect(props.favorited).toBe(true) + }) + + it('应该接受 likeCount 属性', () => { + const props = { likeCount: 100 } + expect(props.likeCount).toBe(100) + }) + + it('应该接受 favoriteCount 属性', () => { + const props = { favoriteCount: 50 } + expect(props.favoriteCount).toBe(50) + }) + + it('应该接受 loading 属性', () => { + const props = { loading: true } + expect(props.loading).toBe(true) + }) + + it('应该接受 onLike 回调', () => { + const onLike = jest.fn() + expect(typeof onLike).toBe('function') + }) + + it('应该接受 onFavorite 回调', () => { + const onFavorite = jest.fn() + expect(typeof onFavorite).toBe('function') + }) + }) + + describe('渲染', () => { + it('应该成功渲染', () => { + const { getByTestId } = render( + + ) + expect(getByTestId('video-social-button')).toBeTruthy() + }) + + it('应该渲染点赞按钮', () => { + const { getByTestId } = render( + + ) + expect(getByTestId('video-social-like-like-button')).toBeTruthy() + }) + + it('应该渲染收藏按钮', () => { + const { getByTestId } = render( + + ) + expect(getByTestId('video-social-favorite-favorite-button')).toBeTruthy() + }) + + it('应该显示点赞数量', () => { + const { getByText } = render( + + ) + expect(getByText('100')).toBeTruthy() + }) + + it('应该显示收藏数量', () => { + const { getByText } = render( + + ) + expect(getByText('50')).toBeTruthy() + }) + }) + + describe('交互', () => { + it('点击点赞按钮应该调用 onLike', () => { + const onLike = jest.fn() + const { getByTestId } = render( + + ) + const likeButton = getByTestId('video-social-on-like-like-button') + fireEvent.press(likeButton) + expect(onLike).toHaveBeenCalledTimes(1) + }) + + it('点击收藏按钮应该调用 onFavorite', () => { + const onFavorite = jest.fn() + const { getByTestId } = render( + + ) + const favoriteButton = getByTestId('video-social-on-favorite-favorite-button') + fireEvent.press(favoriteButton) + expect(onFavorite).toHaveBeenCalledTimes(1) + }) + + it('loading 状态下应该禁用按钮', () => { + const onLike = jest.fn() + const onFavorite = jest.fn() + const { getByTestId } = render( + + ) + const likeButton = getByTestId('video-social-loading-like-button') + const favoriteButton = getByTestId('video-social-loading-favorite-button') + + fireEvent.press(likeButton) + fireEvent.press(favoriteButton) + + expect(onLike).not.toHaveBeenCalled() + expect(onFavorite).not.toHaveBeenCalled() + }) + }) + + describe('样式', () => { + it('应该使用垂直布局', () => { + const { getByTestId } = render( + + ) + const container = getByTestId('video-social-vertical') + expect(container).toBeTruthy() + }) + + it('应该使用圆形背景样式', () => { + const { getByTestId } = render( + + ) + const container = getByTestId('video-social-round') + expect(container).toBeTruthy() + }) + }) + + describe('边界情况', () => { + it('应该处理零数量', () => { + const { getByText } = render( + + ) + expect(getByText('0')).toBeTruthy() + }) + + it('应该处理大数量', () => { + const { getByText } = render( + + ) + expect(getByText('9999')).toBeTruthy() + expect(getByText('8888')).toBeTruthy() + }) + + it('应该处理缺失的回调函数', () => { + const { getByTestId } = render( + + ) + const likeButton = getByTestId('video-social-no-callback-like-button') + const favoriteButton = getByTestId('video-social-no-callback-favorite-button') + + expect(() => { + fireEvent.press(likeButton) + fireEvent.press(favoriteButton) + }).not.toThrow() + }) + + it('应该同时处理已点赞和已收藏状态', () => { + const { getByTestId } = render( + + ) + expect(getByTestId('video-social-both')).toBeTruthy() + }) + }) +}) diff --git a/components/blocks/ui/VideoSocialButton.tsx b/components/blocks/ui/VideoSocialButton.tsx new file mode 100644 index 0000000..5d1be25 --- /dev/null +++ b/components/blocks/ui/VideoSocialButton.tsx @@ -0,0 +1,115 @@ +import React, { memo, useCallback, useMemo } from 'react' +import { View, StyleSheet } from 'react-native' +import { LikeButton, LikeButtonProps } from './LikeButton' +import { FavoriteButton, FavoriteButtonProps } from './FavoriteButton' + +export interface VideoSocialButtonProps { + templateId: string + liked?: boolean + favorited?: boolean + likeCount?: number + favoriteCount?: number + loading?: boolean + onLike?: () => void + onUnlike?: () => void + onFavorite?: () => void + onUnfavorite?: () => void + testID?: string +} + +const VideoSocialButtonComponent: React.FC = ({ + templateId, + liked = false, + favorited = false, + likeCount, + favoriteCount, + loading = false, + onLike, + onUnlike, + onFavorite, + onUnfavorite, + testID, +}) => { + // 处理点赞按钮点击 + const handleLikePress = useCallback(() => { + if (!loading) { + if (liked) { + onUnlike?.() + } else { + onLike?.() + } + } + }, [loading, liked, onLike, onUnlike]) + + // 处理收藏按钮点击 + const handleFavoritePress = useCallback(() => { + if (!loading) { + if (favorited) { + onUnfavorite?.() + } else { + onFavorite?.() + } + } + }, [loading, favorited, onFavorite, onUnfavorite]) + + // LikeButton 的 props + const likeButtonProps: LikeButtonProps = useMemo( + () => ({ + liked, + loading, + count: likeCount, + onPress: handleLikePress, + testID: testID ? `${testID}-like-button` : undefined, + }), + [liked, loading, likeCount, handleLikePress, testID] + ) + + // FavoriteButton 的 props + const favoriteButtonProps: FavoriteButtonProps = useMemo( + () => ({ + favorited, + loading, + count: favoriteCount, + onPress: handleFavoritePress, + testID: testID ? `${testID}-favorite-button` : undefined, + }), + [favorited, loading, favoriteCount, handleFavoritePress, testID] + ) + + return ( + + {/* 点赞按钮 */} + + + + + {/* 收藏按钮 */} + + + + + ) +} + +export const VideoSocialButton = memo(VideoSocialButtonComponent) + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + right: 13, + bottom: 100, + flexDirection: 'column', + alignItems: 'center', + gap: 16, + }, + button: { + width: 48, + height: 48, + borderRadius: 24, + backgroundColor: 'rgba(25, 27, 31, 0.8)', + justifyContent: 'center', + alignItems: 'center', + borderWidth: 1, + borderColor: 'rgba(47, 49, 52, 1)', + }, +})