Use Angular mock to load JSON file for Backendless development
Asked Answered
W

5

9

I wrote this little code in separate .js file for frontend backendless environment. I need to get myfile.json whenever there is an ajax calling /somelink.

angular.module('myApp')
.config(function($provide) {
  $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
})
.run(function($httpBackend, $http) {

  $httpBackend.whenGET('/somelink').respond(function(method, url, data) {
    $http({method: 'GET', url: '/somelink/myfile.json'})
    .success(function(data, status, headers, config) {
      return data;
    })
    .error(function(data, status, headers, config) {
    });

  });
});

However this code doesn't work and gave me error:

Error: Unexpected request: GET /somelink/myfile.json

Can someone help me fix this?

Note that I don't want to call $http directly to get .json file inside my code because that will trash the production code. The purpose of doing this is to keep this code for backendless development separately.

Thanks.

UPDATE 1:

I added:

$rootScope.$apply(); 
$httpBackend.flush();

Now I have another error in addition to same one previously: Uncaught Error: No pending request to flush !

UPDATE 2:

After playing around, I found a small hack. I put this in .run() before all other $httpBackend mocks. Also this .js file must be placed before all controllers/services/directives and after the app.js bootstrap.

  var data;

  $.ajax({
    type: 'GET',
    async: false,
    url: '/somelink/myfile.json'
  }).success(function(res) {
    data = res;
  }).error(function(data) {
  });

Then this:

$httpBackend.whenGET('/somelink').respond(data);

The key is async: false so that this makes sure the JSON is loaded into variable data. All of these must happen before other objects triggered and call ajax events. This is a hack for frontend backendless development only. When production, of course this .js file is removed. I don't like this much is because using async: false and direct $.ajax() instead of $http

Wolfe answered 4/1, 2014 at 0:29 Comment(0)
C
8

Following worked for me without any hack

$httpBackend.whenGET('/endpoint').respond($resource("/path/to.json").query());

Courtesy https://groups.google.com/d/msg/angular/grbwk-VehDE/UBIho6qcmLMJ

Contusion answered 18/6, 2014 at 7:21 Comment(2)
I am getting an error when I do this: Uncaught Error: Unexpected request: GET /mockData.json No more request expectedMonogenesis
You have to by pass /mockData.json through mock service. Try httpBackend.whenGET(/mockData.json/).passThrough();Kayleigh
G
4

A very clean solution to this problem is to work with plain vanilla JavaScript since $httpBackend is not made to handle asynchronous requests.

This method doesn't require jQuery code.

$httpBackend.when('GET', 'http://localhost:3000/api/data').respond(getData());

function getData() {
               var request = new XMLHttpRequest();
               request.open('GET', '/db/myData.json', false);
               request.send(null);

               return [request.status, request.response, {}];
}

I got this tip from: https://mcmap.net/q/575197/-how-to-return-a-file-content-from-angular-39-s-httpbackend

Garbers answered 29/11, 2015 at 9:55 Comment(1)
wow I couldn't get this to work for the longest time. thanks for your very clear answer.Estimative
B
3

I know it's a late response but will share my experience hoping to be of some help for future peers.

I successfully achieved a working mocked backend thanks to this extremely useful blog post.

First of all I put all my endpoints in one place as constants in order to define them only once and have them available in the mocked backend, in my tests and obviously in all the services responsible of AJAX calls.

angular.module('appName.urls', [])
 .constant('API_endpoints', {
   login: 'authentication/login',
   logout: 'authentication/logout',
   signUp: 'authentication/signup',
   userList: 'users/list'
 });

I then added ngMockE2E as a dependency to the whole app.

angular.module('appName', [
  'ui.router',
   ... 
  'ngMockE2E'
])

Then I created a file for the actual mocked backend, let's call it fakeBackend.js and referenced in the index.html. This file was taken from the above link, but here's a simplified example from my implementation (here serving an emulated login):

angular.module('appName').run(function($httpBackend, API_endpoints) {

   var credentials = {
    email : '[email protected]',
    password : '12345'
  };

  $httpBackend.whenPOST(API_endpoints.login)
              .respond(function(method, url, data) {

    var req = JSON.parse(data),
        res;
    // very light credential check...
    if(req.email === credentials.email && req.password === credentials.password ){
        // generate a successful response
        res = [200, {uuid:1}, {}];
    } else {
        // generate an error if credentials are wrong
        res = [400, {}, {}];
    }
    return res;
  });

   // Respond to all templates request
   // Every file in states/ folder will be served automatically
   $httpBackend.whenGET(/states\//).passThrough();
}):

Note also the last line that serves all the content from my states folder, where all my templates reside. This is obviously a very simplistic example, but the blog post author also shared a very detailed and useful plunkr.

Biernat answered 13/2, 2015 at 23:19 Comment(0)
C
2

I (and many others) have had this problem when using $httpBackend for testing. I haven't yet used it for backendless development. The solution in a test is:

AngularJS is opinionated AND hungry, so to make $http requests fire in a test, you must either $apply or $digest.

to make $http work in my test I had to

root.$apply(); 
httpBackend.flush();

Perhaps something like this will help you.

Coventry answered 4/1, 2014 at 1:0 Comment(2)
Sorry it didn't work. what happens when you do the apply without doing the flush?Coventry
apply without doing the flush -> nothing happened. Same as original postWolfe
E
1

@Aakash Shah's answer to use raw javascript to make a synchronous xhr request worked amazingly for me. here's a bit more code to clarify how I generalized it.

addMock('/mocks/json/myjson.json', new RegExp('yada/.*/getMyJson'));

    function addMock(jsonFilePath, urlToReplace) {
        $httpBackend.whenGET(urlToReplace)
            .respond.apply(this, getData(jsonFilePath)); // apply to put the parameters as args
    }

    function getData(jsonFilePath) {
        var request = new XMLHttpRequest();
        request.open('GET', jsonFilePath, false);
        request.send(null);

        return [request.status, request.response, {}];
    }
Estimative answered 30/11, 2015 at 17:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.