UNPKG

@octopusdeploy/design-system-components

Version:
228 lines (227 loc) • 12.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const testing_library_1 = require("@octopusdeploy/testing-library"); const react_1 = require("@testing-library/react"); const vitest_1 = require("vitest"); const Timespan_1 = require("../Timespan"); (0, vitest_1.describe)("<Timespan />", () => { (0, vitest_1.test)("renders the label as a group", () => { const field = renderTimespan({ label: "Cache duration" }); field.shouldHaveGroupLabel("Cache duration"); }); (0, vitest_1.test)("renders day, hour and minute segments by default", () => { const field = renderTimespan({ label: "Cache duration" }); field.shouldHaveSegments(["Days", "Hours", "Minutes"]); field.shouldHaveSuffixes(["days", "hrs", "min"]); }); (0, vitest_1.test)("renders hour, minute and second segments", () => { const field = renderTimespan({ label: "Timeout", units: "hour-minute-second" }); field.shouldHaveSegments(["Hours", "Minutes", "Seconds"]); field.shouldNotHaveSegment("Days"); }); (0, vitest_1.test)("renders minute and second segments", () => { const field = renderTimespan({ label: "Interval", units: "minute-second" }); field.shouldHaveSegments(["Minutes", "Seconds"]); field.shouldNotHaveSegment("Days"); field.shouldNotHaveSegment("Hours"); }); (0, vitest_1.test)("reflects the value in each segment", () => { const field = renderTimespan({ label: "Cache duration", value: { days: 1, hours: 2, minutes: 3 } }); field.shouldHaveSegmentValue("Days", 1); field.shouldHaveSegmentValue("Hours", 2); field.shouldHaveSegmentValue("Minutes", 3); }); (0, vitest_1.test)("calls onChange with the updated segment, preserving the others", async () => { // Hours starts empty so the controlled value doesn't fight the typed keystroke (the prop value // is never fed back through the mocked onChange in a test). const field = renderTimespan({ label: "Cache duration", value: { days: 1, minutes: 3 } }); await field.typeIntoSegment("Hours", 5); field.shouldHaveCalledOnChangeWith({ days: 1, hours: 5, minutes: 3 }); }); (0, vitest_1.test)("calls onChange with undefined for a cleared segment", async () => { const field = renderTimespan({ label: "Cache duration", value: { days: 1, hours: 2, minutes: 3 } }); await field.clearSegment("Hours"); field.shouldHaveCalledOnChangeWith({ days: 1, hours: undefined, minutes: 3 }); }); (0, vitest_1.test)("day-hour-minute caps hours and minutes but leaves the leading days segment unbounded", () => { const field = renderTimespan({ label: "Cache duration" }); field.shouldHaveSegmentMin("Days", 0); field.shouldNotHaveSegmentMax("Days"); field.shouldHaveSegmentMax("Hours", 23); field.shouldHaveSegmentMax("Minutes", 59); }); (0, vitest_1.test)("hour-minute-second caps minutes and seconds but leaves the leading hours segment unbounded", () => { const field = renderTimespan({ label: "Timeout", units: "hour-minute-second" }); field.shouldHaveSegmentMin("Hours", 0); field.shouldNotHaveSegmentMax("Hours"); field.shouldHaveSegmentMax("Minutes", 59); field.shouldHaveSegmentMax("Seconds", 59); }); (0, vitest_1.test)("minute-second caps seconds but leaves the leading minutes segment unbounded", () => { const field = renderTimespan({ label: "Interval", units: "minute-second" }); field.shouldHaveSegmentMin("Minutes", 0); field.shouldNotHaveSegmentMax("Minutes"); field.shouldHaveSegmentMax("Seconds", 59); }); (0, vitest_1.describe)("only accepts whole, non-negative numbers", () => { vitest_1.test.each(["-", "+", "e", "E", ".", ","])("blocks the '%s' character in a segment", (key) => { const field = renderTimespan({ label: "Cache duration" }); field.shouldBlockKeyInSegment("Days", key); }); vitest_1.test.each(["0", "5", "9", "Backspace", "ArrowUp", "ArrowDown"])("allows the '%s' key in a segment", (key) => { const field = renderTimespan({ label: "Cache duration" }); field.shouldAllowKeyInSegment("Days", key); }); (0, vitest_1.test)("clamps a negative value to zero", () => { const field = renderTimespan({ label: "Cache duration" }); field.setSegmentRawValue("Days", "-5"); field.shouldHaveCalledOnChangeWith({ days: 0 }); }); (0, vitest_1.test)("truncates a fractional value to a whole number", () => { const field = renderTimespan({ label: "Cache duration" }); field.setSegmentRawValue("Days", "1.9"); field.shouldHaveCalledOnChangeWith({ days: 1 }); }); }); (0, vitest_1.describe)("clamps trailing segments to their max but leaves the leading segment unbounded", () => { (0, vitest_1.test)("clamps an over-max trailing hours value down to its max", () => { const field = renderTimespan({ label: "Cache duration" }); field.setSegmentRawValue("Hours", "30"); field.shouldHaveCalledOnChangeWith({ hours: 23 }); }); (0, vitest_1.test)("clamps an over-max trailing minutes value down to its max", () => { const field = renderTimespan({ label: "Timeout", units: "hour-minute-second" }); field.setSegmentRawValue("Minutes", "90"); field.shouldHaveCalledOnChangeWith({ minutes: 59 }); }); (0, vitest_1.test)("leaves an over-max leading hours value unclamped", () => { const field = renderTimespan({ label: "Timeout", units: "hour-minute-second" }); field.setSegmentRawValue("Hours", "50"); field.shouldHaveCalledOnChangeWith({ hours: 50 }); }); (0, vitest_1.test)("leaves an over-max leading minutes value unclamped", () => { const field = renderTimespan({ label: "Interval", units: "minute-second" }); field.setSegmentRawValue("Minutes", "90"); field.shouldHaveCalledOnChangeWith({ minutes: 90 }); }); }); (0, vitest_1.test)("renders the description", () => { const description = "How long to keep cached entries."; const field = renderTimespan({ label: "Cache duration", description }); field.shouldHaveDescription(description); }); (0, vitest_1.test)("renders the validation message without flagging individual segments", () => { const validationMessage = "Enter a duration greater than zero"; const field = renderTimespan({ label: "Cache duration", validationMessage }); field.shouldHaveError(validationMessage); field.shouldHaveAriaInvalid("Hours", false); }); (0, vitest_1.test)("disables all segments when disabled", () => { const field = renderTimespan({ label: "Cache duration", disabled: true }); field.shouldHaveDisabledSegment("Days"); field.shouldHaveDisabledSegment("Hours"); field.shouldHaveDisabledSegment("Minutes"); }); (0, vitest_1.test)("marks segments read only", () => { const field = renderTimespan({ label: "Cache duration", readOnly: true }); field.shouldHaveReadOnlySegment("Hours"); }); (0, vitest_1.test)("autofocuses the first segment", () => { const field = renderTimespan({ label: "Cache duration", autoFocus: true }); field.shouldHaveFocusedSegment("Days"); }); (0, vitest_1.test)("derives segment name attributes from the name prop", () => { const field = renderTimespan({ label: "Cache duration", name: "cache" }); field.shouldHaveSegmentName("Days", "cache-days"); field.shouldHaveSegmentName("Hours", "cache-hours"); field.shouldHaveSegmentName("Minutes", "cache-minutes"); }); (0, vitest_1.test)("renders the required marker", () => { const field = renderTimespan({ label: "Cache duration", hasRequiredMarker: true }); field.shouldHaveRequiredMarker(); }); (0, vitest_1.test)("renders the optional marker", () => { const field = renderTimespan({ label: "Cache duration", hasOptionalMarker: true }); field.shouldHaveOptionalMarker(); }); }); function renderTimespan(options) { const onChange = vitest_1.vi.fn(); const value = options.value ?? {}; (0, react_1.render)((0, jsx_runtime_1.jsx)(Timespan_1.Timespan, { ...options, value: value, onChange: onChange })); return getTimespanInteractions(onChange); } function getTimespanInteractions(onChange) { // domQueries has no query for a `role="group"` nor a raw-attribute matcher, so the group legend // and attribute-level checks (min/max/readonly/aria-invalid) fall back to `screen` as a last resort. const segmentElement = (label) => react_1.screen.getByLabelText(label); return { shouldHaveGroupLabel: (label) => { (0, vitest_1.expect)(react_1.screen.getByRole("group", { name: new RegExp(label) })).toBeInTheDocument(); }, shouldHaveSegments: (labels) => { labels.forEach((label) => testing_library_1.domQueries.getNumberInput(label).assertIsInTheDocument()); }, shouldNotHaveSegment: (label) => { testing_library_1.domQueries.queryNumberInput(label).assertIsNotInTheDocument(); }, shouldHaveSuffixes: (suffixes) => { suffixes.forEach((suffix) => testing_library_1.domQueries.getText(suffix).assertIsInTheDocument()); }, shouldHaveSegmentValue: (label, value) => { testing_library_1.domQueries.getNumberInput(label).assertHasValue(value); }, shouldHaveSegmentMin: (label, min) => { (0, vitest_1.expect)(segmentElement(label)).toHaveAttribute("min", min.toString()); }, shouldHaveSegmentMax: (label, max) => { (0, vitest_1.expect)(segmentElement(label)).toHaveAttribute("max", max.toString()); }, shouldNotHaveSegmentMax: (label) => { (0, vitest_1.expect)(segmentElement(label)).not.toHaveAttribute("max"); }, shouldHaveSegmentName: (label, name) => { (0, vitest_1.expect)(segmentElement(label)).toHaveAttribute("name", name); }, shouldHaveDescription: (description) => { testing_library_1.domQueries.getText(description).assertIsInTheDocument(); }, shouldHaveError: (message) => { testing_library_1.domQueries.getText(message).assertIsInTheDocument(); }, shouldHaveAriaInvalid: (label, invalid) => { (0, vitest_1.expect)(segmentElement(label)).toHaveAttribute("aria-invalid", invalid.toString()); }, shouldHaveDisabledSegment: (label) => { testing_library_1.domQueries.getNumberInput(label).assertIsDisabled(); }, shouldHaveReadOnlySegment: (label) => { (0, vitest_1.expect)(segmentElement(label)).toHaveAttribute("readonly"); }, shouldHaveFocusedSegment: (label) => { testing_library_1.domQueries.getNumberInput(label).assertHasFocus(); }, shouldHaveRequiredMarker: () => { testing_library_1.domQueries.getText("(required)").assertIsInTheDocument(); }, shouldHaveOptionalMarker: () => { testing_library_1.domQueries.getText("(optional)").assertIsInTheDocument(); }, shouldHaveCalledOnChangeWith: (value) => { (0, vitest_1.expect)(onChange).toHaveBeenLastCalledWith(value); }, shouldBlockKeyInSegment: (label, key) => { // fireEvent returns false when a handler called preventDefault on the event. (0, vitest_1.expect)(react_1.fireEvent.keyDown(segmentElement(label), { key })).toBe(false); }, shouldAllowKeyInSegment: (label, key) => { (0, vitest_1.expect)(react_1.fireEvent.keyDown(segmentElement(label), { key })).toBe(true); }, setSegmentRawValue: (label, rawValue) => { react_1.fireEvent.change(segmentElement(label), { target: { value: rawValue } }); }, typeIntoSegment: (label, value) => testing_library_1.domQueries.getNumberInput(label).replaceNumber(value), clearSegment: (label) => testing_library_1.domQueries.getNumberInput(label).clear(), }; }