refactor(search): extract search into workspace package
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import {
|
||||
cleanup,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
} from "@testing-library/react"
|
||||
import { I18nProvider } from "@workspace/i18n"
|
||||
import { afterEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import { SearchProvider } from "./context"
|
||||
import { SearchDialog } from "./dialog"
|
||||
import { searchDialogHandle } from "./handle"
|
||||
import { splitHighlightSegments } from "./highlight"
|
||||
import { messages as englishMessages } from "./locales/en-US"
|
||||
import type { SearchAdapter } from "./types"
|
||||
|
||||
class ResizeObserverStub {
|
||||
disconnect() {}
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
}
|
||||
|
||||
vi.stubGlobal("ResizeObserver", ResizeObserverStub)
|
||||
Object.defineProperty(Element.prototype, "getAnimations", {
|
||||
configurable: true,
|
||||
value: () => [],
|
||||
})
|
||||
|
||||
function renderSearch({
|
||||
adapter,
|
||||
onSelect,
|
||||
}: {
|
||||
adapter: SearchAdapter
|
||||
onSelect?: (event: { item: { id: string }; query: string }) => void
|
||||
}) {
|
||||
return render(
|
||||
<I18nProvider locale="en-US" catalogs={{ "en-US": englishMessages }}>
|
||||
<SearchProvider
|
||||
adapter={adapter}
|
||||
historyStorageKey={false}
|
||||
onSelect={onSelect}
|
||||
>
|
||||
<SearchDialog hotkey={false} />
|
||||
</SearchProvider>
|
||||
</I18nProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe("search package", () => {
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
window.localStorage.clear()
|
||||
})
|
||||
|
||||
it("delegates searching, pagination, and selection to the provider", async () => {
|
||||
const adapter: SearchAdapter = {
|
||||
search: vi.fn(async ({ cursor, query }) => {
|
||||
if (cursor) {
|
||||
return {
|
||||
groups: [
|
||||
{
|
||||
id: "people",
|
||||
label: "People",
|
||||
items: [{ id: "2", title: "Grace Hopper" }],
|
||||
},
|
||||
],
|
||||
nextCursor: null,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
groups: [
|
||||
{
|
||||
id: "people",
|
||||
label: "People",
|
||||
total: 2,
|
||||
items: [
|
||||
{
|
||||
id: "1",
|
||||
title: "Ada Lovelace",
|
||||
description: `Matched ${query}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
nextCursor: "next-page",
|
||||
}
|
||||
}),
|
||||
}
|
||||
const onSelect = vi.fn()
|
||||
renderSearch({ adapter, onSelect })
|
||||
|
||||
searchDialogHandle.open(null)
|
||||
const input = await screen.findByPlaceholderText("Search your workspace…")
|
||||
fireEvent.change(input, { target: { value: "ada" } })
|
||||
|
||||
await waitFor(() =>
|
||||
expect(adapter.search).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ query: "ada" })
|
||||
)
|
||||
)
|
||||
await waitFor(() =>
|
||||
expect(screen.getByRole("dialog").textContent).toContain("Ada Lovelace")
|
||||
)
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Load more" }))
|
||||
await waitFor(() =>
|
||||
expect(screen.getByRole("dialog").textContent).toContain("Grace Hopper")
|
||||
)
|
||||
expect(adapter.search).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ cursor: "next-page", query: "ada" })
|
||||
)
|
||||
|
||||
fireEvent.click(screen.getByRole("option", { name: "Open Ada Lovelace" }))
|
||||
await waitFor(() =>
|
||||
expect(onSelect).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
item: expect.objectContaining({ id: "1" }),
|
||||
query: "ada",
|
||||
})
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
it("splits case-insensitive literal query matches for highlighting", () => {
|
||||
expect(splitHighlightSegments("Ada ADA Lovelace", "ada")).toEqual([
|
||||
{ highlighted: true, text: "Ada" },
|
||||
{ highlighted: false, text: " " },
|
||||
{ highlighted: true, text: "ADA" },
|
||||
{ highlighted: false, text: " Lovelace" },
|
||||
])
|
||||
expect(splitHighlightSegments("price [usd]", "[usd]")).toEqual([
|
||||
{ highlighted: false, text: "price " },
|
||||
{ highlighted: true, text: "[usd]" },
|
||||
])
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user