Giter Site home page Giter Site logo

kbaltrinic / http-backend-proxy Goto Github PK

View Code? Open in Web Editor NEW
84.0 9.0 14.0 138 KB

A proxy that allows configuring the ngMockE2E $httpBackend service from within protractor based tests.

License: MIT License

CSS 0.85% JavaScript 94.49% HTML 4.66%

http-backend-proxy's Introduction

$httpBackend Proxy

Build Status

This is a node module for use with the AngularJS Protractor end-to-end testing framework. It allows you to make configuration calls to $httpBackend from within Protractor itself as well as share data and functions between the test environment and the browser. Being able to configuring the mock back end along side the tests that depend upon it improves the modularity, encapsulation and flexibility of your tests. The proxy allows $httpBackend to live up to its full potential, making it easier to test angular web applications in abstraction from their back end services.

Credits

The proxy itself is my own work. However much of the test application and project structure, etc. is based off of the angular-seed project. This includes significant parts of this README.

Release Notes and Documentation

See the wiki for release note. Documentation is in the process of being moved from this readme (which is getting too long) to the wiki. If you are reading this on NPM, I recommend you look on github for the most recent version. Documentation often gets updated/improved there without a release to NPM.

The proxy has been tested with the lastest .x versions of the Angular.js from the 1.2, 1.3 and 1.4 series through 1.4.3. It has been tested with the latest .x versions of Protractor from the 0.24, 1.8 and 2.1 series through 2.1.0.

Getting and Using the Proxy

The proxy is available via npm and can be installed into your project by calling npm install http-backend-proxy or better yet, just add http-backend-proxy to devDependencies in your package.json file. The current version is 1.4.2 and is released under the MIT license. Source code can be found on GitHub.

To instantiate an instance of the proxy, require it and create a new instance:

var HttpBackend = require('http-backend-proxy');
var proxy = new HttpBackend(browser);

browser is, of course, the protractor browser object. A configuration object may be passed as a second argument to the constructor. Available configuration options are discussed where appropriate below.

The proxy supports the same basic interface as Angular's $httpBackend so start with its docs. Note that all proxied methods return promises in the fashion of most other Protractor methods except when buffering is turned on. (See Buffered Mode below.) Beyond the $httpBackend API, the proxy adds a few additional methods which are discussed in the following sections.

See the end-to-end tests in test/e2e for some examples of usage.

Buffered Mode

It is possible to use the proxy in a 'buffered' mode by adding buffer: true to the configuration object passed to proxy constructor. When buffering is enabled, proxied methods return void and do not immediately pass their calls through to the browser. Calling flush() will pass all buffered calls through to the browser at once and return a promise that will be fulfilled after all calls have been executed.

Buffering is the generally recommended approach because in most cases you will need to make numerous calls to the proxy to set things up the way you want them for a given spec. Buffering will reduce the number of remote calls and considerably speed up your test setup.

Calling Functions and Sharing Data between Tests and Browser

Using the proxy to configure $httpBackend for simple calls is, well, simple:

proxy.whenGET('/logoff').respond(200);

But what if I want to return some big piece of JSON? If we were coding our test in the browser we might write something like:

var searchResults = require('./mock-data/searchResults.json');
$httpBackend.whenGET('/search&q=beatles').respond(200, searchResults)

This too will work just fine as long as at the time you call respond() on the proxy, searchResults resolves to a JSON object (or anything you would expect to find in a JSON object: strings, numbers, regular expressions, arrays, etc.)

To get a little fancier, you can even do this:

proxy.when('GET', /.*/)
    .respond(function(method, url){return [200, 'You called: ' + url];});

The proxy will serialize the function and send it up to the browser for execution.

But what about:

var searchResults = require('./mock-data/searchResults.json');

function getQueryTermsFrom(url){  ... implementation omitted ... };

proxy.when('GET', /search\?q=.*/)
    .respond(function(method, url){
      var term = getQueryTermFrom(url);
      var fixedUpResponse = searchResults.replace(/__TERM__/, term);
      return [200, fixedUpResponse];
    });

Now we have a problem. The proxy can serialize the function just fine and send it to the browser, but when it gets there, getQueryTermFrom and searchResults are not going to resolve. This calls for...

Using the Context Object

