Repository: Azure/azure-functions-durable-js
Pull request #44 (2019-01-23 19:05:08)

durable-functions 1.1.4 Release Payload
Merge branch **dev** into **master** for 1.1.4 release.


Patch:
diff --git a/package.json b/package.json
index 43ff70a..c43029b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "durable-functions",
-  "version": "1.1.3",
+  "version": "1.1.4",
   "description": "Durable Functions library for Node.js Azure Functions",
   "license": "MIT",
   "repository": "github:Azure/azure-functions-durable-js",
diff --git a/samples/extensions.csproj b/samples/extensions.csproj
index 519ac80..a669809 100644
--- a/samples/extensions.csproj
+++ b/samples/extensions.csproj
@@ -5,7 +5,7 @@
 	<DefaultItemExcludes>**</DefaultItemExcludes>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.7.0" />
+    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.DurableTask" Version="1.7.1" />
     <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="3.0.0" />
     <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Twilio" Version="3.0.0" />
     <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.0.0" />
diff --git a/samples/package-lock.json b/samples/package-lock.json
index 9fc011c..36df09e 100644
--- a/samples/package-lock.json
+++ b/samples/package-lock.json
@@ -1,13 +1,18 @@
 {
   "name": "durable-functions-samples",
-  "version": "1.1.0",
+  "version": "1.1.3",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "@types/lodash": {
+      "version": "4.14.120",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.120.tgz",
+      "integrity": "sha512-jQ21kQ120mo+IrDs1nFNVm/AsdFxIx2+vZ347DbogHJPd/JzKNMOqU6HCYin1W6v8l5R9XSO2/e9cxmn7HAnVw=="
+    },
     "@types/validator": {
-      "version": "9.4.3",
-      "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.3.tgz",
-      "integrity": "sha512-D4zRrAs2pTg5cva6+hJ6GrQlb/UX5NxNtk/da3Gw27enoLvbRMTTloZ1w6CCqc+kHyZvT3DsyWQZ8baTGgSg0g=="
+      "version": "9.4.4",
+      "resolved": "https://registry.npmjs.org/@types/validator/-/validator-9.4.4.tgz",
+      "integrity": "sha512-7bWNKQ3lDMhRS2lxe1aHGTBijZ/a6wQfZmCtKJDefpb81sYd+FrfNqj6Gda1Tcw8bYK0gG1CVuNLWV2JS7K8Dw=="
     },
     "ajv": {
       "version": "6.5.5",
@@ -78,6 +83,15 @@
       "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
       "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
     },
+    "axios": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
+      "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
+      "requires": {
+        "follow-redirects": "^1.3.0",
+        "is-buffer": "^1.1.5"
+      }
+    },
     "azure-functions-typescript": {
       "version": "github:christopheranderson/azure-functions-typescript#bbb6b0fd67fcdf82cabaf1af41e65fa6d8496ff5",
       "from": "github:christopheranderson/azure-functions-typescript"
@@ -355,14 +369,17 @@
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
     },
     "durable-functions": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/durable-functions/-/durable-functions-1.1.0.tgz",
-      "integrity": "sha512-mk3Hf+CbSQnlE+MTO1/sGcqYup5gxAE6H7xGieM/F7jSCYgSKzMfhiRelJPRakNOJRMevthLErnjDMt3Kf67bA==",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/durable-functions/-/durable-functions-1.1.3.tgz",
+      "integrity": "sha512-YH+ah8E0bQTgFkcgiPmvep62TNsolLmKL2e9QUgGokuxV8vln+exJr9aJjKv6Q620BtAq95lYTOND0A9/9LyAw==",
       "requires": {
+        "@types/lodash": "^4.14.119",
         "@types/validator": "^9.4.3",
-        "azure-functions-typescript": "github:christopheranderson/azure-functions-typescript#bbb6b0fd67fcdf82cabaf1af41e65fa6d8496ff5",
+        "axios": "~0.18.0",
+        "azure-functions-typescript": "github:christopheranderson/azure-functions-typescript",
         "commander": "~2.9.0",
         "debug": "~2.6.9",
+        "lodash": "^4.17.11",
         "rimraf": "~2.5.4",
         "validator": "~10.8.0"
       },
@@ -534,6 +551,24 @@
         }
       }
     },
+    "follow-redirects": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz",
+      "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==",
+      "requires": {
+        "debug": "=3.1.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        }
+      }
+    },
     "for-in": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -842,6 +877,11 @@
       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
       "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
     },
