@testing-library/svelte 4.2.0 → 4.2.1

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
@@ -80,6 +80,21 @@ This library has `peerDependencies` listings for `svelte >= 3`.
80
80
  You may also be interested in installing `@testing-library/jest-dom` so you can use
81
81
  [the custom jest matchers](https://github.com/testing-library/jest-dom).
82
82
 
83
+ ### Svelte 5 support
84
+
85
+ If you are riding the bleeding edge of Svelte 5, you'll need to either
86
+ import from `@testing-library/svelte/svelte5` instead of `@testing-library/svelte`, or have your `vite.config.js` contains the following alias:
87
+
88
+ ```
89
+ export default defineConfig(({ }) => ({
90
+ test: {
91
+ alias: {
92
+ '@testing-library/svelte': '@testing-library/svelte/svelte5'
93
+ }
94
+ },
95
+ }))
96
+ ```
97
+
83
98
  ## Docs
84
99
 
85
100
  See the [**docs**](https://testing-library.com/docs/svelte-testing-library/intro) over at the Testing Library website.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testing-library/svelte",
3
- "version": "4.2.0",
3
+ "version": "4.2.1",
4
4
  "description": "Simple and complete Svelte testing utilities that encourage good testing practices.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -8,6 +8,10 @@
8
8
  "types": "./types/index.d.ts",
9
9
  "default": "./src/index.js"
10
10
  },
11
+ "./svelte5": {
12
+ "types": "./types/index.d.ts",
13
+ "default": "./src/svelte5-index.js"
14
+ },
11
15
  "./vitest": {
12
16
  "default": "./src/vitest.js"
13
17
  }
@@ -1,6 +1,6 @@
1
1
  import { beforeEach, describe, expect, test } from 'vitest'
2
2
 
3
- import { act, fireEvent, render as stlRender } from '..'
3
+ import { act, fireEvent, render as stlRender } from '@testing-library/svelte'
4
4
  import Comp from './fixtures/Comp.svelte'
5
5
 
6
6
  describe('act', () => {
@@ -7,7 +7,7 @@ describe('auto-cleanup-skip', () => {
7
7
 
8
8
  beforeAll(async () => {
9
9
  process.env.STL_SKIP_AUTO_CLEANUP = 'true'
10
- const stl = await import('..')
10
+ const stl = await import('@testing-library/svelte')
11
11
  render = stl.render
12
12
  })
13
13
 
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from 'vitest'
2
2
 
3
- import { render } from '..'
3
+ import { render } from '@testing-library/svelte'
4
4
  import Comp from './fixtures/Comp.svelte'
5
5
 
6
6
  describe('auto-cleanup', () => {
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, test, vi } from 'vitest'
2
+ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
2
3
 
3
- import { act, cleanup, render } from '..'
4
+ import { act, cleanup, render } from '@testing-library/svelte'
4
5
  import Mounter from './fixtures/Mounter.svelte'
5
6
 
6
7
  const onExecuted = vi.fn()
@@ -15,7 +16,7 @@ describe('cleanup', () => {
15
16
  expect(document.body).toBeEmptyDOMElement()
16
17
  })
17
18
 
18
- test('cleanup unmounts component', async () => {
19
+ test.runIf(SVELTE_VERSION < '5')('cleanup unmounts component', async () => {
19
20
  await act(renderSubject)
20
21
  cleanup()
21
22
 
@@ -1,9 +1,10 @@
1
1
  import { expect, test } from 'vitest'
2
2
 
3
- import { render } from '..'
3
+ import { render } from '@testing-library/svelte'
4
4
  import Comp from './fixtures/Context.svelte'
5
+ import { IS_HAPPYDOM, IS_SVELTE_5 } from './utils.js'
5
6
 
6
- test('can set a context', () => {
7
+ test.skipIf(IS_SVELTE_5 && IS_HAPPYDOM)('can set a context', () => {
7
8
  const message = 'Got it'
8
9
 
9
10
  const { getByText } = render(Comp, {
@@ -1,7 +1,7 @@
1
1
  import { prettyDOM } from '@testing-library/dom'
2
2
  import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
3
3
 
4
- import { render } from '..'
4
+ import { render } from '@testing-library/svelte'
5
5
  import Comp from './fixtures/Comp.svelte'
6
6
 
7
7
  describe('debug', () => {
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from 'vitest'
2
2
 
3
- import { fireEvent, render } from '..'
3
+ import { fireEvent, render } from '@testing-library/svelte'
4
4
  import Comp from './fixtures/Comp.svelte'
5
5
 
6
6
  describe('events', () => {
@@ -1,13 +1,14 @@
1
1
  import { describe, expect, test, vi } from 'vitest'
2
2
 
3
- import { act, render, screen } from '..'
3
+ import { act, render, screen } from '@testing-library/svelte'
4
4
  import Mounter from './fixtures/Mounter.svelte'
5
+ import { IS_HAPPYDOM, IS_SVELTE_5 } from './utils.js'
5
6
 
6
7
  const onMounted = vi.fn()
7
8
  const onDestroyed = vi.fn()
8
9
  const renderSubject = () => render(Mounter, { onMounted, onDestroyed })
9
10
 
10
- describe('mount and destroy', () => {
11
+ describe.skipIf(IS_SVELTE_5 && IS_HAPPYDOM)('mount and destroy', () => {
11
12
  test('component is mounted', async () => {
12
13
  renderSubject()
13
14
 
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from 'vitest'
2
2
 
3
- import { render } from '..'
3
+ import { render } from '@testing-library/svelte'
4
4
  import Comp from './fixtures/Comp.svelte'
5
5
 
6
6
  describe('multi-base', () => {
@@ -1,7 +1,7 @@
1
1
  import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
2
2
  import { beforeEach, describe, expect, test } from 'vitest'
3
3
 
4
- import { act, render as stlRender } from '..'
4
+ import { act, render as stlRender } from '@testing-library/svelte'
5
5
  import Comp from './fixtures/Comp.svelte'
6
6
  import CompDefault from './fixtures/Comp2.svelte'
7
7
 
@@ -107,7 +107,7 @@ describe('render', () => {
107
107
  })
108
108
 
109
109
  test('correctly find component constructor on the default property', () => {
110
- const { getByText } = render(CompDefault, { props: { name: 'World' } })
110
+ const { getByText } = stlRender(CompDefault, { props: { name: 'World' } })
111
111
 
112
112
  expect(getByText('Hello World!')).toBeInTheDocument()
113
113
  })
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * @jest-environment jsdom
3
3
  */
4
- import { describe, expect, test, vi } from 'vitest'
5
- import { writable } from 'svelte/store'
4
+ import { expect, test, vi } from 'vitest'
5
+
6
+ import { render, waitFor } from '@testing-library/svelte'
6
7
 
7
- import { act, render, waitFor } from '..'
8
8
  import Comp from './fixtures/Rerender.svelte'
9
9
 
10
10
  test('mounts new component successfully', async () => {
@@ -1,16 +1,17 @@
1
1
  import { userEvent } from '@testing-library/user-event'
2
- import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
3
2
  import { beforeEach, describe, expect, test, vi } from 'vitest'
4
3
 
5
- import { render, screen, waitFor } from '..'
4
+ import { IS_JSDOM, IS_SVELTE_5 } from './utils.js'
5
+
6
+ import { render, screen, waitFor } from '@testing-library/svelte'
6
7
  import Transitioner from './fixtures/Transitioner.svelte'
7
8
 
8
- describe.runIf(SVELTE_VERSION < '5')('transitions', () => {
9
+ describe.runIf(!IS_SVELTE_5)('transitions', () => {
9
10
  beforeEach(() => {
10
- if (window.navigator.userAgent.includes('jsdom')) {
11
- const raf = (fn) => setTimeout(() => fn(new Date()), 16)
12
- vi.stubGlobal('requestAnimationFrame', raf)
13
- }
11
+ if (!IS_JSDOM) return
12
+
13
+ const raf = (fn) => setTimeout(() => fn(new Date()), 16)
14
+ vi.stubGlobal('requestAnimationFrame', raf)
14
15
  })
15
16
 
16
17
  test('on:introend', async () => {
@@ -0,0 +1,7 @@
1
+ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
2
+
3
+ export const IS_JSDOM = window.navigator.userAgent.includes('jsdom')
4
+
5
+ export const IS_HAPPYDOM = !IS_JSDOM // right now it's happy or js
6
+
7
+ export const IS_SVELTE_5 = SVELTE_VERSION >= '5'
package/src/index.js CHANGED
@@ -13,3 +13,4 @@ if (typeof afterEach === 'function' && !process.env.STL_SKIP_AUTO_CLEANUP) {
13
13
  }
14
14
 
15
15
  export * from './pure.js'
16
+ export * from '@testing-library/dom'
package/src/pure.js CHANGED
@@ -3,60 +3,60 @@ import {
3
3
  getQueriesForElement,
4
4
  prettyDOM,
5
5
  } from '@testing-library/dom'
6
+ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'
6
7
  import * as Svelte from 'svelte'
7
8
 
8
- const IS_SVELTE_5 = typeof Svelte.createRoot === 'function'
9
- const targetCache = new Set()
10
- const componentCache = new Set()
11
-
12
- const svelteComponentOptions = IS_SVELTE_5
13
- ? ['target', 'props', 'events', 'context', 'intro', 'recover']
14
- : ['accessors', 'anchor', 'props', 'hydrate', 'intro', 'context']
15
-
16
- const render = (
17
- Component,
18
- { target, ...options } = {},
19
- { container, queries } = {}
20
- ) => {
21
- container = container || document.body
22
- target = target || container.appendChild(document.createElement('div'))
23
- targetCache.add(target)
24
-
25
- const ComponentConstructor = Component.default || Component
26
-
27
- const checkProps = (options) => {
28
- const isProps = !Object.keys(options).some((option) =>
29
- svelteComponentOptions.includes(option)
9
+ const IS_SVELTE_5 = /^5\./.test(SVELTE_VERSION)
10
+ export const targetCache = new Set()
11
+ export const componentCache = new Set()
12
+
13
+ const svelteComponentOptions = [
14
+ 'accessors',
15
+ 'anchor',
16
+ 'props',
17
+ 'hydrate',
18
+ 'intro',
19
+ 'context',
20
+ ]
21
+
22
+ export const buildCheckProps = (svelteComponentOptions) => (options) => {
23
+ const isProps = !Object.keys(options).some((option) =>
24
+ svelteComponentOptions.includes(option)
25
+ )
26
+
27
+ // Check if any props and Svelte options were accidentally mixed.
28
+ if (!isProps) {
29
+ const unrecognizedOptions = Object.keys(options).filter(
30
+ (option) => !svelteComponentOptions.includes(option)
30
31
  )
31
32
 
32
- // Check if any props and Svelte options were accidentally mixed.
33
- if (!isProps) {
34
- const unrecognizedOptions = Object.keys(options).filter(
35
- (option) => !svelteComponentOptions.includes(option)
36
- )
37
-
38
- if (unrecognizedOptions.length > 0) {
39
- throw Error(`
33
+ if (unrecognizedOptions.length > 0) {
34
+ throw Error(`
40
35
  Unknown options were found [${unrecognizedOptions}]. This might happen if you've mixed
41
36
  passing in props with Svelte options into the render function. Valid Svelte options
42
37
  are [${svelteComponentOptions}]. You can either change the prop names, or pass in your
43
38
  props for that component via the \`props\` option.\n\n
44
39
  Eg: const { /** Results **/ } = render(MyComponent, { props: { /** props here **/ } })\n\n
45
40
  `)
46
- }
47
-
48
- return options
49
41
  }
50
42
 
51
- return { props: options }
43
+ return options
52
44
  }
53
45
 
54
- const renderComponent = (options) => {
46
+ return { props: options }
47
+ }
48
+
49
+ const checkProps = buildCheckProps(svelteComponentOptions)
50
+
51
+ const buildRenderComponent =
52
+ ({ target, ComponentConstructor }) =>
53
+ (options) => {
55
54
  options = { target, ...checkProps(options) }
56
55
 
57
- const component = IS_SVELTE_5
58
- ? Svelte.createRoot(ComponentConstructor, options)
59
- : new ComponentConstructor(options)
56
+ if (IS_SVELTE_5)
57
+ throw new Error('for Svelte 5, use `@testing-library/svelte/svelte5`')
58
+
59
+ const component = new ComponentConstructor(options)
60
60
 
61
61
  componentCache.add(component)
62
62
 
@@ -71,30 +71,46 @@ const render = (
71
71
  return component
72
72
  }
73
73
 
74
- let component = renderComponent(options)
75
-
76
- return {
77
- container,
78
- component,
79
- debug: (el = container) => console.log(prettyDOM(el)),
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()
89
- },
90
- unmount: () => {
91
- cleanupComponent(component)
92
- },
93
- ...getQueriesForElement(container, queries),
74
+ export const buildRender =
75
+ (buildRenderComponent) =>
76
+ (Component, { target, ...options } = {}, { container, queries } = {}) => {
77
+ container = container || document.body
78
+ target = target || container.appendChild(document.createElement('div'))
79
+ targetCache.add(target)
80
+
81
+ const ComponentConstructor = Component.default || Component
82
+
83
+ const renderComponent = buildRenderComponent({
84
+ target,
85
+ ComponentConstructor,
86
+ })
87
+
88
+ let component = renderComponent(options)
89
+
90
+ return {
91
+ container,
92
+ component,
93
+ debug: (el = container) => console.log(prettyDOM(el)),
94
+ rerender: async (props) => {
95
+ if (props.props) {
96
+ console.warn(
97
+ 'rerender({ props: {...} }) deprecated, use rerender({...}) instead'
98
+ )
99
+ props = props.props
100
+ }
101
+ component.$set(props)
102
+ await Svelte.tick()
103
+ },
104
+ unmount: () => {
105
+ cleanupComponent(component)
106
+ },
107
+ ...getQueriesForElement(container, queries),
108
+ }
94
109
  }
95
- }
96
110
 
97
- const cleanupComponent = (component) => {
111
+ export const render = buildRender(buildRenderComponent)
112
+
113
+ export const cleanupComponent = (component) => {
98
114
  const inCache = componentCache.delete(component)
99
115
 
100
116
  if (inCache) {
@@ -110,19 +126,19 @@ const cleanupTarget = (target) => {
110
126
  }
111
127
  }
112
128
 
113
- const cleanup = () => {
129
+ export const cleanup = () => {
114
130
  componentCache.forEach(cleanupComponent)
115
131
  targetCache.forEach(cleanupTarget)
116
132
  }
117
133
 
118
- const act = async (fn) => {
134
+ export const act = async (fn) => {
119
135
  if (fn) {
120
136
  await fn()
121
137
  }
122
138
  return Svelte.tick()
123
139
  }
124
140
 
125
- const fireEvent = async (...args) => {
141
+ export const fireEvent = async (...args) => {
126
142
  const event = dtlFireEvent(...args)
127
143
  await Svelte.tick()
128
144
  return event
@@ -135,9 +151,3 @@ Object.keys(dtlFireEvent).forEach((key) => {
135
151
  return event
136
152
  }
137
153
  })
138
-
139
- /* eslint-disable import/export */
140
-
141
- export * from '@testing-library/dom'
142
-
143
- export { render, cleanup, fireEvent, act }
@@ -0,0 +1,17 @@
1
+ import { act, cleanup } from './svelte5.js'
2
+
3
+ // If we're running in a test runner that supports afterEach
4
+ // then we'll automatically run cleanup afterEach test
5
+ // this ensures that tests run in isolation from each other
6
+ // if you don't like this then either import the `pure` module
7
+ // or set the STL_SKIP_AUTO_CLEANUP env variable to 'true'.
8
+ if (typeof afterEach === 'function' && !process.env.STL_SKIP_AUTO_CLEANUP) {
9
+ afterEach(async () => {
10
+ await act()
11
+ cleanup()
12
+ })
13
+ }
14
+
15
+ export * from './svelte5.js'
16
+ export * from '@testing-library/dom'
17
+ export { act, fireEvent } from './pure.js'
package/src/svelte5.js ADDED
@@ -0,0 +1,41 @@
1
+ import { createClassComponent } from 'svelte/legacy'
2
+ import {
3
+ componentCache,
4
+ cleanup,
5
+ buildCheckProps,
6
+ buildRender,
7
+ } from './pure.js'
8
+
9
+ const svelteComponentOptions = [
10
+ 'target',
11
+ 'props',
12
+ 'events',
13
+ 'context',
14
+ 'intro',
15
+ 'recover',
16
+ ]
17
+
18
+ const checkProps = buildCheckProps(svelteComponentOptions)
19
+
20
+ const buildRenderComponent =
21
+ ({ target, ComponentConstructor }) =>
22
+ (options) => {
23
+ options = { target, ...checkProps(options) }
24
+
25
+ const component = createClassComponent({
26
+ component: ComponentConstructor,
27
+ ...options,
28
+ })
29
+
30
+ componentCache.add(component)
31
+
32
+ return component
33
+ }
34
+
35
+ const render = buildRender(buildRenderComponent)
36
+
37
+ /* eslint-disable import/export */
38
+
39
+ import { act, fireEvent } from './pure.js'
40
+
41
+ export { render, cleanup, fireEvent, act }
package/src/vitest.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { afterEach } from 'vitest'
2
2
 
3
- import { act, cleanup } from './pure.js'
3
+ import { act, cleanup } from '@testing-library/svelte'
4
4
 
5
5
  afterEach(async () => {
6
6
  await act()