Skip to content

Commit

Permalink
feat(tree): init e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed May 12, 2024
1 parent 6784ab2 commit 239d084
Show file tree
Hide file tree
Showing 8 changed files with 291 additions and 12 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ fmt: ##@0 global format code using prettier (js, css, md)
"storybook/stories/**/*.{js,ts,tsx}" \
"cypress/src/**/*.{js,ts,tsx}" \
"scripts/*.{js,mjs}" \
"cypress/src/**/*.{js,tsx}" \
"README.md"

fmt-check: ##@0 global check if files were all formatted using prettier
Expand All @@ -76,6 +77,7 @@ fmt-check: ##@0 global check if files were all formatted using prettier
"storybook/stories/**/*.{js,ts,tsx}" \
"cypress/src/**/*.{js,ts,tsx}" \
"scripts/*.{js,mjs}" \
"cypress/src/**/*.{js,tsx}" \
"README.md"

test: ##@0 global run all checks/tests (packages, website)
Expand Down
10 changes: 6 additions & 4 deletions cypress/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { defineConfig } from 'cypress'
import { defineConfig } from "cypress";

export default defineConfig({
viewportWidth: 600,
viewportHeight: 600,
component: {
devServer: {
framework: 'create-react-app',
bundler: 'webpack',
framework: "create-react-app",
bundler: "webpack",
},
video: false,
},
})
});
7 changes: 4 additions & 3 deletions cypress/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@nivo/stream": "workspace:*",
"@nivo/sunburst": "workspace:*",
"@nivo/swarmplot": "workspace:*",
"@nivo/tree": "workspace:*",
"@nivo/treemap": "workspace:*",
"@nivo/voronoi": "workspace:*",
"@nivo/waffle": "workspace:*"
Expand All @@ -45,9 +46,9 @@
"node": ">=18"
},
"devDependencies": {
"cypress": "^12.11.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"cypress": "^13.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-scripts": "^5.0.1",
"typescript": "^4.9.5"
},
Expand Down
174 changes: 174 additions & 0 deletions cypress/src/components/tree/Tree.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { Tree, TreeSvgProps } from '@nivo/tree'
import { before } from 'lodash'

interface Datum {
id: string
children?: Datum[]
}

const sampleData: Datum = {
id: 'A',
children: [
{ id: '0' },
{
id: '1',
children: [{ id: 'A' }, { id: 'B' }],
},
{ id: '2' },
],
}

const defaultProps: Pick<
TreeSvgProps<Datum>,
| 'data'
| 'width'
| 'height'
| 'margin'
| 'nodeSize'
| 'activeNodeSize'
| 'inactiveNodeSize'
| 'linkThickness'
| 'activeLinkThickness'
| 'inactiveLinkThickness'
| 'animate'
> = {
data: sampleData,
width: 640,
height: 640,
margin: {
top: 20,
right: 20,
bottom: 20,
left: 20,
},
nodeSize: 12,
activeNodeSize: 24,
inactiveNodeSize: 8,
linkThickness: 2,
activeLinkThickness: 12,
inactiveLinkThickness: 1,
animate: false,
}

