Skip to content

Commit 5b1f05d

Browse files
committed
updated branch
2 parents e3a5139 + 7f6cfe9 commit 5b1f05d

File tree

7 files changed

+393
-177
lines changed

7 files changed

+393
-177
lines changed

src/modules/common/enum/testflow.enum.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ export enum RequestDataTypeEnum {
3232
export interface EmailData {
3333
userName: string;
3434
scheduleName: string;
35-
scheduleLastestRun: Date;
35+
scheduleLastestRun: string;
3636
scheduleRunResult: string;
3737
scheduleRunPassedCount: number;
3838
scheduleRunFailedCount: number;
3939
scheduleRunTotalRequest: number;
40-
scheduleRunPassPercentage: number;
40+
scheduleRunPassPercentage: string;
4141
scheduleTotalTime: string | number;
4242
scheduleRunEnvName: string;
4343
isSuccess: boolean;
@@ -61,6 +61,7 @@ export interface DailyConfig {
6161

6262
export interface HourlyConfig {
6363
type: RunCycleEnum.HOURLY;
64+
executeAt: Date;
6465
intervalHours: number;
6566
startTime?: {
6667
hour: number;

src/modules/views/testflowScheduleRunEmail.handlebars

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@
116116
{{else if isFailed}}
117117
❌️ <span class="status" style=""> Failed</span>
118118
{{else if isPartial}}
119-
⚠️ <span class="status" style=""> Partially Failed</span><span>({{scheduleRunPassedCount}}/{{scheduleRunTotalRequest}} Requests Failed)</span>
119+
⚠️ <span class="status" style=""> Partially Failed</span><span>({{scheduleRunFailedCount}}/{{scheduleRunTotalRequest}} Requests Failed)</span>
120120
{{/if}}
121121
</p>
122122
</div>
@@ -126,7 +126,7 @@
126126
<table style="margin-bottom: 20px;" class="email-text-style" width="100%" cellpadding="0" cellspacing="0" border="0">
127127
<tr>
128128
<td style="border-bottom:1px solid #b0b8c1" colspan="2">
129-
<h1 style="margin-top:0; margin-bottom: -6px; font-size: 20px; font-weight: 600;">Run Summary</h1>
129+
<h1 style="margin-top:0; font-size: 20px;font-weight: 600;margin-bottom: 15px;">Run Summary</h1>
130130
</td>
131131
</tr>
132132
<tr>
@@ -143,7 +143,7 @@
143143
</tr>
144144
<tr>
145145
<td style="border-bottom:1px solid #e0e0e0;">Pass Rate</td>
146-
<td style="text-align:start; padding:12px 160px 12px 96px; border-bottom:1px solid #e0e0e0;">{{scheduleRunPassPercentage}}</td>
146+
<td style="text-align:start; padding:12px 160px 12px 96px; border-bottom:1px solid #e0e0e0;">{{scheduleRunPassPercentage}}%</td>
147147
</tr>
148148
<tr>
149149
<td style="border-bottom:1px solid #e0e0e0;">Total Duration</td>
@@ -178,11 +178,21 @@
178178
<div>
179179
<table cellspacing="0" cellpadding="0" border="0">
180180
<tr>
181-
<td style="border-radius: 6px; background-color: #316CF6; padding: 6px 12px; min-height: 36px; cursor:pointer;">
182-
<a href="https://web.sparrowapp.dev/app/collections" class="email-text-style" style="display: inline-block; text-decoration: none;">
183-
View Report
184-
</a>
185-
</td>
181+
<td align="left" valign="middle" style="">
182+
<div>
183+
<div>
184+
<table cellspacing="0" cellpadding="0" border="0">
185+
<tr>
186+
<td style="border-radius: 6px; background-color: #316CF6; padding: 6px 12px; min-height: 36px;">
187+
<a href="https://web.sparrowapp.dev/app/collections" class="email-text-style" style="display: inline-block; color: #ffffff; text-decoration: none;">
188+
View Report
189+
</a>
190+
</td>
191+
</tr>
192+
</table>
193+
</div>
194+
</div>
195+
</td>
186196
</tr>
187197
</table>
188198
</div>

src/modules/workspace/controllers/testflow.controller.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export class TestflowController {
109109
* @description This will retrieve a specific Testflow using its ID,
110110
* returning the Testflow object if found.
111111
*/
112-
@Get("testflow/:testflowId")
112+
@Get(":workspaceId/testflow/:testflowId")
113113
@ApiOperation({
114114
summary: "Get Individual Testflow",
115115
description: "This will get individual testflow of a workspace",
@@ -121,10 +121,13 @@ export class TestflowController {
121121
})
122122
@ApiResponse({ status: 400, description: "Fetch Testflow Request Failed" })
123123
async getTestflow(
124+
@Param("workspaceId") workspaceId: string,
124125
@Param("testflowId") testflowId: string,
125126
@Res() res: FastifyReply,
127+
@Req() request: ExtendedFastifyRequest,
126128
) {
127-
const testflow = await this.testflowService.getTestflow(testflowId);
129+
const user = request.user;
130+
const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id);
128131
const responseData = new ApiResponseService(
129132
"Success",
130133
HttpStatusCode.OK,
@@ -321,8 +324,8 @@ export class TestflowController {
321324
const response = await this.testflowService.createTestflowSchedular(
322325
createTestflowSchedularDto,
323326
user,
324-
);
325-
const testflow = await this.testflowService.getTestflow(createTestflowSchedularDto.testflowId);
327+
);
328+
const testflow = await this.testflowService.getTestflow(createTestflowSchedularDto.workspaceId, createTestflowSchedularDto.testflowId, user._id);
326329
const result = {
327330
testflow,
328331
schedule:response
@@ -359,7 +362,7 @@ export class TestflowController {
359362
workspaceId,
360363
user,
361364
);
362-
const testflow = await this.testflowService.getTestflow(testflowId);
365+
const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id);
363366
const responseData = new ApiResponseService(
364367
"Success",
365368
HttpStatusCode.OK,
@@ -390,7 +393,7 @@ export class TestflowController {
390393
workspaceId,
391394
user,
392395
);
393-
const testflow = await this.testflowService.getTestflow(testflowId);
396+
const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id);
394397
const responseData = new ApiResponseService(
395398
"Success",
396399
HttpStatusCode.OK,
@@ -421,7 +424,7 @@ export class TestflowController {
421424
workspaceId,
422425
user,
423426
);
424-
const testflow = await this.testflowService.getTestflow(testflowId);
427+
const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id);
425428
const responseData = new ApiResponseService(
426429
"Success",
427430
HttpStatusCode.OK,
@@ -448,7 +451,7 @@ export class TestflowController {
448451
) {
449452
const user = request.user;
450453
await this.testflowService.deleteScheduleRunHistory(workspaceId, testflowId, scheduleId, runHistoryId, user);
451-
const testflow = await this.testflowService.getTestflow(testflowId);
454+
const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id);
452455
const responseData = new ApiResponseService(
453456
"Success",
454457
HttpStatusCode.OK,

src/modules/workspace/repositories/testflow.repository.ts

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ export class TestflowRepository {
206206
schedularId: string,
207207
runHistoryItem: TestFlowSchedularRunHistory,
208208
): Promise<UpdateResult> {
209-
const now = new Date();
209+
const nowUtc = new Date().toISOString();
210210
if (!testflowId || !schedularId) {
211211
throw new Error("Both testflowId and schedularId are required");
212212
}
@@ -215,8 +215,8 @@ export class TestflowRepository {
215215
{
216216
$inc: { "schedules.$[elem].executedCount": 1 },
217217
$set: {
218-
"schedules.$[elem].lastExecuted": now,
219-
updatedAt: now,
218+
"schedules.$[elem].lastExecuted": nowUtc,
219+
updatedAt: nowUtc,
220220
},
221221
$push: {
222222
"schedules.$[elem].schedularRunHistory": {
@@ -231,34 +231,65 @@ export class TestflowRepository {
231231
);
232232
}
233233

234-
/**
234+
/**
235+
* Edit a schedular execution (run history item) in a testflow's schedule.
236+
* @param {string} testflowId - The testflow document ID.
237+
* @param {string} schedularId - The schedule ID.
238+
* @param {Partial<TestFlowSchedularRunHistory>} updatedRunHistory - The updated fields for the run history item.
239+
* @returns {Promise<UpdateResult>} - The result of the update operation.
240+
*/
241+
async editSchedularExecution(
242+
testflowId: string,
243+
schedularId: string,
244+
updatedRunHistory: Partial<TestFlowSchedularRunHistory>,
245+
): Promise<UpdateResult> {
246+
if (!testflowId || !schedularId || !updatedRunHistory.id) {
247+
throw new Error("testflowId, schedularId, and runHistoryId are required");
248+
}
249+
// Build the update object for only the provided fields
250+
const setObj: Record<string, any> = {};
251+
for (const [key, value] of Object.entries(updatedRunHistory)) {
252+
setObj[`schedules.$[elem].schedularRunHistory.$[run].${key}`] = value;
253+
}
254+
setObj["updatedAt"] = new Date();
255+
return this.db.collection(Collections.TESTFLOW).updateOne(
256+
{ _id: new ObjectId(testflowId) },
257+
{ $set: setObj },
258+
{
259+
arrayFilters: [
260+
{ "elem.id": schedularId },
261+
{ "run.id": updatedRunHistory.id },
262+
],
263+
},
264+
);
265+
}
266+
267+
/**
235268
* Edit a schedular execution (run history item) in a testflow's schedule.
236269
* @param {string} testflowId - The testflow document ID.
237270
* @param {string} schedularId - The schedule ID.
238-
* @param {Partial<TestFlowSchedularRunHistory>} updatedRunHistory - The updated fields for the run history item.
271+
* @param {Partial<TestFlowSchedular>} updatedSchedular - The updated fields for the schedule item.
239272
* @returns {Promise<UpdateResult>} - The result of the update operation.
240273
*/
241-
async editSchedularExecution(
274+
async editSchedular(
242275
testflowId: string,
243276
schedularId: string,
244-
updatedRunHistory: Partial<TestFlowSchedularRunHistory>,
277+
updatedSchedular: Partial<TestflowSchedular>,
245278
): Promise<UpdateResult> {
246-
if (!testflowId || !schedularId || !updatedRunHistory.id) {
247-
throw new Error("testflowId, schedularId, and runHistoryId are required");
279+
if (!testflowId || !schedularId) {
280+
throw new Error("testflowId and schedularId are required");
248281
}
249282
// Build the update object for only the provided fields
250283
const setObj: Record<string, any> = {};
251-
for (const [key, value] of Object.entries(updatedRunHistory)) {
252-
setObj[`schedules.$[elem].schedularRunHistory.$[run].${key}`] = value;
284+
for (const [key, value] of Object.entries(updatedSchedular)) {
285+
setObj[`schedules.$[elem].${key}`] = value;
253286
}
254-
setObj["updatedAt"] = new Date();
255287
return this.db.collection(Collections.TESTFLOW).updateOne(
256288
{ _id: new ObjectId(testflowId) },
257289
{ $set: setObj },
258290
{
259291
arrayFilters: [
260292
{ "elem.id": schedularId },
261-
{ "run.id": updatedRunHistory.id },
262293
],
263294
},
264295
);

src/modules/workspace/services/testflow-run.service.ts

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -73,33 +73,35 @@ export class TestflowRunService {
7373
testflowId:string,
7474
user?: DecodedUserObject,
7575
): Promise<any> => {
76-
// Fetch testflow and environment data
77-
const testflowDetails = await this.testflowRepository.get(testflowId);
78-
const workspaceID = await this.workspaceReposistory.get(workspaceId);
79-
const globalEnvironment = workspaceID.environments[0];
80-
const globalEnvDetails = await this.environmentReposistory.get(
81-
globalEnvironment.id.toString(),
82-
);
83-
let environmentData;
84-
if (environmentId) {
85-
environmentData =
86-
await this.environmentReposistory.get(environmentId);
87-
}
88-
const activeVariables = this.combineEnvironmentData(
89-
globalEnvDetails?.variable || [],
90-
environmentData?.variable || [],
91-
);
92-
// Build proxy URL
93-
const sparrowProxy = this.configService.get<string>("sparrowProxy.baseUrl");
94-
const proxyUrl = `${sparrowProxy}/proxy/testflow/execute`;
95-
// Prepare request body for proxy API
96-
const body = {
97-
nodes: testflowDetails.nodes || [],
98-
variables: activeVariables || [],
99-
edges: testflowDetails.edges,
100-
userId: user?._id || new ObjectId("000000000000000000000000"),
101-
};
10276
try {
77+
// Fetch testflow and environment data
78+
const testflowDetails = await this.testflowRepository.get(testflowId);
79+
const workspaceID = await this.workspaceReposistory.get(workspaceId);
80+
const globalEnvironment = workspaceID.environments[0];
81+
const globalEnvDetails = await this.environmentReposistory.get(
82+
globalEnvironment.id.toString(),
83+
);
84+
let environmentData;
85+
if (environmentId) {
86+
try{
87+
environmentData =
88+
await this.environmentReposistory.get(environmentId);
89+
}catch(err){}
90+
}
91+
const activeVariables = this.combineEnvironmentData(
92+
globalEnvDetails?.variable || [],
93+
environmentData?.variable || [],
94+
);
95+
// Build proxy URL
96+
const sparrowProxy = this.configService.get<string>("sparrowProxy.baseUrl");
97+
const proxyUrl = `${sparrowProxy}/proxy/testflow/execute`;
98+
// Prepare request body for proxy API
99+
const body = {
100+
nodes: testflowDetails.nodes || [],
101+
variables: activeVariables || [],
102+
edges: testflowDetails.edges,
103+
userId: user?._id || new ObjectId("000000000000000000000000"),
104+
};
103105
const response = await axios.post(proxyUrl, body, {
104106
headers: {
105107
"Content-Type": "application/json",
@@ -111,11 +113,18 @@ export class TestflowRunService {
111113
nodes:testflowDetails.nodes,
112114
edges:testflowDetails.edges,
113115
}
114-
// Return only history or any relevant part
115116
return finalResult;
116117
} catch (error: any) {
117-
console.error("Testflow proxy execution failed:", error.message || error);
118-
throw new Error(error?.message || "Testflow execution failed.");
118+
return {
119+
result:{
120+
history: {
121+
status: "error"
122+
}
123+
},
124+
environmentName: "",
125+
nodes: [],
126+
edges: [],
127+
}
119128
}
120129
};
121130
}

0 commit comments

Comments
 (0)