The proxy provides a special object called the context object that is intended to help out in theses kinds of situations. The context object is a property of the proxy, called context oddly enough, the value of which will be synchronized between the proxy and the browser-side $httpBackend before any proxied calls are executed on the browser. With this object in place we can now do the following:

var searchResults = require('./mock-data/searchResults.json');

proxy.context = {
  searchResults: searchResults,
  getQueryTermsFrom: function (url){  ... implementation omitted ... };
}

proxy.when('GET', /search\?q=.*/)
    .respond(function(method, url){
      var term = $httpBackend.context.getQueryTermFrom(url);
      var fixedUpResponse = $httpBackend.context.searchResults.replace(/__TERM__/, term);
      return [200, fixedUpResponse];
    });

Hint: If we rename our in-test proxy from proxy to $httpBackend, our tests will more easily get through any linting we may have set up.

Two caveats to the above: First, the context is limited to the following data types: strings, numbers, booleans, null, regular expresions, dates, functions, and arrays and hashes (simple objects) that in turn contain only said types, including further arrays and/or hashes. Second, any functions defined on the context object (getQueryTermsFrom in our example) must themselves either be self-contained or only reference other functions and values on the context object (or available globally in the browser, but lets not go there...)

When buffering is turned off, the context object is synchronized with the browser before every call to respond(). When buffering is turned on, this synchronization occurs as part of the call to flush(). This is important, because it is the value of the context object at the time of synchronization, not at the point when respond() is called on the proxy, that determines its value in the browser. More precisely, since values in the context object may not even be evaluated in the browser until an HTTP call occurs, the value at the time of the HTTP call will be the value of the object as of the most recent prior synchronization. Said another way, there is no closure mechanism in play here. Because of this behavior, it is also possible to manually synchronized the context object at any time. See below for how and why you might want to do this.

Configuring the Context Object

If for some reason you don't like your context object being called 'context' (or more importantly, if 'context' should turn out to conflict with a future property of $httpBackend), it can be renamed by adding contextField: "a-new-field-name" to the configuration object that the proxy is constructed with. You can also disable the auto-synchronization of the context object described above by passing contextAutoSync: false. If you do, you will need to manually invoke synchronization.

Manually Synchronizing Contexts

The state of the context object can be synchronized manually at any time by calling proxy.syncContext(). This does not flush the buffer or otherwise send any new configuration to the remote $httpBackend instance. It simply synchronizes the state of the local and in-browser context objects. syncContext returns a promise.

Why do this? Consider the above example where we have a search URL whose return value is essentially defined as context.searchResults. If we can update the context in between tests, we can effectively cause search to return different results for each test. This makes it easy, for example, to test for correct behavior when some, none, and more-than-expected results are returned.

To avoid having to write this awkward code:

proxy.context = {
  searchResults: searchResults,
  getQueryTermsFrom: function (url){  ... implementation omitted ... };
}

proxy.when( ... );

... do some tests ...

proxy.context.searchResults = emptyResults;
proxy.syncContext();

... do some more tests ...

//rinse, wash, repeat...

you can pass the new context directly to syncContext like so:

proxy.syncContext({searchResults: emptyResults});

The above will merge the provided object with any existing context and synchronize the result. Merging allows you to avoid re-specifying the entire context object. Calling syncContext in this manner also updates the instance of the context object on the local proxy as well.

Note that the merge behavior only works if both the current and newly provided values are simple javascript objects. If either value is anything but, then simple assignment is used and the value passed to syncContext will completely replace the prior value. Examples of javascript objects that are not 'simple' and will not be merged are arrays, dates, regular expressions and pretty much anything created with the new keyword. Except for arrays and regular expressions, you shouldn't be using most of these anyway as they would never be returned from an HTTP call. The proxy would likely not correctly serialize them either.

Moreover, merging is only performed for the top-level object. Nested objects are treated atomically and simply replaced.

If any of this is confusing the syncContext unit tests may help clear it up and give detailed examples of the behavior.

Configuring $httpBackend upon Page Load

All of the above works great for setting up mock HTTP responses for calls that will be made in response to user interaction with a loaded page. But what about mocking data that your Angular application requests upon page load? The proxy supports doing this through its onLoad qualifier. Any configuration of the $httpBackend that needs to happen as part of the Angular applications initialization should be specified as follows:

proxy.onLoad.when(...).respond(...);

