Skip to content

Commit b9ebcc9

Browse files
committed
refactor(types): build types from JS source
1 parent f4c7b90 commit b9ebcc9

File tree

9 files changed

+173
-115
lines changed

9 files changed

+173
-115
lines changed

.github/workflows/release.yml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,35 @@ jobs:
5959
run: npm run test:${{ matrix.test-runner }}
6060

6161
- name: ▶️ Run type-checks
62-
if: ${{ matrix.node == '20' && matrix.svelte == '4' && matrix.test-runner == 'vitest:jsdom' }}
62+
if: ${{ matrix.node == '20' && matrix.svelte != '3' && matrix.test-runner == 'vitest:jsdom' }}
6363
run: npm run types
6464

6565
- name: ⬆️ Upload coverage report
6666
uses: codecov/codecov-action@v3
6767

68+
build:
69+
runs-on: ubuntu-latest
70+
steps:
71+
- name: ⬇️ Checkout repo
72+
uses: actions/checkout@v4
73+
74+
- name: ⎔ Setup node
75+
uses: actions/setup-node@v4
76+
with:
77+
node-version: 20
78+
79+
- name: 📥 Download deps
80+
run: npm install --no-package-lock
81+
82+
- name: 🏗️ Build types
83+
run: npm run build
84+
85+
- name: ⬆️ Upload types build
86+
uses: actions/upload-artifact@v4
87+
with:
88+
name: types
89+
path: types
90+
6891
release:
6992
needs: main
7093
runs-on: ubuntu-latest
@@ -80,6 +103,12 @@ jobs:
80103
with:
81104
node-version: 20
82105

