SuperTest: Listen at Random Port
In the example section of SuperTest (v0.15.0), it mentions something about ephemeral port:
You may pass an
http.Server
, or aFunction
torequest()
- if the server is not already listening for connections then it is bound to an ephemeral port for you so there is no need to keep track of ports. - https://github.com/visionmedia/supertest#example
Let’s dissect this sentence. There are a few key concepts to grasp:
- The
request
function will accept either a function or anhttp.Server
object. - When does the server not listening for connections?
- What is an ephemeral port?
Taking a peek at the index.js
file in SuperTest source code, it is easy to see that it accepts both function and http.Server
object, but prefer latter:
|
|
Why it does this? This has to do with Express:
|
|
Only when initiating an Express app, it returns a function, not an object. And follows up on lib/test.js
, when SuperTest detects the created server is yet to bind to any port number, it will invoke app.listen(0)
, so called ephemeral port. In fact, it is just a random port.
When something is ephemeral, it last for a very short time. When allowing a server to accept connections, we usually do is setting the server to listen on a specific port:
|
|
What if setting this to 0
like above or omit this port number?
Begin accepting connections on the specified
port
andhostname
. If thehostname
is omitted, the server will accept connections on any IPv6 address (::) when IPv6 is available, or any IPv4 address (0.0.0.0) otherwise. A port value of zero will assign a random port. - https://iojs.org/api/http.html#http_server_listen_port_hostname_backlog_callback
If we omit the port number, it is treated as a value of zero. If fact, anything that evaluates to be falsy, including zero, will be assigned a random port. Hence the following are the same:
|
|
So, do not get confused by the word ephemeral. What SuperTest does for Express is that, if the server is yet to be created, it will create it for you and bind to a random port. And this only applies to Express. When we use SuperTest with Express, we can simply do:
|
|
But when we use SuperTest with Koa, we have to create the server:
|
|
The legacy of Express continues. That’s why when using Koa, we will do app.listen()
instead.
Another thing to note that both Express and Koa instantiate an http.Server
instance only when it invokes listen
method to bind to a specific port number:
|
|
There is a difference between the application created by Express and Koa, and the server created by the application after invoking the listen
method. And this is completely different from the core HTTP module. Creating an application in Express and Koa does not equal to creating a HTTP server instance.
I always thought that both app.listen
will just return the same app
, and app
is an instance of http.Server
, but it is not. In Koa and Express, app
is the application, server
is the true HTTP server.