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
Wei Dong 10Wei Dong 10 

How to write a unit test for ContentDocumentLink as the attachment of EmailMessage?

Hi,

I have an EmailMessage trigger (after insert), I'll do some checks of attachments (Notice my attachments are of ContentDocumentLink!)
The code looks like this following:
private static void doNotAllowProfilesSendEmailsWithAttachments(List<EmailMessage> newMessages) {

        if (!validateCurrentUserRule()) {
            System.debug('====User without the permission===');
            String digitalSignature = [SELECT CA_Digital_Signature__c FROM User WHERE Id = :UserInfo.getUserId()][0].CA_Digital_Signature__c;
            System.debug('===digitalSignature===='+digitalSignature);
            System.debug('===newMessages===='+newMessages);
            Set<String> msgIdSet = new Set<String>();
            Map<String, Set<String>> attMap = new Map<String, Set<String>>();
            for(EmailMessage msg:newMessages){
                msgIdSet.add(msg.Id);
            }
            System.debug('===msgIdSet===='+msgIdSet);
            for(ContentDocumentLink cdl :[SELECT Id, LinkedEntityId, ContentDocumentId, ContentDocument.title FROM ContentDocumentLink where LinkedEntityId IN :msgIdSet]){
                if(!attMap.containsKey(cdl.LinkedEntityId)){
                    attMap.put(cdl.LinkedEntityId, new Set<string>());
                }
                attMap.get(cdl.LinkedEntityId).add(cdl.ContentDocument.title);
            }
            System.debug('===attMap===='+attMap);
            for(EmailMessage msg:newMessages){
                if(msg.Incoming == FALSE){
                    for(String title : attMap.get(msg.Id)){
                        if(!digitalSignature.contains(title)){
                            msg.addError('You may not include an attachment in outbound emails.');
                            break;
                        }
                    }
                }
            }
        }
    }
And then my Unit test is:
@IsTest
    public static void doNotAllowProfilesSendEmailsWithAttachments_TestWrong() {

        String[]emails = new String[]{
                'wei.dong@pwc.com'
        };
        Boolean isSentSuccessful = true;

        // Test when we attach an attachment with 'Stand User'
        Profile p = [SELECT Id FROM Profile WHERE Name = 'Consumer Care Agent'];
        User u = new User(Alias = 'standt', Email = 'standarduser@testorg.com',
                EmailEncodingKey = 'UTF-8', LastName = 'Testing', LanguageLocaleKey = 'en_US',
                LocaleSidKey = 'en_US', ProfileId = p.Id,
                TimeZoneSidKey = 'America/Los_Angeles',
                UserName = 'standarduser_dongwei_test@testorg.com');

        Test.startTest();

        System.runAs(u) {

            // Insert a new contact for inner search contact ID
            Contact newContact = new Contact();
            newContact.LastName = 'Last Name';
            insert newContact;

            // 1. Create a Document as an attachment
            Document doc = new Document();
            doc.Name = 'Test document';
            doc.Body = Blob.valueOf('Test me');
            doc.ContentType = 'text/plain';
            doc.Type = 'txt';
            doc.FolderId = UserInfo.getUserId();
            insert doc;

            // 2. Preparing to attach the attachment
            Messaging.EmailFileAttachment file = new Messaging.EmailFileAttachment();
            file.setContentType('application/txt');
            file.setFileName('testAttachment.txt');
            // Make this as an attachment
            file.setInline(false);
            file.Body = doc.Body;


            // 3. Successfully sent
            Map<String, String> replacers = new Map<String, String>();
            replacers.put('dongwei', '');
            isSentSuccessful = CA_Utility.sendSingleEmail(emails,
                    'Test', 'Test body',replacers, 'DongWei',
                    true, new Messaging.EmailFileAttachment[]{
                            file
                    });
            System.assert(isSentSuccessful);

            EmailMessage email = new EmailMessage();
            email.FromAddress = 'test@abc.org';
            email.Incoming = True;
            email.ToAddress = 'test@xyz.org';
            email.Subject = 'Test email';
            email.HtmlBody = 'Test email body';

            Blob beforeblob = Blob.valueOf('Unit Test Attachment Body');

            ContentVersion cv = new ContentVersion();
            cv.title = 'Bad Signature Here';
            cv.PathOnClient = 'test';
            cv.VersionData = beforeblob;
            insert cv;

            ContentVersion testContent = [SELECT id, ContentDocumentId FROM ContentVersion where Id = :cv.Id];

            ContentDocumentLink contentlink = new ContentDocumentLink();
            contentlink.LinkedEntityId = email.Id;
            contentlink.ShareType = 'V';
            contentlink.ContentDocumentId = testcontent.ContentDocumentId;
            contentlink.LinkedEntityId = email.Id;

            email.ContentDocumentLinks.add(contentlink);
            insert email;
        }

        Test.stopTest();
    }
I tried to use Email attach to attach an attachments, but nothing hopes to improve the coverage; And when I tried to use "ContentDocumentLink" it still doesn't help. 

Any one can help me to improve the coverage about entering the 'for' of ContentDocumentLink in my trigger?
David EntremontDavid Entremont

If the loop doesn't execute there are no records, and I can see that you have not inserted the record in the unit test. Perhaps you need to add a database insert for contentLink on Line 76 of the test.

My understanding is that the insert on Line 78 will not recursively insert sobjects of a different type. So the insert on Line 78 is only performing DML on the first dimension of the array.

David EntremontDavid Entremont
If doing the above, you will need to refactor a bit. You can't get email.Id on Line 72 until email has been inserted.
Wei Dong 10Wei Dong 10
>>If doing the above, you will need to refactor a bit. You can't get email.Id on Line 72 until email has been inserted.
That's the POINT. so how?
Wei Dong 10Wei Dong 10
So what should I do now? 
David EntremontDavid Entremont
You can control content sharing through Permission Sets. Check these out: Create Public Links, Create Content Deliveries, Select Files from Salesforce.
There is not a permission that distincts between Send Email and Send Email (but no attachments), so try something like this: https://success.salesforce.com/answers?id=90630000000h2gZAAQ