mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-28 09:24:24 +01:00
(test) improved frontend tests
This commit is contained in:
parent
9d2dde8257
commit
b30701ba6f
@ -25,6 +25,7 @@ interface FabTextEditorProps {
|
||||
placeholder?: string,
|
||||
error?: string,
|
||||
disabled?: boolean
|
||||
editorId?: string,
|
||||
}
|
||||
|
||||
export interface FabTextEditorRef {
|
||||
@ -34,7 +35,7 @@ export interface FabTextEditorRef {
|
||||
/**
|
||||
* This component is a WYSIWYG text editor
|
||||
*/
|
||||
const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEditorProps> = ({ heading, bulletList, blockquote, content, limit = 400, video, image, link, onChange, placeholder, error, disabled = false }, ref: RefObject<FabTextEditorRef>) => {
|
||||
const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEditorProps> = ({ heading, bulletList, blockquote, content, limit = 400, video, image, link, onChange, placeholder, error, disabled = false, editorId }, ref: RefObject<FabTextEditorRef>) => {
|
||||
const { t } = useTranslation('shared');
|
||||
const placeholderText = placeholder || t('app.shared.text_editor.fab_text_editor.text_placeholder');
|
||||
// TODO: Add ctrl+click on link to visit
|
||||
@ -74,6 +75,11 @@ const FabTextEditor: React.ForwardRefRenderFunction<FabTextEditorRef, FabTextEdi
|
||||
}
|
||||
})
|
||||
],
|
||||
editorProps: {
|
||||
attributes: {
|
||||
id: editorId
|
||||
}
|
||||
},
|
||||
content,
|
||||
onUpdate: ({ editor }) => {
|
||||
if (editor.isEmpty) {
|
||||
|
@ -8,6 +8,7 @@ export interface AbstractFormItemProps<TFieldValues> extends PropsWithChildren<A
|
||||
id: string,
|
||||
label?: string|ReactNode,
|
||||
ariaLabel?: string,
|
||||
ariaLabelledBy?: string,
|
||||
tooltip?: ReactNode,
|
||||
className?: string,
|
||||
disabled?: boolean|((id: string) => boolean),
|
||||
@ -20,7 +21,7 @@ export interface AbstractFormItemProps<TFieldValues> extends PropsWithChildren<A
|
||||
* This abstract component should not be used directly.
|
||||
* Other forms components that are intended to be used with react-hook-form must extend this component.
|
||||
*/
|
||||
export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label, ariaLabel, tooltip, className, disabled, error, warning, rules, formState, onLabelClick, inLine, containerType, children }: AbstractFormItemProps<TFieldValues>) => {
|
||||
export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label, ariaLabel, ariaLabelledBy, tooltip, className, disabled, error, warning, rules, formState, onLabelClick, inLine, containerType, children }: AbstractFormItemProps<TFieldValues>) => {
|
||||
const [isDirty, setIsDirty] = useState<boolean>(false);
|
||||
const [fieldError, setFieldError] = useState<{ message: string }>(error);
|
||||
const [isDisabled, setIsDisabled] = useState<boolean>(false);
|
||||
@ -71,7 +72,7 @@ export const AbstractFormItem = <TFieldValues extends FieldValues>({ id, label,
|
||||
</div>}
|
||||
</div>}
|
||||
|
||||
<div className='form-item-field' aria-label={ariaLabel}>
|
||||
<div className='form-item-field' aria-label={ariaLabel} aria-labelledby={ariaLabelledBy}>
|
||||
{inLine && <div className='form-item-header'><p>{label}</p>
|
||||
{tooltip && <div className="fab-tooltip">
|
||||
<span className="trigger"><i className="fa fa-question-circle" /></span>
|
||||
|
@ -47,6 +47,7 @@ export const FormRichText = <TFieldValues extends FieldValues, TContext extends
|
||||
return (
|
||||
<AbstractFormItem id={id} label={label} tooltip={tooltip}
|
||||
ariaLabel={label as string}
|
||||
ariaLabelledBy={id}
|
||||
containerType={'div'}
|
||||
className={`form-rich-text ${className || ''}`}
|
||||
error={error} warning={warning} rules={rules}
|
||||
@ -66,7 +67,8 @@ export const FormRichText = <TFieldValues extends FieldValues, TContext extends
|
||||
image={image}
|
||||
link={link}
|
||||
disabled={isDisabled}
|
||||
ref={textEditorRef} />
|
||||
ref={textEditorRef}
|
||||
editorId={id} />
|
||||
} />
|
||||
</AbstractFormItem>
|
||||
);
|
||||
|
@ -32,12 +32,13 @@ interface PlanFormProps {
|
||||
plan?: Plan,
|
||||
onError: (message: string) => void,
|
||||
onSuccess: (message: string) => void,
|
||||
beforeSubmit?: (data: Plan) => void,
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to edit or create subscription plans
|
||||
*/
|
||||
export const PlanForm: React.FC<PlanFormProps> = ({ action, plan, onError, onSuccess }) => {
|
||||
export const PlanForm: React.FC<PlanFormProps> = ({ action, plan, onError, onSuccess, beforeSubmit }) => {
|
||||
const { handleSubmit, register, control, formState, setValue } = useForm<Plan>({ defaultValues: { ...plan } });
|
||||
const output = useWatch<Plan>({ control }); // eslint-disable-line
|
||||
const { t } = useTranslation('admin');
|
||||
@ -64,6 +65,7 @@ export const PlanForm: React.FC<PlanFormProps> = ({ action, plan, onError, onSuc
|
||||
* Callback triggered when the user validates the plan form: handle create or update
|
||||
*/
|
||||
const onSubmit: SubmitHandler<Plan> = (data: Plan) => {
|
||||
if (typeof beforeSubmit === 'function') beforeSubmit(data);
|
||||
PlanAPI[action](data).then(() => {
|
||||
onSuccess(t(`app.admin.plan_form.${action}_success`));
|
||||
window.location.href = '/#!/admin/pricing';
|
||||
|
@ -24,6 +24,7 @@
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "12",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.17.0",
|
||||
"@typescript-eslint/parser": "^5.17.0",
|
||||
"babel-jest": "^29.3.1",
|
||||
|
@ -3,7 +3,7 @@ import { rest } from 'msw';
|
||||
import groups from '../__fixtures__/groups';
|
||||
import plans from '../__fixtures__/plans';
|
||||
import planCategories from '../__fixtures__/plan_categories';
|
||||
import { partners } from '../__fixtures__/users';
|
||||
import { partners, managers, users } from '../__fixtures__/users';
|
||||
import { settings } from '../__fixtures__/settings';
|
||||
|
||||
export const server = setupServer(
|
||||
@ -14,11 +14,21 @@ export const server = setupServer(
|
||||
return res(ctx.json(planCategories));
|
||||
}),
|
||||
rest.get('/api/users', (req, res, ctx) => {
|
||||
return res(ctx.json(partners));
|
||||
switch (new URLSearchParams(req.url.search).get('role')) {
|
||||
case 'partner':
|
||||
return res(ctx.json(partners));
|
||||
case 'manager':
|
||||
return res(ctx.json(managers));
|
||||
default:
|
||||
return res(ctx.json(users));
|
||||
}
|
||||
}),
|
||||
rest.get('/api/plans', (req, res, ctx) => {
|
||||
return res(ctx.json(plans));
|
||||
}),
|
||||
rest.post('/api/plans', (req, res, ctx) => {
|
||||
return res(ctx.json(req.body));
|
||||
}),
|
||||
rest.post('/api/users', (req, res, ctx) => {
|
||||
/* eslint-disable camelcase */
|
||||
const { user: { first_name, last_name, email } } = req.body;
|
||||
|
@ -15,5 +15,9 @@ describe('AccountingCodesSettings', () => {
|
||||
expect(screen.getAllByLabelText(/app.admin.accounting_codes_settings.code/)).toHaveLength(13);
|
||||
expect(screen.getAllByLabelText(/app.admin.accounting_codes_settings.label/)).toHaveLength(13);
|
||||
expect(screen.getByRole('button', { name: /app.admin.accounting_codes_settings.save/ })).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: /app.admin.accounting_codes_settings.save/ }));
|
||||
await waitFor(() => {
|
||||
expect(onSuccess).toHaveBeenCalledWith('app.admin.accounting_codes_settings.update_success');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -2,15 +2,19 @@ import React from 'react';
|
||||
import { render, fireEvent, waitFor, screen } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { PlanForm } from 'components/plans/plan-form';
|
||||
import selectEvent from 'react-select-event';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import plans from '../../__fixtures__/plans';
|
||||
|
||||
describe('PlanForm', () => {
|
||||
const onError = jest.fn();
|
||||
const onSuccess = jest.fn();
|
||||
const beforeSubmit = jest.fn();
|
||||
|
||||
test('render create PlanForm', async () => {
|
||||
render(<PlanForm action="create" onError={onError} onSuccess={onSuccess} />);
|
||||
render(<PlanForm action="create" onError={onError} onSuccess={onSuccess} beforeSubmit={beforeSubmit} />);
|
||||
await waitFor(() => screen.getByRole('combobox', { name: /app.admin.plan_form.group/ }));
|
||||
// check inputs
|
||||
expect(screen.getByLabelText(/app.admin.plan_form.name/)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/app.admin.plan_form.transversal/)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/app.admin.plan_form.group/)).toBeInTheDocument();
|
||||
@ -27,6 +31,24 @@ describe('PlanForm', () => {
|
||||
expect(screen.getByLabelText(/app.admin.plan_form.partner_plan/)).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('plan-pricing-form')).toBeNull();
|
||||
expect(screen.getByRole('button', { name: /app.admin.plan_form.ACTION_plan/ })).toBeInTheDocument();
|
||||
// input values
|
||||
const user = userEvent.setup();
|
||||
fireEvent.change(screen.getByLabelText(/app.admin.plan_form.name/), { target: { value: 'Test Plan' } });
|
||||
await selectEvent.select(screen.getByLabelText(/app.admin.plan_form.group/), 'Standard');
|
||||
await selectEvent.select(screen.getByLabelText(/app.admin.plan_form.category/), 'beginners');
|
||||
fireEvent.change(screen.getByLabelText(/app.admin.plan_form.subscription_price/), { target: { value: 25.21 } });
|
||||
fireEvent.change(screen.getByLabelText(/app.admin.plan_form.visual_prominence/), { target: { value: 10 } });
|
||||
fireEvent.change(screen.getByLabelText(/app.admin.plan_form.rolling_subscription/), { target: { value: true } });
|
||||
fireEvent.change(screen.getByLabelText(/app.admin.plan_form.monthly_payment/), { target: { value: true } });
|
||||
await user.click(screen.getByLabelText(/app.admin.plan_form.description/));
|
||||
await user.keyboard('Lorem ipsum dolor sit amet');
|
||||
fireEvent.change(screen.getByLabelText(/app.admin.plan_form.number_of_periods/), { target: { value: 6 } });
|
||||
await selectEvent.select(screen.getByLabelText(/app.admin.plan_form.period/), 'app.admin.plan_form.month');
|
||||
// send the form
|
||||
fireEvent.click(screen.getByRole('button', { name: /app.admin.plan_form.ACTION_plan/ }));
|
||||
await waitFor(() => {
|
||||
expect(beforeSubmit).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
test('render update PlanForm with partner', async () => {
|
||||
|
@ -2914,6 +2914,11 @@
|
||||
"@testing-library/dom" "^8.0.0"
|
||||
"@types/react-dom" "<18.0.0"
|
||||
|
||||
"@testing-library/user-event@^14.4.3":
|
||||
version "14.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591"
|
||||
integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==
|
||||
|
||||
"@tiptap/core@^2.0.0-beta.204":
|
||||
version "2.0.0-beta.204"
|
||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.204.tgz#ec37e333718ed21b399e394cea06b7ab4653bbd3"
|
||||
|
Loading…
Reference in New Issue
Block a user