@testing-library/svelte 4.1.0 → 4.2.0

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
@@ -38,7 +38,6 @@
38
38
  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
39
39
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
40
40
 
41
-
42
41
  - [The Problem](#the-problem)
43
42
  - [This Solution](#this-solution)
44
43
  - [Installation](#installation)
@@ -119,23 +118,29 @@ Thanks goes to these people ([emoji key][emojis]):
119
118
  <!-- prettier-ignore-start -->
120
119
  <!-- markdownlint-disable -->
121
120
  <table>
122
- <tr>
123
- <td align="center"><a href="https://github.com/benmonro"><img src="https://avatars3.githubusercontent.com/u/399236?v=4?s=100" width="100px;" alt=""/><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>
124
- <td align="center"><a href="https://twitter.com/EmilTholin"><img src="https://avatars0.githubusercontent.com/u/11573167?v=4?s=100" width="100px;" alt=""/><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>
125
- <td align="center"><a href="https://medium.com/@oieduardorabelo"><img src="https://avatars1.githubusercontent.com/u/829902?v=4?s=100" width="100px;" alt=""/><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>
126
- <td align="center"><a href="http://timdeschryver.dev"><img src="https://avatars1.githubusercontent.com/u/28659384?v=4?s=100" width="100px;" alt=""/><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>
127
- <td align="center"><a href="http://www.ematipico.com"><img src="https://avatars3.githubusercontent.com/u/602478?v=4?s=100" width="100px;" alt=""/><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>
128
- <td align="center"><a href="https://github.com/pngwn"><img src="https://avatars1.githubusercontent.com/u/12937446?v=4?s=100" width="100px;" alt=""/><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>
129
- <td align="center"><a href="https://twitter.com/sebsilbermann"><img src="https://avatars3.githubusercontent.com/u/12292047?v=4?s=100" width="100px;" alt=""/><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>
130
- </tr>
131
- <tr>
132
- <td align="center"><a href="https://github.com/mihar-22"><img src="https://avatars3.githubusercontent.com/u/14304599?s=460&v=4?s=100" width="100px;" alt=""/><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>
133
- <td align="center"><a href="https://github.com/MirrorBytes"><img src="https://avatars3.githubusercontent.com/u/22119469?v=4?s=100" width="100px;" alt=""/><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>
134
- <td align="center"><a href="https://github.com/ronmerkin"><img src="https://avatars.githubusercontent.com/u/17492527?v=4?s=100" width="100px;" alt=""/><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>
135
- <td align="center"><a href="http://www.benmccann.com"><img src="https://avatars.githubusercontent.com/u/322311?v=4?s=100" width="100px;" alt=""/><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>
136
- <td align="center"><a href="https://johnbowser.dev/"><img src="https://avatars.githubusercontent.com/u/66637570?v=4?s=100" width="100px;" alt=""/><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>
137
- <td align="center"><a href="https://github.com/ysaskia"><img src="https://avatars.githubusercontent.com/u/1370679?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Yoann</b></sub></a><br /><a href="https://github.com/testing-library/svelte-testing-library/commits?author=ysaskia" title="Code">💻</a></td>
138
- </tr>
121
+ <tbody>
122
+ <tr>
123
+ <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>
124
+ <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>
125
+ <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>
126
+ <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>
127
+ <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>
128
+ <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>
129
+ <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>
130
+ </tr>
131
+ <tr>
132
+ <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>
133
+ <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>
134
+ <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>
135
+ <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>
136
+ <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>
137
+ <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>
138
+ <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>
139
+ </tr>
140
+ <tr>
141
+ <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>
142
+ </tr>
143
+ </tbody>
139
144
  </table>
140
145
 
141
146
  <!-- markdownlint-restore -->
@@ -154,8 +159,8 @@ Contributions of any kind welcome!
154
159
 
155
160
  [npm]: https://www.npmjs.com/
156
161
  [node]: https://nodejs.org
157
- [build-badge]: https://img.shields.io/travis/testing-library/svelte-testing-library.svg?style=flat-square
158
- [build]: https://travis-ci.org/testing-library/svelte-testing-library
162
+ [build-badge]: https://img.shields.io/github/actions/workflow/status/testing-library/svelte-testing-library/release.yml?style=flat-square
163
+ [build]: https://github.com/testing-library/svelte-testing-library/actions
159
164
  [coverage-badge]: https://img.shields.io/codecov/c/github/testing-library/svelte-testing-library.svg?style=flat-square
160
165
  [coverage]: https://codecov.io/github/testing-library/svelte-testing-library
161
166
  [version-badge]: https://img.shields.io/npm/v/@testing-library/svelte.svg?style=flat-square
@@ -164,7 +169,7 @@ Contributions of any kind welcome!
164
169
  [npmtrends]: http://www.npmtrends.com/@testing-library/svelte
165
170
  [discord-badge]: https://img.shields.io/discord/723559267868737556.svg?color=7389D8&labelColor=6A7EC2&logo=discord&logoColor=ffffff&style=flat-square
166
171
  [discord]: https://discord.gg/testing-library
167
- [license-badge]: https://img.shields.io/github/license/testing-library/svelte-testing-library?color=b
172
+ [license-badge]: https://img.shields.io/github/license/testing-library/svelte-testing-library?color=b&style=flat-square
168
173
  [license]: https://github.com/testing-library/svelte-testing-library/blob/main/LICENSE
169
174
  [prs-badge]: https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square
170
175
  [prs]: http://makeapullrequest.com
@@ -187,4 +192,3 @@ Contributions of any kind welcome!
187
192
  [stackoverflow]: https://stackoverflow.com/questions/tagged/svelte-testing-library
188
193
 
189
194
  <!-- prettier-ignore-end -->
190
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testing-library/svelte",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "Simple and complete Svelte testing utilities that encourage good testing practices.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -44,73 +44,61 @@
44
44
  ],
45
45
  "scripts": {
46
46
  "toc": "doctoc README.md",
47
- "lint": "(prettier . --check || true) && eslint .",
47
+ "lint": "prettier . --check && eslint .",
48
+ "lint:delta": "npm-run-all -p prettier:delta eslint:delta",
49
+ "prettier:delta": "prettier --check `./scripts/changed-files`",
50
+ "eslint:delta": "eslint `./scripts/changed-files`",
48
51
  "format": "prettier . --write && eslint . --fix",
52
+ "format:delta": "npm-run-all format:prettier:delta format:eslint:delta",
53
+ "format:prettier:delta": "prettier --write `./scripts/changed-files`",
54
+ "format:eslint:delta": "eslint --fix `./scripts/changed-files`",
55
+ "setup": "npm install && npm run validate",
49
56
  "test": "vitest run --coverage",
50
57
  "test:watch": "vitest",
51
58
  "test:update": "vitest run --update",
52
- "setup": "npm install && npm run validate",
53
- "validate": "npm-run-all lint test",
59
+ "test:vitest:jsdom": "vitest run --coverage --environment jsdom",
60
+ "test:vitest:happy-dom": "vitest run --coverage --environment happy-dom",
61
+ "types": "svelte-check",
62
+ "validate": "npm-run-all test:vitest:* types",
54
63
  "contributors:add": "all-contributors add",
55
64
  "contributors:generate": "all-contributors generate"
56
65
  },
57
66
  "peerDependencies": {
58
- "svelte": "^3 || ^4"
67
+ "svelte": "^3 || ^4 || ^5"
59
68
  },
60
69
  "dependencies": {
61
70
  "@testing-library/dom": "^9.3.1"
62
71
  },
63
72
  "devDependencies": {
64
- "@commitlint/cli": "^17.6.6",
65
- "@commitlint/config-conventional": "^17.6.6",
66
- "@sveltejs/vite-plugin-svelte": "^2.4.2",
73
+ "@sveltejs/vite-plugin-svelte": "^3.0.2",
67
74
  "@testing-library/jest-dom": "^6.3.0",
68
- "@typescript-eslint/eslint-plugin": "^6.19.1",
69
- "@typescript-eslint/parser": "^6.19.1",
75
+ "@testing-library/user-event": "^14.5.2",
76
+ "@typescript-eslint/eslint-plugin": "6.19.1",
77
+ "@typescript-eslint/parser": "6.19.1",
70
78
  "@vitest/coverage-v8": "^0.33.0",
71
- "all-contributors-cli": "^6.26.0",
79
+ "all-contributors-cli": "^6.26.1",
72
80
  "doctoc": "^2.2.1",
73
- "eslint": "^8.43.0",
74
- "eslint-config-prettier": "^9.1.0",
75
- "eslint-config-standard": "^17.1.0",
76
- "eslint-plugin-import": "^2.27.5",
77
- "eslint-plugin-n": "^16.0.1",
78
- "eslint-plugin-promise": "^6.1.1",
79
- "eslint-plugin-simple-import-sort": "^10.0.0",
80
- "eslint-plugin-svelte": "^2.32.0",
81
- "eslint-plugin-vitest-globals": "^1.3.1",
82
- "husky": "^8.0.3",
81
+ "eslint": "8.56.0",
82
+ "eslint-config-prettier": "9.1.0",
83
+ "eslint-config-standard": "17.1.0",
84
+ "eslint-plugin-import": "2.29.1",
85
+ "eslint-plugin-json-files": "^4.1.0",
86
+ "eslint-plugin-n": "16.6.2",
87
+ "eslint-plugin-promise": "6.1.1",
88
+ "eslint-plugin-simple-import-sort": "10.0.0",
89
+ "eslint-plugin-svelte": "2.35.1",
90
+ "eslint-plugin-vitest-globals": "1.4.0",
91
+ "expect-type": "^0.17.3",
92
+ "happy-dom": "^13.3.1",
83
93
  "jsdom": "^22.1.0",
84
- "lint-staged": "^13.2.3",
85
94
  "npm-run-all": "^4.1.5",
86
- "prettier": "^3.0.0",
87
- "prettier-plugin-svelte": "^3.1.2",
88
- "svelte": "^4.0.1",
95
+ "prettier": "3.2.4",
96
+ "prettier-plugin-svelte": "3.1.2",
97
+ "svelte": "^4.2.10",
98
+ "svelte-check": "^3.6.3",
89
99
  "svelte-jester": "^3.0.0",
90
100
  "typescript": "^5.3.3",
91
- "vite": "^4.3.9",
101
+ "vite": "^5.1.1",
92
102
  "vitest": "^0.33.0"
93
- },
94
- "lint-staged": {
95
- "{README.md,.all-contributorsrc}": [
96
- "npm run toc",
97
- "npm run contributors:generate",
98
- "npx --no-install prettier --write README.md .all-contributorsrc",
99
- "git add README.md .all-contributorsrc"
100
- ],
101
- "src/**/*": [
102
- "npx --no-install vitest related --run"
103
- ],
104
- "*.{js,cjs,ts,svelte,json,yml,yaml}": [
105
- "npx --no-install prettier --check"
106
- ],
107
- "*.{js,cjs,ts,svelte}": [
108
- "npx --no-install eslint"
109
- ]
110
- },
111
- "commitlint": {
112
- "extends": [
113
- "@commitlint/config-conventional"
114
- ]
115
103
  }
116
104
  }
@@ -1,6 +1,6 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`render > should accept svelte component options 1`] = `
3
+ exports[`render > should accept svelte v4 component options 1`] = `
4
4
  <body>