All calls to $httpBackend that are set up in this manner will be buffered and sent to the browser using Protractor's addMockModule capability. The proxy hooks into the browser.get() method such that when your tests call get(), the proxy gathers all calls made to onLoad... and wraps them in an Angular module that will execute them in its run() callback. The proxy also makes the current value of its context object available within the callback such that it can be reference in the same manner as with post-load calls.

Calls made using the onLoad qualifier are cumulative. For example:

proxy.onLoad.whenGET('/app-config').respond(...);
browser.get('index.html');
//The /app-config endpoint is configured as part of initializing the index.html page

... do some tests...

proxy.onLoad.whenGET('/user-prefs').respond(...);
browser.get('my-account.html');
//The /app-config and /user-prefs endpoints are both configured as part of initializing the my-accounts.html page

... more tests ...

When this is not desired, it is possible to reset the proxy's buffer of commands to send upon page load by calling proxy.onLoad.reset(). This also releases the hook into browser.get() which the proxy creates when a call is registered using onLoad. To ensure that tests using onLoad do not impact other tests, it is highly recommended that reset() be called as part of test clean-up for any tests that use onLoad. Further, protractor versions prior to 0.19.0 do not support the browser.removeMockModule() method which reset uses. Reset will silently fail to remove the module in this case. If you are using a protractor version prior to 0.19.0 you can invoke browser.clearMockModules() yourself and deal with the consequences, if any, of having all modules removed. For this reason, use of onLoad with earlier versions of Protractor is not recommended.

Note that the buffer used for calls against onLoad is separate from the buffer for calls made directly against the proxy (when buffering is enabled). Only the former buffer is resettable.

Again, looking at the tests should help clarify the proxy's onLoad behavior.

Resetting the Mock

The underlying $httpBackend mock does not support resetting the set of configured calls. So there is no way to do this through the proxy either. The simplest solution is to use browser.get() to reload your page. This of course resets the entire application state, not just that of the $httpBackend. Doing so may not seem ideal but if used wisely will give you good test isolation as well resetting the proxy. Alternately, you can use the techniques described under context synchronization above to modify the mock's behavior for each test.

The Test-Harness Application

The angular application that makes up most of this repository is simply a test harness for the proxy. It enables testing the proxy by way of Protractor. However it can also be used to manually tests the 'hard-coded' $httpBackend configuration set up in app.js. Manual testing can useful for debugging problems during proxy development.

Chance are, unless you plan to contribute to the development of http-backend-proxy, you will never need to load the test harness and can safely skip this section.

Setup

Install Dependencies

There are three kinds of dependencies in this project: tools, angular framework code and bootstrap css. The tools help us manage and test the application.

  • We get the tools we depend upon via npm, the node package manager.
  • We get the angular code via bower, a client-side code package manager.
  • I added bootstrap.css as a hard-coded dependency under app/css just to make the test harness look nice. :-) Strictly speaking it is not needed.

None of these dependencies are needed for http-backend-proxy itself. They are only needed for the test harness. Thus the project is configured to only install the npm dependencies if you specify the --dev option on your npm install command. Likewise, the bower dependencies are installed when you do npm run (below) to start the test harness for the first time.

Once the node (npm) modules and bower moduels are installed, you should find that you have two new folders in your project.

  • node_modules - contains the npm packages for the tools we need
  • bower_components - contains the angular framework files

Run the Test Harness

The project is preconfigured with a simple development web server to host the test harness. The simplest way to start this server is:

npm start

Now browse to the app at http://localhost:8000/app/index.html.

Directory Layout

app/                --> all of the files to be used in production
  css/              --> css files
    app.css         --> default stylesheet
    bootstrap.css   --> bootstrap stylesheet
  index.html        --> that test app's single page and view.
  js/               --> javascript files
    app.js          --> the application's angular code

test/               --> test config and source files
  protractor-conf.js    --> config file for running e2e tests with Protractor
  e2e/                  --> end-to-end specs
    ...
  lib/
    http-backend-proxy.js  ==>This is the proxy library itself.
  unit/                 --> unit level specs/tests
    ...

Testing

There are two kinds of tests in the project: Unit tests and end-to-end tests.

Running the Unit Tests

The project contains unit tests for testing the proxy behavior in abstraction from Protractor and Selenium. These are written in Jasmine and run using the Jasmine-Node test runner.

  • the unit tests are found in test/unit/.

