Skip to content

Commit

Permalink
test: refactor and more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fmorency committed Sep 4, 2024
1 parent 1b32348 commit 19a8476
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 60 deletions.
Binary file modified bun.lockb
Binary file not shown.
13 changes: 5 additions & 8 deletions components/bank/forms/__tests__/ibcSendForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ function renderWithProps(props = {}) {
return renderWithChainProvider(<IbcSendForm {...defaultProps} {...props} />);
}

// TODO: Validate form inputs in component
describe('IbcSendForm Component', () => {
afterEach(cleanup);

Expand Down Expand Up @@ -60,14 +59,12 @@ describe('IbcSendForm Component', () => {
expect(amountInput).toHaveValue('100');
});

// // TODO: Make this test pass
// test('send button is disabled when inputs are invalid', () => {
// renderWithProps();
// const sendButton = screen.getByLabelText('send-btn');
// expect(sendButton).toBeDisabled();
// });
test('send button is disabled when inputs are invalid', () => {
renderWithProps();
const sendButton = screen.getByLabelText('send-btn');
expect(sendButton).toBeDisabled();
});

// TODO: Fix inputs to be valid
test('send button is enabled when inputs are valid', () => {
renderWithProps();
fireEvent.change(screen.getByPlaceholderText('Recipient address'), {
Expand Down
13 changes: 5 additions & 8 deletions components/bank/forms/__tests__/sendForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ function renderWithProps(props = {}) {
return renderWithChainProvider(<SendForm {...defaultProps} {...props} />);
}

// TODO: Validate form inputs in component
describe('SendForm Component', () => {
afterEach(cleanup);

Expand Down Expand Up @@ -67,14 +66,12 @@ describe('SendForm Component', () => {
expect(amountInput).toHaveValue('100');
});

// TODO: Make this test pass
// test('send button is disabled when inputs are invalid', () => {
// renderWithProps();
// const sendButton = screen.getByText('Send');
// expect(sendButton).toBeDisabled();
// });
test('send button is disabled when inputs are invalid', () => {
renderWithProps();
const sendButton = screen.getByText('Send');
expect(sendButton).toBeDisabled();
});

// TODO: Fix inputs to be valid
test('send button is enabled when inputs are valid', () => {
renderWithProps();
fireEvent.change(screen.getByPlaceholderText('Recipient address'), {
Expand Down
1 change: 0 additions & 1 deletion components/factory/forms/CreateDenom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export default function CreateDenom({
const { estimateFee } = useFeeEstimation('manifest');

const validateSubdenom = (value: string) => {
console.log('Validating subdenom', value);
if (value.length === 0) {
return 'Subdenom is required';
}
Expand Down
4 changes: 3 additions & 1 deletion components/groups/forms/groups/GroupDetailsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ export default function GroupDetails({
validationSchema={GroupSchema}
onSubmit={nextStep}
validateOnChange={true}
validateOnMount={true}
enableReinitialize
>
{({ isValid, dirty, setFieldValue }) => (
{({ isValid, setFieldValue }) => (
<Form className="min-h-[330px]">
<div className="grid gap-5 my-6 sm:grid-cols-2">
<TextInput
Expand Down
47 changes: 25 additions & 22 deletions components/groups/forms/groups/GroupPolicyForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ const GroupPolicySchema = Yup.object().shape({
.min(1, 'Minimum voting threshold is 1'),
});

enum VotingUnit {
Hours = 'hours',
Days = 'days',
Weeks = 'weeks',
Months = 'months',
}

export default function GroupPolicyForm({
nextStep,
prevStep,
Expand All @@ -25,18 +32,22 @@ export default function GroupPolicyForm({
nextStep: () => void;
prevStep: () => void;
}>) {
const [votingUnit, setVotingUnit] = useState('days');
const updateField = (field: keyof FormData, value: any) => {
dispatch({ type: 'UPDATE_FIELD', field, value });
};

const [votingUnit, setVotingUnit] = useState(VotingUnit.Days);
const [votingAmount, setVotingAmount] = useState(1);

const convertToSeconds = (unit: string, amount: number): number => {
const convertToSeconds = (unit: VotingUnit, amount: number): number => {
switch (unit) {
case 'hours':
case VotingUnit.Hours:
return amount * 3600;
case 'days':
case VotingUnit.Days:
return amount * 86400;
case 'weeks':
case VotingUnit.Weeks:
return amount * 604800;
case 'months':
case VotingUnit.Months:
return amount * 2592000;
default:
return 0;
Expand All @@ -45,17 +56,13 @@ export default function GroupPolicyForm({

useEffect(() => {
const votingPeriodSeconds = convertToSeconds(votingUnit, votingAmount);
dispatch({
type: 'UPDATE_FIELD',
field: 'votingPeriod',
value: {
seconds: BigInt(votingPeriodSeconds),
nanos: 0,
},
updateField('votingPeriod', {
seconds: BigInt(votingPeriodSeconds),
nanos: 0,
});
}, [votingUnit, votingAmount, dispatch]);

const handleUnitChange = (unit: string) => {
const handleUnitChange = (unit: VotingUnit) => {
setVotingUnit(unit);
};

Expand Down Expand Up @@ -106,7 +113,7 @@ export default function GroupPolicyForm({
tabIndex={0}
className="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52 mt-1"
>
{['hours', 'days', 'weeks', 'months'].map(unit => (
{Object.values(VotingUnit).map(unit => (
<li key={unit}>
<a onClick={() => handleUnitChange(unit)}>
{unit.charAt(0).toUpperCase() + unit.slice(1)}
Expand All @@ -132,12 +139,8 @@ export default function GroupPolicyForm({
label=""
value={formData.votingThreshold}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
const value = Math.max(1, parseInt(e.target.value) || 1);
dispatch({
type: 'UPDATE_FIELD',
field: 'votingThreshold',
value: value.toString(),
});
const value = Math.max(1, parseInt(e.target.value));
updateField('votingThreshold', value.toString());
setFieldValue('votingThreshold', value);
}}
min={1}
Expand All @@ -148,7 +151,7 @@ export default function GroupPolicyForm({
<button
type="submit"
className="w-full btn btn-primary"
disabled={!isValid}
disabled={!isValid || !dirty}
onClick={() => {
nextStep();
}}
Expand Down
1 change: 0 additions & 1 deletion components/groups/forms/groups/MemberInfoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export default function MemberInfoForm({
address: string;
}>) {
const [numberOfMembers, setNumberOfMembers] = useState(formData.members.length);
console.log('formData', formData);
const updateMembers = () => {
const currentLength = formData.members.length;
if (numberOfMembers > currentLength) {
Expand Down
65 changes: 51 additions & 14 deletions components/groups/forms/groups/__tests__/GroupDetailsForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('GroupDetails Component', () => {
test('updates form fields correctly', async () => {
renderWithChainProvider(<GroupDetails {...mockProps} />);

const titleInput = screen.getByLabelText('Group Title') as HTMLInputElement;
const titleInput = screen.getByLabelText('Group Title');
fireEvent.change(titleInput, { target: { value: 'New Group Title' } });
await waitFor(() => {
expect(mockProps.dispatch).toHaveBeenCalledWith({
Expand All @@ -44,7 +44,7 @@ describe('GroupDetails Component', () => {
});
});

const authorsInput = screen.getByLabelText('Authors') as HTMLInputElement;
const authorsInput = screen.getByLabelText('Authors');
fireEvent.change(authorsInput, { target: { value: 'New Author' } });
await waitFor(() => {
expect(mockProps.dispatch).toHaveBeenCalledWith({
Expand All @@ -54,7 +54,7 @@ describe('GroupDetails Component', () => {
});
});

const summaryInput = screen.getByLabelText('Summary') as HTMLTextAreaElement;
const summaryInput = screen.getByLabelText('Summary');
fireEvent.change(summaryInput, { target: { value: 'New Summary' } });
await waitFor(() => {
expect(mockProps.dispatch).toHaveBeenCalledWith({
Expand All @@ -64,7 +64,7 @@ describe('GroupDetails Component', () => {
});
});

const descriptionInput = screen.getByLabelText('Description') as HTMLTextAreaElement;
const descriptionInput = screen.getByLabelText('Description');
fireEvent.change(descriptionInput, { target: { value: 'New Description' } });
await waitFor(() => {
expect(mockProps.dispatch).toHaveBeenCalledWith({
Expand All @@ -74,7 +74,7 @@ describe('GroupDetails Component', () => {
});
});

const forumLinkInput = screen.getByLabelText('Forum Link') as HTMLInputElement;
const forumLinkInput = screen.getByLabelText('Forum Link');
fireEvent.change(forumLinkInput, { target: { value: 'http://newforumlink.com' } });
await waitFor(() => {
expect(mockProps.dispatch).toHaveBeenCalledWith({
Expand All @@ -85,38 +85,75 @@ describe('GroupDetails Component', () => {
});
});

test('next button is enabled when form is not dirty but valid', async () => {
renderWithChainProvider(<GroupDetails {...mockProps} />);
expect(screen.getByText('Next: Group Policy')).toBeEnabled();
});

test('next button is disabled when form is dirty and invalid', async () => {
function updateField(field: string, validValue: string) {
const input = screen.getByLabelText(field);
fireEvent.change(input, { target: { value: validValue } });
}

const invalidProps = {
...mockProps,
formData: {
...mockGroupFormData,
title: '',
authors: '',
summary: '',
description: '',
forumLink: '',
members: [],
votingThreshold: '',
},
};

renderWithChainProvider(<GroupDetails {...invalidProps} />);
const nextButton = screen.getByText('Next: Group Policy');
await waitFor(() => expect(nextButton).toBeDisabled());

updateField('Group Title', 'New Group Title');
await waitFor(() => expect(nextButton).toBeDisabled());
updateField('Authors', 'New Author');
await waitFor(() => expect(nextButton).toBeDisabled());
updateField('Summary', 'New Summary');
await waitFor(() => expect(nextButton).toBeDisabled());
updateField('Description', 'New Long Description is Long Enough');
await waitFor(() => expect(nextButton).toBeEnabled());
});

test('next button is enabled when form is valid and dirty', async () => {
renderWithChainProvider(<GroupDetails {...mockProps} />);
const titleInput = screen.getByLabelText('Group Title') as HTMLInputElement;
const titleInput = screen.getByLabelText('Group Title');
fireEvent.change(titleInput, { target: { value: 'New Group Title' } });
await waitFor(() => {
const nextButton = screen.getByText('Next: Group Policy') as HTMLButtonElement;
expect(nextButton.disabled).toBe(false);
expect(screen.getByText('Next: Group Policy')).toBeEnabled();
});
});

test('calls nextStep when next button is clicked', async () => {
renderWithChainProvider(<GroupDetails {...mockProps} />);

const titleInput = screen.getByLabelText('Group Title') as HTMLInputElement;
const titleInput = screen.getByLabelText('Group Title');
fireEvent.change(titleInput, { target: { value: 'New Group Title' } });

const authorsInput = screen.getByLabelText('Authors') as HTMLInputElement;
const authorsInput = screen.getByLabelText('Authors');
fireEvent.change(authorsInput, { target: { value: 'New Author' } });

const summaryInput = screen.getByLabelText('Summary') as HTMLTextAreaElement;
const summaryInput = screen.getByLabelText('Summary');
fireEvent.change(summaryInput, {
target: { value: 'New summary that is at least 10 characters long' },
});

const descriptionInput = screen.getByLabelText('Description') as HTMLTextAreaElement;
const descriptionInput = screen.getByLabelText('Description');
fireEvent.change(descriptionInput, {
target: { value: 'New description that is at least 20 characters long' },
});

await waitFor(() => {
const nextButton = screen.getByText('Next: Group Policy') as HTMLButtonElement;
expect(nextButton.disabled).toBe(false);
expect(screen.getByText('Next: Group Policy')).toBeEnabled();
});

const nextButton = screen.getByText('Next: Group Policy');
Expand Down
31 changes: 29 additions & 2 deletions components/groups/forms/groups/__tests__/GroupPolicyForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,40 @@ describe('GroupPolicyForm Component', () => {
});
});

test('next button is disabled when form is not dirty', async () => {
renderWithChainProvider(<GroupPolicyForm {...mockProps} />);
const nextButton = screen.getByText('Next: Member Info');
expect(nextButton).toBeDisabled();
});

test('next button is disabled when form is invalid', async () => {
renderWithChainProvider(<GroupPolicyForm {...mockProps} />);
const nextButton = screen.getByText('Next: Member Info');
expect(nextButton).toBeDisabled();

const votingThresholdInput = screen.getByPlaceholderText('e.g. (1)');
fireEvent.change(votingThresholdInput, { target: { value: '' } });
await waitFor(() => {
expect(nextButton).toBeDisabled();
});

fireEvent.change(votingThresholdInput, { target: { value: '1' } });
await waitFor(() => {
expect(nextButton).toBeEnabled();
});

const votingAmountInput = screen.getByPlaceholderText('Enter duration');
// The value will be set to 1 if the input is less than 1
fireEvent.change(votingAmountInput, { target: { value: '0' } });
expect(votingAmountInput).toHaveValue(1);
});

test('next button is enabled when form is valid and dirty', async () => {
renderWithChainProvider(<GroupPolicyForm {...mockProps} />);
const votingThresholdInput = screen.getByPlaceholderText('e.g. (1)');
fireEvent.change(votingThresholdInput, { target: { value: '3' } });
await waitFor(() => {
const nextButton = screen.getByText('Next: Member Info');
expect(nextButton).toBeEnabled();
expect(screen.getByText('Next: Member Info')).toBeEnabled();
});
});

Expand Down
1 change: 0 additions & 1 deletion components/groups/forms/proposals/ProposalDetailsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default function ProposalDetails({
const updateField = (field: keyof ProposalFormData, value: any) => {
dispatch({ type: 'UPDATE_FIELD', field, value });
};
console.log(formData);
return (
<section className="">
<div className="lg:flex mx-auto">
Expand Down
2 changes: 0 additions & 2 deletions components/groups/forms/proposals/ProposalMessages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,6 @@ export default function ProposalMessages({
checkFormValidity();
};

console.log(formData);

const renderInputs = (
object: Record<string, any>,
handleChange: (field: string, value: any) => void,
Expand Down

0 comments on commit 19a8476

Please sign in to comment.