Skip to content

test: deprecate react-unit-test-utils 7/14 #343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions src/components/FilePreview/__snapshots__/index.test.jsx.snap

This file was deleted.

This file was deleted.

24 changes: 24 additions & 0 deletions src/components/FilePreview/components/FileRenderer/hooks.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { mockUseKeyedState } from '@edx/react-unit-test-utils';

import { useRenderData, stateKeys } from './hooks';
import { errorStatuses, errorMessages } from '../constants';

const state = mockUseKeyedState(stateKeys);

Expand Down Expand Up @@ -43,4 +44,27 @@ describe('useRenderData', () => {
state.expectSetStateCalledWith(stateKeys.errorStatus, null);
state.expectSetStateCalledWith(stateKeys.isLoading, true);
});

it('returns correct error message for different error statuses', () => {
// Test notFound error message
state.mockVal(stateKeys.errorStatus, errorStatuses.notFound);
let out = useRenderData(props);
expect(out.error.headerMessage).toBe(errorMessages[errorStatuses.notFound]);

// Test fallback to serverError message for unknown error status
state.mockVal(stateKeys.errorStatus, errorStatuses.badRequest);
out = useRenderData(props);
expect(out.error.headerMessage).toBe(
errorMessages[errorStatuses.serverError],
);
});

it('handles unknown file types', () => {
const propsWithUnknownFile = {
...props,
file: { fileName: 'file.unknown', fileUrl: 'http://example.com' },
};
const out = useRenderData(propsWithUnknownFile);
expect(out.Renderer).toBeUndefined();
});
});
140 changes: 116 additions & 24 deletions src/components/FilePreview/components/FileRenderer/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
import { shallow } from '@edx/react-unit-test-utils';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { IntlProvider } from '@edx/frontend-platform/i18n';

import { useRenderData } from './hooks';
import { FileRenderer } from './index';

jest.mock('./Banners', () => ({
ErrorBanner: () => 'ErrorBanner',
LoadingBanner: () => 'LoadingBanner',
}));
jest.unmock('@openedx/paragon');
jest.unmock('react');
jest.unmock('@edx/frontend-platform/i18n');

/* eslint-disable react/prop-types */

jest.mock('./hooks', () => ({
useRenderData: jest.fn(),
}));

jest.mock('./Banners', () => ({
ErrorBanner: ({ message, headerMessage, actions }) => (
<div data-testid="error-banner">
<div data-testid="error-header">{headerMessage}</div>
<div data-testid="error-message">{message}</div>
{actions?.map((action) => (
<span data-testid={`error-action-${action.id}`}>{action.message}</span>
))}
</div>
),
LoadingBanner: () => <div data-testid="loading-banner">Loading...</div>,
}));

jest.mock('./FileCard', () => ({ children, file, defaultOpen }) => (
<div data-testid="file-card">
<div>
{file.fileName} - {defaultOpen ? 'open' : 'closed'}
</div>
{children}
</div>
));

