test: added more test inside containers component (#3765)

* test: wip several component under containers

* remoce checkbox test containers

* test: added more test to containers component
This commit is contained in:
Faisal Amir 2024-10-16 09:45:28 +07:00 committed by GitHub
parent 5e8a27b010
commit 19a60bc973
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 851 additions and 11 deletions

View File

@ -0,0 +1,43 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import AutoLink from './index'
describe('AutoLink Component', () => {
it('renders text without links correctly', () => {
const text = 'This is a test without links.'
render(<AutoLink text={text} />)
expect(screen.getByText(text)).toBeInTheDocument()
})
it('renders text with a single link correctly', () => {
const text = 'Check this link: https://example.com'
render(<AutoLink text={text} />)
const link = screen.getByText('https://example.com')
expect(link).toBeInTheDocument()
expect(link).toHaveAttribute('href', 'https://example.com')
expect(link).toHaveAttribute('target', 'blank')
})
it('renders text with multiple links correctly', () => {
const text = 'Visit https://example.com and http://test.com'
render(<AutoLink text={text} />)
const link1 = screen.getByText('https://example.com')
const link2 = screen.getByText('http://test.com')
expect(link1).toBeInTheDocument()
expect(link1).toHaveAttribute('href', 'https://example.com')
expect(link1).toHaveAttribute('target', 'blank')
expect(link2).toBeInTheDocument()
expect(link2).toHaveAttribute('href', 'http://test.com')
expect(link2).toHaveAttribute('target', 'blank')
})
it('renders text with a link without protocol correctly', () => {
const text = 'Visit example.com for more info.'
render(<AutoLink text={text} />)
const link = screen.getByText('example.com')
expect(link).toBeInTheDocument()
expect(link).toHaveAttribute('href', 'http://example.com')
expect(link).toHaveAttribute('target', 'blank')
})
})

View File

@ -0,0 +1,38 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import BlankState from './index'
describe('BlankState Component', () => {
it('renders title correctly', () => {
const title = 'Test Title'
render(<BlankState title={title} />)
expect(screen.getByText(title)).toBeInTheDocument()
})
it('renders description correctly when provided', () => {
const title = 'Test Title'
const description = 'Test Description'
render(<BlankState title={title} description={description} />)
expect(screen.getByText(description)).toBeInTheDocument()
})
it('does not render description when not provided', () => {
const title = 'Test Title'
render(<BlankState title={title} />)
expect(screen.queryByText('Test Description')).not.toBeInTheDocument()
})
it('renders action correctly when provided', () => {
const title = 'Test Title'
const action = <button>Test Action</button>
render(<BlankState title={title} action={action} />)
expect(screen.getByText('Test Action')).toBeInTheDocument()
})
it('does not render action when not provided', () => {
const title = 'Test Title'
render(<BlankState title={title} />)
expect(screen.queryByText('Test Action')).not.toBeInTheDocument()
})
})

View File

@ -0,0 +1,37 @@
import React from 'react'
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import LogoMark from './Mark'
describe('LogoMark Component', () => {
it('renders with default width and height', () => {
render(<LogoMark />)
const image = screen.getByAltText('Jan - Logo')
expect(image).toBeInTheDocument()
expect(image).toHaveAttribute('width', '24')
expect(image).toHaveAttribute('height', '24')
})
it('renders with provided width and height', () => {
render(<LogoMark width={48} height={48} />)
const image = screen.getByAltText('Jan - Logo')
expect(image).toBeInTheDocument()
expect(image).toHaveAttribute('width', '48')
expect(image).toHaveAttribute('height', '48')
})
it('applies provided className', () => {
render(<LogoMark className="custom-class" />)
const image = screen.getByAltText('Jan - Logo')
expect(image).toBeInTheDocument()
expect(image).toHaveClass('custom-class')
})
it('renders with the correct src and alt attributes', () => {
render(<LogoMark />)
const image = screen.getByAltText('Jan - Logo')
expect(image).toBeInTheDocument()
expect(image).toHaveAttribute('src', 'icons/app_icon.svg')
expect(image).toHaveAttribute('alt', 'Jan - Logo')
})
})

View File

@ -0,0 +1,56 @@
import { render, screen } from '@testing-library/react'
import { useAtomValue } from 'jotai'
import CenterPanelContainer from './index'
import '@testing-library/jest-dom'
// Mock useAtomValue from jotai
jest.mock('jotai', () => ({
...jest.requireActual('jotai'),
useAtomValue: jest.fn(),
}))
describe('CenterPanelContainer', () => {
it('renders with reduceTransparent set to true', () => {
// Mock reduceTransparentAtom to be true
;(useAtomValue as jest.Mock).mockReturnValue(true)
render(
<CenterPanelContainer>
<div>Test Child</div>
</CenterPanelContainer>
)
// Check that the container renders with no border or rounded corners
const container = screen.getByText('Test Child').parentElement
expect(container).not.toHaveClass('rounded-lg border')
})
it('renders with reduceTransparent set to false', () => {
// Mock reduceTransparentAtom to be false
;(useAtomValue as jest.Mock).mockReturnValue(false)
render(
<CenterPanelContainer>
<div>Test Child</div>
</CenterPanelContainer>
)
// Check that the container renders with border and rounded corners
const container = screen.getByText('Test Child').parentElement
expect(container).toHaveClass('rounded-lg border')
})
it('renders children correctly', () => {
// Mock reduceTransparentAtom to be true for this test
;(useAtomValue as jest.Mock).mockReturnValue(true)
render(
<CenterPanelContainer>
<div>Child Content</div>
</CenterPanelContainer>
)
// Verify that the child content is rendered
expect(screen.getByText('Child Content')).toBeInTheDocument()
})
})

View File

@ -0,0 +1,65 @@
import { render, screen, fireEvent } from '@testing-library/react'
import { useAtom } from 'jotai'
import '@testing-library/jest-dom'
import CopyOverInstruction from './index'
// Mock the `useAtom` hook from jotai
jest.mock('jotai', () => ({
useAtom: jest.fn(),
}))
describe('CopyOverInstruction', () => {
const setCopyOverInstructionEnabled = jest.fn()
beforeEach(() => {
;(useAtom as jest.Mock).mockImplementation(() => [
false,
setCopyOverInstructionEnabled,
])
})
afterEach(() => {
jest.clearAllMocks()
})
it('should render the component with the switch in the correct state', () => {
render(<CopyOverInstruction />)
// Assert the text is rendered
expect(
screen.getByText(/Save instructions for new threads/i)
).toBeInTheDocument()
// Assert the switch is rendered and in the unchecked state
const switchInput = screen.getByRole('checkbox')
expect(switchInput).toBeInTheDocument()
expect(switchInput).not.toBeChecked()
})
it('should call setCopyOverInstructionEnabled when the switch is toggled', () => {
render(<CopyOverInstruction />)
const switchInput = screen.getByRole('checkbox')
// Simulate toggling the switch
fireEvent.click(switchInput)
// Assert that the atom setter is called with true when checked
expect(setCopyOverInstructionEnabled).toHaveBeenCalledWith(true)
})
it('should reflect the updated state when the atom value changes', () => {
// Mock the atom to return true (enabled state)
;(useAtom as jest.Mock).mockImplementation(() => [
true,
setCopyOverInstructionEnabled,
])
render(<CopyOverInstruction />)
const switchInput = screen.getByRole('checkbox')
// The switch should now be checked
expect(switchInput).toBeChecked()
})
})

View File

@ -0,0 +1,115 @@
import { render } from '@testing-library/react'
import '@testing-library/jest-dom'
import EngineSetting from './index'
import SettingComponentBuilder from '@/containers/ModelSetting/SettingComponent'
import { SettingComponentProps } from '@janhq/core'
// Mock the SettingComponentBuilder component
jest.mock('@/containers/ModelSetting/SettingComponent', () =>
jest.fn(() => null)
)
describe('EngineSetting', () => {
const mockComponentData: SettingComponentProps[] = [
{
key: 'setting1',
title: 'Setting 1',
description: 'This is the first setting.',
controllerType: 'input',
controllerProps: {
placeholder: 'Enter text',
value: 'default text',
type: 'text',
},
},
{
key: 'setting2',
title: 'Setting 2',
description: 'This is the second setting.',
controllerType: 'slider',
controllerProps: {
min: 0,
max: 100,
step: 1,
value: 50,
},
},
{
key: 'setting3',
title: 'Setting 3',
description: 'This is the third setting.',
controllerType: 'checkbox',
controllerProps: {
value: true,
},
},
]
const onValueChangedMock = jest.fn()
afterEach(() => {
jest.clearAllMocks() // Clear mocks after each test
})
it('renders SettingComponentBuilder with the correct props', () => {
render(
<EngineSetting
componentData={mockComponentData}
onValueChanged={onValueChangedMock}
disabled={false}
/>
)
// Check that SettingComponentBuilder is called with the correct props
expect(SettingComponentBuilder).toHaveBeenCalledWith(
{
componentProps: mockComponentData,
disabled: false,
onValueUpdated: onValueChangedMock,
},
{}
)
})
it('renders SettingComponentBuilder with disabled prop', () => {
render(
<EngineSetting
componentData={mockComponentData}
onValueChanged={onValueChangedMock}
disabled={true}
/>
)
// Check that SettingComponentBuilder is called with disabled=true
expect(SettingComponentBuilder).toHaveBeenCalledWith(
{
componentProps: mockComponentData,
disabled: true,
onValueUpdated: onValueChangedMock,
},
{}
)
})
it('calls onValueChanged when the value is updated', () => {
// Simulating value update in SettingComponentBuilder
;(SettingComponentBuilder as jest.Mock).mockImplementation(
({ onValueUpdated }) => {
// Simulate calling the value update handler
onValueUpdated('setting1', 'new value')
return null
}
)
render(
<EngineSetting
componentData={mockComponentData}
onValueChanged={onValueChangedMock}
disabled={false}
/>
)
// Assert that onValueChanged is called with the correct parameters
expect(onValueChangedMock).toHaveBeenCalledWith('setting1', 'new value')
})
})

View File

@ -1,9 +0,0 @@
export default function BubbleLoader() {
return (
<div className="bubble-loader">
<span></span>
<span></span>
<span></span>
</div>
)
}

View File

@ -0,0 +1,47 @@
import '@testing-library/jest-dom'
import { render, screen, act } from '@testing-library/react'
import ModelStart from './ModelStart' // Adjust the path based on your file structure
import { useActiveModel } from '@/hooks/useActiveModel'
// Mock the useActiveModel hook
jest.mock('@/hooks/useActiveModel', () => ({
useActiveModel: jest.fn(),
}))
describe('ModelStart', () => {
const mockSetStateModel = jest.fn()
const mockModel = { id: 'test-model' }
beforeEach(() => {
// Reset the mock implementation before each test
jest.clearAllMocks()
})
it('renders correctly when loading is false', () => {
;(useActiveModel as jest.Mock).mockReturnValue({
stateModel: {
loading: false,
state: 'start',
model: mockModel,
},
})
render(<ModelStart />)
// Ensure the component returns null when not loading
expect(screen.queryByText(/Starting model/i)).toBeNull()
})
it('renders loading state with model id', () => {
;(useActiveModel as jest.Mock).mockReturnValue({
stateModel: {
loading: true,
state: 'start',
model: mockModel,
},
})
render(<ModelStart />)
// Ensure the loading text is rendered
expect(screen.getByText(/Starting model test-model/i)).toBeInTheDocument()
})
})

View File

@ -0,0 +1,47 @@
import '@testing-library/jest-dom'
import { render } from '@testing-library/react'
import { useAtomValue } from 'jotai'
import ResettingModal from './index'
// Mocking the Jotai atom
jest.mock('jotai', () => {
const originalModule = jest.requireActual('jotai')
return {
...originalModule,
useAtomValue: jest.fn(),
}
})
describe('ResettingModal', () => {
it('renders the modal with loading info when provided', () => {
const mockLoadingInfo = {
title: 'Loading...',
message: 'Please wait while we process your request.',
}
// Mock the useAtomValue hook to return mock loading info
;(useAtomValue as jest.Mock).mockReturnValue(mockLoadingInfo)
const { getByText } = render(<ResettingModal />)
// Check if the modal title and message are displayed
expect(getByText('Loading...')).toBeInTheDocument()
expect(
getByText('Please wait while we process your request.')
).toBeInTheDocument()
})
it('does not render the modal when loading info is undefined', () => {
// Mock the useAtomValue hook to return undefined
;(useAtomValue as jest.Mock).mockReturnValue(undefined)
const { queryByText } = render(<ResettingModal />)
// Check that the modal does not appear
expect(queryByText('Loading...')).not.toBeInTheDocument()
expect(
queryByText('Please wait while we process your request.')
).not.toBeInTheDocument()
})
})

View File

@ -0,0 +1,56 @@
import '@testing-library/jest-dom'
import { render } from '@testing-library/react'
import { useAtomValue } from 'jotai'
import MainViewContainer from './index'
import { MainViewState } from '@/constants/screens'
// Mocking the Jotai atom
jest.mock('jotai', () => {
const originalModule = jest.requireActual('jotai')
return {
...originalModule,
useAtomValue: jest.fn(),
}
})
// Mocking the screen components
jest.mock('@/screens/Hub', () => () => <div>Hub Screen</div>)
jest.mock('@/screens/LocalServer', () => () => <div>Local Server Screen</div>)
jest.mock('@/screens/Settings', () => () => <div>Settings Screen</div>)
jest.mock('@/screens/Thread', () => () => <div>Thread Screen</div>)
describe('MainViewContainer', () => {
it('renders HubScreen when mainViewState is Hub', () => {
;(useAtomValue as jest.Mock).mockReturnValue(MainViewState.Hub)
const { getByText } = render(<MainViewContainer />)
expect(getByText('Hub Screen')).toBeInTheDocument()
})
it('renders SettingsScreen when mainViewState is Settings', () => {
;(useAtomValue as jest.Mock).mockReturnValue(MainViewState.Settings)
const { getByText } = render(<MainViewContainer />)
expect(getByText('Settings Screen')).toBeInTheDocument()
})
it('renders LocalServerScreen when mainViewState is LocalServer', () => {
;(useAtomValue as jest.Mock).mockReturnValue(MainViewState.LocalServer)
const { getByText } = render(<MainViewContainer />)
expect(getByText('Local Server Screen')).toBeInTheDocument()
})
it('renders ThreadScreen when mainViewState is not defined', () => {
;(useAtomValue as jest.Mock).mockReturnValue(undefined)
const { getByText } = render(<MainViewContainer />)
expect(getByText('Thread Screen')).toBeInTheDocument()
})
})

View File

@ -0,0 +1,85 @@
import '@testing-library/jest-dom'
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import ModelConfigInput from './index'
import { Tooltip } from '@janhq/joi'
// Mocking the Tooltip component to simplify testing
jest.mock('@janhq/joi', () => ({
...jest.requireActual('@janhq/joi'),
Tooltip: ({
trigger,
content,
}: {
trigger: React.ReactNode
content: string
}) => (
<div data-testid="tooltip">
{trigger}
<span>{content}</span>
</div>
),
}))
describe('ModelConfigInput', () => {
it('renders correctly with given props', () => {
const { getByText, getByPlaceholderText } = render(
<ModelConfigInput
title="Test Title"
description="This is a description."
placeholder="Enter text here"
value=""
name={''}
/>
)
// Check if title is rendered
expect(getByText('Test Title')).toBeInTheDocument()
// Check if the description tooltip content is rendered
expect(getByText('This is a description.')).toBeInTheDocument()
// Check if the placeholder is rendered
expect(getByPlaceholderText('Enter text here')).toBeInTheDocument()
})
it('calls onValueChanged when value changes', () => {
const onValueChangedMock = jest.fn()
const { getByPlaceholderText } = render(
<ModelConfigInput
title="Test Title"
description="This is a description."
placeholder="Enter text here"
value=""
onValueChanged={onValueChangedMock}
name={''}
/>
)
const textArea = getByPlaceholderText('Enter text here')
// Simulate typing in the textarea
fireEvent.change(textArea, { target: { value: 'New Value' } })
// Check if onValueChanged was called with the new value
expect(onValueChangedMock).toHaveBeenCalledWith('New Value')
})
it('disables the textarea when disabled prop is true', () => {
const { getByPlaceholderText } = render(
<ModelConfigInput
title="Test Title"
description="This is a description."
placeholder="Enter text here"
value=""
disabled={true}
name={''}
/>
)
const textArea = getByPlaceholderText('Enter text here')
// Check if the textarea is disabled
expect(textArea).toBeDisabled()
})
})

View File

@ -0,0 +1,110 @@
import '@testing-library/jest-dom'
import React from 'react'
import { render } from '@testing-library/react'
import { useAtom } from 'jotai'
import Responsive from './Responsive'
import { showLeftPanelAtom, showRightPanelAtom } from '@/helpers/atoms/App.atom'
// Mocking the required atoms
jest.mock('jotai', () => {
const originalModule = jest.requireActual('jotai')
return {
...originalModule,
useAtom: jest.fn(),
useAtomValue: jest.fn(),
}
})
const mockSetShowLeftPanel = jest.fn()
const mockSetShowRightPanel = jest.fn()
const mockShowLeftPanel = true
const mockShowRightPanel = true
beforeEach(() => {
// Mocking the atom behavior
;(useAtom as jest.Mock).mockImplementation((atom) => {
if (atom === showLeftPanelAtom) {
return [mockShowLeftPanel, mockSetShowLeftPanel]
}
if (atom === showRightPanelAtom) {
return [mockShowRightPanel, mockSetShowRightPanel]
}
return [null, jest.fn()]
})
})
describe('Responsive', () => {
beforeAll(() => {
// Mocking the window.matchMedia function
window.matchMedia = jest.fn().mockImplementation((query) => {
return {
matches: false, // Set this to true to simulate mobile view
addListener: jest.fn(),
removeListener: jest.fn(),
}
})
})
it('renders children correctly', () => {
const { getByText } = render(
<Responsive>
<div>Child Content</div>
</Responsive>
)
// Check if the child content is rendered
expect(getByText('Child Content')).toBeInTheDocument()
})
it('hides left and right panels on small screens', () => {
// Simulate mobile view
window.matchMedia = jest.fn().mockImplementation((query) => ({
matches: true, // Change to true to simulate mobile
addListener: jest.fn(),
removeListener: jest.fn(),
}))
render(
<Responsive>
<div>Child Content</div>
</Responsive>
)
// Check that the left and right panel states were updated to false
expect(mockSetShowLeftPanel).toHaveBeenCalledWith(false)
expect(mockSetShowRightPanel).toHaveBeenCalledWith(false)
})
it('restores the last known panel states on larger screens', () => {
// Simulate mobile view first
window.matchMedia = jest.fn().mockImplementation((query) => ({
matches: true, // Change to true to simulate mobile
addListener: jest.fn(),
removeListener: jest.fn(),
}))
render(
<Responsive>
<div>Child Content</div>
</Responsive>
)
// Change back to desktop view
window.matchMedia = jest.fn().mockImplementation((query) => ({
matches: false, // Change to false to simulate desktop
addListener: jest.fn(),
removeListener: jest.fn(),
}))
// Call the effect manually to simulate the component re-rendering
const rerender = render(
<Responsive>
<div>Child Content</div>
</Responsive>
)
// Check that the last known states were restored (which were true initially)
expect(mockSetShowLeftPanel).toHaveBeenCalledWith(true)
expect(mockSetShowRightPanel).toHaveBeenCalledWith(true)
})
})

View File

@ -0,0 +1,24 @@
import '@testing-library/jest-dom'
import React from 'react'
import { render } from '@testing-library/react'
import ThemeWrapper from './Theme'
// Mock the ThemeProvider from next-themes
jest.mock('next-themes', () => ({
ThemeProvider: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
}))
describe('ThemeWrapper', () => {
it('renders children within ThemeProvider', () => {
const { getByText } = render(
<ThemeWrapper>
<div>Child Component</div>
</ThemeWrapper>
)
// Check if the child component is rendered
expect(getByText('Child Component')).toBeInTheDocument()
})
})

View File

@ -0,0 +1,126 @@
import '@testing-library/jest-dom'
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import RightPanelContainer from './index'
import { useAtom } from 'jotai'
// Mocking ResizeObserver
class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
}
global.ResizeObserver = ResizeObserver
// Mocking window.matchMedia
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
})
// Mocking the required atoms
jest.mock('jotai', () => {
const originalModule = jest.requireActual('jotai')
return {
...originalModule,
useAtom: jest.fn(),
useAtomValue: jest.fn(),
}
})
const mockSetShowRightPanel = jest.fn()
const mockShowRightPanel = true // Change this to test the panel visibility
beforeEach(() => {
// Setting up the localStorage mock
localStorage.clear()
localStorage.setItem('rightPanelWidth', '280') // Setting a default width
// Mocking the atom behavior
;(useAtom as jest.Mock).mockImplementation(() => [
mockShowRightPanel,
mockSetShowRightPanel,
])
})
describe('RightPanelContainer', () => {
it('renders correctly with children', () => {
const { getByText } = render(
<RightPanelContainer>
<div>Child Content</div>
</RightPanelContainer>
)
// Check if the child content is rendered
expect(getByText('Child Content')).toBeInTheDocument()
})
it('initializes width from localStorage', () => {
const { container } = render(<RightPanelContainer />)
// Check the width from localStorage is applied
const rightPanel = container.firstChild as HTMLDivElement
expect(rightPanel.style.width).toBe('280px') // Width from localStorage
})
it('changes width on resizing', () => {
const { container } = render(<RightPanelContainer />)
const rightPanel = container.firstChild as HTMLDivElement
// Simulate mouse down on the resize handle
const resizeHandle = document.createElement('div')
resizeHandle.className = 'group/resize'
rightPanel.appendChild(resizeHandle)
// Simulate mouse down to start resizing
fireEvent.mouseDown(resizeHandle)
// Simulate mouse move event
fireEvent.mouseMove(window, { clientX: 100 })
// Simulate mouse up to stop resizing
fireEvent.mouseUp(window)
// Verify that the right panel's width changes
// Since we can't get the actual width calculation in this test,
// you may want to check if the rightPanelWidth is updated in your implementation.
// Here, just check if the function is called:
expect(localStorage.getItem('rightPanelWidth')).toBeDefined()
})
it('hides panel when clicked outside on mobile', () => {
// Mock useMediaQuery to simulate mobile view
;(window.matchMedia as jest.Mock).mockImplementation((query) => ({
matches: true, // Always return true for mobile
addListener: jest.fn(),
removeListener: jest.fn(),
}))
const { container } = render(
<RightPanelContainer>
<div>Child Content</div>
</RightPanelContainer>
)
const rightPanel = container.firstChild as HTMLDivElement
// Simulate a click outside
fireEvent.mouseDown(document.body)
fireEvent.mouseUp(document.body) // Ensure the click event is completed
// Verify that setShowRightPanel was called to hide the panel
expect(mockSetShowRightPanel).toHaveBeenCalledWith(false)
})
})

View File

@ -19,8 +19,8 @@ const config = {
runner: './testRunner.js',
collectCoverageFrom: ['./**/*.{ts,tsx}'],
transform: {
"^.+\\.tsx?$": [
"ts-jest",
'^.+\\.tsx?$': [
'ts-jest',
{
diagnostics: false,
},