From d205ccbc6fbf0dc96e0e20a40a6aa0faa43447b5 Mon Sep 17 00:00:00 2001 From: soridalac Date: Thu, 6 Aug 2026 14:56:43 -0700 Subject: [PATCH 1/2] fix: add setup[] to json output --- schemas/apex-run-test.json | 60 +++++++++ schemas/logic-get-test.json | 60 +++++++++ schemas/logic-run-test.json | 60 +++++++++ src/reporters/jsonReporter.ts | 32 +++++ test/commands/logic/testHelper.ts | 9 +- .../config/project-scratch-def.json | 36 +++--- test/reporters/jsonReporter.test.ts | 8 ++ test/shared/TestRunService.test.js | 18 +-- test/testData.ts | 119 ++++++++++++++++++ 9 files changed, 371 insertions(+), 31 deletions(-) diff --git a/schemas/apex-run-test.json b/schemas/apex-run-test.json index 28d0fd12..28821dde 100644 --- a/schemas/apex-run-test.json +++ b/schemas/apex-run-test.json @@ -157,6 +157,66 @@ "additionalProperties": false } }, + "setup": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "StackTrace": { + "type": ["string", "null"] + }, + "Message": { + "type": ["string", "null"] + }, + "AsyncApexJobId": { + "type": "string" + }, + "MethodName": { + "type": "string" + }, + "ApexLogId": { + "type": ["string", "null"] + }, + "ApexClass": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "NamespacePrefix": { + "type": "string" + } + }, + "required": ["Id", "Name", "NamespacePrefix"], + "additionalProperties": false + }, + "TestSetupTime": { + "type": "number" + }, + "FullName": { + "type": "string" + } + }, + "required": [ + "Id", + "StackTrace", + "Message", + "AsyncApexJobId", + "MethodName", + "ApexLogId", + "ApexClass", + "TestSetupTime", + "FullName" + ], + "additionalProperties": false + } + }, "coverage": { "type": "object", "properties": { diff --git a/schemas/logic-get-test.json b/schemas/logic-get-test.json index fc6191ac..0600a8c5 100644 --- a/schemas/logic-get-test.json +++ b/schemas/logic-get-test.json @@ -147,6 +147,66 @@ "additionalProperties": false } }, + "setup": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "StackTrace": { + "type": ["string", "null"] + }, + "Message": { + "type": ["string", "null"] + }, + "AsyncApexJobId": { + "type": "string" + }, + "MethodName": { + "type": "string" + }, + "ApexLogId": { + "type": ["string", "null"] + }, + "ApexClass": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "NamespacePrefix": { + "type": "string" + } + }, + "required": ["Id", "Name", "NamespacePrefix"], + "additionalProperties": false + }, + "TestSetupTime": { + "type": "number" + }, + "FullName": { + "type": "string" + } + }, + "required": [ + "Id", + "StackTrace", + "Message", + "AsyncApexJobId", + "MethodName", + "ApexLogId", + "ApexClass", + "TestSetupTime", + "FullName" + ], + "additionalProperties": false + } + }, "coverage": { "type": "object", "properties": { diff --git a/schemas/logic-run-test.json b/schemas/logic-run-test.json index 28d0fd12..28821dde 100644 --- a/schemas/logic-run-test.json +++ b/schemas/logic-run-test.json @@ -157,6 +157,66 @@ "additionalProperties": false } }, + "setup": { + "type": "array", + "items": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "StackTrace": { + "type": ["string", "null"] + }, + "Message": { + "type": ["string", "null"] + }, + "AsyncApexJobId": { + "type": "string" + }, + "MethodName": { + "type": "string" + }, + "ApexLogId": { + "type": ["string", "null"] + }, + "ApexClass": { + "type": "object", + "properties": { + "Id": { + "type": "string" + }, + "Name": { + "type": "string" + }, + "NamespacePrefix": { + "type": "string" + } + }, + "required": ["Id", "Name", "NamespacePrefix"], + "additionalProperties": false + }, + "TestSetupTime": { + "type": "number" + }, + "FullName": { + "type": "string" + } + }, + "required": [ + "Id", + "StackTrace", + "Message", + "AsyncApexJobId", + "MethodName", + "ApexLogId", + "ApexClass", + "TestSetupTime", + "FullName" + ], + "additionalProperties": false + } + }, "coverage": { "type": "object", "properties": { diff --git a/src/reporters/jsonReporter.ts b/src/reporters/jsonReporter.ts index 639960ac..a432e3b1 100644 --- a/src/reporters/jsonReporter.ts +++ b/src/reporters/jsonReporter.ts @@ -19,6 +19,7 @@ import { ApexTestRunResultStatus } from '@salesforce/apex-node/lib/src/tests/typ export type RunResult = { summary: Summary; tests: CliTestResult[]; + setup?: CliTestSetupResult[]; coverage?: CliCoverageResult; }; @@ -82,6 +83,18 @@ type PerClassCoverage = { NumLinesUncovered: number; }; +type CliTestSetupResult = { + Id: string; + StackTrace: string | null; + Message: string | null; + AsyncApexJobId: string; + MethodName: string; + ApexLogId: string | null; + ApexClass: { Id: string; Name: string; NamespacePrefix: string }; + TestSetupTime: number; + FullName: string; +}; + type CliCoverageResult = { coverage: ClassCoverage[]; records: PerClassCoverage[]; @@ -132,6 +145,25 @@ export class JsonReporter { FullName: test.fullName, ...(includeCategory ? { Category: test.category } : {}), })), + ...(result.setup?.length + ? { + setup: result.setup.map((s) => ({ + Id: s.id, + StackTrace: s.stackTrace, + Message: s.message, + AsyncApexJobId: s.asyncApexJobId, + MethodName: s.methodName, + ApexLogId: s.apexLogId, + ApexClass: { + Id: s.apexClass.id, + Name: s.apexClass.name, + NamespacePrefix: s.apexClass.namespacePrefix, + }, + TestSetupTime: s.testSetupTime, + FullName: s.fullName, + })), + } + : {}), ...(result.codecoverage ? { coverage: this.formatCoverage(result), diff --git a/test/commands/logic/testHelper.ts b/test/commands/logic/testHelper.ts index 79c441a5..a19c8b1a 100644 --- a/test/commands/logic/testHelper.ts +++ b/test/commands/logic/testHelper.ts @@ -77,10 +77,11 @@ export async function setupUnifiedFrameworkProject(): Promise { const sfdxProjectPath = path.join(session.project.dir, 'sfdx-project.json'); // We need to update the sourceApiVersion to 65.0 because the changes in the api are not supported in 64.0 - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const sfdxProject = JSON.parse(fs.readFileSync(sfdxProjectPath, 'utf8')); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument - sfdxProject.sourceApiVersion = parseInt(sfdxProject.sourceApiVersion, 10) < 65 ? '65.0' : sfdxProject.sourceApiVersion; + const sfdxProject = JSON.parse(fs.readFileSync(sfdxProjectPath, 'utf8')) as { + sourceApiVersion: string; + }; + sfdxProject.sourceApiVersion = + parseInt(sfdxProject.sourceApiVersion, 10) < 65 ? '65.0' : sfdxProject.sourceApiVersion; fs.writeFileSync(sfdxProjectPath, JSON.stringify(sfdxProject, null, 2)); execCmd('project:deploy:start --source-dir force-app', { ensureExitCode: 0, cli: 'sf' }); diff --git a/test/nuts/unifiedFrameworkProject/config/project-scratch-def.json b/test/nuts/unifiedFrameworkProject/config/project-scratch-def.json index fdfd74bc..4e7f9088 100644 --- a/test/nuts/unifiedFrameworkProject/config/project-scratch-def.json +++ b/test/nuts/unifiedFrameworkProject/config/project-scratch-def.json @@ -1,21 +1,21 @@ { - "orgName": "Easy Spaces", - "edition": "Developer", - "hasSampleData": false, - "features": ["Walkthroughs", "EnableSetPasswordInApi"], - "settings": { - "lightningExperienceSettings": { - "enableS1DesktopEnabled": true - }, - "mobileSettings": { - "enableS1EncryptedStoragePref2": false - }, - "pathAssistantSettings": { - "pathAssistantEnabled": true - }, - "userEngagementSettings": { - "enableOrchestrationInSandbox": true, - "enableShowSalesforceUserAssist": false - } + "orgName": "Easy Spaces", + "edition": "Developer", + "hasSampleData": false, + "features": ["Walkthroughs", "EnableSetPasswordInApi"], + "settings": { + "lightningExperienceSettings": { + "enableS1DesktopEnabled": true + }, + "mobileSettings": { + "enableS1EncryptedStoragePref2": false + }, + "pathAssistantSettings": { + "pathAssistantEnabled": true + }, + "userEngagementSettings": { + "enableOrchestrationInSandbox": true, + "enableShowSalesforceUserAssist": false } + } } diff --git a/test/reporters/jsonReporter.test.ts b/test/reporters/jsonReporter.test.ts index 279ec52b..69205b86 100644 --- a/test/reporters/jsonReporter.test.ts +++ b/test/reporters/jsonReporter.test.ts @@ -24,6 +24,8 @@ import { failureResult, runWithMixed, mixedResult, + runWithSetup, + jsonWithSetup, } from '../testData.js'; describe('JSON Test Reporter', () => { @@ -50,4 +52,10 @@ describe('JSON Test Reporter', () => { const formatted = reporter.format(runWithMixed); expect(formatted).to.deep.equal(mixedResult); }); + + it('should include @testSetup methods in setup array', () => { + const reporter = new JsonReporter(); + const formatted = reporter.format(runWithSetup); + expect(formatted).to.deep.equal(jsonWithSetup); + }); }); diff --git a/test/shared/TestRunService.test.js b/test/shared/TestRunService.test.js index 42399fb4..b98d080d 100644 --- a/test/shared/TestRunService.test.js +++ b/test/shared/TestRunService.test.js @@ -56,11 +56,11 @@ describe('Common TestRunService behavior', () => { // Spy on buildSyncPayload to verify the testCategory parameter const buildSyncPayloadSpy = sandbox.spy(TestService.prototype, 'buildSyncPayload'); - + // Stub runTestSynchronous to avoid actual execution sandbox.stub(TestService.prototype, 'runTestSynchronous').resolves({ - summary: { - outcome: 'Passed', + summary: { + outcome: 'Passed', testsRan: 1, failRate: '0%', orgId: '00D4xx00000FH4IEAW', @@ -77,9 +77,9 @@ describe('Common TestRunService behavior', () => { username: 'test@example.com', hostname: 'https://na139.salesforce.com', commandTime: '60 ms', - testExecutionTime: '53 ms' + testExecutionTime: '53 ms', }, - tests: [] + tests: [], }); await TestRunService.runTestCommand(context); @@ -113,7 +113,7 @@ describe('Common TestRunService behavior', () => { // Spy on buildAsyncPayload to verify the testCategory parameter (RunLocalTests uses async by default) const buildAsyncPayloadSpy = sandbox.spy(TestService.prototype, 'buildAsyncPayload'); - + // Stub runTestAsynchronous to avoid actual execution sandbox.stub(TestService.prototype, 'runTestAsynchronous').resolves({ testRunId: '707xx0000AUS2gH', @@ -152,7 +152,7 @@ describe('Common TestRunService behavior', () => { // Spy on buildAsyncPayload to verify the testCategory parameter (logic uses async by default) const buildAsyncPayloadSpy = sandbox.spy(TestService.prototype, 'buildAsyncPayload'); - + // Stub runTestAsynchronous to avoid actual execution sandbox.stub(TestService.prototype, 'runTestAsynchronous').resolves({ testRunId: '707xx0000AUS2gH', @@ -190,7 +190,7 @@ describe('Common TestRunService behavior', () => { // Spy on buildAsyncPayload to verify the testCategory parameter (logic uses async by default) const buildAsyncPayloadSpy = sandbox.spy(TestService.prototype, 'buildAsyncPayload'); - + // Stub runTestAsynchronous to avoid actual execution sandbox.stub(TestService.prototype, 'runTestAsynchronous').resolves({ testRunId: '707xx0000AUS2gH', @@ -203,4 +203,4 @@ describe('Common TestRunService behavior', () => { expect(buildAsyncPayloadSpy.firstCall.args[4]).to.equal('Flow,Apex'); }); }); -}); \ No newline at end of file +}); diff --git a/test/testData.ts b/test/testData.ts index d3d97523..abd112df 100644 --- a/test/testData.ts +++ b/test/testData.ts @@ -827,3 +827,122 @@ export const cliWithCoverage = { warnings: [], status: 0, }; + +export const runWithSetup: TestResult = { + summary: { + failRate: '0%', + testsRan: 2, + orgId: '00D4xx00000FH4IEAW', + outcome: ApexTestRunResultStatus.Passed, + passing: 2, + failing: 0, + skipped: 0, + passRate: '100%', + skipRate: '0%', + testStartTime: '2020-08-25T00:48:02.000+0000', + testExecutionTimeInMs: 100, + commandTimeInMs: 120, + testTotalTimeInMs: 150, + testSetupTimeInMs: 50, + hostname: 'https://na139.salesforce.com', + testRunId: '707xx0000AUS2gH', + userId: '005xx000000uEgSAAU', + username: 'test@example.com', + }, + tests: [ + { + id: '07Mxx00000ErgiHUAR', + queueItemId: '709xx000001IlUMQA0', + stackTrace: '', + message: '', + asyncApexJobId: '707xx0000AUS2gHQQT', + methodName: 'testConfig', + outcome: ApexTestResultOutcome.Pass, + apexLogId: null, + apexClass: { + id: '01pxx00000NWwb3AAD', + name: 'MyApexTests', + namespacePrefix: '', + fullName: 'MyApexTests', + }, + runTime: 53, + testTimestamp: '2020-08-25T00:48:02.000+0000', + fullName: 'MyApexTests.testConfig', + }, + ], + setup: [ + { + id: '07Mxx00000ErgiHUAZ', + stackTrace: null, + message: null, + asyncApexJobId: '707xx0000AUS2gHQQT', + methodName: 'testSetup', + apexLogId: null, + apexClass: { + id: '01pxx00000NWwb3AAD', + name: 'MyApexTests', + namespacePrefix: '', + fullName: 'MyApexTests', + }, + testSetupTime: 50, + testTimestamp: '2020-08-25T00:48:01.000+0000', + fullName: 'MyApexTests.testSetup', + }, + ], +}; + +export const jsonWithSetup: RunResult = { + summary: { + commandTime: '120 ms', + failing: 0, + hostname: 'https://na139.salesforce.com', + passing: 2, + skipped: 0, + testTotalTime: '150 ms', + failRate: '0%', + testsRan: 2, + orgId: '00D4xx00000FH4IEAW', + outcome: ApexTestRunResultStatus.Passed, + passRate: '100%', + testStartTime: '2020-08-25T00:48:02.000+0000', + testExecutionTime: '100 ms', + testRunId: '707xx0000AUS2gH', + userId: '005xx000000uEgSAAU', + username: 'test@example.com', + }, + tests: [ + { + Id: '07Mxx00000ErgiHUAR', + QueueItemId: '709xx000001IlUMQA0', + StackTrace: '', + Message: '', + AsyncApexJobId: '707xx0000AUS2gHQQT', + MethodName: 'testConfig', + Outcome: ApexTestResultOutcome.Pass, + ApexClass: { + Id: '01pxx00000NWwb3AAD', + Name: 'MyApexTests', + NamespacePrefix: '', + }, + RunTime: 53, + FullName: 'MyApexTests.testConfig', + }, + ], + setup: [ + { + Id: '07Mxx00000ErgiHUAZ', + StackTrace: null, + Message: null, + AsyncApexJobId: '707xx0000AUS2gHQQT', + MethodName: 'testSetup', + ApexLogId: null, + ApexClass: { + Id: '01pxx00000NWwb3AAD', + Name: 'MyApexTests', + NamespacePrefix: '', + }, + TestSetupTime: 50, + FullName: 'MyApexTests.testSetup', + }, + ], +}; From 2e9228fdb5033876ef26d54d985eea441854632d Mon Sep 17 00:00:00 2001 From: soridalac Date: Thu, 6 Aug 2026 15:13:36 -0700 Subject: [PATCH 2/2] chore: trigger CI