import React, { useState } from 'react'; import { render, act, fireEvent, screen, waitFor } from '@testing-library/react'; import { ResourceBrowserInput, ResourceBrowserInputProps } from './ResourceBrowserInput'; import { mockSource, mockResource } from '../__mocks__/MockModels'; import { ResourceBrowserPlugin, ResourceBrowserUnresolvedResource } from '../types'; import * as RP from '../ResourcePicker/ResourcePicker'; jest.spyOn(RP, 'ResourcePicker'); describe('Resource browser input', () => { const mockUseResource = jest.fn().mockReturnValue({ data: null, error: null, isLoading: false, reload: () => {}, }); const mockChange = jest.fn(); const mockSetSource = jest.fn(); const mockOnModalStateChange = jest.fn(); const renderComponent = (props: Partial = {}) => { return render( , ); }; it('If onClear function is provided passes through to ResourcePicker', async () => { const myOnClear = jest.fn(); renderComponent({ onClear: myOnClear }); await waitFor(() => { expect(RP.ResourcePicker).toHaveBeenCalledWith( expect.objectContaining({ onClear: myOnClear, }), {}, ); }); }); it('If onClear function is not provided creates one which nulls change', async () => { renderComponent(); await waitFor(() => { expect(RP.ResourcePicker).toHaveBeenCalled(); }); expect(mockChange).not.toHaveBeenCalled(); // Invoke modal close callback const { onClear } = (RP.ResourcePicker as unknown as jest.SpyInstance).mock.calls[0][0]; onClear(); expect(mockChange).toHaveBeenCalledWith(null); }); /* These tests dont actually belong in this component as they do not control these items directly and never have but were tested here when this was originally written. */ describe('Legacy tests', () => { it('should render the related asset picker with the default label', async () => { renderComponent(); await waitFor(() => { expect(screen.getByText('Choose asset')).toBeInTheDocument(); }); }); it('should display the generic asset picking icon', async () => { renderComponent(); await waitFor(() => { expect(screen.getByText('Choose asset')).toBeInTheDocument(); expect(screen.getByTestId('AdsClickRoundedIcon')).toBeInTheDocument(); }); }); it('should display the image icon when only images are allowed', async () => { renderComponent({ allowedTypes: ['image'] }); await waitFor(() => { expect(screen.getByText('Choose image')).toBeInTheDocument(); expect(screen.getByTestId('PhotoLibraryRoundedIcon')).toBeInTheDocument(); }); }); it('should disallow removing and replacing selection if the input is disabled', async () => { const source = mockSource(); const resource = mockResource({ source: source }); mockUseResource.mockReturnValueOnce({ data: resource, error: null, isLoading: false, reload: () => {}, }); const plugin: Partial = { renderSelectedResource: () => { return Promise.resolve({ icon:
IconGoesHere
, label: 'Products', description: [], }); }, }; renderComponent({ value: { sourceId: source.id, resourceId: '100' }, isDisabled: true, plugin: plugin as ResourceBrowserPlugin, }); await waitFor(() => expect(screen.queryByLabelText('Loading selection')).not.toBeInTheDocument()); expect(screen.getByRole('button', { name: 'Remove selection' })).toBeDisabled(); expect(screen.getByRole('button', { name: 'Replace selection' })).toBeDisabled(); }); it('clicking the replace selection button should open the resource browser', async () => { const source = mockSource(); const resource = mockResource({ source: source }); mockUseResource.mockReturnValueOnce({ data: resource, error: null, isLoading: false, reload: () => {}, }); const plugin: Partial = { renderSelectedResource: () => { return Promise.resolve({ icon:
IconGoesHere
, label: 'Products', description: [], }); }, sourceBrowserComponent: () => { return () => { return <>; }; }, sourceSearchComponent: () => { return () => { return <>; }; }, }; renderComponent({ value: { sourceId: source.id, resourceId: '100' }, plugin: plugin as ResourceBrowserPlugin, }); await waitFor(() => expect(screen.queryByLabelText('Loading selection')).not.toBeInTheDocument()); await act(() => fireEvent.click(screen.getByRole('button', { name: 'Replace selection' }))); // Modal index state change handler was instructed to open expect(mockOnModalStateChange).toHaveBeenCalledWith(true); }); it.each([ ['resource selected', { sourceId: mockSource().id, resourceId: '100' }, 1], ['resource not selected', null, 0], ])( 'should only display the "replace" button if a resource has already been selected - %s', async (description: string, value: ResourceBrowserUnresolvedResource | null, expectedReplaceSelectionButtons: number) => { const source = mockSource(); const resource = mockResource({ source: source }); mockUseResource.mockReturnValueOnce({ data: value, error: null, isLoading: false, reload: () => {}, }); const plugin: Partial = { renderSelectedResource: () => { return Promise.resolve({ icon:
IconGoesHere
, label: 'Products', description: [], }); }, }; renderComponent({ value, plugin: plugin as ResourceBrowserPlugin }); await waitFor(() => expect(screen.queryByLabelText('Loading selection')).not.toBeInTheDocument()); expect(screen.queryAllByRole('button', { name: 'Replace selection' })).toHaveLength(expectedReplaceSelectionButtons); }, ); }); });