describe('FileRenderer Component', () => {
const renderWithIntl = (component) => render(<IntlProvider locale="en">{component}</IntlProvider>);

const props = {
file: {
fileName: 'some_file',
Expand All @@ -22,7 +49,7 @@ describe('FileRenderer Component', () => {
};

const defaultRenderData = {
Renderer: () => 'Renderer',
Renderer: () => <div data-testid="renderer">Renderer content</div>,
isLoading: false,
errorStatus: false,
error: null,
Expand All @@ -31,32 +58,97 @@ describe('FileRenderer Component', () => {
},
};

it('render default', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('renders default renderer', () => {
useRenderData.mockReturnValue(defaultRenderData);
const wrapper = shallow(<FileRenderer {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
renderWithIntl(<FileRenderer {...props} />);

expect(wrapper.instance.findByType('Renderer')).toHaveLength(1);
expect(wrapper.instance.findByType('LoadingBanner')).toHaveLength(0);
expect(wrapper.instance.findByType('ErrorBanner')).toHaveLength(0);
expect(screen.getByTestId('file-card')).toBeInTheDocument();
expect(screen.getByText('some_file - open')).toBeInTheDocument();
expect(screen.getByTestId('renderer')).toBeInTheDocument();
expect(screen.getByText('Renderer content')).toBeInTheDocument();
expect(screen.queryByTestId('loading-banner')).not.toBeInTheDocument();
expect(screen.queryByTestId('error-banner')).not.toBeInTheDocument();
});

it('render loading banner', () => {
it('renders loading banner', () => {
useRenderData.mockReturnValue({ ...defaultRenderData, isLoading: true });
const wrapper = shallow(<FileRenderer {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
renderWithIntl(<FileRenderer {...props} />);

expect(screen.getByTestId('loading-banner')).toBeInTheDocument();
expect(screen.getByText('Loading...')).toBeInTheDocument();
expect(screen.queryByTestId('error-banner')).not.toBeInTheDocument();
expect(screen.queryByTestId('renderer')).not.toBeInTheDocument();
});

expect(wrapper.instance.findByType('LoadingBanner')).toHaveLength(1);
expect(wrapper.instance.findByType('ErrorBanner')).toHaveLength(0);
expect(wrapper.instance.findByType('Renderer')).toHaveLength(0);
it('renders error banner', () => {
useRenderData.mockReturnValue({
errorStatus: true,
error: { message: 'some_error' },
});
renderWithIntl(<FileRenderer {...props} />);

expect(screen.getByTestId('error-banner')).toBeInTheDocument();
expect(screen.getByText('some_error')).toBeInTheDocument();
expect(screen.queryByTestId('loading-banner')).not.toBeInTheDocument();
expect(screen.queryByTestId('renderer')).not.toBeInTheDocument();
});

it('passes defaultOpen prop correctly', () => {
useRenderData.mockReturnValue(defaultRenderData);
renderWithIntl(<FileRenderer {...props} defaultOpen={false} />);

expect(screen.getByText('some_file - closed')).toBeInTheDocument();
});

it('passes rendererProps to Renderer component', () => {
const CustomRenderer = jest.fn(() => <div>Custom Renderer</div>);
const customRendererProps = {
prop1: 'value1',
prop2: 'value2',
};
useRenderData.mockReturnValue({
...defaultRenderData,
Renderer: CustomRenderer,
rendererProps: customRendererProps,
});

renderWithIntl(<FileRenderer {...props} />);
expect(CustomRenderer).toHaveBeenCalledWith(customRendererProps, {});
});

it('passes all error properties to ErrorBanner', () => {
const errorData = {
headerMessage: 'Error Header',
message: 'Error Message',
actions: [{ id: 'retry', message: 'Retry', onClick: jest.fn() }],
};
useRenderData.mockReturnValue({
errorStatus: true,
error: errorData,
});

renderWithIntl(<FileRenderer {...props} />);
expect(screen.getByTestId('error-header')).toHaveTextContent(
'Error Header',
);
expect(screen.getByTestId('error-message')).toHaveTextContent(
'Error Message',
);
expect(screen.getByTestId('error-action-retry')).toHaveTextContent('Retry');
});

it('render error banner', () => {
useRenderData.mockReturnValue({ errorStatus: true, error: { message: 'some_error' } });
const wrapper = shallow(<FileRenderer {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
it('handles missing optional file properties', () => {
const minimalProps = {
file: { fileName: 'minimal_file' },
defaultOpen: true,
};
useRenderData.mockReturnValue(defaultRenderData);

expect(wrapper.instance.findByType('ErrorBanner')).toHaveLength(1);
expect(wrapper.instance.findByType('LoadingBanner')).toHaveLength(0);
renderWithIntl(<FileRenderer {...minimalProps} />);
expect(screen.getByText('minimal_file - open')).toBeInTheDocument();
});
});
63 changes: 46 additions & 17 deletions src/components/FilePreview/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,86 @@
import { shallow } from '@edx/react-unit-test-utils';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import { useResponse } from 'hooks/app';
import { isSupported } from './components';

import FilePreview from './index';

jest.unmock('@openedx/paragon');
jest.unmock('react');
jest.unmock('@edx/frontend-platform/i18n');

jest.mock('hooks/app', () => ({
useResponse: jest.fn(),
}));

jest.mock('./components', () => ({
FileRenderer: () => 'FileRenderer',
// eslint-disable-next-line react/prop-types
FileRenderer: ({ file, defaultOpen }) => (
<div data-testid="file-renderer">
{/* eslint-disable-next-line react/prop-types */}
{file.fileName} - {defaultOpen ? 'open' : 'closed'}
</div>
),
isSupported: jest.fn(),
}));

describe('<FilePreview />', () => {
const props = {
defaultCollapsePreview: false,
};

beforeEach(() => {
jest.clearAllMocks();
});

it('renders nothing when no files are uploaded', () => {
useResponse.mockReturnValueOnce({ uploadedFiles: null });
const wrapper = shallow(<FilePreview {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
expect(wrapper.isEmptyRender()).toBe(true);
useResponse.mockReturnValue({ uploadedFiles: null });
const { container } = render(<FilePreview {...props} />);
expect(container.firstChild).toBeNull();
});

it('renders only div when no supported files are uploaded', () => {
useResponse.mockReturnValueOnce({
it('renders empty div when no supported files are uploaded', () => {
useResponse.mockReturnValue({
uploadedFiles: [{ fileName: 'file1.txt' }],
});
isSupported.mockReturnValueOnce(false);
const wrapper = shallow(<FilePreview {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
isSupported.mockReturnValue(false);
const { container } = render(<FilePreview {...props} />);

expect(wrapper.instance.findByType('FileRenderer')).toHaveLength(0);
expect(container.firstChild).toBeInTheDocument();
expect(container.firstChild.tagName).toBe('DIV');
expect(screen.queryByTestId('file-renderer')).not.toBeInTheDocument();
});

it('render only supported files', () => {
it('renders only supported files', () => {
isSupported
.mockReturnValueOnce(false)
.mockReturnValueOnce(true)
.mockReturnValueOnce(true);

useResponse.mockReturnValueOnce({
useResponse.mockReturnValue({
uploadedFiles: [
{ fileName: 'file1.txt' },
{ fileName: 'file2.pdf' },
{ fileName: 'file3.jpg' },
],
});
const wrapper = shallow(<FilePreview {...props} />);
expect(wrapper.snapshot).toMatchSnapshot();
render(<FilePreview {...props} />);

const fileRenderers = screen.getAllByTestId('file-renderer');
expect(fileRenderers).toHaveLength(2);
expect(screen.getByText('file2.pdf - open')).toBeInTheDocument();
expect(screen.getByText('file3.jpg - open')).toBeInTheDocument();
expect(screen.queryByText('file1.txt - open')).not.toBeInTheDocument();
});

it('passes defaultCollapsePreview prop correctly', () => {
isSupported.mockReturnValue(true);
useResponse.mockReturnValue({
uploadedFiles: [{ fileName: 'file1.pdf' }],
});
render(<FilePreview defaultCollapsePreview />);

expect(wrapper.instance.findByType('FileRenderer')).toHaveLength(2);
expect(screen.getByText('file1.pdf - closed')).toBeInTheDocument();
});
});
Loading
Loading