import React from 'react'; import { AutofillContextProvider, type MetadataTemplateField, type MetadataTemplateInstance, } from '@box/metadata-editor'; import userEvent from '@testing-library/user-event'; import { TooltipProvider } from '@box/blueprint-web'; import { IntlProvider } from 'react-intl'; import { screen, render } from '../../../test-utils/testing-library'; import MetadataInstanceEditor, { MetadataInstanceEditorProps } from '../MetadataInstanceEditor'; import { FeatureProvider } from '../../common/feature-checking'; const mockOnCancel = jest.fn(); const mockOnDiscardUnsavedChanges = jest.fn(); const mockSetIsUnsavedChangesModalOpen = jest.fn(); jest.unmock('react-intl'); const wrapper = ({ children }) => ( Promise.resolve([])} isAiSuggestionsFeatureEnabled> {children} ); const renderWithAutofill = element => render(element, { wrapper }); describe('MetadataInstanceEditor', () => { const mockCustomMetadataTemplate: MetadataTemplateInstance = { id: 'template-id', fields: [], scope: 'global', templateKey: 'properties', type: 'template-id', hidden: false, canEdit: true, }; const mockMetadataTemplate: MetadataTemplateInstance = { ...mockCustomMetadataTemplate, displayName: 'Template Name', canEdit: true, }; const mockCustomMetadataTemplateWithField: MetadataTemplateInstance = { id: 'template-id', fields: [ { id: '1', type: 'string', key: 'signature', hidden: false, displayName: 'Signature', }, ], scope: 'global', templateKey: 'customTemplate', type: 'template-id', hidden: false, canEdit: true, }; const mockMetadataTemplateInstance: MetadataTemplateInstance = { ...mockCustomMetadataTemplate, displayName: 'Template Name', }; const defaultProps: MetadataInstanceEditorProps = { areAiSuggestionsAvailable: true, isBetaLanguageEnabled: false, isBoxAiSuggestionsEnabled: true, isDeleteButtonDisabled: false, isDeleteConfirmationModalCheckboxEnabled: false, isLargeFile: false, isMetadataMultiLevelTaxonomyFieldEnabled: false, isUnsavedChangesModalOpen: false, onCancel: mockOnCancel, onDelete: jest.fn(), onDiscardUnsavedChanges: mockOnDiscardUnsavedChanges, onSubmit: jest.fn(), setIsUnsavedChangesModalOpen: mockSetIsUnsavedChangesModalOpen, taxonomyOptionsFetcher: jest.fn(), template: mockMetadataTemplate, }; test('should render MetadataInstanceForm with correct props', () => { renderWithAutofill(); const templateHeader = screen.getByText(mockMetadataTemplateInstance.displayName); expect(templateHeader).toBeInTheDocument(); }); test('should render MetadataInstanceForm with Custom Template', () => { const props = { ...defaultProps, template: mockCustomMetadataTemplate }; renderWithAutofill(); const templateHeader = screen.getByText('Custom Metadata'); expect(templateHeader).toBeInTheDocument(); }); test('should render UnsavedChangesModal if isUnsavedChangesModalOpen is true', async () => { const props = { ...defaultProps, isUnsavedChangesModalOpen: true }; const { findByText } = renderWithAutofill(); const unsavedChangesModal = await findByText('Unsaved Changes'); expect(unsavedChangesModal).toBeInTheDocument(); }); test('should render MetadataInstanceForm with Delete button disabled', () => { const props = { ...defaultProps, isDeleteButtonDisabled: true }; renderWithAutofill(); const deleteButton = screen.getByRole('button', { name: 'Delete' }); expect(deleteButton).toBeDisabled(); }); test('should render MetadataInstanceForm with Delete button enabled', () => { renderWithAutofill(); const deleteButton = screen.getByRole('button', { name: 'Delete' }); expect(deleteButton).toBeEnabled(); }); test('Should call onCancel when canceling editing', async () => { const props: MetadataInstanceEditorProps = { ...defaultProps, template: mockCustomMetadataTemplate }; renderWithAutofill(); const cancelButton = await screen.findByRole('button', { name: 'Cancel' }); await userEvent.click(cancelButton); expect(mockOnCancel).toHaveBeenCalled(); }); test('Should call onDiscardUnsavedChanges instead onCancel when canceling through UnsavedChangesModal', async () => { const props: MetadataInstanceEditorProps = { ...defaultProps, template: mockCustomMetadataTemplateWithField, }; const { rerender } = renderWithAutofill(); const input = await screen.findByRole('textbox'); const cancelButton = await screen.findByRole('button', { name: 'Cancel' }); await userEvent.type(input, 'Lorem ipsum dolor.'); await userEvent.click(cancelButton); expect(mockOnCancel).not.toHaveBeenCalled(); expect(mockSetIsUnsavedChangesModalOpen).toHaveBeenCalledWith(true); rerender(); const unsavedChangesModal = await screen.findByText('Unsaved Changes'); expect(unsavedChangesModal).toBeInTheDocument(); const unsavedChangesModalDiscardButton = await screen.findByRole('button', { name: 'Discard Changes' }); await userEvent.click(unsavedChangesModalDiscardButton); expect(mockOnDiscardUnsavedChanges).toHaveBeenCalled(); }); test('should call taxonomyOptionsFetcher on metadata taxonomy field search', async () => { const taxonomyField: MetadataTemplateField = { type: 'taxonomy', key: 'States', displayName: 'States', description: 'State locations', hidden: false, id: '2', taxonomyKey: 'geography', taxonomyId: '1', optionsRules: { multiSelect: true, selectableLevels: [1], }, }; const template: MetadataTemplateInstance = { ...mockCustomMetadataTemplateWithField, fields: [...mockCustomMetadataTemplateWithField.fields, taxonomyField], }; const props: MetadataInstanceEditorProps = { ...defaultProps, template, }; const { getByRole } = renderWithAutofill(); const combobox = getByRole('combobox', { name: 'States' }); await userEvent.type(combobox, 'A'); expect(props.taxonomyOptionsFetcher).toHaveBeenCalledWith( template.scope, template.templateKey, taxonomyField.key, taxonomyField.optionsRules.selectableLevels[0], { marker: null, searchInput: 'A', signal: expect.anything() }, ); }); });