The easiest way to run the unit tests is to use the supplied npm script:

npm test

This script will start the Jasmine-Node test runner to execute the unit tests.

If you are actually doing development work on the proxy itself (Thank you!) and want to run the tests continuously as you work, use the following command line.

npm run test-watch

This will watch both the test/unit and test/lib directories.

Running the End-to-End Tests

The project comes with end-to-end tests, again written in Jasmine. These tests are run using Protractor. They also demonstrate how to actually use the proxy to manipulate $httpBackend in your tests. I recommend taking a look.

  • the configuration is found at test/protractor-conf.js
  • the end-to-end tests are found in test/e2e/

To run them, first start the test harness.

npm start

In addition, since Protractor is built upon WebDriver we need to install this. The angular-seed project comes with a predefined script to do this:

npm run update-webdriver

This will download and install the latest version of the stand-alone WebDriver tool.

Once you have ensured that the development web server hosting the test harness is up and running and WebDriver is updated, you can run the end-to-end tests using the supplied npm script:

npm run e2e

This script will execute the end-to-end tests against the application being hosted on the development server.

Feedback and Support

To provide feedback or get support, please post an issue on the GitHub project.

http-backend-proxy's People

Contributors

andyperlitch avatar azevedo avatar jslain avatar kbaltrinic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http-backend-proxy's Issues

Protractor: Testing Angular App in an Iframe using mock data

I have an Angular App that loads another Angular App inside an iframe. I'm interested in testing the iframed-in Angular app with Protractor. (using mockdata).

before open the iframe all mocked Request and response are working fine .

While on opening the Iframe with mocked Request and response is not working.
while on opening the Iframe it loads another Angular App inside an iframe...Recheck the user is still logged in Request getting Response code 401 how to solve this ?

How can we mock two responses for same request i.e, one on page load and other one on page request.

I have a scenario where I need to mock a http request two times. i.e., on page load it should return 401 status and on page when I fill the username, password and click on login button, it will request the same url and should return 200 status.

Below is the code snippet:

proxy.onLoad.when('GET','http://localhost:8080/login')
            .respond(function(method, url){return [401,{"message":"Authorization has been denied for this request."}];});

browser.get('http://localhost:8888');

proxy.when('GET','http://localhost:8080/login')
            .respond(function(method, url){return [200,{"message":"Authorization has been sucess for this request."}];});

I'm getting same response for onload and onpage request i.e., 401 status.

Please let me know how can I mock such scenario's.

calling an undefined function when running .respond(200)

when i run the following snippet from within protractor:

var HttpBackend = require('http-backend-proxy');
var proxy = new HttpBackend(browser);

describe('foo', function() {
  it('should foo', function() {

    proxy.whenPOST('/auth/sign_in').respond(200);

  });
});

i get the following error:

   Stacktrace:
     UnknownError: unknown error: undefined is not a function
  (Session info: chrome=38.0.2125.104)
  (Driver info: chromedriver=2.10.267517,platform=Mac OS X 10.9.5 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 2 milliseconds
Build info: version: '2.43.1', revision: '5163bce', time: '2014-09-10 16:27:33'
System info: host: 'dc-mbp', ip: '192.168.1.3', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9.5', java.version: '1.8.0_20'
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{applicationCacheEnabled=false, rotatable=false, chrome={userDataDir=/var/folders/tv/cj4wg9x57xjbd2w91cp5r77c0000gn/T/.org.chromium.Chromium.v6QYuB}, takesHeapSnapshot=true, databaseEnabled=false, handlesAlerts=true, version=38.0.2125.104, platform=MAC, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}]
Session ID: e4da1c3c9fd2751b6cf744a6967ce35b
==== async task ====
WebDriver.executeScript()
    at executeOrBuffer (/Users/dc/dev/oscil.io/frontend-gulp/node_modules/http-backend-proxy/test/lib/http-backend-proxy.js:65:22)
    at Object.respond (/Users/dc/dev/oscil.io/frontend-gulp/node_modules/http-backend-proxy/test/lib/http-backend-proxy.js:46:18)
    at null.<anonymous> (/Users/dc/dev/oscil.io/frontend-gulp/spec/users_can_sign_up_spec.js:28:10)
