Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
input example + aria label

types and refactor

prettier

self review + cs

update tooltip css

typedocs + change label prop to marks

Slider Cypress / QA Tests (#3353)

[WIP] Slider range (#3451)

validation example

update cs

prettier + qa tests

prevent default

update mouse to pointer

fix types

type error

explaination for type issue

range slider cypress tests

prettier

typo

update thumb tooltip behaviour
  • Loading branch information
lukeac123 authored and tomhazledine committed Jul 23, 2024
1 parent 3c635db commit a7fb1d1
Show file tree
Hide file tree
Showing 23 changed files with 978 additions and 1,106 deletions.
6 changes: 6 additions & 0 deletions .changeset/spotty-pants-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@salt-ds/lab": minor
---

Remove `Slider` props, `pageStep`, `pushable`, `pushDistance`, `disabled`, `hideMarks`
Updated `Marks` prop to recieve inline, bottom or all
2 changes: 0 additions & 2 deletions docs/components/ResponsiveContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export const ResponsiveContainer = ({ children }: { children?: ReactNode }) => {
<Slider
className="StoryContainer-slider"
id="width"
label="Container Width"
max={maxUnits}
min={10}
onChange={(nextValue) => setWidth(nextValue as number)}
Expand All @@ -51,7 +50,6 @@ export const ResponsiveContainer = ({ children }: { children?: ReactNode }) => {
<Slider
className="StoryContainer-slider"
id="height"
label="Container Height"
max={maxUnits}
min={10}
onChange={(nextValue) => setHeight(nextValue as number)}
Expand Down
359 changes: 163 additions & 196 deletions packages/lab/src/__tests__/__e2e__/slider/Slider.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,202 +1,169 @@
import { Slider } from "@salt-ds/lab";

describe("Given a Slider with a single value", () => {
it("THEN it should have ARIA roles and attributes", () => {
cy.mount(
<Slider
label={"TestLabel"}
min={5}
max={125}
step={5}
pageStep={25}
defaultValue={100}
/>,
);
cy.findByRole("slider")
.should("have.attr", "aria-valuemin", "5")
.and("have.attr", "aria-valuemax", "125")
.and("have.attr", "aria-disabled", "false");
describe("Given a Slider", () => {
describe("Given a Slider with a single value", () => {
it("THEN it should have ARIA roles and attributes", () => {
cy.mount(
<Slider
style={{ width: "400px" }}
min={5}
max={125}
step={5}
defaultValue={100}
/>
);
cy.findByRole("slider")
.should("have.attr", "aria-valuemin", "5")
.and("have.attr", "aria-valuemax", "125")
.and("have.attr", "aria-valuenow", "100");
});

it("THEN onChange should fire on pointer down on slider track", () => {
const changeSpy = cy.stub().as("changeSpy");
cy.mount(<Slider style={{ width: "400px" }} onChange={changeSpy} />);
cy.get(".saltSliderTrack").trigger("pointerdown", {
clientX: 50,
clientY: 50,
});
cy.get("@changeSpy").should("have.callCount", 1);
});

it("THEN keyboard navigation can be used to change the slider position", () => {
const changeSpy = cy.stub().as("changeSpy");
cy.mount(
<Slider
style={{ width: "400px" }}
min={5}
max={125}
step={5}
defaultValue={100}
onChange={changeSpy}
/>
);
cy.findByRole("slider").focus().realPress("ArrowRight");
cy.findByRole("slider").should("have.attr", "aria-valuenow", "105");
cy.get("@changeSpy").should("have.callCount", 1);

cy.findByRole("slider").realPress("ArrowLeft");
cy.findByRole("slider").should("have.attr", "aria-valuenow", "100");
cy.get("@changeSpy").should("have.callCount", 2);

cy.findByRole("slider").realPress("End");
cy.findByRole("slider").should("have.attr", "aria-valuenow", "125");
cy.get("@changeSpy").should("have.callCount", 3);

cy.findByRole("slider").realPress("Home");
cy.findByRole("slider").should("have.attr", "aria-valuenow", "5");
cy.get("@changeSpy").should("have.callCount", 4);
});

it("THEN it should display a tooltip on pointerover", () => {
cy.mount(<Slider style={{ width: "400px" }} />);
cy.get(".saltSliderThumb-container").trigger("pointerover");
cy.get(".saltSliderThumb-tooltip").should("be.visible");

cy.get(".saltSliderThumb-container").trigger("pointerout");
cy.get(".saltSliderThumb-tooltip").should("not.be.visible");
});
});

it("THEN it should respond to keyboard", () => {
const changeSpy = cy.stub().as("changeSpy");
cy.mount(
<Slider
label={"TestLabel"}
min={5}
max={125}
step={5}
pageStep={25}
defaultValue={100}
onChange={changeSpy}
/>,
);

cy.findByRole("slider").focus();
cy.realPress("ArrowLeft");
cy.get("@changeSpy")
.should("have.been.calledOnce")
.and("be.calledWith", 95);
cy.findByRole("slider").should("have.attr", "aria-valuenow", "95");

// Page Up/Down buttons should move the value one "pageStep" up/down
cy.findByRole("slider").realPress("PageDown");
cy.get("@changeSpy")
.should("have.been.calledTwice")
.and("be.calledWith", 70);

// End key should move the value to max
cy.findByRole("slider").realPress("End");
cy.get("@changeSpy")
.should("have.been.calledThrice")
.and("be.calledWith", 125);

// Home key should move the value to min
cy.findByRole("slider").realPress("Home");
cy.get("@changeSpy").should("have.callCount", 4).and("be.calledWith", 5);
});
});

describe("Given a Slider with a range value", () => {
it("THEN it should have ARIA roles and attributes", () => {
cy.mount(
<Slider
label={"TestLabel"}
min={-100}
max={100}
step={10}
defaultValue={[20, 40]}
/>,
);

cy.findByRole("group").should(
"have.attr",
"aria-label",
"TestLabel slider from -100 to 100",
);

cy.findAllByRole("slider").should("have.length", 2);

cy.findAllByRole("slider")
.eq(0)
.should("have.attr", "aria-label", "Min")
.and("have.attr", "aria-valuenow", "20");

cy.findAllByRole("slider")
.eq(1)
.should("have.attr", "aria-label", "Max")
.and("have.attr", "aria-valuenow", "40");
});
});

describe("Given a Slider with more than 2 items in the value", () => {
it("THEN it should have ARIA roles and attributes", () => {
cy.mount(
<Slider
label={"TestLabel"}
min={-10}
max={110}
step={1}
defaultValue={[20, 40, 100]}
/>,
);

cy.findByRole("group").should(
"have.attr",
"aria-label",
"TestLabel slider from -10 to 110",
);

cy.findAllByRole("slider").should("have.length", 3);

cy.findAllByRole("slider")
.eq(0)
.should("have.attr", "aria-label", "First")
.and("have.attr", "aria-valuenow", "20");

cy.findAllByRole("slider")
.eq(1)
.should("have.attr", "aria-label", "Second")
.and("have.attr", "aria-valuenow", "40");

cy.findAllByRole("slider")
.eq(2)
.should("have.attr", "aria-label", "Third")
.and("have.attr", "aria-valuenow", "100");
});
});

describe("Given a pushable range slider", () => {
it("WHEN moving a handle, it should push other handles", () => {
const changeSpy = cy.stub().as("changeSpy");

cy.mount(
<Slider
label={"TestLabel"}
min={-8}
max={8}
step={1}
defaultValue={[-1, 3, 7]}
pushable
pushDistance={3}
onChange={changeSpy}
/>,
);

cy.findAllByRole("slider").should("have.length", 3);

cy.findAllByRole("slider").eq(0).focus();
cy.realPress("ArrowRight");
cy.get("@changeSpy").should("have.been.calledWith", [0, 3, 7]);

cy.realPress("ArrowRight");
cy.get("@changeSpy").should("have.been.calledWith", [1, 4, 7]);

cy.realPress("ArrowRight");
cy.get("@changeSpy").should("have.been.calledWith", [2, 5, 8]);

// Should not push beyond max
cy.realPress("ArrowRight");
cy.get("@changeSpy").should("have.callCount", 3);
cy.findAllByRole("slider").eq(0).should("have.attr", "aria-valuenow", "2");
cy.findAllByRole("slider").eq(1).should("have.attr", "aria-valuenow", "5");
cy.findAllByRole("slider").eq(2).should("have.attr", "aria-valuenow", "8");
});
});

describe("Given a non-pushable range slider", () => {
it("WHEN moving a handle, it should be constrained by the handles next to it", () => {
const changeSpy = cy.stub().as("changeSpy");
cy.mount(
<Slider
label={"TestLabel"}
min={-8}
max={8}
step={1}
pageStep={4}
defaultValue={[-1, 3, 7]}
onChange={changeSpy}
/>,
);

cy.findAllByRole("slider").should("have.length", 3);

cy.findAllByRole("slider").eq(0).focus();
cy.realPress("PageUp");
cy.realPress("ArrowUp");
cy.realPress("ArrowRight");
cy.realPress("End");
cy.get("@changeSpy")
.should("have.been.calledOnce")
.and("been.calledWith", [3, 3, 7]);

cy.findAllByRole("slider").eq(2).focus();
cy.realPress("Home");
cy.realPress("PageDown");
cy.realPress("ArrowLeft");
cy.realPress("ArrowDown");
cy.get("@changeSpy")
.should("have.been.calledTwice")
.and("been.calledWith", [3, 3, 3]);
describe("Given a Slider with a range value", () => {
it("THEN it should have ARIA roles and attributes", () => {
cy.mount(
<Slider
style={{ width: "400px" }}
min={-100}
max={100}
step={10}
defaultValue={[20, 40]}
/>
);

cy.findAllByRole("slider").should("have.length", 2);

cy.findAllByRole("slider")
.eq(0)
.should("have.attr", "aria-valuenow", "20");

cy.findAllByRole("slider")
.eq(1)
.should("have.attr", "aria-valuenow", "40");
});

it("THEN the nearest slider thumb should move on pointer down track", () => {
const changeSpy = cy.stub().as("changeSpy");
cy.mount(
<Slider
style={{ width: "400px" }}
min={0}
max={10}
step={1}
defaultValue={[2, 8]}
onChange={changeSpy}
/>
);

cy.get(".saltSliderTrack").trigger("pointerdown", {
clientX: 0,
clientY: 0,
});
cy.get("@changeSpy").should("have.callCount", 1);
cy.findAllByRole("slider")
.eq(0)
.should("have.attr", "aria-valuenow", "0");
cy.findAllByRole("slider")
.eq(1)
.should("have.attr", "aria-valuenow", "8");
});

it("THEN slider thumbs should not cross and maintain a gap of 1 step when using keyboard nav", () => {
const changeSpy = cy.stub().as("changeSpy");
cy.mount(
<Slider
style={{ width: "400px" }}
min={0}
max={10}
step={1}
defaultValue={[5, 8]}
onChange={changeSpy}
/>
);

cy.findAllByRole("slider")
.eq(0)
.focus()
.realPress("ArrowRight")
.realPress("ArrowRight")
.realPress("ArrowRight");
// Value does not change on the final arrow right to call count remains at 2
cy.get("@changeSpy").should("have.callCount", 2);
cy.findAllByRole("slider")
.eq(0)
.should("have.attr", "aria-valuenow", "7");
});

it("THEN slider thumbs should not cross and maintain a gap of 1 step when using keyboard nav", () => {
cy.mount(
<Slider
style={{ width: "400px" }}
min={0}
max={10}
step={1}
defaultValue={[2, 5]}
/>
);

cy.findAllByRole("slider")
.eq(0)
.trigger("pointerdown")
.trigger("pointermove", {
clientX: 1000,
clientY: 1000,
});

cy.findAllByRole("slider")
.eq(0)
.should("have.attr", "aria-valuenow", "4");
});
});
});
Loading

0 comments on commit a7fb1d1

Please sign in to comment.