From 7ce4031a203d9f576a20acdb8aa9e8d59ae9ce99 Mon Sep 17 00:00:00 2001 From: Hunter Johnston <64506580+huntabyte@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:51:02 -0400 Subject: [PATCH] next: accordion test updates (#501) --- packages/bits-ui/package.json | 1 + .../lib/bits/accordion/accordion.svelte.ts | 23 +- .../accordion/components/accordion.svelte | 8 +- .../bits/toggle-group/toggle-group.svelte.ts | 3 +- .../src/tests/accordion/Accordion.spec.ts | 322 +++++++++++++++++- .../tests/accordion/AccordionMultiTest.svelte | 34 ++ .../AccordionMultiTestControlled.svelte | 48 +++ .../AccordionSingleTestControlled.svelte | 43 +++ packages/bits-ui/vite.config.ts | 1 - 9 files changed, 454 insertions(+), 29 deletions(-) create mode 100644 packages/bits-ui/src/tests/accordion/AccordionMultiTest.svelte create mode 100644 packages/bits-ui/src/tests/accordion/AccordionMultiTestControlled.svelte create mode 100644 packages/bits-ui/src/tests/accordion/AccordionSingleTestControlled.svelte diff --git a/packages/bits-ui/package.json b/packages/bits-ui/package.json index bcef3e98c..a0ff20497 100644 --- a/packages/bits-ui/package.json +++ b/packages/bits-ui/package.json @@ -39,6 +39,7 @@ "@types/node": "^20.12.2", "@types/resize-observer-browser": "^0.1.11", "@types/testing-library__jest-dom": "^5.14.9", + "@vitest/ui": "^1.5.0", "csstype": "^3.1.3", "jest-axe": "^8.0.0", "jsdom": "^24.0.0", diff --git a/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts b/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts index a265e88c0..014cb4f9c 100644 --- a/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts +++ b/packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts @@ -50,10 +50,6 @@ class AccordionBaseState { ); } - createHeader(props: AccordionHeaderStateProps) { - return new AccordionHeaderState(props); - } - props = $derived({ id: this.id.value, [ROOT_ATTR]: "", @@ -107,7 +103,7 @@ export class AccordionMultiState extends AccordionBaseState { if (this.includesItem(item)) { this.#value.value = this.#value.value.filter((v) => v !== item); } else { - this.#value.value.push(item); + this.#value.value = [...this.#value.value, item]; } } } @@ -148,6 +144,10 @@ export class AccordionItemState { return new AccordionContentState(props, this); } + createHeader(props: AccordionHeaderStateProps) { + return new AccordionHeaderState(props, this); + } + props = $derived({ [ITEM_ATTR]: "", "data-state": getDataOpenClosed(this.isSelected), @@ -320,16 +320,18 @@ type AccordionHeaderStateProps = ReadonlyBoxedValues<{ }>; class AccordionHeaderState { + #item = undefined as unknown as AccordionItemState; #level = undefined as unknown as AccordionHeaderStateProps["level"]; - - constructor(props: AccordionHeaderStateProps) { + constructor(props: AccordionHeaderStateProps, item: AccordionItemState) { this.#level = props.level; + this.#item = item; } props = $derived({ role: "heading", "aria-level": this.#level.value, "data-heading-level": this.#level.value, + "data-state": getDataOpenClosed(this.#item.isSelected), [HEADER_ATTR]: "", }); } @@ -360,11 +362,11 @@ export function setAccordionRootState(props: InitAccordionProps) { } export function getAccordionRootState() { + verifyContextDeps(ACCORDION_ROOT_KEY); return getContext(ACCORDION_ROOT_KEY); } export function setAccordionItemState(props: Omit) { - verifyContextDeps(ACCORDION_ROOT_KEY); const rootState = getAccordionRootState(); const itemState = new AccordionItemState({ ...props, rootState }); setContext(ACCORDION_ITEM_KEY, itemState); @@ -372,21 +374,20 @@ export function setAccordionItemState(props: Omit(ACCORDION_ITEM_KEY); } export function getAccordionTriggerState(props: AccordionTriggerStateProps): AccordionTriggerState { - verifyContextDeps(ACCORDION_ITEM_KEY); const itemState = getAccordionItemState(); return itemState.createTrigger(props); } export function getAccordionContentState(props: AccordionContentStateProps): AccordionContentState { - verifyContextDeps(ACCORDION_ITEM_KEY); const itemState = getAccordionItemState(); return itemState.createContent(props); } export function getAccordionHeaderState(props: AccordionHeaderStateProps): AccordionHeaderState { - return getAccordionRootState().createHeader(props); + return getAccordionItemState().createHeader(props); } diff --git a/packages/bits-ui/src/lib/bits/accordion/components/accordion.svelte b/packages/bits-ui/src/lib/bits/accordion/components/accordion.svelte index 080a424ee..6373a5534 100644 --- a/packages/bits-ui/src/lib/bits/accordion/components/accordion.svelte +++ b/packages/bits-ui/src/lib/bits/accordion/components/accordion.svelte @@ -9,21 +9,21 @@ children, child, type, - value: valueProp = $bindable(), + value = $bindable(), el = $bindable(), id = useId(), onValueChange, ...restProps }: RootProps = $props(); - valueProp === undefined && (valueProp = type === "single" ? "" : []); + value === undefined && (value = type === "single" ? "" : []); const rootState = setAccordionRootState({ type, value: box( - () => valueProp!, + () => value!, (v) => { - valueProp = v; + value = v; onValueChange?.(v as any); } ) as Box | Box, diff --git a/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts b/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts index 64a7da4d2..20a91f60b 100644 --- a/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts +++ b/packages/bits-ui/src/lib/bits/toggle-group/toggle-group.svelte.ts @@ -12,7 +12,8 @@ import { type ReadonlyBoxedValues, boxedState, } from "$lib/internal/box.svelte.js"; -import { getDirectionalKeys, kbd } from "$lib/internal/kbd.js"; +import { kbd } from "$lib/internal/kbd.js"; +import { getDirectionalKeys } from "$lib/internal/get-directional-keys.js"; import { getElemDirection } from "$lib/internal/locale.js"; import { useNodeById } from "$lib/internal/use-node-by-id.svelte.js"; import type { Orientation } from "$lib/shared/index.js"; diff --git a/packages/bits-ui/src/tests/accordion/Accordion.spec.ts b/packages/bits-ui/src/tests/accordion/Accordion.spec.ts index 8896819e4..892da3fae 100644 --- a/packages/bits-ui/src/tests/accordion/Accordion.spec.ts +++ b/packages/bits-ui/src/tests/accordion/Accordion.spec.ts @@ -1,11 +1,15 @@ /* eslint-disable ts/no-explicit-any */ -import { render } from "@testing-library/svelte/svelte5"; +import { render, waitFor } from "@testing-library/svelte/svelte5"; import { userEvent } from "@testing-library/user-event"; import { axe } from "jest-axe"; import { describe, it } from "vitest"; +import { tick } from "svelte"; import { getTestKbd } from "../utils.js"; import AccordionSingleTest from "./AccordionSingleTest.svelte"; +import AccordionMultiTest from "./AccordionMultiTest.svelte"; import AccordionTestIsolated from "./AccordionTestIsolated.svelte"; +import AccordionSingleTestControlledSvelte from "./AccordionSingleTestControlled.svelte"; +import AccordionMultiTestControlled from "./AccordionMultiTestControlled.svelte"; export type Item = { value: string; @@ -55,7 +59,7 @@ const itemsWithDisabled = items.map((item) => { return item; }); -describe("accordion", () => { +describe("accordion - single", () => { it("has no accessibility violations", async () => { const { container } = render(AccordionSingleTest as any, { items }); expect(await axe(container)).toHaveNoViolations(); @@ -87,6 +91,7 @@ describe("accordion", () => { expect(triggerEls[0]).not.toHaveAttribute("data-disabled"); await user.click(triggerEls[0] as HTMLElement); + await tick(); expect(itemEls[0]).toHaveAttribute("data-state", "open"); expect(triggerEls[0]).toHaveAttribute("data-state", "open"); @@ -94,6 +99,27 @@ describe("accordion", () => { expect(triggerEls[1]).toHaveAttribute("data-disabled"); }); + it("disables everything when the `disabled` prop is true", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { + items, + disabled: true, + }); + + const triggerEls = items.map((item) => getByTestId(`${item.value}-trigger`)); + await user.click(triggerEls[0] as HTMLElement); + expect(triggerEls[0]).not.toHaveAttribute("data-state", "open"); + expect(triggerEls[0]).toHaveAttribute("data-disabled"); + + await user.click(triggerEls[1] as HTMLElement); + expect(triggerEls[1]).not.toHaveAttribute("data-state", "open"); + expect(triggerEls[1]).toHaveAttribute("data-disabled"); + + await user.click(triggerEls[2] as HTMLElement); + expect(triggerEls[2]).not.toHaveAttribute("data-state", "open"); + expect(triggerEls[2]).toHaveAttribute("data-disabled"); + }); + it("displays content when an item is expanded", async () => { const user = userEvent.setup(); const { getByTestId } = render(AccordionSingleTest as any, { items }); @@ -134,11 +160,252 @@ describe("accordion", () => { expect(openItems.length).toBe(1); }); - it.skip("expands multiple items when `multiple` is true", async () => { + it("expands when the trigger is focused and `Enter` key is pressed", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { + items, + }); + + for (const item of items) { + const trigger = getByTestId(`${item.value}-trigger`); + const content = getByTestId(`${item.value}-content`); + const itemEl = getByTestId(`${item.value}-item`); + expect(itemEl).toHaveAttribute("data-state", "closed"); + expect(itemEl).toHaveAttribute("data-state", "closed"); + expect(content).not.toBeVisible(); + trigger.focus(); + await user.keyboard(kbd.ENTER); + const contentAfter = getByTestId(`${item.value}-content`); + expect(contentAfter).toHaveTextContent(item.content); + expect(itemEl).toHaveAttribute("data-state", "open"); + } + }); + + it("expands when the trigger is focused and `Space` key is pressed", async () => { const user = userEvent.setup(); const { getByTestId } = render(AccordionSingleTest as any, { items, - type: "multiple", + }); + + for (const item of items) { + const trigger = getByTestId(`${item.value}-trigger`); + const content = getByTestId(`${item.value}-content`); + const itemEl = getByTestId(`${item.value}-item`); + expect(itemEl).toHaveAttribute("data-state", "closed"); + expect(itemEl).toHaveAttribute("data-state", "closed"); + expect(content).not.toBeVisible(); + trigger.focus(); + await user.keyboard(kbd.SPACE); + const contentAfter = getByTestId(`${item.value}-content`); + expect(contentAfter).toHaveTextContent(item.content); + expect(itemEl).toHaveAttribute("data-state", "open"); + } + }); + + it("focuses the next item when `ArrowDown` key is pressed", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { items }); + + const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); + triggers[0]?.focus(); + await user.keyboard(kbd.ARROW_DOWN); + expect(triggers[1]).toHaveFocus(); + await user.keyboard(kbd.ARROW_DOWN); + expect(triggers[2]).toHaveFocus(); + await user.keyboard(kbd.ARROW_DOWN); + expect(triggers[3]).toHaveFocus(); + await user.keyboard(kbd.ARROW_DOWN); + expect(triggers[0]).toHaveFocus(); + }); + + it("focuses the previous item when the `ArrowUp` key is pressed", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { items }); + + const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); + triggers[0]?.focus(); + await user.keyboard(kbd.ARROW_UP); + expect(triggers[3]).toHaveFocus(); + await user.keyboard(kbd.ARROW_UP); + expect(triggers[2]).toHaveFocus(); + await user.keyboard(kbd.ARROW_UP); + expect(triggers[1]).toHaveFocus(); + await user.keyboard(kbd.ARROW_UP); + expect(triggers[0]).toHaveFocus(); + }); + + it("focuses the first item when the `Home` key is pressed", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { items }); + + const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); + + for (const trigger of triggers) { + trigger.focus(); + await user.keyboard(kbd.HOME); + expect(triggers[0]).toHaveFocus(); + } + }); + + it("focuses the last item when the `End` key is pressed", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { items }); + + const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); + + for (const trigger of triggers) { + trigger.focus(); + await user.keyboard(kbd.END); + expect(triggers[3]).toHaveFocus(); + } + }); + + it("respects the `disabled` prop for items", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTest as any, { items: itemsWithDisabled }); + + const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); + await user.click(triggers[0] as HTMLElement); + + await user.keyboard(kbd.ARROW_DOWN); + expect(triggers[1]).not.toHaveFocus(); + expect(triggers[2]).toHaveFocus(); + }); + + it("respects the `level` prop for headers", async () => { + const itemsWithLevel = items.map((item, i) => { + if (i === 0) { + return { ...item, level: 1 } as const; + } + return item; + }); + const { getByTestId } = render(AccordionSingleTest as any, { items: itemsWithLevel }); + + const headers = items.map((item) => getByTestId(`${item.value}-header`)); + expect(headers[0]).toHaveAttribute("data-heading-level", "1"); + expect(headers[0]).toHaveAttribute("aria-level", "1"); + expect(headers[1]).toHaveAttribute("data-heading-level", "3"); + expect(headers[1]).toHaveAttribute("aria-level", "3"); + }); + + it("updates the `bind:value` prop when the value changes", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTestControlledSvelte as any, { items }); + const trigger = getByTestId("item-1-trigger"); + + const value = getByTestId("value"); + + expect(value).toHaveTextContent(""); + + await user.click(trigger); + + expect(value).toHaveTextContent("item-1"); + }); + + it('handles programatic changes to the "value" prop', async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionSingleTestControlledSvelte as any, { items }); + const updateButton = getByTestId("update-value"); + const value = getByTestId("value"); + + expect(value).toHaveTextContent(""); + + const itemTwoItem = getByTestId("item-2-item"); + expect(itemTwoItem).toHaveAttribute("data-state", "closed"); + + await user.click(updateButton); + + expect(value).toHaveTextContent("item-2"); + expect(itemTwoItem).toHaveAttribute("data-state", "open"); + }); +}); + +// +// MULTIPLE ACCORDION +// + +describe("accordion - multiple", () => { + it("has no accessibility violations", async () => { + const { container } = render(AccordionMultiTest as any, { items }); + expect(await axe(container)).toHaveNoViolations(); + }); + + it("has bits data attrs", async () => { + const { getByTestId } = render(AccordionTestIsolated); + const root = getByTestId("root"); + const trigger = getByTestId("trigger"); + const item = getByTestId("item"); + const header = getByTestId("header"); + const content = getByTestId("content"); + expect(root).toHaveAttribute("data-accordion-root"); + expect(item).toHaveAttribute("data-accordion-item"); + expect(header).toHaveAttribute("data-accordion-header"); + expect(content).toHaveAttribute("data-accordion-content"); + expect(trigger).toHaveAttribute("data-accordion-trigger"); + }); + + it("has expected data attributes", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionMultiTest as any, { items: itemsWithDisabled }); + const itemEls = items.map((item) => getByTestId(`${item.value}-item`)); + const triggerEls = items.map((item) => getByTestId(`${item.value}-trigger`)); + + expect(itemEls[0]).toHaveAttribute("data-state", "closed"); + expect(itemEls[0]).not.toHaveAttribute("data-disabled"); + expect(triggerEls[0]).toHaveAttribute("data-state", "closed"); + expect(triggerEls[0]).not.toHaveAttribute("data-disabled"); + + await user.click(triggerEls[0] as HTMLElement); + await waitFor(() => expect(triggerEls[0]).toHaveAttribute("data-state", "open")); + expect(itemEls[0]).toHaveAttribute("data-state", "open"); + + expect(itemEls[1]).toHaveAttribute("data-disabled"); + expect(triggerEls[1]).toHaveAttribute("data-disabled"); + }); + + it("disables everything when the `disabled` prop is true", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionMultiTest as any, { + items, + disabled: true, + }); + + const triggerEls = items.map((item) => getByTestId(`${item.value}-trigger`)); + await user.click(triggerEls[0] as HTMLElement); + expect(triggerEls[0]).not.toHaveAttribute("data-state", "open"); + expect(triggerEls[0]).toHaveAttribute("data-disabled"); + + await user.click(triggerEls[1] as HTMLElement); + expect(triggerEls[1]).not.toHaveAttribute("data-state", "open"); + expect(triggerEls[1]).toHaveAttribute("data-disabled"); + + await user.click(triggerEls[2] as HTMLElement); + expect(triggerEls[2]).not.toHaveAttribute("data-state", "open"); + expect(triggerEls[2]).toHaveAttribute("data-disabled"); + }); + + it("displays content when an item is expanded", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionMultiTest as any, { items }); + + for (const item of items) { + const trigger = getByTestId(`${item.value}-trigger`); + const content = getByTestId(`${item.value}-content`); + const itemEl = getByTestId(`${item.value}-item`); + expect(itemEl).toHaveAttribute("data-state", "closed"); + expect(itemEl).toHaveAttribute("data-state", "closed"); + expect(content).not.toBeVisible(); + await user.click(trigger); + const contentAfter = getByTestId(`${item.value}-content`); + expect(contentAfter).toHaveTextContent(item.content); + expect(itemEl).toHaveAttribute("data-state", "open"); + } + }); + + it("expands multiple items", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionMultiTest as any, { + items, }); for (const item of items) { @@ -160,7 +427,7 @@ describe("accordion", () => { it("expands when the trigger is focused and `Enter` key is pressed", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { + const { getByTestId } = render(AccordionMultiTest as any, { items, }); @@ -181,7 +448,7 @@ describe("accordion", () => { it("expands when the trigger is focused and `Space` key is pressed", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { + const { getByTestId } = render(AccordionMultiTest as any, { items, }); @@ -202,7 +469,7 @@ describe("accordion", () => { it("focuses the next item when `ArrowDown` key is pressed", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { items }); + const { getByTestId } = render(AccordionMultiTest as any, { items }); const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); triggers[0]?.focus(); @@ -218,7 +485,7 @@ describe("accordion", () => { it("focuses the previous item when the `ArrowUp` key is pressed", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { items }); + const { getByTestId } = render(AccordionMultiTest as any, { items }); const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); triggers[0]?.focus(); @@ -234,7 +501,7 @@ describe("accordion", () => { it("focuses the first item when the `Home` key is pressed", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { items }); + const { getByTestId } = render(AccordionMultiTest as any, { items }); const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); @@ -247,7 +514,7 @@ describe("accordion", () => { it("focuses the last item when the `End` key is pressed", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { items }); + const { getByTestId } = render(AccordionMultiTest as any, { items }); const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); @@ -260,7 +527,7 @@ describe("accordion", () => { it("respects the `disabled` prop for items", async () => { const user = userEvent.setup(); - const { getByTestId } = render(AccordionSingleTest as any, { items: itemsWithDisabled }); + const { getByTestId } = render(AccordionMultiTest as any, { items: itemsWithDisabled }); const triggers = items.map((item) => getByTestId(`${item.value}-trigger`)); await user.click(triggers[0] as HTMLElement); @@ -277,7 +544,7 @@ describe("accordion", () => { } return item; }); - const { getByTestId } = render(AccordionSingleTest as any, { items: itemsWithLevel }); + const { getByTestId } = render(AccordionMultiTest as any, { items: itemsWithLevel }); const headers = items.map((item) => getByTestId(`${item.value}-header`)); expect(headers[0]).toHaveAttribute("data-heading-level", "1"); @@ -285,4 +552,35 @@ describe("accordion", () => { expect(headers[1]).toHaveAttribute("data-heading-level", "3"); expect(headers[1]).toHaveAttribute("aria-level", "3"); }); + + it("updates the `bind:value` prop when the value changes", async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionMultiTestControlled as any, { items }); + const trigger = getByTestId("item-1-trigger"); + + const value = getByTestId("value"); + + expect(value).toHaveTextContent(""); + + await user.click(trigger); + + expect(value).toHaveTextContent("item-1"); + }); + + it('handles programatic changes to the "value" prop', async () => { + const user = userEvent.setup(); + const { getByTestId } = render(AccordionMultiTestControlled as any, { items }); + const updateButton = getByTestId("update-value"); + const value = getByTestId("value"); + + expect(value).toHaveTextContent(""); + + const itemTwoItem = getByTestId("item-2-item"); + expect(itemTwoItem).toHaveAttribute("data-state", "closed"); + + await user.click(updateButton); + + expect(value).toHaveTextContent("item-2"); + expect(itemTwoItem).toHaveAttribute("data-state", "open"); + }); }); diff --git a/packages/bits-ui/src/tests/accordion/AccordionMultiTest.svelte b/packages/bits-ui/src/tests/accordion/AccordionMultiTest.svelte new file mode 100644 index 000000000..71212752c --- /dev/null +++ b/packages/bits-ui/src/tests/accordion/AccordionMultiTest.svelte @@ -0,0 +1,34 @@ + + + + {#each items as { value, title, disabled, content, level } (value)} + + + + {title} + + + {content} + + {/each} + diff --git a/packages/bits-ui/src/tests/accordion/AccordionMultiTestControlled.svelte b/packages/bits-ui/src/tests/accordion/AccordionMultiTestControlled.svelte new file mode 100644 index 000000000..1bbb489b3 --- /dev/null +++ b/packages/bits-ui/src/tests/accordion/AccordionMultiTestControlled.svelte @@ -0,0 +1,48 @@ + + +
+ {value} +
+ + + + + {#each items as { value, title, disabled, content, level } (value)} + + + + {title} + + + {content} + + {/each} + diff --git a/packages/bits-ui/src/tests/accordion/AccordionSingleTestControlled.svelte b/packages/bits-ui/src/tests/accordion/AccordionSingleTestControlled.svelte new file mode 100644 index 000000000..079d8bb18 --- /dev/null +++ b/packages/bits-ui/src/tests/accordion/AccordionSingleTestControlled.svelte @@ -0,0 +1,43 @@ + + +
+ {value} +
+ + + + + {#each items as { value, title, disabled, content, level }} + + + + {title} + + + {content} + + {/each} + diff --git a/packages/bits-ui/vite.config.ts b/packages/bits-ui/vite.config.ts index a79f37278..1f8e3173c 100644 --- a/packages/bits-ui/vite.config.ts +++ b/packages/bits-ui/vite.config.ts @@ -27,6 +27,5 @@ export default defineConfig({ coverage: { exclude: ["./other/setupTest.ts"], }, - retry: 3, }, });