+    "lodash": {
+      "version": "4.17.11",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+    },
     "map-cache": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
diff --git a/samples/package.json b/samples/package.json
index 1d0d163..8775276 100644
--- a/samples/package.json
+++ b/samples/package.json
@@ -1,6 +1,6 @@
 {
   "name": "durable-functions-samples",
-  "version": "1.1.1",
+  "version": "1.1.3",
   "description": "Durable Functions sample library for Node.js Azure Functions",
   "license": "MIT",
   "repository": "",
@@ -10,7 +10,7 @@
   ],
   "dependencies": {
     "azure-storage": "^2.10.2",
-    "durable-functions": "^1.1.1",
+    "durable-functions": "^1.1.3",
     "moment": "^2.22.2",
     "readdirp": "^2.2.1",
     "request": "^2.87.0",
diff --git a/src/durableorchestrationclient.ts b/src/durableorchestrationclient.ts
index 0569975..392681a 100644
--- a/src/durableorchestrationclient.ts
+++ b/src/durableorchestrationclient.ts
@@ -1,4 +1,4 @@
-import axios, { AxiosResponse } from "axios";
+import axios, { AxiosInstance } from "axios";
 import cloneDeep = require("lodash/cloneDeep");
 import process = require("process");
 import url = require("url");
@@ -7,8 +7,6 @@ import { Constants, DurableOrchestrationStatus, HttpCreationPayload, HttpManagem
     IHttpRequest, IHttpResponse, IRequest, OrchestrationClientInputData, OrchestrationRuntimeStatus, Utils,
 } from "./classes";
 
-axios.defaults.validateStatus = (status) => status < 600;   // don't throw errors for non-2XX HTTP responses
-
 /**
  * Returns an OrchestrationClient instance.
  * @param context The context object of the Azure function whose body
@@ -89,6 +87,8 @@ export class DurableOrchestrationClient {
     /** @hidden */
     public readonly uniqueWebhookOrigins: string[];
 
+    private readonly axiosInstance: AxiosInstance;
+
     private readonly eventNamePlaceholder = "{eventName}";
     private readonly functionNamePlaceholder = "{functionName}";
     private readonly instanceIdPlaceholder = "[/{instanceId}]";
@@ -118,6 +118,14 @@ export class DurableOrchestrationClient {
             throw new TypeError(`clientData: Expected OrchestrationClientInputData but got ${typeof clientData}`);
         }
 
+        this.axiosInstance = axios.create({
+            validateStatus: (status: number) => status < 600,
+            headers: {
+                post: {
+                    "Content-Type": "application/json",
+                },
+            },
+        });
         this.taskHubName = this.clientData.taskHubName;
         this.uniqueWebhookOrigins = this.extractUniqueWebhookOrigins(this.clientData);
     }
