2

I'm in the process of upgrading an AngularJS v1.5 project to Angular 4.x. During development of the original AngularJS application, we would use the ngMocks package to simulate actual web service API responses, and display the data accordingly on the page. This was incredibly helpful during development as I didn't have to hard-code values for removal later on. Best of all, we configured Webpack to only include the mock data during development, and ignore those mock data files when building our application for production use. The mock data was configured like this:

/* app-login.mock.js */
import angular from 'angular';
import 'angular-mocks';

angular.module('app').run(function ($httpBackend) {
    $httpBackend
        .whenPOST('./api/auth')
        .respond(function(method, url, data) {
            var credentials = angular.fromJson(data);
            if (credentials.username == 'gooduser') {
                return [200, {'token': createToken(credentials.username)}];
            } else {
                return [401, {'errorMsg': 'Mock login only allows username "gooduser"'}];
            }
        });
});

function createToken(username) {
    // Create a token, which is valid enough for testing purposes.
    // This token is based on the actual token generated by the web service.
    let currentTime = new Date();
    let futureTime = new Date(currentTime.getTime() + ((currentTime.getHours() + 8) * 60 * 60 * 1000));

    let header = {
        alg: 'HS512'
    };

    let payload = {
        exp: futureTime.getTime() / 1000,
        sub: username,
        roles: 'SOME_APPLICATION_ROLES',
        iat: currentTime.getTime() / 1000
    };

    return `${btoa(angular.toJson(header))}.${btoa(angular.toJson(payload))}`;
}

Webpack was then configured to include all "mock" files into the built bundle, which could then be displayed as if it were a real HTTP response.

/* webpack.config.js */
const isProd = process.env.NODE_ENV === 'production';

const entry = {
    app: (() => {
        let app = [
            'babel-polyfill',
            path.join(PATHS.app, 'pollyfills.ts'),
            path.join(PATHS.app, 'main.ts')
        ];

        if (isProd) {
            app.push(path.join(PATHS.app, 'app.prod.js'));
        } else {
            app.push(path.join(PATHS.app, 'app.mock.js'));
        }

        return app;
    })()
};

module.exports = {
    entry,
    // ...other exports
};

And then the app.mock.js file:

/* app.mock.js */
var mockContext = require.context(".", true, /\.mock$/);
mockContext.keys().forEach(mockContext);

I've scoured the internet looking for a solution that works just as well as our old one, though I haven't come up with any good answers. Best I've found are tutorials on how to set up Unit Tests that return mock data, and while that's useful for testing functionality it doesn't help me test the application during the development process.

I also have seen some documentation on setting up Interceptors using the new HttpClient class found within Angular 4, but I'm not sure how to add it to our Webpack configuration under the condition of only being allowed during development. Does anyone have any advice on what to do?

2
  • Have you tried json-server . I use that in our app Commented Sep 30, 2017 at 3:35
  • I've never heard of it, but I'll have myself a look. Thanks for the suggestion! Commented Sep 30, 2017 at 16:10

1 Answer 1

6

I use the angular-in-memory-web-api. You can find it here: https://github.com/angular/in-memory-web-api

UPDATE: The repo was moved here, within the angular/angular repo: https://github.com/angular/angular/tree/e0dfa42d6e656124f3c3d78e178b1bf091b38e79/packages/misc/angular-in-memory-web-api

It intercepts all of your http calls and works with sample data you provide.

To change from dev to production, you need to remove the imports. Or you could possibly write two different modules, one with the dev imports and one with the production imports and include one or the other with webpack similar to what you do now. (But I have not tried this.)

You set up your data like this:

import { InMemoryDbService } from 'angular-in-memory-web-api';

import { IProduct } from './product';

export class ProductData implements InMemoryDbService {

    createDb() {
        let products: IProduct[] = [
            {
                'id': 1,
                'productName': 'Leaf Rake',
                'productCode': 'GDN-0011',
                'releaseDate': 'March 19, 2016',
                'description': 'Leaf rake with 48-inch wooden handle.',
                'price': 19.95,
                'starRating': 3.2,
                'imageUrl': 'http://openclipart.org/image/300px/svg_to_png/26215/Anonymous_Leaf_Rake.png',
                'tags': ['rake', 'leaf', 'yard', 'home']
            }, 
            // ...
        ];
        return { products };
    }
}

And you build your data access service using the normal Http or HttpClient.

I have a full example with all CRUD operations here: https://github.com/DeborahK/Angular2-ReactiveForms

Sign up to request clarification or add additional context in comments.

3 Comments

Angular-in-memory-web-api github repo has been archived by the owner and there is a limition by the owner that the libary is not stable and they will not feel bad if they break it: "Most importantly, it is always experimental. We will make breaking changes and we won't feel bad about it because this is a development tool, not a production product" do you still recommend using it?
The reason it was archived there is because it was moved to within the angular/angular github repo here: github.com/angular/angular/tree/…
And yes, I still recommend it for simulating CRUD operations during development.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.