Skip to content

Commit

Permalink
Read and set query parameters for all dropdown filters
Browse files Browse the repository at this point in the history
  • Loading branch information
holly-cummins committed Apr 16, 2024
1 parent 0ebd38b commit e588007
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 26 deletions.
16 changes: 16 additions & 0 deletions src/components/filters/compatibility-filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@ import { fireEvent, render, screen } from "@testing-library/react"
import selectEvent from "react-select-event"
import CompatibilityFilter from "./compatibility-filter"


let mockQueryParamSearchString = undefined

jest.mock("react-use-query-param-string", () => {

const original = jest.requireActual("react-use-query-param-string")
const setQueryParam = jest.fn().mockImplementation((val) => {
mockQueryParamSearchString = val
})
return {
...original,
useQueryParamString: jest.fn().mockImplementation(() => [mockQueryParamSearchString, setQueryParam, true]),
}
})

describe("compatibility filter", () => {
const label = "Compatibility"

Expand Down Expand Up @@ -34,6 +49,7 @@ describe("compatibility filter", () => {
const filterer = jest.fn()
beforeEach(() => {
filterer.mockReset()
mockQueryParamSearchString = undefined

render(
<CompatibilityFilter
Expand Down
23 changes: 20 additions & 3 deletions src/components/filters/dropdown-filter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as React from "react"
import { useEffect } from "react"
import styled from "styled-components"
import Select from "react-select"
import Title from "./title"
import { useQueryParamString } from "react-use-query-param-string"


const Element = styled.form`
Expand All @@ -13,8 +15,13 @@ const Element = styled.form`
gap: 16px;
`

const onChange = (value, { action }, filterer) => {
if (action === "select-option" && filterer) filterer(value.value)
const onChange = (value, { action }, filterer, setSelectedOption) => {
if (action === "select-option") {
setSelectedOption && setSelectedOption(value.value)
if (filterer) {
filterer(value.value)
}
}
}


Expand Down Expand Up @@ -50,6 +57,8 @@ const DropdownFilter = ({
? displayLabel.toLowerCase().replace(" ", "-")
: "unknown"

const [selectedOption, setSelectedOption] = useQueryParamString(label, undefined, true)

const deduplicatedOptions = options ? [...new Set(options)] : []

const processedOptions = deduplicatedOptions.map(option => {
Expand All @@ -64,13 +73,21 @@ const DropdownFilter = ({
// A filter string of zero length is interpreted as 'everything'
processedOptions.unshift({ value: "", label: "All" })

// This is what makes the selection work if the page is loaded from a url with a query parameter
useEffect(() => {
if (selectedOption && selectedOption.length > 0) {
filterer(selectedOption)
}
}, [selectedOption, filterer])

return (
<Element data-testid={label + "-form"}>
<Title htmlFor={label}>{displayLabel}</Title>
<Select
value={processedOptions.find(o => o.value === selectedOption)}
placeholder="All"
options={processedOptions}
onChange={(a, b) => onChange(a, b, filterer)}
onChange={(a, b) => onChange(a, b, filterer, setSelectedOption)}
name={label}
inputId={label}
classNames={classNames}
Expand Down
93 changes: 76 additions & 17 deletions src/components/filters/dropdown-filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@ import React from "react"
import { fireEvent, render, screen } from "@testing-library/react"
import selectEvent from "react-select-event"
import DropdownFilter from "./dropdown-filter"
import { useQueryParamString } from "react-use-query-param-string"


let mockQueryParamSearchString = undefined
let rerender = undefined

jest.mock("react-use-query-param-string", () => {

const original = jest.requireActual("react-use-query-param-string")
const setQueryParam = jest.fn().mockImplementation((val) => {
mockQueryParamSearchString = val
})
return {
...original,
useQueryParamString: jest.fn().mockImplementation(() => [mockQueryParamSearchString, setQueryParam, true]),
}
})

describe("dropdown menu filter", () => {
describe("when the list is empty", () => {
Expand Down Expand Up @@ -37,18 +54,39 @@ describe("dropdown menu filter", () => {

const transformerFunction = value => (value === code ? "Strawberry" : value)

const filterer = jest.fn()
const filterer = jest.fn(() => {
// cheat, since normally the parent will force a rerender, and the child does not use usestate to avoid infinite loops
if (rerender) {
try {
rerender()
} catch (e) {
// This can happen if the component is already unmounted
}
}
})
beforeEach(() => {
filterer.mockReset()
mockQueryParamSearchString = undefined

render(
const options = [duplicate, "vanilla", "chocolate", duplicate, code]

const products = render(
<DropdownFilter
displayLabel={label}
filterer={filterer}
options={[duplicate, "vanilla", "chocolate", duplicate, code]}
options={options}
optionTransformer={transformerFunction}
/>
)


rerender = () => products.rerender(<DropdownFilter
displayLabel={label}
filterer={filterer}
options={options}
optionTransformer={transformerFunction}
/>)

})

it("has a dropdown menu", () => {
Expand Down Expand Up @@ -91,6 +129,17 @@ describe("dropdown menu filter", () => {
expect(filterer).toHaveBeenCalledWith(code)
})

it("sets query parameters", async () => {

const [, setQueryParam] = useQueryParamString()
expect(screen.getByTestId(id)).toHaveFormValues({
frogs: "",
})
await selectEvent.select(screen.getByLabelText(label), "Strawberry")

expect(setQueryParam).toHaveBeenCalledWith("632T")
})

it("has an option to reset", async () => {
await selectEvent.openMenu(screen.getByLabelText(label))
// In the dom, there are two Alls, one placeholder and one real one
Expand Down Expand Up @@ -122,7 +171,7 @@ describe("dropdown menu filter", () => {
// compareDocumentPosition returns a bitmask, so we do a bitwise AND on the results
expect(
chocolateElement.compareDocumentPosition(vanillaElement) &
Node.DOCUMENT_POSITION_FOLLOWING
Node.DOCUMENT_POSITION_FOLLOWING
).toBeTruthy()
})
})
Expand All @@ -135,33 +184,43 @@ describe("dropdown menu filter", () => {
const transformerFunction = value => (value === code ? "Strawberry" : value)

const compareFunction = (a, b) => {
{
if (a.toLowerCase() < b.toLowerCase()) {
return 1
}
if (a.toLowerCase() > b.toLowerCase()) {
return -1
}

return 0
if (a.toLowerCase() < b.toLowerCase()) {
return 1
}
if (a.toLowerCase() > b.toLowerCase()) {
return -1
}

return 0
}

const filterer = jest.fn()
beforeEach(() => {
filterer.mockReset()
mockQueryParamSearchString = undefined

render(
const options = [duplicate, "vanilla", "chocolate", duplicate, code]

const products = render(
<DropdownFilter
displayLabel={label}
filterer={filterer}
options={[duplicate, "vanilla", "chocolate", duplicate, code]}
options={options}
optionTransformer={transformerFunction}
compareFunction={compareFunction}
/>
)

rerender = () => products.rerender(<DropdownFilter
displayLabel={label}
filterer={filterer}
options={options}
optionTransformer={transformerFunction}
compareFunction={compareFunction}
/>)
})


it("sorts entries according to the function", async () => {
await selectEvent.openMenu(screen.getByLabelText(label))

Expand All @@ -172,12 +231,12 @@ describe("dropdown menu filter", () => {
// compareDocumentPosition returns a bitmask, so we do a bitwise AND on the results
expect(
chocolateElement.compareDocumentPosition(vanillaElement) &
Node.DOCUMENT_POSITION_PRECEDING
Node.DOCUMENT_POSITION_PRECEDING
).toBeTruthy()

expect(
strawberryElement.compareDocumentPosition(vanillaElement) &
Node.DOCUMENT_POSITION_PRECEDING
Node.DOCUMENT_POSITION_PRECEDING
).toBeTruthy()
})
})
Expand Down
42 changes: 36 additions & 6 deletions src/components/filters/status-filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@ import React from "react"
import { fireEvent, render, screen } from "@testing-library/react"
import StatusFilter from "./status-filter"
import selectEvent from "react-select-event"
import { useQueryParamString } from "react-use-query-param-string"

let mockQueryParamSearchString = undefined

jest.mock("react-use-query-param-string", () => {

const original = jest.requireActual("react-use-query-param-string")
const setQueryParam = jest.fn().mockImplementation((val) => {
mockQueryParamSearchString = val
})
return {
...original,
useQueryParamString: jest.fn().mockImplementation(() => [mockQueryParamSearchString, setQueryParam, true]),
}
})

describe("status filter", () => {
const label = "Status"
Expand Down Expand Up @@ -34,18 +49,22 @@ describe("status filter", () => {
const filterer = jest.fn()
beforeEach(() => {
filterer.mockReset()
mockQueryParamSearchString = undefined

const extensions = [
{ metadata: { status: "shinyduplicate" } },
{ metadata: { status: "sublime" } },
{ metadata: { status: "sad" } },
{ metadata: { status: "shinyduplicate" } },
]

render(
<StatusFilter
filterer={filterer}
extensions={[
{ metadata: { status: "shinyduplicate" } },
{ metadata: { status: "sublime" } },
{ metadata: { status: "sad" } },
{ metadata: { status: "shinyduplicate" } },
]}
extensions={extensions}
/>
)

})

it("renders a title", () => {
Expand Down Expand Up @@ -78,5 +97,16 @@ describe("status filter", () => {
await selectEvent.select(screen.getByLabelText(label), "sublime")
expect(filterer).toHaveBeenCalledWith("sublime")
})

it("sets search parameters", async () => {

const [, setQueryParam] = useQueryParamString()
expect(screen.getByTestId("status-form")).toHaveFormValues({
status: "",
})
await selectEvent.select(screen.getByLabelText(label), "sublime")

expect(setQueryParam).toHaveBeenCalledWith("sublime")
})
})
})
15 changes: 15 additions & 0 deletions src/components/filters/version-filter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ import { fireEvent, render, screen } from "@testing-library/react"
import VersionFilter from "./version-filter"
import selectEvent from "react-select-event"

let mockQueryParamSearchString = undefined

jest.mock("react-use-query-param-string", () => {

const original = jest.requireActual("react-use-query-param-string")
const setQueryParam = jest.fn().mockImplementation((val) => {
mockQueryParamSearchString = val
})
return {
...original,
useQueryParamString: jest.fn().mockImplementation(() => [mockQueryParamSearchString, setQueryParam, true]),
}
})

describe("version filter", () => {
const label = "Built With"

Expand Down Expand Up @@ -34,6 +48,7 @@ describe("version filter", () => {
const filterer = jest.fn()
beforeEach(() => {
filterer.mockReset()
mockQueryParamSearchString = undefined

render(
<VersionFilter
Expand Down

0 comments on commit e588007

Please sign in to comment.