0

my developer createed the following trigger and Apex Test Class. For some reason, the coverage is 0%. I need to deploy it ASAP and he already left for the rest of the week. any help is highly appreciated!

Trigger

    trigger ContentDocumentLinkArchiverTrigger on ContentDocumentLink (after delete) {

    if (Trigger.isAfter) {
        if (Trigger.isDelete) {
            List<Id> dealDocumentsId = new List<Id>();   
            for (ContentDocumentLink cdl : Trigger.old) {
                Id relatedToId = cdl.LinkedEntityId;
                if(relatedToId.getsobjecttype().getDescribe().getName() == 'Deal_Document__c'){
                    dealDocumentsId.add(relatedToId);

                }
            }

            List<Deal_Document__c> deals = [Select Id, Document_Archived_By_OwnBackup__c From  Deal_Document__c where id IN: dealDocumentsId];
            for(Deal_Document__c deal : deals){
                deal.Document_Archived_By_OwnBackup__c = true;
            }

            update deals;
         }
     }




}

Apex Test Class:

    @isTest
class ContentDocumentLinkArchiverHandlerTest{

    @isTest
    private static void testUpdateDealDocumentWithArchivedFiles(){
         Account dealAccount = new Account(
             Name='Test'
         );
         insert dealAccount;

         Contact dealContact = new Contact(
             FirstName='Test', 
             LastName='Test', 
             AccountId=dealAccount.Id
         );
         insert dealContact;

         Opportunity deal = New Opportunity(
             Contact__c=dealContact.Id, 
             CloseDate=Date.Today(), 
             AccountId=dealAccount.Id, 
             Name='Test', 
             StageName='Initial Review');
         insert deal;

         Deal_Document__c dealDocument = new Deal_Document__c(
             Deal__c=deal.Id
         );
             insert dealDocument;


         ContentVersion cv = new ContentVersion(
            Title = 'Test',
            PathOnClient = 'Test.jpg',
            VersionData = blob.valueof('Test Content Data')     
        );
        insert cv;

            ContentVersion contentVersionSelect = [SELECT Id, Title, ContentDocumentId FROM ContentVersion WHERE Id = :cv.Id LIMIT 1];
            List<ContentDocument> documents = [SELECT Id, Title, LatestPublishedVersionId FROM ContentDocument];

             ContentDocumentLink contentlink=new ContentDocumentLink();
             contentlink.LinkedEntityId=dealDocument.id;  
             contentlink.ShareType= 'I';               
             contentlink.ContentDocumentId=documents[0].Id;
             contentlink.Visibility = 'AllUsers'; 
             insert contentlink;
             System.assertEquals(documents.size(), 1);

             delete documents;

            Deal_Document__c  dealDocumentAfterUpdate = [Select Id, Document_Archived_By_OwnBackup__c From Deal_Document__c Where Id=:dealDocument.id Limit 1][0];
            System.assertEquals(dealDocumentAfterUpdate.Document_Archived_By_OwnBackup__c, true);




    }


}

enter image description here Thanks in advance!

  • 4
    Does the test show that it passes, or is there an error message? – Brand0R Dec 19 '19 at 23:52
  • as you can see above, I added a screenshot, the code coverage on the trigger is 0/11 - 0% – Lihod Rachmilevitch Dec 19 '19 at 23:56
  • @LihodRachmilevitch You don't receive code coverage for tests that fail. If you run the test, what do the results actually say? – David Reed Dec 19 '19 at 23:58
  • @LihodRachmilevitch while this certainly isn't the answer you're hoping for, I think this is documented / expected behavior, your test class will never cover that code. See my answer for more info. – Morgan Marchese Dec 20 '19 at 0:34
  • Pro tip if(relatedToId.getsobjecttype().getDescribe().getName() == 'Deal_Document__c') can be simplified to if (relatedToId.getSobjectType() == Deal_Document__c.SobjectType) – cropredy Dec 21 '19 at 6:15
4

This outcome is explained by considering the relationships between ContentDocument and ContentDocumentLink.

It's documented Salesforce behavior that cascade-deletes do not invoke apex triggers on any of the cascade-deleted children, only on the item(s) that were physically deleted.

When you delete a ContentDocument, any related ContentDocumentLinks aren't necessary anymore and are cascade deleted.

Therefore, Salesforce will (natively) never run a delete trigger on ContentDocumentLink when you delete a ContentDocument. Unless you were to explicitly delete a ContentDocumentLink directly, this trigger would never fire.

More Info:

https://developer.salesforce.com/forums/?id=906F00000008x2FIAQ

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_ignoring_operations.htm

Some operations don’t invoke triggers.

Triggers are invoked for data manipulation language (DML) operations that the Java application server initiates or processes. Therefore, some system bulk operations don't invoke triggers. Some examples include:

  • Cascading delete operations. Records that did not initiate a delete don't cause trigger evaluation.

If your intention is to run this logic when your users (or integrations) delete a ContentDocument, you should refactor the trigger to run on delete of ContentDocument rather than ContentDocumentLink, and if you need to work with the ContentDocumentLink child records then you would query for them in the ContentDocument trigger.

Sorry for the bad news.

You can vote for this idea to have this "fixed", but it would require Salesforce to change its stance on cascade delete trigger invocation: https://success.salesforce.com/ideaView?id=0873A000000LqYeQAK

| improve this answer | |
  • The relationship from ContentDocument -> ContentDocumentLink is definitely CascadeDelete, no need to speculate – cropredy Dec 20 '19 at 1:48
  • Fair point, I didn't have time to dig into the relationship so I wasn't comfortable being concrete, but in retrospect, it really wouldn't make sense to leave a Link behind if the associated Document was gone. I'll edit the answer slightly – Morgan Marchese Dec 20 '19 at 15:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.