Before you submit any pull request, please check if your code can pass all the tests by running:
npm test
If your code contains new features, add the corresponding tests.
I want to contribute but I don't understand how the project is organized, where do I start?
The project is divided in two parts. One client and many servers (currently, there's only the PHP version). The goal is to provide a few servers for various platforms (PHP, Node, .Net, Python, etc...).
The server part has only one job: respond to the client. It must provide appropriate headers for the latency tests, configure the platform to allow large uploads and return large chunks of data for the download tests.
If you want to contribute by creating a server in any language or with any platform you want, here's some simple guidelines to help you:
- Don't let HTTP connections opened (disabled them, or use HTTP 1.0, the latest isn't recommended). The latency calculations are based on the time it takes for the client to establish an HTTP connection with the server, if a connection is still open you will get a 0 latency for each test.
- Disable every caching capabilities of client browsers or proxies. Take a look at the
Cache-Control
andPragma
headers. - Disable all types of compression, like gzip.
You will need to handle a single endpoint, it must return an empty response with a 200
HTTP code when a GET
request is made. At this point, latency calculations should work. Your server must support binary file uploads on this endpoint, check your environment configuration if you have any issues.
Finally, the endpoint should return generated data when the client measures the download bandwidth. You can identify this scenario by checking if the module
query parameter is equal to "download"
.
The easiest way to generate some data is to return a simple string concatenated multiple times to finally get the appropriate size and return it to the client. If you can easily generate some random binary data, prefer this option. You should, by default, return a 20MB
size but the client can override this value by providing a size in Bytes through the size
query parameter. Since the client can define this value, make sure to define a maximum value, I recommend 200MB
.
That's it for the server part, check my PHP implementation if you need some context.
The client part is written in ES6 and transpiled to ES5 using Babel. It is composed of one main class (SpeedTest
) which is divided into modules: latency (LatencyModule
), upload (BandwidthModule
), download (BandwidthModule
). Each of them inherits from the http module (HttpModule
) which inherits from the event dispatcher (EventDispatcher
).
The EventDispatcher
class provides the on
, off
and trigger
methods which allows event management.
The HttpModule
class provides methods to handle networking management (only over HTTP, of course). Basically, you prepare a new request with the _newRequest
method and you send it with _sendRequest
. The goal with this class is to never expose the XMLHttpRequest
instance until it has been sent, thus we can safely manage the request without any breaking code from the child modules. It also provides an isRequesting
method to check if the module is currently making a request.
The LatencyModule
and the BandwidthModule
classes make all the calculations and trigger the events. The code is correctly commented so it's up to you to understand how it works, it shouldn't be very difficult.
These last two modules depend on the Timing
class. It allows to check for Resource Timing support and provides two methods used to make measures based on the Performance API which fallback to DateTime calculations if the browser doesn't have the required APIs.
Finally, the SpeedTest
class initiates all the modules and makes them accessible through the module
method (this will probably change). Like the HttpModule
class, it provides an isRequesting
method to check if any module is currently making a request.