diff --git a/src/__internal__/fieldset/fieldset.spec.tsx b/src/__internal__/fieldset/fieldset.spec.tsx deleted file mode 100644 index 0141cf654f..0000000000 --- a/src/__internal__/fieldset/fieldset.spec.tsx +++ /dev/null @@ -1,225 +0,0 @@ -import React from "react"; -import { mount, ReactWrapper } from "enzyme"; -import Fieldset, { FieldsetProps } from "./fieldset.component"; - -import { - StyledFieldset, - StyledLegend, - StyledLegendContent, -} from "./fieldset.style"; -import { - assertStyleMatch, - testStyledSystemMargin, -} from "../../__spec_helper__/__internal__/test-utils"; - -import ValidationIcon from "../validations/validation-icon.component"; - -const Component = () =>
; -const RenderComponent = (props?: Partial) => ( -
- -
-); - -const render = (props?: Partial) => - mount(); - -const validationTypes = ["error", "warning", "info"] as const; - -describe("Fieldset", () => { - let wrapper: ReactWrapper; - - testStyledSystemMargin((props) => ); - - // added as `testStyledSystemMargin` will not catch if there is a regression and refactoring that will affect all tests that use it - it.each([ - [undefined, { margin: 0 }], - [{ m: 8 }, { margin: "var(--spacing800)" }], - [ - { mx: 8 }, - { marginLeft: "var(--spacing800)", marginRight: "var(--spacing800)" }, - ], - [ - { my: 8 }, - { marginTop: "var(--spacing800)", marginBottom: "var(--spacing800)" }, - ], - [ - { mt: 8, mr: 8, mb: 8, ml: 8 }, - { - marginTop: "var(--spacing800)", - marginBottom: "var(--spacing800)", - marginLeft: "var(--spacing800)", - marginRight: "var(--spacing800)", - }, - ], - ])( - "has the expected margin when %s passed as margin props", - (props, style) => { - wrapper = render({ legend: "Legend", ...props }); - expect(wrapper.getDOMNode()).toHaveStyle(style); - } - ); - - it("renders passed on children", () => { - wrapper = render(); - expect(wrapper.find(Component).exists()).toBe(true); - }); - - describe("when ml prop set", () => { - it("should apply the correct left margin", () => { - wrapper = render({ ml: "10%" }); - assertStyleMatch( - { - marginLeft: "10%", - }, - wrapper.find(StyledFieldset) - ); - }); - }); - - describe("when mb prop set", () => { - it("should apply the correct bottom margin", () => { - wrapper = render({ mb: 2 }); - assertStyleMatch( - { - marginBottom: "var(--spacing200)", - }, - wrapper.find(StyledFieldset) - ); - }); - }); - - describe("Fieldset Legend", () => { - it("is rendered if supplied", () => { - wrapper = render({ legend: "Legend" }); - expect(wrapper.find(StyledLegend).exists()).toEqual(true); - }); - - it("is not rendered if omitted", () => { - wrapper = render(); - expect(wrapper.find(StyledLegend).exists()).toEqual(false); - }); - - describe("when inline", () => { - it("applies the correct default styles", () => { - wrapper = render({ inline: true, legend: "Legend" }); - assertStyleMatch( - { - boxSizing: "border-box", - margin: "0", - justifyContent: "flex-end", - paddingRight: "var(--spacing200)", - }, - wrapper.find(StyledLegend) - ); - }); - - it("applies the correct width when legendWidth prop set", () => { - wrapper = render({ inline: true, legend: "Legend", legendWidth: 10 }); - assertStyleMatch( - { - width: "10%", - }, - wrapper.find(StyledLegend) - ); - }); - - it("aligns the content right when legendAlign prop set", () => { - wrapper = render({ - inline: true, - legend: "Legend", - legendAlign: "right", - }); - assertStyleMatch( - { - justifyContent: "flex-end", - }, - wrapper.find(StyledLegend) - ); - }); - - it("applies the correct right padding when legendSpacing prop set", () => { - wrapper = render({ inline: true, legend: "Legend", legendSpacing: 1 }); - assertStyleMatch( - { - paddingRight: "var(--spacing100)", - }, - wrapper.find(StyledLegend) - ); - }); - - describe('when legendAlign set to "left"', () => { - it("should apply the correct justifyContent style", () => { - wrapper = render({ - inline: true, - legend: "Legend", - legendAlign: "left", - }); - assertStyleMatch( - { - justifyContent: "flex-start", - }, - wrapper.find(StyledLegend) - ); - }); - }); - }); - }); - - describe.each(validationTypes)( - "when prop %s === string", - (validationType) => { - it("shows validation icon with proper type", () => { - wrapper = render({ legend: "Legend", [validationType]: "Message" }); - const icon = wrapper.find(ValidationIcon); - - expect(icon.props()[validationType]).toEqual("Message"); - }); - } - ); - - it("add an asterisk after the text when the field is mandatory", () => { - assertStyleMatch( - { - content: '"*"', - color: "var(--colorsSemanticNegative500)", - fontWeight: "var(--fontWeights700)", - marginLeft: "var(--spacing050)", - }, - mount(), - { modifier: "::after" } - ); - }); - - it("adds the required attribute to any child inputs when isRequired is true", () => { - wrapper = mount( -
- - -
- ); - - expect(wrapper.find("input").first().getDOMNode()).toHaveAttribute( - "required" - ); - expect(wrapper.find("input").last().getDOMNode()).toHaveAttribute( - "required" - ); - }); - - it("does not add the required attribute to any child inputs when isRequired is falsy", () => { - wrapper = mount( -
- - -
- ); - - expect(wrapper.find("input").first().getDOMNode()).not.toHaveAttribute( - "required" - ); - expect(wrapper.find("input").last().getDOMNode()).not.toHaveAttribute( - "required" - ); - }); -}); diff --git a/src/__internal__/fieldset/fieldset.test.tsx b/src/__internal__/fieldset/fieldset.test.tsx new file mode 100644 index 0000000000..9ae5c454f6 --- /dev/null +++ b/src/__internal__/fieldset/fieldset.test.tsx @@ -0,0 +1,123 @@ +import React from "react"; +import { render, screen, within } from "@testing-library/react"; +import Fieldset from "."; +import { testStyledSystemMargin } from "../../__spec_helper__/__internal__/test-utils"; + +test("renders with provided `children`", () => { + render( +
+ +
+ ); + + const input = within(screen.getByRole("group")).getByRole("textbox"); + + expect(input).toBeVisible(); +}); + +test("renders fieldset with provided `legend`", () => { + render( +
+ +
+ ); + + const fieldset = screen.getByRole("group", { name: "Legend" }); + + expect(fieldset).toBeVisible(); +}); + +test("sets child inputs as required when `isRequired` is true", () => { + render( +
+ + +
+ ); + + const inputs = screen.getAllByRole("textbox"); + + expect(inputs[0]).toBeRequired(); + expect(inputs[1]).toBeRequired(); +}); + +test("renders validation icon when `legend` and `error` are provided", () => { + render( +
+ +
+ ); + + const icon = screen.getByTestId("icon-error"); + + expect(icon).toBeVisible(); +}); + +test("renders validation icon when `legend` and `warning` are provided", () => { + render( +
+ +
+ ); + + const icon = screen.getByTestId("icon-warning"); + + expect(icon).toBeVisible(); +}); + +test("renders validation icon when `legend` and `info` are provided", () => { + render( +
+ +
+ ); + + const icon = screen.getByTestId("icon-info"); + + expect(icon).toBeVisible(); +}); + +// coverage +test("renders legend with provided `legendWidth` when `inline` is true", () => { + render( +
+ +
+ ); + + const legend = screen.getByTestId("legend"); + + expect(legend).toHaveStyle({ width: "30%" }); +}); + +// coverage +test("renders with expected styles when `inline` is true and `align` is 'left'", () => { + render( +
+ +
+ ); + + const legend = screen.getByTestId("legend"); + + expect(legend).toHaveStyle({ justifyContent: "flex-start" }); +}); + +// coverage +test("renders with expected padding when `inline` is true and `legendSpacing` is 1", () => { + render( +
+ +
+ ); + + const legend = screen.getByTestId("legend"); + + expect(legend).toHaveStyleRule("padding-right", "var(--spacing100)"); +}); + +testStyledSystemMargin((props) => ( +
+ +
+)); diff --git a/src/__internal__/form-field/form-field.component.tsx b/src/__internal__/form-field/form-field.component.tsx index 73395294f9..ec1ca13c48 100644 --- a/src/__internal__/form-field/form-field.component.tsx +++ b/src/__internal__/form-field/form-field.component.tsx @@ -182,7 +182,7 @@ const FormField = ({ return ( - + {reverse && children} {label && ( diff --git a/src/__internal__/form-field/form-field.spec.tsx b/src/__internal__/form-field/form-field.spec.tsx deleted file mode 100644 index e5a34d008b..0000000000 --- a/src/__internal__/form-field/form-field.spec.tsx +++ /dev/null @@ -1,283 +0,0 @@ -import React from "react"; -import { mount } from "enzyme"; -import FormField, { FormFieldProps } from "./form-field.component"; -import FieldHelp from "../field-help"; -import { FieldLineStyle } from "./form-field.style"; -import Label from "../label"; -import TabContext from "../../components/tabs/tab/__internal__/tab.context"; -import { - assertStyleMatch, - mockMatchMedia, -} from "../../__spec_helper__/__internal__/test-utils"; - -const setError = jest.fn(); -const setWarning = jest.fn(); -const setInfo = jest.fn(); - -function render(formFieldProps: FormFieldProps) { - return mount( - - - - ); -} - -function renderWithTabContext(formFieldProps: FormFieldProps) { - return mount( - - - - - - ); -} - -describe("FormField", () => { - it("with the mb prop set, correct bottom margin should be set", () => { - const wrapper = render({ id: "mock-input", mb: 5 }); - - assertStyleMatch( - { - marginBottom: "var(--spacing500)", - }, - wrapper.find(FormField), - { modifier: "&&&" } - ); - }); - - describe("with a label", () => { - it("renders label alongside children", () => { - const wrapper = render({ - id: "mock-input", - label: "Name", - labelAlign: "left", - labelWidth: 20, - }); - - expect(wrapper.find("label[data-element='label']").exists()).toBe(true); - expect(wrapper.find("input").exists()).toBe(true); - }); - - it.each([ - [false, "block"], - [true, "flex"], - ])( - "when labelInline prop is %s, make container of input and label a %s container", - (labelInline, display) => { - const wrapper = render({ - id: "mock-input", - label: "Name", - labelInline, - labelAlign: "left", - labelWidth: 20, - }); - - assertStyleMatch( - { - display, - }, - wrapper.find(FieldLineStyle) - ); - } - ); - - it("renders label with htmlFor prop that is the id of the input", () => { - const id = "foo"; - const wrapper = render({ - id, - label: "Name", - }); - expect(wrapper.find(`input[id='${id}']`).exists()).toBe(true); - expect(wrapper.find(`label[htmlFor='${id}']`).exists()).toBe(true); - }); - - it("passes the tooltipId to the Label id prop", () => { - const tooltipId = "test-help-id"; - expect( - render({ id: "mock-input", tooltipId, label: "test label" }) - .find(Label) - .prop("tooltipId") - ).toBe(tooltipId); - }); - - describe("when validationRedesignOptIn is true", () => { - it("does not set the validation props on the Label", () => { - const wrapper = render({ - id: "mock-input", - label: "test label", - error: true, - warning: true, - info: true, - validationRedesignOptIn: true, - }); - const { error, warning, info } = wrapper.find(Label).props(); - - expect(error).toEqual(false); - expect(warning).toEqual(false); - expect(info).toEqual(false); - }); - }); - - describe("when adaptiveLabelBreakpoint prop is set", () => { - describe("when screen bigger than breakpoint", () => { - beforeEach(() => { - mockMatchMedia(true); - }); - - it("should pass labelInline to its children", () => { - const wrapper = render({ - id: "mock-input", - label: "Name", - labelInline: true, - fieldHelp: "Help", - adaptiveLabelBreakpoint: 1000, - }); - - expect(wrapper.find(FieldLineStyle).props().inline).toEqual(true); - expect(wrapper.find(Label).props().inline).toEqual(true); - expect(wrapper.find(FieldHelp).props().labelInline).toEqual(true); - }); - }); - - describe("when screen smaller than breakpoint", () => { - beforeEach(() => { - mockMatchMedia(false); - }); - - it("should pass labelInline to its children", () => { - const wrapper = render({ - id: "mock-input", - label: "Name", - labelInline: true, - fieldHelp: "Help", - adaptiveLabelBreakpoint: 1000, - }); - - expect(wrapper.find(FieldLineStyle).props().inline).toEqual(false); - expect(wrapper.find(Label).props().inline).toEqual(false); - expect(wrapper.find(FieldHelp).props().labelInline).toEqual(false); - }); - }); - }); - }); - - describe("with fieldHelp", () => { - const fieldHelpId = "mock-id"; - const fieldHelp = "Help me!"; - - it("renders field help element with correct id", () => { - const wrapper = render({ - id: "mock-input", - fieldHelpId, - fieldHelp, - labelWidth: 20, - }); - expect(wrapper.find(`[id='${fieldHelpId}']`).exists()).toBe(true); - }); - - it("when fieldHelpInline and labelInline props are true, field help is rendered inline with input", () => { - const wrapper = render({ - id: "mock-input", - fieldHelpId, - fieldHelp, - labelWidth: 20, - fieldHelpInline: true, - labelInline: true, - }); - assertStyleMatch({ display: "flex" }, wrapper.find(FieldLineStyle)); - expect(wrapper.find(FieldLineStyle).find(FieldHelp).exists()).toBe(true); - }); - - it("when fieldHelpInline prop is false and labelInline is true, field help is not rendered inline with input", () => { - const wrapper = render({ - id: "mock-input", - fieldHelpId, - fieldHelp, - labelWidth: 20, - fieldHelpInline: false, - labelInline: true, - }); - assertStyleMatch({ display: "flex" }, wrapper.find(FieldLineStyle)); - expect(wrapper.find(FieldLineStyle).find(FieldHelp).exists()).toBe(false); - }); - }); - - describe("invariant", () => { - it("should throw when isOptional and isRequired props are both true", () => { - const consoleSpy = jest.spyOn(console, "error").mockImplementation(); - - expect(() => { - render({ - id: "mock-input", - isOptional: true, - isRequired: true, - }); - }).toThrow( - "an input cannot be set to both required and optional at the same time" - ); - - consoleSpy.mockRestore(); - }); - - it("should not throw when isRequired prop is true and isOptional is false", () => { - expect(() => { - render({ - id: "mock-input", - isRequired: true, - isOptional: false, - }); - }).not.toThrow(); - }); - - it("should not throw when isOptional prop is true and isRequired is false", () => { - expect(() => { - render({ - id: "mock-input", - isRequired: false, - isOptional: true, - }); - }).not.toThrow(); - }); - }); - - describe("with TabContext", () => { - it('calls "setError" when has "error" is true', () => { - renderWithTabContext({ id: "foo", error: true }); - expect(setError).toHaveBeenCalledWith("foo", true); - }); - - it('calls "setWarning" when has "warning" is true', () => { - renderWithTabContext({ id: "foo", warning: true }); - expect(setWarning).toHaveBeenCalledWith("foo", true); - }); - - it('calls "setInfo" when has "info" is true', () => { - renderWithTabContext({ id: "foo", info: true }); - expect(setInfo).toHaveBeenCalledWith("foo", true); - }); - }); - - it.each(["error", "warning", "info"])( - "validates the %s prop to throw an error if disabled is set as well", - (validation) => { - // Even though error is caught, it is still printed to console so mock console.error - // to avoid this. See https://github.com/facebook/jest/issues/5785 for details - const consoleSpy = jest.spyOn(console, "error"); - consoleSpy.mockImplementation(() => {}); - - const error = - `Prop \`${validation}\` cannot be used in conjunction with \`disabled\`. ` + - "Use `readOnly` if you require users to see validations with a non-interactive field"; - - expect(() => - renderWithTabContext({ - id: "mock-input", - disabled: true, - [validation]: true, - }) - ).toThrow(error); - - consoleSpy.mockRestore(); - } - ); -}); diff --git a/src/__internal__/form-field/form-field.test.tsx b/src/__internal__/form-field/form-field.test.tsx new file mode 100644 index 0000000000..fee5240554 --- /dev/null +++ b/src/__internal__/form-field/form-field.test.tsx @@ -0,0 +1,129 @@ +import React from "react"; +import { render, screen } from "@testing-library/react"; +import FormField from "."; +import TabContext from "../../components/tabs/tab/__internal__/tab.context"; +import { mockMatchMedia } from "../../__spec_helper__/__internal__/test-utils"; + +test("throws a console error when `isOptional` and `isRequired` are both true", () => { + const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {}); + + expect(() => { + render(); + }).toThrow( + "an input cannot be set to both required and optional at the same time" + ); + + consoleSpy.mockRestore(); +}); + +test("does not throw a console error when `isRequired` is true and `isOptional` is false", () => { + expect(() => { + render(); + }).not.toThrow(); +}); + +test("does not throw a console error when `isOptional` is true and `isRequired` is false", () => { + expect(() => { + render(); + }).not.toThrow(); +}); + +test("throws a console error when `error` and `disabled` are both true", () => { + const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {}); + + expect(() => { + render(); + }).toThrow( + `Prop \`error\` cannot be used in conjunction with \`disabled\`. ` + + "Use `readOnly` if you require users to see validations with a non-interactive field" + ); + + consoleSpy.mockRestore(); +}); + +test("throws a console error when `warning` and `disabled` are both true", () => { + const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {}); + + expect(() => { + render(); + }).toThrow( + `Prop \`warning\` cannot be used in conjunction with \`disabled\`. ` + + "Use `readOnly` if you require users to see validations with a non-interactive field" + ); + + consoleSpy.mockRestore(); +}); + +test("throws a console error when `info` and `disabled` are both true", () => { + const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {}); + + expect(() => { + render(); + }).toThrow( + `Prop \`info\` cannot be used in conjunction with \`disabled\`. ` + + "Use `readOnly` if you require users to see validations with a non-interactive field" + ); + + consoleSpy.mockRestore(); +}); + +test("calls `setError` passed from `TabContext` when `error` is true", () => { + const setError = jest.fn(); + render( + + + + ); + + expect(setError).toHaveBeenCalledWith("foo", true); +}); + +test("calls `setWarning` passed from `TabContext` when `warning` is true", () => { + const setWarning = jest.fn(); + render( + + + + ); + + expect(setWarning).toHaveBeenCalledWith("foo", true); +}); + +test("calls `setInfo` passed from `TabContext` when `info` is true", () => { + const setInfo = jest.fn(); + render( + + + + ); + + expect(setInfo).toHaveBeenCalledWith("foo", true); +}); + +test("should not render with `labelInline` when `adaptiveLabelBreakpoint` set and screen is smaller than the breakpoint", () => { + mockMatchMedia(false); + render( + + ); + + expect(screen.getByTestId("field-line")).toHaveStyle("display: block"); +}); + +test("should render with `labelInline` when `adaptiveLabelBreakpoint` set and screen is bigger than the breakpoint", () => { + mockMatchMedia(true); + render( + + ); + + expect(screen.getByTestId("field-line")).toHaveStyle("display: flex"); +}); diff --git a/src/__internal__/label/label.test.tsx b/src/__internal__/label/label.test.tsx index 704e3198fa..2b6360d47e 100644 --- a/src/__internal__/label/label.test.tsx +++ b/src/__internal__/label/label.test.tsx @@ -155,3 +155,16 @@ test.each(["error", "warning", "info"])( ); } ); + +// coverage +test("renders with expected styles when `inline` is true and `align` is 'left'", () => { + render( + + ); + + expect(screen.getByTestId("label-container")).toHaveStyle({ + justifyContent: "flex-start", + }); +});