From d81c43134997c462728e85f24ec337a52fa4f53a Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Tue, 7 Oct 2025 12:52:14 +0530 Subject: [PATCH 01/27] Fix: added time zone property for decoding the user time --- src/modules/common/enum/testflow.enum.ts | 2 +- src/modules/common/models/testflow.model.ts | 6 ++++++ .../workspace/payloads/testflow.payload.ts | 5 +++++ .../workspace/services/testflow.service.ts | 21 +++++++++++++++---- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/modules/common/enum/testflow.enum.ts b/src/modules/common/enum/testflow.enum.ts index 8e6b02c13..f6bc04d5f 100644 --- a/src/modules/common/enum/testflow.enum.ts +++ b/src/modules/common/enum/testflow.enum.ts @@ -32,7 +32,7 @@ export enum RequestDataTypeEnum { export interface EmailData { userName: string; scheduleName: string; - scheduleLastestRun: Date; + scheduleLastestRun: string; scheduleRunResult: string; scheduleRunPassedCount: number; scheduleRunFailedCount: number; diff --git a/src/modules/common/models/testflow.model.ts b/src/modules/common/models/testflow.model.ts index 766915d74..5a0b4d236 100644 --- a/src/modules/common/models/testflow.model.ts +++ b/src/modules/common/models/testflow.model.ts @@ -549,6 +549,12 @@ export class TestflowSchedular { @IsOptional() schedularRunHistory?: TestFlowSchedularRunHistory[]; + + @IsString() + @ApiProperty({ required: true, example: "Asia/Kolkata" }) + @IsOptional() + timeZone:string; + @IsDate() @IsOptional() createdAt?: Date; diff --git a/src/modules/workspace/payloads/testflow.payload.ts b/src/modules/workspace/payloads/testflow.payload.ts index 3e15cc72c..15c9f20b8 100644 --- a/src/modules/workspace/payloads/testflow.payload.ts +++ b/src/modules/workspace/payloads/testflow.payload.ts @@ -181,4 +181,9 @@ export class CreateTestflowSchedularDto { @ValidateNested() @Type(() => NotificationDto) notification?: NotificationDto; + + @IsString() + @ApiProperty({ required: true, example: "Asia/Kolkata" }) + @IsOptional() + timeZone:string; } diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 3ea1426d5..bf8158f0e 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -151,11 +151,11 @@ export class TestflowService implements OnModuleInit { throw new NotFoundException("Schedule not found"); } - let environmentName = ""; + let environmentName = ""; if(updateScheduleDto?.environmentId){ const environmentData = await this.environmentReposistory.get(updateScheduleDto?.environmentId); - environmentName = environmentData?.name || ""; - } + environmentName = environmentData?.name || ""; + } // Merge update fields, ensure id is present const updatedSchedular: TestflowSchedular = { ...existingSchedular, @@ -537,6 +537,7 @@ export class TestflowService implements OnModuleInit { schedularName: jobName, executedCount: 0, lastExecuted: undefined, + timeZone: schedularData?.timeZone, createdAt: new Date(), updatedAt: new Date(), createdBy: user._id.toString(), @@ -789,7 +790,19 @@ export class TestflowService implements OnModuleInit { const emailData: EmailData = { userName: userDetails?.name, scheduleName: getSchedular.name, - scheduleLastestRun: new Date(getSchedular.lastExecuted), + scheduleLastestRun: new Date(getSchedular.lastExecuted).toLocaleString( + "en-IN", + { + year: "numeric", + month: "short", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + hour12: true, + timeZone: getSchedular.timeZone, + }, + ), scheduleRunResult: scheduleRunResult, scheduleRunPassedCount: data.successRequests, scheduleRunFailedCount: data.failedRequests, From d1b67f417464bc7800a6bc6fded27b2a54e123ff Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Tue, 7 Oct 2025 17:28:39 +0530 Subject: [PATCH 02/27] Fix: I have updated module function to handle empty testflows --- .../repositories/testflow.repository.ts | 29 ++++++--- .../workspace/services/testflow.service.ts | 62 +++++++++++-------- 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/modules/workspace/repositories/testflow.repository.ts b/src/modules/workspace/repositories/testflow.repository.ts index 8bb4f666e..310de46b0 100644 --- a/src/modules/workspace/repositories/testflow.repository.ts +++ b/src/modules/workspace/repositories/testflow.repository.ts @@ -282,13 +282,28 @@ export class TestflowRepository { } async getAll(): Promise[]> { - const data = await this.db - .collection(Collections.TESTFLOW) - .find({}) - .toArray(); - if (!data || data.length === 0) { - throw new BadRequestException("No Testflow data found"); + try { + // Check if the Testflow collection exists in the database + const collections = await this.db.listCollections().toArray(); + const testflowCollectionExists = collections.some( + (col) => col.name === Collections.TESTFLOW, + ); + if (!testflowCollectionExists) { + console.log("Testflow collection does not exist, skipping..."); + return []; // Return empty array + } + const data = await this.db + .collection(Collections.TESTFLOW) + .find({}) + .toArray(); + if (!data || data.length === 0) { + console.log("No Testflow data found"); + return []; + } + return data; + } catch (error) { + console.error("Error fetching Testflow data:", error); + return []; } - return data; } } diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 3ea1426d5..fe5ebea17 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -84,28 +84,34 @@ export class TestflowService implements OnModuleInit { async onModuleInit() { this.logger.log("Bootstrapping schedulers from DB..."); const testflows = await this.testflowRepository.getAll(); - for (const tf of testflows) { - if (!tf.schedules?.length) continue; - for (const schedule of tf.schedules) { - const runCycleConfig = this.buildRunCycleConfig( - schedule.runConfiguration, - ); - if (schedule.isActive && schedule.cronExpression) { - await this.testflowSchedulerService.addSchedulerJob( - runCycleConfig, - this.getScheduledExecutionCallback( - tf._id.toString(), - schedule.environmentId, - tf.workspaceId, - schedule.id, - ), - schedule.schedularName, - schedule.cronExpression, - schedule.id, - "UTC", + if (testflows.length > 0) { + for (const tf of testflows) { + if (!tf.schedules?.length) continue; + + for (const schedule of tf.schedules) { + const runCycleConfig = this.buildRunCycleConfig( + schedule.runConfiguration, ); + + if (schedule.isActive && schedule.cronExpression) { + await this.testflowSchedulerService.addSchedulerJob( + runCycleConfig, + this.getScheduledExecutionCallback( + tf._id.toString(), + schedule.environmentId, + tf.workspaceId, + schedule.id, + ), + schedule.schedularName, + schedule.cronExpression, + schedule.id, + "UTC", + ); + } } } + } else { + this.logger.log("No testflows found, skipping scheduler bootstrap"); } } @@ -151,11 +157,13 @@ export class TestflowService implements OnModuleInit { throw new NotFoundException("Schedule not found"); } - let environmentName = ""; - if(updateScheduleDto?.environmentId){ - const environmentData = await this.environmentReposistory.get(updateScheduleDto?.environmentId); - environmentName = environmentData?.name || ""; - } + let environmentName = ""; + if (updateScheduleDto?.environmentId) { + const environmentData = await this.environmentReposistory.get( + updateScheduleDto?.environmentId, + ); + environmentName = environmentData?.name || ""; + } // Merge update fields, ensure id is present const updatedSchedular: TestflowSchedular = { ...existingSchedular, @@ -520,8 +528,10 @@ export class TestflowService implements OnModuleInit { throw new BadRequestException("Invalid run cycle configuration"); } let environmentName = ""; - if(schedularData?.environmentId){ - const environmentData = await this.environmentReposistory.get(schedularData?.environmentId); + if (schedularData?.environmentId) { + const environmentData = await this.environmentReposistory.get( + schedularData?.environmentId, + ); environmentName = environmentData?.name || ""; } // Save scheduler details in DB From 1d834dc06918d1e16e60d6e293d76acca8ab1efb Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Tue, 7 Oct 2025 17:52:51 +0530 Subject: [PATCH 03/27] Fix: I have updated module function to handle empty testflows --- .../repositories/testflow.repository.ts | 39 ++++++++++--------- .../workspace/services/testflow.service.ts | 26 ++++++++++--- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/modules/workspace/repositories/testflow.repository.ts b/src/modules/workspace/repositories/testflow.repository.ts index 310de46b0..68b3c877a 100644 --- a/src/modules/workspace/repositories/testflow.repository.ts +++ b/src/modules/workspace/repositories/testflow.repository.ts @@ -282,28 +282,31 @@ export class TestflowRepository { } async getAll(): Promise[]> { + const data = await this.db + .collection(Collections.TESTFLOW) + .find({}) + .toArray(); + if (!data || data.length === 0) { + throw new BadRequestException("No Testflow data found"); + } + return data; + } + + async getAllCollectionNames(): Promise { try { - // Check if the Testflow collection exists in the database const collections = await this.db.listCollections().toArray(); - const testflowCollectionExists = collections.some( - (col) => col.name === Collections.TESTFLOW, - ); - if (!testflowCollectionExists) { - console.log("Testflow collection does not exist, skipping..."); - return []; // Return empty array - } - const data = await this.db - .collection(Collections.TESTFLOW) - .find({}) - .toArray(); - if (!data || data.length === 0) { - console.log("No Testflow data found"); - return []; + const collectionNames = collections.map((col) => col.name); + + if (!collectionNames || collectionNames.length === 0) { + throw new BadRequestException("No collections found in the database"); } - return data; + + return collectionNames; } catch (error) { - console.error("Error fetching Testflow data:", error); - return []; + console.error("Error fetching collection names:", error); + throw new BadRequestException( + error.message || "Failed to fetch collection names", + ); } } } diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index fe5ebea17..a42a7ce9a 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -61,6 +61,7 @@ import { Logger } from "@nestjs/common"; import { OnModuleInit } from "@nestjs/common"; import { UserRepository } from "@src/modules/identity/repositories/user.repository"; import { EnvironmentRepository } from "../repositories/environment.repository"; +import { Collections } from "@src/modules/common/enum/database.collection.enum"; /** * Testflow Service @@ -82,9 +83,24 @@ export class TestflowService implements OnModuleInit { ) {} async onModuleInit() { - this.logger.log("Bootstrapping schedulers from DB..."); - const testflows = await this.testflowRepository.getAll(); - if (testflows.length > 0) { + try { + this.logger.log("Bootstrapping schedulers from DB..."); + const collectionItems = + await this.testflowRepository.getAllCollectionNames(); + const testflowCollectionExists = collectionItems.some( + (col) => col === Collections.TESTFLOW, + ); + if (!testflowCollectionExists) { + this.logger.warn( + "Testflow collection does not exist — skipping scheduler bootstrap.", + ); + return; + } + const testflows = await this.testflowRepository.getAll(); + if (testflows.length === 0) { + this.logger.log("No testflows found — skipping scheduler bootstrap."); + return; + } for (const tf of testflows) { if (!tf.schedules?.length) continue; @@ -110,8 +126,8 @@ export class TestflowService implements OnModuleInit { } } } - } else { - this.logger.log("No testflows found, skipping scheduler bootstrap"); + } catch (error) { + this.logger.error("Error during scheduler bootstrap:", error); } } From 06f35b7420d7fe8e3634b0086394065837504d34 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Tue, 7 Oct 2025 18:11:42 +0530 Subject: [PATCH 04/27] Fix: I have updated module function to handle empty testflows --- .../repositories/testflow.repository.ts | 18 +++++++----------- .../workspace/services/testflow.service.ts | 9 +++------ 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/modules/workspace/repositories/testflow.repository.ts b/src/modules/workspace/repositories/testflow.repository.ts index 68b3c877a..f8b5045d0 100644 --- a/src/modules/workspace/repositories/testflow.repository.ts +++ b/src/modules/workspace/repositories/testflow.repository.ts @@ -292,21 +292,17 @@ export class TestflowRepository { return data; } - async getAllCollectionNames(): Promise { + async isTestflowCollectionExist(): Promise { try { const collections = await this.db.listCollections().toArray(); - const collectionNames = collections.map((col) => col.name); - - if (!collectionNames || collectionNames.length === 0) { - throw new BadRequestException("No collections found in the database"); - } + const testflowExists = collections.some( + (col) => col.name === Collections.TESTFLOW, + ); - return collectionNames; + return testflowExists; } catch (error) { - console.error("Error fetching collection names:", error); - throw new BadRequestException( - error.message || "Failed to fetch collection names", - ); + console.error("Error checking Testflow collection existence:", error); + return false; // Return false if any error occurs } } } diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index a42a7ce9a..4c3ab0f8b 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -85,12 +85,9 @@ export class TestflowService implements OnModuleInit { async onModuleInit() { try { this.logger.log("Bootstrapping schedulers from DB..."); - const collectionItems = - await this.testflowRepository.getAllCollectionNames(); - const testflowCollectionExists = collectionItems.some( - (col) => col === Collections.TESTFLOW, - ); - if (!testflowCollectionExists) { + const testflowCollection = + await this.testflowRepository.isTestflowCollectionExist(); + if (!testflowCollection) { this.logger.warn( "Testflow collection does not exist — skipping scheduler bootstrap.", ); From dda25e97f486090199e870ed19161778ae831b30 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Tue, 7 Oct 2025 18:22:11 +0530 Subject: [PATCH 05/27] Fix: I have updated module function to handle empty testflows --- .../workspace/repositories/testflow.repository.ts | 14 -------------- src/modules/workspace/services/testflow.service.ts | 8 -------- 2 files changed, 22 deletions(-) diff --git a/src/modules/workspace/repositories/testflow.repository.ts b/src/modules/workspace/repositories/testflow.repository.ts index f8b5045d0..8bb4f666e 100644 --- a/src/modules/workspace/repositories/testflow.repository.ts +++ b/src/modules/workspace/repositories/testflow.repository.ts @@ -291,18 +291,4 @@ export class TestflowRepository { } return data; } - - async isTestflowCollectionExist(): Promise { - try { - const collections = await this.db.listCollections().toArray(); - const testflowExists = collections.some( - (col) => col.name === Collections.TESTFLOW, - ); - - return testflowExists; - } catch (error) { - console.error("Error checking Testflow collection existence:", error); - return false; // Return false if any error occurs - } - } } diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 4c3ab0f8b..08ca17322 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -85,14 +85,6 @@ export class TestflowService implements OnModuleInit { async onModuleInit() { try { this.logger.log("Bootstrapping schedulers from DB..."); - const testflowCollection = - await this.testflowRepository.isTestflowCollectionExist(); - if (!testflowCollection) { - this.logger.warn( - "Testflow collection does not exist — skipping scheduler bootstrap.", - ); - return; - } const testflows = await this.testflowRepository.getAll(); if (testflows.length === 0) { this.logger.log("No testflows found — skipping scheduler bootstrap."); From 07c940e1d946e19860c462acd2e79ffc44e52df3 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Tue, 7 Oct 2025 20:13:43 +0530 Subject: [PATCH 06/27] Fix: I have resolved template issues --- src/modules/common/enum/testflow.enum.ts | 2 +- .../views/testflowScheduleRunEmail.handlebars | 26 +++++++++++++------ .../workspace/services/testflow.service.ts | 5 ++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/modules/common/enum/testflow.enum.ts b/src/modules/common/enum/testflow.enum.ts index f6bc04d5f..b1ed21226 100644 --- a/src/modules/common/enum/testflow.enum.ts +++ b/src/modules/common/enum/testflow.enum.ts @@ -37,7 +37,7 @@ export interface EmailData { scheduleRunPassedCount: number; scheduleRunFailedCount: number; scheduleRunTotalRequest: number; - scheduleRunPassPercentage: number; + scheduleRunPassPercentage: string; scheduleTotalTime: string | number; scheduleRunEnvName: string; isSuccess: boolean; diff --git a/src/modules/views/testflowScheduleRunEmail.handlebars b/src/modules/views/testflowScheduleRunEmail.handlebars index 37c613f37..49b508abe 100644 --- a/src/modules/views/testflowScheduleRunEmail.handlebars +++ b/src/modules/views/testflowScheduleRunEmail.handlebars @@ -116,7 +116,7 @@ {{else if isFailed}} ❌️ Failed {{else if isPartial}} - ⚠️ Partially Failed({{scheduleRunPassedCount}}/{{scheduleRunTotalRequest}} Requests Failed) + ⚠️ Partially Failed({{scheduleRunFailedCount}}/{{scheduleRunTotalRequest}} Requests Failed) {{/if}}

@@ -126,7 +126,7 @@ @@ -143,7 +143,7 @@ - + @@ -178,11 +178,21 @@
- +
- - +
+
+ + + + +
+ +
+
+
+
diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index bf8158f0e..bf4a8491a 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -785,8 +785,7 @@ export class TestflowService implements OnModuleInit { const userDetails = await this.userReposistory.getUserById( data.createdBy, ); - const successPercentage = - (data.successRequests / totalRequestCount) * 100; + const successPercentage = Math.round((data.successRequests / totalRequestCount) * 100 * 100) / 100; const emailData: EmailData = { userName: userDetails?.name, scheduleName: getSchedular.name, @@ -807,7 +806,7 @@ export class TestflowService implements OnModuleInit { scheduleRunPassedCount: data.successRequests, scheduleRunFailedCount: data.failedRequests, scheduleRunTotalRequest: data.successRequests + data.failedRequests, - scheduleRunPassPercentage: successPercentage, + scheduleRunPassPercentage: successPercentage.toString(), scheduleTotalTime: data.totalTime, scheduleRunEnvName: response.environmentName, isSuccess: data.successRequests === totalRequestCount, From 678361c04671b58535da09c6b82b077a3ecc448d Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Wed, 8 Oct 2025 13:37:18 +0530 Subject: [PATCH 07/27] fix: time updated according to the Utc --- src/modules/workspace/services/testflow.service.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 451afff62..ddcaaee94 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -825,19 +825,7 @@ export class TestflowService implements OnModuleInit { const emailData: EmailData = { userName: userDetails?.name, scheduleName: getSchedular.name, - scheduleLastestRun: new Date(getSchedular.lastExecuted).toLocaleString( - "en-IN", - { - year: "numeric", - month: "short", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - hour12: true, - timeZone: getSchedular.timeZone, - }, - ), + scheduleLastestRun: new Date(getSchedular.lastExecuted).toString(), scheduleRunResult: scheduleRunResult, scheduleRunPassedCount: data.successRequests, scheduleRunFailedCount: data.failedRequests, From 79f42e4930cd312cdbb596b9741f4f11249f70c8 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Wed, 8 Oct 2025 13:39:56 +0530 Subject: [PATCH 08/27] fix: time updated according to the Utc --- src/modules/common/models/testflow.model.ts | 2 +- src/modules/workspace/payloads/testflow.payload.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/common/models/testflow.model.ts b/src/modules/common/models/testflow.model.ts index 5a0b4d236..3d2882c20 100644 --- a/src/modules/common/models/testflow.model.ts +++ b/src/modules/common/models/testflow.model.ts @@ -553,7 +553,7 @@ export class TestflowSchedular { @IsString() @ApiProperty({ required: true, example: "Asia/Kolkata" }) @IsOptional() - timeZone:string; + timeZone?:string; @IsDate() @IsOptional() diff --git a/src/modules/workspace/payloads/testflow.payload.ts b/src/modules/workspace/payloads/testflow.payload.ts index 15c9f20b8..4ef0caa4c 100644 --- a/src/modules/workspace/payloads/testflow.payload.ts +++ b/src/modules/workspace/payloads/testflow.payload.ts @@ -185,5 +185,5 @@ export class CreateTestflowSchedularDto { @IsString() @ApiProperty({ required: true, example: "Asia/Kolkata" }) @IsOptional() - timeZone:string; + timeZone?:string; } From 9a5021869f6aa7227542c13f14e8feecf1ffd22c Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Wed, 8 Oct 2025 15:14:31 +0530 Subject: [PATCH 09/27] feat: add permission check to get a testflow --- .../controllers/testflow.controller.ts | 19 +++++++----- .../workspace/services/testflow.service.ts | 29 +++++-------------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/modules/workspace/controllers/testflow.controller.ts b/src/modules/workspace/controllers/testflow.controller.ts index a79f8a896..5f4c75aa0 100644 --- a/src/modules/workspace/controllers/testflow.controller.ts +++ b/src/modules/workspace/controllers/testflow.controller.ts @@ -109,7 +109,7 @@ export class TestflowController { * @description This will retrieve a specific Testflow using its ID, * returning the Testflow object if found. */ - @Get("testflow/:testflowId") + @Get(":workspaceId/testflow/:testflowId") @ApiOperation({ summary: "Get Individual Testflow", description: "This will get individual testflow of a workspace", @@ -121,10 +121,13 @@ export class TestflowController { }) @ApiResponse({ status: 400, description: "Fetch Testflow Request Failed" }) async getTestflow( + @Param("workspaceId") workspaceId: string, @Param("testflowId") testflowId: string, @Res() res: FastifyReply, + @Req() request: ExtendedFastifyRequest, ) { - const testflow = await this.testflowService.getTestflow(testflowId); + const user = request.user; + const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id); const responseData = new ApiResponseService( "Success", HttpStatusCode.OK, @@ -321,8 +324,8 @@ export class TestflowController { const response = await this.testflowService.createTestflowSchedular( createTestflowSchedularDto, user, - ); - const testflow = await this.testflowService.getTestflow(createTestflowSchedularDto.testflowId); + ); + const testflow = await this.testflowService.getTestflow(createTestflowSchedularDto.workspaceId, createTestflowSchedularDto.testflowId, user._id); const result = { testflow, schedule:response @@ -359,7 +362,7 @@ export class TestflowController { workspaceId, user, ); - const testflow = await this.testflowService.getTestflow(testflowId); + const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id); const responseData = new ApiResponseService( "Success", HttpStatusCode.OK, @@ -390,7 +393,7 @@ export class TestflowController { workspaceId, user, ); - const testflow = await this.testflowService.getTestflow(testflowId); + const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id); const responseData = new ApiResponseService( "Success", HttpStatusCode.OK, @@ -421,7 +424,7 @@ export class TestflowController { workspaceId, user, ); - const testflow = await this.testflowService.getTestflow(testflowId); + const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id); const responseData = new ApiResponseService( "Success", HttpStatusCode.OK, @@ -448,7 +451,7 @@ export class TestflowController { ) { const user = request.user; await this.testflowService.deleteScheduleRunHistory(workspaceId, testflowId, scheduleId, runHistoryId, user); - const testflow = await this.testflowService.getTestflow(testflowId); + const testflow = await this.testflowService.getTestflow(workspaceId, testflowId, user._id); const responseData = new ApiResponseService( "Success", HttpStatusCode.OK, diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 4500a6888..4768573d9 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -330,8 +330,9 @@ export class TestflowService implements OnModuleInit { * Fetches single testflow. * @param id - Testflow id you want to fetch. */ - async getTestflow(id: string): Promise> { - return await this.testflowRepository.get(id); + async getTestflow(workspaceId: string, testflowId: string, userId: ObjectId): Promise> { + await this.checkPermission(workspaceId, userId); + return await this.testflowRepository.get(testflowId); } /** @@ -341,6 +342,9 @@ export class TestflowService implements OnModuleInit { */ async checkPermission(workspaceId: string, userid: ObjectId): Promise { const workspace = await this.workspaceService.get(workspaceId); + if(workspace.workspaceType === WorkspaceType.PUBLIC){ + return; + } const hasPermission = workspace.users.some((user) => { return user.id.toString() === userid.toString(); }); @@ -502,26 +506,7 @@ export class TestflowService implements OnModuleInit { user: DecodedUserObject, ) { try { - const workspaceUsers = await this.workspaceReposistory.get( - schedularData?.workspaceId, - ); - if (!workspaceUsers) { - throw new NotFoundException("Workspace not found."); - } - const userDetails = workspaceUsers.users.find( - (item) => item.id === user._id.toString(), - ); - if (!userDetails) { - throw new NotFoundException("User not found in workspace."); - } - if ( - userDetails.role !== WorkspaceRole.ADMIN && - userDetails.role !== WorkspaceRole.EDITOR - ) { - throw new ForbiddenException( - "User does not have permission to perform this action.", - ); - } + await this.isWorkspaceAdminorEditor(schedularData?.workspaceId, user._id); // Build cron config const runCycleConfig = this.buildRunCycleConfig( schedularData.runConfiguration, From b9c634a9f4c19e56c6033fc492fcf8d12c899d60 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Wed, 8 Oct 2025 15:58:45 +0530 Subject: [PATCH 10/27] fix: time updated according to the Utc --- src/modules/common/models/testflow.model.ts | 6 -- .../workspace/payloads/testflow.payload.ts | 5 -- .../repositories/testflow.repository.ts | 68 +++++++++---------- .../workspace/services/testflow.service.ts | 14 ++-- 4 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/modules/common/models/testflow.model.ts b/src/modules/common/models/testflow.model.ts index 3d2882c20..766915d74 100644 --- a/src/modules/common/models/testflow.model.ts +++ b/src/modules/common/models/testflow.model.ts @@ -549,12 +549,6 @@ export class TestflowSchedular { @IsOptional() schedularRunHistory?: TestFlowSchedularRunHistory[]; - - @IsString() - @ApiProperty({ required: true, example: "Asia/Kolkata" }) - @IsOptional() - timeZone?:string; - @IsDate() @IsOptional() createdAt?: Date; diff --git a/src/modules/workspace/payloads/testflow.payload.ts b/src/modules/workspace/payloads/testflow.payload.ts index 4ef0caa4c..3e15cc72c 100644 --- a/src/modules/workspace/payloads/testflow.payload.ts +++ b/src/modules/workspace/payloads/testflow.payload.ts @@ -181,9 +181,4 @@ export class CreateTestflowSchedularDto { @ValidateNested() @Type(() => NotificationDto) notification?: NotificationDto; - - @IsString() - @ApiProperty({ required: true, example: "Asia/Kolkata" }) - @IsOptional() - timeZone?:string; } diff --git a/src/modules/workspace/repositories/testflow.repository.ts b/src/modules/workspace/repositories/testflow.repository.ts index 7243b9054..76f27984e 100644 --- a/src/modules/workspace/repositories/testflow.repository.ts +++ b/src/modules/workspace/repositories/testflow.repository.ts @@ -206,7 +206,7 @@ export class TestflowRepository { schedularId: string, runHistoryItem: TestFlowSchedularRunHistory, ): Promise { - const now = new Date(); + const nowUtc = new Date().toISOString(); if (!testflowId || !schedularId) { throw new Error("Both testflowId and schedularId are required"); } @@ -215,8 +215,8 @@ export class TestflowRepository { { $inc: { "schedules.$[elem].executedCount": 1 }, $set: { - "schedules.$[elem].lastExecuted": now, - updatedAt: now, + "schedules.$[elem].lastExecuted": nowUtc, + updatedAt: nowUtc, }, $push: { "schedules.$[elem].schedularRunHistory": { @@ -231,38 +231,38 @@ export class TestflowRepository { ); } - /** - * Edit a schedular execution (run history item) in a testflow's schedule. - * @param {string} testflowId - The testflow document ID. - * @param {string} schedularId - The schedule ID. - * @param {Partial} updatedRunHistory - The updated fields for the run history item. - * @returns {Promise} - The result of the update operation. - */ - async editSchedularExecution( - testflowId: string, - schedularId: string, - updatedRunHistory: Partial, - ): Promise { - if (!testflowId || !schedularId || !updatedRunHistory.id) { - throw new Error("testflowId, schedularId, and runHistoryId are required"); - } - // Build the update object for only the provided fields - const setObj: Record = {}; - for (const [key, value] of Object.entries(updatedRunHistory)) { - setObj[`schedules.$[elem].schedularRunHistory.$[run].${key}`] = value; - } - setObj["updatedAt"] = new Date(); - return this.db.collection(Collections.TESTFLOW).updateOne( - { _id: new ObjectId(testflowId) }, - { $set: setObj }, - { - arrayFilters: [ - { "elem.id": schedularId }, - { "run.id": updatedRunHistory.id }, - ], - }, - ); + /** + * Edit a schedular execution (run history item) in a testflow's schedule. + * @param {string} testflowId - The testflow document ID. + * @param {string} schedularId - The schedule ID. + * @param {Partial} updatedRunHistory - The updated fields for the run history item. + * @returns {Promise} - The result of the update operation. + */ + async editSchedularExecution( + testflowId: string, + schedularId: string, + updatedRunHistory: Partial, + ): Promise { + if (!testflowId || !schedularId || !updatedRunHistory.id) { + throw new Error("testflowId, schedularId, and runHistoryId are required"); + } + // Build the update object for only the provided fields + const setObj: Record = {}; + for (const [key, value] of Object.entries(updatedRunHistory)) { + setObj[`schedules.$[elem].schedularRunHistory.$[run].${key}`] = value; } + setObj["updatedAt"] = new Date(); + return this.db.collection(Collections.TESTFLOW).updateOne( + { _id: new ObjectId(testflowId) }, + { $set: setObj }, + { + arrayFilters: [ + { "elem.id": schedularId }, + { "run.id": updatedRunHistory.id }, + ], + }, + ); + } async updateSchedularStatus( diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index ddcaaee94..52656bed7 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -553,7 +553,6 @@ export class TestflowService implements OnModuleInit { schedularName: jobName, executedCount: 0, lastExecuted: undefined, - timeZone: schedularData?.timeZone, createdAt: new Date(), updatedAt: new Date(), createdBy: user._id.toString(), @@ -764,12 +763,12 @@ export class TestflowService implements OnModuleInit { isScheduled, status: "pending", requests: [], - responses:[], + responses: [], nodes: [], edges: [], failedRequests: 0, successRequests: 0, - totalTime:"0 ms", + totalTime: "0 ms", createdAt: new Date(), }; //Save execution result in DB @@ -821,11 +820,16 @@ export class TestflowService implements OnModuleInit { const userDetails = await this.userReposistory.getUserById( data.createdBy, ); - const successPercentage = Math.round((data.successRequests / totalRequestCount) * 100 * 100) / 100; + const successPercentage = + Math.round((data.successRequests / totalRequestCount) * 100 * 100) / + 100; const emailData: EmailData = { userName: userDetails?.name, scheduleName: getSchedular.name, - scheduleLastestRun: new Date(getSchedular.lastExecuted).toString(), + scheduleLastestRun: new Date(getSchedular.lastExecuted) + .toISOString() + .replace("T", " ") + .replace("Z", " UTC"), scheduleRunResult: scheduleRunResult, scheduleRunPassedCount: data.successRequests, scheduleRunFailedCount: data.failedRequests, From d2c63a591513c3efe1a6b42a8cb05552a4c569a3 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Wed, 8 Oct 2025 16:12:39 +0530 Subject: [PATCH 11/27] fix: time updated according to the Utc --- .../workspace/services/testflow.service.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 52656bed7..6fbeb86bc 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -826,10 +826,18 @@ export class TestflowService implements OnModuleInit { const emailData: EmailData = { userName: userDetails?.name, scheduleName: getSchedular.name, - scheduleLastestRun: new Date(getSchedular.lastExecuted) - .toISOString() - .replace("T", " ") - .replace("Z", " UTC"), + scheduleLastestRun: + new Date(getSchedular.lastExecuted).toLocaleString("en-US", { + timeZone: "UTC", + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + fractionalSecondDigits: 3, + hour12: false, + }) + " UTC", scheduleRunResult: scheduleRunResult, scheduleRunPassedCount: data.successRequests, scheduleRunFailedCount: data.failedRequests, From 2aa3ec5570ae01224d68464efec2a5f55c6b2732 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Wed, 8 Oct 2025 16:34:55 +0530 Subject: [PATCH 12/27] fix: time updated according to the Utc --- src/modules/workspace/services/testflow.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 6fbeb86bc..1b719ed3e 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -835,7 +835,6 @@ export class TestflowService implements OnModuleInit { hour: "2-digit", minute: "2-digit", second: "2-digit", - fractionalSecondDigits: 3, hour12: false, }) + " UTC", scheduleRunResult: scheduleRunResult, From c406072c8c25d84076c4aeaba0e3bdff067d2981 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Wed, 8 Oct 2025 18:35:43 +0530 Subject: [PATCH 13/27] feat: add permission check to get a testflow --- src/modules/workspace/services/testflow-run.service.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/workspace/services/testflow-run.service.ts b/src/modules/workspace/services/testflow-run.service.ts index d4dc848f3..4d9aaec50 100644 --- a/src/modules/workspace/services/testflow-run.service.ts +++ b/src/modules/workspace/services/testflow-run.service.ts @@ -82,8 +82,10 @@ export class TestflowRunService { ); let environmentData; if (environmentId) { - environmentData = - await this.environmentReposistory.get(environmentId); + try{ + environmentData = + await this.environmentReposistory.get(environmentId); + }catch(err){} } const activeVariables = this.combineEnvironmentData( globalEnvDetails?.variable || [], From 03e55aa4cb38b0778f827794f02c46a725fdb702 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 00:47:35 +0530 Subject: [PATCH 14/27] fix: cron expression on edit --- .../workspace/services/testflow.service.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 4768573d9..3cb9fef40 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -170,6 +170,18 @@ export class TestflowService implements OnModuleInit { ); environmentName = environmentData?.name || ""; } + let cronExpression; + if(updateScheduleDto.runConfiguration){ + const runCycleConfig = this.buildRunCycleConfig(updateScheduleDto.runConfiguration); + cronExpression = this.generateCronExpression(runCycleConfig); + if (!cronExpression) { + updateScheduleDto.cronExpression = null; + } + else{ + updateScheduleDto.cronExpression = cronExpression; + } + } + // Merge update fields, ensure id is present const updatedSchedular: TestflowSchedular = { ...existingSchedular, @@ -187,7 +199,6 @@ export class TestflowService implements OnModuleInit { ); // Optionally update cron job if runConfiguration or isActive changed if ( - updateScheduleDto.runConfiguration || updateScheduleDto.isActive !== undefined ) { const schedular = await this.testflowRepository.getSchedularById( @@ -202,9 +213,7 @@ export class TestflowService implements OnModuleInit { const runCycleConfig = this.buildRunCycleConfig( schedular.runConfiguration, ); - const cronExpression = - schedular.cronExpression || - this.generateCronExpression(runCycleConfig); + const cronExpression = schedular.cronExpression; await this.testflowSchedulerService.addSchedulerJob( runCycleConfig, this.getScheduledExecutionCallback( From 3e40503a305041fa053095f760963d815f56b906 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 01:01:07 +0530 Subject: [PATCH 15/27] fix: cron expression on edit --- src/modules/workspace/services/testflow.service.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 3cb9fef40..ab8364058 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -197,7 +197,7 @@ export class TestflowService implements OnModuleInit { scheduleId, updatedSchedular, ); - // Optionally update cron job if runConfiguration or isActive changed + // Optionally update cron job if isActive changed if ( updateScheduleDto.isActive !== undefined ) { @@ -383,6 +383,16 @@ export class TestflowService implements OnModuleInit { id, user._id, ); + + // Remove all associated cronjobs for this testflow + if (testflow?.schedules && Array.isArray(testflow.schedules)) { + for (const schedule of testflow.schedules) { + if (schedule?.id) { + await this.testflowSchedulerService.removeSchedulerJob(schedule.id); + } + } + } + const updateMessage = `"${testflow.name}" testflow is deleted from "${workspace.name}" workspace`; const currentWorkspaceObject = new ObjectId(workspaceId); const updateWorkspaceData: Partial = { From 0f8f274b50a70d2c873e91b4f3611c26df828e3a Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 01:10:50 +0530 Subject: [PATCH 16/27] fix: testflow cron job configurations --- .../workspace/services/testflow.service.ts | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index ab8364058..c93ccd6c3 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -197,39 +197,36 @@ export class TestflowService implements OnModuleInit { scheduleId, updatedSchedular, ); - // Optionally update cron job if isActive changed - if ( - updateScheduleDto.isActive !== undefined - ) { - const schedular = await this.testflowRepository.getSchedularById( - testflowId, - scheduleId, - ); - if (schedular) { - // Remove old job - await this.testflowSchedulerService.removeSchedulerJob(scheduleId); - // If still active, re-add job - if (schedular.isActive) { - const runCycleConfig = this.buildRunCycleConfig( - schedular.runConfiguration, - ); - const cronExpression = schedular.cronExpression; - await this.testflowSchedulerService.addSchedulerJob( - runCycleConfig, - this.getScheduledExecutionCallback( - testflowId, - schedular.environmentId, - workspaceId, - scheduleId, - user, - ), - schedular.schedularName, - cronExpression, + + const schedular = await this.testflowRepository.getSchedularById( + testflowId, + scheduleId, + ); + if (schedular) { + // Remove old job + await this.testflowSchedulerService.removeSchedulerJob(scheduleId); + // If still active, re-add job + if (schedular.isActive) { + const runCycleConfig = this.buildRunCycleConfig( + schedular.runConfiguration, + ); + const cronExpression = schedular.cronExpression; + await this.testflowSchedulerService.addSchedulerJob( + runCycleConfig, + this.getScheduledExecutionCallback( + testflowId, + schedular.environmentId, + workspaceId, scheduleId, - ); - } + user, + ), + schedular.schedularName, + cronExpression, + scheduleId, + ); } } + return result; } From 524e1d4af40d1a275d70cfa430aaab86188fe1fc Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 01:14:35 +0530 Subject: [PATCH 17/27] fix: testflow cron job configurations --- src/modules/workspace/services/testflow.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index c93ccd6c3..b5833778a 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -170,10 +170,10 @@ export class TestflowService implements OnModuleInit { ); environmentName = environmentData?.name || ""; } - let cronExpression; + if(updateScheduleDto.runConfiguration){ const runCycleConfig = this.buildRunCycleConfig(updateScheduleDto.runConfiguration); - cronExpression = this.generateCronExpression(runCycleConfig); + const cronExpression = this.generateCronExpression(runCycleConfig); if (!cronExpression) { updateScheduleDto.cronExpression = null; } From fe16c1dcd667b99296bfe62ab8291a1cdaaa249a Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 13:36:30 +0530 Subject: [PATCH 18/27] feat: add error handling for proxy fail --- .../workspace/services/testflow-run.service.ts | 13 +++++++++++-- src/modules/workspace/services/testflow.service.ts | 6 +++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/modules/workspace/services/testflow-run.service.ts b/src/modules/workspace/services/testflow-run.service.ts index 4d9aaec50..fd337a1a2 100644 --- a/src/modules/workspace/services/testflow-run.service.ts +++ b/src/modules/workspace/services/testflow-run.service.ts @@ -113,11 +113,20 @@ export class TestflowRunService { nodes:testflowDetails.nodes, edges:testflowDetails.edges, } + // throw new NotFoundException("Testflow not found"); // Return only history or any relevant part return finalResult; } catch (error: any) { - console.error("Testflow proxy execution failed:", error.message || error); - throw new Error(error?.message || "Testflow execution failed."); + return { + result:{ + history: { + status: "error" + } + }, + environmentName:environmentData?.name, + nodes:testflowDetails.nodes, + edges:testflowDetails.edges, + } } }; } \ No newline at end of file diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index b5833778a..bbee19ba9 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -814,7 +814,11 @@ export class TestflowService implements OnModuleInit { scheduleRunResult = "failed"; } else if (data.status === "success") { scheduleRunResult = "success"; - } else { + } + else if (data.status === "error") { + scheduleRunResult = "error"; + } + else { scheduleRunResult = "partial"; } const totalRequestCount = data.successRequests + data.failedRequests; From 2af92914d3d2238d67c5cf83e0ea151d091218c0 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 13:43:53 +0530 Subject: [PATCH 19/27] feat: add error handling for proxy fail --- .../services/testflow-run.service.ts | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/modules/workspace/services/testflow-run.service.ts b/src/modules/workspace/services/testflow-run.service.ts index fd337a1a2..f9215310c 100644 --- a/src/modules/workspace/services/testflow-run.service.ts +++ b/src/modules/workspace/services/testflow-run.service.ts @@ -73,35 +73,35 @@ export class TestflowRunService { testflowId:string, user?: DecodedUserObject, ): Promise => { - // Fetch testflow and environment data - const testflowDetails = await this.testflowRepository.get(testflowId); - const workspaceID = await this.workspaceReposistory.get(workspaceId); - const globalEnvironment = workspaceID.environments[0]; - const globalEnvDetails = await this.environmentReposistory.get( - globalEnvironment.id.toString(), - ); - let environmentData; - if (environmentId) { - try{ - environmentData = - await this.environmentReposistory.get(environmentId); - }catch(err){} - } - const activeVariables = this.combineEnvironmentData( - globalEnvDetails?.variable || [], - environmentData?.variable || [], - ); - // Build proxy URL - const sparrowProxy = this.configService.get("sparrowProxy.baseUrl"); - const proxyUrl = `${sparrowProxy}/proxy/testflow/execute`; - // Prepare request body for proxy API - const body = { - nodes: testflowDetails.nodes || [], - variables: activeVariables || [], - edges: testflowDetails.edges, - userId: user?._id || new ObjectId("000000000000000000000000"), - }; try { + // Fetch testflow and environment data + const testflowDetails = await this.testflowRepository.get(testflowId); + const workspaceID = await this.workspaceReposistory.get(workspaceId); + const globalEnvironment = workspaceID.environments[0]; + const globalEnvDetails = await this.environmentReposistory.get( + globalEnvironment.id.toString(), + ); + let environmentData; + if (environmentId) { + try{ + environmentData = + await this.environmentReposistory.get(environmentId); + }catch(err){} + } + const activeVariables = this.combineEnvironmentData( + globalEnvDetails?.variable || [], + environmentData?.variable || [], + ); + // Build proxy URL + const sparrowProxy = this.configService.get("sparrowProxy.baseUrl"); + const proxyUrl = `${sparrowProxy}/proxy/testflow/execute`; + // Prepare request body for proxy API + const body = { + nodes: testflowDetails.nodes || [], + variables: activeVariables || [], + edges: testflowDetails.edges, + userId: user?._id || new ObjectId("000000000000000000000000"), + }; const response = await axios.post(proxyUrl, body, { headers: { "Content-Type": "application/json", @@ -113,8 +113,7 @@ export class TestflowRunService { nodes:testflowDetails.nodes, edges:testflowDetails.edges, } - // throw new NotFoundException("Testflow not found"); - // Return only history or any relevant part + throw new Error("Test flow execution failed"); return finalResult; } catch (error: any) { return { @@ -123,9 +122,9 @@ export class TestflowRunService { status: "error" } }, - environmentName:environmentData?.name, - nodes:testflowDetails.nodes, - edges:testflowDetails.edges, + environmentName: "", + nodes: [], + edges: [], } } }; From 97838cd5d5073b4223dcfd7260f3259b0756cd4a Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Thu, 9 Oct 2025 13:45:32 +0530 Subject: [PATCH 20/27] feat: add error handling for proxy fail --- src/modules/workspace/services/testflow-run.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/workspace/services/testflow-run.service.ts b/src/modules/workspace/services/testflow-run.service.ts index f9215310c..0c4c45d2c 100644 --- a/src/modules/workspace/services/testflow-run.service.ts +++ b/src/modules/workspace/services/testflow-run.service.ts @@ -113,7 +113,6 @@ export class TestflowRunService { nodes:testflowDetails.nodes, edges:testflowDetails.edges, } - throw new Error("Test flow execution failed"); return finalResult; } catch (error: any) { return { From 7ef80c86cfcde7313c810731f50f2c2947c7f8e9 Mon Sep 17 00:00:00 2001 From: "aakash.reddy@techdome.net.in" Date: Thu, 9 Oct 2025 15:54:07 +0530 Subject: [PATCH 21/27] fix: added margin for text name --- src/modules/views/testflowScheduleRunEmail.handlebars | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/views/testflowScheduleRunEmail.handlebars b/src/modules/views/testflowScheduleRunEmail.handlebars index 49b508abe..4abe68f28 100644 --- a/src/modules/views/testflowScheduleRunEmail.handlebars +++ b/src/modules/views/testflowScheduleRunEmail.handlebars @@ -126,7 +126,7 @@ From 16f0a275a9cf5a40d1662464f389d623ee0bd7e5 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Fri, 10 Oct 2025 03:09:50 +0530 Subject: [PATCH 22/27] feat: add hourly cron fix --- src/modules/common/enum/testflow.enum.ts | 1 + .../services/testflow-schedular.service.ts | 88 ++++++++++++- .../workspace/services/testflow.service.ts | 121 +++++++++++++----- 3 files changed, 175 insertions(+), 35 deletions(-) diff --git a/src/modules/common/enum/testflow.enum.ts b/src/modules/common/enum/testflow.enum.ts index 8e6b02c13..96c5c9530 100644 --- a/src/modules/common/enum/testflow.enum.ts +++ b/src/modules/common/enum/testflow.enum.ts @@ -61,6 +61,7 @@ export interface DailyConfig { export interface HourlyConfig { type: RunCycleEnum.HOURLY; + executeAt: Date; intervalHours: number; startTime?: { hour: number; diff --git a/src/modules/workspace/services/testflow-schedular.service.ts b/src/modules/workspace/services/testflow-schedular.service.ts index 8d5010363..ef6d28aa8 100644 --- a/src/modules/workspace/services/testflow-schedular.service.ts +++ b/src/modules/workspace/services/testflow-schedular.service.ts @@ -27,7 +27,86 @@ export class TestflowSchedulerService { return false; } try { - // Create cron job with UTC timezone + // For HOURLY rolling interval, create a one-time cron job for the next execution + if (runCycle.type === RunCycleEnum.HOURLY && runCycle.intervalHours) { + + const scheduleNext = async (lastRun: Date) => { + // Calculate next run time + const nextRun = new Date(lastRun.getTime() + runCycle.intervalHours * 60 * 60 * 1000); + // Generate one-time cron expression for nextRun + const second = nextRun.getUTCSeconds(); + const minute = nextRun.getUTCMinutes(); + const hour = nextRun.getUTCHours(); + const dayOfMonth = nextRun.getUTCDate(); + const month = nextRun.getUTCMonth() + 1; + const oneTimeCron = `${second} ${minute} ${hour} ${dayOfMonth} ${month} *`; + const nextJobName = schedularId; // Always use scheduleId as job name + this.logger.log(`Next rolling interval job ${nextJobName} scheduled for ${nextRun.toISOString()} (cron: ${oneTimeCron})`); + // Remove any existing job with this name before adding + if (this.schedulerRegistry.doesExist("cron", nextJobName)) { + const oldJob = this.schedulerRegistry.getCronJob(nextJobName); + oldJob.stop(); + this.schedulerRegistry.deleteCronJob(nextJobName); + } + const job = new CronJob( + oneTimeCron, + async () => { + this.logger.log(`Executing rolling interval job ${nextJobName} at ${new Date().toISOString()} (UTC)`); + if (runApis) { + try { + await runApis(schedularId); + } catch (error) { + this.logger.error(`Error executing job ${nextJobName}: ${error.message}`, error.stack); + } + } + job.stop(); + this.schedulerRegistry.deleteCronJob(nextJobName); + this.logAllCronJobs(); + // Schedule next job + await scheduleNext(nextRun); + this.logAllCronJobs(); + }, + null, + false, + timezone, + ); + this.schedulerRegistry.addCronJob(nextJobName, job); + job.start(); + }; + // Use the provided initial cron expression for the first run + const nextJobName = schedularId; + // Remove any existing job with this name before adding + if (this.schedulerRegistry.doesExist("cron", nextJobName)) { + const oldJob = this.schedulerRegistry.getCronJob(nextJobName); + oldJob.stop(); + this.schedulerRegistry.deleteCronJob(nextJobName); + } + const job = new CronJob( + cronExpression, + async () => { + this.logger.log(`Executing rolling interval job ${nextJobName} at ${new Date().toISOString()} (UTC)`); + if (runApis) { + try { + await runApis(schedularId); + } catch (error) { + this.logger.error(`Error executing job ${nextJobName}: ${error.message}`, error.stack); + } + } + job.stop(); + this.schedulerRegistry.deleteCronJob(nextJobName); + // After first run, start rolling with scheduleNext + await scheduleNext(new Date()); + }, + null, + false, + timezone, + ); + this.schedulerRegistry.addCronJob(nextJobName, job); + job.start(); + this.logger.log(`Rolling interval scheduler job ${jobName} registered with interval: ${runCycle.intervalHours}h, timezone: ${timezone}`); + return true; + } + // Default: Create cron job with UTC timezone const job = new CronJob( cronExpression, async () => { @@ -119,6 +198,11 @@ export class TestflowSchedulerService { } private generateJobName(schedulerId: string): string { - return `scheduler_${schedulerId}`; + return `${schedulerId}`; + } + + public logAllCronJobs() { + const jobs = Array.from(this.schedulerRegistry.getCronJobs().keys()); + console.log('Active cron jobs: ' + jobs.join(', ')); } } diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index bbee19ba9..15466e2db 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -83,6 +83,38 @@ export class TestflowService implements OnModuleInit { private readonly environmentReposistory: EnvironmentRepository, ) {} + async getNextFutureCronExpression(pastCron: string, intervalHours: number): Promise { + // Expecting cron in format: 's m h * * *' + const parts = pastCron.trim().split(/\s+/); + if (parts.length !== 6) return pastCron; + + let second = parseInt(parts[0], 10); + let minute = parseInt(parts[1], 10); + let hour = parseInt(parts[2], 10); + let day = parseInt(parts[3], 10); + let month = parseInt(parts[4], 10) - 1; + + // Start from the past time + let now = new Date(); + let next = new Date(Date.UTC( + now.getUTCFullYear(), + month, + day, + hour, + minute, + second, + 0 + )); + + // If the past time is in the past, keep adding interval until it's in the future + while (next <= now) { + next.setUTCHours(next.getUTCHours() + intervalHours); + } + + // Return new cron expression + return `${next.getUTCSeconds()} ${next.getUTCMinutes()} ${next.getUTCHours()} ${next.getUTCDate()} ${next.getUTCMonth() + 1} *`; + } + async onModuleInit() { try { this.logger.log("Bootstrapping schedulers from DB..."); @@ -95,24 +127,32 @@ export class TestflowService implements OnModuleInit { if (!tf.schedules?.length) continue; for (const schedule of tf.schedules) { - const runCycleConfig = this.buildRunCycleConfig( - schedule.runConfiguration, - ); - - if (schedule.isActive && schedule.cronExpression) { - await this.testflowSchedulerService.addSchedulerJob( - runCycleConfig, - this.getScheduledExecutionCallback( - tf._id.toString(), - schedule.environmentId, - tf.workspaceId, - schedule.id, - ), - schedule.schedularName, - schedule.cronExpression, - schedule.id, - "UTC", + try{ + const runCycleConfig = this.buildRunCycleConfig( + schedule.runConfiguration, ); + if (schedule.isActive && schedule.cronExpression) { + let cronExpression = schedule.cronExpression; + if(schedule.runConfiguration.runCycle === RunCycleEnum.HOURLY){ + const intervalHours = schedule.runConfiguration.intervalHours; + cronExpression = await this.getNextFutureCronExpression(cronExpression, intervalHours); + } + await this.testflowSchedulerService.addSchedulerJob( + runCycleConfig, + this.getScheduledExecutionCallback( + tf._id.toString(), + schedule.environmentId, + tf.workspaceId, + schedule.id, + ), + schedule.schedularName, + cronExpression, + schedule.id, + "UTC", + ); + } + }catch(error){ + this.logger.error("Error adding scheduler job:", error); } } } @@ -180,6 +220,17 @@ export class TestflowService implements OnModuleInit { else{ updateScheduleDto.cronExpression = cronExpression; } + }else{ + if(existingSchedular.runConfiguration.runCycle === RunCycleEnum.HOURLY){ + const runCycleConfig = this.buildRunCycleConfig(existingSchedular.runConfiguration); + const cronExpression = this.generateCronExpression(runCycleConfig); + if (!cronExpression) { + updateScheduleDto.cronExpression = null; + } + else{ + updateScheduleDto.cronExpression = cronExpression; + } + } } // Merge update fields, ensure id is present @@ -227,7 +278,7 @@ export class TestflowService implements OnModuleInit { } } - return result; + return result; } /** @@ -624,6 +675,7 @@ export class TestflowService implements OnModuleInit { } return { type: RunCycleEnum.HOURLY, + executeAt: new Date(Date.now() + 1 * 60 * 1000), intervalHours: runConfig.intervalHours, startTime: runConfig.time ? this.parseTime(runConfig.time) @@ -710,17 +762,17 @@ export class TestflowService implements OnModuleInit { } private generateHourlyCronExpression(config: HourlyConfig): string { - const { intervalHours, startTime } = config; - if (startTime) { - const { hour, minute, second = 0 } = startTime; - return `${second} ${minute} ${hour}-23/${intervalHours} * * *`; - } else { - const now = new Date(); - const utcHour = now.getUTCHours(); - const utcMinute = now.getUTCMinutes(); - const utcSecond = now.getUTCSeconds(); - return `${utcSecond} ${utcMinute} ${utcHour}-23/${intervalHours} * * *`; + const executeAt = config.executeAt; + const now = new Date(); + if (executeAt <= now) { + return null; } + const second = executeAt.getUTCSeconds(); + const minute = executeAt.getUTCMinutes(); + const hour = executeAt.getUTCHours(); + const dayOfMonth = executeAt.getUTCDate(); + const month = executeAt.getUTCMonth() + 1; + return `${second} ${minute} ${hour} ${dayOfMonth} ${month} *`; } private generateWeeklyCronExpression(config: WeeklyConfig): string { @@ -790,6 +842,7 @@ export class TestflowService implements OnModuleInit { nodes: response.nodes, edges: response.edges, ...response.result.history, + status: response?.result?.history?.status || "error", }; //Save execution result in DB await this.testflowRepository.editSchedularExecution( @@ -808,14 +861,16 @@ export class TestflowService implements OnModuleInit { false, ); } - const data = response.result.history; + const data = response?.result?.history; let scheduleRunResult; - if (data.status === "fail" && data.successRequests < 1) { + if(!response?.status){ + scheduleRunResult = "error"; + } + else if (data?.status === "fail" && data?.successRequests < 1) { scheduleRunResult = "failed"; - } else if (data.status === "success") { + } else if (data?.status === "success") { scheduleRunResult = "success"; - } - else if (data.status === "error") { + } else if (data?.status === "error") { scheduleRunResult = "error"; } else { From 409ca1052156c9d6482183126b696d14a14c43ab Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Fri, 10 Oct 2025 11:10:28 +0530 Subject: [PATCH 23/27] feat: updated hourly cron expression --- .../repositories/testflow.repository.ts | 31 +++++++++++++++++++ .../services/testflow-schedular.service.ts | 5 ++- .../workspace/services/testflow.service.ts | 15 +++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/modules/workspace/repositories/testflow.repository.ts b/src/modules/workspace/repositories/testflow.repository.ts index 7243b9054..c356236aa 100644 --- a/src/modules/workspace/repositories/testflow.repository.ts +++ b/src/modules/workspace/repositories/testflow.repository.ts @@ -264,6 +264,37 @@ export class TestflowRepository { ); } + /** + * Edit a schedular execution (run history item) in a testflow's schedule. + * @param {string} testflowId - The testflow document ID. + * @param {string} schedularId - The schedule ID. + * @param {Partial} updatedSchedular - The updated fields for the schedule item. + * @returns {Promise} - The result of the update operation. + */ + async editSchedular( + testflowId: string, + schedularId: string, + updatedSchedular: Partial, + ): Promise { + if (!testflowId || !schedularId) { + throw new Error("testflowId and schedularId are required"); + } + // Build the update object for only the provided fields + const setObj: Record = {}; + for (const [key, value] of Object.entries(updatedSchedular)) { + setObj[`schedules.$[elem].${key}`] = value; + } + return this.db.collection(Collections.TESTFLOW).updateOne( + { _id: new ObjectId(testflowId) }, + { $set: setObj }, + { + arrayFilters: [ + { "elem.id": schedularId }, + ], + }, + ); + } + async updateSchedularStatus( testflowId: string, diff --git a/src/modules/workspace/services/testflow-schedular.service.ts b/src/modules/workspace/services/testflow-schedular.service.ts index ef6d28aa8..1a502efd1 100644 --- a/src/modules/workspace/services/testflow-schedular.service.ts +++ b/src/modules/workspace/services/testflow-schedular.service.ts @@ -3,12 +3,13 @@ import { SchedulerRegistry } from "@nestjs/schedule"; import { CronJob } from "cron"; import { RunCycleEnum } from "@src/modules/common/enum/testflow.enum"; import { RunCycleConfig } from "@src/modules/common/enum/testflow.enum"; +import { TestflowRepository } from "../repositories/testflow.repository"; @Injectable() export class TestflowSchedulerService { private readonly logger = new Logger(TestflowSchedulerService.name); - constructor(private schedulerRegistry: SchedulerRegistry) {} + constructor(private schedulerRegistry: SchedulerRegistry, private testflowRepository: TestflowRepository) {} /** * Add a cron job @@ -16,6 +17,7 @@ export class TestflowSchedulerService { async addSchedulerJob( runCycle: RunCycleConfig, runApis: (schedularId: string) => Promise, + afterJobCreate: (cronExpression: string) => void, jobName: string, cronExpression: string, schedularId: string, @@ -70,6 +72,7 @@ export class TestflowSchedulerService { false, timezone, ); + afterJobCreate(oneTimeCron); this.schedulerRegistry.addCronJob(nextJobName, job); job.start(); }; diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index 15466e2db..be94eb2f5 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -145,6 +145,11 @@ export class TestflowService implements OnModuleInit { tf.workspaceId, schedule.id, ), + (_cronExpression: string)=>{ + this.testflowRepository.editSchedular(tf._id.toString(), schedule.id, { + cronExpression: _cronExpression, + }); + }, schedule.schedularName, cronExpression, schedule.id, @@ -271,6 +276,11 @@ export class TestflowService implements OnModuleInit { scheduleId, user, ), + (_cronExpression: string)=>{ + this.testflowRepository.editSchedular(testflowId, scheduleId, { + cronExpression: _cronExpression, + }); + }, schedular.schedularName, cronExpression, scheduleId, @@ -624,6 +634,11 @@ export class TestflowService implements OnModuleInit { schedulerId, user, ), + (_cronExpression: string)=>{ + this.testflowRepository.editSchedular(schedularData.testflowId, schedulerId, { + cronExpression: _cronExpression, + }); + }, jobName, cronExpression, schedulerId, From f38693b2f405eb2fbc3fa57eebae9aec78569790 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Fri, 10 Oct 2025 11:43:12 +0530 Subject: [PATCH 24/27] feat: updated hourly cron expression --- src/modules/workspace/services/testflow.service.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index be94eb2f5..b61f10890 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -47,6 +47,7 @@ import { v4 as uuidv4 } from "uuid"; import { TestflowSchedulerService } from "./testflow-schedular.service"; import { DailyConfig, + DayOfWeek, EmailData, HourlyConfig, NotificationReceiveType, @@ -793,7 +794,17 @@ export class TestflowService implements OnModuleInit { private generateWeeklyCronExpression(config: WeeklyConfig): string { const { days, time } = config; const { hour, minute, second = 0 } = time; - return `${second} ${minute} ${hour} * * ${days.join(",")}`; + const validDays = days.filter((day) => { + return day >= DayOfWeek.SUNDAY && day <= DayOfWeek.SATURDAY; + }); + if (validDays.length === 0) { + throw new BadRequestException( + "Invalid days specified. Days must be valid DayOfWeek values (0=Sunday, 1=Monday, ..., 6=Saturday)", + ); + } + const sortedDays = validDays.sort((a, b) => a - b); + const daysString = sortedDays.join(","); + return `${second} ${minute} ${hour} * * ${daysString}`; } public getScheduledExecutionCallback( From e8702c3377397ed5c885cdc4ab582ec213fdfd03 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Fri, 10 Oct 2025 11:48:13 +0530 Subject: [PATCH 25/27] feat: updated hourly cron expression --- .../services/testflow-schedular.service.ts | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/modules/workspace/services/testflow-schedular.service.ts b/src/modules/workspace/services/testflow-schedular.service.ts index 1a502efd1..fb2fb846d 100644 --- a/src/modules/workspace/services/testflow-schedular.service.ts +++ b/src/modules/workspace/services/testflow-schedular.service.ts @@ -63,10 +63,8 @@ export class TestflowSchedulerService { } job.stop(); this.schedulerRegistry.deleteCronJob(nextJobName); - this.logAllCronJobs(); // Schedule next job await scheduleNext(nextRun); - this.logAllCronJobs(); }, null, false, @@ -87,7 +85,6 @@ export class TestflowSchedulerService { const job = new CronJob( cronExpression, async () => { - this.logger.log(`Executing rolling interval job ${nextJobName} at ${new Date().toISOString()} (UTC)`); if (runApis) { try { await runApis(schedularId); @@ -106,16 +103,12 @@ export class TestflowSchedulerService { ); this.schedulerRegistry.addCronJob(nextJobName, job); job.start(); - this.logger.log(`Rolling interval scheduler job ${jobName} registered with interval: ${runCycle.intervalHours}h, timezone: ${timezone}`); return true; } // Default: Create cron job with UTC timezone const job = new CronJob( cronExpression, async () => { - this.logger.log( - `Executing job ${jobName} at ${new Date().toISOString()} (UTC)` - ); if (runApis) { try { await runApis(schedularId); @@ -130,7 +123,6 @@ export class TestflowSchedulerService { if (runCycle.type === RunCycleEnum.ONCE) { job.stop(); this.schedulerRegistry.deleteCronJob(jobName); - this.logger.log(`One-time scheduler ${jobName} completed and removed`); } }, null, // onComplete callback @@ -139,10 +131,6 @@ export class TestflowSchedulerService { ); this.schedulerRegistry.addCronJob(jobName, job); job.start(); - this.logger.log( - `Scheduler job ${jobName} registered with cycle: ${runCycle.type}, ` + - `timezone: ${timezone}, cron: ${cronExpression}` - ); return true; } catch (error) { this.logger.error( @@ -164,9 +152,6 @@ export class TestflowSchedulerService { job.stop(); this.schedulerRegistry.deleteCronJob(jobName); } - this.logger.log( - `Scheduler job ${jobName} (ID: ${schedulerId}) removed from DB + registry`, - ); return true; } catch (error) { this.logger.warn( @@ -184,7 +169,6 @@ export class TestflowSchedulerService { if (this.schedulerRegistry.doesExist("cron", jobName)) { const job = this.schedulerRegistry.getCronJob(jobName); job.stop(); - this.logger.log(`Scheduler job ${jobName} paused`); } } @@ -196,7 +180,6 @@ export class TestflowSchedulerService { if (this.schedulerRegistry.doesExist("cron", jobName)) { const job = this.schedulerRegistry.getCronJob(jobName); job.start(); - this.logger.log(`Scheduler job ${jobName} resumed`); } } @@ -205,7 +188,6 @@ export class TestflowSchedulerService { } public logAllCronJobs() { - const jobs = Array.from(this.schedulerRegistry.getCronJobs().keys()); - console.log('Active cron jobs: ' + jobs.join(', ')); + return Array.from(this.schedulerRegistry.getCronJobs().keys()); } } From beb6eda292e4be9439a17e86bcad5923301aaaa9 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Fri, 10 Oct 2025 11:48:54 +0530 Subject: [PATCH 26/27] feat: updated hourly cron expression --- src/modules/workspace/services/testflow-schedular.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/workspace/services/testflow-schedular.service.ts b/src/modules/workspace/services/testflow-schedular.service.ts index fb2fb846d..292d98a5f 100644 --- a/src/modules/workspace/services/testflow-schedular.service.ts +++ b/src/modules/workspace/services/testflow-schedular.service.ts @@ -9,7 +9,7 @@ import { TestflowRepository } from "../repositories/testflow.repository"; export class TestflowSchedulerService { private readonly logger = new Logger(TestflowSchedulerService.name); - constructor(private schedulerRegistry: SchedulerRegistry, private testflowRepository: TestflowRepository) {} + constructor(private schedulerRegistry: SchedulerRegistry ) {} /** * Add a cron job From 353fc7ecb8d8f329e8fe64e3a08e9050d433b564 Mon Sep 17 00:00:00 2001 From: Md Asif Raza Date: Fri, 10 Oct 2025 14:57:36 +0530 Subject: [PATCH 27/27] feat: updated hourly cron expression --- .../workspace/services/testflow-schedular.service.ts | 12 +++++------- src/modules/workspace/services/testflow.service.ts | 4 +--- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/modules/workspace/services/testflow-schedular.service.ts b/src/modules/workspace/services/testflow-schedular.service.ts index 292d98a5f..6fc81fbd2 100644 --- a/src/modules/workspace/services/testflow-schedular.service.ts +++ b/src/modules/workspace/services/testflow-schedular.service.ts @@ -18,14 +18,12 @@ export class TestflowSchedulerService { runCycle: RunCycleConfig, runApis: (schedularId: string) => Promise, afterJobCreate: (cronExpression: string) => void, - jobName: string, cronExpression: string, schedularId: string, timezone: string = "UTC", // Always use UTC by default ): Promise { if (!cronExpression) { - console.error(`Invalid run cycle configuration for job ${jobName}`); - this.logger.log(`Invalid run cycle configuration for job ${jobName}`); + this.logger.log(`Invalid run cycle configuration for job ${schedularId}`); return false; } try { @@ -114,7 +112,7 @@ export class TestflowSchedulerService { await runApis(schedularId); } catch (error) { this.logger.error( - `Error executing job ${jobName}: ${error.message}`, + `Error executing job ${schedularId}: ${error.message}`, error.stack ); } @@ -122,19 +120,19 @@ export class TestflowSchedulerService { // Handle one-time jobs if (runCycle.type === RunCycleEnum.ONCE) { job.stop(); - this.schedulerRegistry.deleteCronJob(jobName); + this.schedulerRegistry.deleteCronJob(schedularId); } }, null, // onComplete callback false, // start - we'll call start() manually timezone, // Set timezone to UTC ); - this.schedulerRegistry.addCronJob(jobName, job); + this.schedulerRegistry.addCronJob(schedularId, job); job.start(); return true; } catch (error) { this.logger.error( - `Failed to create scheduler job ${jobName}: ${error.message}`, + `Failed to create scheduler job ${schedularId}: ${error.message}`, error.stack ); return false; diff --git a/src/modules/workspace/services/testflow.service.ts b/src/modules/workspace/services/testflow.service.ts index b61f10890..271f232f9 100644 --- a/src/modules/workspace/services/testflow.service.ts +++ b/src/modules/workspace/services/testflow.service.ts @@ -151,7 +151,6 @@ export class TestflowService implements OnModuleInit { cronExpression: _cronExpression, }); }, - schedule.schedularName, cronExpression, schedule.id, "UTC", @@ -282,9 +281,9 @@ export class TestflowService implements OnModuleInit { cronExpression: _cronExpression, }); }, - schedular.schedularName, cronExpression, scheduleId, + "UTC", ); } } @@ -640,7 +639,6 @@ export class TestflowService implements OnModuleInit { cronExpression: _cronExpression, }); }, - jobName, cronExpression, schedulerId, "UTC",