Challenge #1: Listening

Most of the work of implementing low-level infrastructure is in figuring out how to use third-party libraries to communicate with external systems. In this case, Node.js’s http module. To make this easier, most of your initial work will be exploratory, written in a single test, and using console.log() to see what’s happening.

You’ll start by creating an HTTP server. Although your ultimate goal is to create an HTTP client, you can’t test it without having a server to test against. The best tests are entirely self-sufficient, with no requirement to start external servers. Creating the server as the part of the test makes it self-sufficient, which makes the tests faster and more reliable.

Instructions

1. In the "performs request" test:

  1. Start an HTTP server that listens on the PORT constant. This will cause the build to time out, because the tests won’t exit while the server is running.
  2. Use console.log() to log "SERVER LISTENING" when the listening event occurs. Check the test runner window for the output.
  3. Use await new Promise(...) to wait for the server to start up.
  4. Log "SERVER STARTED" after the promise resolves.

2. Your build should time out, but you should also see:

SERVER LISTENING
SERVER STARTED

Remember to commit your changes when you’re done.

API Documentation

const server = http.createServer();

Create an HTTP server. This doesn’t start the server; it just creates an object that represents the server. To start the server, use server.listen().

  • returns server (http.Server) - the HTTP server
server.listen(port);

Start the server by listening for incoming HTTP requests on the specified port. This function returns immediately, before the server has started. To wait for the server to start, wait for the listening event.

  • port (http.Server) - the HTTP server
server.on("listening", fn);

Run fn after the server has finished starting.

  • fn (() => void) - the function to run
console.log(data);

Convert data to a string and write it to stdout, followed by a newline (\n).

  • data (any) - the data to write
const PORT = 5001

This constant is available in the test code. It’s the port of the tests’ HTTP server. Use it when you create the server and when your tests make HTTP requests.

JavaScript Primers

Hints

1
Begin by creating the server object.
You can do that with http.createServer().
it("performs request", async () => {
	const server = http.createServer();
});
2
Start the server.
You can do that with server.listen().
This will cause the build to time out, because the active server prevents the tests from exiting.
it("performs request", async () => {
	const server = http.createServer();
	server.listen(PORT);
});
3
Log the listening event.
You can log with console.log().
You can wait for the event with server.on("listening", ...). (See the Using Events primer.)
You’ll need to pass an arrow function to server.on().
it("performs request", async () => {
	const server = http.createServer();
	server.listen(PORT);
	server.on("listening", () => {
		console.log("SERVER LISTENING");
	});
});
4
Wait for the server to start up.
You can use await new Promise() to wait. (See the Creating Promises and Using Events primers.)
The server has started up when the listening event occurs.
If the test times out, in addition to the build, it’s because the promise isn’t resolving.
You can use resolve() to make the promise resolve.
it("performs request", async () => {
	await new Promise((resolve, reject) => {
		const server = http.createServer();
		server.listen(PORT);
		server.on("listening", () => {
			console.log("SERVER LISTENING");
			return resolve();
		});
	});
});

TypeScript requires the type of the resolve() parameter to be specified. In this case, there is no return value, so the type is void:

it("performs request", async () => {
	await new Promise<void>((resolve, reject) => {
		const server = http.createServer();
		server.listen(PORT);
		server.on("listening", () => {
			console.log("SERVER LISTENING");
			return resolve();
		});
	});
});
5
Log that the server has started.
it("performs request", async () => {
	await new Promise((resolve, reject) => {  // add <void> for TypeScript
		const server = http.createServer();
		server.listen(PORT);
		server.on("listening", () => {
			console.log("SERVER LISTENING");
			return resolve();
		});
	});
	console.log("SERVER STARTED");
});

Complete Solution

Test code (JavaScript):
it("performs request", async () => {
	await new Promise((resolve, reject) => {
		const server = http.createServer();
		server.listen(PORT);
		server.on("listening", () => {
			console.log("SERVER LISTENING");
			return resolve();
		});
	});
	console.log("SERVER STARTED");
});
Test code (TypeScript):
it("performs request", async () => {
	await new Promise<void>((resolve, reject) => {
		const server = http.createServer();
		server.listen(PORT);
		server.on("listening", () => {
			console.log("SERVER LISTENING");
			return resolve();
		});
	});
	console.log("SERVER STARTED");
});

No production code yet.

Next challenge

Return to module overview