Challenge #7: Partial Configuration
Tests will often only need to configure certain responses. The rest can be left as a default. In this challenge, you’ll update your embedded stub to support partially-configured responses.
Instructions
1. In the "provides defaults for partially-configured responses"
test:
- Assert that an endpoint with no specific configuration has the following response:
{ status: 501, headers: {}, body: "", }
2. In the production code:
- Modify the embedded stub to make the test pass.
Remember to commit your changes when you’re done.
API Documentation
No new methods.
JavaScript Primers
No new concepts.
Hints
1
The test needs to configure an endpoint, then assert on it.
The configured response for the endpoint should be {}
. That’s technically a configuration that has no status
, headers
, or body
.
it("provides defaults for partially-configured responses", async () => {
const client = HttpClient.createNull({
"/endpoint": {},
});
const { response } = await requestAsync({ client, path: "/endpoint" });
assert.deepEqual(response, {
status: 501,
headers: {},
body: "",
});
});
2
In JavaScript, the test is ready to run. (If you’re using TypeScript, skip this hint.)
It should fail, saying that it cannot convert undefined or null to object
.
It’s failing in Object.entries(headers)
.
That’s because the endpoint technically has a configuration—it’s an empty object—but the headers
property is undefined
.
3
In TypeScript, the test is ready to run. (If you’re using JavaScript, skip this hint.)
It should fail, saying that the status
and body
are different than expected.
The actual values are the same as the placeholders in StubbedResponse
.
That’s because the endpoint technically has a configuration—it’s an empty object—but the status
, headers
, and body
are undefined
. As a result, the ??
operators in StubbedResponse
are assigning defaults.
4
Modify the production code to make the test pass.
You need to provide defaults in the case where the object exists, but specific fields don’t.
Object destructuring is probably the cleanest way to do that.
In TypeScript, this will replace the ??
operators.
class StubbedResponse extends EventEmitter {
constructor({
status = 501,
headers = {},
body = "",
} = DEFAULT_NULLED_RESPONSE) {
super();
this.statusCode = status;
this.headers = normalizeHeaders(headers);
setImmediate(() => {
this.emit("data", body);
this.emit("end");
});
}
}
The TypeScript code is cleaner now:
class StubbedResponse extends EventEmitter implements NodeHttpResponse {
statusCode: number;
headers: HttpHeaders;
constructor({
status = 501,
headers = {},
body = "",
}: NulledHttpClientResponse = DEFAULT_NULLED_RESPONSE) {
super();
this.statusCode = status; // no more ??
this.headers = normalizeHeaders(headers); // no more ??
setImmediate(() => {
this.emit("data", body);
this.emit("end");
});
}
}
Complete Solution
Test code:
it("provides defaults for partially-configured responses", async () => {
const client = HttpClient.createNull({
"/endpoint": {},
});
const { response } = await requestAsync({ client, path: "/endpoint" });
assert.deepEqual(response, {
status: 501,
headers: {},
body: "",
});
});
Production code (JavaScript):
class StubbedResponse extends EventEmitter {
constructor({
status = 501,
headers = {},
body = "",
} = DEFAULT_NULLED_RESPONSE) {
super();
this.statusCode = status;
this.headers = normalizeHeaders(headers);
setImmediate(() => {
this.emit("data", body);
this.emit("end");
});
}
}
Production code (TypeScript):
class StubbedResponse extends EventEmitter implements NodeHttpResponse {
statusCode: number;
headers: HttpHeaders;
constructor({
status = 501,
headers = {},
body = "",
}: NulledHttpClientResponse = DEFAULT_NULLED_RESPONSE) {
super();
this.statusCode = status;
this.headers = normalizeHeaders(headers);
setImmediate(() => {
this.emit("data", body);
this.emit("end");
});
}
}