diff --git a/lib/MetadataTypeDefinitions.js b/lib/MetadataTypeDefinitions.js index d34eeeef7..7b26654c2 100644 --- a/lib/MetadataTypeDefinitions.js +++ b/lib/MetadataTypeDefinitions.js @@ -29,6 +29,7 @@ import query from './metadataTypes/definitions/Query.definition.js'; import role from './metadataTypes/definitions/Role.definition.js'; import script from './metadataTypes/definitions/Script.definition.js'; import sendClassification from './metadataTypes/definitions/SendClassification.definition.js'; +import senderProfile from './metadataTypes/definitions/SenderProfile.definition.js'; import transactionalEmail from './metadataTypes/definitions/TransactionalEmail.definition.js'; import transactionalPush from './metadataTypes/definitions/TransactionalPush.definition.js'; import transactionalSMS from './metadataTypes/definitions/TransactionalSMS.definition.js'; @@ -69,6 +70,7 @@ export default { role, script, sendClassification, + senderProfile, transactionalEmail, transactionalPush, transactionalSMS, diff --git a/lib/MetadataTypeInfo.js b/lib/MetadataTypeInfo.js index 17ae9d198..b0be83eaa 100644 --- a/lib/MetadataTypeInfo.js +++ b/lib/MetadataTypeInfo.js @@ -29,6 +29,7 @@ import query from './metadataTypes/Query.js'; import role from './metadataTypes/Role.js'; import script from './metadataTypes/Script.js'; import sendClassification from './metadataTypes/SendClassification.js'; +import senderProfile from './metadataTypes/SenderProfile.js'; import transactionalEmail from './metadataTypes/TransactionalEmail.js'; import transactionalPush from './metadataTypes/TransactionalPush.js'; import transactionalSMS from './metadataTypes/TransactionalSMS.js'; @@ -69,6 +70,7 @@ export default { role, script, sendClassification, + senderProfile, transactionalEmail, transactionalPush, transactionalSMS, diff --git a/lib/metadataTypes/SenderProfile.js b/lib/metadataTypes/SenderProfile.js new file mode 100644 index 000000000..41ebfedd4 --- /dev/null +++ b/lib/metadataTypes/SenderProfile.js @@ -0,0 +1,115 @@ +'use strict'; + +import MetadataType from './MetadataType.js'; +import { Util } from '../util/util.js'; + +/** + * @typedef {import('../../types/mcdev.d.js').BuObject} BuObject + * @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract + * @typedef {import('../../types/mcdev.d.js').CodeExtractItem} CodeExtractItem + * @typedef {import('../../types/mcdev.d.js').MetadataTypeItem} MetadataTypeItem + * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemDiff} MetadataTypeItemDiff + * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemObj} MetadataTypeItemObj + * @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap + * @typedef {import('../../types/mcdev.d.js').MetadataTypeMapObj} MetadataTypeMapObj + * @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams + * @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap + */ + +/** + * SenderProfile MetadataType + * + * @augments MetadataType + */ +class SenderProfile extends MetadataType { + /** + * Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata + * + * @param {string} retrieveDir Directory where retrieved metadata directory will be saved + * @param {void} [_] unused parameter + * @param {void} [__] unused parameter + * @param {void} [___] unused parameter + * @param {string} [key] customer key of single item to retrieve + * @returns {Promise.} Promise of metadata + */ + static retrieve(retrieveDir, _, __, ___, key) { + /** @type {SoapRequestParams} */ + let requestParams = null; + if (key) { + requestParams = { + filter: { + leftOperand: 'CustomerKey', + operator: 'equals', + rightOperand: key, + }, + }; + } + return super.retrieveSOAP(retrieveDir, null, requestParams); + } + /** + * Updates a single item + * + * @param {MetadataTypeItem} metadataItem a single item + * @returns {Promise} Promise + */ + static update(metadataItem) { + return super.updateSOAP(metadataItem); + } + + /** + * Creates a single item + * + * @param {MetadataTypeItem} metadataItem a single item + * @returns {Promise} Promise + */ + static create(metadataItem) { + return super.createSOAP(metadataItem); + } + + /** + * Delete a metadata item from the specified business unit + * + * @param {string} customerKey Identifier of data extension + * @returns {Promise.} deletion success status + */ + static deleteByKey(customerKey) { + return super.deleteByKeySOAP(customerKey); + } + + /** + * prepares a single item for deployment + * + * @param {MetadataTypeItem} metadata a single query activity + * @returns {Promise.} Promise + */ + static async preDeployTasks(metadata) { + if ( + metadata.UseDefaultRMMRules && + (metadata.AutoForwardToEmailAddress !== '' || metadata.AutoForwardToName !== '') + ) { + Util.logger.warn( + ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${ + metadata[this.definition.keyField] + }): AutoForwardToEmailAddress and AutoForwardToName will be ignored because UseDefaultRMMRules is set to true; setting UseDefaultRMMRules to false` + ); + metadata.UseDefaultRMMRules = false; + } else if ( + !metadata.UseDefaultRMMRules && + (metadata.AutoForwardToEmailAddress === '' || metadata.AutoForwardToName === '') + ) { + Util.logger.warn( + ` - ${this.definition.type} ${metadata[this.definition.nameField]} (${ + metadata[this.definition.keyField] + }): AutoForwardToEmailAddress and AutoForwardToName are required when UseDefaultRMMRules is set to false; setting UseDefaultRMMRules to true` + ); + metadata.UseDefaultRMMRules = true; + } + return metadata; + } +} + +// Assign definition & cache to static attributes +import MetadataTypeDefinitions from '../MetadataTypeDefinitions.js'; +SenderProfile.definition = MetadataTypeDefinitions.senderProfile; + +export default SenderProfile; diff --git a/lib/metadataTypes/definitions/SenderProfile.definition.js b/lib/metadataTypes/definitions/SenderProfile.definition.js new file mode 100644 index 000000000..53957a1e0 --- /dev/null +++ b/lib/metadataTypes/definitions/SenderProfile.definition.js @@ -0,0 +1,184 @@ +export default { + bodyIteratorField: 'Results', + dependencies: [], + filter: {}, + hasExtended: false, + idField: 'ObjectID', + keyIsFixed: false, + keyField: 'CustomerKey', + nameField: 'Name', + createdDateField: 'CreatedDate', + createdNameField: null, + lastmodDateField: 'ModifiedDate', + lastmodNameField: null, + restPagination: false, + type: 'senderProfile', + typeDescription: 'Specifies the From information for a send in a central location', + typeRetrieveByDefault: false, + typeName: 'Sender Profile', + fields: { + 'Client.ID': { + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + CreatedDate: { + isCreateable: false, + isUpdateable: false, + retrieving: true, + template: false, + }, + ModifiedDate: { + isCreateable: false, + isUpdateable: false, + retrieving: true, + template: false, + }, + CustomerKey: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + ObjectID: { + isCreateable: false, + isUpdateable: true, + retrieving: true, + template: false, + }, + Name: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + Description: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + PartnerKey: { + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + PartnerProperties: { + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + + AutoForwardToEmailAddress: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + AutoForwardToName: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + AutoForwardTriggeredSend: { + // not supported + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + AutoReply: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + AutoReplyTriggeredSend: { + // not supported + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + DataRetentionPeriodLength: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + DataRetentionPeriodUnitOfMeasure: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + DirectForward: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + FromAddress: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + FromName: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + ID: { + // not supported + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + ReplyManagementRuleSet: { + // not supported + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + ReplyToAddress: { + // not supported + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + ReplyToDisplayName: { + // not supported + isCreateable: false, + isUpdateable: false, + retrieving: false, + template: false, + }, + SenderHeaderEmailAddress: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + SenderHeaderName: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + UseDefaultRMMRules: { + isCreateable: true, + isUpdateable: true, + retrieving: true, + template: true, + }, + }, +}; diff --git a/test/mockRoot/deploy/testInstance/testBU/senderProfile/testExisting_senderProfile.senderProfile-meta.json b/test/mockRoot/deploy/testInstance/testBU/senderProfile/testExisting_senderProfile.senderProfile-meta.json new file mode 100644 index 000000000..949919fbc --- /dev/null +++ b/test/mockRoot/deploy/testInstance/testBU/senderProfile/testExisting_senderProfile.senderProfile-meta.json @@ -0,0 +1,14 @@ +{ + "CustomerKey": "testExisting_senderProfile", + "Name": "testExisting_senderProfile", + "Description": "updated via deploy", + "FromName": "Jörn Berkefeld", + "FromAddress": "joern.berkefeld@accenture.com", + "UseDefaultRMMRules": false, + "AutoForwardToEmailAddress": "joern.berkefeld@accenture.com", + "AutoForwardToName": "Jörn Berkefeld", + "DirectForward": false, + "AutoReply": false, + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "" +} diff --git a/test/mockRoot/deploy/testInstance/testBU/senderProfile/testNew_senderProfile.senderProfile-meta.json b/test/mockRoot/deploy/testInstance/testBU/senderProfile/testNew_senderProfile.senderProfile-meta.json new file mode 100644 index 000000000..46f07378e --- /dev/null +++ b/test/mockRoot/deploy/testInstance/testBU/senderProfile/testNew_senderProfile.senderProfile-meta.json @@ -0,0 +1,14 @@ +{ + "CustomerKey": "testNew_senderProfile", + "Name": "testNew_senderProfile", + "Description": "created on deploy", + "FromName": "Jörn Berkefeld", + "FromAddress": "joern.berkefeld@accenture.com", + "UseDefaultRMMRules": false, + "AutoForwardToEmailAddress": "joern.berkefeld@accenture.com", + "AutoForwardToName": "Jörn Berkefeld", + "DirectForward": false, + "AutoReply": false, + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "" +} diff --git a/test/resources/9999999/senderProfile/build-expected.json b/test/resources/9999999/senderProfile/build-expected.json new file mode 100644 index 000000000..b4e1838f5 --- /dev/null +++ b/test/resources/9999999/senderProfile/build-expected.json @@ -0,0 +1,14 @@ +{ + "AutoForwardToEmailAddress": "", + "AutoForwardToName": "", + "AutoReply": false, + "CustomerKey": "testTemplated_senderProfile", + "Description": "Send from joern.berkefeld@accenture.com", + "DirectForward": false, + "FromAddress": "joern.berkefeld@accenture.com", + "FromName": "Jörn Berkefeld", + "Name": "testTemplated_senderProfile", + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "", + "UseDefaultRMMRules": true +} diff --git a/test/resources/9999999/senderProfile/create-response.xml b/test/resources/9999999/senderProfile/create-response.xml new file mode 100644 index 000000000..24c20420c --- /dev/null +++ b/test/resources/9999999/senderProfile/create-response.xml @@ -0,0 +1,49 @@ + + + + CreateResponse + urn:uuid:da5fb2ee-2ca9-4f56-a9e8-2b98d43379f7 + urn:uuid:3cbd2577-f0e6-4593-8657-e1f48d94624c + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + + 2024-04-12T12:53:28Z + 2024-04-12T12:58:28Z + + + + + + + OK + SenderProfile created + 0 + 0 + 70accba4-cbf8-ee11-a5c8-5cba2c6fc270 + + + 70accba4-cbf8-ee11-a5c8-5cba2c6fc270 + testNew_senderProfile + testNew_senderProfile + created on deploy + Jörn Berkefeld + joern.berkefeld@accenture.com + false + joern.berkefeld@accenture.com + Jörn Berkefeld + false + false + + + + + b6be1480-01a4-4e48-9f47-06bf51a301c1 + OK + + + diff --git a/test/resources/9999999/senderProfile/delete-response.xml b/test/resources/9999999/senderProfile/delete-response.xml new file mode 100644 index 000000000..2be198379 --- /dev/null +++ b/test/resources/9999999/senderProfile/delete-response.xml @@ -0,0 +1,36 @@ + + + + DeleteResponse + urn:uuid:9d089538-9132-421c-b905-827dc760447b + urn:uuid:2dbd051c-b714-4302-bb66-53d0916620ed + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + + 2024-04-12T13:05:55Z + 2024-04-12T13:10:55Z + + + + + + + OK + SenderProfile deleted + 0 + + + + testExisting_senderProfile + + + 0387ba17-c330-4239-a2dd-c0e15f968476 + OK + + + diff --git a/test/resources/9999999/senderProfile/get-expected.json b/test/resources/9999999/senderProfile/get-expected.json new file mode 100644 index 000000000..e92fcba48 --- /dev/null +++ b/test/resources/9999999/senderProfile/get-expected.json @@ -0,0 +1,16 @@ +{ + "CreatedDate": "2021-08-03T11:14:00", + "ModifiedDate": "2021-08-03T11:14:00", + "CustomerKey": "testExisting_senderProfile", + "Name": "testExisting_senderProfile", + "Description": "Send from joern.berkefeld@accenture.com", + "FromName": "Jörn Berkefeld", + "FromAddress": "joern.berkefeld@accenture.com", + "UseDefaultRMMRules": true, + "AutoForwardToEmailAddress": "", + "AutoForwardToName": "", + "DirectForward": false, + "AutoReply": false, + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "" +} diff --git a/test/resources/9999999/senderProfile/patch-expected.json b/test/resources/9999999/senderProfile/patch-expected.json new file mode 100644 index 000000000..c82bbdecc --- /dev/null +++ b/test/resources/9999999/senderProfile/patch-expected.json @@ -0,0 +1,14 @@ +{ + "AutoForwardToEmailAddress": "joern.berkefeld@accenture.com", + "AutoForwardToName": "Jörn Berkefeld", + "AutoReply": false, + "CustomerKey": "testExisting_senderProfile", + "Description": "updated via deploy", + "DirectForward": false, + "FromAddress": "joern.berkefeld@accenture.com", + "FromName": "Jörn Berkefeld", + "Name": "testExisting_senderProfile", + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "", + "UseDefaultRMMRules": false +} diff --git a/test/resources/9999999/senderProfile/post-expected.json b/test/resources/9999999/senderProfile/post-expected.json new file mode 100644 index 000000000..8286574c4 --- /dev/null +++ b/test/resources/9999999/senderProfile/post-expected.json @@ -0,0 +1,14 @@ +{ + "AutoForwardToEmailAddress": "joern.berkefeld@accenture.com", + "AutoForwardToName": "Jörn Berkefeld", + "AutoReply": false, + "CustomerKey": "testNew_senderProfile", + "Description": "created on deploy", + "DirectForward": false, + "FromAddress": "joern.berkefeld@accenture.com", + "FromName": "Jörn Berkefeld", + "Name": "testNew_senderProfile", + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "", + "UseDefaultRMMRules": false +} diff --git a/test/resources/9999999/senderProfile/retrieve-response.xml b/test/resources/9999999/senderProfile/retrieve-response.xml new file mode 100644 index 000000000..8ed9de26c --- /dev/null +++ b/test/resources/9999999/senderProfile/retrieve-response.xml @@ -0,0 +1,44 @@ + + + + RetrieveResponse + urn:uuid:cbecb68a-7bdf-417e-8fce-bef6c72febbd + urn:uuid:2e88f8d2-82e7-4e2d-b780-b885a2205a0f + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + + 2024-04-12T12:20:37Z + 2024-04-12T12:25:37Z + + + + + + OK + 4c6f37a1-7ab4-47a1-b341-f9912462ee97 + + + 2021-08-03T11:14:00 + 2021-08-03T11:14:00 + a75d452b-7ef4-eb11-b82d-48df37d1da95 + testExisting_senderProfile + testExisting_senderProfile + Send from joern.berkefeld@accenture.com + Jörn Berkefeld + joern.berkefeld@accenture.com + true + + + false + false + + + + + + diff --git a/test/resources/9999999/senderProfile/template-expected.json b/test/resources/9999999/senderProfile/template-expected.json new file mode 100644 index 000000000..2dee8a079 --- /dev/null +++ b/test/resources/9999999/senderProfile/template-expected.json @@ -0,0 +1,14 @@ +{ + "AutoForwardToEmailAddress": "", + "AutoForwardToName": "", + "AutoReply": false, + "CustomerKey": "{{{prefix}}}senderProfile", + "Description": "Send from joern.berkefeld@accenture.com", + "DirectForward": false, + "FromAddress": "joern.berkefeld@accenture.com", + "FromName": "Jörn Berkefeld", + "Name": "{{{prefix}}}senderProfile", + "SenderHeaderEmailAddress": "", + "SenderHeaderName": "", + "UseDefaultRMMRules": true +} diff --git a/test/resources/9999999/senderProfile/update-response.xml b/test/resources/9999999/senderProfile/update-response.xml new file mode 100644 index 000000000..f2a4fa26a --- /dev/null +++ b/test/resources/9999999/senderProfile/update-response.xml @@ -0,0 +1,47 @@ + + + + UpdateResponse + urn:uuid:4ba5314f-13c0-4fcf-a193-f6160531acd6 + urn:uuid:4f56d229-63e7-4d8b-9bfe-1ace0c596056 + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + + 2022-04-19T20:03:41Z + 2024-04-12T12:58:29Z + + + + + + + OK + SenderProfile updated + 0 + + + + testExisting_senderProfile + testExisting_senderProfile + updated via deploy + Jörn Berkefeld + joern.berkefeld@accenture.com + false + joern.berkefeld@accenture.com + Jörn Berkefeld + false + false + + + + + ef6e2933-b767-47ea-a1c4-d3dc44674a56 + OK + + + diff --git a/test/type.senderProfile.test.js b/test/type.senderProfile.test.js new file mode 100644 index 000000000..64cbfa330 --- /dev/null +++ b/test/type.senderProfile.test.js @@ -0,0 +1,151 @@ +import * as chai from 'chai'; +const assert = chai.assert; + +import chaiFiles from 'chai-files'; +import cache from '../lib/util/cache.js'; +import * as testUtils from './utils.js'; +import handler from '../lib/index.js'; +chai.use(chaiFiles); + +describe('type: senderProfile', () => { + beforeEach(() => { + testUtils.mockSetup(); + }); + + afterEach(() => { + testUtils.mockReset(); + }); + + describe('Retrieve ================', () => { + it('Should retrieve a senderProfile', async () => { + // WHEN + await handler.retrieve('testInstance/testBU', ['senderProfile']); + // THEN + assert.equal(process.exitCode, 0, 'retrieve should not have thrown an error'); + // get results from cache + const result = cache.getCache(); + assert.equal( + result.senderProfile ? Object.keys(result.senderProfile).length : 0, + 1, + 'only one senderProfile expected' + ); + assert.deepEqual( + await testUtils.getActualJson('testExisting_senderProfile', 'senderProfile'), + await testUtils.getExpectedJson('9999999', 'senderProfile', 'get'), + 'returned JSON was not equal expected' + ); + assert.equal( + testUtils.getAPIHistoryLength(), + 1, + 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests' + ); + return; + }); + }); + + describe('Deploy ================', () => { + beforeEach(() => { + testUtils.mockSetup(true); + }); + + it('Should create & upsert a senderProfile', async () => { + // WHEN + + await handler.deploy('testInstance/testBU', ['senderProfile']); + // THEN + assert.equal(process.exitCode, 0, 'deploy should not have thrown an error'); + // get results from cache + const result = cache.getCache(); + assert.equal( + result.senderProfile ? Object.keys(result.senderProfile).length : 0, + 2, + 'two senderProfiles expected' + ); + // confirm created item + assert.deepEqual( + await testUtils.getActualJson('testNew_senderProfile', 'senderProfile'), + await testUtils.getExpectedJson('9999999', 'senderProfile', 'post'), + 'returned new-JSON was not equal expected for insert senderProfile' + ); + // confirm updated item + assert.deepEqual( + await testUtils.getActualJson('testExisting_senderProfile', 'senderProfile'), + await testUtils.getExpectedJson('9999999', 'senderProfile', 'patch'), + 'returned existing-JSON was not equal expected for update senderProfile' + ); + // check number of API calls + assert.equal( + testUtils.getAPIHistoryLength(), + 3, + 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests' + ); + return; + }); + }); + + describe('Templating ================', () => { + it('Should create a senderProfile template via buildTemplate and build it', async () => { + // download first before we test buildTemplate + await handler.retrieve('testInstance/testBU', ['senderProfile']); + // buildTemplate + const result = await handler.buildTemplate( + 'testInstance/testBU', + 'senderProfile', + ['testExisting_senderProfile'], + 'testSourceMarket' + ); + assert.equal(process.exitCode, 0, 'buildTemplate should not have thrown an error'); + assert.equal( + result.senderProfile ? Object.keys(result.senderProfile).length : 0, + 1, + 'only one senderProfile expected' + ); + assert.deepEqual( + await testUtils.getActualTemplateJson( + 'testExisting_senderProfile', + 'senderProfile' + ), + await testUtils.getExpectedJson('9999999', 'senderProfile', 'template'), + 'returned template JSON was not equal expected' + ); + // buildDefinition + await handler.buildDefinition( + 'testInstance/testBU', + 'senderProfile', + 'testExisting_senderProfile', + 'testTargetMarket' + ); + assert.equal( + process.exitCode, + false, + 'buildDefinition should not have thrown an error' + ); + assert.deepEqual( + await testUtils.getActualDeployJson('testTemplated_senderProfile', 'senderProfile'), + await testUtils.getExpectedJson('9999999', 'senderProfile', 'build'), + 'returned deployment JSON was not equal expected' + ); + assert.equal( + testUtils.getAPIHistoryLength(), + 1, + 'Unexpected number of requests made. Run testUtils.logAPIHistoryDebug() to see the requests' + ); + return; + }); + }); + + describe('Delete ================', () => { + it('Should delete the item', async () => { + // WHEN + const isDeleted = await handler.deleteByKey( + 'testInstance/testBU', + 'senderProfile', + 'testExisting_senderProfile' + ); + // THEN + assert.equal(process.exitCode, 0, 'deleteByKey should not have thrown an error'); + assert.equal(isDeleted, true, 'deleteByKey should have returned true'); + return; + }); + }); +});