diff --git a/app/(tabs)/video.tsx b/app/(tabs)/video.tsx
index d8b5798..9dae9da 100644
--- a/app/(tabs)/video.tsx
+++ b/app/(tabs)/video.tsx
@@ -173,8 +173,13 @@ export default function VideoScreen() {
// 过滤掉视频类型的 item
const filteredTemplates = templates.filter((item: TemplateDetail) => {
- const displayUrl = item.webpPreviewUrl || item.previewUrl
- return !(displayUrl && isVideoUrl(displayUrl))
+ // 检查所有可能的预览 URL,如果任何一个包含视频格式则过滤掉
+ const hasVideoUrl = [
+ item.webpHighPreviewUrl,
+ item.webpPreviewUrl,
+ item.previewUrl,
+ ].some(url => url && isVideoUrl(url))
+ return !hasVideoUrl
})
if (loading && templates.length === 0) return
diff --git a/app/generateVideo.test.tsx b/app/generateVideo.test.tsx
index 579d9f7..9458732 100644
--- a/app/generateVideo.test.tsx
+++ b/app/generateVideo.test.tsx
@@ -305,11 +305,26 @@ describe('GenerateVideo Screen', () => {
})
it('should call runTemplate with correct parameters when form is valid', async () => {
+ // Use template without image node from the start
+ const templateWithoutImageNode = {
+ ...mockTemplateDetail,
+ formSchema: {
+ startNodes: [
+ {
+ id: 'node_1',
+ type: 'text',
+ },
+ ],
+ },
+ }
+
+ const mockExecute = jest.fn()
+
mockUseTemplateDetail.mockReturnValue({
- data: mockTemplateDetail,
+ data: templateWithoutImageNode,
loading: false,
error: null,
- execute: jest.fn(),
+ execute: mockExecute,
} as any)
const mockRunTemplate = jest.fn().mockResolvedValue({
@@ -329,32 +344,7 @@ describe('GenerateVideo Screen', () => {
const descriptionInput = getByPlaceholderText('generateVideo.descriptionPlaceholder')
fireEvent.changeText(descriptionInput, 'Test description')
- // Note: Image upload is handled through a drawer, which is mocked
- // In a real test, we would need to simulate the image upload flow
-
- // For now, we test with a template that doesn't require image
- const templateWithoutImageNode = {
- ...mockTemplateDetail,
- formSchema: {
- startNodes: [
- {
- id: 'node_1',
- type: 'text',
- },
- ],
- },
- }
-
- mockUseTemplateDetail.mockReturnValue({
- data: templateWithoutImageNode,
- loading: false,
- error: null,
- execute: jest.fn(),
- } as any)
-
- const { getByText: getByText2 } = render()
-
- const generateButton = getByText2('generateVideo.generate')
+ const generateButton = getByText('generateVideo.generate')
fireEvent.press(generateButton)
await waitFor(() => {
@@ -423,7 +413,7 @@ describe('GenerateVideo Screen', () => {
await waitFor(() => {
expect(Toast.show).toHaveBeenCalledWith({
- title: 'generateVideo.generateFailed',
+ title: 'Generation failed',
})
})
})
diff --git a/app/templateDetail.test.tsx b/app/templateDetail.test.tsx
index 4cc2ea7..a0f2890 100644
--- a/app/templateDetail.test.tsx
+++ b/app/templateDetail.test.tsx
@@ -33,31 +33,40 @@ jest.mock('react-native-safe-area-context', () => ({
// Mock components
jest.mock('@/components/icon', () => ({
- LeftArrowIcon: 'LeftArrowIcon',
+ LeftArrowIcon: () => null,
}))
jest.mock('@/components/SearchResultsGrid', () => ({
__esModule: true,
- default: 'SearchResultsGrid',
+ default: () => null,
}))
-jest.mock('@/components/DynamicForm', () => ({
- __esModule: true,
- DynamicForm: ({ formSchema, onSubmit }: any) => (
-
- onSubmit({})}>Submit Form
-
- ),
- FormSchema: {},
-}))
+jest.mock('@/components/DynamicForm', () => {
+ const { View, Text } = require('react-native')
+ return {
+ __esModule: true,
+ DynamicForm: React.forwardRef(({ formSchema, onSubmit, onOpenDrawer }: any, ref: any) => (
+
+ onSubmit({})}>Submit Form
+
+ )),
+ }
+})
jest.mock('@/components/ui/Toast', () => ({
__esModule: true,
default: {
show: jest.fn(),
+ showLoading: jest.fn(),
+ hideLoading: jest.fn(),
},
}))
+jest.mock('@/components/drawer/UploadReferenceImageDrawer', () => ({
+ __esModule: true,
+ default: () => null,
+}))
+
// Mock hooks
jest.mock('@/hooks', () => ({
useTemplateActions: jest.fn(() => ({
diff --git a/components/DynamicForm.test.tsx b/components/DynamicForm.test.tsx
index 1d097cc..99867ab 100644
--- a/components/DynamicForm.test.tsx
+++ b/components/DynamicForm.test.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import { render, fireEvent, waitFor } from '@testing-library/react-native'
-import { View } from 'react-native'
+import { View, Pressable, TextInput, ActivityIndicator } from 'react-native'
import { DynamicForm, type FormSchema } from './DynamicForm'
// Mock expo-router
@@ -23,11 +23,11 @@ jest.mock('react-i18next', () => ({
})),
}))
+// Mock AIGenerationRecordDrawer BEFORE UploadReferenceImageDrawer
+jest.mock('./drawer/AIGenerationRecordDrawer', () => 'AIGenerationRecordDrawer')
+
// Mock UploadReferenceImageDrawer
-jest.mock('./drawer/UploadReferenceImageDrawer', () => ({
- __esModule: true,
- default: 'UploadReferenceImageDrawer',
-}))
+jest.mock('./drawer/UploadReferenceImageDrawer', () => 'UploadReferenceImageDrawer')
// Mock uploadFile
jest.mock('@/lib/uploadFile', () => ({
@@ -44,22 +44,31 @@ jest.mock('./ui/Toast', () => ({
},
}))
-// Mock Button
+// Mock Button with proper React Native components
jest.mock('./ui/button', () => ({
- Button: ({ children, onPress, disabled }: any) => (
-
+
),
}))
-// Mock Text component
-jest.mock('./ui/Text', () => ({
- __esModule: true,
- default: ({ children, ...props }: any) => {children},
-}))
+// Mock Text component to handle nested text properly
+jest.mock('./ui/Text', () => {
+ const { Text } = require('react-native')
+ return {
+ __esModule: true,
+ default: Text,
+ }
+})
-import Text from './ui/Text'
+// Get mock functions
const uploadFile = require('@/lib/uploadFile').uploadFile
const Toast = require('./ui/Toast').default
@@ -98,7 +107,7 @@ describe('DynamicForm Component', () => {
)
- expect(getByText('文本节点')).toBeTruthy()
+ expect(getByText('文本节点', { exact: false })).toBeTruthy()
// Input placeholder is tested via testID instead
expect(getByTestId('text-input-node_1')).toBeTruthy()
})
@@ -120,7 +129,7 @@ describe('DynamicForm Component', () => {
)
- expect(getByText('图片节点')).toBeTruthy()
+ expect(getByText('图片节点', { exact: false })).toBeTruthy()
expect(getByText('dynamicForm.uploadImage')).toBeTruthy()
})
@@ -141,7 +150,7 @@ describe('DynamicForm Component', () => {
)
- expect(getByText('视频节点')).toBeTruthy()
+ expect(getByText('视频节点', { exact: false })).toBeTruthy()
expect(getByText('dynamicForm.uploadVideo')).toBeTruthy()
})
@@ -170,9 +179,9 @@ describe('DynamicForm Component', () => {
)
- expect(getByText('文本')).toBeTruthy()
- expect(getByText('图片')).toBeTruthy()
- expect(getByText('视频')).toBeTruthy()
+ expect(getByText('文本', { exact: false })).toBeTruthy()
+ expect(getByText('图片', { exact: false })).toBeTruthy()
+ expect(getByText('视频', { exact: false })).toBeTruthy()
})
})
@@ -209,11 +218,11 @@ describe('DynamicForm Component', () => {
],
}
- const { getByText } = render(
+ const { getByTestId } = render(
)
- const submitButton = getByText('dynamicForm.submit')
+ const submitButton = getByTestId('submit-button')
fireEvent.press(submitButton)
await waitFor(() => {
@@ -234,11 +243,11 @@ describe('DynamicForm Component', () => {
],
}
- const { getByTestId, getByText, queryByText } = render(
+ const { getByTestId, queryByText } = render(
)
- const submitButton = getByText('dynamicForm.submit')
+ const submitButton = getByTestId('submit-button')
fireEvent.press(submitButton)
await waitFor(() => {
@@ -288,11 +297,11 @@ describe('DynamicForm Component', () => {
],
}
- const { getByText } = render(
+ const { getByTestId } = render(
)
- const submitButton = getByText('dynamicForm.submit')
+ const submitButton = getByTestId('submit-button')
fireEvent.press(submitButton)
await waitFor(() => {
@@ -367,11 +376,11 @@ describe('DynamicForm Component', () => {
],
}
- const { getByText } = render(
+ const { getByTestId } = render(
)
- const submitButton = getByText('dynamicForm.submit')
+ const submitButton = getByTestId('submit-button')
expect(submitButton).toBeTruthy()
})
@@ -390,14 +399,14 @@ describe('DynamicForm Component', () => {
error: { message: 'Submission failed' },
})
- const { getByTestId, getByText } = render(
+ const { getByTestId } = render(
)
const input = getByTestId('text-input-node_1')
fireEvent.changeText(input, 'Test content')
- const submitButton = getByText('dynamicForm.submit')
+ const submitButton = getByTestId('submit-button')
fireEvent.press(submitButton)
await waitFor(() => {
diff --git a/components/DynamicForm.tsx b/components/DynamicForm.tsx
index 9f732b9..4bf9f0d 100644
--- a/components/DynamicForm.tsx
+++ b/components/DynamicForm.tsx
@@ -199,6 +199,7 @@ export const DynamicForm = forwardRef(
)}
updateFormData(node.id, text)}
@@ -399,6 +400,7 @@ export const DynamicForm = forwardRef(