create-fullstack-scaffold 0.1.1 → 0.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/dist/cli/index.js +1673 -696
- package/dist/cli/index.js.map +1 -1
- package/package.json +16 -10
- package/template/.husky/pre-commit +1 -1
- package/template/modules.config.ts +29 -2
- package/template/package.json +12 -12
- package/template/patches/{typescript+5.8.3.patch → typescript+5.9.3.patch} +2 -4
- package/template/playwright.config.ts +7 -1
- package/template/src/admin/App.tsx +2 -2
- package/template/src/admin/components/CaptchaModal.tsx +7 -9
- package/template/src/admin/layouts/Header.tsx +56 -22
- package/template/src/admin/layouts/Layout.tsx +14 -9
- package/template/src/admin/layouts/Sidebar.tsx +122 -105
- package/template/src/admin/pages/CategoryManagementPage.tsx +241 -0
- package/template/src/admin/pages/ContentPage.tsx +2 -0
- package/template/src/admin/pages/DashboardPage.tsx +2 -0
- package/template/src/admin/pages/DisputesPage.tsx +2 -0
- package/template/src/admin/pages/MediaTestPage.tsx +1 -1
- package/template/src/admin/pages/OrdersPage.tsx +2 -0
- package/template/src/admin/pages/PluginDashboardPage.tsx +297 -0
- package/template/src/admin/pages/PluginManagementPage.tsx +340 -0
- package/template/src/admin/pages/PluginReviewPage.tsx +255 -0
- package/template/src/admin/pages/SystemLogsPage.tsx +11 -2
- package/template/src/admin/pages/TicketsPage.tsx +2 -0
- package/template/src/admin/pages/UsersPage.tsx +3 -2
- package/template/src/admin/stores/adminStore.ts +5 -0
- package/template/src/cli/index.ts +17 -19
- package/template/src/cli/modules/auth/index.ts +65 -0
- package/template/src/cli/modules/config/index.ts +74 -77
- package/template/src/cli/modules/index.ts +28 -6
- package/template/src/cli/modules/notification/index.ts +95 -79
- package/template/src/cli/modules/plugin/index.ts +111 -0
- package/template/src/cli/modules/todo/index.ts +99 -51
- package/template/src/cli/utils/auto-command.ts +7 -25
- package/template/src/cli/utils/index.ts +3 -1
- package/template/src/client/App.tsx +36 -16
- package/template/src/client/Layout.tsx +67 -10
- package/template/src/client/components/AuthButton.tsx +25 -18
- package/template/src/client/components/BottomTabBar.tsx +107 -0
- package/template/src/client/components/Navigation.tsx +162 -52
- package/template/src/client/components/__tests__/App.test.tsx +48 -32
- package/template/src/client/components/__tests__/AuthButton.test.tsx +78 -77
- package/template/src/client/components/__tests__/Navigation.test.tsx +31 -20
- package/template/src/client/components/index.ts +1 -0
- package/template/src/client/contexts/PresetContext.tsx +10 -0
- package/template/src/client/main.tsx +63 -8
- package/template/src/client/pages/CartPage.tsx +244 -0
- package/template/src/client/pages/CategoriesPage.tsx +100 -0
- package/template/src/client/pages/ContentDetailPage.tsx +9 -14
- package/template/src/client/pages/ContentListPage.tsx +4 -11
- package/template/src/client/pages/DashboardPage.tsx +261 -0
- package/template/src/client/pages/DeveloperDashboardPage.tsx +211 -0
- package/template/src/client/pages/LoginPage.tsx +127 -0
- package/template/src/client/pages/OrdersPage.tsx +196 -0
- package/template/src/client/pages/PluginDetailPage.tsx +345 -0
- package/template/src/client/pages/PluginsPage.tsx +223 -0
- package/template/src/client/pages/ProfilePage.tsx +206 -0
- package/template/src/client/pages/PublishPage.tsx +336 -0
- package/template/src/client/pages/RegisterPage.tsx +136 -0
- package/template/src/client/pages/SearchPage.tsx +204 -0
- package/template/src/client/pages/SettingsPage.tsx +220 -0
- package/template/src/client/pages/TopicsPage.tsx +180 -0
- package/template/src/client/pages/__tests__/LoginPage.test.tsx +170 -0
- package/template/src/client/pages/__tests__/RegisterPage.test.tsx +168 -0
- package/template/src/client/preset-ui-config.ts +492 -0
- package/template/src/client/services/apiClient.ts +14 -4
- package/template/src/client/stores/__tests__/authStore.test.ts +293 -38
- package/template/src/client/stores/__tests__/todoStore.test.ts +7 -17
- package/template/src/client/stores/authStore.ts +58 -5
- package/template/src/client/stores/chatWSStore.ts +9 -0
- package/template/src/client/stores/notificationStore.ts +4 -0
- package/template/src/client/stores/pluginStore.ts +279 -0
- package/template/src/client/stores/todoStore.ts +2 -6
- package/template/src/server/core/__tests__/isr-cache.test.ts +117 -0
- package/template/src/server/core/__tests__/isr-invalidation.test.ts +72 -0
- package/template/src/server/core/__tests__/ssr-renderer.test.ts +89 -0
- package/template/src/server/core/isr-cache.ts +239 -0
- package/template/src/server/core/isr-invalidation.ts +45 -0
- package/template/src/server/core/module-loader.ts +14 -7
- package/template/src/server/core/ssr-renderer.ts +240 -0
- package/template/src/server/db/init.ts +257 -10
- package/template/src/server/db/schema/developers.ts +20 -0
- package/template/src/server/db/schema/index.ts +2 -0
- package/template/src/server/db/schema/plugins.ts +114 -0
- package/template/src/server/db/test-setup.ts +91 -0
- package/template/src/server/entries/cloudflare.ts +79 -7
- package/template/src/server/entries/node.ts +48 -5
- package/template/src/server/middleware/__tests__/captcha.test.ts +23 -13
- package/template/src/server/middleware/auth.ts +8 -1
- package/template/src/server/middleware/captcha.ts +14 -4
- package/template/src/server/middleware/rate-limit.ts +7 -2
- package/template/src/server/module-admin/module.ts +9 -5
- package/template/src/server/module-admin/routes/admin-notification-routes.ts +43 -14
- package/template/src/server/module-admin/routes/admin-routes.ts +0 -2
- package/template/src/server/module-admin/routes/client-auth-routes.ts +90 -0
- package/template/src/server/module-admin/routes/dashboard-routes.ts +79 -0
- package/template/src/server/module-admin/services/admin-service.ts +68 -11
- package/template/src/server/module-auth/__tests__/auth-service.test.ts +239 -0
- package/template/src/server/module-auth/index.ts +7 -0
- package/template/src/server/module-auth/module.ts +40 -0
- package/template/src/server/module-auth/routes/auth-routes.ts +94 -0
- package/template/src/server/module-auth/routes/profile-routes.ts +31 -0
- package/template/src/server/module-auth/services/auth-service.ts +100 -0
- package/template/src/server/module-content/module.ts +10 -4
- package/template/src/server/module-content/routes/public-content-routes.ts +2 -2
- package/template/src/server/module-content/routes/topics-routes.ts +205 -0
- package/template/src/server/module-content/services/content-service.ts +18 -2
- package/template/src/server/module-dispute/routes/dispute-routes.ts +2 -1
- package/template/src/server/module-dispute/services/dispute-service.ts +1 -1
- package/template/src/server/module-notifications/__tests__/sse-rpc.test.ts +14 -14
- package/template/src/server/module-notifications/routes/notification-routes.ts +34 -8
- package/template/src/server/module-order/__tests__/order-route.test.ts +22 -2
- package/template/src/server/module-order/module.ts +15 -0
- package/template/src/server/module-order/routes/cart-routes.ts +103 -0
- package/template/src/server/module-order/routes/orders-mock-routes.ts +67 -0
- package/template/src/server/module-order/services/order-service.ts +1 -1
- package/template/src/server/module-plugin/__tests__/plugin-query-service.test.ts +203 -0
- package/template/src/server/module-plugin/__tests__/plugin-service.test.ts +234 -0
- package/template/src/server/module-plugin/index.ts +2 -0
- package/template/src/server/module-plugin/module.ts +52 -0
- package/template/src/server/module-plugin/routes/plugin-admin-routes.ts +261 -0
- package/template/src/server/module-plugin/routes/plugin-routes.ts +354 -0
- package/template/src/server/module-plugin/services/admin-category-service.ts +99 -0
- package/template/src/server/module-plugin/services/admin-plugin-service.ts +170 -0
- package/template/src/server/module-plugin/services/admin-stats-service.ts +41 -0
- package/template/src/server/module-plugin/services/plugin-query-service.ts +360 -0
- package/template/src/server/module-plugin/services/plugin-review-service.ts +95 -0
- package/template/src/server/module-plugin/services/plugin-service.ts +163 -0
- package/template/src/server/module-ticket/services/ticket-service.ts +1 -1
- package/template/src/server/module-todos/routes/todos-routes.ts +0 -4
- package/template/src/server/route-registry.ts +16 -1
- package/template/src/server/test-utils/test-client.ts +1 -2
- package/template/src/server/utils/auth.ts +6 -0
- package/template/src/server/utils/json.ts +13 -0
- package/template/src/shared/core/module-manifest.ts +3 -6
- package/template/src/shared/modules/auth/index.ts +12 -0
- package/template/src/shared/modules/auth/schemas.ts +50 -0
- package/template/src/shared/modules/cart/index.ts +1 -0
- package/template/src/shared/modules/cart/schemas.ts +41 -0
- package/template/src/shared/modules/community/index.ts +1 -0
- package/template/src/shared/modules/community/schemas.ts +58 -0
- package/template/src/shared/modules/dashboard/index.ts +1 -0
- package/template/src/shared/modules/dashboard/schemas.ts +35 -0
- package/template/src/shared/modules/index.ts +41 -0
- package/template/src/shared/modules/order/schemas.ts +29 -0
- package/template/src/shared/modules/plugins/index.ts +48 -0
- package/template/src/shared/modules/plugins/schemas.ts +227 -0
- package/template/src/shared/schemas/index.ts +130 -0
- package/template/tests/e2e/todo.spec.ts +23 -18
- package/template/tests/e2e/visual-screenshots.spec.ts +1824 -0
- package/template/uploads/.gitkeep +0 -0
- package/template/vite.config.ts +2 -1
- package/template/vitest.setup.ts +11 -0
- package/template/wrangler.toml +4 -3
- package/template/package-lock.json +0 -14554
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { z } from '@hono/zod-openapi'
|
|
2
|
+
|
|
3
|
+
export const PluginStatusSchema = z.enum(['pending', 'approved', 'rejected'])
|
|
4
|
+
|
|
5
|
+
export const PluginSchema = z.object({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
name: z.string().min(1).max(200),
|
|
8
|
+
slug: z.string().min(1).max(200),
|
|
9
|
+
description: z.string().max(2000),
|
|
10
|
+
readme: z.string().nullish(),
|
|
11
|
+
authorId: z.string(),
|
|
12
|
+
authorName: z.string(),
|
|
13
|
+
repositoryUrl: z.string().url().nullish(),
|
|
14
|
+
homepageUrl: z.string().url().nullish(),
|
|
15
|
+
npmPackage: z.string().nullish(),
|
|
16
|
+
license: z.string().nullish(),
|
|
17
|
+
version: z.string(),
|
|
18
|
+
status: PluginStatusSchema,
|
|
19
|
+
downloadCount: z.number().int().nonnegative().default(0),
|
|
20
|
+
viewCount: z.number().int().nonnegative().default(0),
|
|
21
|
+
featured: z.boolean().default(false),
|
|
22
|
+
screenshotUrl: z.string().nullish(),
|
|
23
|
+
siteUrls: z.array(z.string().url()).nullish(),
|
|
24
|
+
tags: z.array(z.string()).nullish(),
|
|
25
|
+
commands: z
|
|
26
|
+
.array(
|
|
27
|
+
z.object({
|
|
28
|
+
name: z.string(),
|
|
29
|
+
description: z.string().nullish(),
|
|
30
|
+
})
|
|
31
|
+
)
|
|
32
|
+
.nullish(),
|
|
33
|
+
rejectReason: z.string().nullish(),
|
|
34
|
+
createdAt: z.number(),
|
|
35
|
+
updatedAt: z.number(),
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const CreatePluginSchema = z.object({
|
|
39
|
+
name: z.string().min(1).max(200),
|
|
40
|
+
slug: z
|
|
41
|
+
.string()
|
|
42
|
+
.min(1)
|
|
43
|
+
.max(200)
|
|
44
|
+
.regex(/^[a-z0-9-]+$/),
|
|
45
|
+
description: z.string().min(1).max(2000),
|
|
46
|
+
repositoryUrl: z.string().url().nullish(),
|
|
47
|
+
homepageUrl: z.string().url().nullish(),
|
|
48
|
+
npmPackage: z.string().nullish(),
|
|
49
|
+
license: z.string().nullish(),
|
|
50
|
+
tags: z.array(z.string()).nullish(),
|
|
51
|
+
siteUrls: z.array(z.string().url()).nullish(),
|
|
52
|
+
commands: z
|
|
53
|
+
.array(
|
|
54
|
+
z.object({
|
|
55
|
+
name: z.string(),
|
|
56
|
+
description: z.string().nullish(),
|
|
57
|
+
})
|
|
58
|
+
)
|
|
59
|
+
.nullish(),
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
export const UpdatePluginSchema = CreatePluginSchema.partial()
|
|
63
|
+
|
|
64
|
+
export const PluginVersionStatusSchema = z.enum(['pending', 'approved', 'rejected'])
|
|
65
|
+
|
|
66
|
+
export const VersionSchema = z.object({
|
|
67
|
+
id: z.string(),
|
|
68
|
+
pluginId: z.string(),
|
|
69
|
+
version: z.string(),
|
|
70
|
+
changelog: z.string().nullish(),
|
|
71
|
+
packageUrl: z.string().nullish(),
|
|
72
|
+
fileSize: z.number().nullish(),
|
|
73
|
+
checksum: z.string().nullish(),
|
|
74
|
+
status: PluginVersionStatusSchema,
|
|
75
|
+
publishedAt: z.number(),
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
export const CategorySchema = z.object({
|
|
79
|
+
id: z.string(),
|
|
80
|
+
name: z.string(),
|
|
81
|
+
slug: z.string(),
|
|
82
|
+
description: z.string().nullish(),
|
|
83
|
+
icon: z.string().nullish(),
|
|
84
|
+
sortOrder: z.number().int().default(0),
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
export const ReviewSchema = z.object({
|
|
88
|
+
id: z.string(),
|
|
89
|
+
pluginId: z.string(),
|
|
90
|
+
userId: z.string(),
|
|
91
|
+
userName: z.string(),
|
|
92
|
+
rating: z.number().int().min(1).max(5),
|
|
93
|
+
title: z.string().nullish(),
|
|
94
|
+
content: z.string().nullish(),
|
|
95
|
+
createdAt: z.number(),
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
export const CreateReviewSchema = z.object({
|
|
99
|
+
rating: z.number().int().min(1).max(5),
|
|
100
|
+
title: z.string().max(200).nullish(),
|
|
101
|
+
content: z.string().max(2000).nullish(),
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
export const MarketplaceStatsSchema = z.object({
|
|
105
|
+
totalPlugins: z.number(),
|
|
106
|
+
totalDownloads: z.number(),
|
|
107
|
+
totalDevelopers: z.number(),
|
|
108
|
+
totalCategories: z.number(),
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
export const PluginListResponseSchema = z.object({
|
|
112
|
+
plugins: z.array(PluginSchema),
|
|
113
|
+
total: z.number(),
|
|
114
|
+
page: z.number(),
|
|
115
|
+
limit: z.number(),
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
export const AdminPluginSchema = PluginSchema.extend({
|
|
119
|
+
avgRating: z.number().nullish(),
|
|
120
|
+
reviewCount: z.number().nullish(),
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
export const AdminDashboardStatsSchema = z.object({
|
|
124
|
+
totalPlugins: z.number(),
|
|
125
|
+
pendingPlugins: z.number(),
|
|
126
|
+
totalDownloads: z.number(),
|
|
127
|
+
totalDevelopers: z.number(),
|
|
128
|
+
totalCategories: z.number(),
|
|
129
|
+
recentSubmissions: z.array(AdminPluginSchema).nullish(),
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
export const PluginListQuerySchema = z.object({
|
|
133
|
+
page: z.coerce.number().int().positive().default(1),
|
|
134
|
+
limit: z.coerce.number().int().positive().max(100).default(20),
|
|
135
|
+
search: z.string().nullish(),
|
|
136
|
+
status: PluginStatusSchema.nullish(),
|
|
137
|
+
category: z.string().nullish(),
|
|
138
|
+
sort: z.enum(['newest', 'popular', 'downloads', 'name']).default('newest'),
|
|
139
|
+
featured: z.coerce.boolean().nullish(),
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
export const PluginSlugSchema = z.object({
|
|
143
|
+
slug: z.string().min(1),
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
export const PluginSearchQuerySchema = z.object({
|
|
147
|
+
q: z.string().min(1),
|
|
148
|
+
page: z.coerce.number().int().positive().default(1),
|
|
149
|
+
limit: z.coerce.number().int().positive().max(100).default(20),
|
|
150
|
+
category: z.string().nullish(),
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
export const PluginDeleteResponseSchema = z.object({ slug: z.string() })
|
|
154
|
+
|
|
155
|
+
export const ReviewIdParamsSchema = z.object({ slug: z.string(), reviewId: z.string() })
|
|
156
|
+
|
|
157
|
+
export const ReviewDeleteResponseSchema = z.object({ id: z.string() })
|
|
158
|
+
|
|
159
|
+
export const CategorySlugParamsSchema = z.object({ slug: z.string() })
|
|
160
|
+
|
|
161
|
+
export const CategoryPluginsQuerySchema = z.object({
|
|
162
|
+
page: z.coerce.number().int().positive().default(1),
|
|
163
|
+
limit: z.coerce.number().int().positive().max(100).default(20),
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
export const PluginListAdminSchema = z.object({
|
|
167
|
+
plugins: z.array(PluginSchema),
|
|
168
|
+
total: z.number(),
|
|
169
|
+
page: z.number(),
|
|
170
|
+
limit: z.number(),
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
export const AdminListQuerySchema = z.object({
|
|
174
|
+
page: z.coerce.number().int().positive().default(1),
|
|
175
|
+
limit: z.coerce.number().int().positive().max(100).default(20),
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
export const AdminListAllQuerySchema = z.object({
|
|
179
|
+
page: z.coerce.number().int().positive().default(1),
|
|
180
|
+
limit: z.coerce.number().int().positive().max(100).default(20),
|
|
181
|
+
status: PluginStatusSchema.nullish(),
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
export const RejectPluginBodySchema = z.object({ reason: z.string().min(1) })
|
|
185
|
+
|
|
186
|
+
export const BulkApproveBodySchema = z.object({ slugs: z.array(z.string()).min(1) })
|
|
187
|
+
|
|
188
|
+
export const BulkRejectBodySchema = z.object({
|
|
189
|
+
slugs: z.array(z.string()).min(1),
|
|
190
|
+
reason: z.string().min(1),
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
export const BulkResponseSchema = z.object({ count: z.number() })
|
|
194
|
+
|
|
195
|
+
export const CreateCategoryBodySchema = z.object({
|
|
196
|
+
name: z.string().min(1),
|
|
197
|
+
slug: z.string().min(1),
|
|
198
|
+
description: z.string().nullish(),
|
|
199
|
+
icon: z.string().nullish(),
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
export const UpdateCategoryBodySchema = z.object({
|
|
203
|
+
name: z.string().nullish(),
|
|
204
|
+
slug: z.string().nullish(),
|
|
205
|
+
description: z.string().nullish(),
|
|
206
|
+
icon: z.string().nullish(),
|
|
207
|
+
sortOrder: z.number().int().nullish(),
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
export const CategoryIdParamsSchema = z.object({ id: z.string() })
|
|
211
|
+
|
|
212
|
+
export const CategoryIdResponseSchema = z.object({ id: z.string() })
|
|
213
|
+
|
|
214
|
+
export type Plugin = z.infer<typeof PluginSchema>
|
|
215
|
+
export type PluginStatus = z.infer<typeof PluginStatusSchema>
|
|
216
|
+
export type CreatePluginInput = z.infer<typeof CreatePluginSchema>
|
|
217
|
+
export type UpdatePluginInput = z.infer<typeof UpdatePluginSchema>
|
|
218
|
+
export type PluginVersionStatus = z.infer<typeof PluginVersionStatusSchema>
|
|
219
|
+
export type Version = z.infer<typeof VersionSchema>
|
|
220
|
+
export type Category = z.infer<typeof CategorySchema>
|
|
221
|
+
export type Review = z.infer<typeof ReviewSchema>
|
|
222
|
+
export type CreateReviewInput = z.infer<typeof CreateReviewSchema>
|
|
223
|
+
export type MarketplaceStats = z.infer<typeof MarketplaceStatsSchema>
|
|
224
|
+
export type PluginListResponse = z.infer<typeof PluginListResponseSchema>
|
|
225
|
+
export type AdminPlugin = z.infer<typeof AdminPluginSchema>
|
|
226
|
+
export type AdminDashboardStats = z.infer<typeof AdminDashboardStatsSchema>
|
|
227
|
+
export type PluginListQuery = z.infer<typeof PluginListQuerySchema>
|
|
@@ -77,3 +77,133 @@ export {
|
|
|
77
77
|
type NotificationId,
|
|
78
78
|
type UnreadCountEvent,
|
|
79
79
|
} from '../modules/notifications'
|
|
80
|
+
export {
|
|
81
|
+
DeveloperProfileSchema,
|
|
82
|
+
LoginSchema,
|
|
83
|
+
RegisterSchema,
|
|
84
|
+
TokenResponseSchema,
|
|
85
|
+
ProfileSchema,
|
|
86
|
+
type DeveloperProfile,
|
|
87
|
+
type LoginInput,
|
|
88
|
+
type RegisterInput,
|
|
89
|
+
type TokenResponse,
|
|
90
|
+
type Profile,
|
|
91
|
+
} from '../modules/auth'
|
|
92
|
+
export {
|
|
93
|
+
PluginSchema,
|
|
94
|
+
PluginStatusSchema,
|
|
95
|
+
CreatePluginSchema,
|
|
96
|
+
UpdatePluginSchema,
|
|
97
|
+
PluginVersionStatusSchema,
|
|
98
|
+
VersionSchema,
|
|
99
|
+
CategorySchema,
|
|
100
|
+
ReviewSchema,
|
|
101
|
+
CreateReviewSchema,
|
|
102
|
+
MarketplaceStatsSchema,
|
|
103
|
+
PluginListResponseSchema,
|
|
104
|
+
AdminPluginSchema,
|
|
105
|
+
AdminDashboardStatsSchema,
|
|
106
|
+
PluginListQuerySchema,
|
|
107
|
+
PluginSlugSchema,
|
|
108
|
+
PluginSearchQuerySchema,
|
|
109
|
+
PluginDeleteResponseSchema,
|
|
110
|
+
ReviewIdParamsSchema,
|
|
111
|
+
ReviewDeleteResponseSchema,
|
|
112
|
+
CategorySlugParamsSchema,
|
|
113
|
+
CategoryPluginsQuerySchema,
|
|
114
|
+
PluginListAdminSchema,
|
|
115
|
+
AdminListQuerySchema,
|
|
116
|
+
AdminListAllQuerySchema,
|
|
117
|
+
RejectPluginBodySchema,
|
|
118
|
+
BulkApproveBodySchema,
|
|
119
|
+
BulkRejectBodySchema,
|
|
120
|
+
BulkResponseSchema,
|
|
121
|
+
CreateCategoryBodySchema,
|
|
122
|
+
UpdateCategoryBodySchema,
|
|
123
|
+
CategoryIdParamsSchema,
|
|
124
|
+
CategoryIdResponseSchema,
|
|
125
|
+
type Plugin,
|
|
126
|
+
type PluginStatus,
|
|
127
|
+
type CreatePluginInput,
|
|
128
|
+
type UpdatePluginInput,
|
|
129
|
+
type PluginVersionStatus,
|
|
130
|
+
type Version,
|
|
131
|
+
type Category,
|
|
132
|
+
type Review,
|
|
133
|
+
type CreateReviewInput,
|
|
134
|
+
type MarketplaceStats,
|
|
135
|
+
type PluginListResponse,
|
|
136
|
+
type AdminPlugin,
|
|
137
|
+
type AdminDashboardStats,
|
|
138
|
+
type PluginListQuery,
|
|
139
|
+
} from '../modules/plugins'
|
|
140
|
+
export {
|
|
141
|
+
DashboardStatSchema,
|
|
142
|
+
RevenueDataSchema,
|
|
143
|
+
ActivityStatusSchema,
|
|
144
|
+
ActivitySchema,
|
|
145
|
+
DashboardResponseSchema,
|
|
146
|
+
type DashboardStat,
|
|
147
|
+
type RevenueData,
|
|
148
|
+
type ActivityStatus,
|
|
149
|
+
type Activity,
|
|
150
|
+
type DashboardResponse,
|
|
151
|
+
} from '../modules/dashboard'
|
|
152
|
+
export {
|
|
153
|
+
CartItemSchema,
|
|
154
|
+
CartSummarySchema,
|
|
155
|
+
CartResponseSchema,
|
|
156
|
+
AddCartItemSchema,
|
|
157
|
+
CartItemIdSchema,
|
|
158
|
+
type CartItem,
|
|
159
|
+
type CartSummary,
|
|
160
|
+
type CartResponse,
|
|
161
|
+
type AddCartItemInput,
|
|
162
|
+
} from '../modules/cart'
|
|
163
|
+
export {
|
|
164
|
+
RemoveCartItemResponseSchema,
|
|
165
|
+
ECommerceProductSchema,
|
|
166
|
+
ECommerceOrderStatusSchema,
|
|
167
|
+
ECommerceOrderSchema,
|
|
168
|
+
ECommerceOrderListSchema,
|
|
169
|
+
OrderStatusSchema,
|
|
170
|
+
OrderSchema,
|
|
171
|
+
CreateOrderSchema,
|
|
172
|
+
UpdateOrderSchema,
|
|
173
|
+
OrderListSchema,
|
|
174
|
+
OrderQuerySchema,
|
|
175
|
+
DeleteResultSchema,
|
|
176
|
+
ProcessOrderSchema,
|
|
177
|
+
CancelOrderSchema,
|
|
178
|
+
type RemoveCartItemResponse,
|
|
179
|
+
type ECommerceProduct,
|
|
180
|
+
type ECommerceOrderStatus,
|
|
181
|
+
type ECommerceOrder,
|
|
182
|
+
type OrderStatus,
|
|
183
|
+
type Order,
|
|
184
|
+
type CreateOrderInput,
|
|
185
|
+
type UpdateOrderInput,
|
|
186
|
+
type DeleteResult,
|
|
187
|
+
type ProcessOrderInput,
|
|
188
|
+
type CancelOrderInput,
|
|
189
|
+
type OrderQueryInput,
|
|
190
|
+
} from '../modules/order'
|
|
191
|
+
export {
|
|
192
|
+
TopicStatusSchema,
|
|
193
|
+
TopicTagSchema,
|
|
194
|
+
TopicAuthorSchema,
|
|
195
|
+
TopicSchema,
|
|
196
|
+
TopicsResponseSchema,
|
|
197
|
+
ProfileStatsSchema,
|
|
198
|
+
ActivityTypeSchema,
|
|
199
|
+
ProfileActivitySchema,
|
|
200
|
+
ProfileResponseSchema,
|
|
201
|
+
type TopicStatus,
|
|
202
|
+
type TopicTag,
|
|
203
|
+
type TopicAuthor,
|
|
204
|
+
type Topic,
|
|
205
|
+
type ProfileStats,
|
|
206
|
+
type ActivityType,
|
|
207
|
+
type ProfileActivity,
|
|
208
|
+
type ProfileResponse,
|
|
209
|
+
} from '../modules/community'
|
|
@@ -348,45 +348,48 @@ test.describe('Todo App', () => {
|
|
|
348
348
|
|
|
349
349
|
// Wait for network to be idle
|
|
350
350
|
await page.waitForLoadState('networkidle')
|
|
351
|
+
|
|
352
|
+
// Wait for React to re-render after state update
|
|
353
|
+
await page.waitForTimeout(500)
|
|
351
354
|
})
|
|
352
355
|
|
|
353
356
|
test('should filter to show only pending todos', async ({ page }) => {
|
|
354
357
|
// Click filter to show pending only
|
|
355
358
|
await page.click('[data-testid="filter-pending"]')
|
|
356
359
|
|
|
357
|
-
// Wait for
|
|
358
|
-
await page.
|
|
360
|
+
// Wait for React to re-render after filter state update
|
|
361
|
+
await page.waitForTimeout(500)
|
|
359
362
|
|
|
360
363
|
// Verify only pending todos are shown
|
|
361
|
-
await expect(page.locator('[data-testid="todo-item"]')).toHaveCount(1)
|
|
364
|
+
await expect(page.locator('[data-testid="todo-item"]')).toHaveCount(1, { timeout: 10000 })
|
|
362
365
|
})
|
|
363
366
|
|
|
364
367
|
test('should filter to show only completed todos', async ({ page }) => {
|
|
365
368
|
// Click filter to show completed only
|
|
366
369
|
await page.click('[data-testid="filter-completed"]')
|
|
367
370
|
|
|
368
|
-
// Wait for
|
|
369
|
-
await page.
|
|
371
|
+
// Wait for React to re-render after filter state update
|
|
372
|
+
await page.waitForTimeout(500)
|
|
370
373
|
|
|
371
374
|
// Verify only completed todos are shown
|
|
372
|
-
await expect(page.locator('[data-testid="todo-item"]')).toHaveCount(1)
|
|
375
|
+
await expect(page.locator('[data-testid="todo-item"]')).toHaveCount(1, { timeout: 10000 })
|
|
373
376
|
})
|
|
374
377
|
|
|
375
378
|
test('should show all todos when filter is reset', async ({ page }) => {
|
|
376
379
|
// Filter to completed
|
|
377
380
|
await page.click('[data-testid="filter-completed"]')
|
|
378
381
|
|
|
379
|
-
// Wait for
|
|
380
|
-
await page.
|
|
382
|
+
// Wait for React to re-render
|
|
383
|
+
await page.waitForTimeout(500)
|
|
381
384
|
|
|
382
385
|
// Reset filter to all
|
|
383
386
|
await page.click('[data-testid="filter-all"]')
|
|
384
387
|
|
|
385
|
-
// Wait for
|
|
386
|
-
await page.
|
|
388
|
+
// Wait for React to re-render after filter state update
|
|
389
|
+
await page.waitForTimeout(500)
|
|
387
390
|
|
|
388
391
|
// Verify all todos are shown
|
|
389
|
-
await expect(page.locator('[data-testid="todo-item"]')).toHaveCount(2)
|
|
392
|
+
await expect(page.locator('[data-testid="todo-item"]')).toHaveCount(2, { timeout: 10000 })
|
|
390
393
|
})
|
|
391
394
|
})
|
|
392
395
|
|
|
@@ -468,22 +471,24 @@ test.describe('Todo App', () => {
|
|
|
468
471
|
await expect(page.locator('[data-testid="add-todo-button"]')).toBeEnabled()
|
|
469
472
|
await page.click('[data-testid="add-todo-button"]')
|
|
470
473
|
|
|
471
|
-
// Wait for network to be idle
|
|
474
|
+
// Wait for network to be idle and React re-render
|
|
472
475
|
await page.waitForLoadState('networkidle')
|
|
473
|
-
|
|
474
|
-
// Wait for form to reset
|
|
475
476
|
await page.waitForTimeout(500)
|
|
477
|
+
|
|
476
478
|
await page.fill('[data-testid="todo-title-input"]', 'Todo 2')
|
|
477
479
|
// Wait for input to be processed
|
|
478
480
|
await page.waitForTimeout(500)
|
|
479
481
|
await expect(page.locator('[data-testid="add-todo-button"]')).toBeEnabled()
|
|
480
482
|
await page.click('[data-testid="add-todo-button"]')
|
|
481
483
|
|
|
482
|
-
// Wait for network to be idle
|
|
484
|
+
// Wait for network to be idle and React re-render
|
|
483
485
|
await page.waitForLoadState('networkidle')
|
|
486
|
+
await page.waitForTimeout(500)
|
|
484
487
|
|
|
485
488
|
// Verify todo count
|
|
486
|
-
await expect(page.locator('[data-testid="todo-count"]')).toHaveText(/Total
|
|
489
|
+
await expect(page.locator('[data-testid="todo-count"]')).toHaveText(/Total:\s*\d+/, {
|
|
490
|
+
timeout: 10000,
|
|
491
|
+
})
|
|
487
492
|
})
|
|
488
493
|
})
|
|
489
494
|
|
|
@@ -512,7 +517,7 @@ test.describe('Todo App', () => {
|
|
|
512
517
|
await page.waitForLoadState('networkidle')
|
|
513
518
|
|
|
514
519
|
// Wait for app to render
|
|
515
|
-
await page.waitForSelector('[data-testid="todo-form"]', { timeout:
|
|
520
|
+
await page.waitForSelector('[data-testid="todo-form"]', { timeout: 30000 })
|
|
516
521
|
|
|
517
522
|
// Create a todo
|
|
518
523
|
await page.fill('[data-testid="todo-title-input"]', 'Persistent todo')
|
|
@@ -539,7 +544,7 @@ test.describe('Todo App', () => {
|
|
|
539
544
|
await newPage.reload()
|
|
540
545
|
await newPage.waitForLoadState('load')
|
|
541
546
|
await newPage.waitForLoadState('networkidle')
|
|
542
|
-
await newPage.waitForSelector('[data-testid="todo-item"]', { timeout:
|
|
547
|
+
await newPage.waitForSelector('[data-testid="todo-item"]', { timeout: 30000 })
|
|
543
548
|
|
|
544
549
|
// Verify todo still exists
|
|
545
550
|
await expect(newPage.locator('[data-testid="todo-item"]')).toHaveCount(1)
|