==== async task ====
Asynchronous test function: it()
Error
    at null.<anonymous> (/Users/dc/dev/oscil.io/frontend-gulp/spec/users_can_sign_up_spec.js:11:3)
    at Object.<anonymous> (/Users/dc/dev/oscil.io/frontend-gulp/spec/users_can_sign_up_spec.js:4:1)

Works with AngularJS app only

Here is what I got when implementing a testcase (using Protractor) with the proxy:

UnknownError: unknown error: angular is not defined

Is there any plan on supporting non-angular app? You know Protractor does, so should your http-backend-proxy. I would love to contribute.

Clear Mock between test suite

Hi @kbaltrinic,

thanks for this module.

I've defined two suites in my protractor tests, and I run only one of them both are passing, here is the code:

'use strict';

var mock = require('./mock/user.mock.js');
var httpBackend = require('http-backend-proxy');

describe('The registration view', function () {
    var page, proxy;

    beforeEach(function () {
        browser.get('http://localhost:3000/#/user/login');
        page = require('./registration.po');
        proxy = new httpBackend(browser);

        // Mock Request
        proxy.onLoad.whenPOST('http://localhost:3001/api/members/login?include=user', mock.wrongLoginRequest).respond(422, mock.wrongLoginResponse);
        proxy.onLoad.whenGET(/.*/).passThrough();

        // remove overlay and loader
        browser.executeScript("$('.page-loading-overlay').addClass('loaded');");
        browser.executeScript("$('.load_circle_wrapper').addClass('loaded');");
    });
    // TESTS ...
});
'use strict';

var mock = require('./mock/user.mock.js');
var httpBackend = require('http-backend-proxy');

describe('The registration view', function () {
    var page, proxy;

    beforeEach(function () {
        browser.get('http://localhost:3000/#/user/register');
        page = require('./registration.po');
        proxy = new httpBackend(browser);

        // Mock Request
        proxy.onLoad.whenPOST('http://localhost:3001/api/members', mock.existingUser).respond(422, mock.registrationError);
        proxy.onLoad.whenPOST('http://localhost:3001/api/members').respond(200, mock.registrationSuccess);
        proxy.onLoad.whenGET(/.*/).passThrough();

        // remove overlay and loader
        browser.executeScript("$('.page-loading-overlay').addClass('loaded');");
        browser.executeScript("$('.load_circle_wrapper').addClass('loaded');");
    });

    // TEST ....
});

My problem is that if I run all the tests together the second suite broke as it not get the mocked request.

I tried to add:

afterEach(function(){
    proxy.reset();
});

But with no effect... Any advice?

I also tried to use the proxy without the .onLoad method but it end up with:

UnknownError: unknown error: $httpBackend.whenPOST is not a function

And I can't get why...

simulate delay in response

How do I simulate a delay in responding to the http requests? In few of my tests, I want to respond after few seconds inside whenGET('/foo/get/account').respond( 200, response). How do I achieve it?
I tried with setTimeout but no success yet.

Mocked request not being updated

Hi,

I am trying to update the data returned for a call within a test using the syncContext.

I do something like this:
proxy.context = {
notes: notifications,
messages: allMessages
};

notifications and all messages are json objects that i pull in by doing:
var notifications = require('../fixtures/notifications.json');

proxy.when('GET', '...notificationsURL...').respond(200, proxy.context.notes);

The first time the call is made the correct data is loaded.

Before the second call is made I do,
proxy.syncContext({
notes: notifications2,
messages: messages2
});

When I print the values to the console, the correct values are displayed:
console.log(proxy.context.notes);
console.log(proxy.context.allconvos);

However, the next time the call is made, the original data is returned, not the data that I updated using SyncContext.

Is there something else I need to be doing?

Thanks!

Is it possible to navigate without browser.get and still invoke whenGET?

The application I am working on creates a new session when the application loads (to allow deep linking). This means browser.get, although it returns the required mock data, causes the page being got to start a new session. If I get protractor to click my search button, the application works like it does in a real environment and navigates to the new page without refreshing, however whenGET is not invoked and live data is returned from the api.

Different response return when caching is enabled

Hi,

I have an angular js application that i'm using http-backend-proxy to try to mock the backend. It is using an angular cache factory (DSCacheFactory). When i disable the caching, everything works fine. When the cache is enabled, the format of the response being returned is different from the first call to the second call. In my tests, the initial page loads containing a list of messages. The messages are what I mocked and on the initial load they load fine. I go to another page (settings) then go back to the messages back and it fails. It fails because the data retrieved is now in a different format.

