mirror of
https://github.com/langgenius/dify.git
synced 2026-11-10 21:35:45 +08:00
test(web): replace AP1/AP3/AP32 list and output doubles (#45313)
This commit is contained in:
1 parent
53ea596fc7
commit
3dc973ac34
3 files changed
+210
-131
No files matched your search
@@ -1,66 +1,99 @@
|
||||
import type { Plugin } from '@/app/components/plugins/types'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import type { MarketplaceCollection } from '@dify/contracts/marketplace'
|
||||
import type { ReactElement } from 'react'
|
||||
import { screen } from '@testing-library/react'
|
||||
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
|
||||
import { describe, expect, it, vi } from 'vite-plus/test'
|
||||
import {
|
||||
createPluginInstallPermissionStore,
|
||||
PluginInstallPermissionContext,
|
||||
} from '@/app/components/plugins/install-plugin/hooks/use-plugin-install-permission'
|
||||
import { renderWithConsoleQuery } from '@/test/console/query-data'
|
||||
import { createMarketplacePluginFixture, createPluginEntity } from '@/test/fixtures/plugin'
|
||||
import List from '../index'
|
||||
|
||||
vi.mock(
|
||||
'@/app/components/plugins/install-plugin/components/plugin-install-permission-provider',
|
||||
() => ({
|
||||
PluginInstallPermissionProviderGuard: ({ children }: { children: React.ReactNode }) => children,
|
||||
}),
|
||||
)
|
||||
|
||||
vi.mock('@/app/components/plugins/install-plugin/hooks/use-plugin-install-permission', () => ({
|
||||
useOptionalPluginInstallPermission: () => ({ canInstallPlugin: true }),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/plugins/install-plugin/hooks/use-check-installed', () => ({
|
||||
default: () => ({ installedInfo: { installed: {} } }),
|
||||
}))
|
||||
|
||||
vi.mock('../list-with-collection', () => ({
|
||||
default: () => <div>Collections</div>,
|
||||
}))
|
||||
|
||||
vi.mock('../card-wrapper', () => ({
|
||||
default: ({ plugin, isInstalled }: { plugin: Plugin; isInstalled: boolean }) => (
|
||||
<div>
|
||||
{plugin.name}:{isInstalled ? 'installed' : 'available'}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('../../empty', () => ({
|
||||
default: () => <div>No plugins</div>,
|
||||
}))
|
||||
vi.mock('@/service/console', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/service/console')>()
|
||||
const { withConsoleResponses } = await import('@/test/console/service-responses')
|
||||
return {
|
||||
...actual,
|
||||
consoleQuery: withConsoleResponses(actual.consoleQuery, {
|
||||
'workspaces.current.plugin.list.installations.ids.post': async () => ({
|
||||
plugins: [
|
||||
createPluginEntity({
|
||||
id: 'installed-plugin-id',
|
||||
plugin_id: 'dify/installed-plugin',
|
||||
plugin_unique_identifier: 'dify/installed-plugin:1.0.0@test',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
const collection: MarketplaceCollection = {
|
||||
name: 'featured',
|
||||
label: { en_US: 'Featured plugins' },
|
||||
description: { en_US: 'A curated collection' },
|
||||
rule: 'featured',
|
||||
created_at: '2026-06-01T00:00:00Z',
|
||||
updated_at: '2026-06-01T00:00:00Z',
|
||||
searchable: false,
|
||||
search_params: {},
|
||||
}
|
||||
const featuredPlugin = createMarketplacePluginFixture({
|
||||
plugin_id: 'dify/featured-plugin',
|
||||
name: 'featured-plugin',
|
||||
label: { en_US: 'Featured plugin' },
|
||||
})
|
||||
const baseProps = {
|
||||
marketplaceCollections: [],
|
||||
marketplaceCollectionPluginsMap: {},
|
||||
marketplaceCollections: [collection],
|
||||
marketplaceCollectionPluginsMap: { featured: [featuredPlugin] },
|
||||
}
|
||||
|
||||
function renderList(ui: ReactElement) {
|
||||
const permissionStore = createPluginInstallPermissionStore({ canInstallPlugin: true })
|
||||
return renderWithConsoleQuery(
|
||||
<PluginInstallPermissionContext value={permissionStore}>
|
||||
<NuqsTestingAdapter>{ui}</NuqsTestingAdapter>
|
||||
</PluginInstallPermissionContext>,
|
||||
{ systemFeatures: { deployment_edition: 'CLOUD' } },
|
||||
)
|
||||
}
|
||||
|
||||
describe('List', () => {
|
||||
it('renders collections when search results are absent', () => {
|
||||
render(<List {...baseProps} />)
|
||||
it('renders a real collection and its plugin card when search results are absent', () => {
|
||||
renderList(<List {...baseProps} />)
|
||||
|
||||
expect(screen.getByText('Collections')).toBeInTheDocument()
|
||||
expect(screen.getByText('Featured plugins')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'Featured plugin' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the empty state for an empty search result', () => {
|
||||
render(<List {...baseProps} plugins={[]} />)
|
||||
it('renders the marketplace empty state for an empty search result', () => {
|
||||
renderList(<List {...baseProps} plugins={[]} />)
|
||||
|
||||
expect(screen.getByText('No plugins')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.marketplace.noPluginFound')).toBeInTheDocument()
|
||||
expect(screen.queryByRole('button', { name: 'Featured plugin' })).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders search results with installed state', () => {
|
||||
const plugins = [
|
||||
{ plugin_id: 'installed', name: 'Installed plugin', org: 'dify' },
|
||||
{ plugin_id: 'available', name: 'Available plugin', org: 'dify' },
|
||||
] as Plugin[]
|
||||
it('distinguishes an installed plugin from one that can be installed', async () => {
|
||||
const installedPlugin = createMarketplacePluginFixture({
|
||||
plugin_id: 'dify/installed-plugin',
|
||||
name: 'installed-plugin',
|
||||
label: { en_US: 'Installed plugin' },
|
||||
})
|
||||
const availablePlugin = createMarketplacePluginFixture({
|
||||
plugin_id: 'dify/available-plugin',
|
||||
name: 'available-plugin',
|
||||
label: { en_US: 'Available plugin' },
|
||||
})
|
||||
|
||||
render(<List {...baseProps} plugins={plugins} showInstallButton />)
|
||||
renderList(
|
||||
<List {...baseProps} plugins={[installedPlugin, availablePlugin]} showInstallButton />,
|
||||
)
|
||||
|
||||
expect(screen.getByText('Installed plugin:installed')).toBeInTheDocument()
|
||||
expect(screen.getByText('Available plugin:available')).toBeInTheDocument()
|
||||
expect(await screen.findByRole('button', { name: 'plugin.task.installed' })).toBeDisabled()
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'plugin.detailPanel.operation.install' }),
|
||||
).toBeEnabled()
|
||||
})
|
||||
})
|
||||
+95
-34
@@ -1,28 +1,69 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import type { ToolFormSchema } from '@/app/components/tools/utils/to-form-schema'
|
||||
import type { ToolWithProvider } from '@/app/components/workflow/types'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { useState } from 'react'
|
||||
import { describe, expect, it, vi } from 'vite-plus/test'
|
||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { createNode } from '@/app/components/workflow/__tests__/fixtures'
|
||||
import { renderWorkflowFlowComponent } from '@/app/components/workflow/__tests__/workflow-test-env'
|
||||
import { VarKindType } from '@/app/components/workflow/nodes/_base/types'
|
||||
import { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { consoleQuery } from '@/service/console'
|
||||
import { seedModelProviderQueries } from '@/test/console/model-provider'
|
||||
import { createConsoleQueryWrapper, seedAppDslVersion } from '@/test/console/query-data'
|
||||
import { seedToolProviders } from '@/test/console/tool-providers'
|
||||
import { ToolSettingsPanel } from '../tool-settings-panel'
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/tool/components/tool-form', () => ({
|
||||
default: ({ schema }: { schema: Array<{ name: string }> }) => (
|
||||
<div data-testid="tool-form">{schema.map((item) => item.name).join(',')}</div>
|
||||
),
|
||||
}))
|
||||
const createSchema = (overrides: Partial<ToolFormSchema> = {}): ToolFormSchema => ({
|
||||
name: 'api_key',
|
||||
variable: 'api_key',
|
||||
label: { en_US: 'API key', zh_Hans: 'API 密钥' },
|
||||
type: FormTypeEnum.textInput,
|
||||
_type: 'string',
|
||||
form: 'form',
|
||||
required: false,
|
||||
default: '',
|
||||
tooltip: { en_US: 'Credential used by the tool', zh_Hans: '工具使用的凭据' },
|
||||
show_on: [],
|
||||
options: [],
|
||||
placeholder: { en_US: 'Enter API key', zh_Hans: '输入 API 密钥' },
|
||||
...overrides,
|
||||
})
|
||||
|
||||
vi.mock('../reasoning-config-form', () => ({
|
||||
ReasoningConfigForm: ({ schemas }: { schemas: Array<{ name: string }> }) => (
|
||||
<div data-testid="reasoning-config-form">{schemas.map((item) => item.name).join(',')}</div>
|
||||
),
|
||||
}))
|
||||
const settingsSchema = createSchema()
|
||||
const paramsSchema = createSchema({
|
||||
name: 'temperature',
|
||||
variable: 'temperature',
|
||||
label: { en_US: 'Temperature', zh_Hans: '温度' },
|
||||
type: FormTypeEnum.textNumber,
|
||||
_type: 'number',
|
||||
form: 'llm',
|
||||
default: '0.5',
|
||||
tooltip: { en_US: 'Controls randomness', zh_Hans: '控制随机性' },
|
||||
placeholder: { en_US: 'Enter temperature', zh_Hans: '输入温度' },
|
||||
})
|
||||
|
||||
const baseProps = {
|
||||
nodeId: 'node-1',
|
||||
currType: 'settings' as const,
|
||||
settingsFormSchemas: [{ name: 'api_key' }] as never[],
|
||||
paramsFormSchemas: [{ name: 'temperature' }] as never[],
|
||||
settingsValue: {},
|
||||
settingsFormSchemas: [settingsSchema],
|
||||
paramsFormSchemas: [paramsSchema],
|
||||
settingsValue: {
|
||||
api_key: { type: VarKindType.mixed, value: 'saved-key' },
|
||||
},
|
||||
value: {
|
||||
provider_name: 'test-provider',
|
||||
tool_name: 'test-tool',
|
||||
tool_label: 'Test tool',
|
||||
parameters: {
|
||||
temperature: {
|
||||
auto: 0 as const,
|
||||
value: { type: VarKindType.constant, value: '0.7' },
|
||||
},
|
||||
},
|
||||
},
|
||||
showTabSlider: true,
|
||||
userSettingsOnly: false,
|
||||
reasoningConfigOnly: false,
|
||||
@@ -36,20 +77,42 @@ const baseProps = {
|
||||
} as ToolWithProvider,
|
||||
}
|
||||
|
||||
function renderPanel(ui: ReactElement) {
|
||||
const { queryClient } = createConsoleQueryWrapper()
|
||||
seedAppDslVersion(queryClient)
|
||||
seedModelProviderQueries(queryClient, [])
|
||||
seedToolProviders(queryClient, {
|
||||
builtInTools: [],
|
||||
customTools: [],
|
||||
workflowTools: [],
|
||||
mcpTools: [],
|
||||
})
|
||||
queryClient.setQueryData(consoleQuery.spec.schemaDefinitions.get.queryKey(), [])
|
||||
return renderWorkflowFlowComponent(ui, {
|
||||
queryClient,
|
||||
nodes: [createNode({ id: 'node-1', data: { type: BlockEnum.Tool, title: 'Tool' } })],
|
||||
edges: [],
|
||||
})
|
||||
}
|
||||
|
||||
describe('ToolSettingsPanel', () => {
|
||||
it('returns null when the provider is not team-authorized or has no forms', () => {
|
||||
const { container, rerender } = render(
|
||||
const { rerender } = renderPanel(
|
||||
<ToolSettingsPanel
|
||||
{...baseProps}
|
||||
currentProvider={{ is_team_authorization: false } as ToolWithProvider}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(container).toBeEmptyDOMElement()
|
||||
expect(screen.queryByRole('tablist')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('textbox')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('spinbutton')).not.toBeInTheDocument()
|
||||
|
||||
rerender(<ToolSettingsPanel {...baseProps} settingsFormSchemas={[]} paramsFormSchemas={[]} />)
|
||||
|
||||
expect(container).toBeEmptyDOMElement()
|
||||
expect(screen.queryByRole('tablist')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('textbox')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('spinbutton')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('switches the controlled settings and params panels with the keyboard', async () => {
|
||||
@@ -58,28 +121,22 @@ describe('ToolSettingsPanel', () => {
|
||||
const [currType, setCurrType] = useState<'settings' | 'params'>('settings')
|
||||
return <ToolSettingsPanel {...baseProps} currType={currType} onCurrTypeChange={setCurrType} />
|
||||
}
|
||||
render(<ControlledPanel />)
|
||||
renderPanel(<ControlledPanel />)
|
||||
|
||||
expect(
|
||||
screen.getByRole('tabpanel', { name: 'plugin.detailPanel.toolSelector.settings' }),
|
||||
).toHaveTextContent('api_key')
|
||||
expect(screen.getByRole('textbox')).toHaveTextContent('saved-key')
|
||||
await user.click(screen.getByRole('tab', { name: 'plugin.detailPanel.toolSelector.settings' }))
|
||||
await user.keyboard('{ArrowRight}{Enter}')
|
||||
expect(
|
||||
screen.getByRole('tab', { name: 'plugin.detailPanel.toolSelector.params' }),
|
||||
).toHaveFocus()
|
||||
expect(
|
||||
screen.getByRole('tabpanel', { name: 'plugin.detailPanel.toolSelector.params' }),
|
||||
).toHaveTextContent('temperature')
|
||||
expect(screen.queryByTestId('tool-form')).not.toBeInTheDocument()
|
||||
expect(screen.getByRole('spinbutton', { name: 'Temperature' })).toHaveValue(0.7)
|
||||
expect(screen.queryByText('saved-key')).not.toBeInTheDocument()
|
||||
await user.keyboard('{ArrowLeft}{Enter}')
|
||||
expect(
|
||||
screen.getByRole('tabpanel', { name: 'plugin.detailPanel.toolSelector.settings' }),
|
||||
).toHaveTextContent('api_key')
|
||||
expect(screen.getByRole('textbox')).toHaveTextContent('saved-key')
|
||||
})
|
||||
|
||||
it('renders a settings-only form without an orphaned tab panel', () => {
|
||||
render(
|
||||
it('renders a settings-only real form without an orphaned tab panel', () => {
|
||||
renderPanel(
|
||||
<ToolSettingsPanel
|
||||
{...baseProps}
|
||||
paramsFormSchemas={[]}
|
||||
@@ -87,13 +144,15 @@ describe('ToolSettingsPanel', () => {
|
||||
userSettingsOnly
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByTestId('tool-form')).toHaveTextContent('api_key')
|
||||
|
||||
const input = screen.getByRole('textbox')
|
||||
expect(input).toHaveTextContent('saved-key')
|
||||
expect(screen.queryByRole('tablist')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('tabpanel')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders params tips and the reasoning config form for params-only views', () => {
|
||||
render(
|
||||
it('renders params tips and a real reasoning control without orphaned panels', () => {
|
||||
renderPanel(
|
||||
<ToolSettingsPanel
|
||||
{...baseProps}
|
||||
currType="params"
|
||||
@@ -105,8 +164,10 @@ describe('ToolSettingsPanel', () => {
|
||||
)
|
||||
|
||||
expect(screen.getByText('plugin.detailPanel.toolSelector.paramsTip1')).toBeInTheDocument()
|
||||
expect(screen.getByText('plugin.detailPanel.toolSelector.paramsTip2')).toBeInTheDocument()
|
||||
expect(screen.getByRole('spinbutton', { name: 'Temperature' })).toHaveValue(0.7)
|
||||
expect(screen.getByRole('switch')).not.toBeChecked()
|
||||
expect(screen.queryByRole('tablist')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('tabpanel')).not.toBeInTheDocument()
|
||||
expect(screen.getByTestId('reasoning-config-form')).toHaveTextContent('temperature')
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { FileEntity } from '@/app/components/base/file-uploader/types'
|
||||
import type { FileResponse } from '@/types/workflow'
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
@@ -7,35 +6,6 @@ import OutputPanel from '../output-panel'
|
||||
|
||||
type FileOutput = FileResponse & { dify_model_identity: '__dify__file__' }
|
||||
|
||||
vi.mock('@/app/components/base/file-uploader', () => ({
|
||||
FileList: ({ files }: { files: FileEntity[] }) => (
|
||||
<div data-testid="file-list">{files.map((file) => file.name).join(', ')}</div>
|
||||
),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/markdown', () => ({
|
||||
Markdown: ({ content }: { content: string }) => <div data-testid="markdown">{content}</div>,
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/workflow/nodes/_base/components/editor/code-editor', () => ({
|
||||
default: ({
|
||||
language,
|
||||
value,
|
||||
height,
|
||||
title,
|
||||
}: {
|
||||
language: string
|
||||
value: string
|
||||
height?: number
|
||||
title?: React.ReactNode
|
||||
}) => (
|
||||
<div data-height={height} data-language={language} data-testid="code-editor" data-value={value}>
|
||||
<div>{title}</div>
|
||||
{value}
|
||||
</div>
|
||||
),
|
||||
}))
|
||||
|
||||
const createFileOutput = (overrides: Partial<FileOutput> = {}): FileOutput => ({
|
||||
dify_model_identity: '__dify__file__',
|
||||
related_id: 'file-1',
|
||||
@@ -52,11 +22,11 @@ const createFileOutput = (overrides: Partial<FileOutput> = {}): FileOutput => ({
|
||||
})
|
||||
|
||||
describe('OutputPanel', () => {
|
||||
it('shows no-output only after execution finishes without a result', () => {
|
||||
it('shows no-output only after execution finishes without a result', async () => {
|
||||
const { rerender } = render(<OutputPanel isRunning />)
|
||||
expect(screen.queryByText('No Output')).not.toBeInTheDocument()
|
||||
rerender(<OutputPanel isRunning={false} />)
|
||||
expect(screen.getByText('No Output')).toBeVisible()
|
||||
expect(await screen.findByText('No Output')).toBeVisible()
|
||||
})
|
||||
|
||||
it('shows and copies a failed execution message', async () => {
|
||||
@@ -70,22 +40,35 @@ describe('OutputPanel', () => {
|
||||
expect(screen.getByText('Execution failed')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders a plain text output as markdown', () => {
|
||||
render(<OutputPanel outputs={{ answer: 'Hello Dify' }} />)
|
||||
it('renders a plain text output as semantic markdown', async () => {
|
||||
render(
|
||||
<OutputPanel
|
||||
outputs={{ answer: '# Run summary\n\n[Review output](https://example.com/review)' }}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByTestId('markdown')).toHaveTextContent('Hello Dify')
|
||||
expect(await screen.findByRole('heading', { name: 'Run summary' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('link', { name: 'Review output' })).toHaveAttribute(
|
||||
'href',
|
||||
'https://example.com/review',
|
||||
)
|
||||
})
|
||||
|
||||
it('renders array text outputs as joined markdown content', () => {
|
||||
render(<OutputPanel outputs={{ answer: ['Line 1', 'Line 2'] }} />)
|
||||
it('renders array text outputs as joined semantic markdown content', async () => {
|
||||
render(<OutputPanel outputs={{ answer: ['## First result', '## Second result'] }} />)
|
||||
|
||||
expect(screen.getByTestId('markdown').textContent).toMatch(/Line 1\s+Line 2/)
|
||||
expect(await screen.findByRole('heading', { name: 'First result' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('heading', { name: 'Second result' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders a file list for a single file output', () => {
|
||||
render(<OutputPanel outputs={{ attachment: createFileOutput() }} />)
|
||||
|
||||
expect(screen.getByTestId('file-list')).toHaveTextContent('report.pdf')
|
||||
expect(screen.getByRole('button', { name: 'report.pdf' })).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'common.operation.download' })).toBeInTheDocument()
|
||||
expect(
|
||||
screen.queryByRole('button', { name: 'common.operation.remove' }),
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders a file list for an array of file outputs', () => {
|
||||
@@ -108,25 +91,27 @@ describe('OutputPanel', () => {
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(screen.getByTestId('file-list')).toHaveTextContent('report.pdf, summary.md')
|
||||
expect(screen.getByRole('button', { name: 'report.pdf' })).toBeInTheDocument()
|
||||
expect(screen.getByText('summary.md')).toBeInTheDocument()
|
||||
expect(screen.getAllByRole('button', { name: 'common.operation.download' })).toHaveLength(2)
|
||||
expect(
|
||||
screen.queryByRole('button', { name: 'common.operation.remove' }),
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders structured outputs inside the code editor when height is available', () => {
|
||||
render(<OutputPanel height={200} outputs={{ answer: 'hello', score: 1 }} />)
|
||||
|
||||
expect(screen.getByTestId('code-editor')).toHaveAttribute('data-language', 'json')
|
||||
expect(screen.getByTestId('code-editor')).toHaveAttribute(
|
||||
'data-value',
|
||||
`{
|
||||
"answer": "hello",
|
||||
"score": 1
|
||||
}`,
|
||||
)
|
||||
const editor = screen.getByTestId<HTMLInputElement>('monaco-editor')
|
||||
expect(editor).toHaveAttribute('readonly')
|
||||
const parsedValue: unknown = JSON.parse(editor.value)
|
||||
const semanticValue = typeof parsedValue === 'string' ? JSON.parse(parsedValue) : parsedValue
|
||||
expect(semanticValue).toEqual({ answer: 'hello', score: 1 })
|
||||
})
|
||||
|
||||
it('skips the code editor when structured outputs have no positive height', () => {
|
||||
render(<OutputPanel height={0} outputs={{ answer: 'hello', score: 1 }} />)
|
||||
|
||||
expect(screen.queryByTestId('code-editor')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('monaco-editor')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user