@friggframework/devtools 2.0.0-next.4 → 2.0.0-next.40
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/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/build-command/index.js +54 -0
- package/frigg-cli/deploy-command/index.js +175 -0
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/generate-iam-command.js +115 -0
- package/frigg-cli/index.js +47 -1
- package/frigg-cli/index.test.js +1 -4
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/install-command/index.js +1 -4
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/start-command/index.js +24 -4
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +16 -17
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
- package/infrastructure/GENERATE-IAM-DOCS.md +278 -0
- package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
- package/infrastructure/README.md +443 -0
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/aws-discovery.js +1176 -0
- package/infrastructure/aws-discovery.test.js +1220 -0
- package/infrastructure/build-time-discovery.js +206 -0
- package/infrastructure/build-time-discovery.test.js +378 -0
- package/infrastructure/create-frigg-infrastructure.js +3 -5
- package/infrastructure/env-validator.js +77 -0
- package/infrastructure/frigg-deployment-iam-stack.yaml +401 -0
- package/infrastructure/iam-generator.js +836 -0
- package/infrastructure/iam-generator.test.js +172 -0
- package/infrastructure/iam-policy-basic.json +218 -0
- package/infrastructure/iam-policy-full.json +288 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/run-discovery.js +110 -0
- package/infrastructure/serverless-template.js +1472 -138
- package/infrastructure/serverless-template.test.js +1759 -0
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/docs/phase2-integration-guide.md +320 -0
- package/management-ui/index.html +13 -0
- package/management-ui/package-lock.json +16517 -0
- package/management-ui/package.json +76 -0
- package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +876 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +1029 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +873 -0
- package/management-ui/server/middleware/errorHandler.js +93 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +346 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +109 -0
- package/management-ui/src/assets/FriggLogo.svg +1 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +70 -0
- package/management-ui/src/components/Card.jsx +97 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +481 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +336 -0
- package/management-ui/src/components/Layout.jsx +716 -0
- package/management-ui/src/components/LoadingSpinner.jsx +113 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +350 -0
- package/management-ui/src/components/StatusBadge.jsx +208 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
- package/management-ui/src/components/UserSimulation.jsx +327 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +601 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +193 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
- package/management-ui/src/pages/IntegrationTest.jsx +742 -0
- package/management-ui/src/pages/Integrations.jsx +253 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +20 -9
- package/infrastructure/app-handler-helpers.js +0 -57
- package/infrastructure/backend-utils.js +0 -90
- package/infrastructure/routers/auth.js +0 -26
- package/infrastructure/routers/integration-defined-routers.js +0 -37
- package/infrastructure/routers/middleware/loadUser.js +0 -15
- package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
- package/infrastructure/routers/user.js +0 -41
- package/infrastructure/routers/websocket.js +0 -55
- package/infrastructure/workers/integration-defined-workers.js +0 -24
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { render, screen, waitFor, fireEvent } from '@testing-library/react'
|
|
3
|
+
import { BrowserRouter } from 'react-router-dom'
|
|
4
|
+
import '@testing-library/jest-dom'
|
|
5
|
+
import Welcome from '../../components/Welcome'
|
|
6
|
+
import { FriggProvider } from '../../hooks/useFrigg'
|
|
7
|
+
|
|
8
|
+
// Mock the navigation
|
|
9
|
+
const mockNavigate = vi.fn()
|
|
10
|
+
vi.mock('react-router-dom', async () => {
|
|
11
|
+
const actual = await vi.importActual('react-router-dom')
|
|
12
|
+
return {
|
|
13
|
+
...actual,
|
|
14
|
+
useNavigate: () => mockNavigate
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
// Mock the socket hook
|
|
19
|
+
vi.mock('../../hooks/useSocket', () => ({
|
|
20
|
+
useSocket: () => ({
|
|
21
|
+
on: vi.fn(),
|
|
22
|
+
emit: vi.fn()
|
|
23
|
+
})
|
|
24
|
+
}))
|
|
25
|
+
|
|
26
|
+
// Mock API
|
|
27
|
+
const mockApi = {
|
|
28
|
+
get: vi.fn(),
|
|
29
|
+
post: vi.fn()
|
|
30
|
+
}
|
|
31
|
+
vi.mock('../../services/api', () => ({
|
|
32
|
+
default: mockApi
|
|
33
|
+
}))
|
|
34
|
+
|
|
35
|
+
// Test wrapper component
|
|
36
|
+
const TestWrapper = ({ children, friggContextValue }) => {
|
|
37
|
+
return (
|
|
38
|
+
<BrowserRouter>
|
|
39
|
+
<FriggProvider>
|
|
40
|
+
{children}
|
|
41
|
+
</FriggProvider>
|
|
42
|
+
</BrowserRouter>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe('Welcome Component - Repository Selection', () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
vi.clearAllMocks()
|
|
49
|
+
mockNavigate.mockClear()
|
|
50
|
+
|
|
51
|
+
// Default API responses
|
|
52
|
+
mockApi.get.mockImplementation((url) => {
|
|
53
|
+
switch (url) {
|
|
54
|
+
case '/api/project/repositories':
|
|
55
|
+
return Promise.resolve({
|
|
56
|
+
data: {
|
|
57
|
+
data: {
|
|
58
|
+
repositories: [],
|
|
59
|
+
currentRepository: null,
|
|
60
|
+
isMultiRepo: false
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
case '/api/repository/current':
|
|
65
|
+
return Promise.resolve({
|
|
66
|
+
data: { data: { repository: null } }
|
|
67
|
+
})
|
|
68
|
+
default:
|
|
69
|
+
return Promise.resolve({ data: { data: {} } })
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
vi.restoreAllMocks()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should show loading screen initially', async () => {
|
|
79
|
+
render(
|
|
80
|
+
<TestWrapper>
|
|
81
|
+
<Welcome />
|
|
82
|
+
</TestWrapper>
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
// Should show loading animation and messages
|
|
86
|
+
expect(screen.getByText(/Scanning for local Frigg repositories/)).toBeInTheDocument()
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should show repository selection even for single repository', async () => {
|
|
90
|
+
// Mock single repository response
|
|
91
|
+
mockApi.get.mockImplementation((url) => {
|
|
92
|
+
switch (url) {
|
|
93
|
+
case '/api/project/repositories':
|
|
94
|
+
return Promise.resolve({
|
|
95
|
+
data: {
|
|
96
|
+
data: {
|
|
97
|
+
repositories: [{
|
|
98
|
+
name: 'test-app',
|
|
99
|
+
path: '/path/to/test-app',
|
|
100
|
+
framework: 'React'
|
|
101
|
+
}],
|
|
102
|
+
currentRepository: null,
|
|
103
|
+
isMultiRepo: false
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
case '/api/repository/current':
|
|
108
|
+
return Promise.resolve({
|
|
109
|
+
data: { data: { repository: null } }
|
|
110
|
+
})
|
|
111
|
+
default:
|
|
112
|
+
return Promise.resolve({ data: { data: {} } })
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
render(
|
|
117
|
+
<TestWrapper>
|
|
118
|
+
<Welcome />
|
|
119
|
+
</TestWrapper>
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
// Wait for loading to complete
|
|
123
|
+
await waitFor(() => {
|
|
124
|
+
expect(screen.getByText('Welcome to Frigg')).toBeInTheDocument()
|
|
125
|
+
}, { timeout: 5000 })
|
|
126
|
+
|
|
127
|
+
// Should show repository selection interface, not auto-navigate
|
|
128
|
+
expect(screen.getByText('Choose Your Project')).toBeInTheDocument()
|
|
129
|
+
expect(screen.getByText('Select a Frigg Project')).toBeInTheDocument()
|
|
130
|
+
|
|
131
|
+
// Should NOT navigate to dashboard automatically
|
|
132
|
+
expect(mockNavigate).not.toHaveBeenCalledWith('/dashboard')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('should show repository selection when multiple repositories are found', async () => {
|
|
136
|
+
const mockRepositories = [
|
|
137
|
+
{
|
|
138
|
+
name: 'frigg-app-1',
|
|
139
|
+
path: '/path/to/app1',
|
|
140
|
+
framework: 'React',
|
|
141
|
+
version: '1.0.0'
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'frigg-app-2',
|
|
145
|
+
path: '/path/to/app2',
|
|
146
|
+
framework: 'Vue',
|
|
147
|
+
version: '2.0.0'
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'frigg-app-3',
|
|
151
|
+
path: '/path/to/app3',
|
|
152
|
+
framework: 'Angular',
|
|
153
|
+
version: '1.5.0'
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
// Mock multi-repository response
|
|
158
|
+
mockApi.get.mockImplementation((url) => {
|
|
159
|
+
switch (url) {
|
|
160
|
+
case '/api/project/repositories':
|
|
161
|
+
return Promise.resolve({
|
|
162
|
+
data: {
|
|
163
|
+
data: {
|
|
164
|
+
repositories: mockRepositories,
|
|
165
|
+
currentRepository: {
|
|
166
|
+
name: 'Multiple Repositories Available',
|
|
167
|
+
isMultiRepo: true,
|
|
168
|
+
availableRepos: mockRepositories
|
|
169
|
+
},
|
|
170
|
+
isMultiRepo: true
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
case '/api/repository/current':
|
|
175
|
+
return Promise.resolve({
|
|
176
|
+
data: {
|
|
177
|
+
data: {
|
|
178
|
+
repository: {
|
|
179
|
+
name: 'Multiple Repositories Available',
|
|
180
|
+
isMultiRepo: true,
|
|
181
|
+
availableRepos: mockRepositories
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
default:
|
|
187
|
+
return Promise.resolve({ data: { data: {} } })
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
render(
|
|
192
|
+
<TestWrapper>
|
|
193
|
+
<Welcome />
|
|
194
|
+
</TestWrapper>
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
// Wait for loading to complete
|
|
198
|
+
await waitFor(() => {
|
|
199
|
+
expect(screen.getByText('Welcome to Frigg Management UI')).toBeInTheDocument()
|
|
200
|
+
}, { timeout: 3000 })
|
|
201
|
+
|
|
202
|
+
// Should show repository selection interface
|
|
203
|
+
expect(screen.getByText('Select Your Frigg Application')).toBeInTheDocument()
|
|
204
|
+
|
|
205
|
+
// Should show all repositories
|
|
206
|
+
expect(screen.getByText('frigg-app-1')).toBeInTheDocument()
|
|
207
|
+
expect(screen.getByText('frigg-app-2')).toBeInTheDocument()
|
|
208
|
+
expect(screen.getByText('frigg-app-3')).toBeInTheDocument()
|
|
209
|
+
|
|
210
|
+
// Should show paths
|
|
211
|
+
expect(screen.getByText('/path/to/app1')).toBeInTheDocument()
|
|
212
|
+
expect(screen.getByText('/path/to/app2')).toBeInTheDocument()
|
|
213
|
+
expect(screen.getByText('/path/to/app3')).toBeInTheDocument()
|
|
214
|
+
|
|
215
|
+
// Should NOT navigate to dashboard automatically
|
|
216
|
+
expect(mockNavigate).not.toHaveBeenCalledWith('/dashboard')
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('should handle repository selection via dropdown and launch button', async () => {
|
|
220
|
+
const mockRepositories = [
|
|
221
|
+
{
|
|
222
|
+
name: 'frigg-app-1',
|
|
223
|
+
path: '/path/to/app1',
|
|
224
|
+
framework: 'React'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'frigg-app-2',
|
|
228
|
+
path: '/path/to/app2',
|
|
229
|
+
framework: 'Vue'
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
// Mock repository response
|
|
234
|
+
mockApi.get.mockImplementation((url) => {
|
|
235
|
+
switch (url) {
|
|
236
|
+
case '/api/project/repositories':
|
|
237
|
+
return Promise.resolve({
|
|
238
|
+
data: {
|
|
239
|
+
data: {
|
|
240
|
+
repositories: mockRepositories,
|
|
241
|
+
currentRepository: null,
|
|
242
|
+
isMultiRepo: false
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
case '/api/repository/current':
|
|
247
|
+
return Promise.resolve({
|
|
248
|
+
data: { data: { repository: null } }
|
|
249
|
+
})
|
|
250
|
+
default:
|
|
251
|
+
return Promise.resolve({ data: { data: {} } })
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
// Mock successful repository switch
|
|
256
|
+
mockApi.post.mockImplementation((url) => {
|
|
257
|
+
if (url === '/api/project/switch-repository') {
|
|
258
|
+
return Promise.resolve({
|
|
259
|
+
data: {
|
|
260
|
+
data: {
|
|
261
|
+
repository: {
|
|
262
|
+
name: 'frigg-app-1',
|
|
263
|
+
path: '/path/to/app1'
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
return Promise.resolve({ data: { data: {} } })
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
render(
|
|
273
|
+
<TestWrapper>
|
|
274
|
+
<Welcome />
|
|
275
|
+
</TestWrapper>
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
// Wait for loading to complete
|
|
279
|
+
await waitFor(() => {
|
|
280
|
+
expect(screen.getByText('Choose Your Project')).toBeInTheDocument()
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
// Click dropdown to open
|
|
284
|
+
const dropdown = screen.getByText('Select a Frigg Project')
|
|
285
|
+
fireEvent.click(dropdown)
|
|
286
|
+
|
|
287
|
+
// Wait for dropdown options to appear
|
|
288
|
+
await waitFor(() => {
|
|
289
|
+
expect(screen.getByText('frigg-app-1')).toBeInTheDocument()
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
// Click on first repository in dropdown
|
|
293
|
+
const repoOption = screen.getByText('frigg-app-1')
|
|
294
|
+
fireEvent.click(repoOption)
|
|
295
|
+
|
|
296
|
+
// Wait for selection to be made
|
|
297
|
+
await waitFor(() => {
|
|
298
|
+
expect(screen.getByText('Launch Project')).toBeInTheDocument()
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
// Click launch button
|
|
302
|
+
const launchButton = screen.getByText('Launch Project')
|
|
303
|
+
fireEvent.click(launchButton)
|
|
304
|
+
|
|
305
|
+
// Should call switch repository API
|
|
306
|
+
await waitFor(() => {
|
|
307
|
+
expect(mockApi.post).toHaveBeenCalledWith('/api/project/switch-repository', {
|
|
308
|
+
repositoryPath: '/path/to/app1'
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
// Should navigate to dashboard after selection
|
|
313
|
+
await waitFor(() => {
|
|
314
|
+
expect(mockNavigate).toHaveBeenCalledWith('/dashboard')
|
|
315
|
+
}, { timeout: 2000 })
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
it('should show create new app option when no repositories found', async () => {
|
|
319
|
+
// Mock empty repository response
|
|
320
|
+
mockApi.get.mockImplementation((url) => {
|
|
321
|
+
switch (url) {
|
|
322
|
+
case '/api/project/repositories':
|
|
323
|
+
return Promise.resolve({
|
|
324
|
+
data: {
|
|
325
|
+
data: {
|
|
326
|
+
repositories: [],
|
|
327
|
+
currentRepository: null,
|
|
328
|
+
isMultiRepo: false
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
})
|
|
332
|
+
case '/api/repository/current':
|
|
333
|
+
return Promise.resolve({
|
|
334
|
+
data: { data: { repository: null } }
|
|
335
|
+
})
|
|
336
|
+
default:
|
|
337
|
+
return Promise.resolve({ data: { data: {} } })
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
render(
|
|
342
|
+
<TestWrapper>
|
|
343
|
+
<Welcome />
|
|
344
|
+
</TestWrapper>
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
// Wait for loading to complete
|
|
348
|
+
await waitFor(() => {
|
|
349
|
+
expect(screen.getByText('Welcome to Frigg')).toBeInTheDocument()
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
// Should show no repositories message
|
|
353
|
+
expect(screen.getByText('No Frigg Projects Found')).toBeInTheDocument()
|
|
354
|
+
|
|
355
|
+
// Should show create new button
|
|
356
|
+
expect(screen.getByText('Create Your First Frigg Application')).toBeInTheDocument()
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
it('should show loading steps with proper timing', async () => {
|
|
360
|
+
render(
|
|
361
|
+
<TestWrapper>
|
|
362
|
+
<Welcome />
|
|
363
|
+
</TestWrapper>
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
// Should start with first loading message
|
|
367
|
+
expect(screen.getByText('Scanning for local Frigg repositories...')).toBeInTheDocument()
|
|
368
|
+
|
|
369
|
+
// Wait for additional messages to appear
|
|
370
|
+
await waitFor(() => {
|
|
371
|
+
expect(screen.getByText('Checking installed integrations...')).toBeInTheDocument()
|
|
372
|
+
}, { timeout: 1000 })
|
|
373
|
+
|
|
374
|
+
await waitFor(() => {
|
|
375
|
+
expect(screen.getByText('Pinging npm for up-to-date API modules...')).toBeInTheDocument()
|
|
376
|
+
}, { timeout: 2000 })
|
|
377
|
+
})
|
|
378
|
+
})
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { setupServer } from 'msw/node'
|
|
2
|
+
import { http, HttpResponse } from 'msw'
|
|
3
|
+
|
|
4
|
+
// Mock API responses
|
|
5
|
+
export const handlers = [
|
|
6
|
+
// Health check
|
|
7
|
+
http.get('/health', () => {
|
|
8
|
+
return HttpResponse.json({
|
|
9
|
+
status: 'healthy',
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
uptime: 123.45,
|
|
12
|
+
version: '1.0.0'
|
|
13
|
+
})
|
|
14
|
+
}),
|
|
15
|
+
|
|
16
|
+
// Repository endpoints
|
|
17
|
+
http.get('/api/repository/current', () => {
|
|
18
|
+
return HttpResponse.json({
|
|
19
|
+
data: {
|
|
20
|
+
repository: {
|
|
21
|
+
name: 'test-repo',
|
|
22
|
+
path: '/test/path',
|
|
23
|
+
framework: 'React',
|
|
24
|
+
hasBackend: true,
|
|
25
|
+
version: '1.0.0'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
http.get('/api/project/repositories', () => {
|
|
32
|
+
return HttpResponse.json({
|
|
33
|
+
data: {
|
|
34
|
+
repositories: [
|
|
35
|
+
{
|
|
36
|
+
name: 'test-repo-1',
|
|
37
|
+
path: '/test/path/1',
|
|
38
|
+
framework: 'React',
|
|
39
|
+
hasBackend: true,
|
|
40
|
+
detectionReasons: ['frigg dependencies']
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'test-repo-2',
|
|
44
|
+
path: '/test/path/2',
|
|
45
|
+
framework: 'Vue',
|
|
46
|
+
hasBackend: false,
|
|
47
|
+
detectionReasons: ['frigg config file']
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
}),
|
|
53
|
+
|
|
54
|
+
http.post('/api/project/switch-repository', () => {
|
|
55
|
+
return HttpResponse.json({
|
|
56
|
+
data: {
|
|
57
|
+
repository: {
|
|
58
|
+
name: 'switched-repo',
|
|
59
|
+
path: '/switched/path'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
// Project status
|
|
66
|
+
http.get('/api/project/status', () => {
|
|
67
|
+
return HttpResponse.json({
|
|
68
|
+
data: {
|
|
69
|
+
status: 'running'
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
}),
|
|
73
|
+
|
|
74
|
+
// Integrations
|
|
75
|
+
http.get('/api/integrations', () => {
|
|
76
|
+
return HttpResponse.json({
|
|
77
|
+
data: {
|
|
78
|
+
integrations: [
|
|
79
|
+
{
|
|
80
|
+
name: 'slack',
|
|
81
|
+
version: '1.0.0',
|
|
82
|
+
installed: true,
|
|
83
|
+
configured: true
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'github',
|
|
87
|
+
version: '2.0.0',
|
|
88
|
+
installed: false,
|
|
89
|
+
configured: false
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
}),
|
|
95
|
+
|
|
96
|
+
// Environment
|
|
97
|
+
http.get('/api/environment', () => {
|
|
98
|
+
return HttpResponse.json({
|
|
99
|
+
data: {
|
|
100
|
+
variables: {
|
|
101
|
+
NODE_ENV: 'test',
|
|
102
|
+
DATABASE_URL: 'test://localhost:27017/test'
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
}),
|
|
107
|
+
|
|
108
|
+
// Users
|
|
109
|
+
http.get('/api/users', () => {
|
|
110
|
+
return HttpResponse.json({
|
|
111
|
+
data: {
|
|
112
|
+
users: [
|
|
113
|
+
{
|
|
114
|
+
id: '1',
|
|
115
|
+
email: 'test@example.com',
|
|
116
|
+
name: 'Test User',
|
|
117
|
+
createdAt: '2023-01-01T00:00:00Z'
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
}),
|
|
123
|
+
|
|
124
|
+
// Connections
|
|
125
|
+
http.get('/api/connections', () => {
|
|
126
|
+
return HttpResponse.json({
|
|
127
|
+
data: {
|
|
128
|
+
connections: [
|
|
129
|
+
{
|
|
130
|
+
id: '1',
|
|
131
|
+
type: 'slack',
|
|
132
|
+
name: 'Test Slack',
|
|
133
|
+
status: 'active',
|
|
134
|
+
lastUsed: '2023-01-01T00:00:00Z'
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
}),
|
|
140
|
+
|
|
141
|
+
// Logs
|
|
142
|
+
http.get('/api/project/logs', () => {
|
|
143
|
+
return HttpResponse.json({
|
|
144
|
+
data: {
|
|
145
|
+
logs: [
|
|
146
|
+
{
|
|
147
|
+
timestamp: '2023-01-01T00:00:00Z',
|
|
148
|
+
level: 'info',
|
|
149
|
+
message: 'Test log message',
|
|
150
|
+
source: 'test'
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
}),
|
|
156
|
+
|
|
157
|
+
// Metrics
|
|
158
|
+
http.get('/api/project/metrics', () => {
|
|
159
|
+
return HttpResponse.json({
|
|
160
|
+
data: {
|
|
161
|
+
cpu: 45.2,
|
|
162
|
+
memory: 67.8,
|
|
163
|
+
requests: 1234,
|
|
164
|
+
errors: 5
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
}),
|
|
168
|
+
|
|
169
|
+
// IDE integration
|
|
170
|
+
http.post('/api/open-in-ide', () => {
|
|
171
|
+
return HttpResponse.json({
|
|
172
|
+
success: true,
|
|
173
|
+
method: 'vscode'
|
|
174
|
+
})
|
|
175
|
+
}),
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
export const server = setupServer(...handlers)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { beforeAll, afterEach, afterAll, vi } from 'vitest'
|
|
3
|
+
import { cleanup } from '@testing-library/react'
|
|
4
|
+
import { server } from './mocks/server'
|
|
5
|
+
|
|
6
|
+
// Mock matchMedia
|
|
7
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
8
|
+
writable: true,
|
|
9
|
+
value: vi.fn().mockImplementation(query => ({
|
|
10
|
+
matches: false,
|
|
11
|
+
media: query,
|
|
12
|
+
onchange: null,
|
|
13
|
+
addListener: vi.fn(), // deprecated
|
|
14
|
+
removeListener: vi.fn(), // deprecated
|
|
15
|
+
addEventListener: vi.fn(),
|
|
16
|
+
removeEventListener: vi.fn(),
|
|
17
|
+
dispatchEvent: vi.fn(),
|
|
18
|
+
})),
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
// Mock ResizeObserver
|
|
22
|
+
global.ResizeObserver = vi.fn().mockImplementation(() => ({
|
|
23
|
+
observe: vi.fn(),
|
|
24
|
+
unobserve: vi.fn(),
|
|
25
|
+
disconnect: vi.fn(),
|
|
26
|
+
}))
|
|
27
|
+
|
|
28
|
+
// Mock IntersectionObserver
|
|
29
|
+
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
|
|
30
|
+
observe: vi.fn(),
|
|
31
|
+
unobserve: vi.fn(),
|
|
32
|
+
disconnect: vi.fn(),
|
|
33
|
+
}))
|
|
34
|
+
|
|
35
|
+
// Mock localStorage
|
|
36
|
+
const localStorageMock = {
|
|
37
|
+
getItem: vi.fn(),
|
|
38
|
+
setItem: vi.fn(),
|
|
39
|
+
removeItem: vi.fn(),
|
|
40
|
+
clear: vi.fn(),
|
|
41
|
+
}
|
|
42
|
+
global.localStorage = localStorageMock
|
|
43
|
+
|
|
44
|
+
// Mock socket.io-client
|
|
45
|
+
vi.mock('socket.io-client', () => ({
|
|
46
|
+
io: vi.fn(() => ({
|
|
47
|
+
on: vi.fn(),
|
|
48
|
+
off: vi.fn(),
|
|
49
|
+
emit: vi.fn(),
|
|
50
|
+
connect: vi.fn(),
|
|
51
|
+
disconnect: vi.fn(),
|
|
52
|
+
})),
|
|
53
|
+
}))
|
|
54
|
+
|
|
55
|
+
// Setup MSW
|
|
56
|
+
beforeAll(() => server.listen())
|
|
57
|
+
afterEach(() => {
|
|
58
|
+
server.resetHandlers()
|
|
59
|
+
cleanup()
|
|
60
|
+
})
|
|
61
|
+
afterAll(() => server.close())
|