feat: Reinitialize frontend with SvelteKit and TypeScript

- Delete old Vite+Svelte frontend
- Initialize new SvelteKit project with TypeScript
- Configure Tailwind CSS v4 + DaisyUI
- Implement JWT authentication with auto-refresh
- Create login page with form validation (Zod)
- Add protected route guards
- Update Docker configuration for single-stage build
- Add E2E tests with Playwright (6/11 passing)
- Fix Svelte 5 reactivity with $state() runes

Known issues:
- 5 E2E tests failing (timing/async issues)
- Token refresh implementation needs debugging
- Validation error display timing
This commit is contained in:
2026-02-17 16:19:59 -05:00
parent 54df6018f5
commit de2d83092e
28274 changed files with 3816354 additions and 90 deletions

21
frontend/node_modules/@testing-library/svelte/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Ben Monro <ben.monro@gmail.com> (https://github.com/benmonro)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

259
frontend/node_modules/@testing-library/svelte/README.md generated vendored Normal file
View File

@@ -0,0 +1,259 @@
<div align="center">
<h1>Svelte Testing Library</h1>
<a href="https://www.emojione.com/emoji/1f410">
<img
height="80"
width="80"
alt="chipmunk"
src="https://raw.githubusercontent.com/testing-library/svelte-testing-library/main/other/chipmunk.png"
/>
</a>
<p>Simple and complete Svelte testing utilities that encourage good testing practices.</p>
[**Read The Docs**][stl-docs] | [Edit the docs][stl-docs-repo] | [Examples](./examples)
<!-- prettier-ignore-start -->
[![Build Status][build-badge]][build]
[![Code Coverage][coverage-badge]][coverage]
[![version][version-badge]][package]
[![downloads][downloads-badge]][downloads]
[![MIT License][license-badge]][license]
[![All Contributors][contributors-badge]][contributors]
[![PRs Welcome][prs-badge]][prs]
[![Code of Conduct][coc-badge]][coc]
[![Discord][discord-badge]][discord]
[![Watch on GitHub][github-watch-badge]][github-watch]
[![Star on GitHub][github-star-badge]][github-star]
[![Tweet][twitter-badge]][twitter]
<!-- prettier-ignore-end -->
</div>
<hr />
[stl-docs]: https://testing-library.com/docs/svelte-testing-library/intro
[stl-docs-repo]: https://github.com/testing-library/testing-library-docs
[build-badge]: https://img.shields.io/github/actions/workflow/status/testing-library/svelte-testing-library/release.yml?style=flat-square
[build]: https://github.com/testing-library/svelte-testing-library/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/testing-library/svelte-testing-library.svg?style=flat-square
[coverage]: https://codecov.io/github/testing-library/svelte-testing-library
[version-badge]: https://img.shields.io/npm/v/@testing-library/svelte.svg?style=flat-square
[package]: https://www.npmjs.com/package/@testing-library/svelte
[downloads-badge]: https://img.shields.io/npm/dm/@testing-library/svelte.svg?style=flat-square
[downloads]: http://www.npmtrends.com/@testing-library/svelte
[license-badge]: https://img.shields.io/github/license/testing-library/svelte-testing-library?color=b&style=flat-square
[license]: https://github.com/testing-library/svelte-testing-library/blob/main/LICENSE
[contributors-badge]: https://img.shields.io/badge/all_contributors-8-orange.svg?style=flat-square
[contributors]: #contributors
[prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
[prs]: http://makeapullrequest.com
[coc-badge]: https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square
[coc]: https://github.com/testing-library/svelte-testing-library/blob/main/CODE_OF_CONDUCT.md
[discord-badge]: https://img.shields.io/discord/723559267868737556.svg?color=7389D8&labelColor=6A7EC2&logo=discord&logoColor=ffffff&style=flat-square
[discord]: https://discord.gg/testing-library
[github-watch-badge]: https://img.shields.io/github/watchers/testing-library/svelte-testing-library.svg?style=social
[github-watch]: https://github.com/testing-library/svelte-testing-library/watchers
[github-star-badge]: https://img.shields.io/github/stars/testing-library/svelte-testing-library.svg?style=social
[github-star]: https://github.com/testing-library/svelte-testing-library/stargazers
[twitter]: https://twitter.com/intent/tweet?text=Check%20out%20svelte-testing-library%20by%20%40@TestingLib%20https%3A%2F%2Fgithub.com%2Ftesting-library%2Fsvelte-testing-library%20%F0%9F%91%8D
[twitter-badge]: https://img.shields.io/twitter/url/https/github.com/testing-library/svelte-testing-library.svg?style=social
## Table of Contents
- [The Problem](#the-problem)
- [This Solution](#this-solution)
- [Installation](#installation)
- [Setup](#setup)
- [Auto-cleanup](#auto-cleanup)
- [Docs](#docs)
- [Issues](#issues)
- [🐛 Bugs](#-bugs)
- [💡 Feature Requests](#-feature-requests)
- [❓ Questions](#-questions)
- [Contributors](#contributors)
## The Problem
You want to write maintainable tests for your [Svelte][svelte] components.
[svelte]: https://svelte.dev/
## This Solution
`@testing-library/svelte` is a lightweight library for testing Svelte
components. It provides functions on top of `svelte` and
`@testing-library/dom` so you can mount Svelte components and query their
rendered output in the DOM. Its primary guiding principle is:
> [The more your tests resemble the way your software is used, the more
> confidence they can give you.][guiding-principle]
[guiding-principle]: https://twitter.com/kentcdodds/status/977018512689455106
## Installation
This module is distributed via [npm][npm] which is bundled with [node][node] and
should be installed as one of your project's `devDependencies`:
```shell
npm install --save-dev @testing-library/svelte
```
This library supports `svelte` versions `3`, `4`, and `5`.
You may also be interested in installing `@testing-library/jest-dom` so you can
use [the custom jest matchers][jest-dom].
[npm]: https://www.npmjs.com/
[node]: https://nodejs.org
[jest-dom]: https://github.com/testing-library/jest-dom
## Setup
We recommend using `@testing-library/svelte` with [Vitest][] as your test
runner. To get started, add the `svelteTesting` plugin to your Vite or Vitest
config.
```diff
// vite.config.js
import { svelte } from '@sveltejs/vite-plugin-svelte'
+ import { svelteTesting } from '@testing-library/svelte/vite'
export default defineConfig({
plugins: [
svelte(),
+ svelteTesting(),
]
});
```
See the [setup docs][] for more detailed setup instructions, including for other
test runners like Jest.
[vitest]: https://vitest.dev/
[setup docs]: https://testing-library.com/docs/svelte-testing-library/setup
### Auto-cleanup
In Vitest (via the `svelteTesting` plugin) and Jest (via the `beforeEach` and `afterEach` globals),
this library will automatically setup and cleanup the test environment before and after each test.
To do your own cleanup, or if you're using another framework, call the `setup` and `cleanup` functions yourself:
```js
import { cleanup, render, setup } from '@testing-library/svelte'
// before
setup()
// test
render(/* ... */)
// after
cleanup()
```
To disable auto-cleanup in Vitest, set the `autoCleanup` option of the plugin to false:
```js
svelteTesting({ autoCleanup: false })
```
To disable auto-cleanup in Jest and other frameworks with global test hooks,
set the `STL_SKIP_AUTO_CLEANUP` environment variable:
```shell
STL_SKIP_AUTO_CLEANUP=1 jest
```
## Docs
See the [**docs**][stl-docs] over at the Testing Library website.
## Issues
_Looking to contribute? Look for the [Good First Issue][good-first-issue]
label._
[good-first-issue]: https://github.com/testing-library/svelte-testing-library/issues?utf8=✓&q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3A"good+first+issue"+
### 🐛 Bugs
Please file an issue for bugs, missing documentation, or unexpected behavior.
[**See Bugs**][bugs]
[bugs]: https://github.com/testing-library/svelte-testing-library/issues?q=is%3Aissue+is%3Aopen+label%3Abug+sort%3Acreated-desc
### 💡 Feature Requests
Please file an issue to suggest new features. Vote on feature requests by adding
a 👍. This helps maintainers prioritize what to work on.
[**See Feature Requests**][requests]
[requests]: https://github.com/testing-library/svelte-testing-library/issues?q=is%3Aissue+sort%3Areactions-%2B1-desc+label%3Aenhancement+is%3Aopen
### ❓ Questions
For questions related to using the library, please visit a support community
instead of filing an issue on GitHub.
- [Discord][discord]
- [Stack Overflow][stackoverflow]
[stackoverflow]: https://stackoverflow.com/questions/tagged/svelte-testing-library
## Contributors
Thanks goes to these people ([emoji key][emojis]):
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/benmonro"><img src="https://avatars3.githubusercontent.com/u/399236?v=4?s=100" width="100px;" alt="Ben Monro"/><br /><sub><b>Ben Monro</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=benmonro" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=benmonro" title="Tests">⚠️</a> <a href="#ideas-benmonro" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=benmonro" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/EmilTholin"><img src="https://avatars0.githubusercontent.com/u/11573167?v=4?s=100" width="100px;" alt="Emil Tholin"/><br /><sub><b>Emil Tholin</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=EmilTholin" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=EmilTholin" title="Tests">⚠️</a> <a href="#ideas-EmilTholin" title="Ideas, Planning, & Feedback">🤔</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://medium.com/@oieduardorabelo"><img src="https://avatars1.githubusercontent.com/u/829902?v=4?s=100" width="100px;" alt="Eduardo Rabelo"/><br /><sub><b>Eduardo Rabelo</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=oieduardorabelo" title="Tests">⚠️</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=oieduardorabelo" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=oieduardorabelo" title="Documentation">📖</a> <a href="#example-oieduardorabelo" title="Examples">💡</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://timdeschryver.dev"><img src="https://avatars1.githubusercontent.com/u/28659384?v=4?s=100" width="100px;" alt="Tim Deschryver"/><br /><sub><b>Tim Deschryver</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=timdeschryver" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.ematipico.com"><img src="https://avatars3.githubusercontent.com/u/602478?v=4?s=100" width="100px;" alt="Emanuele"/><br /><sub><b>Emanuele</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=ematipico" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=ematipico" title="Tests">⚠️</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=ematipico" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pngwn"><img src="https://avatars1.githubusercontent.com/u/12937446?v=4?s=100" width="100px;" alt="pngwn"/><br /><sub><b>pngwn</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=pngwn" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=pngwn" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://twitter.com/sebsilbermann"><img src="https://avatars3.githubusercontent.com/u/12292047?v=4?s=100" width="100px;" alt="Sebastian Silbermann"/><br /><sub><b>Sebastian Silbermann</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=eps1lon" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mihar-22"><img src="https://avatars3.githubusercontent.com/u/14304599?s=460&v=4?s=100" width="100px;" alt="Rahim Alwer"/><br /><sub><b>Rahim Alwer</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=mihar-22" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=mihar-22" title="Documentation">📖</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=mihar-22" title="Tests">⚠️</a> <a href="https://github.com/testing-library/svelte-testing-library/pulls?q=is%3Apr+reviewed-by%3Amihar-22" title="Reviewed Pull Requests">👀</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MirrorBytes"><img src="https://avatars3.githubusercontent.com/u/22119469?v=4?s=100" width="100px;" alt="Bob"/><br /><sub><b>Bob</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/issues?q=author%3AMirrorBytes" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=MirrorBytes" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ronmerkin"><img src="https://avatars.githubusercontent.com/u/17492527?v=4?s=100" width="100px;" alt="Ron Merkin"/><br /><sub><b>Ron Merkin</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=ronmerkin" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.benmccann.com"><img src="https://avatars.githubusercontent.com/u/322311?v=4?s=100" width="100px;" alt="Ben McCann"/><br /><sub><b>Ben McCann</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=benmccann" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://johnbowser.dev/"><img src="https://avatars.githubusercontent.com/u/66637570?v=4?s=100" width="100px;" alt="John Bowser"/><br /><sub><b>John Bowser</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=jgbowser" title="Code">💻</a> <a href="https://github.com/testing-library/svelte-testing-library/commits?author=jgbowser" title="Tests">⚠️</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ysitbon"><img src="https://avatars.githubusercontent.com/u/1370679?v=4?s=100" width="100px;" alt="Yoann"/><br /><sub><b>Yoann</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=ysitbon" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://techblog.babyl.ca/"><img src="https://avatars.githubusercontent.com/u/19954?v=4?s=100" width="100px;" alt="Yanick Champoux"/><br /><sub><b>Yanick Champoux</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=yanick" title="Code">💻</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://michael.cousins.io/"><img src="https://avatars.githubusercontent.com/u/2963448?v=4?s=100" width="100px;" alt="Michael Cousins"/><br /><sub><b>Michael Cousins</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=mcous" title="Code">💻</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors][all-contributors] specification.
Contributions of any kind welcome!
[emojis]: https://github.com/all-contributors/all-contributors#emoji-key
[all-contributors]: https://github.com/all-contributors/all-contributors

View File

@@ -0,0 +1,2 @@
export * from "./pure.js";
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":""}

View File

@@ -0,0 +1,103 @@
export * from "@testing-library/dom";
export { UnknownSvelteOptionsError } from "@testing-library/svelte-core";
/**
* Customize how Svelte renders the component.
*/
export type SvelteComponentOptions<C extends import("@testing-library/svelte-core/types").Component> = import("@testing-library/svelte-core/types").ComponentOptions<C>;
/**
* Customize how Testing Library sets up the document and binds queries.
*/
export type RenderOptions<Q extends DomTestingLibrary.Queries = typeof DomTestingLibrary.queries> = import("@testing-library/svelte-core/types").SetupOptions & {
queries?: Q;
};
/**
* The rendered component and bound testing functions.
*/
export type RenderResult<C extends import("@testing-library/svelte-core/types").Component, Q extends DomTestingLibrary.Queries = typeof DomTestingLibrary.queries> = {
container: HTMLElement;
baseElement: HTMLElement;
component: import("@testing-library/svelte-core/types").Exports<C>;
debug: (el?: HTMLElement | DocumentFragment) => void;
rerender: import("@testing-library/svelte-core/types").Rerender<C>;
unmount: () => void;
} & { [P in keyof Q]: DomTestingLibrary.BoundFunction<Q[P]>; };
export type FireFunction = (...args: Parameters<DomTestingLibrary.FireFunction>) => Promise<ReturnType<DomTestingLibrary.FireFunction>>;
export type FireObject = { [K in DomTestingLibrary.EventType]: (...args: Parameters<DomTestingLibrary.FireObject[K]>) => Promise<ReturnType<DomTestingLibrary.FireObject[K]>>; };
/**
* Call a function and wait for Svelte to flush pending changes.
*
* @template T
* @param {() => Promise<T> | T} [fn] - A function, which may be `async`, to call before flushing updates.
* @returns {Promise<T>}
*/
export function act<T>(fn?: () => Promise<T> | T): Promise<T>;
/** Unmount components, remove elements added to `<body>`, and reset `@testing-library/dom`. */
export function cleanup(): void;
/**
* @typedef {(...args: Parameters<DomTestingLibrary.FireFunction>) => Promise<ReturnType<DomTestingLibrary.FireFunction>>} FireFunction
*/
/**
* @typedef {{
* [K in DomTestingLibrary.EventType]: (...args: Parameters<DomTestingLibrary.FireObject[K]>) => Promise<ReturnType<DomTestingLibrary.FireObject[K]>>
* }} FireObject
*/
/**
* Fire an event on an element.
*
* Consider using `@testing-library/user-event` instead, if possible.
* @see https://testing-library.com/docs/user-event/intro/
*
* @type {FireFunction & FireObject}
*/
export const fireEvent: FireFunction & FireObject;
/**
* Customize how Svelte renders the component.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @typedef {import('@testing-library/svelte-core/types').ComponentOptions<C>} SvelteComponentOptions
*/
/**
* Customize how Testing Library sets up the document and binds queries.
*
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
* @typedef {import('@testing-library/svelte-core/types').SetupOptions & { queries?: Q }} RenderOptions
*/
/**
* The rendered component and bound testing functions.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
*
* @typedef {{
* container: HTMLElement
* baseElement: HTMLElement
* component: import('@testing-library/svelte-core/types').Exports<C>
* debug: (el?: HTMLElement | DocumentFragment) => void
* rerender: import('@testing-library/svelte-core/types').Rerender<C>
* unmount: () => void
* } & {
* [P in keyof Q]: DomTestingLibrary.BoundFunction<Q[P]>
* }} RenderResult
*/
/**
* Render a component into the document.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
*
* @param {import('@testing-library/svelte-core/types').ComponentImport<C>} Component - The component to render.
* @param {import('@testing-library/svelte-core/types').ComponentOptions<C>} options - Customize how Svelte renders the component.
* @param {RenderOptions<Q>} renderOptions - Customize how Testing Library sets up the document and binds queries.
* @returns {RenderResult<C, Q>} The rendered component and bound testing functions.
*/
export function render<C extends import("@testing-library/svelte-core/types").Component, Q extends DomTestingLibrary.Queries = typeof DomTestingLibrary.queries>(Component: import("@testing-library/svelte-core/types").ComponentImport<C>, options?: import("@testing-library/svelte-core/types").ComponentOptions<C>, renderOptions?: RenderOptions<Q>): RenderResult<C, Q>;
/**
* Configure `@testing-library/dom` for usage with Svelte.
*
* Ensures events fired from `@testing-library/dom`
* and `@testing-library/user-event` wait for Svelte
* to flush changes to the DOM before proceeding.
*/
export function setup(): void;
import * as DomTestingLibrary from '@testing-library/dom';
//# sourceMappingURL=pure.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"pure.d.ts","sourceRoot":"","sources":["../src/pure.js"],"names":[],"mappings":";;;;;mCAOsE,CAAC,SAA1D,OAAQ,oCAAoC,EAAE,SAAU,IACxD,OAAO,oCAAoC,EAAE,gBAAgB,CAAC,CAAC,CAAC;;;;0BAMnC,CAAC,SAA7B,iBAAiB,CAAC,OAAQ,uCAC3B,OAAO,oCAAoC,EAAE,YAAY,GAAG;IAAE,OAAO,CAAC,EAAE,CAAC,CAAA;CAAE;;;;yBAMlB,CAAC,SAA1D,OAAQ,oCAAoC,EAAE,SAAU,EAC3B,CAAC,SAA7B,iBAAiB,CAAC,OAAQ,uCAE3B;IACR,SAAS,EAAE,WAAW,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,OAAO,oCAAoC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IAClE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,WAAW,GAAG,gBAAgB,KAAK,IAAI,CAAA;IACpD,QAAQ,EAAE,OAAO,oCAAoC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;IAClE,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,GACD,CAAC,IAAI,MAAM,CAAC,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACtD;2BA+ES,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,iBAAiB,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;yBAI5G,GACP,CAAC,IAAI,iBAAiB,CAAC,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GACnJ;AAvBJ;;;;;;GAMG;AACH,oBAJa,CAAC,OACH,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAClB,OAAO,CAAC,CAAC,CAAC,CAStB;AAnBD,+FAA+F;AAC/F,gCAEC;AAkBD;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAFU,YAAY,GAAG,UAAU,CAIlC;AA/HD;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;GAUG;AACH,uBARsE,CAAC,SAA1D,OAAQ,oCAAoC,EAAE,SAAU,EAC3B,CAAC,SAA7B,iBAAiB,CAAC,OAAQ,gDAE7B,OAAO,oCAAoC,EAAE,eAAe,CAAC,CAAC,CAAC,YAC/D,OAAO,oCAAoC,EAAE,gBAAgB,CAAC,CAAC,CAAC,kBAChE,aAAa,CAAC,CAAC,CAAC,GACd,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAuB9B;AAED;;;;;;GAMG;AACH,8BAWC;mCAxFkC,sBAAsB"}

View File

@@ -0,0 +1,6 @@
export function svelteTesting({ resolveBrowser, autoCleanup, noExternal, }?: {
resolveBrowser?: boolean;
autoCleanup?: boolean;
noExternal?: boolean;
}): import("vite").Plugin;
//# sourceMappingURL=vite.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.js"],"names":[],"mappings":"AAcO,6EAHI;IAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAC,GACrE,OAAO,MAAM,EAAE,MAAM,CAyBhC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=vitest.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"vitest.d.ts","sourceRoot":"","sources":["../src/vitest.js"],"names":[],"mappings":""}

View File

@@ -0,0 +1,80 @@
{
"name": "@testing-library/svelte",
"version": "5.3.1",
"description": "Simple and complete Svelte testing utilities that encourage good testing practices.",
"main": "src/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./src/index.js"
},
"./pure": {
"types": "./dist/pure.d.ts",
"default": "./src/pure.js"
},
"./svelte5": {
"types": "./dist/index.d.ts",
"default": "./src/index.js"
},
"./vitest": {
"types": "./dist/vitest.d.ts",
"default": "./src/vitest.js"
},
"./vite": {
"types": "./dist/vite.d.ts",
"default": "./src/vite.js"
}
},
"type": "module",
"types": "dist/index.d.ts",
"license": "MIT",
"homepage": "https://github.com/testing-library/svelte-testing-library#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/testing-library/svelte-testing-library.git",
"directory": "packages/svelte"
},
"bugs": {
"url": "https://github.com/testing-library/svelte-testing-library/issues"
},
"engines": {
"node": ">= 10"
},
"keywords": [
"testing",
"svelte",
"ui",
"dom",
"jsdom",
"unit",
"integration",
"functional",
"end-to-end",
"e2e"
],
"files": [
"src",
"dist"
],
"peerDependencies": {
"svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0",
"vite": "*",
"vitest": "*"
},
"peerDependenciesMeta": {
"vite": {
"optional": true
},
"vitest": {
"optional": true
}
},
"dependencies": {
"@testing-library/dom": "9.x.x || 10.x.x",
"@testing-library/svelte-core": "1.0.0"
},
"publishConfig": {
"access": "public",
"provenance": true
}
}

View File

@@ -0,0 +1,22 @@
import { act, cleanup, setup } from './pure.js'
// If we're running in a test runner that supports beforeEach/afterEach
// we'll automatically run setup and cleanup before and after each test
// this ensures that tests run in isolation from each other
// if you don't like this then set the STL_SKIP_AUTO_CLEANUP env variable.
if (typeof process !== 'undefined' && !process.env.STL_SKIP_AUTO_CLEANUP) {
if (typeof beforeEach === 'function') {
beforeEach(() => {
setup()
})
}
if (typeof afterEach === 'function') {
afterEach(async () => {
await act()
cleanup()
})
}
}
export * from './pure.js'

View File

@@ -0,0 +1,140 @@
import * as DomTestingLibrary from '@testing-library/dom'
import * as Core from '@testing-library/svelte-core'
import * as Svelte from 'svelte'
/**
* Customize how Svelte renders the component.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @typedef {import('@testing-library/svelte-core/types').ComponentOptions<C>} SvelteComponentOptions
*/
/**
* Customize how Testing Library sets up the document and binds queries.
*
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
* @typedef {import('@testing-library/svelte-core/types').SetupOptions & { queries?: Q }} RenderOptions
*/
/**
* The rendered component and bound testing functions.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
*
* @typedef {{
* container: HTMLElement
* baseElement: HTMLElement
* component: import('@testing-library/svelte-core/types').Exports<C>
* debug: (el?: HTMLElement | DocumentFragment) => void
* rerender: import('@testing-library/svelte-core/types').Rerender<C>
* unmount: () => void
* } & {
* [P in keyof Q]: DomTestingLibrary.BoundFunction<Q[P]>
* }} RenderResult
*/
/**
* Render a component into the document.
*
* @template {import('@testing-library/svelte-core/types').Component} C
* @template {DomTestingLibrary.Queries} [Q=typeof DomTestingLibrary.queries]
*
* @param {import('@testing-library/svelte-core/types').ComponentImport<C>} Component - The component to render.
* @param {import('@testing-library/svelte-core/types').ComponentOptions<C>} options - Customize how Svelte renders the component.
* @param {RenderOptions<Q>} renderOptions - Customize how Testing Library sets up the document and binds queries.
* @returns {RenderResult<C, Q>} The rendered component and bound testing functions.
*/
const render = (Component, options = {}, renderOptions = {}) => {
const { baseElement, container, component, unmount, rerender } = Core.render(
Component,
options,
renderOptions
)
const queries = DomTestingLibrary.getQueriesForElement(
baseElement,
renderOptions.queries
)
return {
baseElement,
container,
component,
rerender,
unmount,
debug: (el = baseElement) => console.log(DomTestingLibrary.prettyDOM(el)),
...queries,
}
}
/**
* Configure `@testing-library/dom` for usage with Svelte.
*
* Ensures events fired from `@testing-library/dom`
* and `@testing-library/user-event` wait for Svelte
* to flush changes to the DOM before proceeding.
*/
const setup = () => {
const originalConfig = DomTestingLibrary.getConfig()
DomTestingLibrary.configure({
asyncWrapper: act,
eventWrapper: Svelte.flushSync ?? ((cb) => cb()),
})
Core.addCleanupTask(() => {
DomTestingLibrary.configure(originalConfig)
})
}
/** Unmount components, remove elements added to `<body>`, and reset `@testing-library/dom`. */
const cleanup = () => {
Core.cleanup()
}
/**
* Call a function and wait for Svelte to flush pending changes.
*
* @template T
* @param {() => Promise<T> | T} [fn] - A function, which may be `async`, to call before flushing updates.
* @returns {Promise<T>}
*/
const act = async (fn) => {
let result
if (fn) {
result = await fn()
}
await Svelte.tick()
return result
}
/**
* @typedef {(...args: Parameters<DomTestingLibrary.FireFunction>) => Promise<ReturnType<DomTestingLibrary.FireFunction>>} FireFunction
*/
/**
* @typedef {{
* [K in DomTestingLibrary.EventType]: (...args: Parameters<DomTestingLibrary.FireObject[K]>) => Promise<ReturnType<DomTestingLibrary.FireObject[K]>>
* }} FireObject
*/
/**
* Fire an event on an element.
*
* Consider using `@testing-library/user-event` instead, if possible.
* @see https://testing-library.com/docs/user-event/intro/
*
* @type {FireFunction & FireObject}
*/
const fireEvent = async (...args) => {
return act(() => DomTestingLibrary.fireEvent(...args))
}
for (const [key, baseEvent] of Object.entries(DomTestingLibrary.fireEvent)) {
fireEvent[key] = async (...args) => act(() => baseEvent(...args))
}
export * from '@testing-library/dom'
export { UnknownSvelteOptionsError } from '@testing-library/svelte-core'
export { act, cleanup, fireEvent, render, setup }

View File

@@ -0,0 +1,133 @@
import path from 'node:path'
import url from 'node:url'
const STL_PACKAGES = ['@testing-library/svelte', '@testing-library/svelte-core']
/**
* Vite plugin to configure @testing-library/svelte.
*
* Ensures Svelte is imported correctly in tests
* and that the DOM is cleaned up after each test.
*
* @param {{resolveBrowser?: boolean, autoCleanup?: boolean, noExternal?: boolean}} options
* @returns {import('vite').Plugin}
*/
export const svelteTesting = ({
resolveBrowser = true,
autoCleanup = true,
noExternal = true,
} = {}) => ({
name: 'vite-plugin-svelte-testing-library',
config: (config) => {
if (!process.env.VITEST) {
return
}
if (resolveBrowser) {
addBrowserCondition(config)
}
if (autoCleanup) {
addAutoCleanup(config)
}
if (noExternal) {
addNoExternal(config)
}
},
})
/**
* Add `browser` to `resolve.conditions` before `node`.
*
* This ensures that Svelte's browser code is used in tests,
* rather than its SSR code.
*
* @param {import('vitest/config').UserConfig} config
*/
const addBrowserCondition = (config) => {
const resolve = config.resolve ?? {}
const conditions = resolve.conditions ?? []
const nodeConditionIndex = conditions.indexOf('node')
const browserConditionIndex = conditions.indexOf('browser')
if (
nodeConditionIndex !== -1 &&
(nodeConditionIndex < browserConditionIndex || browserConditionIndex === -1)
) {
conditions.splice(nodeConditionIndex, 0, 'browser')
}
resolve.conditions = conditions
config.resolve = resolve
}
/**
* Add auto-cleanup file to Vitest's setup files.
*
* @param {import('vitest/config').UserConfig} config
*/
const addAutoCleanup = (config) => {
const test = config.test ?? {}
let setupFiles = test.setupFiles ?? []
if (test.globals) {
return
}
if (typeof setupFiles === 'string') {
setupFiles = [setupFiles]
}
setupFiles.push(
path.join(path.dirname(url.fileURLToPath(import.meta.url)), './vitest.js')
)
test.setupFiles = setupFiles
config.test = test
}
/**
* Add `@testing-library/svelte` to Vite's noExternal rules, if not present.
*
* This ensures `@testing-library/svelte` is processed by `@sveltejs/vite-plugin-svelte`
* in certain monorepo setups.
*/
const addNoExternal = (config) => {
const ssr = config.ssr ?? {}
let noExternal = ssr.noExternal ?? []
if (noExternal === true) {
return
}
if (typeof noExternal === 'string' || noExternal instanceof RegExp) {
noExternal = [noExternal]
}
if (!Array.isArray(noExternal)) {
return
}
const missingPackages = []
for (const packageName of STL_PACKAGES) {
const isIncluded = noExternal.some(
(rule) =>
(typeof rule === 'string' && rule === packageName) ||
(rule instanceof RegExp && rule.test(packageName))
)
if (!isIncluded) {
missingPackages.push(packageName)
}
}
if (missingPackages.length === 0) {
return
}
noExternal.push(...missingPackages)
ssr.noExternal = noExternal
config.ssr = ssr
}

View File

@@ -0,0 +1,11 @@
import { act, cleanup, setup } from '@testing-library/svelte'
import { beforeEach } from 'vitest'
beforeEach(() => {
setup()
return async () => {
await act()
cleanup()
}
})