Appearance
Basic setup
SDT is controlling a Hitchy instance and thus requires access on @hitchy/core.
In the past, @hitchy/core has been a dependency of SDT. However, this was impeding its maintainability on major changes in the core. In addition, code solely necessary for testing was included with the core thus ending up in production setups unnecessarily.
Because of this, there are two ways of setting up SDT in a test depending on the version of SDT itself as well as of @hitchy/core used in your project.
Before v0.6
Before v0.6, SDT has been imported directly. It was depending on versions of @hitchy/core before v1.0. The managed Hitchy instance was always related to that dependency. Thus, the API of SDT has been ready for use on import:
javascript
const SDT = require( "@hitchy/server-dev-tools" );
// TODO use SDT.before() or SDT.start() ...
In this pattern, SDT
is exposing methods described below.
Since v0.6
Hitchy's core in version 1.0.0 and later comes with lots of breaking changes compared to its predecessors. Due to fully detaching SDT from Hitchy's core, the former one's API isn't ready for use on import anymore but has to be tied to a particular version of @hitchy/core manually:
javascript
import SDT from "@hitchy/server-dev-tools";
import Core from "@hitchy/core/sdt.js";
const Test = await SDT( Core );
// TODO use Test.before() or Test.start() ...
For that to work, you need to add @hitchy/core as a development-only (!!) dependency to your project.
In this pattern, Test
is exposing methods described below while SDT
has become a function you need to invoke to asynchronously assign your version of @hitchy/core.
Methods
before()
Signature: before( context, configuration ): Function
This method is generating a function for use with test runners such as mocha on setting up tests or test suites. It requires provision of an empty context descriptor to be set up and a configuration for customizing started the testing environment and the Hitchy instance it is managing.
The common pattern looks like this:
javascript
const ctx = {};
before( SDT.before( ctx, { ... } ) );
Check out our examples for additional demonstration.
after()
Signature: after( context ): Function
This method is generating a function for use with test runners such as mocha on tearing down tests or test suites. It requires provision of same context descriptor used with before() to pick the right instance of Hitchy to shut down.
Combined with before()
, the common pattern looks like this:
javascript
const ctx = {};
before( SDT.before( ctx, { ... } ) );
after( SDT.after( ctx ) );
Check out our examples for additional demonstration.
start()
Prefer before()
When using test runner such as mocha, before() and after() should be preferred over start() and stop().
Signature: start( configuration ): Promise<ContextDescriptor>
This method is starting a Hitchy instance serving a project described by a mandatory configuration. It is returning a promise resolved with the context descriptor suitable for interacting with the running Hitchy instance.
stop()
Prefer after()
When using test runner such as mocha, before() and after() should be preferred over start() and stop().
Signature: stop( context ): Promise<void>
This method requires context descriptor returned from related start() to shut down related instance of Hitchy. It is returning another promise resolved when Hitchy instance has been shut down properly.
Configuration
SDT can be customized using a configuration object consisting of these options:
projectFolder
This option may be a string serving as the relative path name of a folder containing a Hitchy-based application to be presented by the Hitchy instance SDT is managing. Usually, such an application has certain sub-folders like config/, api/controllers/ or api/services/.
javascript
{ projectFolder: "../projects/sample-a" }
Providing relative path names works in two separate ways:
Names starting with
./
or../
are processed in relation to the file containing your test script, which is the file invoking e.g. before() or start().Any other relative name is processed in relation to the folder of your project containing your test scripts and declaring @hitchy/server-dev-tools as its dependency. This is available to simplify addressing of projects in different test suites.
Absolute path names work as well, but using them is strongly discouraged as it prevents unit tests from running in different contexts such as a developer's local device vs. a CI pipeline.
As a special case, you may provide false
instead of a string to explicitly prevent the automatic discovery of a project from interfering with your intention of describing all files of a test project using files option yourself.
javascript
{ projectFolder: false }
Eventually, you may omit this option in case there is no project folder that could be discovered automatically. This results in a temporary empty folder served as Hitchy-based application you may add some files to.
pluginsFolder
This option selects folder containing sub-folder node_modules with additional Hitchy plugins required at runtime.
Providing relative path names works in two separate ways:
Names starting with
./
or../
are processed in relation to the file containing your test script, which is the file invoking e.g. before() or start().Any other relative name is processed in relation to the folder of your project containing your test scripts and declaring @hitchy/server-dev-tools as its dependency. This is available to simplify addressing of projects in different test suites.
Using absolute path names is available but strongly discouraged as it prevents unit tests to run in different contexts such as a developer's local device vs. a CI pipeline.
plugin 0.4.0+
You should always set this boolean option when testing a plugin. It is configuring SDT to discover default options in a slightly different way matching common setups for plugin development. For example, pluginsFolder must not be selected explicitly anymore as it is discovered automatically.
files
This is an object mapping relative path names of files into either file's content to be written to some temporary project folder created as a copy from selected or discovered project folder.
Project folder, only
Any copy consists of files found in selected or discovered project folder, only. It does not apply to separate plugins folder. Any content of a node_modules/ sub-folder is always ignored.
These limitations are intended to improve performance on frequently setting up and tearing down applications based on Hitchy.
This option is useful for adjusting project folder per test more conveniently.
javascript
{
files: {
"config/routes.js": "exports.routes = { '/': ( _, res ) => res.json( 'success' ) }"
}
}
This example is writing
javascript
exports.routes = { '/': ( _, res ) => res.json( 'success' ) }
to a file named config/routes.js which is picked up by Hitchy instance started afterwards.
useTmpPath
When declaring files, a temporary copy of a selected project is made automatically. Otherwise, Hitchy instance is set up to work on project folder as selected.
This boolean option can be set to enforce tests running on a temporary copy of a selected project folder even without declaring additional files. It is useful to start fresh on every test run assumed to adjust files in tested project folder.
Project folder, only
Any copy consists of files found in selected or discovered project folder, only. It does not apply to separate plugins folder. Any content of a node_modules/ sub-folder is always ignored.
These limitations are intended to improve performance on frequently setting up and tearing down applications based on Hitchy.
options
This setting contains runtime options forwarded to Hitchy. See Hitchy's manual for options basically supported here. In addition, any plugin or application may process these additional options to customize its behavior.
options.arguments
Replacing args
Previous versions of SDT and this manual have been supporting separately provided set of arguments in property args
of SDT configuration. To simplify the processing of this configuration, support for args
has been dropped in favor of this runtime option which is exposing parsed CLI arguments to the application.
The separate provision of arguments is a limited feature of Hitchy's CLI. The SDT manage Hitchy instances without that CLI. Thus, supporting args
does not make much sense.
When starting Hitchy via CLI, all arguments provided on the command line are parsed using minimist. The resulting object is provided in this runtime option. Hitchy's server instance, the core framework and selected plugins inspect these options to customize their behavior.
Arguments must be provided here in the same format as it is resulting from minimist's parser.
- Arguments are provided as object.
- Switches with values become top-level properties of that object.
- Switches without values become top-level properties of that object with value
true
. - All non-switches become an array of strings in special top-level property
_
.
Example
Hitchy may be invoked on the command line with these arguments:
bash
hitchy --api-key=secr3tKey data.log --authenticate "demo server"
When parsed with minimist, this results in the following object:
javascript
{
_: [ "data.log", "demo server" ],
"api-key": "secr3tKey",
authenticate: true,
}
In case you want to mock Hitchy being invoked with those arguments, you have to provide this object in options.arguments
.
Important note on defaults
In context of SDT, the boolean --quiet
argument is set by default to prevent Hitchy from logging anything that might pollute a test runner's report output. However, this does not apply when assigning a custom log level by mocking the --log-level
argument or by enabling the debug mode.
options.debug
This might be the most frequently used option during test implementation as it is enabling all logging.
javascript
{ options: { debug: true } }
When starting Hitchy using its CLI script, the --debug
argument is setting this option eventually. When mocking that argument in context of SDT, this option is set, too.
options.logger
This option can be used to adjust the logger Hitchy is using. As a special case for testing purposes, providing true
results in a capturing logger collecting all log messages generated by managed Hitchy instance and expose them as an array of strings in property logged
of the context descriptor.
Example
A capturing logger comes included with core's SDT API you provide on setting up SDT. Thus, having a custom logger is rather simple:
javascript
import SDT from "@hitchy/server-dev-tools";
import Core from "@hitchy/core/sdt.js";
const Test = await SDT( Core );
describe( "A feature of yours", () => {
const ctx = {};
afterEach( Test.after( ctx ) );
beforeEach( Test.before( ctx, {
options: {
logger: new Core.CapturingLogger(),
},
} ) );
it( "may log stuff and you can check that", () => {
assert.ok( ctx.hitchyOptions.logger.logged.includes(
"my-app:foo:debug expected log message"
) );
} );
} );
This capturing logger accepts a callback on construction invoked on every log message with its namespace and the message rendered as string.
javascript
...
logger: new Core.CapturingLogger( ( namespace, message ) => {
// do whatever you want with the message
// it won't be collected anywhere else
} ),
...
options.tools
Not supported since v0.6 anymore.
In version 0.6 and later, a core instance is provided on setting up this API. Because of that, this option would be redundant and is not processed anymore.
This is optionally picking "the tools" exposed by Hitchy's core framework in versions prior to v1.0.0. It has been used to have a particular version of Hitchy being managed by SDT instead of the one declared in its dependencies. This has been used for testing Hitchy itself, thus you may consider this option internal.
Context Descriptor
All methods controlling Hitchy instance are processing or returning a context descriptor. It is used to identify the Hitchy instance to control. And it's providing information for interacting with the running instance as conveniently as possible.
hitchy
This is a reference to started instance of Hitchy. Use hitchy.api
to access its API for inspection, only.
WARNING
You should not use this reference for anything but inspecting state of Hitchy at runtime.
hitchyOptions
After starting Hitchy instance, this property exposes the eventually used runtime options including qualifications made by the SDT such as the auto-discovered project folder.
logged
When setting option logger to true
, an array of strings each representing a message logged by the running application is exposed here.
request()
Signature: request( method, pathAndQuery, body, headers ): Promise<ExtendedServerResponse>
This method is sending an HTTP request to the running Hitchy instance currently managed by SDT.
No support for remote queries
This method is tightly integrated with Hitchy's request dispatcher. Thus, you can not use it to sent requests to remote endpoints. That's why second argument should be path with query, only.
The request is sent with selected HTTP method. It is addressing a resource of the running Hitchy instance by provided path name which may include a query. Eventually, an optional request body and some custom request headers may be provided.
The request body
may be provided as a string, a Buffer
or some arbitrary data to be converted to a JSON string automatically.
The method is returning a Promise resolved with the completely consumed response. This response is basically an HTTP response as commonly supported by Node.js. In addition, it includes these properties:
The raw response body is included as a
Buffer
in propertybody
.If the response headers indicate a JSON-formatted response, the parsed object is exposed in property
data
of promised response.If the response headers indicate some textual content, it is exposed in property
text
of promised response.
There are additional methods serving as convenience wrappers for this request()
method:
get()
Signature: get( route, headers )
This method is sending a GET request to the running Hitchy instance.
No request body!
This method omits separate argument for request body data due to the lack of supporting any such payload in GET requests.
post()
Signature: post( route, body, headers )
This method is sending a POST request to the running Hitchy instance.
put()
Signature: put( route, body, headers )
This method is sending a PUT request to the running Hitchy instance.
patch()
Signature: patch( route, body, headers )
This method is sending a PATCH request to the running Hitchy instance.
delete()
Signature: delete( route, body, headers )
This method is sending a DELETE request to the running Hitchy instance.
head()
Signature: head( route, headers )
This method is sending a HEAD request to the running Hitchy instance.
No request body!
This method omits separate argument for request body data due to the lack of supporting any such payload in HEAD requests.
options()
Signature: options( route, headers )
This method is sending a OPTIONS request to the running Hitchy instance.
No request body!
This method omits separate argument for request body data due to the lack of supporting any such payload in OPTIONS requests.
trace()
Signature: trace( route, headers )
This method is sending a TRACE request to the running Hitchy instance.
No request body!
This method omits separate argument for request body data due to the lack of supporting any such payload in TRACE requests.
server
This is a reference to the HTTP server set up for dispatching incoming requests to Hitchy.
temporaryFolder
This property provides the path name of a temporary folder SDT has been populated with files of a project folder and additionally configured files to make it the eventually running Hitchy instance's project folder.