I added console statements to debug which shows the difference in the data:
On initial load:
image

On second attempt:
image

Since there is no messages array in the second attempt, it fails.

Does anyone know why this is occurring or how to fix?

Thanks!

Http Backend Missing

I'm seeing an error $httpBackend.when is not a function when I try and use this library.

No Mocking Unless Original Request Returns 200 OK

Hi and thank you for this module!

I've found it very useful, but lately I have noticed that whenever the request I am mocking doesn't go through (does not return 200 OK), then the mocking doesn't occur.

Is this a know issue or can it be solved in some way?

I am calling all my mocks from Protractor's configuration file using the onLoad.whenGET()... respond() way.

Unable to override [requestHandler] as per angular documentation

Hi there,

I'm having a bit of difficulty defining a proxy to selectively fail a test on demand, in my E2E protractor testing...

Just for reference, this is how I instantiate the proxy module at the beginning of my tests...

beforeAll(function(){
    // Set initial window dimensions
    var width = 1280;
    var height = 780;
    browser.driver.manage().window().setSize(width, height);

    // Schedule to attach the mock $httpBackend when app starts
    browser.addMockModule('app', function () {
        angular.module('app').requires.push('ngMockE2E');
    });

    // Set global to allow using proxy throughout tests
    var proxy = global.proxy = new HttpBackend(browser);
    // Allow all GET requests before page loads to allow assets to load
    proxy.onLoad.when('GET', /.*/).passThrough();

    browser.get(browser.baseUrl).then(function(){
        browser.executeScript("localStorage.clear();");
        browser.executeScript("config.viewPath = 'views/';");
        browser.executeScript("config.version = 'v-0.0.0.0';");
        browser.executeScript("window.requestCount = 0;");
        browser.executeScript("window.responseCount = 0;");
        browser.executeScript("window.lastResponses = [];");

        // Returns the config object for use in testing
        browser.executeScript("return config").then(function(config){
            global.config = config;
        });

        proxy.onLoad.reset();
    });
});

According to the docs over at https://docs.angularjs.org/api/ngMockE2E/service/$httpBackend

...I should be able to do the following to allow me to ad-hoc 'override' an endpoint to allow me to force a failure, then reset that override to allow a normal API response in further tests...

        var httpHandler = proxy.whenPUT(/\/register$/);
        httpHandler.respond(500);

        helper.button.manualBarcode();
        helper.trigger.keypad(helper.setup.key());
        expect($('.pz-dialog.alert-dialog').isPresent()).toBeTruthy();

        httpHandler.passThrough();

I can't for the life of me get this to work. The initial httpHandler.respond(500) sets up the failure response perfectly fine but the second call to httpHandler.passThrough() has no effect. I expect it to effectively cancel the override. The test that runs after this block of code (that expects a 200 response from the API) is still getting the 500 error response from the proxy.

I've got to a point now where I just don't think it's possible without doing a full browser.get() for each test (which would be a massive pain due to the way we have the tests written, but alas, if it's the only way I might just have to go down that approach).

I know I can define a context for each test, then have the initial handler interpret the data and respond accordingly, but it doesn't seem that I can selectively passThrough() these requests and respond with fake data for others. It also isn't ideal as the initial setup needs to know about all the tests that follow; something which doesn't sit right with me.

Fundamentally, I just want to be able to selectively fail a HTTP request on-demand but having this proxy module work as required would be far more flexible. I've thought about creating a HTTP intercept service and injecting that at runtime and injecting a variable using browser.executeScript to change the behaviour when required but that's a last resort at the minute.

Any help would be highly appreciated!
Thanks

How to change already mocked requests

I don't really understand the difference between onLoad.when and when and how can I overwrite already mocked request for specific test. I'm mocking "sign in" request with a JSON response using onLoad and then try to modify the response in a specific test:

# http_backend.coffee
...
proxy.onLoad
    .when("POST", "#{proxy.api}/login.json", user: {email: "[email protected]", password: "secret"})
    .respond(201, require("./responses/v2/successful_login.json"))

# test.coffee
proxy  = require("./support/http_backend")

describe "Something", ->
  it "changes previously mocked request", ->
    response = require("./support/responses/v2/successful_login.json")
    response.user.locale = 'es'
    proxy.onLoad
      .when("POST", "#{proxy.api}/login.json", user: {email: "[email protected]", password: "secret"})
      .respond(201, response)

    browser.get("/")
    ...  

