test: add tests for ActionsDropdown

This commit is contained in:
Maxim Beder
2021-10-05 00:42:38 +02:00
committed by Maxim Beder
parent b8b91b9225
commit 35c9dd543c
3 changed files with 190 additions and 2 deletions

View File

@@ -48,7 +48,10 @@ function ActionsDropdown({
isOpen={isOpen}
placement="auto-start"
>
<div className="bg-white p-1 shadow d-flex flex-column">
<div
className="bg-white p-1 shadow d-flex flex-column"
data-testid="actions-dropdown-modal-popup"
>
{actions.map(action => (
<React.Fragment key={action.id}>
{action.action === ContentActions.DELETE

View File

@@ -0,0 +1,185 @@
import {
fireEvent, render, screen, waitFor,
} from '@testing-library/react';
import { IntlProvider } from 'react-intl';
import { Factory } from 'rosie';
import { camelCaseObject, initializeMockApp, snakeCaseObject } from '@edx/frontend-platform';
import { AppProvider } from '@edx/frontend-platform/react';
import { ContentActions } from '../../data/constants';
import messages from '../messages';
import { ACTIONS_LIST } from '../utils';
import ActionsDropdown from './ActionsDropdown';
import '../posts/data/__factories__';
import '../comments/data/__factories__';
let store;
function buildTestContent(buildParams) {
const buildParamsSnakeCase = snakeCaseObject(buildParams);
return [
Factory.build('comment', { ...buildParamsSnakeCase }, null),
// question
Factory.build('thread', { ...buildParamsSnakeCase }, null),
// thread
Factory.build('thread', { ...buildParamsSnakeCase }, null),
].map(content => camelCaseObject(content));
}
const canPerformActionTestData = ACTIONS_LIST
.map(({ action, conditions, label: { defaultMessage } }) => {
const buildParams = {
editable_fields: [action],
};
if (conditions) {
Object.entries(conditions)
.forEach(([conditionKey, conditionValue]) => {
buildParams[conditionKey] = conditionValue;
});
}
return buildTestContent(buildParams)
.map(commentOrPost => ([defaultMessage, commentOrPost, action]));
})
.flat();
const canNotPerformActionTestData = ACTIONS_LIST
.map(({ action, conditions, label: { defaultMessage } }) => {
let content;
if (!conditions) {
content = buildTestContent({
editable_fields: [],
});
} else {
const reversedConditions = Object.keys(conditions)
.reduce(
(results, key) => ({
...results,
[key]: !conditions[key],
}),
{},
);
content = [
// can edit field, but doesn't pass conditions
...buildTestContent({
editable_fields: [action],
...reversedConditions,
}),
// passes conditions, but can't edit field
...(action === ContentActions.DELETE
? []
: buildTestContent({
editable_fields: [],
...conditions,
})
),
// can't edit field, and doesn't pass conditions
...buildTestContent({
editable_fields: [],
...reversedConditions,
}),
];
}
return content.map(commentOrPost => ([defaultMessage, commentOrPost]));
})
.flat();
function renderComponent(
commentOrPost,
{ disabled = false, actionHandlers = {} } = {},
) {
render(
<IntlProvider locale="en">
<AppProvider store={store}>
<ActionsDropdown
commentOrPost={commentOrPost}
disabled={disabled}
actionHandlers={actionHandlers}
/>
</AppProvider>
</IntlProvider>,
);
}
const findOpenActionsDropdownButton = async () => (
screen.findByRole('button', { name: messages.actionsAlt.defaultMessage })
);
describe('ActionsDropdown', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: false,
roles: [],
},
});
});
it.each(buildTestContent())(
'can open drop down if enabled',
async (commentOrPost) => {
renderComponent(commentOrPost, { disabled: false });
const openButton = await findOpenActionsDropdownButton();
fireEvent.click(openButton);
await waitFor(() => expect(screen.queryByTestId('actions-dropdown-modal-popup'))
.toBeInTheDocument());
},
);
it.each(buildTestContent())(
'can not open drop down if disabled',
async (commentOrPost) => {
renderComponent(commentOrPost, { disabled: true });
const openButton = await findOpenActionsDropdownButton();
fireEvent.click(openButton);
await waitFor(() => expect(screen.queryByTestId('actions-dropdown-modal-popup'))
.not
.toBeInTheDocument());
},
);
it.each(canPerformActionTestData)(
// not using jest $variable notation because it's not working (probably a bug)
'can perform action %s',
async (defaultMessage, commentOrPost, action) => {
const mockHandler = jest.fn();
renderComponent(
commentOrPost,
{ actionHandlers: { [action]: mockHandler } },
);
const openButton = await findOpenActionsDropdownButton();
fireEvent.click(openButton);
await waitFor(() => expect(screen.queryByText(defaultMessage))
.toBeInTheDocument());
fireEvent.click(screen.queryByText(defaultMessage));
expect(mockHandler).toHaveBeenCalled();
},
);
it.each(canNotPerformActionTestData)(
// not using jest $variable notation because it's not working (probably a bug)
'can not perform action %s',
async (defaultMessage, commentOrPost) => {
renderComponent(commentOrPost);
const openButton = await findOpenActionsDropdownButton();
fireEvent.click(openButton);
await waitFor(() => expect(screen.queryByText(defaultMessage))
.not
.toBeInTheDocument());
},
);
});

View File

@@ -80,7 +80,7 @@ export function checkPermissions(content, action) {
* in the content/post.
* e.g. for {pinned:false} the action will show up if the content/post has post.pinned==false
*/
const ACTIONS_LIST = [
export const ACTIONS_LIST = [
{
id: 'edit',
action: ContentActions.EDIT_CONTENT,