Challenge #8: Simulating Errors

It’s not enough for our code to handle errors. We need to make it possible for our consumers to handle errors, too. And for them to do that, they need to be able to test what happens when an error occurs. In this challenge, you’ll add support for simulating errors to Rot13Client.createNull().

Instructions

1. Implement the "simulates errors" test (near the bottom again):

  1. Configure Rot13Client.createNull() to throw an exception. Use the following configuration (note the array):
    const rot13Client = Rot13Client.createNull([
    	{ error: "my error" },
    ]);
  2. Assert that rot13Client.transformAsync() throws the following error:
    const expectedError =
    	"Unexpected status from ROT-13 service\n" +
    	`Host: ${HOST}:9999\n` +
    	"Endpoint: /rot13/transform\n" +
    	"Status: 500\n" +
    	"Headers: {}\n" +
    	"Body: my error";

2. Modify Rot13Client.createNull():

  1. Simulate an HTTP response that will cause the desired error to be thrown.

Remember to commit your changes when you’re done.

API Documentation

const rot13Client = Rot13Client.createNull([{ error ]});

Creates a Nulled Rot13Client that throws an error the first time it’s called. (The client returns normally if error is undefined.) Note that the parameter is an array of objects. To specify additional responses, add more objects to the array.

  • error (string) - the body of the ROT-13 service response that causes the error
  • returns rot13Client (Rot13Client) - the ROT-13 client

JavaScript Primers

Hints

1
Your test needs a rot13Client that’s configured to fail.
You can use Rot13Client.createNull({ error }) for that.
it("simulates errors", async () => {
	const rot13Client = Rot13Client.createNull([{ error: "my error" }]);
});
2
The test should assert that rot13Client.transformAsync() throws an error.
You can use assert.throwsAsync() to check for the error. Don’t forget to await it.
You can use the transformAsync() test helper to run the code.
Remember to set the port, because it’s specified in the error message.
it("simulates errors", async () => {
	const rot13Client = Rot13Client.createNull([{ error: "my error" }]);

	const expectedError =
		"Unexpected status from ROT-13 service\n" +
		`Host: ${HOST}:9999\n` +
		"Endpoint: /rot13/transform\n" +
		"Status: 500\n" +
		"Headers: {}\n" +
		"Body: my error";

	await assert.throwsAsync(
		() => transformAsync({
			rot13Client,
			port: 9999,
		}),
		expectedError,
	);
});

(The expectedError variable uses string interpolation.)

3
The test is ready to run.
It should fail with "Expected exception".

This is happening because the production code isn’t throwing an exception.

4
The production code needs to throw an exception when rot13Client.transformAsync() is called.
Because Nullables run real code, the configuration needs to cause the error to occur, in the same way that it would happen in production, rather than just throwing an error.
rot13Client.transformAsync() throws an error if it gets an unexpected status code.
Rot13Client.createNull() needs to configure an HTTP response that has a 500 status code.
You can do that in nulledHttpResponse().
function nulledHttpResponse({
	response = "Nulled Rot13Client response",
	error = undefined,
}) {
	if (error !== undefined) {
		return {
			status: 500,
			headers: {},
			body: error,
		};
	}
	else {
		return {
			status: 200,
			headers: {
				"content-type": "application/json",
			},
			body: JSON.stringify({
				transformed: response,
			}),
		};
	}
}

TypeScript requires the types to be declared:

function nulledHttpResponse({
	response = "Nulled Rot13Client response",
	error = undefined,
}: NulledRot13ClientResponse): NulledHttpClientResponse {
	if (error !== undefined) {
		return {
			status: 500,
			headers: {},
			body: error,
		};
	}
	else {
		return {
			status: 200,
			headers: {
				"content-type": "application/json",
			},
			body: JSON.stringify({
				transformed: response,
			}),
		};
	}
}

Complete Solution

Test code:
it("simulates errors", async () => {
	const rot13Client = Rot13Client.createNull([{ error: "my error" }]);

	const expectedError =
		"Unexpected status from ROT-13 service\n" +
		`Host: ${HOST}:9999\n` +
		"Endpoint: /rot13/transform\n" +
		"Status: 500\n" +
		"Headers: {}\n" +
		"Body: my error";

	await assert.throwsAsync(
		() => transformAsync({
			rot13Client,
			port: 9999,
		}),
		expectedError,
	);
});
Production code (JavaScript):
function nulledHttpResponse({
	response = "Nulled Rot13Client response",
	error = undefined,
}) {
	if (error !== undefined) {
		return {
			status: 500,
			headers: {},
			body: error,
		};
	}
	else {
		return {
			status: 200,
			headers: {
				"content-type": "application/json",
			},
			body: JSON.stringify({
				transformed: response,
			}),
		};
	}
}
Production code (TypeScript):
function nulledHttpResponse({
	response = "Nulled Rot13Client response",
	error = undefined,
}: NulledRot13ClientResponse): NulledHttpClientResponse {
	if (error !== undefined) {
		return {
			status: 500,
			headers: {},
			body: error,
		};
	}
	else {
		return {
			status: 200,
			headers: {
				"content-type": "application/json",
			},
			body: JSON.stringify({
				transformed: response,
			}),
		};
	}
}

Next challenge

Return to module overview