function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Connor TothConnor Toth 

ProcessInstanceWorkItem Query Test fails on deploy (but works in sandbox)

Problem/Context:
  • Approval process exists identically on orgs DEV and INT.
  • Test passes on DEV, but fails on deployment validation to INT
  • Test failure on deployment validation is that the SOQL query returns 0 rows.
Attempted Fixes:
  • enable SeeAllData
  • Move around the Test.startTest and Test.stopTest methods
  • Use StepsAndWorkItems related list on ProcessInstance
  • Remove specific approval process Id on test
  • Move data creation out of @TestSetup method
Test Code:
    @TestSetup
    static void before() {
        List<User> userList = createNewUserList(NUM_USERS, false);
        insert new List<User>{userList[PENDING_APPROVER]};
        userList[PENDING_SUBMITTER].CustomObj_Approver__c = userList[PENDING_APPROVER].Id;
        insert new List<User>{userList[PENDING_SUBMITTER]};
        CustomObject__c pendingObj = new CustomObject__c(
            Name = PENDING_OBJ_NAME,
            OwnerId = userList[PENDING_SUBMITTER].Id
        );
        
        insert new List<CustomObject__c>{pendingObj};
        insertApprovalProcesses(userList[PENDING_SUBMITTER], userList[APPROVED_SUBMITTER], pendingPlan, approvedPlan);
    }
    private static void insertApprovalProcesses(User pendingSubmitter, CustomObject__c pendingObj) {
        List<Approval.ProcessRequest> requestList;
        List<Approval.ProcessResult> resultList;
        Approval.ProcessSubmitRequest request;
        
        requestList = new List<Approval.ProcessRequest>();
        request = new Approval.ProcessSubmitRequest();
        request.setObjectId(pendingObj.Id);
        request.setSubmitterId(pendingSubmitter.Id);
        requestList.add(request);
        resultList = Approval.process(requestList);
        for (Approval.ProcessResult result : resultList) {
            System.assert(result.isSuccess(), 'Failed result: ' + result);
        }
    }

@IsTest
static void test() {
        Id pendingApproverId = getUser(PENDING_APPROVER).Id;
        Set<Id> approverIdSet = new Set<Id>{ pendingApproverId };
        List<String> PENDING_STATUSES = new List<String>{null, 'Pending', 'Started'};

        // When
        Test.startTest();
        Map<Id, ProcessInstanceWorkItem> resultMap = [
            SELECT Id, ActorId
            FROM ProcessInstanceWorkItem
            WHERE ActorId IN :approverIdSet
            AND ProcessInstance.Status IN :PENDING_STATUSES
        ];
        Test.stopTest();

        // Then
        System.assert(!resultMap.isEmpty());
}
 
Best Answer chosen by Connor Toth
Connor TothConnor Toth

Problem was that the Approval Process itself was defined to operate based on criteria associated with "Current User". This criteria was different in the two orgs. The Current User is not necessarily the Submitting User; when running tests, the Current User is the person running the test. The resolution to this issue was to run the Approval.process methods in a System.runAs block using the Submitting User.

private static void insertApprovalProcesses(User pendingSubmitter, CustomObject__c pendingObj) {
        List<Approval.ProcessRequest> requestList;
        List<Approval.ProcessResult> resultList;
        Approval.ProcessSubmitRequest request;
        
        requestList = new List<Approval.ProcessRequest>();
        request = new Approval.ProcessSubmitRequest();
        request.setObjectId(pendingObj.Id);
        request.setSubmitterId(pendingSubmitter.Id);
        requestList.add(request);
/////////////////////////////////////////////////////////////////
        System.runAs(pendingSubmitter) {
                resultList = Approval.process(requestList);
        }
////////////////////////////////////////////////////////////////
        for (Approval.ProcessResult result : resultList) {
            System.assert(result.isSuccess(), 'Failed result: ' + result);
        }
    }

All Answers

VinayVinay (Salesforce Developers) 
Hi Connor,

Check below link and try steps mentioned.

https://salesforce.stackexchange.com/questions/148768/how-to-unit-test-query-processinstanceworkitem-without-a-defined-approval-proces

Thanks,
Connor TothConnor Toth
That link does not apply to this situation. I am able to get code coverage and successful testing when the test is run in an org; however, the test is failing in the validation step of deployment from the Salesforce CLI due to the query returning 0 records.
VinayVinay (Salesforce Developers) 
Can you run query on ProcessInstanceWorkItem in destination org to check if you have existing records?

Thanks,
Connor TothConnor Toth

Problem was that the Approval Process itself was defined to operate based on criteria associated with "Current User". This criteria was different in the two orgs. The Current User is not necessarily the Submitting User; when running tests, the Current User is the person running the test. The resolution to this issue was to run the Approval.process methods in a System.runAs block using the Submitting User.

private static void insertApprovalProcesses(User pendingSubmitter, CustomObject__c pendingObj) {
        List<Approval.ProcessRequest> requestList;
        List<Approval.ProcessResult> resultList;
        Approval.ProcessSubmitRequest request;
        
        requestList = new List<Approval.ProcessRequest>();
        request = new Approval.ProcessSubmitRequest();
        request.setObjectId(pendingObj.Id);
        request.setSubmitterId(pendingSubmitter.Id);
        requestList.add(request);
/////////////////////////////////////////////////////////////////
        System.runAs(pendingSubmitter) {
                resultList = Approval.process(requestList);
        }
////////////////////////////////////////////////////////////////
        for (Approval.ProcessResult result : resultList) {
            System.assert(result.isSuccess(), 'Failed result: ' + result);
        }
    }
This was selected as the best answer