106+
- name: 📥 Downloads types build
107+
uses: actions/download-artifact@v4
108+
with:
109+
name: types
110+
path: types
111+
83112
- name: 🚀 Release
84113
uses: cycjimmy/semantic-release-action@v4
85114
with:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ dist
99
yarn-error.log
1010
package-lock.json
1111
yarn.lock
12+
13+
# generated typing output
14+
types

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@
6969
"test:vitest:happy-dom": "vitest run --coverage --environment happy-dom",
7070
"test:jest": "npx --node-options=\"--experimental-vm-modules --no-warnings\" jest --coverage",
7171
"types": "svelte-check",
72-
"validate": "npm-run-all test:vitest:* types lint",
72+
"validate": "npm-run-all test:vitest:* types build",
73+
"build": "tsc -p tsconfig.build.json",
7374
"contributors:add": "all-contributors add",
7475
"contributors:generate": "all-contributors generate",
7576
"preview-release": "./scripts/preview-release"
@@ -92,7 +93,7 @@
9293
},
9394
"devDependencies": {
9495
"@jest/globals": "^29.7.0",
95-
"@sveltejs/vite-plugin-svelte": "^3.1.1",
96+
"@sveltejs/vite-plu gin-svelte": "^3.1.1",
9697
"@testing-library/jest-dom": "^6.3.0",
9798
"@testing-library/user-event": "^14.5.2",
9899
"@typescript-eslint/eslint-plugin": "7.8.0",

types/types.test-d.ts renamed to src/__tests__/types.test-d.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { expectTypeOf } from 'expect-type'
22
import type { ComponentProps, SvelteComponent } from 'svelte'
33
import { describe, test } from 'vitest'
44

5-
import Simple from '../src/__tests__/fixtures/Simple.svelte'
6-
import * as subject from './index.js'
5+
import * as subject from '../index.js'
6+
import Simple from './fixtures/Simple.svelte'
77

88
describe('types', () => {
99
test('render is a function that accepts a Svelte component', () => {
@@ -62,4 +62,36 @@ describe('types', () => {
6262

6363
expectTypeOf(result.getByVibes).parameters.toMatchTypeOf<[vibes: string]>()
6464
})
65+
66+
test('act is an async function', () => {
67+
expectTypeOf(subject.act).toMatchTypeOf<() => Promise<void>>()
68+
})
69+
70+
test('act accepts a sync function', () => {
71+
expectTypeOf(subject.act).toMatchTypeOf<(fn: () => void) => Promise<void>>()
72+
})
73+
74+
test('act accepts an async function', () => {
75+
expectTypeOf(subject.act).toMatchTypeOf<
76+
(fn: () => Promise<void>) => Promise<void>
77+
>()
78+
})
79+
80+
test('fireEvent is an async function', () => {
81+
expectTypeOf(subject.fireEvent).toMatchTypeOf<
82+
(
83+
element: Element | Node | Document | Window,
84+
event: Event
85+
) => Promise<boolean>
86+
>()
87+
})
88+
89+
test('fireEvent[eventName] is an async function', () => {
90+
expectTypeOf(subject.fireEvent.click).toMatchTypeOf<
91+
(
92+
element: Element | Node | Document | Window,
93+
options?: {}
94+
) => Promise<boolean>
95+
>()
96+
})
6597
})

src/pure.js

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,57 @@
1-
import {
2-
fireEvent as dtlFireEvent,
3-
getQueriesForElement,
4-
prettyDOM,
5-
} from '@testing-library/dom'
6-
import { tick } from 'svelte'
1+
import * as DOMTestingLibrary from '@testing-library/dom'
2+
import * as Svelte from 'svelte'
73

84
import { mount, unmount, updateProps, validateOptions } from './core/index.js'
95

106
const targetCache = new Set()
117
const componentCache = new Set()
128

9+
/**
10+
* Customize how Svelte renders the component.
11+
*
12+
* @template {Svelte.SvelteComponent} C
13+
* @typedef {Svelte.ComponentProps<C> | Partial<Svelte.ComponentConstructorOptions<Svelte.ComponentProps<C>>>} SvelteComponentOptions
14+
*/
15+
16+
/**
17+
* Customize how Testing Library sets up the document and binds queries.
18+
*
19+
* @template {DOMTestingLibrary.Queries} [Q=typeof DOMTestingLibrary.queries]
20+
* @typedef {{
21+
* baseElement?: HTMLElement
22+
* queries?: Q
23+
* }} RenderOptions
24+
*/
25+
26+
/**
27+
* The rendered component and bound testing functions.
28+
*
29+
* @template {Svelte.SvelteComponent} C
30+
* @template {DOMTestingLibrary.Queries} [Q=typeof DOMTestingLibrary.queries]
31+
*
32+
* @typedef {{
33+
* container: HTMLElement
34+
* baseElement: HTMLElement
35+
* component: C
36+
* debug: (el?: HTMLElement | DocumentFragment) => void
37+
* rerender: (props: Partial<Svelte.ComponentProps<C>>) => Promise<void>
38+
* unmount: () => void
39+
* } & {
40+
* [P in keyof Q]: DOMTestingLibrary.BoundFunction<Q[P]>
41+
* }} RenderResult
42+
*/
43+
44+
/**
45+
* Render a component into the document.
46+
*
47+
* @template {Svelte.SvelteComponent} C
48+
* @template {DOMTestingLibrary.Queries} [Q=typeof DOMTestingLibrary.queries]
49+
*
50+
* @param {Svelte.ComponentType<C>} Component - The component to render.
51+
* @param {SvelteComponentOptions<C>} options - Customize how Svelte renders the component.
52+
* @param {RenderOptions<Q>} renderOptions - Customize how Testing Library sets up the document and binds queries.
53+
* @returns {RenderResult<C, Q>} The rendered component and bound testing functions.
54+
*/
1355
const render = (Component, options = {}, renderOptions = {}) => {
1456
options = validateOptions(options)
1557

@@ -33,7 +75,9 @@ const render = (Component, options = {}, renderOptions = {}) => {
3375
baseElement,
3476
component,
3577
container: target,
36-
debug: (el = baseElement) => console.log(prettyDOM(el)),
78+
debug: (el = baseElement) => {
79+
console.log(DOMTestingLibrary.prettyDOM(el))
80+
},
3781
rerender: async (props) => {
3882
if (props.props) {
3983
console.warn(
@@ -43,15 +87,19 @@ const render = (Component, options = {}, renderOptions = {}) => {
4387
}
4488

4589
updateProps(component, props)
46-
await tick()
90+
await Svelte.tick()
4791
},
4892
unmount: () => {
4993
cleanupComponent(component)
5094
},
51-
...getQueriesForElement(baseElement, renderOptions.queries),
95+
...DOMTestingLibrary.getQueriesForElement(
96+
baseElement,
97+
renderOptions.queries
98+
),
5299
}
53100
}
54101

102+
/** Remove a component from the component cache. */
55103
const cleanupComponent = (component) => {
56104
const inCache = componentCache.delete(component)
57105

@@ -60,6 +108,7 @@ const cleanupComponent = (component) => {
60108
}
61109
}
62110

111+
/** Remove a target element from the target cache. */
63112
const cleanupTarget = (target) => {
64113
const inCache = targetCache.delete(target)
65114

@@ -68,28 +117,53 @@ const cleanupTarget = (target) => {
68117
}
69118
}
70119

120+
/** Unmount all components and remove elements added to `<body>`. */
71121
const cleanup = () => {
72122
componentCache.forEach(cleanupComponent)
73123
targetCache.forEach(cleanupTarget)
74124
}
75125

126+
/**
127+
* Call a function and wait for Svelte to flush pending changes.
128+
*
129+
* @param {() => unknown} [fn] - A function, which may be `async`, to call before flushing updates.
130+
* @returns {Promise<void>}
131+
*/
76132
const act = async (fn) => {
77133
if (fn) {
78134
await fn()
79135
}
80-
return tick()
136+
return Svelte.tick()
81137
}
82138

139+
/**
140+
* @typedef {(...args: Parameters<DOMTestingLibrary.FireFunction>) => Promise<ReturnType<DOMTestingLibrary.FireFunction>>} FireFunction
141+
*/
142+
143+
/**
144+
* @typedef {{
145+
* [K in DOMTestingLibrary.EventType]: (...args: Parameters<DOMTestingLibrary.FireObject[K]>) => Promise<ReturnType<DOMTestingLibrary.FireObject[K]>>
146+
* }} FireObject
147+
*/
148+
149+
/**
150+
* Fire an event on an element.
151+
*
152+
* Consider using `@testing-library/user-event` instead, if possible.
153+
* @see https://testing-library.com/docs/user-event/intro/
154+
*
155+
* @type {FireFunction & FireObject}
156+
*/
83157
const fireEvent = async (...args) => {
84-
const event = dtlFireEvent(...args)
85-
await tick()
158+
const event = DOMTestingLibrary.fireEvent(...args)
159+
await Svelte.tick()
86160
return event
87161
}
88162

89-
Object.keys(dtlFireEvent).forEach((key) => {
163+
Object.keys(DOMTestingLibrary.fireEvent).forEach((key) => {
90164
fireEvent[key] = async (...args) => {
91-
const event = dtlFireEvent[key](...args)
92-
await tick()
165+
const event = DOMTestingLibrary.fireEvent[key](...args)
166+
await Svelte.tick()
93167
return event
94168
}
95169
})

tsconfig.build.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"extends": ["./tsconfig.json"],
3+
"compilerOptions": {
4+
"declaration": true,
5+
"declarationMap": true,
6+
"emitDeclarationOnly": true,
7+
"noEmit": false,
8+
"rootDir": "src",
9+
"outDir": "types"
10+
},
11+
"exclude": ["src/**/__tests__/**"]
12+
}

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
{
22
"compilerOptions": {
33
"module": "node16",
4+
"allowJs": true,
45
"noEmit": true,
56
"skipLibCheck": true,
67
"strict": true,
78
"types": ["svelte", "vite/client", "vitest", "vitest/globals"]
89
},
9-
"include": ["src", "types"]
10+
"include": ["src"]
1011
}

types/index.d.ts

Lines changed: 0 additions & 82 deletions
This file was deleted.

0 commit comments

Comments
 (0)