@@ -179,7 +187,7 @@ export class DurableOrchestrationClient {
         }
 
         try {
-            const response = await axios.get(webhookUrl);
+            const response = await this.axiosInstance.get(webhookUrl);
             switch (response.status) {
                 case 200: // instance completed
                 case 202: // instance in progress
@@ -188,7 +196,7 @@ export class DurableOrchestrationClient {
                 case 500: // instance failed with unhandled exception
                     return response.data as DurableOrchestrationStatus;
                 default:
-                    throw new Error(`Webhook returned unrecognized status code ${response.status}`);
+                    return Promise.reject(new Error(`Webhook returned unrecognized status code ${response.status}`));
             }
         } catch (error) {   // error object is axios-specific, not a JavaScript Error; extract relevant bit
             throw error.message;
@@ -205,7 +213,7 @@ export class DurableOrchestrationClient {
             .replace(idPlaceholder, "");
 
         try {
-            const response = await axios.get(requestUrl);
+            const response = await this.axiosInstance.get(requestUrl);
             return response.data as DurableOrchestrationStatus[];
         } catch (error) {   // error object is axios-specific, not a JavaScript Error; extract relevant bit
             throw error.message;
@@ -250,9 +258,9 @@ export class DurableOrchestrationClient {
         }
 
         try {
-            const response = await axios.get(requestUrl);
+            const response = await this.axiosInstance.get(requestUrl);
             if (response.status > 202) {
-                throw new Error(`Webhook returned status code ${response.status}: ${response.data}`);
+                return Promise.reject(new Error(`Webhook returned status code ${response.status}: ${response.data}`));
             } else {
                 return response.data as DurableOrchestrationStatus[];
             }
@@ -306,17 +314,17 @@ export class DurableOrchestrationClient {
         }
 
         try {
-            const response = await axios.post(requestUrl, JSON.stringify(eventData));
+            const response = await this.axiosInstance.post(requestUrl, JSON.stringify(eventData));
             switch (response.status) {
                 case 202: // event accepted
                 case 410: // instance completed or failed
                     return;
                 case 404:
-                    throw new Error(`No instance with ID '${instanceId}' found.`);
+                    return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
                 case 400:
-                    throw new Error("Only application/json request content is supported");
+                    return Promise.reject(new Error("Only application/json request content is supported"));
                 default:
-                    throw new Error(`Webhook returned unrecognized status code ${response.status}`);
+                    return Promise.reject(new Error(`Webhook returned unrecognized status code ${response.status}`));
             }
         } catch (error) {   // error object is axios-specific, not a JavaScript Error; extract relevant bit
             throw error.message;
@@ -338,16 +346,16 @@ export class DurableOrchestrationClient {
             .replace(this.reasonPlaceholder, reason);
 
         try {
-            const response = await axios.post(requestUrl);
+            const response = await this.axiosInstance.post(requestUrl);
             switch (response.status) {
                 case 202:
                     return;
                 case 404:
-                    throw new Error(`No instance with ID '${instanceId}' found.`);
+                    return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
                 case 410:
-                    throw new Error("The rewind operation is only supported on failed orchestration instances.");
+                    return Promise.reject(new Error("The rewind operation is only supported on failed orchestration instances."));
                 default:
-                    throw new Error(`Webhook returned unrecognized status code ${response.status}`);
+                    return Promise.reject(new Error(`Webhook returned unrecognized status code ${response.status}`));
             }
         } catch (error) {   // error object is axios-specific, not a JavaScript Error; extract relevant bit
             throw error.message;
@@ -379,9 +387,9 @@ export class DurableOrchestrationClient {
             .replace(this.instanceIdPlaceholder, (instanceId ? `/${instanceId}` : ""));
 
         try {
-            const response = await axios.post(requestUrl, JSON.stringify(input));
+            const response = await this.axiosInstance.post(requestUrl, JSON.stringify(input));
             if (response.status > 202) {
-                throw new Error(response.data as string);
+                return Promise.reject(new Error(response.data as string));
             } else if (response.data) {
                 return (response.data as HttpManagementPayload).id;
             }
@@ -407,15 +415,15 @@ export class DurableOrchestrationClient {
             .replace(this.reasonPlaceholder, reason);
 
         try {
-            const response = await axios.post(requestUrl);
+            const response = await this.axiosInstance.post(requestUrl);
             switch (response.status) {
                 case 202: // terminate accepted
                 case 410: // instance completed or failed
                     return;
                 case 404:
-                    throw new Error(`No instance with ID '${instanceId}' found.`);
+                    return Promise.reject(new Error(`No instance with ID '${instanceId}' found.`));
                 default:
-                    throw new Error(`Webhook returned unrecognized status code ${response.status}`);
+                    return Promise.reject(new Error(`Webhook returned unrecognized status code ${response.status}`));
             }
         } catch (error) {   // error object is axios-specific, not a JavaScript Error; extract relevant bit
             throw error.message;


Test patch:
diff --git a/test/unit/orchestrationclient-spec.ts b/test/unit/orchestrationclient-spec.ts
index 3aca40b..e84e248 100644
--- a/test/unit/orchestrationclient-spec.ts
+++ b/test/unit/orchestrationclient-spec.ts
@@ -28,7 +28,6 @@ describe("Orchestration Client", () => {
     const defaultTaskHub = "TestTaskHub";
     const defaultConnection = "Storage";
     const defaultInstanceId = uuidv1();
-    const defaultDate = new Date();
 
     const defaultClientInputData = TestUtils.createOrchestrationClientInputData(
         TestConstants.idPlaceholder,
@@ -37,6 +36,8 @@ describe("Orchestration Client", () => {
         defaultConnection,
     );
 
+    const requiredPostHeaders = { reqheaders: { "Content-Type": "application/json" } };
+
     describe("Constructor", () => {
         it("throws if clientData is undefined", async () => {
             expect(() => {
@@ -312,7 +313,7 @@ describe("Orchestration Client", () => {
                 .replace(TestConstants.idPlaceholder, defaultInstanceId)
                 .replace(TestConstants.eventNamePlaceholder, defaultTestEvent));
 
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname, JSON.stringify(defaultTestData))
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -332,7 +333,7 @@ describe("Orchestration Client", () => {
                 .replace(TestConstants.idPlaceholder, defaultInstanceId)
                 .replace(TestConstants.eventNamePlaceholder, defaultTestEvent)
                 .replace(defaultTaskHub, testTaskHub));
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname, JSON.stringify(defaultTestData))
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -352,7 +353,7 @@ describe("Orchestration Client", () => {
                 .replace(TestConstants.idPlaceholder, defaultInstanceId)
                 .replace(TestConstants.eventNamePlaceholder, defaultTestEvent)
                 .replace(defaultConnection, testConnection));
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname, JSON.stringify(defaultTestData))
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -376,7 +377,7 @@ describe("Orchestration Client", () => {
             const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.sendEventPostUri
                 .replace(TestConstants.idPlaceholder, id)
                 .replace(TestConstants.eventNamePlaceholder, defaultTestEvent));
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname, JSON.stringify(defaultTestData))
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -405,7 +406,7 @@ describe("Orchestration Client", () => {
             const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.rewindPostUri
                 .replace(TestConstants.idPlaceholder, defaultInstanceId)
                 .replace(TestConstants.reasonPlaceholder, testReason));
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname)
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -417,26 +418,64 @@ describe("Orchestration Client", () => {
             expect(result).to.be.equal(undefined);
         });
 
-        const invalidCodes = [ 404, 410, 500 ];
-        invalidCodes.forEach((statusCode) => {
-            it(`throws when webhook returns invalid status code ${statusCode}`, async () => {
-                const client = new DurableOrchestrationClient(defaultClientInputData);
+        it(`throws when webhook returns invalid status code 404`, async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const testId = "badId";
+            const testReason = "test";
+            const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.rewindPostUri
+                .replace(TestConstants.idPlaceholder, testId)
+                .replace(TestConstants.reasonPlaceholder, testReason));
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
+                .post(expectedWebhookUrl.pathname)
+                .query(() => {
+                    return getQueryObjectFromSearchParams(expectedWebhookUrl);
+                })
+                .reply(404);
+
+            await expect(client.rewind(testId, testReason)).to.be
+                .rejectedWith(`No instance with ID '${testId}' found.`);
+            expect(scope.isDone()).to.be.equal(true);
+        });
+
+        it(`throws when webhook returns invalid status code 410`, async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const testId = "badId";
+            const testReason = "test";
+            const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.rewindPostUri
+                .replace(TestConstants.idPlaceholder, testId)
+                .replace(TestConstants.reasonPlaceholder, testReason));
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
+                .post(expectedWebhookUrl.pathname)
+                .query(() => {
+                    return getQueryObjectFromSearchParams(expectedWebhookUrl);
+                })
+                .reply(410);
 
-                const testId = "badId";
-                const testReason = "test";
-                const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.rewindPostUri
-                    .replace(TestConstants.idPlaceholder, testId)
-                    .replace(TestConstants.reasonPlaceholder, testReason));
-                const scope = nock(expectedWebhookUrl.origin)
-                    .post(expectedWebhookUrl.pathname)
-                    .query(() => {
-                        return getQueryObjectFromSearchParams(expectedWebhookUrl);
-                    })
-                    .reply(statusCode);
+            await expect(client.rewind(testId, testReason)).to.be
+                .rejectedWith("The rewind operation is only supported on failed orchestration instances.");
+            expect(scope.isDone()).to.be.equal(true);
+        });
+
+        it(`throws when webhook returns invalid status code 500`, async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const testId = "badId";
+            const testReason = "test";
+            const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.rewindPostUri
+                .replace(TestConstants.idPlaceholder, testId)
+                .replace(TestConstants.reasonPlaceholder, testReason));
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
+                .post(expectedWebhookUrl.pathname)
+                .query(() => {
+                    return getQueryObjectFromSearchParams(expectedWebhookUrl);
+                })
+                .reply(500);
 
-                await expect(client.rewind(testId, testReason)).to.be.rejected;
-                expect(scope.isDone()).to.be.equal(true);
-            });
+            await expect(client.rewind(testId, testReason)).to.be
+                .rejectedWith(`Webhook returned unrecognized status code 500`);
+            expect(scope.isDone()).to.be.equal(true);
         });
     });
 
@@ -454,7 +493,7 @@ describe("Orchestration Client", () => {
 
             const functionName = defaultOrchestrationName;
             const expectedWebhookUrl = createInstanceWebhookUrl(Constants.DefaultLocalOrigin, functionName);
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname)
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -476,7 +515,7 @@ describe("Orchestration Client", () => {
                 Constants.DefaultLocalOrigin,
                 functionName,
                 defaultInstanceId);
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname, JSON.stringify(testData))
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -492,15 +531,16 @@ describe("Orchestration Client", () => {
             const client = new DurableOrchestrationClient(defaultClientInputData);
 
             const functionName = "BadOrchestration";
+            const functionBody = "Something went wrong!";
             const expectedWebhookUrl = createInstanceWebhookUrl(Constants.DefaultLocalOrigin, functionName);
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname)
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
                 })
-                .reply(500);
+                .reply(500, functionBody);
 
-            await expect(client.startNew(functionName)).to.be.rejectedWith(Error);
+            await expect(client.startNew(functionName)).to.be.rejectedWith(functionBody);
             expect(scope.isDone()).to.be.equal(true);
         });
     });
@@ -521,7 +561,7 @@ describe("Orchestration Client", () => {
             const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.terminatePostUri
                 .replace(TestConstants.idPlaceholder, defaultInstanceId)
                 .replace(TestConstants.reasonPlaceholder, testReason));
-            const scope = nock(expectedWebhookUrl.origin)
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
                 .post(expectedWebhookUrl.pathname)
                 .query(() => {
                     return getQueryObjectFromSearchParams(expectedWebhookUrl);
@@ -533,26 +573,44 @@ describe("Orchestration Client", () => {
             expect(result).to.be.equal(undefined);
         });
 
-        const invalidCodes = [ 404, 500 ];
-        invalidCodes.forEach((statusCode) => {
-            it(`throws when webhook returns invalid status code ${statusCode}`, async () => {
-                const client = new DurableOrchestrationClient(defaultClientInputData);
-
-                const id = "badId";
-                const testReason = "test";
-                const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.terminatePostUri
-                    .replace(TestConstants.idPlaceholder, id)
-                    .replace(TestConstants.reasonPlaceholder, testReason));
-                const scope = nock(expectedWebhookUrl.origin)
-                    .post(expectedWebhookUrl.pathname)
-                    .query(() => {
-                        return getQueryObjectFromSearchParams(expectedWebhookUrl);
-                    })
-                    .reply(404);
-
-                await expect(client.terminate(id, testReason)).to.be.rejected;
-                expect(scope.isDone()).to.be.equal(true);
-            });
+        it(`throws when webhook returns invalid status code 404`, async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const id = "badId";
+            const testReason = "test";
+            const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.terminatePostUri
+                .replace(TestConstants.idPlaceholder, id)
+                .replace(TestConstants.reasonPlaceholder, testReason));
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
+                .post(expectedWebhookUrl.pathname)
+                .query(() => {
+                    return getQueryObjectFromSearchParams(expectedWebhookUrl);
+                })
+                .reply(404);
+
+            await expect(client.terminate(id, testReason)).to.be
+                .rejectedWith(`No instance with ID '${id}' found.`);
+            expect(scope.isDone()).to.be.equal(true);
+        });
+
+        it(`throws when webhook returns invalid status code 500`, async () => {
+            const client = new DurableOrchestrationClient(defaultClientInputData);
+
+            const id = "badId";
+            const testReason = "test";
+            const expectedWebhookUrl = new url.URL(defaultClientInputData.managementUrls.terminatePostUri
+                .replace(TestConstants.idPlaceholder, id)
+                .replace(TestConstants.reasonPlaceholder, testReason));
+            const scope = nock(expectedWebhookUrl.origin, requiredPostHeaders)
+                .post(expectedWebhookUrl.pathname)
+                .query(() => {
+                    return getQueryObjectFromSearchParams(expectedWebhookUrl);
+                })
+                .reply(500);
+
+            await expect(client.terminate(id, testReason)).to.be
+                .rejectedWith(`Webhook returned unrecognized status code 500`);
+            expect(scope.isDone()).to.be.equal(true);
         });
     });