Challenge #2a: Tracking Requests

Next, you’ll make HomePageController respond to POST requests. This is a lot more challenging! To make it easier, the challenge is broken up into three parts.

For part (a), make the HomePageController call the ROT-13 service when it receives a POST request. Use hard-coded parameters. You don’t need to worry about the response for this challenge. Don’t worry about errors or edge cases either.

This challenge introduces the Output Tracking pattern. You’ll use it to confirm that the HomePageController calls the ROT-13 service.

Instructions

1. Implement the "POST asks ROT-13 service to transform text" test:

  1. Call HomePageController.postAsync().
  2. Assert that it called the ROT-13 service using port 123, the text "some text", and the correlation ID "0000-0000".

2. Implement HomePageController.postAsync():

  1. Call the ROT-13 service. Hardcode the port, text, and correlation ID.

Remember to commit your changes when you’re done.

API Documentation

const transformedText = await rot13Client.transformAsync(port, text, correlationId);

Call the ROT-13 service.

  • port (number) - the port of the ROT-13 service
  • text (string) - the text to send to the ROT-13 service
  • correlationId (string) - a unique ID representing the user’s request
  • returns transformedText (string) - the encoded text returned by the ROT-13 service
const rot13Requests = rot13Client.trackRequests();

Track requests made by rot13Client. This returns an OutputTracker instance. Every time rot13Client makes a request to the ROT-13 service, the OutputTracker is updated with an object describing the request. The object is in this format:

{
	port: 123,
	text: "some text",
	correlationId: "0000-0000",
}
  • returns rot13Requests (OutputTracker) - the request tracker
const output = rot13Requests.data;

Returns an array with every request stored in the output tracker. Use it like this:

const rot13Requests = rot13Client.trackRequests();
// run code that makes requests
const output = rot13Requests.data;
  • returns output (array): the data
const response = await controller.postAsync(request, config);

Handle a browser’s POST request. In production, this method is called by WwwRouter.

  • request (HttpServerRequest) - browser’s request
  • config (WwwConfig) - configuration for this request
  • returns response (HttpResponse) - the response to serve

TypeScript Types

rot13Requests.data: Rot13ClientOutput[]

The requests stored in the output tracker.

interface Rot13ClientOutput {
	port: number,
	text: string,
	correlationId: string,
	cancelled?: boolean,    // not relevant to this challenge
}

JavaScript Primers

No new concepts.

Hints

1
Your test will need a HomePageController.
You can construct it just like in the last challenge.
it("POST asks ROT-13 service to transform text", async () => {
  // Arrange
	const rot13Client = Rot13Client.createNull();
	const clock = Clock.createNull();
  const controller = new HomePageController(rot13Client, clock);

  // Act

  // Assert
});
2
Your test will need to check whether the ROT-13 service was called.
You can track how the service is used by calling rot13Client.trackRequests().
You have to call rot13Client.trackRequests() before the request is made.
it("POST asks ROT-13 service to transform text", async () => {
  // Arrange
	const rot13Client = Rot13Client.createNull();
	const rot13Requests = rot13Client.trackRequests();

	const clock = Clock.createNull();
  const controller = new HomePageController(rot13Client, clock);

  // Act

  // Assert
});
3
Your test needs to simulate a POST request.
You can do that by calling controller.postAsync(). (Don’t forget to await it.) You can ignore the return value.
it("POST asks ROT-13 service to transform text", async () => {
  // Arrange
	const rot13Client = Rot13Client.createNull();
	const rot13Requests = rot13Client.trackRequests();

	const clock = Clock.createNull();
  const controller = new HomePageController(rot13Client, clock);

  // Act
	await controller.postAsync(request, config);

  // Assert
});
4
Just like before, you’ll need HttpServerRequest and WwwConfig instances.
Use their createNull() and createTestInstance() factory methods.
it("POST asks ROT-13 service to transform text", async () => {
  // Arrange
	const rot13Client = Rot13Client.createNull();
	const rot13Requests = rot13Client.trackRequests();

	const clock = Clock.createNull();
  const controller = new HomePageController(rot13Client, clock);

	const request = HttpServerRequest.createNull();
	const config = WwwConfig.createTestInstance();

  // Act
	await controller.postAsync(request, config);

  // Assert
});
5
It’s time to assert that the ROT-13 service was called.
You’re tracking requests to the ROT-13 service in rot13Requests.
You can access the tracking data with rot13Requests.data.
You can use assert.deepEqual() to compare rot13Requests.data to an array with the expected requests.
it("POST asks ROT-13 service to transform text", async () => {
  // Arrange
	const rot13Client = Rot13Client.createNull();
	const rot13Requests = rot13Client.trackRequests();

	const clock = Clock.createNull();
  const controller = new HomePageController(rot13Client, clock);

	const request = HttpServerRequest.createNull();
	const config = WwwConfig.createTestInstance();

  // Act
	await controller.postAsync(request, config);

  // Assert
	assert.deepEqual(rot13Requests.data, [{
		port: 123,
		text: "some text",
		correlationId: "0000-0000",
	}]);
});
6
You’re ready to run the test.
It should fail, saying the actual value is [] (an empty array).

This means your production code isn’t making any requests of the ROT-13 service.

7
Call the ROT-13 service in your production code. Remember, you only need to provide hardcoded values.
You can use this._rot13Client.transformAsync(). Don’t forget to await it.
async postAsync(request, config) {
	await this._rot13Client.transformAsync(123, "some text", "0000-0000");
}

TypeScript needs a placeholder return:

// TypeScript
async postAsync(request: HttpServerRequest, config: WwwConfig): Promise<HttpServerResponse> {
	await this._rot13Client.transformAsync(123, "some text", "0000-0000");

	// DELETE ME: placeholder to satisfy compiler
	return await HttpServerResponse.createPlainTextResponse({ status: 501, body: "not implemented" });
}

Complete Solution

Test code:
it("POST asks ROT-13 service to transform text", async () => {
  // Arrange
	const rot13Client = Rot13Client.createNull();
	const rot13Requests = rot13Client.trackRequests();

	const clock = Clock.createNull();
  const controller = new HomePageController(rot13Client, clock);

	const request = HttpServerRequest.createNull();
	const config = WwwConfig.createTestInstance();

  // Act
	await controller.postAsync(request, config);

  // Assert
	assert.deepEqual(rot13Requests.data, [{
		port: 123,
		text: "some text",
		correlationId: "0000-0000",
	}]);
});
Production code (JavaScript):
async postAsync(request, config) {
	await this._rot13Client.transformAsync(123, "some text", "0000-0000");
}
Production code (TypeScript):
async postAsync(request: HttpServerRequest, config: WwwConfig): Promise<HttpServerResponse> {
	await this._rot13Client.transformAsync(123, "some text", "0000-0000");

	// DELETE ME: placeholder to satisfy compiler
	return await HttpServerResponse.createPlainTextResponse({ status: 501, body: "not implemented" });
}

Next challenge

Return to module overview