5
5
  <div>
6
6
  <h1
@@ -18,8 +18,31 @@ exports[`render > should accept svelte component options 1`] = `
18
18
  <button>
19
19
  Button
20
20
  </button>
21
- <!--&lt;Comp&gt;-->
22
21
  <div />
23
22
  </div>
24
23
  </body>
25
24
  `;
25
+
26
+ exports[`render > should accept svelte v5 component options 1`] = `
27
+ <body>
28
+
29
+
30
+
31
+ <section>
32
+ <h1
33
+ data-testid="test"
34
+ >
35
+ Hello World!
36
+ </h1>
37
+
38
+ <div>
39
+ we have context
40
+ </div>
41
+
42
+ <button>
43
+ Button
44
+ </button>
45
+
46
+ </section>
47
+ </body>
48
+ `;
@@ -0,0 +1,35 @@
1
+ import { describe, expect, test, vi } from 'vitest'
2
+
3
+ import { act, cleanup, render } from '..'
4
+ import Mounter from './fixtures/Mounter.svelte'
5
+
6
+ const onExecuted = vi.fn()
7
+ const onDestroyed = vi.fn()
8
+ const renderSubject = () => render(Mounter, { onExecuted, onDestroyed })
9
+
10
+ describe('cleanup', () => {
11
+ test('cleanup deletes element', async () => {
12
+ renderSubject()
13
+ cleanup()
14
+
15
+ expect(document.body).toBeEmptyDOMElement()
16
+ })
17
+
18
+ test('cleanup unmounts component', async () => {
19
+ await act(renderSubject)
20
+ cleanup()
21
+
22
+ expect(onDestroyed).toHaveBeenCalledOnce()
23
+ })
24
+
25
+ test('cleanup handles unexpected errors during mount', () => {
26
+ onExecuted.mockImplementation(() => {
27
+ throw new Error('oh no!')
28
+ })
29
+
30
+ expect(renderSubject).toThrowError()
31
+ cleanup()
32
+
33
+ expect(document.body).toBeEmptyDOMElement()
34
+ })
35
+ })
@@ -0,0 +1,19 @@
1
+ <script>
2
+ import { onDestroy, onMount } from 'svelte'
3
+
4
+ export let onExecuted = undefined
5
+ export let onMounted = undefined
6
+ export let onDestroyed = undefined
7
+
8
+ onExecuted?.()
9
+
10
+ onMount(() => {
11
+ onMounted?.()
12
+ })
13
+
14
+ onDestroy(() => {
15
+ onDestroyed?.()
16
+ })
17
+ </script>
18
+
19
+ <button />
@@ -0,0 +1,17 @@
1
+ <script>
2
+ import { onDestroy, onMount } from 'svelte'
3
+
4
+ export let onExecuted = undefined
5
+ export let onMounted = undefined
6
+ export let onDestroyed = undefined
7
+
8
+ export let name = ''
9
+
10
+ onExecuted?.()
11
+
12
+ onMount(() => onMounted?.())
13
+
14
+ onDestroy(() => onDestroyed?.())
15
+ </script>
16
+
17
+ <div data-testid="test">Hello {name}!</div>
@@ -0,0 +1,5 @@
1
+ <script lang="ts">
2
+ export let name: string
3
+ </script>
4
+
5
+ <h1>hello {name}</h1>
@@ -0,0 +1,18 @@
1
+ <script>
2
+ import { blur } from 'svelte/transition'
3
+
4
+ let show = false
5
+ let introDone = false
6
+ </script>
7
+
8
+ <button on:click={() => (show = true)}>Show</button>
9
+
10
+ {#if show}
11
+ <div in:blur={{ duration: 64 }} on:introend={() => (introDone = true)}>
12
+ {#if introDone}
13
+ <p data-testid="intro-done">Done</p>
14
+ {:else}
15
+ <p data-testid="intro-pending">Pending</p>
16
+ {/if}
17
+ </div>
18
+ {/if}
@@ -0,0 +1,33 @@
1
+ import { describe, expect, test, vi } from 'vitest'
2
+
3
+ import { act, render, screen } from '..'
4
+ import Mounter from './fixtures/Mounter.svelte'
5
+
6
+ const onMounted = vi.fn()
7
+ const onDestroyed = vi.fn()
8
+ const renderSubject = () => render(Mounter, { onMounted, onDestroyed })
9
+
10
+ describe('mount and destroy', () => {
11
+ test('component is mounted', async () => {
12
+ renderSubject()
13
+
14
+ const content = screen.getByRole('button')
15
+
16
+ expect(content).toBeInTheDocument()
17
+ await act()
18
+ expect(onMounted).toHaveBeenCalledOnce()
19
+ })
20
+
21
+ test('component is destroyed', async () => {
22
+ const { unmount } = renderSubject()
23
+
24
+ await act()
25
+ unmount()
26
+
27
+ const content = screen.queryByRole('button')
28
+
29
+ expect(content).not.toBeInTheDocument()
30
+ await act()
31
+ expect(onDestroyed).toHaveBeenCalledOnce()
32
+ })
33
+ })
@@ -1,3 +1,4 @@
1
+ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
1
2
  import { beforeEach, describe, expect, test } from 'vitest'
2
3
 
3
4
  import { act, render as stlRender } from '..'
@@ -11,13 +12,13 @@ describe('render', () => {
11
12
  return stlRender(Comp, {
12
13
  target: document.body,
13
14
  props,
14
- ...additional
15
+ ...additional,
15
16
  })
16
17
  }
17
18
 
18
19
  beforeEach(() => {
19
20
  props = {
20
- name: 'World'
21
+ name: 'World',
21
22
  }
22
23
  })
23
24
 
@@ -41,7 +42,9 @@ describe('render', () => {
41
42
  })
42
43
 
43
44
  test('change props with accessors', async () => {
44
- const { component, getByText } = render({ accessors: true })
45
+ const { component, getByText } = render(
46
+ SVELTE_VERSION < '5' ? { accessors: true } : {}
47
+ )
45
48
 
46
49
  expect(getByText('Hello World!')).toBeInTheDocument()
47
50
 
@@ -59,23 +62,41 @@ describe('render', () => {
59
62
  expect(getByText('Hello World!')).toBeInTheDocument()
60
63
  })
61
64
 
62
- test('should accept svelte component options', () => {
63
- const target = document.createElement('div')
64
- const div = document.createElement('div')
65
- document.body.appendChild(target)
66
- target.appendChild(div)
67
- const { container } = stlRender(Comp, {
68
- target,
69
- anchor: div,
70
- props: { name: 'World' },
71
- context: new Map([['name', 'context']])
72
- })
73
- expect(container).toMatchSnapshot()
74
- })
65
+ test.runIf(SVELTE_VERSION < '5')(
66
+ 'should accept svelte v4 component options',
67
+ () => {
68
+ const target = document.createElement('div')
69
+ const div = document.createElement('div')
70
+ document.body.appendChild(target)
71
+ target.appendChild(div)
72
+ const { container } = stlRender(Comp, {
73
+ target,
74
+ anchor: div,
75
+ props: { name: 'World' },
76
+ context: new Map([['name', 'context']]),
77
+ })
78
+ expect(container).toMatchSnapshot()
79
+ }
80
+ )
81
+
82
+ test.runIf(SVELTE_VERSION >= '5')(
83
+ 'should accept svelte v5 component options',
84
+ () => {
85
+ const target = document.createElement('section')
86
+ document.body.appendChild(target)
87
+
88
+ const { container } = stlRender(Comp, {
89
+ target,
90
+ props: { name: 'World' },
91
+ context: new Map([['name', 'context']]),
92
+ })
93
+ expect(container).toMatchSnapshot()
94
+ }
95
+ )
75
96
 
76
97
  test('should throw error when mixing svelte component options and props', () => {
77
98
  expect(() => {
78
- stlRender(Comp, { anchor: '', name: 'World' })
99
+ stlRender(Comp, { props: {}, name: 'World' })
79
100
  }).toThrow(/Unknown options were found/)
80
101
  })
81
102
 
@@ -93,10 +114,8 @@ describe('render', () => {
93
114
 
94
115
  test("accept the 'context' option", () => {
95
116
  const { getByText } = stlRender(Comp, {
96
- props: {
97
- name: 'Universe'
98
- },
99
- context: new Map([['name', 'context']])
117
+ props: { name: 'Universe' },
118
+ context: new Map([['name', 'context']]),
100
119
  })
101
120
 
102
121
  expect(getByText('we have context')).toBeInTheDocument()
@@ -1,38 +1,41 @@
1
1
  /**
2
2
  * @jest-environment jsdom
3
3
  */
4
- import { describe, expect, test } from 'vitest'
4
+ import { describe, expect, test, vi } from 'vitest'
5
+ import { writable } from 'svelte/store'
5
6
 
6
- import { render } from '..'
7
- import Comp from './fixtures/Comp.svelte'
7
+ import { act, render, waitFor } from '..'
8
+ import Comp from './fixtures/Rerender.svelte'
8
9
 
9
- describe('rerender', () => {
10
- test('mounts new component successfully', () => {
11
- const { container, rerender } = render(Comp, { props: { name: 'World 1' } })
10
+ test('mounts new component successfully', async () => {
11
+ const onMounted = vi.fn()
12
+ const onDestroyed = vi.fn()
12
13
 
13
- expect(container.firstChild).toHaveTextContent('Hello World 1!')
14
- rerender({ props: { name: 'World 2' } })
15
- expect(container.firstChild).toHaveTextContent('Hello World 2!')
14
+ const { getByTestId, rerender } = render(Comp, {
15
+ props: { name: 'World 1', onMounted, onDestroyed },
16
16
  })
17
17
 
18
- test('destroys old component', () => {
19
- let isDestroyed
18
+ const expectToRender = (content) =>
19
+ waitFor(() => {
20
+ expect(getByTestId('test')).toHaveTextContent(content)
21
+ expect(onMounted).toHaveBeenCalledOnce()
22
+ })
20
23
 
21
- const { rerender, component } = render(Comp, { props: { name: '' } })
24
+ await expectToRender('Hello World 1!')
22
25
 
23
- component.$$.on_destroy.push(() => {
24
- isDestroyed = true
25
- })
26
- rerender({ props: { name: '' } })
27
- expect(isDestroyed).toBeTruthy()
28
- })
26
+ console.warn = vi.fn()
29
27
 
30
- test('destroys old components on multiple rerenders', () => {
31
- const { rerender, queryByText } = render(Comp, { props: { name: 'Neil' } })
28
+ rerender({ props: { name: 'World 2' } })
29
+ await expectToRender('Hello World 2!')
30
+ expect(onDestroyed).not.toHaveBeenCalled()
32
31
 
33
- rerender({ props: { name: 'Alex' } })
34
- expect(queryByText('Hello Neil!')).not.toBeInTheDocument()
35
- rerender({ props: { name: 'Geddy' } })
36
- expect(queryByText('Hello Alex!')).not.toBeInTheDocument()
37
- })
32
+ expect(console.warn).toHaveBeenCalledOnce()
33
+
34
+ console.warn.mockClear()
35
+ onDestroyed.mockReset()
36
+ rerender({ name: 'World 3' })
37
+ await expectToRender('Hello World 3!')
38
+ expect(onDestroyed).not.toHaveBeenCalled()
39
+
40
+ expect(console.warn).not.toHaveBeenCalled()
38
41
  })
@@ -0,0 +1,31 @@
1
+ import { userEvent } from '@testing-library/user-event'
2
+ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
3
+ import { beforeEach, describe, expect, test, vi } from 'vitest'
4
+
5
+ import { render, screen, waitFor } from '..'
6
+ import Transitioner from './fixtures/Transitioner.svelte'
7
+
8
+ describe.runIf(SVELTE_VERSION < '5')('transitions', () => {
9
+ beforeEach(() => {
10
+ if (window.navigator.userAgent.includes('jsdom')) {
11
+ const raf = (fn) => setTimeout(() => fn(new Date()), 16)
12
+ vi.stubGlobal('requestAnimationFrame', raf)
13
+ }
14
+ })
15
+
16
+ test('on:introend', async () => {
17
+ const user = userEvent.setup()
18
+
19
+ render(Transitioner)
20
+ const start = screen.getByRole('button')
21
+ await user.click(start)
22
+
23
+ const pending = screen.getByTestId('intro-pending')
24
+ expect(pending).toBeInTheDocument()
25
+
26
+ await waitFor(() => {
27
+ const done = screen.queryByTestId('intro-done')
28
+ expect(done).toBeInTheDocument()
29
+ })
30
+ })
31
+ })
package/src/pure.js CHANGED
@@ -1,21 +1,17 @@
1
1
  import {
2
2
  fireEvent as dtlFireEvent,
3
3
  getQueriesForElement,
4
- prettyDOM
4
+ prettyDOM,
5
5
  } from '@testing-library/dom'
6
- import { tick } from 'svelte'
6
+ import * as Svelte from 'svelte'
7
7
 
8
- const containerCache = new Set()
8
+ const IS_SVELTE_5 = typeof Svelte.createRoot === 'function'
9
+ const targetCache = new Set()
9
10
  const componentCache = new Set()
10
11
 
11
- const svelteComponentOptions = [
12
- 'accessors',
13
- 'anchor',
14
- 'props',
15
- 'hydrate',
16
- 'intro',
17
- 'context'
18
- ]
12
+ const svelteComponentOptions = IS_SVELTE_5
13
+ ? ['target', 'props', 'events', 'context', 'intro', 'recover']
14
+ : ['accessors', 'anchor', 'props', 'hydrate', 'intro', 'context']
19
15
 
20
16
  const render = (
21
17
  Component,
@@ -24,6 +20,7 @@ const render = (
24
20
  ) => {
25
21
  container = container || document.body
26
22
  target = target || container.appendChild(document.createElement('div'))
23
+ targetCache.add(target)
27
24
 
28
25
  const ComponentConstructor = Component.default || Component
29
26
 
@@ -54,78 +51,87 @@ const render = (
54
51
  return { props: options }
55
52
  }
56
53
 
57
- let component = new ComponentConstructor({
58
- target,
59
- ...checkProps(options)
60
- })
54
+ const renderComponent = (options) => {
55
+ options = { target, ...checkProps(options) }
61
56
 
62
- containerCache.add({ container, target, component })
63
- componentCache.add(component)
57
+ const component = IS_SVELTE_5
58
+ ? Svelte.createRoot(ComponentConstructor, options)
59
+ : new ComponentConstructor(options)
64
60
 
65
- component.$$.on_destroy.push(() => {
66
- componentCache.delete(component)
67
- })
61
+ componentCache.add(component)
62
+
63
+ // TODO(mcous, 2024-02-11): remove this behavior in the next major version
64
+ // It is unnecessary has no path to implementation in Svelte v5
65
+ if (!IS_SVELTE_5) {
66
+ component.$$.on_destroy.push(() => {
67
+ componentCache.delete(component)
68
+ })
69
+ }
70
+
71
+ return component
72
+ }
73
+
74
+ let component = renderComponent(options)
68
75
 
69
76
  return {
70
77
  container,
71
78
  component,
72
79
  debug: (el = container) => console.log(prettyDOM(el)),
73
- rerender: (options) => {
74
- if (componentCache.has(component)) component.$destroy()
75
-
76
- // eslint-disable-next-line no-new
77
- component = new ComponentConstructor({
78
- target,
79
- ...checkProps(options)
80
- })
81
-
82
- containerCache.add({ container, target, component })
83
- componentCache.add(component)
84
-
85
- component.$$.on_destroy.push(() => {
86
- componentCache.delete(component)
87
- })
80
+ rerender: async (props) => {
81
+ if (props.props) {
82
+ console.warn(
83
+ 'rerender({ props: {...} }) deprecated, use rerender({...}) instead'
84
+ )
85
+ props = props.props
86
+ }
87
+ component.$set(props)
88
+ await Svelte.tick()
88
89
  },
89
90
  unmount: () => {
90
- if (componentCache.has(component)) component.$destroy()
91
+ cleanupComponent(component)
91
92
  },
92
- ...getQueriesForElement(container, queries)
93
+ ...getQueriesForElement(container, queries),
93
94
  }
94
95
  }
95
96
 
96
- const cleanupAtContainer = (cached) => {
97
- const { target, component } = cached
97
+ const cleanupComponent = (component) => {
98
+ const inCache = componentCache.delete(component)
98
99
 
99
- if (componentCache.has(component)) component.$destroy()
100
+ if (inCache) {
101
+ component.$destroy()
102
+ }
103
+ }
100
104
 
101
- if (target.parentNode === document.body) {
105
+ const cleanupTarget = (target) => {
106
+ const inCache = targetCache.delete(target)
107
+
108
+ if (inCache && target.parentNode === document.body) {
102
109
  document.body.removeChild(target)
103
110
  }
104
-
105
- containerCache.delete(cached)
106
111
  }
107
112
 
108
113
  const cleanup = () => {
109
- Array.from(containerCache.keys()).forEach(cleanupAtContainer)
114
+ componentCache.forEach(cleanupComponent)
115
+ targetCache.forEach(cleanupTarget)
110
116
  }
111
117
 
112
118
  const act = async (fn) => {
113
119
  if (fn) {
114
120
  await fn()
115
121
  }
116
- return tick()
122
+ return Svelte.tick()
117
123
  }
118
124
 
119
125
  const fireEvent = async (...args) => {
120
126
  const event = dtlFireEvent(...args)
121
- await tick()
127
+ await Svelte.tick()
122
128
  return event
123
129
  }
124
130
 
125
131
  Object.keys(dtlFireEvent).forEach((key) => {
126
132
  fireEvent[key] = async (...args) => {
127
133
  const event = dtlFireEvent[key](...args)
128
- await tick()
134
+ await Svelte.tick()
129
135
  return event
130
136
  }
131
137
  })
package/types/index.d.ts CHANGED
@@ -2,25 +2,42 @@
2
2
  // Project: https://github.com/testing-library/svelte-testing-library
3
3
  // Definitions by: Rahim Alwer <https://github.com/mihar-22>
4
4
 
5
- import {BoundFunction, EventType,Queries, queries} from '@testing-library/dom'
6
- import { ComponentConstructorOptions,ComponentProps, SvelteComponent } from 'svelte'
5
+ import {
6
+ BoundFunction,
7
+ EventType,
8
+ Queries,
9
+ queries,
10
+ } from '@testing-library/dom'
11
+ import {
12
+ ComponentConstructorOptions,
13
+ ComponentProps,
14
+ SvelteComponent,
15
+ } from 'svelte'
7
16
 
8
17
  export * from '@testing-library/dom'
9
18
 
10
- type SvelteComponentOptions<C extends SvelteComponent> = ComponentProps<C> | Pick<ComponentConstructorOptions<ComponentProps<C>>, "anchor" | "props" | "hydrate" | "intro" | "context">
19
+ type SvelteComponentOptions<C extends SvelteComponent> =
20
+ | ComponentProps<C>
21
+ | Pick<
22
+ ComponentConstructorOptions<ComponentProps<C>>,
23
+ 'anchor' | 'props' | 'hydrate' | 'intro' | 'context'
24
+ >
11
25
 
12
26
  type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
13
27
 
14
- type Constructor<T> = new (...args: any[]) => T;
28
+ type Constructor<T> = new (...args: any[]) => T
15
29
 
16
30
  /**
17
31
  * Render a Component into the Document.
18
32
  */
19
- export type RenderResult<C extends SvelteComponent, Q extends Queries = typeof queries> = {
33
+ export type RenderResult<
34
+ C extends SvelteComponent,
35
+ Q extends Queries = typeof queries,
36
+ > = {
20
37
  container: HTMLElement
21
38
  component: C
22
39
  debug: (el?: HTMLElement | DocumentFragment) => void
23
- rerender: (options: SvelteComponentOptions<C>) => void
40
+ rerender: (props: ComponentProps<C>) => Promise<void>
24
41
  unmount: () => void
25
42
  } & { [P in keyof Q]: BoundFunction<Q[P]> }
26
43
 
@@ -38,7 +55,7 @@ export function render<C extends SvelteComponent>(
38
55
  export function render<C extends SvelteComponent, Q extends Queries>(
39
56
  component: Constructor<C>,
40
57
  componentOptions?: SvelteComponentOptions<C>,
41
- renderOptions?: RenderOptions<Q>,
58
+ renderOptions?: RenderOptions<Q>
42
59
  ): RenderResult<C, Q>
43
60
 
44
61
  /**
@@ -50,13 +67,19 @@ export function cleanup(): void
50
67
  * Fires DOM events on an element provided by @testing-library/dom. Since Svelte needs to flush
51
68
  * pending state changes via `tick`, these methods have been override and now return a promise.
52
69
  */
53
- export type FireFunction = (element: Document | Element | Window, event: Event) => Promise<boolean>;
70
+ export type FireFunction = (
71
+ element: Document | Element | Window,
72
+ event: Event
73
+ ) => Promise<boolean>
54
74
 
55
75
  export type FireObject = {
56
- [K in EventType]: (element: Document | Element | Window, options?: {}) => Promise<boolean>;
57
- };
76
+ [K in EventType]: (
77
+ element: Document | Element | Window,
78
+ options?: {}
79
+ ) => Promise<boolean>
80
+ }
58
81
 
59
- export const fireEvent: FireFunction & FireObject;
82
+ export const fireEvent: FireFunction & FireObject
60
83
 
61
84
  /**
62
85
  * Calls a function and notifies Svelte to flush any pending state changes.
@@ -1,40 +0,0 @@
1
- <script>
2
- import { onDestroy } from 'svelte'
3
-
4
- let timer
5
- let lapse = 0
6
- let running = false
7
-
8
- function handleRunClick () {
9
- if (running) {
10
- clearInterval(timer)
11
- } else {
12
- const startTime = Date.now() - lapse
13
-
14
- timer = setInterval(() => {
15
- lapse = Date.now() - startTime
16
- }, 1)
17
- }
18
- running = true
19
- }
20
-
21
- function handleClearClick () {
22
- clearInterval(timer)
23
- lapse = 0
24
- running = false
25
- }
26
-
27
- onDestroy(() => {
28
- clearInterval(timer)
29
- })
30
- </script>
31
-
32
- <style></style>
33
-
34
- <span>{lapse}ms</span>
35
-
36
- <button on:click={handleRunClick}>
37
- {running ? 'Stop' : 'Start'}
38
- </button>
39
-
40
- <button on:click={handleClearClick}>Clear</button>
@@ -1,35 +0,0 @@
1
- import { describe, expect, test, vi } from 'vitest'
2
-
3
- import { act, fireEvent, render } from '..'
4
- import Stopwatch from './fixtures/Stopwatch.svelte'
5
-
6
- describe('unmount', () => {
7
- test('unmounts component successfully', async () => {
8
- console.warn = vi.fn()
9
-
10
- const { unmount, getByText, container } = render(Stopwatch)
11
-
12
- await fireEvent.click(getByText('Start'))
13
-
14
- unmount()
15
-
16
- // Hey there reader! You don't need to have an assertion like this one
17
- // this is just me making sure that the unmount function works.
18
- // You don't need to do this in your apps. Just rely on the fact that this works.
19
- expect(container.innerHTML).toBe('<div></div>')
20
-
21
- await act()
22
- expect(console.warn).not.toHaveBeenCalled()
23
- })
24
-
25
- test('destroying component directly and calling unmount does not log warning', async () => {
26
- console.warn = vi.fn()
27
-
28
- const { unmount, component } = render(Stopwatch)
29
-
30
- component.$destroy()
31
- unmount()
32
-
33
- expect(console.warn).not.toHaveBeenCalled()
34
- })
35
- })