@testing-library/svelte 5.2.7 → 5.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,9 +12,10 @@
12
12
 
13
13
  <p>Simple and complete Svelte testing utilities that encourage good testing practices.</p>
14
14
 
15
- [**Read The Docs**][stl-docs] | [Edit the docs][stl-docs-repo]
15
+ [**Read The Docs**][stl-docs] | [Edit the docs][stl-docs-repo] | [Examples](./examples)
16
16
 
17
17
  <!-- prettier-ignore-start -->
18
+
18
19
  [![Build Status][build-badge]][build]
19
20
  [![Code Coverage][coverage-badge]][coverage]
20
21
  [![version][version-badge]][package]
@@ -29,7 +30,9 @@
29
30
  [![Watch on GitHub][github-watch-badge]][github-watch]
30
31
  [![Star on GitHub][github-star-badge]][github-star]
31
32
  [![Tweet][twitter-badge]][twitter]
33
+
32
34
  <!-- prettier-ignore-end -->
35
+
33
36
  </div>
34
37
 
35
38
  <hr />
@@ -63,13 +66,11 @@
63
66
 
64
67
  ## Table of Contents
65
68
 
66
- <!-- START doctoc generated TOC please keep comment here to allow auto update -->
67
- <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
68
-
69
69
  - [The Problem](#the-problem)
70
70
  - [This Solution](#this-solution)
71
71
  - [Installation](#installation)
72
72
  - [Setup](#setup)
73
+ - [Auto-cleanup](#auto-cleanup)
73
74
  - [Docs](#docs)
74
75
  - [Issues](#issues)
75
76
  - [🐛 Bugs](#-bugs)
@@ -77,8 +78,6 @@
77
78
  - [❓ Questions](#-questions)
78
79
  - [Contributors](#contributors)
79
80
 
80
- <!-- END doctoc generated TOC please keep comment here to allow auto update -->
81
-
82
81
  ## The Problem
83
82
 
84
83
  You want to write maintainable tests for your [Svelte][svelte] components.
@@ -140,6 +139,39 @@ test runners like Jest.
140
139
  [vitest]: https://vitest.dev/
141
140
  [setup docs]: https://testing-library.com/docs/svelte-testing-library/setup
142
141
 
142
+ ### Auto-cleanup
143
+
144
+ In Vitest (via the `svelteTesting` plugin) and Jest (via the `beforeEach` and `afterEach` globals),
145
+ this library will automatically setup and cleanup the test environment before and after each test.
146
+
147
+ To do your own cleanup, or if you're using another framework, call the `setup` and `cleanup` functions yourself:
148
+
149
+ ```js
150
+ import { cleanup, render, setup } from '@testing-library/svelte'
151
+
152
+ // before
153
+ setup()
154
+
155
+ // test
156
+ render(/* ... */)
157
+
158
+ // after
159
+ cleanup()
160
+ ```
161
+
162
+ To disable auto-cleanup in Vitest, set the `autoCleanup` option of the plugin to false:
163
+
164
+ ```js
165
+ svelteTesting({ autoCleanup: false })
166
+ ```
167
+
168
+ To disable auto-cleanup in Jest and other frameworks with global test hooks,
169
+ set the `STL_SKIP_AUTO_CLEANUP` environment variable:
170
+
171
+ ```shell
172
+ STL_SKIP_AUTO_CLEANUP=1 jest
173
+ ```
174
+
143
175
  ## Docs
144
176
 
145
177
  See the [**docs**][stl-docs] over at the Testing Library website.
@@ -183,8 +215,11 @@ instead of filing an issue on GitHub.
183
215
  Thanks goes to these people ([emoji key][emojis]):
184
216
 
185
217
  <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
218
+
186
219
  <!-- prettier-ignore-start -->
220
+
187
221
  <!-- markdownlint-disable -->
222
+
188
223
  <table>
189
224
  <tbody>
190
225
  <tr>
@@ -212,6 +247,7 @@ Thanks goes to these people ([emoji key][emojis]):
212
247
  </table>
213
248
 
214
249
  <!-- markdownlint-restore -->
250
+
215
251
  <!-- prettier-ignore-end -->
216
252
 
217
253
  <!-- ALL-CONTRIBUTORS-LIST:END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testing-library/svelte",
3
- "version": "5.2.7",
3
+ "version": "5.2.9",
4
4
  "description": "Simple and complete Svelte testing utilities that encourage good testing practices.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -49,29 +49,23 @@
49
49
  ],
50
50
  "files": [
51
51
  "src",
52
- "types",
53
- "!__tests__"
52
+ "types"
54
53
  ],
55
54
  "scripts": {
56
- "all": "npm-run-all contributors:generate toc format types build test:vitest:* test:jest",
57
- "toc": "doctoc README.md",
55
+ "all": "npm-run-all contributors:generate docs format types build test:vitest:* test:jest test:examples",
56
+ "all:legacy": "npm-run-all types:legacy test:vitest:* test:jest",
57
+ "docs": "remark --output --use remark-toc --use remark-code-import --use unified-prettier README.md examples",
58
58
  "lint": "prettier . --check && eslint .",
59
- "lint:delta": "npm-run-all -p prettier:delta eslint:delta",
60
- "prettier:delta": "prettier --check `./scripts/changed-files`",
61
- "eslint:delta": "eslint `./scripts/changed-files`",
62
59
  "format": "prettier . --write && eslint . --fix",
63
- "format:delta": "npm-run-all format:prettier:delta format:eslint:delta",
64
- "format:prettier:delta": "prettier --write `./scripts/changed-files`",
65
- "format:eslint:delta": "eslint --fix `./scripts/changed-files`",
66
- "setup": "npm install && npm run all",
60
+ "setup": "npm run install:5 && npm run all",
67
61
  "test": "vitest run --coverage",
68
62
  "test:watch": "vitest",
69
- "test:vitest:jsdom": "vitest run --coverage --environment jsdom",
70
- "test:vitest:happy-dom": "vitest run --coverage --environment happy-dom",
63
+ "test:vitest:jsdom": "vitest run tests --coverage --environment jsdom",
64
+ "test:vitest:happy-dom": "vitest run tests --coverage --environment happy-dom",
71
65
  "test:jest": "npx --node-options=\"--experimental-vm-modules --no-warnings\" jest --coverage",
66
+ "test:examples": "vitest run examples --coverage",
72
67
  "types": "svelte-check",
73
68
  "types:legacy": "svelte-check --tsconfig tsconfig.legacy.json",
74
- "validate": "npm-run-all test:vitest:* test:jest types build",
75
69
  "build": "tsc -p tsconfig.build.json && cp src/component-types.d.ts types",
76
70
  "contributors:add": "all-contributors add",
77
71
  "contributors:generate": "all-contributors generate",
@@ -94,40 +88,45 @@
94
88
  }
95
89
  },
96
90
  "dependencies": {
97
- "@testing-library/dom": "^10.0.0"
91
+ "@testing-library/dom": "9.x.x || 10.x.x"
98
92
  },
99
93
  "devDependencies": {
94
+ "@eslint/js": "^9.26.0",
100
95
  "@jest/globals": "^29.7.0",
101
- "@sveltejs/vite-plugin-svelte": "^2.0.0 || ^3.0.0 || ^4.0.0",
102
- "@testing-library/jest-dom": "^6.3.0",
103
- "@testing-library/user-event": "^14.5.2",
104
- "@typescript-eslint/eslint-plugin": "^8.0.0",
105
- "@typescript-eslint/parser": "^8.0.0",
106
- "@vitest/coverage-v8": "0.x.x || ^1.0.0 || ^2.0.2",
96
+ "@sveltejs/vite-plugin-svelte": "^5.0.3",
97
+ "@testing-library/jest-dom": "^6.6.3",
98
+ "@testing-library/user-event": "^14.6.1",
99
+ "@vitest/coverage-v8": "^3.1.3",
100
+ "@vitest/eslint-plugin": "^1.1.44",
107
101
  "all-contributors-cli": "^6.26.1",
108
- "doctoc": "^2.2.1",
109
- "esbuild": "*",
110
- "eslint": "^8.57.0",
111
- "eslint-config-prettier": "^9.1.0",
112
- "eslint-config-standard": "^17.1.0",
113
- "eslint-plugin-import": "^2.29.1",
114
- "eslint-plugin-n": "^16.6.2",
115
- "eslint-plugin-promise": "^6.4.0",
102
+ "eslint": "^9.26.0",
103
+ "eslint-config-prettier": "^10.1.5",
104
+ "eslint-plugin-jest-dom": "^5.5.0",
105
+ "eslint-plugin-promise": "^7.2.1",
116
106
  "eslint-plugin-simple-import-sort": "^12.1.1",
117
- "eslint-plugin-svelte": "^2.42.0",
118
- "expect-type": "^1.1.0",
119
- "happy-dom": "^16.3.0",
107
+ "eslint-plugin-svelte": "^3.5.1",
108
+ "eslint-plugin-testing-library": "^7.1.1",
109
+ "eslint-plugin-unicorn": "^59.0.1",
110
+ "expect-type": "^1.2.1",
111
+ "globals": "^16.1.0",
112
+ "happy-dom": "^17.4.6",
120
113
  "jest": "^29.7.0",
121
114
  "jest-environment-jsdom": "^29.7.0",
122
- "jsdom": "^25.0.0",
115
+ "jsdom": "^26.1.0",
123
116
  "npm-run-all": "^4.1.5",
124
- "prettier": "^3.3.3",
125
- "prettier-plugin-svelte": "^3.2.5",
126
- "svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0",
127
- "svelte-check": "^3.0.0 || ^4.0.4",
117
+ "prettier": "^3.5.3",
118
+ "prettier-plugin-svelte": "^3.3.3",
119
+ "remark-cli": "^12.0.1",
120
+ "remark-code-import": "^1.2.0",
121
+ "remark-toc": "^9.0.0",
122
+ "svelte": "^5.28.2",
123
+ "svelte-check": "^4.1.7",
128
124
  "svelte-jester": "^5.0.0",
129
- "typescript": "^5.5.3",
130
- "vite": "^4.0.0 || ^5.3.3",
131
- "vitest": "0.x.x || ^1.0.0 || ^2.0.2"
125
+ "typescript": "^5.8.3",
126
+ "typescript-eslint": "^8.32.0",
127
+ "typescript-svelte-plugin": "^0.3.46",
128
+ "unified-prettier": "^2.0.1",
129
+ "vite": "^6.3.5",
130
+ "vitest": "^3.1.3"
132
131
  }
133
132
  }
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents */
1
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-deprecated */
2
2
  import type {
3
3
  Component as ModernComponent,
4
4
  ComponentConstructorOptions as LegacyConstructorOptions,
@@ -0,0 +1,32 @@
1
+ /** @type {Set<() => void>} */
2
+ const cleanupTasks = new Set()
3
+
4
+ /**
5
+ * Register later cleanup task
6
+ *
7
+ * @param {() => void} onCleanup
8
+ */
9
+ const addCleanupTask = (onCleanup) => {
10
+ cleanupTasks.add(onCleanup)
11
+ return onCleanup
12
+ }
13
+
14
+ /**
15
+ * Remove a cleanup task without running it.
16
+ *
17
+ * @param {() => void} onCleanup
18
+ */
19
+ const removeCleanupTask = (onCleanup) => {
20
+ cleanupTasks.delete(onCleanup)
21
+ }
22
+
23
+ /** Clean up all components and elements added to the document. */
24
+ const cleanup = () => {
25
+ for (const handleCleanup of cleanupTasks.values()) {
26
+ handleCleanup()
27
+ }
28
+
29
+ cleanupTasks.clear()
30
+ }
31
+
32
+ export { addCleanupTask, cleanup, removeCleanupTask }
package/src/core/index.js CHANGED
@@ -5,23 +5,9 @@
5
5
  * Will switch to legacy, class-based mounting logic
6
6
  * if it looks like we're in a Svelte <= 4 environment.
7
7
  */
8
- import * as LegacyCore from './legacy.js'
9
- import * as ModernCore from './modern.svelte.js'
10
- import {
11
- createValidateOptions,
12
- UnknownSvelteOptionsError,
13
- } from './validate-options.js'
14
-
15
- const { mount, unmount, updateProps, allowedOptions } =
16
- ModernCore.IS_MODERN_SVELTE ? ModernCore : LegacyCore
17
-
18
- /** Validate component options. */
19
- const validateOptions = createValidateOptions(allowedOptions)
20
-
8
+ export { addCleanupTask, cleanup } from './cleanup.js'
9
+ export { mount } from './mount.js'
21
10
  export {
22
- mount,
23
11
  UnknownSvelteOptionsError,
24
- unmount,
25
- updateProps,
26
12
  validateOptions,
27
- }
13
+ } from './validate-options.js'
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Component rendering core, with support for Svelte 3, 4, and 5
3
+ */
4
+ import * as Svelte from 'svelte'
5
+
6
+ import { addCleanupTask, removeCleanupTask } from './cleanup.js'
7
+ import { createProps } from './props.svelte.js'
8
+
9
+ /** Whether we're using Svelte >= 5. */
10
+ const IS_MODERN_SVELTE = typeof Svelte.mount === 'function'
11
+
12
+ /** Allowed options to the `mount` call or legacy component constructor. */
13
+ const ALLOWED_MOUNT_OPTIONS = IS_MODERN_SVELTE
14
+ ? ['target', 'anchor', 'props', 'events', 'context', 'intro']
15
+ : ['target', 'accessors', 'anchor', 'props', 'hydrate', 'intro', 'context']
16
+
17
+ /** Mount a modern Svelte 5 component into the DOM. */
18
+ const mountModern = (Component, options) => {
19
+ const [props, updateProps] = createProps(options.props)
20
+ const component = Svelte.mount(Component, { ...options, props })
21
+
22
+ /** Remove the component from the DOM. */
23
+ const unmount = () => {
24
+ Svelte.flushSync(() => Svelte.unmount(component))
25
+ removeCleanupTask(unmount)
26
+ }
27
+
28
+ /** Update the component's props. */
29
+ const rerender = (nextProps) => {
30
+ Svelte.flushSync(() => updateProps(nextProps))
31
+ }
32
+
33
+ addCleanupTask(unmount)
34
+ Svelte.flushSync()
35
+
36
+ return { component, unmount, rerender }
37
+ }
38
+
39
+ /** Mount a legacy Svelte 3 or 4 component into the DOM. */
40
+ const mountLegacy = (Component, options) => {
41
+ const component = new Component(options)
42
+
43
+ /** Remove the component from the DOM. */
44
+ const unmount = () => {
45
+ component.$destroy()
46
+ removeCleanupTask(unmount)
47
+ }
48
+
49
+ /** Update the component's props. */
50
+ const rerender = (nextProps) => {
51
+ component.$set(nextProps)
52
+ }
53
+
54
+ // This `$$.on_destroy` listener is included for strict backwards compatibility
55
+ // with previous versions of `@testing-library/svelte`.
56
+ // It's unnecessary and will be removed in a future major version.
57
+ component.$$.on_destroy.push(() => {
58
+ removeCleanupTask(unmount)
59
+ })
60
+
61
+ addCleanupTask(unmount)
62
+
63
+ return { component, unmount, rerender }
64
+ }
65
+
66
+ /** The mount method in use. */
67
+ const mountComponent = IS_MODERN_SVELTE ? mountModern : mountLegacy
68
+
69
+ /**
70
+ * Render a Svelte component into the document.
71
+ *
72
+ * @template {import('./types.js').Component} C
73
+ * @param {import('./types.js').ComponentType<C>} Component
74
+ * @param {import('./types.js').MountOptions<C>} options
75
+ * @returns {{
76
+ * component: C
77
+ * unmount: () => void
78
+ * rerender: (props: Partial<import('./types.js').Props<C>>) => Promise<void>
79
+ * }}
80
+ */
81
+ const mount = (Component, options = {}) => {
82
+ const { component, unmount, rerender } = mountComponent(Component, options)
83
+
84
+ return {
85
+ component,
86
+ unmount,
87
+ rerender: async (props) => {
88
+ rerender(props)
89
+ // Await the next tick for Svelte 4, which cannot flush changes synchronously
90
+ await Svelte.tick()
91
+ },
92
+ }
93
+ }
94
+
95
+ export { ALLOWED_MOUNT_OPTIONS, mount }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Create a shallowly reactive props object.
3
+ *
4
+ * This allows us to update props on `rerender`
5
+ * without turing `props` into a deep set of Proxy objects
6
+ *
7
+ * @template {Record<string, unknown>} Props
8
+ * @param {Props} initialProps
9
+ * @returns {[Props, (nextProps: Partial<Props>) => void]}
10
+ */
11
+ const createProps = (initialProps) => {
12
+ const targetProps = initialProps ?? {}
13
+ let currentProps = $state.raw(targetProps)
14
+
15
+ const props = new Proxy(targetProps, {
16
+ get(_, key) {
17
+ return currentProps[key]
18
+ },
19
+ set(_, key, value) {
20
+ currentProps[key] = value
21
+ return true
22
+ },
23
+ has(_, key) {
24
+ return Reflect.has(currentProps, key)
25
+ },
26
+ ownKeys() {
27
+ return Reflect.ownKeys(currentProps)
28
+ },
29
+ })
30
+
31
+ const update = (nextProps) => {
32
+ currentProps = { ...currentProps, ...nextProps }
33
+ }
34
+
35
+ return [props, update]
36
+ }
37
+
38
+ export { createProps }
@@ -1,3 +1,5 @@
1
+ import { ALLOWED_MOUNT_OPTIONS } from './mount.js'
2
+
1
3
  class UnknownSvelteOptionsError extends TypeError {
2
4
  constructor(unknownOptions, allowedOptions) {
3
5
  super(`Unknown options.
@@ -15,9 +17,9 @@ class UnknownSvelteOptionsError extends TypeError {
15
17
  }
16
18
  }
17
19
 
18
- const createValidateOptions = (allowedOptions) => (options) => {
20
+ const validateOptions = (options) => {
19
21
  const isProps = !Object.keys(options).some((option) =>
20
- allowedOptions.includes(option)
22
+ ALLOWED_MOUNT_OPTIONS.includes(option)
21
23
  )
22
24
 
23
25
  if (isProps) {
@@ -26,14 +28,14 @@ const createValidateOptions = (allowedOptions) => (options) => {
26
28
 
27
29
  // Check if any props and Svelte options were accidentally mixed.
28
30
  const unknownOptions = Object.keys(options).filter(
29
- (option) => !allowedOptions.includes(option)
31
+ (option) => !ALLOWED_MOUNT_OPTIONS.includes(option)
30
32
  )
31
33
 
32
34
  if (unknownOptions.length > 0) {
33
- throw new UnknownSvelteOptionsError(unknownOptions, allowedOptions)
35
+ throw new UnknownSvelteOptionsError(unknownOptions, ALLOWED_MOUNT_OPTIONS)
34
36
  }
35
37
 
36
38
  return options
37
39
  }
38
40
 
39
- export { createValidateOptions, UnknownSvelteOptionsError }
41
+ export { UnknownSvelteOptionsError, validateOptions }
package/src/index.js CHANGED
@@ -1,15 +1,22 @@
1
- /* eslint-disable import/export */
2
- import { act, cleanup } from './pure.js'
1
+ import { act, cleanup, setup } from './pure.js'
3
2
 
4
- // If we're running in a test runner that supports afterEach
5
- // then we'll automatically run cleanup afterEach test
3
+ // If we're running in a test runner that supports beforeEach/afterEach
4
+ // we'll automatically run setup and cleanup before and after each test
6
5
  // this ensures that tests run in isolation from each other
7
6
  // if you don't like this then set the STL_SKIP_AUTO_CLEANUP env variable.
8
- if (typeof afterEach === 'function' && !process.env.STL_SKIP_AUTO_CLEANUP) {
9
- afterEach(async () => {
10
- await act()
11
- cleanup()
12
- })
7
+ if (typeof process !== 'undefined' && !process.env.STL_SKIP_AUTO_CLEANUP) {
8
+ if (typeof beforeEach === 'function') {
9
+ beforeEach(() => {
10
+ setup()
11
+ })
12
+ }
13
+
14
+ if (typeof afterEach === 'function') {
15
+ afterEach(async () => {
16
+ await act()
17
+ cleanup()
18
+ })
19
+ }
13
20
  }
14
21
 
15
22
  // export all base queries, screen, etc.
package/src/pure.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import {
2
+ configure as configureDTL,
2
3
  fireEvent as baseFireEvent,
4
+ getConfig as getDTLConfig,
3
5
  getQueriesForElement,
4
6
  prettyDOM,
5
7
  } from '@testing-library/dom'
6
- import { tick } from 'svelte'
8
+ import * as Svelte from 'svelte'
7
9
 
8
- import { mount, unmount, updateProps, validateOptions } from './core/index.js'
9
-
10
- const targetCache = new Set()
11
- const componentCache = new Set()
10
+ import { addCleanupTask, mount, validateOptions } from './core/index.js'
12
11
 
13
12
  /**
14
13
  * Customize how Svelte renders the component.
@@ -65,18 +64,20 @@ const render = (Component, options = {}, renderOptions = {}) => {
65
64
  const queries = getQueriesForElement(baseElement, renderOptions.queries)
66
65
 
67
66
  const target =
67
+ // eslint-disable-next-line unicorn/prefer-dom-node-append
68
68
  options.target ?? baseElement.appendChild(document.createElement('div'))
69
69
 
70
- targetCache.add(target)
70
+ addCleanupTask(() => {
71
+ if (target.parentNode === document.body) {
72
+ target.remove()
73
+ }
74
+ })
71
75
 
72
- const component = mount(
76
+ const { component, unmount, rerender } = mount(
73
77
  Component.default ?? Component,
74
- { ...options, target },
75
- cleanupComponent
78
+ { ...options, target }
76
79
  )
77
80
 
78
- componentCache.add(component)
79
-
80
81
  return {
81
82
  baseElement,
82
83
  component,
@@ -92,51 +93,47 @@ const render = (Component, options = {}, renderOptions = {}) => {
92
93
  props = props.props
93
94
  }
94
95
 
95
- updateProps(component, props)
96
- await tick()
97
- },
98
- unmount: () => {
99
- cleanupComponent(component)
96
+ await rerender(props)
100
97
  },
98
+ unmount,
101
99
  ...queries,
102
100
  }
103
101
  }
104
102
 
105
- /** Remove a component from the component cache. */
106
- const cleanupComponent = (component) => {
107
- const inCache = componentCache.delete(component)
108
-
109
- if (inCache) {
110
- unmount(component)
111
- }
112
- }
113
-
114
- /** Remove a target element from the target cache. */
115
- const cleanupTarget = (target) => {
116
- const inCache = targetCache.delete(target)
103
+ /**
104
+ * Configure `@testing-library/dom` for usage with Svelte.
105
+ *
106
+ * Ensures events fired from `@testing-library/dom`
107
+ * and `@testing-library/user-event` wait for Svelte
108
+ * to flush changes to the DOM before proceeding.
109
+ */
110
+ const setup = () => {
111
+ const originalDTLConfig = getDTLConfig()
117
112
 
118
- if (inCache && target.parentNode === document.body) {
119
- document.body.removeChild(target)
120
- }
121
- }
113
+ configureDTL({
114
+ asyncWrapper: act,
115
+ eventWrapper: Svelte.flushSync ?? ((cb) => cb()),
116
+ })
122
117
 
123
- /** Unmount all components and remove elements added to `<body>`. */
124
- const cleanup = () => {
125
- componentCache.forEach(cleanupComponent)
126
- targetCache.forEach(cleanupTarget)
118
+ addCleanupTask(() => {
119
+ configureDTL(originalDTLConfig)
120
+ })
127
121
  }
128
122
 
129
123
  /**
130
124
  * Call a function and wait for Svelte to flush pending changes.
131
125
  *
132
- * @param {() => unknown} [fn] - A function, which may be `async`, to call before flushing updates.
133
- * @returns {Promise<void>}
126
+ * @template T
127
+ * @param {(() => Promise<T>) | () => T} [fn] - A function, which may be `async`, to call before flushing updates.
128
+ * @returns {Promise<T>}
134
129
  */
135
130
  const act = async (fn) => {
131
+ let result
136
132
  if (fn) {
137
- await fn()
133
+ result = await fn()
138
134
  }
139
- return tick()
135
+ await Svelte.tick()
136
+ return result
140
137
  }
141
138
 
142
139
  /**
@@ -157,18 +154,11 @@ const act = async (fn) => {
157
154
  *
158
155
  * @type {FireFunction & FireObject}
159
156
  */
160
- const fireEvent = async (...args) => {
161
- const event = baseFireEvent(...args)
162
- await tick()
163
- return event
164
- }
157
+ const fireEvent = async (...args) => act(() => baseFireEvent(...args))
165
158
 
166
- Object.keys(baseFireEvent).forEach((key) => {
167
- fireEvent[key] = async (...args) => {
168
- const event = baseFireEvent[key](...args)
169
- await tick()
170
- return event
171
- }
172
- })
159
+ for (const [key, baseEvent] of Object.entries(baseFireEvent)) {
160
+ fireEvent[key] = async (...args) => act(() => baseEvent(...args))
161
+ }
173
162
 
174
- export { act, cleanup, fireEvent, render }
163
+ export { cleanup } from './core/index.js'
164
+ export { act, fireEvent, render, setup }
package/src/vite.js CHANGED
@@ -1,5 +1,5 @@
1
- import { dirname, join } from 'node:path'
2
- import { fileURLToPath } from 'node:url'
1
+ import path from 'node:path'
2
+ import url from 'node:url'
3
3
 
4
4
  /**
5
5
  * Vite plugin to configure @testing-library/svelte.
@@ -50,8 +50,8 @@ const addBrowserCondition = (config) => {
50
50
  const browserConditionIndex = conditions.indexOf('browser')
51
51
 
52
52
  if (
53
- nodeConditionIndex >= 0 &&
54
- (nodeConditionIndex < browserConditionIndex || browserConditionIndex < 0)
53
+ nodeConditionIndex !== -1 &&
54
+ (nodeConditionIndex < browserConditionIndex || browserConditionIndex === -1)
55
55
  ) {
56
56
  conditions.splice(nodeConditionIndex, 0, 'browser')
57
57
  }
@@ -77,7 +77,9 @@ const addAutoCleanup = (config) => {
77
77
  setupFiles = [setupFiles]
78
78
  }
79
79
 
80
- setupFiles.push(join(dirname(fileURLToPath(import.meta.url)), './vitest.js'))
80
+ setupFiles.push(
81
+ path.join(path.dirname(url.fileURLToPath(import.meta.url)), './vitest.js')
82
+ )
81
83
 
82
84
  test.setupFiles = setupFiles
83
85
  config.test = test
package/src/vitest.js CHANGED
@@ -1,7 +1,11 @@
1
- import { act, cleanup } from '@testing-library/svelte'
2
- import { afterEach } from 'vitest'
1
+ import { act, cleanup, setup } from '@testing-library/svelte'
2
+ import { beforeEach } from 'vitest'
3
3
 
4
- afterEach(async () => {
5
- await act()
6
- cleanup()
4
+ beforeEach(() => {
5
+ setup()
6
+
7
+ return async () => {
8
+ await act()
9
+ cleanup()
10
+ }
7
11
  })
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents */
1
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-deprecated */
2
2
  import type {
3
3
  Component as ModernComponent,
4
4
  ComponentConstructorOptions as LegacyConstructorOptions,
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Register later cleanup task
3
+ *
4
+ * @param {() => void} onCleanup
5
+ */
6
+ export function addCleanupTask(onCleanup: () => void): () => void;
7
+ /** Clean up all components and elements added to the document. */
8
+ export function cleanup(): void;
9
+ /**
10
+ * Remove a cleanup task without running it.
11
+ *
12
+ * @param {() => void} onCleanup
13
+ */
14
+ export function removeCleanupTask(onCleanup: () => void): void;
15
+ //# sourceMappingURL=cleanup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/core/cleanup.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,0CAFW,MAAM,IAAI,SAAJ,IAAI,CAKpB;AAWD,kEAAkE;AAClE,gCAMC;AAhBD;;;;GAIG;AACH,6CAFW,MAAM,IAAI,QAIpB"}
@@ -1,8 +1,4 @@
1
- export const mount: (Component: any, options: any, onDestroy: any) => any;
2
- import { UnknownSvelteOptionsError } from './validate-options.js';
3
- export const unmount: (component: any) => void;
4
- export const updateProps: (component: any, nextProps: any) => void;
5
- /** Validate component options. */
6
- export const validateOptions: (options: any) => any;
7
- export { UnknownSvelteOptionsError };
1
+ export { mount } from "./mount.js";
2
+ export { addCleanupTask, cleanup } from "./cleanup.js";
3
+ export { UnknownSvelteOptionsError, validateOptions } from "./validate-options.js";
8
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.js"],"names":[],"mappings":";0CAYO,uBAAuB;;;AAK9B,kCAAkC;AAClC,oDAA6D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.js"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ /** Allowed options to the `mount` call or legacy component constructor. */
2
+ export const ALLOWED_MOUNT_OPTIONS: string[];
3
+ /**
4
+ * Render a Svelte component into the document.
5
+ *
6
+ * @template {import('./types.js').Component} C
7
+ * @param {import('./types.js').ComponentType<C>} Component
8
+ * @param {import('./types.js').MountOptions<C>} options
9
+ * @returns {{
10
+ * component: C
11
+ * unmount: () => void
12
+ * rerender: (props: Partial<import('./types.js').Props<C>>) => Promise<void>
13
+ * }}
14
+ */
15
+ export function mount<C extends any>(Component: any, options?: any): {
16
+ component: C;
17
+ unmount: () => void;
18
+ rerender: (props: Partial<any>) => Promise<void>;
19
+ };
20
+ //# sourceMappingURL=mount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount.d.ts","sourceRoot":"","sources":["../../src/core/mount.js"],"names":[],"mappings":"AAWA,2EAA2E;AAC3E,6CAE6E;AAsD7E;;;;;;;;;;;GAWG;AACH,sBAT8C,CAAC,SAAlC,GAAgC,kCAGhC;IACR,SAAS,EAAE,CAAC,CAAA;IACZ,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,GAA6B,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3E,CAcH"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Create a shallowly reactive props object.
3
+ *
4
+ * This allows us to update props on `rerender`
5
+ * without turing `props` into a deep set of Proxy objects
6
+ *
7
+ * @template {Record<string, unknown>} Props
8
+ * @param {Props} initialProps
9
+ * @returns {[Props, (nextProps: Partial<Props>) => void]}
10
+ */
11
+ export function createProps<Props extends Record<string, unknown>>(initialProps: Props): [Props, (nextProps: Partial<Props>) => void];
12
+ //# sourceMappingURL=props.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"props.svelte.d.ts","sourceRoot":"","sources":["../../src/core/props.svelte.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,4BAJuC,KAAK,SAA9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAE,gBAC3B,KAAK,GACH,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CA2BxD"}
@@ -1,5 +1,5 @@
1
- export function createValidateOptions(allowedOptions: any): (options: any) => any;
2
1
  export class UnknownSvelteOptionsError extends TypeError {
3
2
  constructor(unknownOptions: any, allowedOptions: any);
4
3
  }
4
+ export function validateOptions(options: any): any;
5
5
  //# sourceMappingURL=validate-options.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-options.d.ts","sourceRoot":"","sources":["../../src/core/validate-options.js"],"names":[],"mappings":"AAiBA,kFAmBC;AApCD;IACE,sDAaC;CACF"}
1
+ {"version":3,"file":"validate-options.d.ts","sourceRoot":"","sources":["../../src/core/validate-options.js"],"names":[],"mappings":"AAEA;IACE,sDAaC;CACF;AAED,mDAmBC"}
package/types/pure.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { cleanup } from "./core/index.js";
1
2
  /**
2
3
  * Customize how Svelte renders the component.
3
4
  */
@@ -25,12 +26,11 @@ export type FireObject = { [K in import("@testing-library/dom").EventType]: (...
25
26
  /**
26
27
  * Call a function and wait for Svelte to flush pending changes.
27
28
  *
28
- * @param {() => unknown} [fn] - A function, which may be `async`, to call before flushing updates.
29
- * @returns {Promise<void>}
29
+ * @template T
30
+ * @param {(() => Promise<T>) | () => T} [fn] - A function, which may be `async`, to call before flushing updates.
31
+ * @returns {Promise<T>}
30
32
  */
31
- export function act(fn?: () => unknown): Promise<void>;
32
- /** Unmount all components and remove elements added to `<body>`. */
33
- export function cleanup(): void;
33
+ export function act<T>(fn?: (() => Promise<T>) | (() => T)): Promise<T>;
34
34
  /**
35
35
  * @typedef {(...args: Parameters<import('@testing-library/dom').FireFunction>) => Promise<ReturnType<import('@testing-library/dom').FireFunction>>} FireFunction
36
36
  */
@@ -92,4 +92,12 @@ export const fireEvent: FireFunction & FireObject;
92
92
  * @returns {RenderResult<C, Q>} The rendered component and bound testing functions.
93
93
  */
94
94
  export function render<C extends import("./component-types.js").Component, Q extends import("@testing-library/dom").Queries = typeof import("@testing-library/dom/types/queries.js")>(Component: import("./component-types.js").ComponentType<C>, options?: SvelteComponentOptions<C>, renderOptions?: RenderOptions<Q>): RenderResult<C, Q>;
95
+ /**
96
+ * Configure `@testing-library/dom` for usage with Svelte.
97
+ *
98
+ * Ensures events fired from `@testing-library/dom`
99
+ * and `@testing-library/user-event` wait for Svelte
100
+ * to flush changes to the DOM before proceeding.
101
+ */
102
+ export function setup(): void;
95
103
  //# sourceMappingURL=pure.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pure.d.ts","sourceRoot":"","sources":["../src/pure.js"],"names":[],"mappings":";;;mCAewD,CAAC,SAA5C,OAAQ,sBAAsB,EAAE,SAAU,IAC1C,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;;;;0BAMvD,CAAC,SAA3C,OAAQ,sBAAsB,EAAE,OAAQ,6DACxC;IACR,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,OAAO,CAAC,EAAE,CAAC,CAAA;CACZ;;;;yBAMoD,CAAC,SAA5C,OAAQ,sBAAsB,EAAE,SAAU,EACA,CAAC,SAA3C,OAAQ,sBAAsB,EAAE,OAAQ,6DAExC;IACR,SAAS,EAAE,WAAW,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,OAAO,sBAAsB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACpD,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,WAAW,GAAG,gBAAgB,KAAK,IAAI,CAAA;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpF,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,GACD,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACnE;2BAkGS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,sBAAsB,EAAE,YAAY,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC;yBAItI,GACP,CAAC,IAAI,OAAO,sBAAsB,EAAE,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,sBAAsB,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,sBAAsB,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAC1L;AApBJ;;;;;GAKG;AACH,yBAHW,MAAM,OAAO,GACX,OAAO,CAAC,IAAI,CAAC,CAOzB;AAjBD,oEAAoE;AACpE,gCAGC;AAeD;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAFU,YAAY,GAAG,UAAU,CAMlC;AAvJD;;;;;GAKG;AAEH;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;GAUG;AACH,uBARwD,CAAC,SAA5C,OAAQ,sBAAsB,EAAE,SAAU,EACA,CAAC,SAA3C,OAAQ,sBAAsB,EAAE,OAAQ,sEAE1C,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC,CAAC,YAC/C,sBAAsB,CAAC,CAAC,CAAC,kBACzB,aAAa,CAAC,CAAC,CAAC,GACd,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CA8C9B"}
1
+ {"version":3,"file":"pure.d.ts","sourceRoot":"","sources":["../src/pure.js"],"names":[],"mappings":";;;;mCAcwD,CAAC,SAA5C,OAAQ,sBAAsB,EAAE,SAAU,IAC1C,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;;;;0BAMvD,CAAC,SAA3C,OAAQ,sBAAsB,EAAE,OAAQ,6DACxC;IACR,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,OAAO,CAAC,EAAE,CAAC,CAAA;CACZ;;;;yBAMoD,CAAC,SAA5C,OAAQ,sBAAsB,EAAE,SAAU,EACA,CAAC,SAA3C,OAAQ,sBAAsB,EAAE,OAAQ,6DAExC;IACR,SAAS,EAAE,WAAW,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,OAAO,sBAAsB,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACpD,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,WAAW,GAAG,gBAAgB,KAAK,IAAI,CAAA;IACpD,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,sBAAsB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpF,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,GAAG,GACD,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACnE;2BAgGS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,sBAAsB,EAAE,YAAY,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,sBAAsB,EAAE,YAAY,CAAC,CAAC;yBAItI,GACP,CAAC,IAAI,OAAO,sBAAsB,EAAE,SAAS,GAAG,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,OAAO,sBAAsB,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,OAAO,sBAAsB,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAC1L;AAvBJ;;;;;;GAMG;AACH,oBAJa,CAAC,OACH,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,IAAG,MAAM,CAAC,CAAA,GAC1B,OAAO,CAAC,CAAC,CAAC,CAStB;AAED;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAFU,YAAY,GAAG,UAAU,CAEmC;AAjJtE;;;;;GAKG;AAEH;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;;;GAUG;AACH,uBARwD,CAAC,SAA5C,OAAQ,sBAAsB,EAAE,SAAU,EACA,CAAC,SAA3C,OAAQ,sBAAsB,EAAE,OAAQ,sEAE1C,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC,CAAC,YAC/C,sBAAsB,CAAC,CAAC,CAAC,kBACzB,aAAa,CAAC,CAAC,CAAC,GACd,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CA6C9B;AAED;;;;;;GAMG;AACH,8BAWC"}
@@ -1,46 +0,0 @@
1
- /**
2
- * Legacy rendering core for svelte-testing-library.
3
- *
4
- * Supports Svelte <= 4.
5
- */
6
-
7
- /** Allowed options for the component constructor. */
8
- const allowedOptions = [
9
- 'target',
10
- 'accessors',
11
- 'anchor',
12
- 'props',
13
- 'hydrate',
14
- 'intro',
15
- 'context',
16
- ]
17
-
18
- /**
19
- * Mount the component into the DOM.
20
- *
21
- * The `onDestroy` callback is included for strict backwards compatibility
22
- * with previous versions of this library. It's mostly unnecessary logic.
23
- */
24
- const mount = (Component, options, onDestroy) => {
25
- const component = new Component(options)
26
-
27
- if (typeof onDestroy === 'function') {
28
- component.$$.on_destroy.push(() => {
29
- onDestroy(component)
30
- })
31
- }
32
-
33
- return component
34
- }
35
-
36
- /** Remove the component from the DOM. */
37
- const unmount = (component) => {
38
- component.$destroy()
39
- }
40
-
41
- /** Update the component's props. */
42
- const updateProps = (component, nextProps) => {
43
- component.$set(nextProps)
44
- }
45
-
46
- export { allowedOptions, mount, unmount, updateProps }
@@ -1,51 +0,0 @@
1
- /**
2
- * Modern rendering core for svelte-testing-library.
3
- *
4
- * Supports Svelte >= 5.
5
- */
6
- import * as Svelte from 'svelte'
7
-
8
- /** Props signals for each rendered component. */
9
- const propsByComponent = new Map()
10
-
11
- /** Whether we're using Svelte >= 5. */
12
- const IS_MODERN_SVELTE = typeof Svelte.mount === 'function'
13
-
14
- /** Allowed options to the `mount` call. */
15
- const allowedOptions = [
16
- 'target',
17
- 'anchor',
18
- 'props',
19
- 'events',
20
- 'context',
21
- 'intro',
22
- ]
23
-
24
- /** Mount the component into the DOM. */
25
- const mount = (Component, options) => {
26
- const props = $state(options.props ?? {})
27
- const component = Svelte.mount(Component, { ...options, props })
28
-
29
- Svelte.flushSync()
30
- propsByComponent.set(component, props)
31
-
32
- return component
33
- }
34
-
35
- /** Remove the component from the DOM. */
36
- const unmount = (component) => {
37
- propsByComponent.delete(component)
38
- Svelte.flushSync(() => Svelte.unmount(component))
39
- }
40
-
41
- /**
42
- * Update the component's props.
43
- *
44
- * Relies on the `$state` signal added in `mount`.
45
- */
46
- const updateProps = (component, nextProps) => {
47
- const prevProps = propsByComponent.get(component)
48
- Object.assign(prevProps, nextProps)
49
- }
50
-
51
- export { allowedOptions, IS_MODERN_SVELTE, mount, unmount, updateProps }
@@ -1,19 +0,0 @@
1
- /**
2
- * Legacy rendering core for svelte-testing-library.
3
- *
4
- * Supports Svelte <= 4.
5
- */
6
- /** Allowed options for the component constructor. */
7
- export const allowedOptions: string[];
8
- /**
9
- * Mount the component into the DOM.
10
- *
11
- * The `onDestroy` callback is included for strict backwards compatibility
12
- * with previous versions of this library. It's mostly unnecessary logic.
13
- */
14
- export function mount(Component: any, options: any, onDestroy: any): any;
15
- /** Remove the component from the DOM. */
16
- export function unmount(component: any): void;
17
- /** Update the component's props. */
18
- export function updateProps(component: any, nextProps: any): void;
19
- //# sourceMappingURL=legacy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"legacy.d.ts","sourceRoot":"","sources":["../../src/core/legacy.js"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,qDAAqD;AACrD,sCAQC;AAED;;;;;GAKG;AACH,yEAUC;AAED,yCAAyC;AACzC,8CAEC;AAED,oCAAoC;AACpC,kEAEC"}
@@ -1,15 +0,0 @@
1
- /** Allowed options to the `mount` call. */
2
- export const allowedOptions: string[];
3
- /** Whether we're using Svelte >= 5. */
4
- export const IS_MODERN_SVELTE: boolean;
5
- /** Mount the component into the DOM. */
6
- export function mount(Component: any, options: any): Record<string, any>;
7
- /** Remove the component from the DOM. */
8
- export function unmount(component: any): void;
9
- /**
10
- * Update the component's props.
11
- *
12
- * Relies on the `$state` signal added in `mount`.
13
- */
14
- export function updateProps(component: any, nextProps: any): void;
15
- //# sourceMappingURL=modern.svelte.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"modern.svelte.d.ts","sourceRoot":"","sources":["../../src/core/modern.svelte.js"],"names":[],"mappings":"AAaA,2CAA2C;AAC3C,sCAOC;AAXD,uCAAuC;AACvC,uCAA2D;AAY3D,wCAAwC;AACxC,yEAQC;AAED,yCAAyC;AACzC,8CAGC;AAED;;;;GAIG;AACH,kEAGC"}