Should it work or should I do it somehow differently?

2nd test fails when using mocked calls

Hi,

I have 2 tests within my protractor spec file. I do the setup of the mocked calls in the beforeEach() as shown below. Each test will pass when ran individually, but it will fail on the 2nd test if I run both.

beforeEach(function () {
httpBackend = new HttpBackend(browser);

httpBackend.onLoad.when('GET', /scripts.*/).passThrough();
httpBackend.onLoad.when('GET', /views.*/).passThrough();
.....all of the onLoad calls...... 
browser.get(browser.params.route);

httpBackend.when('GET', /images.*/).passThrough(); 
httpBackend.when('GET', '....URL....').respond(function () {
          return [200, $httpBackend.context.conversations];
        });
.....all of the calls to load......

login to application

})

afterEach(function(){
logout of application
httpBackend.onLoad.reset();
})

it ('test 1', function(){
.....
})

it ('test 2', function(){
.....
})

Thanks -

Mocked POST ignored

Hi my protractor + jasmine test looks as follows

beforall =>

mock a post request on page load
pass through all requests on page load

it =>

test if the mocked post above is working ( true)

do another post mock (not using onLoad)

test if this mocked post is working ( false) // this fails looks like passing trough all request in the beforeall overrides the post mock in the "it" method ?

//even if i add passThrough() for all requests (not onLoad) it does not make any difference.

When using this package, do you have to mock _all_ service responses?

Hi

I've got this running now (initially had the issues described in #1), and have written an e2e test that mocks one of the service responses that the app requires (in my case, I want to test what happens when the service call fails).

I now am receiving different errors... when I insert a browser.pause() in the e2e tests, it looks like the other service calls that the app makes are producing a 404 response.

So to my question: when I am using http-backend-proxy, is it a complete replacement for the service layer? Which would mean that I have to mock all the service responses?

My ideal solution is one where, by default, the normal services are used, and I can select which service responses to override.

Many thanks

Matt

undefined is not a function error throws when respond or flush[with buffer] is called

Hi , I have downloaded the proxy using 'npm install http-backend-proxy' and in my test file i have set
HttpBackend = require('http-backend-proxy');
proxy = new HttpBackend(browser);

when i do
res = proxy.whenGET('/api/v2/catalog/')
,and try to console output the 'res' variable I get the respond and passThrough functions which is correct but at the same time if i do
res = proxy.whenGET('/api/v2/catalog/').respond(200);
and console output it res is getting resolved with
{ then: [Function: then],
cancel: [Function: cancel],
isPending: [Function: isPending] }

