create-appraisejs 0.1.9 → 0.1.10-alpha.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/README.md +24 -17
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.e2e.test.js +11 -8
- package/dist/cli.e2e.test.js.map +1 -1
- package/dist/cli.js +32 -48
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -1
- package/dist/config.js.map +1 -1
- package/dist/config.test.js +9 -5
- package/dist/config.test.js.map +1 -1
- package/dist/copy-template.d.ts +1 -1
- package/dist/copy-template.d.ts.map +1 -1
- package/dist/copy-template.js +7 -3
- package/dist/copy-template.js.map +1 -1
- package/dist/copy-template.test.js +14 -9
- package/dist/copy-template.test.js.map +1 -1
- package/dist/create-project.d.ts +23 -0
- package/dist/create-project.d.ts.map +1 -0
- package/dist/create-project.js +58 -0
- package/dist/create-project.js.map +1 -0
- package/dist/create-project.test.d.ts +2 -0
- package/dist/create-project.test.d.ts.map +1 -0
- package/dist/create-project.test.js +80 -0
- package/dist/create-project.test.js.map +1 -0
- package/dist/install.d.ts +8 -4
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +22 -72
- package/dist/install.js.map +1 -1
- package/dist/install.test.js +26 -10
- package/dist/install.test.js.map +1 -1
- package/dist/package-manager.d.ts +11 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +47 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/package-manager.test.d.ts +2 -0
- package/dist/package-manager.test.d.ts.map +1 -0
- package/dist/package-manager.test.js +51 -0
- package/dist/package-manager.test.js.map +1 -0
- package/dist/prepare-template-utils.d.ts +10 -0
- package/dist/prepare-template-utils.d.ts.map +1 -0
- package/dist/prepare-template-utils.js +53 -0
- package/dist/prepare-template-utils.js.map +1 -0
- package/dist/prepare-template-utils.test.d.ts +2 -0
- package/dist/prepare-template-utils.test.d.ts.map +1 -0
- package/dist/prepare-template-utils.test.js +67 -0
- package/dist/prepare-template-utils.test.js.map +1 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +11 -3
- package/dist/prompts.js.map +1 -1
- package/dist/prompts.test.js +17 -7
- package/dist/prompts.test.js.map +1 -1
- package/dist/template-sync-utils.test.d.ts +2 -0
- package/dist/template-sync-utils.test.d.ts.map +1 -0
- package/dist/template-sync-utils.test.js +41 -0
- package/dist/template-sync-utils.test.js.map +1 -0
- package/package.json +3 -2
- package/templates/default/.appraise-template-meta.json +5 -0
- package/templates/default/.env.example +1 -1
- package/templates/default/.vscode/settings.json +10 -3
- package/templates/default/README.md +27 -25
- package/templates/default/automation/features/base/login.feature +15 -0
- package/templates/default/automation/locators/base/home.json +3 -0
- package/templates/default/automation/locators/base/login.json +6 -0
- package/templates/default/automation/locators/base/test.json +1 -0
- package/templates/default/automation/mapping/locator-map.json +14 -0
- package/templates/default/{src/tests → automation}/steps/actions/click.step.ts +1 -4
- package/templates/default/{src/tests → automation}/steps/actions/hover.step.ts +1 -4
- package/templates/default/{src/tests → automation}/steps/actions/input.step.ts +1 -4
- package/templates/default/{src/tests → automation}/steps/actions/navigation.step.ts +1 -3
- package/templates/default/{src/tests → automation}/steps/actions/random_data.step.ts +1 -3
- package/templates/default/{src/tests → automation}/steps/actions/store.step.ts +1 -4
- package/templates/default/automation/steps/actions/wait.step.ts +91 -0
- package/templates/default/{src/tests → automation}/steps/validations/active_state_assertion.step.ts +1 -4
- package/templates/default/{src/tests → automation}/steps/validations/navigation_assertion.step.ts +1 -2
- package/templates/default/{src/tests → automation}/steps/validations/text_assertion.step.ts +1 -4
- package/templates/default/{src/tests → automation}/steps/validations/visibility_assertion.step.ts +1 -4
- package/templates/default/cucumber.mjs +6 -6
- package/templates/default/eslint.config.mjs +5 -4
- package/templates/default/package-lock.json +322 -485
- package/templates/default/package.json +11 -6
- package/templates/default/packages/cucumber-runtime/package.json +13 -0
- package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -0
- package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -0
- package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -0
- package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -0
- package/templates/default/{src/tests/hooks → packages/cucumber-runtime/src}/hooks.ts +17 -32
- package/templates/default/packages/cucumber-runtime/src/index.ts +17 -0
- package/templates/default/{src/tests/utils → packages/cucumber-runtime/src}/locator.util.ts +50 -64
- package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -0
- package/templates/default/packages/cucumber-runtime/src/paths.ts +33 -0
- package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -0
- package/templates/default/packages/cucumber-runtime/src/types.ts +13 -0
- package/templates/default/{src/tests/config/executor → packages/cucumber-runtime/src}/world.ts +4 -1
- package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -0
- package/templates/default/scripts/setup-env.ts +4 -4
- package/templates/default/scripts/sync-appraise-base-template.ts +123 -105
- package/templates/default/scripts/sync-environments.ts +8 -5
- package/templates/default/scripts/sync-locator-groups.ts +7 -10
- package/templates/default/scripts/sync-locators.ts +5 -9
- package/templates/default/scripts/sync-modules.ts +9 -17
- package/templates/default/scripts/sync-tags.ts +2 -2
- package/templates/default/scripts/sync-template-step-groups.ts +16 -6
- package/templates/default/scripts/sync-template-steps.ts +16 -5
- package/templates/default/scripts/sync-test-cases.ts +6 -3
- package/templates/default/scripts/sync-test-suites.ts +7 -4
- package/templates/default/src/actions/environments/environment-actions.ts +6 -23
- package/templates/default/src/actions/locator/locator-actions.ts +36 -93
- package/templates/default/src/actions/locator-groups/locator-group-actions.ts +24 -78
- package/templates/default/src/actions/modules/module-actions.ts +4 -2
- package/templates/default/src/actions/tags/tag-actions.ts +4 -1
- package/templates/default/src/actions/template-step/template-step-actions.ts +10 -101
- package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +31 -130
- package/templates/default/src/actions/test-case/test-case-actions.ts +31 -94
- package/templates/default/src/actions/test-run/test-run-actions.ts +11 -13
- package/templates/default/src/actions/test-suite/test-suite-actions.ts +29 -82
- package/templates/default/src/app/(base)/locator-groups/page.tsx +1 -3
- package/templates/default/src/app/(base)/reports/page.tsx +1 -1
- package/templates/default/src/app/(base)/reports/test-cases/page.tsx +2 -2
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +1 -1
- package/templates/default/src/app/(base)/tags/page.tsx +2 -2
- package/templates/default/src/app/(base)/template-steps/page.tsx +1 -2
- package/templates/default/src/app/(base)/test-runs/page.tsx +2 -2
- package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +2 -1
- package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +2 -1
- package/templates/default/src/app/page.tsx +4 -5
- package/templates/default/src/components/diagram/dynamic-parameters.tsx +76 -40
- package/templates/default/src/components/diagram/options-header-node.tsx +1 -1
- package/templates/default/src/components/ui/data-table.tsx +33 -39
- package/templates/default/src/lib/automation/paths.ts +181 -0
- package/templates/default/src/lib/automation/projection-service.ts +230 -0
- package/templates/default/src/lib/environment-file-utils.ts +14 -51
- package/templates/default/src/lib/executor/local-executor-adapter.ts +101 -0
- package/templates/default/src/lib/executor/types.ts +24 -0
- package/templates/default/src/lib/feature-file-generator.ts +22 -112
- package/templates/default/src/lib/locator-group-file-utils.ts +57 -120
- package/templates/default/src/lib/process/task-spawner.ts +236 -0
- package/templates/default/src/lib/template-sync-utils.d.ts +7 -0
- package/templates/default/src/lib/template-sync-utils.d.ts.map +1 -0
- package/templates/default/src/lib/template-sync-utils.js +47 -0
- package/templates/default/src/lib/template-sync-utils.js.map +1 -0
- package/templates/default/src/lib/template-sync-utils.ts +63 -0
- package/templates/default/src/lib/test-run/process-manager.ts +9 -87
- package/templates/default/src/lib/test-run/test-run-executor.ts +7 -136
- package/templates/default/src/lib/test-run/winston-logger.ts +6 -35
- package/templates/default/src/lib/utils/template-step-file-generator.ts +22 -85
- package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +7 -22
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/src/tests/executor.ts +0 -80
- package/templates/default/src/tests/mapping/locator-map.json +0 -1
- package/templates/default/src/tests/steps/actions/wait.step.ts +0 -107
- package/templates/default/src/tests/support/parameter-types.ts +0 -12
- package/templates/default/src/tests/utils/cache.util.ts +0 -260
- package/templates/default/src/tests/utils/cli.util.ts +0 -177
- package/templates/default/src/tests/utils/environment.util.ts +0 -65
- package/templates/default/src/tests/utils/random-data.util.ts +0 -45
- package/templates/default/src/tests/utils/spawner.util.ts +0 -617
|
@@ -2,44 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
import prisma from '@/config/db-config'
|
|
4
4
|
import { locatorGroupSchema } from '@/constants/form-opts/locator-group-form-opts'
|
|
5
|
+
import { automationProjectionService } from '@/lib/automation/projection-service'
|
|
6
|
+
import { getLocatorGroupFilePath, readLocatorGroupFile } from '@/lib/locator-group-file-utils'
|
|
5
7
|
import { ActionResponse } from '@/types/form/actionHandler'
|
|
6
8
|
import { revalidatePath } from 'next/cache'
|
|
7
9
|
import { z } from 'zod'
|
|
8
10
|
import { Prisma } from '@prisma/client'
|
|
9
|
-
|
|
10
|
-
createOrUpdateLocatorGroupFile,
|
|
11
|
-
deleteLocatorGroupFile,
|
|
12
|
-
renameLocatorGroupFile,
|
|
13
|
-
moveLocatorGroupFile,
|
|
14
|
-
createEmptyLocatorGroupFile,
|
|
15
|
-
readLocatorGroupFile,
|
|
16
|
-
updateLocatorMapFile,
|
|
17
|
-
removeLocatorMapEntry,
|
|
18
|
-
} from '@/lib/locator-group-file-utils'
|
|
19
|
-
|
|
20
|
-
// Common include pattern for locator groups
|
|
11
|
+
|
|
21
12
|
const locatorGroupInclude = {
|
|
22
13
|
module: {
|
|
23
14
|
select: { name: true },
|
|
24
15
|
},
|
|
25
16
|
} as const
|
|
26
17
|
|
|
27
|
-
/**
|
|
28
|
-
* Check if a locator group name already exists
|
|
29
|
-
*/
|
|
30
18
|
async function checkUniqueName(name: string, excludeId?: string): Promise<boolean> {
|
|
31
19
|
const existing = await prisma.locatorGroup.findFirst({
|
|
32
20
|
where: {
|
|
33
|
-
name
|
|
21
|
+
name,
|
|
34
22
|
...(excludeId && { id: { not: excludeId } }),
|
|
35
23
|
},
|
|
36
24
|
})
|
|
37
25
|
return !!existing
|
|
38
26
|
}
|
|
39
27
|
|
|
40
|
-
/**
|
|
41
|
-
* Get all locator groups
|
|
42
|
-
*/
|
|
43
28
|
export async function getAllLocatorGroupsAction(): Promise<ActionResponse> {
|
|
44
29
|
try {
|
|
45
30
|
const locatorGroups = await prisma.locatorGroup.findMany({
|
|
@@ -58,9 +43,6 @@ export async function getAllLocatorGroupsAction(): Promise<ActionResponse> {
|
|
|
58
43
|
}
|
|
59
44
|
}
|
|
60
45
|
|
|
61
|
-
/**
|
|
62
|
-
* Get a locator group by ID
|
|
63
|
-
*/
|
|
64
46
|
export async function getLocatorGroupByIdAction(id: string): Promise<ActionResponse> {
|
|
65
47
|
try {
|
|
66
48
|
const locatorGroup = await prisma.locatorGroup.findUnique({
|
|
@@ -80,15 +62,11 @@ export async function getLocatorGroupByIdAction(id: string): Promise<ActionRespo
|
|
|
80
62
|
}
|
|
81
63
|
}
|
|
82
64
|
|
|
83
|
-
/**
|
|
84
|
-
* Create a new locator group
|
|
85
|
-
*/
|
|
86
65
|
export async function createLocatorGroupAction(
|
|
87
66
|
_prev: unknown,
|
|
88
67
|
value: z.infer<typeof locatorGroupSchema>,
|
|
89
68
|
): Promise<ActionResponse> {
|
|
90
69
|
try {
|
|
91
|
-
// Check if name already exists
|
|
92
70
|
const nameExists = await checkUniqueName(value.name)
|
|
93
71
|
if (nameExists) {
|
|
94
72
|
return {
|
|
@@ -96,6 +74,7 @@ export async function createLocatorGroupAction(
|
|
|
96
74
|
error: 'A locator group with this name already exists. Please choose a different name.',
|
|
97
75
|
}
|
|
98
76
|
}
|
|
77
|
+
|
|
99
78
|
const locatorGroup = await prisma.locatorGroup.create({
|
|
100
79
|
data: {
|
|
101
80
|
name: value.name,
|
|
@@ -107,9 +86,8 @@ export async function createLocatorGroupAction(
|
|
|
107
86
|
},
|
|
108
87
|
})
|
|
109
88
|
|
|
110
|
-
|
|
111
|
-
await
|
|
112
|
-
await updateLocatorMapFile(value.name, value.route ?? '/')
|
|
89
|
+
await automationProjectionService.createEmptyLocatorGroup(locatorGroup.id)
|
|
90
|
+
await automationProjectionService.syncLocatorMap(value.name, value.route ?? '/')
|
|
113
91
|
|
|
114
92
|
revalidatePath('/locator-groups')
|
|
115
93
|
return {
|
|
@@ -118,7 +96,6 @@ export async function createLocatorGroupAction(
|
|
|
118
96
|
message: 'Locator group created successfully',
|
|
119
97
|
}
|
|
120
98
|
} catch (error) {
|
|
121
|
-
// Handle Prisma unique constraint error
|
|
122
99
|
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') {
|
|
123
100
|
return {
|
|
124
101
|
status: 400,
|
|
@@ -132,16 +109,12 @@ export async function createLocatorGroupAction(
|
|
|
132
109
|
}
|
|
133
110
|
}
|
|
134
111
|
|
|
135
|
-
/**
|
|
136
|
-
* Update an existing locator group
|
|
137
|
-
*/
|
|
138
112
|
export async function updateLocatorGroupAction(
|
|
139
113
|
_prev: unknown,
|
|
140
114
|
value: z.infer<typeof locatorGroupSchema>,
|
|
141
115
|
id?: string,
|
|
142
116
|
): Promise<ActionResponse> {
|
|
143
117
|
try {
|
|
144
|
-
// Get current state to detect changes
|
|
145
118
|
const currentLocatorGroup = await prisma.locatorGroup.findUnique({
|
|
146
119
|
where: { id },
|
|
147
120
|
include: { module: true },
|
|
@@ -154,7 +127,6 @@ export async function updateLocatorGroupAction(
|
|
|
154
127
|
}
|
|
155
128
|
}
|
|
156
129
|
|
|
157
|
-
// Check if name already exists (only if name is changing)
|
|
158
130
|
if (currentLocatorGroup.name !== value.name) {
|
|
159
131
|
const nameExists = await checkUniqueName(value.name, id)
|
|
160
132
|
if (nameExists) {
|
|
@@ -165,7 +137,8 @@ export async function updateLocatorGroupAction(
|
|
|
165
137
|
}
|
|
166
138
|
}
|
|
167
139
|
|
|
168
|
-
|
|
140
|
+
const previousFilePath = await getLocatorGroupFilePath(id!)
|
|
141
|
+
|
|
169
142
|
const updatedLocatorGroup = await prisma.locatorGroup.update({
|
|
170
143
|
where: { id },
|
|
171
144
|
data: {
|
|
@@ -179,28 +152,27 @@ export async function updateLocatorGroupAction(
|
|
|
179
152
|
include: locatorGroupInclude,
|
|
180
153
|
})
|
|
181
154
|
|
|
182
|
-
// Handle file operations based on changes
|
|
183
155
|
const nameChanged = currentLocatorGroup.name !== value.name
|
|
184
156
|
const moduleChanged = currentLocatorGroup.moduleId !== value.moduleId
|
|
185
157
|
const routeChanged = currentLocatorGroup.route !== value.route
|
|
186
158
|
|
|
187
|
-
if (
|
|
188
|
-
|
|
189
|
-
await moveLocatorGroupFile(id!)
|
|
159
|
+
if (moduleChanged) {
|
|
160
|
+
await automationProjectionService.moveLocatorGroup(id!, previousFilePath ?? undefined)
|
|
190
161
|
} else if (nameChanged) {
|
|
191
|
-
|
|
192
|
-
await renameLocatorGroupFile(id!, value.name, currentLocatorGroup.name)
|
|
193
|
-
} else if (moduleChanged) {
|
|
194
|
-
// Only module changed - move the file
|
|
195
|
-
await moveLocatorGroupFile(id!)
|
|
162
|
+
await automationProjectionService.renameLocatorGroup(id!, value.name, currentLocatorGroup.name)
|
|
196
163
|
} else {
|
|
197
|
-
|
|
198
|
-
await createOrUpdateLocatorGroupFile(id!)
|
|
164
|
+
await automationProjectionService.syncLocatorGroup(id!)
|
|
199
165
|
}
|
|
200
166
|
|
|
201
167
|
if (routeChanged || nameChanged) {
|
|
202
|
-
await
|
|
168
|
+
await automationProjectionService.syncLocatorMap(
|
|
169
|
+
currentLocatorGroup.route,
|
|
170
|
+
value.route ?? '/',
|
|
171
|
+
currentLocatorGroup.name,
|
|
172
|
+
value.name,
|
|
173
|
+
)
|
|
203
174
|
}
|
|
175
|
+
|
|
204
176
|
revalidatePath('/locator-groups')
|
|
205
177
|
return {
|
|
206
178
|
status: 200,
|
|
@@ -208,7 +180,6 @@ export async function updateLocatorGroupAction(
|
|
|
208
180
|
message: 'Locator group updated successfully',
|
|
209
181
|
}
|
|
210
182
|
} catch (error) {
|
|
211
|
-
// Handle Prisma unique constraint error
|
|
212
183
|
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') {
|
|
213
184
|
return {
|
|
214
185
|
status: 400,
|
|
@@ -222,26 +193,16 @@ export async function updateLocatorGroupAction(
|
|
|
222
193
|
}
|
|
223
194
|
}
|
|
224
195
|
|
|
225
|
-
/**
|
|
226
|
-
* Delete locator groups
|
|
227
|
-
*/
|
|
228
196
|
export async function deleteLocatorGroupAction(ids: string[]): Promise<ActionResponse> {
|
|
229
197
|
try {
|
|
230
|
-
// Get locator group names before deletion for locator map cleanup
|
|
231
198
|
const locatorGroupsToDelete = await prisma.locatorGroup.findMany({
|
|
232
199
|
where: { id: { in: ids } },
|
|
233
200
|
select: { name: true },
|
|
234
201
|
})
|
|
235
202
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// Remove entries from locator map
|
|
239
|
-
await removeLocatorMapEntry(locatorGroupNames)
|
|
203
|
+
await automationProjectionService.deleteLocatorMapEntries(locatorGroupsToDelete.map(group => group.name))
|
|
204
|
+
await Promise.all(ids.map(id => automationProjectionService.deleteLocatorGroup(id)))
|
|
240
205
|
|
|
241
|
-
// Delete JSON files first
|
|
242
|
-
await Promise.all(ids.map(id => deleteLocatorGroupFile(id)))
|
|
243
|
-
|
|
244
|
-
// Delete the locator groups (locators will be deleted via cascade)
|
|
245
206
|
await prisma.locatorGroup.deleteMany({
|
|
246
207
|
where: { id: { in: ids } },
|
|
247
208
|
})
|
|
@@ -260,9 +221,6 @@ export async function deleteLocatorGroupAction(ids: string[]): Promise<ActionRes
|
|
|
260
221
|
}
|
|
261
222
|
}
|
|
262
223
|
|
|
263
|
-
/**
|
|
264
|
-
* Get the content of a specific locator group file
|
|
265
|
-
*/
|
|
266
224
|
export async function getLocatorGroupFileContentAction(locatorGroupId: string): Promise<ActionResponse> {
|
|
267
225
|
try {
|
|
268
226
|
const fileData = await readLocatorGroupFile(locatorGroupId)
|
|
@@ -286,9 +244,6 @@ export async function getLocatorGroupFileContentAction(locatorGroupId: string):
|
|
|
286
244
|
}
|
|
287
245
|
}
|
|
288
246
|
|
|
289
|
-
/**
|
|
290
|
-
* Check if a locator group name is unique
|
|
291
|
-
*/
|
|
292
247
|
export async function checkLocatorGroupNameUniqueAction(name: string, excludeId?: string): Promise<ActionResponse> {
|
|
293
248
|
try {
|
|
294
249
|
const nameExists = await checkUniqueName(name, excludeId)
|
|
@@ -304,23 +259,14 @@ export async function checkLocatorGroupNameUniqueAction(name: string, excludeId?
|
|
|
304
259
|
}
|
|
305
260
|
}
|
|
306
261
|
|
|
307
|
-
/**
|
|
308
|
-
* Regenerate all locator group files from database
|
|
309
|
-
*/
|
|
310
262
|
export async function regenerateAllLocatorGroupFilesAction(): Promise<ActionResponse> {
|
|
311
263
|
try {
|
|
312
264
|
const locatorGroups = await prisma.locatorGroup.findMany({
|
|
313
|
-
|
|
314
|
-
module: true,
|
|
315
|
-
locators: {
|
|
316
|
-
select: { name: true, value: true },
|
|
317
|
-
},
|
|
318
|
-
},
|
|
265
|
+
select: { id: true },
|
|
319
266
|
})
|
|
320
267
|
|
|
321
|
-
// Process all files in parallel for better performance
|
|
322
268
|
const results = await Promise.allSettled(
|
|
323
|
-
locatorGroups.map(locatorGroup =>
|
|
269
|
+
locatorGroups.map(locatorGroup => automationProjectionService.syncLocatorGroup(locatorGroup.id)),
|
|
324
270
|
)
|
|
325
271
|
|
|
326
272
|
const successCount = results.filter(result => result.status === 'fulfilled' && result.value).length
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import prisma from '@/config/db-config'
|
|
4
4
|
import { moduleSchema, ROOT_MODULE_UUID } from '@/constants/form-opts/module-form-opts'
|
|
5
|
+
import { automationProjectionService } from '@/lib/automation/projection-service'
|
|
5
6
|
import { ActionResponse } from '@/types/form/actionHandler'
|
|
6
7
|
import { revalidatePath } from 'next/cache'
|
|
7
8
|
import { z } from 'zod'
|
|
@@ -36,6 +37,7 @@ export async function deleteModuleAction(ids: string[]): Promise<ActionResponse>
|
|
|
36
37
|
id: { in: ids },
|
|
37
38
|
},
|
|
38
39
|
})
|
|
40
|
+
await automationProjectionService.regenerateAllPathDependentArtifacts()
|
|
39
41
|
revalidatePath('/modules')
|
|
40
42
|
return {
|
|
41
43
|
status: 200,
|
|
@@ -53,7 +55,6 @@ export async function createModuleAction(_prev: unknown, value: z.infer<typeof m
|
|
|
53
55
|
try {
|
|
54
56
|
moduleSchema.parse(value)
|
|
55
57
|
|
|
56
|
-
// Convert the special root UUID to null for database storage
|
|
57
58
|
const moduleData = {
|
|
58
59
|
...value,
|
|
59
60
|
parentId: value.parentId === ROOT_MODULE_UUID ? null : value.parentId,
|
|
@@ -62,6 +63,7 @@ export async function createModuleAction(_prev: unknown, value: z.infer<typeof m
|
|
|
62
63
|
const newModule = await prisma.module.create({
|
|
63
64
|
data: moduleData,
|
|
64
65
|
})
|
|
66
|
+
await automationProjectionService.regenerateAllPathDependentArtifacts()
|
|
65
67
|
revalidatePath('/modules')
|
|
66
68
|
return {
|
|
67
69
|
status: 200,
|
|
@@ -108,7 +110,6 @@ export async function updateModuleAction(
|
|
|
108
110
|
try {
|
|
109
111
|
moduleSchema.parse(value)
|
|
110
112
|
|
|
111
|
-
// Convert the special root UUID to null for database storage
|
|
112
113
|
const moduleData = {
|
|
113
114
|
...value,
|
|
114
115
|
parentId: value.parentId === ROOT_MODULE_UUID ? null : value.parentId,
|
|
@@ -118,6 +119,7 @@ export async function updateModuleAction(
|
|
|
118
119
|
where: { id },
|
|
119
120
|
data: moduleData,
|
|
120
121
|
})
|
|
122
|
+
await automationProjectionService.regenerateAllPathDependentArtifacts()
|
|
121
123
|
revalidatePath('/modules')
|
|
122
124
|
return {
|
|
123
125
|
status: 200,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import prisma from '@/config/db-config'
|
|
4
4
|
import { tagSchema } from '@/constants/form-opts/tag-form-opts'
|
|
5
|
+
import { automationProjectionService } from '@/lib/automation/projection-service'
|
|
5
6
|
import { ActionResponse } from '@/types/form/actionHandler'
|
|
6
7
|
import { TagType } from '@prisma/client'
|
|
7
8
|
import { revalidatePath } from 'next/cache'
|
|
@@ -29,7 +30,7 @@ export async function getAllTagsAction(): Promise<ActionResponse> {
|
|
|
29
30
|
export async function deleteTagAction(ids: string[]): Promise<ActionResponse> {
|
|
30
31
|
try {
|
|
31
32
|
await prisma.tag.deleteMany({ where: { id: { in: ids } } })
|
|
32
|
-
|
|
33
|
+
await automationProjectionService.regenerateAllFeatures()
|
|
33
34
|
revalidatePath('/tags')
|
|
34
35
|
|
|
35
36
|
return {
|
|
@@ -50,6 +51,7 @@ export async function createTagAction(_prev: unknown, value: z.infer<typeof tagS
|
|
|
50
51
|
data: value,
|
|
51
52
|
})
|
|
52
53
|
|
|
54
|
+
await automationProjectionService.regenerateAllFeatures()
|
|
53
55
|
revalidatePath('/tags')
|
|
54
56
|
|
|
55
57
|
return {
|
|
@@ -88,6 +90,7 @@ export async function updateTagAction(
|
|
|
88
90
|
try {
|
|
89
91
|
const updatedTag = await prisma.tag.update({ where: { id }, data: value })
|
|
90
92
|
|
|
93
|
+
await automationProjectionService.regenerateAllFeatures()
|
|
91
94
|
revalidatePath('/tags')
|
|
92
95
|
|
|
93
96
|
return {
|
|
@@ -2,37 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import prisma from '@/config/db-config'
|
|
4
4
|
import { templateStepSchema } from '@/constants/form-opts/template-test-step-form-opts'
|
|
5
|
+
import { automationProjectionService } from '@/lib/automation/projection-service'
|
|
5
6
|
import { ActionResponse } from '@/types/form/actionHandler'
|
|
6
7
|
import { StepParameterType, TemplateStepIcon, TemplateStepType } from '@prisma/client'
|
|
7
8
|
import { revalidatePath } from 'next/cache'
|
|
8
9
|
import { z } from 'zod'
|
|
9
|
-
import {
|
|
10
|
-
addTemplateStepToFile,
|
|
11
|
-
removeTemplateStepFromFile,
|
|
12
|
-
updateTemplateStepInFile,
|
|
13
|
-
} from '@/lib/utils/template-step-file-manager-intelligent'
|
|
14
|
-
|
|
15
|
-
// TemplateStepGroupType helper - will be available from @prisma/client after migration
|
|
16
|
-
type TemplateStepGroupType = 'ACTION' | 'VALIDATION'
|
|
17
|
-
|
|
18
|
-
// Type helper to safely extract type from Prisma templateStepGroup records
|
|
19
|
-
type TemplateStepGroupWithType = {
|
|
20
|
-
id: string
|
|
21
|
-
name: string
|
|
22
|
-
description: string | null
|
|
23
|
-
type?: TemplateStepGroupType
|
|
24
|
-
createdAt: Date
|
|
25
|
-
updatedAt: Date
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getGroupTypeFromRelation(group: unknown): TemplateStepGroupType {
|
|
29
|
-
const groupWithType = group as TemplateStepGroupWithType
|
|
30
|
-
const type = groupWithType.type
|
|
31
|
-
if (type === 'VALIDATION' || type === 'ACTION') {
|
|
32
|
-
return type
|
|
33
|
-
}
|
|
34
|
-
return 'ACTION' // default
|
|
35
|
-
}
|
|
36
10
|
|
|
37
11
|
export async function getAllTemplateStepsAction(): Promise<ActionResponse> {
|
|
38
12
|
try {
|
|
@@ -61,19 +35,14 @@ export async function getAllTemplateStepsAction(): Promise<ActionResponse> {
|
|
|
61
35
|
|
|
62
36
|
export async function deleteTemplateStepAction(templateStepIds: string[]): Promise<ActionResponse> {
|
|
63
37
|
try {
|
|
64
|
-
// Get the template steps with their group info before deletion
|
|
65
38
|
const stepsToDelete = await prisma.templateStep.findMany({
|
|
66
39
|
where: { id: { in: templateStepIds } },
|
|
67
|
-
|
|
68
|
-
|
|
40
|
+
select: {
|
|
41
|
+
templateStepGroupId: true,
|
|
69
42
|
},
|
|
70
43
|
})
|
|
71
44
|
|
|
72
|
-
// Delete in order: child records first. TemplateTestCaseStepParameter and
|
|
73
|
-
// TestCaseStepParameter must be removed before TemplateTestCaseStep/TestCaseStep
|
|
74
|
-
// (which are cascade-deleted from TemplateStep).
|
|
75
45
|
await prisma.$transaction(async tx => {
|
|
76
|
-
// Delete TemplateTestCaseStepParameter records first
|
|
77
46
|
await tx.templateTestCaseStepParameter.deleteMany({
|
|
78
47
|
where: {
|
|
79
48
|
templateTestCaseStep: {
|
|
@@ -82,7 +51,6 @@ export async function deleteTemplateStepAction(templateStepIds: string[]): Promi
|
|
|
82
51
|
},
|
|
83
52
|
})
|
|
84
53
|
|
|
85
|
-
// Delete TestCaseStepParameter records
|
|
86
54
|
await tx.testCaseStepParameter.deleteMany({
|
|
87
55
|
where: {
|
|
88
56
|
testCaseStep: {
|
|
@@ -91,14 +59,12 @@ export async function deleteTemplateStepAction(templateStepIds: string[]): Promi
|
|
|
91
59
|
},
|
|
92
60
|
})
|
|
93
61
|
|
|
94
|
-
// Delete the template step parameters
|
|
95
62
|
await tx.templateStepParameter.deleteMany({
|
|
96
63
|
where: {
|
|
97
64
|
templateStepId: { in: templateStepIds },
|
|
98
65
|
},
|
|
99
66
|
})
|
|
100
67
|
|
|
101
|
-
// Delete the template steps (this will cascade delete TemplateTestCaseStep and TestCaseStep)
|
|
102
68
|
await tx.templateStep.deleteMany({
|
|
103
69
|
where: {
|
|
104
70
|
id: { in: templateStepIds },
|
|
@@ -106,18 +72,8 @@ export async function deleteTemplateStepAction(templateStepIds: string[]): Promi
|
|
|
106
72
|
})
|
|
107
73
|
})
|
|
108
74
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (step.templateStepGroup) {
|
|
112
|
-
try {
|
|
113
|
-
const groupType = getGroupTypeFromRelation(step.templateStepGroup)
|
|
114
|
-
await removeTemplateStepFromFile(step.templateStepGroup.name, step, groupType)
|
|
115
|
-
} catch (fileError) {
|
|
116
|
-
console.error(`Failed to remove step from file for group "${step.templateStepGroup.name}":`, fileError)
|
|
117
|
-
// Don't fail the entire operation if file update fails
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
75
|
+
const affectedGroupIds = [...new Set(stepsToDelete.map(step => step.templateStepGroupId))]
|
|
76
|
+
await Promise.all(affectedGroupIds.map(groupId => automationProjectionService.syncTemplateStepGroup(groupId)))
|
|
121
77
|
|
|
122
78
|
revalidatePath('/template-steps')
|
|
123
79
|
return {
|
|
@@ -137,7 +93,6 @@ export async function createTemplateStepAction(
|
|
|
137
93
|
value: z.infer<typeof templateStepSchema>,
|
|
138
94
|
): Promise<ActionResponse> {
|
|
139
95
|
try {
|
|
140
|
-
// First, try to create the template step
|
|
141
96
|
const newTemplateStep = await prisma.templateStep.create({
|
|
142
97
|
data: {
|
|
143
98
|
name: value.name,
|
|
@@ -159,21 +114,9 @@ export async function createTemplateStepAction(
|
|
|
159
114
|
},
|
|
160
115
|
},
|
|
161
116
|
},
|
|
162
|
-
include: {
|
|
163
|
-
templateStepGroup: true,
|
|
164
|
-
},
|
|
165
117
|
})
|
|
166
118
|
|
|
167
|
-
|
|
168
|
-
if (newTemplateStep.templateStepGroup) {
|
|
169
|
-
try {
|
|
170
|
-
const groupType = getGroupTypeFromRelation(newTemplateStep.templateStepGroup)
|
|
171
|
-
await addTemplateStepToFile(newTemplateStep.templateStepGroup.name, newTemplateStep, groupType)
|
|
172
|
-
} catch (fileError) {
|
|
173
|
-
console.error(`Failed to add step to file after creating template step:`, fileError)
|
|
174
|
-
// Don't fail the entire operation if file update fails
|
|
175
|
-
}
|
|
176
|
-
}
|
|
119
|
+
await automationProjectionService.syncTemplateStepGroup(newTemplateStep.templateStepGroupId)
|
|
177
120
|
|
|
178
121
|
revalidatePath('/template-steps')
|
|
179
122
|
|
|
@@ -203,11 +146,10 @@ export async function updateTemplateStepAction(
|
|
|
203
146
|
}
|
|
204
147
|
}
|
|
205
148
|
|
|
206
|
-
// Get the current template step to check if group changed
|
|
207
149
|
const currentStep = await prisma.templateStep.findUnique({
|
|
208
150
|
where: { id },
|
|
209
|
-
|
|
210
|
-
|
|
151
|
+
select: {
|
|
152
|
+
templateStepGroupId: true,
|
|
211
153
|
},
|
|
212
154
|
})
|
|
213
155
|
|
|
@@ -218,10 +160,6 @@ export async function updateTemplateStepAction(
|
|
|
218
160
|
}
|
|
219
161
|
}
|
|
220
162
|
|
|
221
|
-
// Check if the group changed
|
|
222
|
-
const groupChanged = currentStep.templateStepGroupId !== value.templateStepGroupId
|
|
223
|
-
|
|
224
|
-
// Update the template step
|
|
225
163
|
const updatedTemplateStep = await prisma.templateStep.update({
|
|
226
164
|
where: { id },
|
|
227
165
|
data: {
|
|
@@ -247,39 +185,10 @@ export async function updateTemplateStepAction(
|
|
|
247
185
|
},
|
|
248
186
|
},
|
|
249
187
|
},
|
|
250
|
-
include: {
|
|
251
|
-
templateStepGroup: true,
|
|
252
|
-
},
|
|
253
188
|
})
|
|
254
189
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (groupChanged) {
|
|
258
|
-
// If group changed, remove from old group and add to new group
|
|
259
|
-
if (currentStep.templateStepGroup) {
|
|
260
|
-
const oldGroupType = getGroupTypeFromRelation(currentStep.templateStepGroup)
|
|
261
|
-
await removeTemplateStepFromFile(currentStep.templateStepGroup.name, currentStep, oldGroupType)
|
|
262
|
-
}
|
|
263
|
-
if (updatedTemplateStep.templateStepGroup) {
|
|
264
|
-
const newGroupType = getGroupTypeFromRelation(updatedTemplateStep.templateStepGroup)
|
|
265
|
-
await addTemplateStepToFile(updatedTemplateStep.templateStepGroup.name, updatedTemplateStep, newGroupType)
|
|
266
|
-
}
|
|
267
|
-
} else {
|
|
268
|
-
// If group didn't change, just update the step in the current group
|
|
269
|
-
if (updatedTemplateStep.templateStepGroup) {
|
|
270
|
-
const groupType = getGroupTypeFromRelation(updatedTemplateStep.templateStepGroup)
|
|
271
|
-
await updateTemplateStepInFile(
|
|
272
|
-
updatedTemplateStep.templateStepGroup.name,
|
|
273
|
-
updatedTemplateStep,
|
|
274
|
-
groupType,
|
|
275
|
-
currentStep,
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
} catch (fileError) {
|
|
280
|
-
console.error(`Failed to update file after updating template step:`, fileError)
|
|
281
|
-
// Don't fail the entire operation if file update fails
|
|
282
|
-
}
|
|
190
|
+
const affectedGroupIds = new Set([currentStep.templateStepGroupId, updatedTemplateStep.templateStepGroupId])
|
|
191
|
+
await Promise.all(Array.from(affectedGroupIds).map(groupId => automationProjectionService.syncTemplateStepGroup(groupId)))
|
|
283
192
|
|
|
284
193
|
revalidatePath('/template-steps')
|
|
285
194
|
return {
|