Faking Requests

Hyper has the ability to fake requests and return fake responses as a result. This is perfect for testing scenarios where you don't actually want to make an HTTP request.

Non-ColdBox users will need to add a mapping to the Globber dependency included with Hyper.

// Application.cfc
component {
    this.mappings[ "/globber" ] = "/path/to/hyper" & "/modules/globber";
}

Faking All Requests

Faking is enabled on a HyperBuilder instance, either the built-in one provided by Hyper or a custom Hyper client you have created.

To enable faking requests, call the fake method:

var hyper = new Hyper.models.HyperBuilder();
hyper.fake();

After calling the fake method, all requests created by this HyperBuilder will be faked. By default, they will return 200 OK responses with empty bodies.

hyper.fake();
var res = hyper.get( "https://google.com" );
expect( res.getStatus() ).toBe( "200 OK" );

Fake Configuration

When calling the fake method, you can provide a struct mapping URL patterns to response generator functions.

hyper.fake( {
    "https://google.com/*": function( newFakeResponse, req ) {
         return newFakeResponse( 404, "Not Found" );
    }
} );

The key is a URL pattern. The pattern can be any valid glob. If the pattern is matched by the fullUrl of the HyperRequest, then the response generator function will be called and the results returned.

A helper function, newFakeResponse, is provided as the first argument to the response generator function. The current request is provided as the second argument.

FakeHyperResponse

The resposne generator function must return a FakeHyperResponse instance. A FakeHyperResponse instance acts similar to a normal HyperResponse except the properties are not read only. Once you have an instance of your FakeHyperResponse, you can continue to set any properties you need.

hyper.fake( {
    "https://jsonplaceholder.typicode.com/posts": function( newFakeResponse, req ) {
         return newFakeResponse()
             .setStatusCode( 201 )
             .setStatusText( "Created" )
             .setData( serializeJSON( {
                 "id": 101,
                 "title": "foo",
                 "body": "bar",
                 "userId": 1
             } ) );
    }
} );

You can also pass the values to the newFakeResponse function, if you'd like.

hyper.fake( {
    "https://jsonplaceholder.typicode.com/posts": function( newFakeResponse, req ) {
         return newFakeResponse( 201, "Created", serializeJSON( {
             "id": 101,
             "title": "foo",
             "body": "bar",
             "userId": 1
         } ) );
    }
} );

newFakeResponse

Creates a new FakeHyperResponse instance.

Return: FakeHyperResponse

Sequencing Fake Responses

In addition to returning a single FakeHyperResponse per pattern, you can return an array of FakeHyperResponse instances. These will be returned in a sequence.

hyper.fake( {
    "https://jsonplaceholder.typicode.com/posts": function( newFakeResponse, req ) {
         return [
             newFakeResponse( 201, "Created", serializeJSON( {
                 "id": 101,
                 "title": "foo",
                 "body": "bar",
                 "userId": 1
             } ) ),
             newFakeResponse( 422, "Unprocessable Entity", "Duplicate title" )
         ];
    }
} );

var resA = hyper.post( "https://jsonplaceholder.typicode.com/posts", { /* ... */ } );
expect( resA.getStatus() ).toBe( "201 Created" );

var resB = hyper.post( "https://jsonplaceholder.typicode.com/posts", { /* ... */ } );
expect( resA.getStatus() ).toBe( "422 Unprocessable Entity" );

If you continue to make requests to the same pattern after the sequence has been exhausted, an exception will be thrown.

hyper.fake( {
    "https://jsonplaceholder.typicode.com/posts": function( newFakeResponse, req ) {
         return [
             newFakeResponse( 201, "Created", serializeJSON( {
                 "id": 101,
                 "title": "foo",
                 "body": "bar",
                 "userId": 1
             } ) ),
             newFakeResponse( 422, "Unprocessable Entity", "Duplicate title" )
         ];
    }
} );

var resA = hyper.post( "https://jsonplaceholder.typicode.com/posts", { /* ... */ } );
expect( resA.getStatus() ).toBe( "201 Created" );

var resB = hyper.post( "https://jsonplaceholder.typicode.com/posts", { /* ... */ } );
expect( resA.getStatus() ).toBe( "422 Unprocessable Entity" );

// THROWS a `HyperFakeSequenceExhausted` exception
var resC = hyper.post( "https://jsonplaceholder.typicode.com/posts", { /* ... */ } );

Preventing Stray Requests

By default, Hyper returns a default FakeHyperResponse for every request that doesn't match one of your configured patterns. You can instead cause Hyper to throw an exception if it encounters one of these stray requests by calling the preventStrayRequests method.

hyper.fake( {
    "https://google.com/*": function( newFakeResponse, req ) {
         return newFakeResponse( 404, "Not Found" );
    }
} ).preventStrayRequests();

// THROWS a `HyperFakeStrayRequest` exception
var res = hyper.get( "https://github.com" );

Making Assertions

In addition to assertions made against the FakeHyperResponse instances returned, you can also make assertions using the HyperBuilder instance you faked. These come in the form of methods on the HyperBuilder instance as well as custom TestBox Assertions.

HyperBuilder Method Assertions

The following methods are available to make assertions in your tests about the requests that were sent.

getFakeRequestCount

Returns the number of fake requests that have been made.

Return: numeric

wasRequestSent

Returns whether a request has been made that matches the predicate. Each request that has been made is passed to the predicate in order. If the predicate returns true, the request is considered a match and true is returned. If no request passes the predicate, false is returned.

Return: boolean

Custom TestBox Assertions

You can register custom TestBox assertions provided by Hyper for more readable tests and test failure messages.

You must register these assertions before using them.

component extends="testbox.system.BaseSpec" {

    function beforeAll() {
        addMatchers( "hyper.models.TestBoxMatchers" )
    }
    
    function run() {
        // ...
    }

}

The following custom assertions are provided:

toHaveSentRequest

This takes in the HyperBuilder instance as the actual and a predicate function as the expected. The predicate function is passed to the HyperBuilder instance's wasRequestSent method.

hyper.fake();

hyper.get( "https://google.com" );

expect( hyper ).toHaveSentRequest( function( req ) {
    return req.getFullUrl( "https://google.com" );
} );

expect( hyper ).notToHaveSentRequest( function( req ) {
    return req.getFullUrl( "https://github.com" );
} );

toHaveSentCount

This takes in the HyperBuilder instance as the actual and an integer number of requests that should have been sent.

hyper.fake();

hyper.get( "https://google.com" );

expect( hyper ).toHaveSentCount( 1 );
expect( hyper ).notToHaveSentCount( 2 );

toHaveSentNothing

This takes in the HyperBuilder instance as the actual and no other parameters.

hyper.fake();

expect( hyper ).toHaveSentNothing();

hyper.get( "https://google.com" );

expect( hyper ).notToHaveSentNothing();

Resetting the Builder

To reset the sent request counts and sequences but keep the fake configuration, use the resetFakes method:

hyper.fake();

hyper.get( "https://google.com" );

expect( hyper ).toHaveSentCount( 1 );

hyper.resetFakes();

expect( hyper ).toHaveSentNothing();

To reset the HyperBuilder instance to normal operation call the clearFakes method:

hyper.fake();

hyper.get( "https://google.com" );

hyper.clearFakes();

These are useful methods to call in an afterEach block in TestBox to make sure you are only faking requests when you want to.

Last updated