first commit
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
import * as React from 'react'
|
||||
import { createElement } from 'react'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { NextIntlClientProvider } from 'next-intl'
|
||||
import type { AbstractIntlMessages } from 'next-intl'
|
||||
import { AI_EDIT_BUTTON_CLASS } from '@/components/ui/ai-edit-style'
|
||||
|
||||
const locationImageListMock = vi.hoisted(() => vi.fn((props: { overlayActions?: React.ReactNode }) => createElement('div', null, props.overlayActions ?? null)))
|
||||
const uploadMutationMock = vi.hoisted(() => ({
|
||||
isPending: false,
|
||||
mutate: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/query/mutations', () => ({
|
||||
useUploadProjectLocationImage: () => uploadMutationMock,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/assets/location-card/LocationCardHeader', () => ({
|
||||
default: () => createElement('div', null),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/assets/location-card/LocationCardActions', () => ({
|
||||
default: () => createElement('div', null),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/assets/location-card/LocationImageList', () => ({
|
||||
default: locationImageListMock,
|
||||
}))
|
||||
|
||||
vi.mock('@/components/ui/icons', () => ({
|
||||
AppIcon: () => createElement('span', null),
|
||||
}))
|
||||
|
||||
vi.mock('@/components/ui/icons/AISparklesIcon', () => ({
|
||||
default: (props: { className?: string }) => createElement('svg', { className: props.className, 'data-icon': 'ai-sparkles' }),
|
||||
}))
|
||||
|
||||
vi.mock('@/components/task/TaskStatusInline', () => ({
|
||||
default: () => createElement('span', null),
|
||||
}))
|
||||
|
||||
vi.mock('@/components/image-generation/ImageGenerationInlineCountButton', () => ({
|
||||
default: () => createElement('button', null),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/image-generation/use-image-generation-count', () => ({
|
||||
useImageGenerationCount: () => ({
|
||||
count: 1,
|
||||
setCount: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/image-generation/count', () => ({
|
||||
getImageGenerationCountOptions: () => [{ value: 1, label: '1' }],
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/task/presentation', () => ({
|
||||
resolveTaskPresentationState: () => null,
|
||||
}))
|
||||
|
||||
const messages = {
|
||||
assets: {
|
||||
image: {
|
||||
upload: '上传图片',
|
||||
uploadReplace: '上传替换图片',
|
||||
edit: '编辑图片',
|
||||
undo: '撤回',
|
||||
regenerateStuck: '重新生成',
|
||||
},
|
||||
location: {
|
||||
regenerateImage: '重新生成场景',
|
||||
edit: '编辑场景',
|
||||
delete: '删除场景',
|
||||
},
|
||||
prop: {
|
||||
regenerateImage: '重新生成道具',
|
||||
edit: '编辑道具',
|
||||
delete: '删除道具',
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
const TestIntlProvider = NextIntlClientProvider as React.ComponentType<{
|
||||
locale: string
|
||||
messages: AbstractIntlMessages
|
||||
timeZone: string
|
||||
children?: React.ReactNode
|
||||
}>
|
||||
|
||||
describe('LocationCard AI edit button', () => {
|
||||
it('uses the shared AI edit button style in single-image mode', async () => {
|
||||
locationImageListMock.mockClear()
|
||||
Reflect.set(globalThis, 'React', React)
|
||||
const { default: LocationCard } = await import('@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/assets/LocationCard')
|
||||
const html = renderToStaticMarkup(
|
||||
createElement(
|
||||
TestIntlProvider,
|
||||
{
|
||||
locale: 'zh',
|
||||
messages: messages as unknown as AbstractIntlMessages,
|
||||
timeZone: 'Asia/Shanghai',
|
||||
},
|
||||
createElement(LocationCard, {
|
||||
location: {
|
||||
id: 'prop-1',
|
||||
name: '银质餐具',
|
||||
summary: '银质西式餐具套装',
|
||||
selectedImageId: 'prop-image-1',
|
||||
images: [
|
||||
{
|
||||
id: 'prop-image-1',
|
||||
imageIndex: 0,
|
||||
description: '银质餐具套装,包含刀叉与汤匙,金属光泽冷白',
|
||||
imageUrl: 'https://example.com/prop.png',
|
||||
previousImageUrl: null,
|
||||
previousDescription: null,
|
||||
isSelected: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
assetType: 'prop',
|
||||
onEdit: () => undefined,
|
||||
onDelete: () => undefined,
|
||||
onRegenerate: () => undefined,
|
||||
onGenerate: () => undefined,
|
||||
onImageClick: () => undefined,
|
||||
onImageEdit: () => undefined,
|
||||
projectId: 'project-1',
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
expect(html).toContain('data-icon=\"ai-sparkles\"')
|
||||
for (const token of AI_EDIT_BUTTON_CLASS.split(' ')) {
|
||||
expect(html).toContain(token)
|
||||
}
|
||||
const firstCall = locationImageListMock.mock.calls[0]?.[0] as { aspectClassName?: string } | undefined
|
||||
expect(firstCall?.aspectClassName).toBe('aspect-[3/2]')
|
||||
})
|
||||
|
||||
it('passes a square image slot to project location cards', async () => {
|
||||
locationImageListMock.mockClear()
|
||||
Reflect.set(globalThis, 'React', React)
|
||||
const { default: LocationCard } = await import('@/app/[locale]/workspace/[projectId]/modes/novel-promotion/components/assets/LocationCard')
|
||||
renderToStaticMarkup(
|
||||
createElement(
|
||||
TestIntlProvider,
|
||||
{
|
||||
locale: 'zh',
|
||||
messages: messages as unknown as AbstractIntlMessages,
|
||||
timeZone: 'Asia/Shanghai',
|
||||
},
|
||||
createElement(LocationCard, {
|
||||
location: {
|
||||
id: 'location-1',
|
||||
name: '餐厅',
|
||||
summary: '极简餐厅',
|
||||
selectedImageId: 'location-image-1',
|
||||
images: [
|
||||
{
|
||||
id: 'location-image-1',
|
||||
imageIndex: 0,
|
||||
description: '极简餐厅室内空间',
|
||||
imageUrl: 'https://example.com/location.png',
|
||||
previousImageUrl: null,
|
||||
previousDescription: null,
|
||||
isSelected: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
assetType: 'location',
|
||||
onEdit: () => undefined,
|
||||
onDelete: () => undefined,
|
||||
onRegenerate: () => undefined,
|
||||
onGenerate: () => undefined,
|
||||
onImageClick: () => undefined,
|
||||
onImageEdit: () => undefined,
|
||||
projectId: 'project-1',
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
const firstCall = locationImageListMock.mock.calls[0]?.[0] as { aspectClassName?: string } | undefined
|
||||
expect(firstCall?.aspectClassName).toBe('aspect-square')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user