Challenge #2: Signature Shielding

Before adding any more tests, you’ll factor out a helper function to make the tests simpler and easier to understand. This is the Signature Shielding pattern.

Instructions

  1. Extract a helper method with this signature:

    const { httpRequests } = await transformAsync({ port, text, correlationId });
  2. Make the parameters to transformAsync() optional.

Remember to commit your changes when you’re done.

Useful Constants

const IRRELEVANT_PORT = 42;

This constant is available in the test code. Use it when the ROT-13 service’s port doesn’t matter.

const IRRELEVANT_TEXT = "irrelevant_text";

This constant is available in the test code. Use it when the text to encode doesn’t matter.

const IRRELEVANT_CORRELATION_ID = "irrelevant-correlation-id";

This constant is available in the test code. Use it when the correlation ID doesn’t matter.

JavaScript Primers

Hints

1
Before you can factor out the helper method, you need to make your code look like the function you want to factor out.
Introduce variables for the test-specific constants in the “Arrange” and “Act” section and put them at the top of the test.
it("makes request", async () => {
	const port = 9999;
	const text = "text_to_transform";
	const correlationId = "my-correlation-id";

	// Arrange
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	// Act
	await rot13Client.transformAsync(port, text, correlationId);

	// Assert
	assert.deepEqual(httpRequests.data, [{
		host: HOST,
		port: 9999,
		path: "/rot13/transform",
		method: "post",
		headers: {
			"content-type": "application/json",
			"x-correlation-id": "my-correlation-id",
		},
		body: JSON.stringify({ text: "text_to_transform" }),
	}]);
});
2
Extract the “Arrange” and “Act” sections of the test into a function named transformAsync(). Remember the async keyword, and don’t forget to await it.
Your editor might have an automated refactoring to do this for you.
it("makes request", async () => {
	const port = 9999;
	const text = "text_to_transform";
	const correlationId = "my-correlation-id";
	const httpRequests = await transformAsync(port, text, correlationId);

	// Assert
	assert.deepEqual(httpRequests.data, [{
		host: HOST,
		port: 9999,
		path: "/rot13/transform",
		method: "post",
		headers: {
			"content-type": "application/json",
			"x-correlation-id": "my-correlation-id",
		},
		body: JSON.stringify({ text: "text_to_transform" }),
	}]);
});

async function transformAsync(port, text, correlationId) {
	// Arrange
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	// Act
	await rot13Client.transformAsync(port, text, correlationId);
	return httpRequests;
}

TypeScript requires types for the function parameters:

async function transformAsync(port: number, text: string, correlationId: string) {
	// Arrange
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	// Act
	await rot13Client.transformAsync(port, text, correlationId);
	return httpRequests;
}
3
Modify transformAsync()’s parameters and return value to match the desired signature.
You’ll need to use object shorthand and object destructuring in the test and transformAsync().
it("makes request", async () => {
	const port = 9999;
	const text = "text_to_transform";
	const correlationId = "my-correlation-id";
	const { httpRequests } = await transformAsync({ port, text, correlationId });

	// Assert
	assert.deepEqual(httpRequests.data, [{
		host: HOST,
		port: 9999,
		path: "/rot13/transform",
		method: "post",
		headers: {
			"content-type": "application/json",
			"x-correlation-id": "my-correlation-id",
		},
		body: JSON.stringify({ text: "text_to_transform" }),
	}]);
});

async function transformAsync({ port, text, correlationId }) {
	// Arrange
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	// Act
	await rot13Client.transformAsync(port, text, correlationId);
	return { httpRequests };
}

TypeScript still requires types, but now they’re declared for the object parameter:

async function transformAsync(
	{ port, text, correlationId }:
	{ port: number, text: string, correlationId: string}
) {
	// Arrange
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	// Act
	await rot13Client.transformAsync(port, text, correlationId);
	return { httpRequests };
}
4
Finish up the refactoring by removing unnecessary variables, comments, and whitespace.
Your editor might have an automatic “Inline Variable” refactoring.
it("makes request", async () => {
	const { httpRequests } = await transformAsync({
		port: 9999,
		text: "text_to_transform",
		correlationId: "my-correlation-id"
	});

	assert.deepEqual(httpRequests.data, [{
		host: HOST,
		port: 9999,
		path: "/rot13/transform",
		method: "post",
		headers: {
			"content-type": "application/json",
			"x-correlation-id": "my-correlation-id",
		},
		body: JSON.stringify({ text: "text_to_transform" }),
	}]);
});

async function transformAsync({ port, text, correlationId }) {
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	await rot13Client.transformAsync(port, text, correlationId);

	return { httpRequests };
}

Complete Solution

Test code (JavaScript):
describe.only("ROT-13 Service client", () => {

	describe("happy path", () => {

		it("makes request", async () => {
			const { httpRequests } = await transformAsync({
				port: 9999,
				text: "text_to_transform",
				correlationId: "my-correlation-id"
			});

			assert.deepEqual(httpRequests.data, [{
				host: HOST,
				port: 9999,
				path: "/rot13/transform",
				method: "post",
				headers: {
					"content-type": "application/json",
					"x-correlation-id": "my-correlation-id",
				},
				body: JSON.stringify({ text: "text_to_transform" }),
			}]);
		});

// ...

});

async function transformAsync({ port, text, correlationId }) {
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	await rot13Client.transformAsync(port, text, correlationId);

	return { httpRequests };
}
Test code (TypeScript):
describe.only("ROT-13 Service client", () => {

	describe("happy path", () => {

		it("makes request", async () => {
			const { httpRequests } = await transformAsync({
				port: 9999,
				text: "text_to_transform",
				correlationId: "my-correlation-id"
			});

			assert.deepEqual(httpRequests.data, [{
				host: HOST,
				port: 9999,
				path: "/rot13/transform",
				method: "post",
				headers: {
					"content-type": "application/json",
					"x-correlation-id": "my-correlation-id",
				},
				body: JSON.stringify({ text: "text_to_transform" }),
			}]);
		});

// ...

});

async function transformAsync(
	{ port, text, correlationId }:
	{ port: number, text: string, correlationId: string }
) {
	const httpClient = HttpClient.createNull();
	const httpRequests = httpClient.trackRequests();
	const rot13Client = new Rot13Client(httpClient);

	await rot13Client.transformAsync(port, text, correlationId);

	return { httpRequests };
}

Production code is unchanged.

Next challenge

Return to module overview