-
Notifications
You must be signed in to change notification settings - Fork 89
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
1 parent
79e9f4b
commit 27139c5
Showing
36 changed files
with
1,107 additions
and
1,365 deletions.
There are no files selected for viewing
434 changes: 434 additions & 0 deletions
434
.yarn/patches/@jpmorganchase-mosaic-components-npm-0.1.0-beta.37-6d8686e3dc.patch
Large diffs are not rendered by default.
Oops, something went wrong.
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
294 changes: 90 additions & 204 deletions
294
packages/lab/src/__tests__/__e2e__/accordion/Accordion.cy.tsx
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 |
---|---|---|
@@ -1,234 +1,120 @@ | ||
import { | ||
AccordionPanel, | ||
Accordion, | ||
AccordionDetails, | ||
AccordionProps, | ||
AccordionSection, | ||
AccordionSummary, | ||
AccordionHeader, | ||
} from "@salt-ds/lab"; | ||
import { useReducer, useState } from "react"; | ||
import { Component, ReactNode } from "react"; | ||
|
||
interface DetailsSpyProps { | ||
children?: ReactNode; | ||
onMount?: () => void; | ||
onUnmount?: () => void; | ||
onUpdated?: () => void; | ||
} | ||
|
||
class DetailsSpy extends Component<DetailsSpyProps> { | ||
render() { | ||
return <p>Detailed text</p>; | ||
} | ||
|
||
const AccordionExample = (props: AccordionProps) => { | ||
return ( | ||
<Accordion {...props}> | ||
<AccordionSection id="section-0" key="AccordionSection0"> | ||
<AccordionSummary>AccordionSummary0</AccordionSummary> | ||
<AccordionDetails>AccordionDetails0</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-1" key="AccordionSection1"> | ||
<AccordionSummary>AccordionSummary1</AccordionSummary> | ||
<AccordionDetails>AccordionDetails1</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-2" key="AccordionSection2"> | ||
<AccordionSummary>AccordionSummary2</AccordionSummary> | ||
<AccordionDetails>AccordionDetails2</AccordionDetails> | ||
</AccordionSection> | ||
</Accordion> | ||
); | ||
}; | ||
componentDidMount() { | ||
this.props.onMount?.(); | ||
} | ||
|
||
componentDidUpdate() { | ||
this.props.onUpdated?.(); | ||
} | ||
|
||
const ControlledAccordionExample = (props: AccordionProps) => { | ||
const { expandedSectionIds, onChange, ...rest } = props; | ||
const [expanded, setExpanded] = useState(expandedSectionIds); | ||
componentWillUnmount() { | ||
this.props.onUnmount?.(); | ||
} | ||
} | ||
|
||
const handleChange = (ids: string[] | null) => { | ||
setExpanded(ids ?? []); | ||
onChange?.(ids); | ||
}; | ||
type AccordionExampleProps = Pick<AccordionProps, "onToggle"> & DetailsSpyProps; | ||
|
||
const AccordionExample = ({ | ||
onToggle, | ||
onMount, | ||
onUnmount, | ||
onUpdated, | ||
}: AccordionExampleProps) => { | ||
return ( | ||
<Accordion expandedSectionIds={expanded} onChange={handleChange} {...rest}> | ||
<AccordionSection id="section-0" key="AccordionSection0"> | ||
<AccordionSummary>AccordionSummary0</AccordionSummary> | ||
<AccordionDetails>AccordionDetails0</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-1" key="AccordionSection1"> | ||
<AccordionSummary>AccordionSummary1</AccordionSummary> | ||
<AccordionDetails>AccordionDetails1</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-2" key="AccordionSection2"> | ||
<AccordionSummary>AccordionSummary2</AccordionSummary> | ||
<AccordionDetails>AccordionDetails2</AccordionDetails> | ||
</AccordionSection> | ||
<Accordion onToggle={onToggle} value="example"> | ||
<AccordionHeader>Summary Text</AccordionHeader> | ||
<AccordionPanel> | ||
<DetailsSpy | ||
onMount={onMount} | ||
onUnmount={onUnmount} | ||
onUpdated={onUpdated} | ||
> | ||
<div data-testid="details-content" /> | ||
</DetailsSpy> | ||
</AccordionPanel> | ||
</Accordion> | ||
); | ||
}; | ||
|
||
const expectExpandedSections = (expected: number[]) => { | ||
const s = new Set(expected); | ||
for (let i of Array(3).keys()) { | ||
cy.findByRole("button", { name: `AccordionSummary${i}` }).should( | ||
"have.attr", | ||
"aria-expanded", | ||
s.has(i) ? "true" : "false" | ||
); | ||
} | ||
}; | ||
|
||
const expectOnChangeLastCalled = (expected: number[]) => { | ||
cy.get("@changeSpy").should( | ||
"have.been.calledWith", | ||
expected.map((index) => `section-${index}`) | ||
); | ||
}; | ||
|
||
describe("GIVEN an Accordion", () => { | ||
describe("WHEN it is used in uncontrolled mode", () => { | ||
describe("WHEN user expands up to maxExpandedItems sections", () => { | ||
it("THEN sections should expand", () => { | ||
const changeSpy = cy.stub().as("changeSpy"); | ||
cy.mount( | ||
<AccordionExample onChange={changeSpy} maxExpandedItems={2} /> | ||
); | ||
cy.findByRole("button", { name: "AccordionSummary0" }).realClick(); | ||
cy.findByRole("button", { name: "AccordionSummary1" }).realClick(); | ||
it("THEN it should render in collapsed state", () => { | ||
cy.mount(<AccordionExample />); | ||
|
||
cy.findByRole("button").should("have.attr", "aria-expanded", "false"); | ||
}); | ||
|
||
cy.get("@changeSpy").should("have.been.calledTwice"); | ||
it("THEN it should render the details", () => { | ||
const mountSpy = cy.stub().as("mountSpy"); | ||
cy.mount(<AccordionExample onMount={mountSpy} />); | ||
cy.findByRole("button").realClick(); | ||
|
||
expectExpandedSections([0, 1]); | ||
cy.get("@mountSpy").should("have.been.calledOnce"); | ||
}); | ||
|
||
expectOnChangeLastCalled([0, 1]); | ||
}); | ||
describe("AND WHEN the summary is clicked", () => { | ||
it("THEN should render in expanded state", () => { | ||
const toggleSpy = cy.stub().as("toggleSpy"); | ||
cy.mount(<AccordionExample onToggle={toggleSpy} />); | ||
|
||
describe("AND WHEN user keeps opening more sections", () => { | ||
it("THEN panels should begin collapsing starting from the ones opened first", () => { | ||
const changeSpy = cy.stub().as("changeSpy"); | ||
cy.mount( | ||
<AccordionExample onChange={changeSpy} maxExpandedItems={2} /> | ||
); | ||
cy.findByRole("button", { name: "AccordionSummary0" }).realClick(); | ||
cy.findByRole("button", { name: "AccordionSummary1" }).realClick(); | ||
cy.findByRole("button", { name: "AccordionSummary2" }).realClick(); | ||
|
||
expectExpandedSections([1, 2]); | ||
expectOnChangeLastCalled([1, 2]); | ||
}); | ||
}); | ||
cy.findByRole("button").realClick(); | ||
cy.findByRole("button").should("have.attr", "aria-expanded", "true"); | ||
|
||
describe("AND WHEN user changes maxExpandedItems to a lower number", () => { | ||
function DynamicMaxExpandedItemsExample(props: AccordionProps) { | ||
const [isToggled, toggle] = useReducer((state) => { | ||
return !state; | ||
}, false); | ||
return ( | ||
<> | ||
<button onClick={toggle}>Toggle Max Expanded Items</button> | ||
<Accordion {...props} maxExpandedItems={isToggled ? 1 : 2}> | ||
<AccordionSection id="section-0" key="AccordionSection0"> | ||
<AccordionSummary>AccordionSummary0</AccordionSummary> | ||
<AccordionDetails>AccordionDetails0</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-1" key="AccordionSection1"> | ||
<AccordionSummary>AccordionSummary1</AccordionSummary> | ||
<AccordionDetails>AccordionDetails1</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-2" key="AccordionSection2"> | ||
<AccordionSummary>AccordionSummary2</AccordionSummary> | ||
<AccordionDetails>AccordionDetails2</AccordionDetails> | ||
</AccordionSection> | ||
</Accordion> | ||
</> | ||
); | ||
} | ||
it("THEN oldest panels should close", () => { | ||
const changeSpy = cy.stub().as("changeSpy"); | ||
cy.mount(<DynamicMaxExpandedItemsExample onChange={changeSpy} />); | ||
cy.findByRole("button", { name: "AccordionSummary0" }).realClick(); | ||
cy.findByRole("button", { name: "AccordionSummary1" }).realClick(); | ||
|
||
cy.findByRole("button", { | ||
name: "Toggle Max Expanded Items", | ||
}).realClick(); | ||
|
||
expectExpandedSections([1]); | ||
expectOnChangeLastCalled([1]); | ||
}); | ||
}); | ||
cy.get("@toggleSpy").should("have.been.calledOnce"); | ||
}); | ||
}); | ||
|
||
describe("WHEN it is used in controlled mode", () => { | ||
it("THEN sections with specified IDs should be expanded", () => { | ||
const changeSpy = cy.stub().as("changeSpy"); | ||
cy.mount( | ||
<ControlledAccordionExample | ||
expandedSectionIds={["section-0", "section-2"]} | ||
onChange={changeSpy} | ||
/> | ||
); | ||
expectExpandedSections([0, 2]); | ||
cy.get("@changeSpy").should("not.have.been.called"); | ||
it("THEN should not remount the details", () => { | ||
const mountSpy = cy.stub().as("mountSpy"); | ||
const unmountSpy = cy.stub().as("unmountSpy"); | ||
cy.mount(<AccordionExample onMount={mountSpy} onUnmount={unmountSpy} />); | ||
|
||
cy.findByRole("button").realClick(); | ||
cy.findByRole("button").should("have.attr", "aria-expanded", "true"); | ||
|
||
cy.get("@mountSpy").should("have.been.calledOnce"); | ||
cy.get("@unmountSpy").should("not.have.been.called"); | ||
}); | ||
|
||
describe("THEN user expands sections", () => { | ||
it("THEN onChange event should be raised but expanded actions remain the same", () => { | ||
const changeSpy = cy.stub().as("changeSpy"); | ||
cy.mount( | ||
<AccordionExample | ||
expandedSectionIds={["section-0", "section-2"]} | ||
onChange={changeSpy} | ||
/> | ||
); | ||
cy.findByRole("button", { name: "AccordionSummary1" }).realClick(); | ||
cy.get("@changeSpy").should("have.been.calledOnce"); | ||
expectExpandedSections([0, 2]); | ||
}); | ||
describe("AND WHEN the summary is clicked again", () => { | ||
it("THEN should render is collapsed state", () => { | ||
const toggleSpy = cy.stub().as("toggleSpy"); | ||
cy.mount(<AccordionExample onToggle={toggleSpy} />); | ||
|
||
cy.findByRole("button").realClick(); | ||
cy.findByRole("button").realClick(); | ||
|
||
describe("AND WHEN expandedSectionIds prop changes", () => { | ||
it("THEN expanded sections should change", () => { | ||
cy.mount( | ||
<ControlledAccordionExample | ||
expandedSectionIds={["section-0", "section-2"]} | ||
/> | ||
); | ||
cy.findByRole("button", { name: "AccordionSummary1" }).realClick(); | ||
|
||
expectExpandedSections([0, 1, 2]); | ||
}); | ||
cy.findByRole("button").should("have.attr", "aria-expanded", "false"); | ||
|
||
cy.get("@toggleSpy").should("have.been.calledTwice"); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("WHEN expanded prop is set directly on accordion sections", () => { | ||
it("THEN sections with expanded property set to true should be expanded", () => { | ||
cy.mount( | ||
<Accordion> | ||
<AccordionSection id="section-0" key="AccordionSection0"> | ||
<AccordionSummary>AccordionSummary0</AccordionSummary> | ||
<AccordionDetails>AccordionDetails0</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-1" key="AccordionSection1" expanded> | ||
<AccordionSummary>AccordionSummary1</AccordionSummary> | ||
<AccordionDetails>AccordionDetails1</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-2" key="AccordionSection2"> | ||
<AccordionSummary>AccordionSummary2</AccordionSummary> | ||
<AccordionDetails>AccordionDetails2</AccordionDetails> | ||
</AccordionSection> | ||
</Accordion> | ||
); | ||
expectExpandedSections([1]); | ||
}); | ||
it("THEN should keep the details mounted", () => { | ||
const unmountSpy = cy.stub().as("unmountSpy"); | ||
cy.mount(<AccordionExample onUnmount={unmountSpy} />); | ||
|
||
// TODO Should this work? | ||
it.skip("THEN expanded property set on sections should have priority over accordion's properties", () => { | ||
cy.mount( | ||
<Accordion expandedSectionIds={["section-0", "section-1"]}> | ||
<AccordionSection id="section-0" key="AccordionSection0"> | ||
<AccordionSummary>AccordionSummary0</AccordionSummary> | ||
<AccordionDetails>AccordionDetails0</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-1" key="AccordionSection1"> | ||
<AccordionSummary>AccordionSummary1</AccordionSummary> | ||
<AccordionDetails>AccordionDetails1</AccordionDetails> | ||
</AccordionSection> | ||
<AccordionSection id="section-2" key="AccordionSection2" expanded> | ||
<AccordionSummary>AccordionSummary2</AccordionSummary> | ||
<AccordionDetails>AccordionDetails2</AccordionDetails> | ||
</AccordionSection> | ||
</Accordion> | ||
); | ||
|
||
expectExpandedSections([2]); | ||
cy.findByRole("button").realClick(); | ||
cy.findByRole("button").realClick(); | ||
|
||
cy.get("@unmountSpy").should("not.have.been.called"); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.
27139c5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
saltdesignsystem – ./
saltdesignsystem-git-main-joshwooding.vercel.app
www.saltdesignsystem.com
saltdesignsystem.vercel.app
saltdesignsystem-joshwooding.vercel.app
next.saltdesignsystem.com