Service Now - ATF - set FileAttachment on record

Thursday May 21, 2020

The FileAttachment type is new to ServiceNow, but it’s a pain in the ass to use. When we use ATF with a required FileAttachment, there’s no clear way in ATF to set a value for this field. If it’s required on a form, we need a way to set it to we can carry on.

First, we should understand exactly how the attachments are stored and determine the filename for the particular field we are working with - more on that here

Method

How are we going to do this?

We are going to use a server-side script run via ATF to set the value on our record. The process is:

  1. Determine the table name for the field (more on that here)
  2. Create the record via a normal ATF form step
  3. Save the record
  4. Create an ATF test step to run a server-side script
  5. Attach a file to the ATF test step that we will use to attach to the test record
  6. Run server-side script to copy the attachment from the ATF step to the record created in step 2
  7. Update the table name in the attachment and set the field value to point to the attachment

Code

Now, we know our table name (test_table), and our field’s table name (ZZ_YYtest_table). We also get our ATF test step’s sys_id (to find the attachment from step 4 above).

Now all we need to do is write the script to do steps 5 & 6 above:

function copyAttachmentToGlideRecord(attachmentName, attachmentContentType, attachmentContentStream, targetGlideRecord) {
    var gsa = new GlideSysAttachment();
    gsa.writeContentStream(
        targetGlideRecord,
        attachmentName,
        attachmentContentType,
        attachmentContentStream
    );

    var attachment = new GlideRecord('sys_attachment');
    attachment.addQuery('file_name', attachmentName);
    attachment.addQuery('content_type', attachmentContentType);
    attachment.addQuery('table_sys_id', targetGlideRecord.getValue('sys_id'));
    attachment.query();
    if (attachment.next()) {
        return attachment;
    }
    throw ("Error adding attachment!");
}

(function(outputs, steps, stepResult, assertEqual) {
    var createConceptStepSysId = 'ed3cf53fdb7050502c071f83059619d1'; // Step 8 - Submit a form
    var thisStepSysId = 'ebfdf573dbb050502c071f8305961936';

    var createConceptStep = steps(createConceptStepSysId);
    var conceptSysId = createConceptStep.record_id;

    var targetGlideRecord = new GlideRecord("test_table");
    if (!targetGlideRecord.get(conceptSysId)) {
        throw ("Cannot find record created by test with sys_id: " + conceptSysId);
    }

    var sourceAttachmentGlideRecord = new GlideRecord('sys_attachment');
    if (!sourceAttachmentGlideRecord.get('table_sys_id', thisStepSysId)) {
        throw ("You need to attach a file to this ATF test step and make sure the sys_id is correct: " + thisStepSysId);
    }
    
    var fileName = sourceAttachmentGlideRecord.getValue('file_name');
    var contentType = sourceAttachmentGlideRecord.getValue('content_type');
    var sourceAttachmentSysId = sourceAttachmentGlideRecord.getValue('sys_id');
    var gsa = new GlideSysAttachment();
    
	var attachment = copyAttachmentToGlideRecord(
	    fileName, 
	    contentType, 
	    gsa.getContentStream(sourceAttachmentSysId), 
	    targetGlideRecord
	);
	gs.debug("Attachment created: " + attachment.getValue('sys_id'));
	targetGlideRecord.setValue('design_document', attachment.getValue('sys_id'));
	targetGlideRecord.update();
	gs.debug("Value set successfully");
	
})(outputs, steps, stepResult, assertEqual);

There we go!