248 lines
6.5 KiB
TypeScript
248 lines
6.5 KiB
TypeScript
/**
|
|
* UploadModal 条件字段测试
|
|
* @jest-environment jsdom
|
|
*/
|
|
|
|
import React from 'react'
|
|
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'
|
|
import '@testing-library/jest-dom'
|
|
|
|
jest.mock('next/image', () => ({
|
|
__esModule: true,
|
|
default: (props: any) => {
|
|
// eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
|
|
return <img {...props} />
|
|
},
|
|
}))
|
|
|
|
jest.mock('@/lib/audio-parser-browser', () => ({
|
|
parseAudioFile: jest.fn(),
|
|
isAudioFile: jest.fn(() => false),
|
|
AUDIO_ACCEPT_TYPES: 'audio/*',
|
|
}))
|
|
|
|
import UploadModal from '../UploadModal'
|
|
|
|
const mockFetch = jest.fn()
|
|
global.fetch = mockFetch
|
|
|
|
global.URL.createObjectURL = jest.fn(() => 'blob:test-url')
|
|
global.URL.revokeObjectURL = jest.fn()
|
|
|
|
const materialTemplate = {
|
|
id: 'template-1',
|
|
name: '条件材质模板',
|
|
description: null,
|
|
materialType: '材质',
|
|
materialKind: 'IMAGE',
|
|
status: 'active',
|
|
isBuiltin: false,
|
|
fields: [
|
|
{
|
|
id: 'field-product',
|
|
key: 'productModel',
|
|
label: '材质名称',
|
|
type: 'text',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'field-conditional',
|
|
key: 'conditionalCode',
|
|
label: '条件编码',
|
|
type: 'text',
|
|
required: true,
|
|
conditions: JSON.stringify({
|
|
logic: 'AND',
|
|
conditions: [{ fieldKey: 'productModel', operator: 'equals', value: '需要编码' }],
|
|
}),
|
|
},
|
|
],
|
|
}
|
|
|
|
const checkboxTemplate = {
|
|
...materialTemplate,
|
|
fields: [
|
|
{
|
|
id: 'field-product',
|
|
key: 'productModel',
|
|
label: '材质名称',
|
|
type: 'text',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'field-checkbox',
|
|
key: 'allowUse',
|
|
label: '允许使用',
|
|
type: 'checkbox',
|
|
required: true,
|
|
},
|
|
],
|
|
}
|
|
|
|
class MockXMLHttpRequest {
|
|
static instances: MockXMLHttpRequest[] = []
|
|
|
|
upload = {
|
|
addEventListener: jest.fn(),
|
|
}
|
|
|
|
timeout = 0
|
|
status = 201
|
|
responseText = '{"success":true}'
|
|
method = ''
|
|
url = ''
|
|
body: FormData | null = null
|
|
private listeners: Record<string, Array<() => void>> = {}
|
|
|
|
constructor() {
|
|
MockXMLHttpRequest.instances.push(this)
|
|
}
|
|
|
|
open(method: string, url: string) {
|
|
this.method = method
|
|
this.url = url
|
|
}
|
|
|
|
send(body: FormData) {
|
|
this.body = body
|
|
this.listeners.load?.forEach((listener) => listener())
|
|
}
|
|
|
|
abort() {
|
|
this.listeners.abort?.forEach((listener) => listener())
|
|
}
|
|
|
|
addEventListener(event: string, listener: () => void) {
|
|
this.listeners[event] = this.listeners[event] || []
|
|
this.listeners[event].push(listener)
|
|
}
|
|
}
|
|
|
|
describe('UploadModal 条件字段', () => {
|
|
const onClose = jest.fn()
|
|
const onSuccess = jest.fn()
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
MockXMLHttpRequest.instances = []
|
|
;(global as any).XMLHttpRequest = MockXMLHttpRequest
|
|
window.localStorage.clear()
|
|
|
|
mockFetch.mockImplementation((url: string) => {
|
|
if (url.includes('/api/upload-templates')) {
|
|
return Promise.resolve({
|
|
ok: true,
|
|
json: () => Promise.resolve([materialTemplate]),
|
|
})
|
|
}
|
|
if (
|
|
url.includes('/api/template-categories') ||
|
|
url.includes('/api/categories') ||
|
|
url.includes('/api/scenes') ||
|
|
url.includes('/api/platforms')
|
|
) {
|
|
return Promise.resolve({
|
|
ok: true,
|
|
json: () => Promise.resolve([]),
|
|
})
|
|
}
|
|
return Promise.resolve({
|
|
ok: false,
|
|
json: () => Promise.resolve({ error: 'Not found' }),
|
|
})
|
|
})
|
|
})
|
|
|
|
it('条件不满足时应隐藏字段且不提交隐藏字段', async () => {
|
|
render(<UploadModal onClose={onClose} onSuccess={onSuccess} />)
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByLabelText('材质名称')).toBeInTheDocument()
|
|
})
|
|
expect(screen.queryByLabelText('条件编码')).not.toBeInTheDocument()
|
|
|
|
fireEvent.change(screen.getByLabelText('材质名称'), {
|
|
target: { value: '普通材质' },
|
|
})
|
|
|
|
await act(async () => {
|
|
fireEvent.click(screen.getByText('上传'))
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(MockXMLHttpRequest.instances.length).toBe(1)
|
|
})
|
|
|
|
const sentBody = MockXMLHttpRequest.instances[0].body
|
|
expect(sentBody?.get('templateId')).toBe('template-1')
|
|
|
|
const templateFields = JSON.parse(String(sentBody?.get('templateFields')))
|
|
expect(templateFields.productModel).toBe('普通材质')
|
|
expect(templateFields.conditionalCode).toBeUndefined()
|
|
})
|
|
|
|
it('依赖字段变化后应显示条件字段并参与必填校验', async () => {
|
|
render(<UploadModal onClose={onClose} onSuccess={onSuccess} />)
|
|
|
|
const productInput = await screen.findByLabelText('材质名称')
|
|
fireEvent.change(productInput, { target: { value: '需要编码' } })
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByLabelText('条件编码')).toBeInTheDocument()
|
|
})
|
|
|
|
await act(async () => {
|
|
fireEvent.click(screen.getByText('上传'))
|
|
})
|
|
|
|
expect(await screen.findByText('请填写必填字段:条件编码')).toBeInTheDocument()
|
|
expect(MockXMLHttpRequest.instances.length).toBe(0)
|
|
})
|
|
|
|
it('必填 checkbox 未勾选也应视为已填写并允许提交 false', async () => {
|
|
mockFetch.mockImplementation((url: string) => {
|
|
if (url.includes('/api/upload-templates')) {
|
|
return Promise.resolve({
|
|
ok: true,
|
|
json: () => Promise.resolve([checkboxTemplate]),
|
|
})
|
|
}
|
|
if (
|
|
url.includes('/api/template-categories') ||
|
|
url.includes('/api/categories') ||
|
|
url.includes('/api/scenes') ||
|
|
url.includes('/api/platforms')
|
|
) {
|
|
return Promise.resolve({
|
|
ok: true,
|
|
json: () => Promise.resolve([]),
|
|
})
|
|
}
|
|
return Promise.resolve({
|
|
ok: false,
|
|
json: () => Promise.resolve({ error: 'Not found' }),
|
|
})
|
|
})
|
|
|
|
render(<UploadModal onClose={onClose} onSuccess={onSuccess} />)
|
|
|
|
const productInput = await screen.findByLabelText('材质名称')
|
|
fireEvent.change(productInput, { target: { value: '普通材质' } })
|
|
|
|
expect(screen.getByLabelText('允许使用')).not.toBeChecked()
|
|
|
|
await act(async () => {
|
|
fireEvent.click(screen.getByText('上传'))
|
|
})
|
|
|
|
await waitFor(() => {
|
|
expect(MockXMLHttpRequest.instances.length).toBe(1)
|
|
})
|
|
expect(screen.queryByText('请填写必填字段:允许使用')).not.toBeInTheDocument()
|
|
|
|
const sentBody = MockXMLHttpRequest.instances[0].body
|
|
const templateFields = JSON.parse(String(sentBody?.get('templateFields')))
|
|
expect(templateFields.allowUse).toBe(false)
|
|
})
|
|
})
|