-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
175 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { ObjectConfig, ObjectState, createObjectState, required } from "@homebound/form-state"; | ||
import { BoundIconCardField } from "./BoundIconCardField"; | ||
import { click, render } from "src/utils/rtl"; | ||
import { AuthorInput } from "./formStateDomain"; | ||
|
||
const formConfig: ObjectConfig<AuthorInput> = { | ||
isAvailable: { type: "value", rules: [required] }, | ||
}; | ||
|
||
const formConfigReadOnly: ObjectConfig<AuthorInput> = { | ||
isAvailable: { type: "value", rules: [required], readOnly: true }, | ||
}; | ||
|
||
describe("BoundIconCardField", () => { | ||
it("should be selected", async () => { | ||
// Given a formState with true boolean field | ||
const formState = createObjectState(formConfig, { isAvailable: true }); | ||
// When rendered | ||
const r = await render(<BoundIconCardField icon="check" field={formState.isAvailable} />); | ||
// Then the BoundCheckboxField should be checked | ||
expect(r.isAvailable_value).toBeChecked(); | ||
}); | ||
|
||
it("should uncheck when clicked", async () => { | ||
// Given a rendered checked BoundCheckboxField | ||
const formState = createObjectState(formConfig, { isAvailable: true }); | ||
const r = await render(<BoundIconCardField icon="check" field={formState.isAvailable} />); | ||
// When interacting with a BoundCheckboxField | ||
click(r.isAvailable); | ||
// Then expect the checkbox to be unchecked and the formState to reflect that state | ||
expect(r.isAvailable).not.toBeChecked(); | ||
expect(formState.isAvailable.value).toBeFalsy(); | ||
}); | ||
|
||
it("triggers 'maybeAutoSave' on change", async () => { | ||
const autoSave = jest.fn(); | ||
// Given a BoundCheckboxField with auto save | ||
const formState: ObjectState<AuthorInput> = createObjectState( | ||
formConfig, | ||
{ isAvailable: true }, | ||
{ maybeAutoSave: () => autoSave(formState.isAvailable.value) }, | ||
); | ||
const r = await render(<BoundIconCardField icon="check" field={formState.isAvailable} />); | ||
|
||
// When toggling the checkbox off | ||
click(r.isAvailable); | ||
// Then the callback should be triggered with the current value | ||
expect(autoSave).toBeCalledWith(false); | ||
}); | ||
it("disables when field is readonly", async () => { | ||
// Given a readOnly BoundCheckboxField | ||
const formState: ObjectState<AuthorInput> = createObjectState(formConfigReadOnly, { isAvailable: true }); | ||
const r = await render(<BoundIconCardField icon="check" field={formState.isAvailable} />); | ||
|
||
// Then the checkbox should be disabled | ||
expect(r.isAvailable).toBeDisabled(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { FieldState } from "@homebound/form-state"; | ||
import { IconCard, IconCardProps } from "src/inputs"; | ||
import { defaultLabel } from "src/utils/defaultLabel"; | ||
import { useTestIds } from "src/utils"; | ||
import { Observer } from "mobx-react"; | ||
import { IconProps } from "src/components"; | ||
|
||
export type BoundIconCardFieldProps = Omit<IconCardProps, "label" | "selected" | "onChange"> & { | ||
field: FieldState<boolean | null | undefined>; | ||
icon: IconProps["icon"]; | ||
/** Make optional so that callers can override if they want to. */ | ||
onChange?: (values: boolean) => void; | ||
label?: string; | ||
}; | ||
|
||
/** Wraps `IconCard` and binds it to a form field. */ | ||
export function BoundIconCardField(props: BoundIconCardFieldProps) { | ||
const { icon, field, onChange = (value) => field.set(value), label = defaultLabel(field.key), ...others } = props; | ||
const testId = useTestIds(props, field.key); | ||
return ( | ||
<Observer> | ||
{() => ( | ||
<IconCard | ||
icon={icon} | ||
label={label} | ||
selected={field.value ?? false} | ||
onChange={(selected) => { | ||
// We are triggering blur manually for checkbox fields due to its transactional nature | ||
onChange(selected); | ||
field.maybeAutoSave(); | ||
}} | ||
disabled={field.readOnly} | ||
{...testId} | ||
{...others} | ||
/> | ||
)} | ||
</Observer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { IconCardGroupItemOption } from "src/inputs/IconCardGroup"; | ||
import { AuthorInput } from "./formStateDomain"; | ||
import { ObjectConfig, ObjectState, createObjectState, required } from "@homebound/form-state"; | ||
import { BoundIconCardGroupField } from "./BoundIconCardGroupField"; | ||
import { click, render } from "src/utils/rtl"; | ||
|
||
const categories: IconCardGroupItemOption[] = [ | ||
{ icon: "abacus", label: "Math", value: "math" }, | ||
{ icon: "archive", label: "History", value: "history" }, | ||
{ icon: "dollar", label: "Finance", value: "finance" }, | ||
{ icon: "hardHat", label: "Engineering", value: "engineering" }, | ||
{ icon: "kanban", label: "Management", value: "management" }, | ||
{ icon: "camera", label: "Media", value: "media" }, | ||
]; | ||
|
||
describe("BoundIconCardGroupField", () => { | ||
it("shows the label", async () => { | ||
const author = createObjectState(formConfig, { favoriteGenres: ["math"] }); | ||
const r = await render(<BoundIconCardGroupField field={author.favoriteGenres} options={categories} />); | ||
expect(r.favoriteGenres_label).toHaveTextContent("Favorite Genres"); | ||
}); | ||
it("triggers 'maybeAutoSave' on change", async () => { | ||
const autoSave = jest.fn(); | ||
// Given a BoundIconCardGroupField with auto save | ||
const author: ObjectState<AuthorInput> = createObjectState( | ||
formConfig, | ||
{}, | ||
{ maybeAutoSave: () => autoSave(author.favoriteGenres.value) }, | ||
); | ||
const r = await render(<BoundIconCardGroupField field={author.favoriteGenres} options={categories} />); | ||
|
||
// When toggling the checkbox off | ||
click(r.favoriteGenres_math); | ||
// Then the callback should be triggered with the current value | ||
expect(autoSave).toBeCalledWith(["math"]); | ||
}); | ||
}); | ||
|
||
const formConfig: ObjectConfig<AuthorInput> = { | ||
favoriteGenres: { type: "value", rules: [required], strictOrder: false }, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { FieldState } from "@homebound/form-state"; | ||
import { Observer } from "mobx-react"; | ||
import { IconCardGroup, IconCardGroupProps } from "src/inputs/IconCardGroup"; | ||
import { useTestIds } from "src/utils"; | ||
import { defaultLabel } from "src/utils/defaultLabel"; | ||
|
||
export type BoundIconCardGroupFieldProps = Omit<IconCardGroupProps, "label" | "values" | "onChange"> & { | ||
field: FieldState<string[] | null | undefined>; | ||
/** Make optional so that callers can override if they want to. */ | ||
onChange?: (values: string[]) => void; | ||
label?: string; | ||
}; | ||
|
||
/** Wraps `IconCardGroup` and binds it to a form field. */ | ||
export function BoundIconCardGroupField(props: BoundIconCardGroupFieldProps) { | ||
const { field, onChange = (value) => field.set(value), label = defaultLabel(field.key), ...others } = props; | ||
const testId = useTestIds(props, field.key); | ||
return ( | ||
<Observer> | ||
{() => ( | ||
<IconCardGroup | ||
label={label} | ||
values={field.value || []} | ||
onChange={(values) => { | ||
// We are triggering blur manually for checkbox fields due to its transactional nature | ||
onChange(values); | ||
field.maybeAutoSave(); | ||
}} | ||
disabled={field.readOnly} | ||
{...testId} | ||
{...others} | ||
/> | ||
)} | ||
</Observer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters