Repository: skeletonlabs/floating-ui-svelte (ts)

Issue:
Chore: Add automatic cleanup for our unit tests
We're currently manually calling `cleanup`. This can be done automatically by adding another import to our `setup` file.

See: https://testing-library.com/docs/svelte-testing-library/api#cleanup

Pull request:
Chore: autocleanup
Closes #80 

Patch:
diff --git a/.changeset/config.json b/.changeset/config.json
index e7aa985..f9654a0 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -1,10 +1,10 @@
 {
 	"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
-	"changelog": "@changesets/cli/changelog",
+	"changelog": ["@changesets/cli/changelog", { "repo": "skeletonlabs/floating-ui-svelte" }],
 	"commit": false,
 	"fixed": [],
 	"linked": [],
-	"access": "restricted",
+	"access": "public",
 	"baseBranch": "dev",
 	"updateInternalDependencies": "patch",
 	"ignore": []
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..295485d
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,13 @@
+# These are supported funding model platforms
+
+github: [skeletonlabs]
+patreon: 'user?u=83786276' # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: skeletonlabs # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
+custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..9668c81
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,38 @@
+name: 🐞 Bug
+description: Report an issue or bug
+labels: [bug]
+body:
+  - type: textarea
+    attributes:
+      label: Current Behavior
+      description: A description of what you're experiencing.
+    validations:
+      required: false
+  - type: textarea
+    attributes:
+      label: Expected Behavior
+      description: A description of what you're experiencing.
+    validations:
+      required: false
+  - type: textarea
+    attributes:
+      label: Steps To Reproduce
+      description: Describe how to reproduce the issue.
+      placeholder: |
+        1. Using this component...
+        2. With these properties...
+        3. Click '...'
+        4. See error...
+    validations:
+      required: false
+  - type: input
+    id: reproduction
+    attributes:
+      label: Link to Reproduction / Stackblitz
+  - type: textarea
+    attributes:
+      label: More Information
+      description: |
+        Provide relevant links or additionl information.
+    validations:
+      required: false
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 0000000..26aba2e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: true
+contact_links:
+  - name: Get support on Discord
+    url: https://discord.com/channels/1003691521280856084/1003691521721245792
+    about: Reach out on Discord in the floating-ui-svelte channel
+  - name: Ask a question, give feedback, share your project
+    url: https://github.com/skeletonlabs/floating-ui-svelte/discussions
+    about: Connect with other community members with GitHub discussions
diff --git a/.github/ISSUE_TEMPLATE/docs_issue.yml b/.github/ISSUE_TEMPLATE/docs_issue.yml
new file mode 100644
index 0000000..0425522
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/docs_issue.yml
@@ -0,0 +1,12 @@
+name: 📗 Report Docs Issue
+description: Use this to report a typo or incorrect information.
+labels: [documentation]
+body:
+  - type: input
+    id: link
+    attributes:
+      label: Link to the Page
+  - type: textarea
+    id: quote
+    attributes:
+      label: Describe the Issue (screenshots encouraged!)
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..50682f8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,12 @@
+name: 🛠️ Request New Feature
+description: Let us know what you would like to see added.
+labels: ['feature request']
+body:
+  - type: textarea
+    id: description
+    attributes:
+      label: Describe the feature in detail (code, mocks, or screenshots encouraged)
+  - type: textarea
+    id: references
+    attributes:
+      label: Provide relevant links or additional information.
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..1ac6cb3
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,30 @@
+## Linked Issue
+
+Closes #{issueNumber}
+
+## Description
+
+{description}
+
+## Changsets
+
+We use [Changesets](https://github.com/changesets/changesets) to automatically create our changelog per each release. Any changes or additions to the Library assets in `/lib` must be documented with a new Changeset. This can be done as follows:
+
+2. Navigate to the root of the project on your feature branch.
+3. Run `pnpm changeset` to trigger the Changeset CLI.
+4. Follow the instructions when prompted.
+    - Changesets should be either `minor` or `patch`. Never `major`.
+    - Prefix your Changeset description using: `docs:`, `feature:`, `chore:` or `bugfix:`.
+5. Changeset `.md` files are added to the `/.changeset` directory.
+6. Commit and push the the new changeset file.
+
+## Checklist
+
+Please read and apply all [contribution requirements](https://github.com/skeletonlabs/floating-ui-svelte/blob/chore/main/CONTRIBUTING.md).
+
+- [ ] PR targets the `dev` branch (NEVER `master`)
+- [ ] All website documentation is current with your changes
+- [ ] Ensure Prettier formatting is current - run `pnpm format`
+- [ ] Ensure Prettier linting is current - run `pnpm format`
+- [ ] All test cases are passing - run `pnpm vitest`
+- [ ] Includes a changeset (if relevant; see above)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f6996eb..5ba91e6 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -37,3 +37,10 @@ jobs:
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
           NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+
+      - name: Merge main into dev after publish
+        if: steps.changesets.outputs.published == 'true'
+        run: |
+          git checkout dev
+          git merge main
+          git push
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..ec80562
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,113 @@
+# Contributing
+
+This project is created using [SvelteKit](https://kit.svelte.dev/), [Tailwind](https://tailwindcss.com/) for styling, and [pnpm](https://pnpm.io/) for package management.
+
+## How to Contribute
+
+Take care to read all contributions guidelines before you begin!
+
+1. Learn how to [contribute to open source](https://opensource.guide/how-to-contribute/).
+2. Follow a [step-by-step guide](https://github.com/firstcontributions/first-contributions) to practice your first contribution.
+3. Locate an [open issue on GitHub](https://github.com/skeletonlabs/floating-ui-svelte/issues). Let us know you would like to volunteer.
+4. Optionally, you may coordinate efforts on the `#contributors` channel within [Discord](https://discord.gg/EXqV7W8MtY).
+5. If the maintainers approves your request, you'll be assigned to the issue.
+6. Complete the work and submit a pull request and we'll review the changes.
+
+> NOTE: non-trivial PRs submitted without our prior consent will be denied. Repeat offenders will be banned.
+
+## Using PNPM
+
+Floating UI Sveltes makes use of [PNPM](https://pnpm.io/).
+
+1. [Install PNPM](https://pnpm.io/installation) on your local computer.
+2. [Fork the repository](https://github.com/skeletonlabs/floating-ui-svelte) via your preferred option.
+3. Use Git to clone the forked project to your local machine.
+4. Point your terminal at the project.
+5. Run `pnpm i` to install the required depedencies.
+6. Run `pnpm dev` to start a local dev server.
+
+## Project Structure
+
+The floating UI Svelte project is built using SvelteKit to handle both the documentation and library assets.
+
+| Path | Description |
+| --- | --- |
+| Documentation | Found in the `/src/routes` directory. |
+| Library | Found in the `/src/lib` directory. |
+
+## Branch
+
+Floating UI Svelte uses two primary branches. All pull requests should be created again the `dev` branch.
+
+| Branch | Description | Pull Requests |
+| --- | --- | --- |
+| `dev` | The developement branch. | Allowed |
+| `main` | The release branch. | Never |
+
+### PR Branch Conventions
+
+Please use the following naming convention when creating your pull request.
+
+| Branch | Role |
+| --- | --- |
+| `docs/*` | Updates for the documentation site. |
+| `feature/*` | When implementing a new feature. |
+| `chore/*` | When implementing small changes. |
+| `bugfix/*` | When implementing feature bugfixes. |
+
+Keep branch names short and semantic, using dashes to seperate words.
+
+```
+docs/getting-started-typo-fix
+bugfix/fixed-use-floating-bug
+```
+
+## Changesets
+
+[Changesets](https://github.com/changesets/changesets) are used to automatically generate the changelog for each release. Any contributions made to projects that live within the `/lib` directory must contain a Changeset. Use the following instructions to generate a changeset.
+
+1. Make sure you're within local pull request feature branch.
+2. Navigate to the root of the project.
+3. Run `pnpm changeset` to trigger the Changeset CLI.
+4. Follow the instructions when prompted.
+5. Changeset are added to the `/.changeset` directory.
+6. Commit and push the the new changeset file.
+
+Changesets use semantic version. We recommend the following convention.
+
+| Version | Role |
+| --- | --- |
+| `major` | Do not use. Reserved for maintainers. |
+| `minor` | For notable changes, such as a new features. |
+| `patch` | For small changes, such as a chore or typo. |
+
+Changeset descriptions will appear verbatim on the [Changelog](https://github.com/skeletonlabs/skeleton/blob/dev/packages/skeleton/CHANGELOG.md). Keep it short, semantic, and prefix this like branch names.
+
+```mdx
+---
+'@skeletonlabs/floating-ui-svelte': minor
+---
+
+feat: Added a new useFoo hook.
+```
+
+## Tooling
+
+Floating UI Svelte makes use of the following technology for improving the developer experience.
+
+### Prettier
+
+We use [Prettier](https://prettier.io/) for code formatting and linting.
+
+```console
+pnpm format
+pnpm lint
+```
+
+### Test Suite
+
+Unit tests are handled via [Vitest](https://vitest.dev/).
+
+```console
+pnpm vitest
+```
diff --git a/package.json b/package.json
index b6af20f..ecf2641 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,6 @@
 		"build:docs": "svelte-kit sync && vite build",
 		"build:package": "svelte-kit sync && svelte-package && publint",
 		"ci:publish": "pnpm build:package && changeset publish",
-		"publish": "pnpm build:package && changeset publish",
 		"test": "vitest run --coverage",
 		"test:watch": "vitest run --coverage --watch",
 		"format": "prettier --write .",
diff --git a/vite.config.ts b/vite.config.ts
index 65e4ef4..c336675 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -6,14 +6,11 @@ export default defineConfig({
 	plugins: [sveltekit(), svelteTesting()],
 	test: {
 		include: ['./src/lib/**/*.{test,test.svelte}.{js,ts}'],
-		setupFiles: ['./src/vitest-setup.js'],
+		setupFiles: ['./src/vitest.setup.ts'],
 		environment: 'jsdom',
 		coverage: {
 			reporter: ['html', 'text'],
 			include: ['./src/lib/**/*.{js,ts}'],
 		},
-		alias: {
-			'@testing-library/svelte': '@testing-library/svelte/svelte5',
-		},
 	},
 });


Test patch:
diff --git a/src/lib/components/FloatingArrow/FloatingArrow.test.svelte.ts b/src/lib/components/FloatingArrow/FloatingArrow.test.svelte.ts
index cc284d9..d334e38 100644
--- a/src/lib/components/FloatingArrow/FloatingArrow.test.svelte.ts
+++ b/src/lib/components/FloatingArrow/FloatingArrow.test.svelte.ts
@@ -1,13 +1,11 @@
-import { afterEach, describe, expect, it } from 'vitest';
-import { screen, cleanup, render } from '@testing-library/svelte';
+import { describe, expect, it } from 'vitest';
+import { screen, render } from '@testing-library/svelte/svelte5';
 import { withEffect } from '$lib/utils/test.svelte.js';
 
 import FloatingArrow from './FloatingArrow.svelte';
 import { useFloating } from '$lib/hooks/useFloating/index.svelte.js';
 
 describe('FloatingArrow', () => {
-	afterEach(() => cleanup());
-
 	it(
 		'renders the component to default props',
 		withEffect(() => {
diff --git a/src/lib/hooks/useClick/index.test.svelte.ts b/src/lib/hooks/useClick/index.test.svelte.ts
index e6597f3..0bf4bfd 100644
--- a/src/lib/hooks/useClick/index.test.svelte.ts
+++ b/src/lib/hooks/useClick/index.test.svelte.ts
@@ -1,5 +1,5 @@
 import { describe, expect, it, vi } from 'vitest';
-import { cleanup, fireEvent, render, screen } from '@testing-library/svelte';
+import { fireEvent, render, screen } from '@testing-library/svelte/svelte5';
 import App from './App.test.svelte';
 
 describe('useClick', () => {
@@ -26,8 +26,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 		it('disables the hook when `enabled` is `false`', async () => {
 			render(App, { enabled: false });
@@ -39,8 +37,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 	});
 
@@ -55,8 +51,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 
 		it('opens on click when `event` is set to `click`', async () => {
@@ -69,8 +63,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 
 		it('opens on mousedown when `event` is set to `mousedown`', async () => {
@@ -83,8 +75,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 	});
 
@@ -105,8 +95,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 
 		it('when set to `true` changes `open` state to both `true` and `false`', async () => {
@@ -125,8 +113,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 
 		it('when set to `true` changes `open` state to `false` when `open` is initially set to `true`', async () => {
@@ -139,8 +125,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 
 		it('when set to `false` changes `open` state to `true` and not back to `false`', async () => {
@@ -159,8 +143,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 		it('when set to `false` does not change `open` state back to `false` when `open` is initially set to `true`', async () => {
 			render(App, { toggle: false, open: true });
@@ -172,8 +154,6 @@ describe('useClick', () => {
 			await vi.waitFor(() => {
 				expect(screen.queryByRole('tooltip')).toBeInTheDocument();
 			});
-
-			cleanup();
 		});
 	});
 
@@ -184,8 +164,6 @@ describe('useClick', () => {
 			await fireEvent.keyDown(screen.getByRole('button'), { key: 'Enter' });
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 
 		it('when set to `true` returns a `Space` keyup event handler', async () => {
@@ -195,8 +173,6 @@ describe('useClick', () => {
 			await fireEvent.keyUp(screen.getByRole('button'), { key: ' ' });
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 
 		it('when applied to a typable reference does not return a `Space` key event handler', async () => {
@@ -206,8 +182,6 @@ describe('useClick', () => {
 			await fireEvent.keyUp(screen.getByRole('button'), { key: ' ' });
 
 			expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
-
-			cleanup();
 		});
 
 		it('when applied to a typable reference does not return a `Enter` key event handler', async () => {
@@ -216,8 +190,6 @@ describe('useClick', () => {
 			await fireEvent.keyDown(screen.getByRole('button'), { key: 'Enter' });
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 	});
 	it('does not change `open` state to `false` on mouseleave when paired with `useHover`', async () => {
@@ -228,7 +200,5 @@ describe('useClick', () => {
 		await fireEvent.mouseLeave(screen.getByRole('button'));
 
 		expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-		cleanup();
 	});
 });
diff --git a/src/lib/hooks/useHover/index.test.svelte.ts b/src/lib/hooks/useHover/index.test.svelte.ts
index 512e7aa..58fe957 100644
--- a/src/lib/hooks/useHover/index.test.svelte.ts
+++ b/src/lib/hooks/useHover/index.test.svelte.ts
@@ -1,5 +1,5 @@
 import { describe, expect, it, vi } from 'vitest';
-import { render, screen, fireEvent, cleanup, act } from '@testing-library/svelte';
+import { render, screen, fireEvent, act } from '@testing-library/svelte/svelte5';
 import App from './App.test.svelte';
 
 vi.useFakeTimers();
@@ -10,8 +10,6 @@ describe('useHover', () => {
 
 		await fireEvent.mouseEnter(screen.getByRole('button'));
 		expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-		cleanup();
 	});
 
 	it('closes on mouseleave', async () => {
@@ -20,8 +18,6 @@ describe('useHover', () => {
 		await fireEvent.mouseEnter(screen.getByRole('button'));
 		await fireEvent.mouseLeave(screen.getByRole('button'));
 		expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
-
-		cleanup();
 	});
 
 	describe('delay', () => {
@@ -41,8 +37,6 @@ describe('useHover', () => {
 			});
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 		it('delays only open when only open is provided a value', async () => {
 			render(App, { delay: { open: 100 } });
@@ -60,8 +54,6 @@ describe('useHover', () => {
 			});
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 		it('delays only close when only close is provided a value', async () => {
 			render(App, { delay: { close: 100 } });
@@ -80,8 +72,6 @@ describe('useHover', () => {
 			});
 
 			expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
-
-			cleanup();
 		});
 	});
 
@@ -110,8 +100,6 @@ describe('useHover', () => {
 			});
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 
 		it('restMs + nullish open delay should respect restMs', async () => {
@@ -128,8 +116,6 @@ describe('useHover', () => {
 			await act(async () => {
 				vi.advanceTimersByTime(1);
 			});
-
-			cleanup();
 		});
 
 		it.skip('ignores restMs on touch pointers', async () => {
@@ -141,8 +127,6 @@ describe('useHover', () => {
 			await act(async () => {});
 
 			expect(screen.queryByRole('tooltip')).toBeInTheDocument();
-
-			cleanup();
 		});
 
 		it('ignores restMs on touch pointers when mouseOnly is true ', async () => {
@@ -154,8 +138,6 @@ describe('useHover', () => {
 			await act(async () => {});
 
 			expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
-
-			cleanup();
 		});
 	});
 
@@ -174,7 +156,5 @@ describe('useHover', () => {
 		});
 
 		expect(screen.queryByRole('tooltip')).not.toBeInTheDocument();
-
-		cleanup();
 	});
 });
diff --git a/src/lib/hooks/useRole/index.test.svelte.ts b/src/lib/hooks/useRole/index.test.svelte.ts
index 737c1ec..5729bb5 100644
--- a/src/lib/hooks/useRole/index.test.svelte.ts
+++ b/src/lib/hooks/useRole/index.test.svelte.ts
@@ -1,5 +1,5 @@
 import { describe, it, expect } from 'vitest';
-import { cleanup, render, screen } from '@testing-library/svelte';
+import { render, screen } from '@testing-library/svelte/svelte5';
 import App from './App.test.svelte';
 
 const ARIA_ROLES = ['grid', 'listbox', 'menu', 'tree', 'tooltip', 'alertdialog', 'dialog'] as const;
@@ -8,14 +8,12 @@ describe('useRole', () => {
 	it('by default applies the "dialog" role to the floating element', () => {
 		render(App, { role: undefined, open: true });
 		expect(screen.queryByRole('dialog')).toBeInTheDocument();
-		cleanup();
 	});
 
 	for (const role of ARIA_ROLES) {
 		it(`applies the "${role}" role to the floating element`, () => {
 			render(App, { role, open: true });
 			expect(screen.queryByRole(role)).toBeInTheDocument();
-			cleanup();
 		});
 	}
 
@@ -31,8 +29,6 @@ describe('useRole', () => {
 			await rerender({ role: 'tooltip', open: false });
 
 			expect(screen.getByRole('buton')).not.toHaveAttribute('aria-describedby');
-
-			cleanup();
 		});
 	});
 
@@ -48,8 +44,6 @@ describe('useRole', () => {
 			await rerender({ role: 'tooltip', open: false });
 
 			expect(screen.getByRole('buton')).not.toHaveAttribute('aria-labelledby');
-
-			cleanup();
 		});
 	});
 
diff --git a/src/vitest-setup.js b/src/vitest-setup.js
deleted file mode 100644
index bb02c60..0000000
--- a/src/vitest-setup.js
+++ /dev/null
@@ -1,1 +0,0 @@
-import '@testing-library/jest-dom/vitest';
diff --git a/src/vitest.setup.ts b/src/vitest.setup.ts
new file mode 100644
index 0000000..d33291e
--- /dev/null
+++ b/src/vitest.setup.ts
@@ -0,0 +1,15 @@
+/**
+ * Injects additional jest matchers, see: https://testing-library.com/docs/svelte-testing-library/setup#vitest
+ */
+import '@testing-library/jest-dom/vitest';
+
+/**
+ * Injects a global afterEach to cleanup, see: https://testing-library.com/docs/svelte-testing-library/api#cleanup
+ */
+import { afterEach } from 'vitest';
+import { act, cleanup } from '@testing-library/svelte/svelte5';
+
+afterEach(async () => {
+	await act();
+	cleanup();
+});