describe('<Tree />', () => {
beforeEach(() => {
cy.viewport(
defaultProps.margin.left + defaultProps.width + defaultProps.margin.right,
defaultProps.margin.top + defaultProps.height + defaultProps.margin.bottom
)
})

it('should render a tree graph', () => {
cy.mount(<Tree<Datum> {...defaultProps} />)

cy.get('[data-testid="node.A"]').should('exist')
cy.get('[data-testid="node.A.0"]').should('exist')
cy.get('[data-testid="node.A.1"]').should('exist')
cy.get('[data-testid="node.A.1.A"]').should('exist')
cy.get('[data-testid="node.A.1.B"]').should('exist')
cy.get('[data-testid="node.A.2"]').should('exist')
})

it('should highlight ancestor nodes and links', () => {
cy.mount(
<Tree<Datum>
{...defaultProps}
useMesh={false}
highlightAncestorNodes={true}
highlightAncestorLinks={true}
/>
)

const expectations = [
{ uid: 'node.A', nodes: ['node.A'], links: [] },
{ uid: 'node.A.0', nodes: ['node.A', 'node.A.0'], links: ['link.A:A.0'] },
{ uid: 'node.A.1', nodes: ['node.A', 'node.A.1'], links: ['link.A:A.1'] },
{
uid: 'node.A.1.A',
nodes: ['node.A', 'node.A.1', 'node.A.1.A'],
links: ['link.A:A.1', 'link.A.1:A.1.A'],
},
{
uid: 'node.A.1.B',
nodes: ['node.A', 'node.A.1', 'node.A.1.B'],
links: ['link.A:A.1', 'link.A.1:A.1.B'],
},
{ uid: 'node.A.2', nodes: ['node.A', 'node.A.2'], links: ['link.A:A.2'] },
]

for (const expectation of expectations) {
cy.get(`[data-testid="${expectation.uid}"]`).trigger('mouseover')
cy.wait(100)

cy.get('[data-testid^="node."]').each($node => {
cy.wrap($node)
.invoke('attr', 'data-testid')
.then(testId => {
const size = expectation.nodes.includes(testId!)
? defaultProps.activeNodeSize
: defaultProps.inactiveNodeSize
cy.wrap($node)
.invoke('attr', 'r')
.should('equal', `${size / 2}`)
})
})

cy.get('[data-testid^="link."]').each($link => {
cy.wrap($link)
.invoke('attr', 'data-testid')
.then(testId => {
const thickness = expectation.links.includes(testId!)
? defaultProps.activeLinkThickness
: defaultProps.inactiveLinkThickness
cy.wrap($link)
.invoke('attr', 'stroke-width')
.should('equal', `${thickness}`)
})
})
}
})

it('should highlight descendant nodes and links', () => {
cy.mount(
<Tree<Datum>
{...defaultProps}
useMesh={false}
highlightAncestorNodes={false}
highlightAncestorLinks={false}
highlightDescendantNodes={true}
highlightDescendantLinks={true}
/>
)

const expectations = [
{
uid: 'node.A',
nodes: ['node.A', 'node.A.0', 'node.A.1', 'node.A.1.A', 'node.A.1.B', 'node.A.2'],
links: [],
},
{ uid: 'node.A.0', nodes: ['node.A.0'], links: [] },
{ uid: 'node.A.1', nodes: ['node.A.1', 'node.A.1.A', 'node.A.1.B'], links: [] },
{ uid: 'node.A.1.A', nodes: ['node.A.1.A'], links: [] },
{ uid: 'node.A.1.B', nodes: ['node.A.1.B'], links: [] },
{ uid: 'node.A.2', nodes: ['node.A.2'], links: [] },
]

for (const expectation of expectations) {
cy.get(`[data-testid="${expectation.uid}"]`).trigger('mouseover')
cy.wait(100)

cy.get('[data-testid^="node."]').each($node => {
cy.wrap($node)
.invoke('attr', 'data-testid')
.then(testId => {
const size = expectation.nodes.includes(testId!)
? defaultProps.activeNodeSize
: defaultProps.inactiveNodeSize
cy.wrap($node)
.invoke('attr', 'r')
.should('equal', `${size / 2}`)
})
})
}
})
})
1 change: 1 addition & 0 deletions packages/tree/src/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const Link = <Datum,>({

return (
<animated.path
data-testid={`link.${link.id}`}
d={to(
[
animatedProps.sourceX,
Expand Down
1 change: 1 addition & 0 deletions packages/tree/src/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const Node = <Datum,>({

return (
<animated.circle
data-testid={`node.${node.uid}`}
r={animatedProps.size.to(size => size / 2)}
fill={animatedProps.color}
cx={animatedProps.x}
Expand Down
9 changes: 6 additions & 3 deletions packages/tree/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ const useNodes = <Datum>({
activeNodeUids,
])

return { ...computed, setActiveNodeUids }
return { ...computed, activeNodeUids, setActiveNodeUids }
}

const useLinkThicknessModifier = <Datum>(
Expand All @@ -224,13 +224,15 @@ const useLinkThicknessModifier = <Datum>(
const useLinks = <Datum>({
root,
nodeByUid,
activeNodeUids,
linkThickness,
activeLinkThickness,
inactiveLinkThickness,
linkColor,
}: {
root: HierarchyTreeNode<Datum>
nodeByUid: Record<string, ComputedNode<Datum>>
activeNodeUids: string[]
linkThickness: Exclude<CommonProps<Datum>['linkThickness'], undefined>
activeLinkThickness?: CommonProps<Datum>['activeLinkThickness']
inactiveLinkThickness?: CommonProps<Datum>['inactiveLinkThickness']
Expand Down Expand Up @@ -268,7 +270,7 @@ const useLinks = <Datum>({
isActive: null,
}

if (activeLinkIds.length > 0) {
if (activeNodeUids.length > 0) {
computedLink.isActive = activeLinkIds.includes(computedLink.id)
if (computedLink.isActive) {
computedLink.thickness = getActiveLinkThickness(computedLink)
Expand Down Expand Up @@ -417,7 +419,7 @@ export const useTree = <Datum = DefaultDatum>({
const root = useRoot<Datum>({ data, mode, getIdentity })

const { xScale, yScale } = useCartesianScales({ width, height, layout })
const { nodes, nodeByUid, setActiveNodeUids } = useNodes<Datum>({
const { nodes, nodeByUid, activeNodeUids, setActiveNodeUids } = useNodes<Datum>({
root,
xScale,
yScale,
Expand All @@ -433,6 +435,7 @@ export const useTree = <Datum = DefaultDatum>({
const { links, setActiveLinkIds } = useLinks<Datum>({
root,
nodeByUid,
activeNodeUids,
linkThickness,
activeLinkThickness,
inactiveLinkThickness,
Expand Down
Loading

0 comments on commit 239d084

Please sign in to comment.