Skip to content

Commit

Permalink
wip: properties panel tests - useFaketimers and implement mock useTra…
Browse files Browse the repository at this point in the history
…cker()
  • Loading branch information
olzzon committed Nov 11, 2024
1 parent d3e0ca7 commit 5fe974f
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 79 deletions.
6 changes: 5 additions & 1 deletion packages/webui/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module.exports = {
setupFilesAfterEnv: ['./src/__mocks__/_setupMocks.ts', '<rootDir>/src/client/__tests__/jest-setup.cjs'],
setupFilesAfterEnv: [
'./src/__mocks__/_setupMocks.ts',
'<rootDir>/src/client/__tests__/jest-setup.cjs',
'@testing-library/jest-dom',
],
globals: {},
moduleFileExtensions: ['js', 'ts', 'tsx'],
moduleNameMapper: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
jest.mock(
'../../../../__mocks__/tracker',
() => ({
setup: () => ({
Tracker: {
autorun: jest.fn((fn) => {
fn()
return {
stop: jest.fn(),
}
}),
nonreactive: jest.fn((fn) => fn()),
active: false,
currentComputation: null,
Dependency: jest.fn().mockImplementation(() => ({
depend: jest.fn(),
changed: jest.fn(),
hasDependents: jest.fn(),
})),
},
}),
}),
{
virtual: true,
}
)

// Mock the ReactiveDataHelper:
jest.mock('../../../lib/reactiveData/ReactiveDataHelper', () => {
class MockReactiveDataHelper {
Expand Down Expand Up @@ -70,7 +97,7 @@ jest.mock('react-i18next', () => ({

import React from 'react'
// eslint-disable-next-line node/no-unpublished-import
import { renderHook, act, render, screen, RenderResult } from '@testing-library/react'
import { renderHook, act, render, screen, waitFor } from '@testing-library/react'
// eslint-disable-next-line node/no-unpublished-import
import '@testing-library/jest-dom'
import { MeteorCall } from '../../../lib/meteorApi'
Expand Down Expand Up @@ -122,6 +149,11 @@ describe('PropertiesPanel', () => {
mockSegmentsCollection.remove({})
mockPartsCollection.remove({})
jest.clearAllMocks()
jest.useFakeTimers()
})

afterEach(() => {
jest.useRealTimers()
})

const createMockSegment = (id: string): DBSegment => ({
Expand All @@ -133,12 +165,14 @@ describe('PropertiesPanel', () => {
userEditOperations: [
{
id: 'operation1',
label: { key: 'TEST_LABEL' },
label: { key: 'TEST_LABEL', namespaces: ['blueprint_main-showstyle'] },
type: UserEditingType.ACTION,
buttonType: UserEditingButtonType.SWITCH,
isActive: false,
svgIcon: '<svg></svg>',
},
],
isHidden: false,
})

const createMockPart = (id: string, segmentId: string): DBPart => ({
Expand All @@ -152,7 +186,7 @@ describe('PropertiesPanel', () => {
userEditOperations: [
{
id: 'operation2',
label: { key: 'TEST_PART_LABEL' },
label: { key: 'TEST_PART_LABEL', namespaces: ['blueprint_main-showstyle'] },
type: UserEditingType.ACTION,
buttonType: UserEditingButtonType.BUTTON,
isActive: true,
Expand All @@ -168,44 +202,39 @@ describe('PropertiesPanel', () => {

test('renders segment properties when segment is selected', async () => {
const mockSegment = createMockSegment('segment1')
mockSegmentsCollection.insert(mockSegment)

// Create a custom wrapper that includes both providers
const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<SelectedElementProvider>{children}</SelectedElementProvider>
)
mockSegmentsCollection.insert(mockSegment)

// Render both the hook and component in the same provider tree
const { result } = renderHook(() => useSelection(), { wrapper: TestWrapper })
let rendered: RenderResult
expect(mockSegmentsCollection.findOne({ _id: mockSegment._id })).toBeTruthy()

await act(async () => {
rendered = render(<PropertiesPanel />, { wrapper: TestWrapper })
})
const { result } = renderHook(() => useSelection(), { wrapper })

// Update selection
// Update selection and wait for component to update
await act(async () => {
result.current.clearAndSetSelection({
type: 'segment',
elementId: mockSegment._id,
})
})
//@ts-expect-error error because avoiding an undefined type
if (!rendered) throw new Error('Component not rendered')

// Force a rerender
// Open component after segment is selected (as used in rundownview)
const { container } = render(<PropertiesPanel />, { wrapper })

await act(async () => {
rendered.rerender(<PropertiesPanel />)
jest.advanceTimersByTime(100)
})

// Wait for the header element to appear
await screen.findByText('SEGMENT : Segment segment1')

const header = rendered.container.querySelector('.propertiespanel-pop-up__header')
const switchButton = rendered.container.querySelector('.propertiespanel-pop-up__switchbutton')
console.log('result', result.current.listSelectedElements())
// Use findByTestId instead of querySelector
await waitFor(
() => {
expect(screen.getByText(`SEGMENT : ${mockSegment.name}`)).toBeInTheDocument()
},
{ timeout: 1000 }
)

expect(header).toHaveTextContent('SEGMENT : Segment segment1')
expect(switchButton).toBeTruthy()
const button = container.querySelector('.propertiespanel-pop-up__button')
expect(button).toBeInTheDocument()
})

test('renders part properties when part is selected', async () => {
Expand All @@ -215,75 +244,59 @@ describe('PropertiesPanel', () => {
mockSegmentsCollection.insert(mockSegment)
mockPartsCollection.insert(mockPart)

// Create a custom wrapper that includes both providers
const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<SelectedElementProvider>{children}</SelectedElementProvider>
)

// Render both the hook and component in the same provider tree
const { result } = renderHook(() => useSelection(), { wrapper: TestWrapper })
let rendered: RenderResult

await act(async () => {
rendered = render(<PropertiesPanel />, { wrapper: TestWrapper })
})
const { result } = renderHook(() => useSelection(), { wrapper })

// Update selection
await act(async () => {
result.current.clearAndSetSelection({
type: 'part',
elementId: mockPart._id,
})
})
// Open component after part is selected (as used in rundownview)
const { container } = render(<PropertiesPanel />, { wrapper })

//@ts-expect-error error because avoiding an undefined type
if (!rendered) throw new Error('Component not rendered')

// Force a rerender
await act(async () => {
rendered.rerender(<PropertiesPanel />)
})

// Wait for the header element to appear
await screen.findByText('PART : Part part1')

const header = rendered.container.querySelector('.propertiespanel-pop-up__header')
const button = rendered.container.querySelector('.propertiespanel-pop-up__button')
await waitFor(
() => {
expect(screen.getByText(`PART : ${mockPart.title}`)).toBeInTheDocument()
},
{ timeout: 1000 }
)

expect(header).toHaveTextContent('PART : Part part1')
expect(button).toBeTruthy()
const button = container.querySelector('.propertiespanel-pop-up__button')
expect(button).toBeInTheDocument()
})

test('handles user edit operations for segments', async () => {
const mockSegment = createMockSegment('segment1')
mockSegmentsCollection.insert(mockSegment)

// First render the selection hook
const { result } = renderHook(() => useSelection(), { wrapper })

// Then render the properties panel
const { container } = render(<PropertiesPanel />, { wrapper })

// Update selection using the hook result
act(() => {
await act(async () => {
result.current.clearAndSetSelection({
type: 'segment',
elementId: mockSegment._id,
})
})

const switchButton = container.querySelector('.propertiespanel-pop-up__switchbutton')
// Wait for the switch button to be available
const switchButton = await waitFor(() => container.querySelector('.propertiespanel-pop-up__switchbutton'))
expect(switchButton).toBeTruthy()

// Toggle the switch
await userEvent.click(switchButton!)
await act(async () => {
await userEvent.click(switchButton!)
})

// Check if commit button is enabled
const commitButton = screen.getByText('COMMIT CHANGES')
expect(commitButton).toBeEnabled()

// Commit changes
await userEvent.click(commitButton)
await act(async () => {
await userEvent.click(commitButton)
})

expect(MeteorCall.userAction.executeUserChangeOperation).toHaveBeenCalledWith(
expect.anything(),
Expand All @@ -305,27 +318,29 @@ describe('PropertiesPanel', () => {
const mockSegment = createMockSegment('segment1')
mockSegmentsCollection.insert(mockSegment)

// First render the selection hook
const { result } = renderHook(() => useSelection(), { wrapper })

// Then render the properties panel
const { container } = render(<PropertiesPanel />, { wrapper })

// Update selection using the hook result
act(() => {
await act(async () => {
result.current.clearAndSetSelection({
type: 'segment',
elementId: mockSegment._id,
})
})

// Wait for the switch button to be available
const switchButton = await waitFor(() => container.querySelector('.propertiespanel-pop-up__switchbutton'))

// Make a change
const switchButton = container.querySelector('.propertiespanel-pop-up__switchbutton')
await userEvent.click(switchButton!)
await act(async () => {
await userEvent.click(switchButton!)
})

// Click revert button
const revertButton = screen.getByText('REVERT CHANGES')
await userEvent.click(revertButton)
await act(async () => {
await userEvent.click(revertButton)
})

expect(MeteorCall.userAction.executeUserChangeOperation).toHaveBeenCalledWith(
expect.anything(),
Expand All @@ -340,30 +355,28 @@ describe('PropertiesPanel', () => {
id: 'REVERT_SEGMENT',
}
)
})
}, 10000) // Increase timeout for this test

test('closes panel when close button is clicked', async () => {
const mockSegment = createMockSegment('segment1')
mockSegmentsCollection.insert(mockSegment)

// First render the selection hook
const { result } = renderHook(() => useSelection(), { wrapper })

// Then render the properties panel
const { container } = render(<PropertiesPanel />, { wrapper })

// Update selection using the hook result
act(() => {
await act(async () => {
result.current.clearAndSetSelection({
type: 'segment',
elementId: mockSegment._id,
})
})

const closeButton = container.querySelector('.propertiespanel-pop-up_close')
const closeButton = await waitFor(() => container.querySelector('.propertiespanel-pop-up_close'))
expect(closeButton).toBeTruthy()

await userEvent.click(closeButton!)
await act(async () => {
await userEvent.click(closeButton!)
})

expect(container.querySelector('.propertiespanel-pop-up__contents')).toBeFalsy()
})
Expand Down

0 comments on commit 5fe974f

Please sign in to comment.