but i get this ERROR on the line where respond is called.
Stacktrace:
UnknownError: unknown error: undefined is not a function
(Session info: chrome=35.0.1916.114)
(Driver info: chromedriver=2.9.248307,platform=Mac OS X 10.9.2 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 87 milliseconds
Build info: version: '2.41.0', revision: '3192d8a', time: '2014-03-27 17:17:32'
==== async task ====
WebDriver.executeScript()
at executeOrBuffer (/Users//projects/projectname/node_modules/http-backend-proxy/test/lib/http-backend-proxy.js:65:22)
at Object.respond (/Users//projects/projectname/node_modules/http-backend-proxy/test/lib/http-backend-proxy.js:46:18)
at null. (/Users//projects/projectname/test/client/preview-card/ew-383.step.js:22:10)
==== async task ====
Asynchronous test function: beforeEach()
Error
at null. (/Users//projects/projectname/test/client/preview-card/ew-383.step.js:12:3)
at Object. (/Users//projects/projectname/test/client/preview-card/ew-383.step.js:1:63)

Also providing below the script for the 'proxy.whenGET('/api/v2/catalog/').respond(200);' that has been passed through the executeOrBuffer(script) function.

var el = document.querySelector("body"); angular.element(el).injector().invoke(function($httpBackend){ $httpBackend.context={};$httpBackend.whenGET("/api/v2/catalog/assets/79e50971-9a09-4814-8471-11e20d40fc0b?artwork=art220x326").respond("200");});

I have also tried using buffer:true and using proxy.flush but again it fails with the same error on the line proxy.flush(). Not sure what am doing wrong as i have set everything according to the wiki

TypeError: undefined is not a function in proxy.whenGet()

i have a simple test that won't recognize whenGET from Httpbackend; it's not barfing on the require('Httpbackend') so I know it's finding the library.

var HttpBackend = require('http-backend-proxy');
var proxy = new HttpBackend(browser, {buffer: true});
var loginpage = require('./pages/login.page.js');
var loginUser = {
"_id": 33,
"username": "tlouisa",
"token": "{5D0A97C1-8659-4995-A8F3-31E20BA46AE9}",
"person": {"name": "Thelma Louisa"},
"address": "123 Main Street",
"credentialList": [],
"services": []
};

describe('login', function () {

var page;

beforeEach(function () {
    page = new loginpage();
});

beforeEach(function () {
    browser.ignoreSynchronization = true;
});

it('should go to mainmenu after successful login', function () {
    proxy.whenGet(/^\/login\//).respond(200,loginUser);  <-- error on this line *****
    proxy.whenGet(/^\/templates\//).passThrough();
    proxy.whenGet(/^\/shifts\//).passThrough();

    browser.executeScript("localStorage.removeItem('activeUser');");
    page.username.sendKeys('tlouisa');
    page.loginButton.click();
    browser.sleep(2000);
    expect(browser.getCurrentUrl()).toEqual('http://localhost:8100/#/mainmenu');
    browser.sleep(2000);
});

});

Not working with JSPM

I'm using JSPM for my front-end dependencies management.
No modules are polluting the global namespace, including 'angular'.

Generally, when i use a third-party library that need angular in the global namespace, i can hack it in the JSPM config file, using a shim.
I don't fully undertsand how http-backend-proxy works, but it would be easy for me if i could simply add something like...
var angular = require('angular');
... at the beginning of the generated module code.
Is there a point of insertion for me to inject some custom code before the module get sent to the browser?

My current error is:
Failed: unknown error: angular is not defined
And i definitely don't wanna add angular directly in my page, since it'ld break the purpose of the E2E test. (angular IS NOT polluting the global namespace once truly deployed)

whenGET function doesn't get called!

In my application, I am trying to mock backend data on GET request. I have already written code to initiate http-backend-proxy, defined onload functions and added mock json data in my app. But when I try to run the app and API call is made, the proxy.onload.whenGET function would not get executed. I don't know where am I doing wrong. Can you please give me any pointer to solve my problem?

Using http-backend-proxy.js on frontend

I try to use http-backend-proxy like on example file:
https://github.com/kbaltrinic/http-backend-proxy/blob/master/test/e2e/proxy-when-spec.js

describe('Test', function () {
    var Homepage = require('../_page-objects/home-page.js'),    
        Device = require('../_page-objects/device.js'),
        HttpBackend = require('../http-backend-proxy');

    describe('Test', function () {
        beforeEach(function () {
            Homepage.navigate();
            httpBackend = new HttpBackend(browser);
            Device.setScreenResolution('large-desktop');
        });
it('should ', function () {
            httpBackend.when('GET', '/remote').respond(200, {
                msg: "You called /remote",
            }, {'test-header': 'remote success'});

        });

but I'm getting from protractor:
A Jasmine spec timed out. Resetting the WebDriver Control Flow.
The last active task was:
unknown
Failed.

Message:
UnknownError: unknown error: undefined is not a function

What is going on because with normal approach $httpMock it works fine

Cheers

precedence of passThrought() calls and mock calls

Hi the core anguraljs httBackend has this shortcoming that if you want some request to pass you have to specify them after your mock request, this means that you cannot have it nicely layout in the jasmine test where you would put all your passThrough() stuff in beforeAll() and the requests you actually want to mock in the test in self.

Are you able to add such a functionality ? I was hoping that the onLoad can do this but it does not.

Treatment of Regular Expressions

I've noticed that when given a regular expression to match, the httpBackendProxy injects the script into the page calling the toString method on the regular expression. This is a problem when the regular expression contains forward slashes that are not escaped. For example, new RegExp("/api/items$") is a valid regular expression and matches the URL "http://localhost/api/items", but when calling the toString method on it we get //api/items$/, instead of /\/api\/items$/. Perhaps we can replace the obj.toString() call with "new RegExp(" + obj.toString().slice(1, -1) + ")"?

It's a great project so thanks for all the help it's given us in our testing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.