@tanstack/cli 0.60.1 → 0.62.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/dist/cli.js +266 -11
- package/dist/command-line.js +103 -8
- package/dist/discovery.js +144 -0
- package/dist/options.js +35 -2
- package/dist/types/command-line.d.ts +7 -0
- package/dist/types/{mcp/types.d.ts → discovery.d.ts} +23 -75
- package/dist/types/types.d.ts +1 -2
- package/dist/types/ui-prompts.d.ts +5 -0
- package/dist/ui-prompts.js +26 -0
- package/package.json +6 -5
- package/skills/CHANGELOG.md +18 -0
- package/skills/add-addons-existing-app/SKILL.md +113 -0
- package/skills/choose-ecosystem-integrations/SKILL.md +140 -0
- package/skills/choose-ecosystem-integrations/references/authentication-providers.md +19 -0
- package/skills/choose-ecosystem-integrations/references/data-layer-providers.md +20 -0
- package/skills/choose-ecosystem-integrations/references/deployment-targets.md +19 -0
- package/skills/create-app-scaffold/SKILL.md +132 -0
- package/skills/create-app-scaffold/references/create-flag-compatibility-matrix.md +34 -0
- package/skills/create-app-scaffold/references/deployment-providers.md +19 -0
- package/skills/create-app-scaffold/references/framework-adapters.md +17 -0
- package/skills/create-app-scaffold/references/toolchains.md +17 -0
- package/skills/maintain-custom-addons-dev-watch/SKILL.md +118 -0
- package/skills/query-docs-library-metadata/SKILL.md +85 -0
- package/skills/query-docs-library-metadata/references/discovery-command-output-schemas.md +70 -0
- package/CHANGELOG.md +0 -787
- package/dist/mcp/api.js +0 -31
- package/dist/mcp/tools.js +0 -250
- package/dist/mcp/types.js +0 -37
- package/dist/mcp.js +0 -181
- package/dist/types/mcp/api.d.ts +0 -4
- package/dist/types/mcp/tools.d.ts +0 -2
- package/dist/types/mcp.d.ts +0 -5
- package/playwright-report/index.html +0 -85
- package/playwright.config.ts +0 -21
- package/src/bin.ts +0 -15
- package/src/cli.ts +0 -767
- package/src/command-line.ts +0 -473
- package/src/dev-watch.ts +0 -564
- package/src/file-syncer.ts +0 -263
- package/src/index.ts +0 -21
- package/src/mcp/api.ts +0 -42
- package/src/mcp/tools.ts +0 -323
- package/src/mcp/types.ts +0 -46
- package/src/mcp.ts +0 -263
- package/src/options.ts +0 -234
- package/src/types.ts +0 -28
- package/src/ui-environment.ts +0 -74
- package/src/ui-prompts.ts +0 -355
- package/src/utils.ts +0 -30
- package/test-results/.last-run.json +0 -4
- package/tests/command-line.test.ts +0 -622
- package/tests/index.test.ts +0 -9
- package/tests/mcp.test.ts +0 -225
- package/tests/options.test.ts +0 -216
- package/tests/setupVitest.ts +0 -6
- package/tests/ui-environment.test.ts +0 -97
- package/tests/ui-prompts.test.ts +0 -205
- package/tests-e2e/addons-smoke.spec.ts +0 -31
- package/tests-e2e/create-smoke.spec.ts +0 -39
- package/tests-e2e/helpers.ts +0 -526
- package/tests-e2e/matrix-opportunistic.spec.ts +0 -142
- package/tests-e2e/router-only-smoke.spec.ts +0 -68
- package/tests-e2e/solid-smoke.spec.ts +0 -25
- package/tests-e2e/templates-smoke.spec.ts +0 -52
- package/tsconfig.json +0 -17
- package/vitest.config.js +0 -8
package/tests/mcp.test.ts
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
3
|
-
import { registerDocTools } from '../src/mcp/tools.js'
|
|
4
|
-
import * as api from '../src/mcp/api.js'
|
|
5
|
-
|
|
6
|
-
vi.mock('../src/mcp/api.js')
|
|
7
|
-
|
|
8
|
-
const mockLibrariesResponse = {
|
|
9
|
-
libraries: [
|
|
10
|
-
{
|
|
11
|
-
id: 'query',
|
|
12
|
-
name: 'TanStack Query',
|
|
13
|
-
tagline: 'Powerful asynchronous state management',
|
|
14
|
-
description: 'Data fetching library',
|
|
15
|
-
frameworks: ['react', 'vue', 'solid'],
|
|
16
|
-
latestVersion: 'v5',
|
|
17
|
-
latestBranch: 'main',
|
|
18
|
-
availableVersions: ['v5', 'v4'],
|
|
19
|
-
docsUrl: 'https://tanstack.com/query',
|
|
20
|
-
githubUrl: 'https://github.com/TanStack/query',
|
|
21
|
-
repo: 'TanStack/query',
|
|
22
|
-
docsRoot: 'docs',
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: 'router',
|
|
26
|
-
name: 'TanStack Router',
|
|
27
|
-
tagline: 'Type-safe routing',
|
|
28
|
-
description: 'Router library',
|
|
29
|
-
frameworks: ['react'],
|
|
30
|
-
latestVersion: 'v1',
|
|
31
|
-
latestBranch: 'main',
|
|
32
|
-
availableVersions: ['v1'],
|
|
33
|
-
docsUrl: 'https://tanstack.com/router',
|
|
34
|
-
githubUrl: 'https://github.com/TanStack/router',
|
|
35
|
-
repo: 'TanStack/router',
|
|
36
|
-
docsRoot: 'docs',
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
groups: {
|
|
40
|
-
state: ['query'],
|
|
41
|
-
headlessUI: [],
|
|
42
|
-
performance: [],
|
|
43
|
-
tooling: ['router'],
|
|
44
|
-
},
|
|
45
|
-
groupNames: {
|
|
46
|
-
state: 'State Management',
|
|
47
|
-
headlessUI: 'Headless UI',
|
|
48
|
-
performance: 'Performance',
|
|
49
|
-
tooling: 'Tooling',
|
|
50
|
-
},
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const mockPartnersResponse = {
|
|
54
|
-
partners: [
|
|
55
|
-
{
|
|
56
|
-
id: 'neon',
|
|
57
|
-
name: 'Neon',
|
|
58
|
-
description: 'Serverless Postgres',
|
|
59
|
-
category: 'database',
|
|
60
|
-
categoryLabel: 'Database',
|
|
61
|
-
libraries: ['start', 'router'],
|
|
62
|
-
url: 'https://neon.tech',
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
categories: ['database', 'auth'],
|
|
66
|
-
categoryLabels: {
|
|
67
|
-
database: 'Database',
|
|
68
|
-
auth: 'Authentication',
|
|
69
|
-
},
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
describe('MCP Tools', () => {
|
|
73
|
-
let server: McpServer
|
|
74
|
-
let registeredTools: Map<string, { handler: Function; schema: unknown }>
|
|
75
|
-
|
|
76
|
-
beforeEach(() => {
|
|
77
|
-
vi.resetAllMocks()
|
|
78
|
-
|
|
79
|
-
// Create a mock server that captures tool registrations
|
|
80
|
-
registeredTools = new Map()
|
|
81
|
-
server = {
|
|
82
|
-
tool: vi.fn((name, description, schema, handler) => {
|
|
83
|
-
registeredTools.set(name, { handler, schema })
|
|
84
|
-
}),
|
|
85
|
-
} as unknown as McpServer
|
|
86
|
-
|
|
87
|
-
vi.mocked(api.fetchLibraries).mockResolvedValue(mockLibrariesResponse)
|
|
88
|
-
vi.mocked(api.fetchPartners).mockResolvedValue(mockPartnersResponse)
|
|
89
|
-
vi.mocked(api.fetchDocContent).mockResolvedValue('# Test Doc\n\nContent here')
|
|
90
|
-
|
|
91
|
-
registerDocTools(server)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
describe('tanstack_list_libraries', () => {
|
|
95
|
-
it('should register the tool', () => {
|
|
96
|
-
expect(registeredTools.has('tanstack_list_libraries')).toBe(true)
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('should list all libraries when no group specified', async () => {
|
|
100
|
-
const tool = registeredTools.get('tanstack_list_libraries')!
|
|
101
|
-
const result = await tool.handler({})
|
|
102
|
-
|
|
103
|
-
expect(result.content[0].type).toBe('text')
|
|
104
|
-
const data = JSON.parse(result.content[0].text)
|
|
105
|
-
expect(data.count).toBe(2)
|
|
106
|
-
expect(data.libraries).toHaveLength(2)
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('should filter libraries by group', async () => {
|
|
110
|
-
const tool = registeredTools.get('tanstack_list_libraries')!
|
|
111
|
-
const result = await tool.handler({ group: 'state' })
|
|
112
|
-
|
|
113
|
-
const data = JSON.parse(result.content[0].text)
|
|
114
|
-
expect(data.count).toBe(1)
|
|
115
|
-
expect(data.libraries[0].id).toBe('query')
|
|
116
|
-
expect(data.group).toBe('State Management')
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('should handle API errors', async () => {
|
|
120
|
-
vi.mocked(api.fetchLibraries).mockRejectedValue(new Error('Network error'))
|
|
121
|
-
|
|
122
|
-
const tool = registeredTools.get('tanstack_list_libraries')!
|
|
123
|
-
const result = await tool.handler({})
|
|
124
|
-
|
|
125
|
-
expect(result.isError).toBe(true)
|
|
126
|
-
expect(result.content[0].text).toContain('Error')
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
describe('tanstack_doc', () => {
|
|
131
|
-
it('should register the tool', () => {
|
|
132
|
-
expect(registeredTools.has('tanstack_doc')).toBe(true)
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
it('should fetch doc content', async () => {
|
|
136
|
-
const tool = registeredTools.get('tanstack_doc')!
|
|
137
|
-
const result = await tool.handler({
|
|
138
|
-
library: 'query',
|
|
139
|
-
path: 'framework/react/overview',
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
expect(api.fetchDocContent).toHaveBeenCalledWith(
|
|
143
|
-
'TanStack/query',
|
|
144
|
-
'main',
|
|
145
|
-
'docs/framework/react/overview.md',
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
const data = JSON.parse(result.content[0].text)
|
|
149
|
-
expect(data.content).toContain('# Test Doc')
|
|
150
|
-
})
|
|
151
|
-
|
|
152
|
-
it('should error for unknown library', async () => {
|
|
153
|
-
const tool = registeredTools.get('tanstack_doc')!
|
|
154
|
-
const result = await tool.handler({
|
|
155
|
-
library: 'unknown',
|
|
156
|
-
path: 'overview',
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
expect(result.isError).toBe(true)
|
|
160
|
-
expect(result.content[0].text).toContain('not found')
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('should error for unknown version', async () => {
|
|
164
|
-
const tool = registeredTools.get('tanstack_doc')!
|
|
165
|
-
const result = await tool.handler({
|
|
166
|
-
library: 'query',
|
|
167
|
-
path: 'overview',
|
|
168
|
-
version: 'v999',
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
expect(result.isError).toBe(true)
|
|
172
|
-
expect(result.content[0].text).toContain('Version')
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
it('should handle 404 doc', async () => {
|
|
176
|
-
vi.mocked(api.fetchDocContent).mockResolvedValue(null)
|
|
177
|
-
|
|
178
|
-
const tool = registeredTools.get('tanstack_doc')!
|
|
179
|
-
const result = await tool.handler({
|
|
180
|
-
library: 'query',
|
|
181
|
-
path: 'nonexistent',
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
expect(result.isError).toBe(true)
|
|
185
|
-
expect(result.content[0].text).toContain('not found')
|
|
186
|
-
})
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
describe('tanstack_ecosystem', () => {
|
|
190
|
-
it('should register the tool', () => {
|
|
191
|
-
expect(registeredTools.has('tanstack_ecosystem')).toBe(true)
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
it('should list ecosystem partners', async () => {
|
|
195
|
-
const tool = registeredTools.get('tanstack_ecosystem')!
|
|
196
|
-
const result = await tool.handler({})
|
|
197
|
-
|
|
198
|
-
const data = JSON.parse(result.content[0].text)
|
|
199
|
-
expect(data.partners).toHaveLength(1)
|
|
200
|
-
expect(data.partners[0].id).toBe('neon')
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
it('should filter by category', async () => {
|
|
204
|
-
const tool = registeredTools.get('tanstack_ecosystem')!
|
|
205
|
-
const result = await tool.handler({ category: 'database' })
|
|
206
|
-
|
|
207
|
-
const data = JSON.parse(result.content[0].text)
|
|
208
|
-
expect(data.partners).toHaveLength(1)
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('should filter by library', async () => {
|
|
212
|
-
const tool = registeredTools.get('tanstack_ecosystem')!
|
|
213
|
-
const result = await tool.handler({ library: 'start' })
|
|
214
|
-
|
|
215
|
-
const data = JSON.parse(result.content[0].text)
|
|
216
|
-
expect(data.partners).toHaveLength(1)
|
|
217
|
-
})
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
describe('tanstack_search_docs', () => {
|
|
221
|
-
it('should register the tool', () => {
|
|
222
|
-
expect(registeredTools.has('tanstack_search_docs')).toBe(true)
|
|
223
|
-
})
|
|
224
|
-
})
|
|
225
|
-
})
|
package/tests/options.test.ts
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, it, expect, vi } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { promptForCreateOptions } from '../src/options'
|
|
4
|
-
import {
|
|
5
|
-
__testClearFrameworks,
|
|
6
|
-
__testRegisterFramework,
|
|
7
|
-
} from '@tanstack/create'
|
|
8
|
-
|
|
9
|
-
import * as prompts from '../src/ui-prompts'
|
|
10
|
-
|
|
11
|
-
import type { Framework } from '@tanstack/create'
|
|
12
|
-
|
|
13
|
-
import type { CliOptions } from '../src/types'
|
|
14
|
-
|
|
15
|
-
vi.mock('../src/ui-prompts')
|
|
16
|
-
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
__testClearFrameworks()
|
|
19
|
-
__testRegisterFramework({
|
|
20
|
-
id: 'react',
|
|
21
|
-
name: 'react',
|
|
22
|
-
getAddOns: () => [
|
|
23
|
-
{
|
|
24
|
-
id: 'react-query',
|
|
25
|
-
type: 'add-on',
|
|
26
|
-
modes: ['file-router'],
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
id: 'tanstack-chat',
|
|
30
|
-
type: 'add-on',
|
|
31
|
-
modes: ['file-router'],
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: 'biome',
|
|
35
|
-
type: 'toolchain',
|
|
36
|
-
modes: ['file-router'],
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
supportedModes: {
|
|
40
|
-
'file-router': {
|
|
41
|
-
displayName: 'File Router',
|
|
42
|
-
description: 'TanStack Start with file-based routing',
|
|
43
|
-
forceTypescript: true,
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
} as unknown as Framework)
|
|
47
|
-
|
|
48
|
-
__testRegisterFramework({
|
|
49
|
-
id: 'solid',
|
|
50
|
-
name: 'solid',
|
|
51
|
-
getAddOns: () => [],
|
|
52
|
-
} as unknown as Framework)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
const baseCliOptions: CliOptions = {
|
|
56
|
-
framework: 'react',
|
|
57
|
-
addOns: [],
|
|
58
|
-
toolchain: undefined,
|
|
59
|
-
projectName: undefined,
|
|
60
|
-
git: undefined,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function setBasicSpies() {
|
|
64
|
-
vi.spyOn(prompts, 'getProjectName').mockImplementation(async () => 'hello')
|
|
65
|
-
vi.spyOn(prompts, 'selectPackageManager').mockImplementation(
|
|
66
|
-
async () => 'npm',
|
|
67
|
-
)
|
|
68
|
-
vi.spyOn(prompts, 'selectToolchain').mockImplementation(async () => undefined)
|
|
69
|
-
vi.spyOn(prompts, 'selectAddOns').mockImplementation(async () => [])
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
describe('promptForCreateOptions', () => {
|
|
73
|
-
//// Project name
|
|
74
|
-
|
|
75
|
-
it('prompt for a project name', async () => {
|
|
76
|
-
setBasicSpies()
|
|
77
|
-
|
|
78
|
-
const options = await promptForCreateOptions(baseCliOptions, {})
|
|
79
|
-
|
|
80
|
-
expect(options?.projectName).toBe('hello')
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('accept incoming project name', async () => {
|
|
84
|
-
setBasicSpies()
|
|
85
|
-
|
|
86
|
-
const options = await promptForCreateOptions(
|
|
87
|
-
{ ...baseCliOptions, projectName: 'override' },
|
|
88
|
-
{},
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
expect(options?.projectName).toBe('override')
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
//// Mode is always file-router (TanStack Start)
|
|
95
|
-
|
|
96
|
-
it('mode should always be file-router', async () => {
|
|
97
|
-
setBasicSpies()
|
|
98
|
-
|
|
99
|
-
const options = await promptForCreateOptions(baseCliOptions, {})
|
|
100
|
-
|
|
101
|
-
expect(options?.mode).toBe('file-router')
|
|
102
|
-
expect(options?.typescript).toBe(true)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
//// Tailwind is always enabled
|
|
106
|
-
|
|
107
|
-
it('tailwind is always enabled', async () => {
|
|
108
|
-
setBasicSpies()
|
|
109
|
-
const options = await promptForCreateOptions(baseCliOptions, {})
|
|
110
|
-
|
|
111
|
-
expect(options?.tailwind).toBe(true)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
//// Package manager
|
|
115
|
-
|
|
116
|
-
it('uses the package manager from the cli options', async () => {
|
|
117
|
-
setBasicSpies()
|
|
118
|
-
|
|
119
|
-
const options = await promptForCreateOptions(
|
|
120
|
-
{ ...baseCliOptions, packageManager: 'bun' },
|
|
121
|
-
{},
|
|
122
|
-
)
|
|
123
|
-
|
|
124
|
-
expect(options?.packageManager).toBe('bun')
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('detects package manager from environment', async () => {
|
|
128
|
-
setBasicSpies()
|
|
129
|
-
|
|
130
|
-
process.env.npm_config_userconfig = 'blarg'
|
|
131
|
-
|
|
132
|
-
const options = await promptForCreateOptions(
|
|
133
|
-
{ ...baseCliOptions, packageManager: undefined },
|
|
134
|
-
{},
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
expect(options?.packageManager).toBe('pnpm')
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
//// Add-ons
|
|
141
|
-
it('should be clean when no add-ons are selected', async () => {
|
|
142
|
-
setBasicSpies()
|
|
143
|
-
|
|
144
|
-
const options = await promptForCreateOptions({ ...baseCliOptions }, {})
|
|
145
|
-
|
|
146
|
-
expect(options?.chosenAddOns).toEqual([])
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('should select biome when toolchain is specified', async () => {
|
|
150
|
-
setBasicSpies()
|
|
151
|
-
|
|
152
|
-
vi.spyOn(prompts, 'selectToolchain').mockImplementation(async () => 'biome')
|
|
153
|
-
|
|
154
|
-
const options = await promptForCreateOptions(
|
|
155
|
-
{ ...baseCliOptions, toolchain: 'biome' },
|
|
156
|
-
{},
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
expect(options?.chosenAddOns.map((a) => a.id).sort()).toEqual(['biome'])
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
it('should handle forced add-ons', async () => {
|
|
163
|
-
setBasicSpies()
|
|
164
|
-
|
|
165
|
-
vi.spyOn(prompts, 'selectToolchain').mockImplementation(
|
|
166
|
-
async () => undefined,
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
const options = await promptForCreateOptions(
|
|
170
|
-
{ ...baseCliOptions },
|
|
171
|
-
{ forcedAddOns: ['react-query'] },
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
expect(options?.chosenAddOns.map((a) => a.id).sort()).toEqual([
|
|
175
|
-
'react-query',
|
|
176
|
-
])
|
|
177
|
-
expect(options?.tailwind).toBe(true)
|
|
178
|
-
expect(options?.typescript).toBe(true)
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
it('should handle add-ons from the CLI', async () => {
|
|
182
|
-
setBasicSpies()
|
|
183
|
-
|
|
184
|
-
const options = await promptForCreateOptions(
|
|
185
|
-
{ ...baseCliOptions, addOns: ['biome', 'react-query'] },
|
|
186
|
-
{},
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
expect(options?.chosenAddOns.map((a) => a.id).sort()).toEqual([
|
|
190
|
-
'biome',
|
|
191
|
-
'react-query',
|
|
192
|
-
])
|
|
193
|
-
expect(options?.tailwind).toBe(true)
|
|
194
|
-
expect(options?.typescript).toBe(true)
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
it('should handle user-selected add-ons', async () => {
|
|
198
|
-
setBasicSpies()
|
|
199
|
-
|
|
200
|
-
vi.spyOn(prompts, 'selectAddOns').mockImplementation(async () =>
|
|
201
|
-
Promise.resolve(['biome', 'react-query']),
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
const options = await promptForCreateOptions(
|
|
205
|
-
{ ...baseCliOptions, addOns: undefined },
|
|
206
|
-
{},
|
|
207
|
-
)
|
|
208
|
-
|
|
209
|
-
expect(options?.chosenAddOns.map((a) => a.id).sort()).toEqual([
|
|
210
|
-
'biome',
|
|
211
|
-
'react-query',
|
|
212
|
-
])
|
|
213
|
-
expect(options?.tailwind).toBe(true)
|
|
214
|
-
expect(options?.typescript).toBe(true)
|
|
215
|
-
})
|
|
216
|
-
})
|
package/tests/setupVitest.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import * as clack from '@clack/prompts'
|
|
4
|
-
|
|
5
|
-
import { createUIEnvironment } from '../src/ui-environment.js'
|
|
6
|
-
|
|
7
|
-
vi.mock('@clack/prompts')
|
|
8
|
-
|
|
9
|
-
// @ts-expect-error
|
|
10
|
-
vi.spyOn(process, 'exit').mockImplementation(() => {})
|
|
11
|
-
|
|
12
|
-
describe('createUIEnvironment', () => {
|
|
13
|
-
it('should create a silent UI environment', () => {
|
|
14
|
-
const environment = createUIEnvironment('test', true)
|
|
15
|
-
expect(environment.appName).toBe('test')
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('should handle intro', () => {
|
|
19
|
-
const environment = createUIEnvironment('test', false)
|
|
20
|
-
const spy = vi
|
|
21
|
-
.spyOn(clack, 'intro')
|
|
22
|
-
.mockImplementation(async () => undefined)
|
|
23
|
-
environment.intro('test')
|
|
24
|
-
expect(spy).toHaveBeenCalledWith('test')
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('should handle outro', () => {
|
|
28
|
-
const environment = createUIEnvironment('test', false)
|
|
29
|
-
const spy = vi
|
|
30
|
-
.spyOn(clack, 'outro')
|
|
31
|
-
.mockImplementation(async () => undefined)
|
|
32
|
-
environment.outro('test')
|
|
33
|
-
expect(spy).toHaveBeenCalledWith('test')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should handle info', () => {
|
|
37
|
-
const environment = createUIEnvironment('test', false)
|
|
38
|
-
const spy = vi
|
|
39
|
-
.spyOn(clack.log, 'info')
|
|
40
|
-
.mockImplementation(async () => undefined)
|
|
41
|
-
environment.info('test')
|
|
42
|
-
expect(spy).toHaveBeenCalled()
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('should handle error', () => {
|
|
46
|
-
const environment = createUIEnvironment('test', false)
|
|
47
|
-
const spy = vi
|
|
48
|
-
.spyOn(clack.log, 'error')
|
|
49
|
-
.mockImplementation(async () => undefined)
|
|
50
|
-
environment.error('test')
|
|
51
|
-
expect(spy).toHaveBeenCalled()
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should handle warn', () => {
|
|
55
|
-
const environment = createUIEnvironment('test', false)
|
|
56
|
-
const spy = vi
|
|
57
|
-
.spyOn(clack.log, 'warn')
|
|
58
|
-
.mockImplementation(async () => undefined)
|
|
59
|
-
environment.warn('test')
|
|
60
|
-
expect(spy).toHaveBeenCalled()
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('should handle confirm', async () => {
|
|
64
|
-
const environment = createUIEnvironment('test', false)
|
|
65
|
-
const spy = vi.spyOn(clack, 'confirm').mockImplementation(async () => true)
|
|
66
|
-
const isCancelSpy = vi
|
|
67
|
-
.spyOn(clack, 'isCancel')
|
|
68
|
-
.mockImplementation(() => false)
|
|
69
|
-
const result = await environment.confirm('test')
|
|
70
|
-
expect(spy).toHaveBeenCalled()
|
|
71
|
-
expect(isCancelSpy).toHaveBeenCalled()
|
|
72
|
-
expect(result).toBe(true)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('should handle confirm', async () => {
|
|
76
|
-
const environment = createUIEnvironment('test', false)
|
|
77
|
-
const spy = vi.spyOn(clack, 'confirm').mockImplementation(async () => true)
|
|
78
|
-
const isCancelSpy = vi
|
|
79
|
-
.spyOn(clack, 'isCancel')
|
|
80
|
-
.mockImplementation(() => true)
|
|
81
|
-
await environment.confirm('test')
|
|
82
|
-
expect(spy).toHaveBeenCalled()
|
|
83
|
-
expect(isCancelSpy).toHaveBeenCalled()
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('should handle spinner', async () => {
|
|
87
|
-
const environment = createUIEnvironment('test', false)
|
|
88
|
-
// @ts-expect-error
|
|
89
|
-
const spy = vi.spyOn(clack, 'spinner').mockImplementation(async () => ({
|
|
90
|
-
start: (_msg?: string) => {},
|
|
91
|
-
stop: (_msg?: string) => {},
|
|
92
|
-
message: (_msg?: string) => {},
|
|
93
|
-
}))
|
|
94
|
-
const result = await environment.spinner()
|
|
95
|
-
expect(spy).toHaveBeenCalled()
|
|
96
|
-
})
|
|
97
|
-
})
|