Code Monkey home page Code Monkey logo

bardjs's Introduction

bardjs Test Helpers

NPM version

bardjs is a small library of functions to help you write Angular v.1.x application tests ... whether you write them in mocha or jasmine or QUnit.

What kind of help? Help with routine tasks that would otherwise clutter your tests and obscure their intent.

The poster child in this respect is the inject method. It can easily remove 10 or more lines of boilerplate so you spend less time with setup and more time with your tests. Check it out.

The bardjs repo also contains code snippets to make writing tests a little easier. See separate instructions for those below.

Installation

Most folks bardjs install it with bower or npm:

bower install bardjs

npm install bardjs

You can also clone bardjs from github and extract bard.jsitself.

bard depends on sinon.js so make sure you have that library available; bower and npm bring that down for you.

Almost all of bard is in the bard.js file within the dist folder.

If you're running tests in a browser, add the appropriate script tag below the script for your test framework library:

<!-- when installed with bower -->
<script src="/bower_components/bardjs/dist/bard.js"></script>

<!-- when installed with npm -->
<script src="/npm_modules/bardjs/dist/bard.js"></script>

You'll need to add sinon.js as well

<!-- when installed with bower -->
<script src="/bower_components/sinon/index.js"></script>

<!-- when installed with npm -->
<script src="/npm_modules/sinon/lib/sinon.js"></script>

karma considerations

If you're running with karma, reference bard.js in karma.config.js among the files to be loaded. See the karma "Config" documentation for details.

Be sure to include sinon among the karma frameworks as in this example extract:

frameworks: ['mocha', 'chai', 'sinon', 'chai-sinon'],

In the dist folder you'll also find optional plug-in extensions such as the bard-ngRouteTester.js which adds the bard.ngRouteTester helper to manage tests of the original Angular router.

bard methods

After loading bard.js, you'll find the global variable bard at your finger tips as you write your tests.

The bard methods are listed right at the top of the bard.js file.

We won't describe every method here. Each method is prefaced in the code with it own documentation in comments describing both purpose and usage.

But we will call out the methods that have proven most notable and useful:

  • appModule - identify the application module to test and also disable certain routine services.
  • asyncModule - enable async integration testing by restoring $http and $q while identifying the application module to test.
  • inject - inject angular and application components and store them by name on the global window object.
  • fake services - register disabled services that you can spy on.
  • log - writes messages to console when bard debugging is turned on.
  • mockService - create a mock for any service with spies and return values for every service member.

appModule

Identify the application module to test and also disable certain routine services.

You typically identify the application module that defines the component you want to test and its dependent services at the top of a test suite. You do this with the angular.mock.module function.

We found that we routinely disable certain services at the same time.

For example, we don't want to see toastr messages in our browser while our tests are running. We may need to assert that toastr was called in a particular way but we'd prefer to hide the toasts themselves.

We also discovered that routing services can fire when the app module loads and trigger failures that have nothing to do with the subject of our tests. We just want routing to go away.

The bard appModule method is a quick way to both identify the module to test and disable the toastr and routing services. This one line ...

beforeEach(bard.appModule('myModule'));

does the work of these seven ...

beforeEach(angular.mock.module(
	'myModule',
	bard.fakeToastr,
	bard.fakeRouteHelperProvider,
	bard.fakeRouteProvider,
	bard.fakeStateProvider)
);

The bard library offers several methods (all beginning with the word "fake") that each disable a particular service. Don't worry if you haven't included all or any of these services in your app. Registering them will be harmless. Not using toastr? Not using the UIRouter? No problem.

Like the angular.mock.module function, you can add configuration arguments to the call to decorate or mock other services:

beforeEach(bard.appModule('myModule', someDecorator, someMock));

don't use appModule when testing routes

You can't use bard.appModule and test the router. For example, if you want to know that a controller would route the user to a particular view, you can't use bard.appModule. There is no way to "unfake" the router service once it's been faked.

Instead, simply fall back to angular.mock.module, adding specific fakes as desired:

beforeEach(module('myModule', bard.fakeToastr));

asyncModule

Enable async integration testing by restoring $httpBackend and $q while identifying the application module to test.

The angular.mock.module function replaces $httpBackend and $q with mocked versions.

The mocked $httpBackend prevents $http from issuing the AJAX calls necessary to communicate with a remote service. The mocked $q requires a manual digest cycle to "flush" the promise queue and prevents event-driven promise fulfillment.

These mocks are great for testing asynchronous behaviors with fast synchronous tests. But you can't write integration tests that require interactions with a server while these mocks are in play.

For example, you can't test that a dataservice works as expected when it sends requests to the remote data server. You can simulate how you think that server will respond. But what if the real server behaves differently than your simulation? How can you confirm that your dataservice continues working even after changes to the backend that you don't even know about?

You'll want at least a few cross-process, truly asynchronous integration tests for peace of mind. You can't have them while $httpBackend and $q are mocked.

The bard asyncModule method restores the original $httpBackend and $q at the same time that you identify the application module under test. Here's how you might call it:

beforeEach(bard.asyncModule('app'));

This is the equivalent of ...

beforeEach(module('app', bard.$httpBackendReal, bard.$qReal, bard.fakeToastr));

The bard library's $httpBackendReal and $qReal restore the original angular $httpBackend and $q implementations; they may be invoked independently.

We're also faking toastr for the same reason we faked it in appModule.

Now you write asynchronous tests that look a lot like production code. Here's a mocha example:

it('should get at least 6 Avengers', function (done) {
    dataservice
        .getAvengers()
        .then(function(data) {
            expect(data).to.have.length.above(6);
        })
        .then(done, done);
});

You should see network traffic for the request and response to the "Avengers" query. The promise succeeds (or fails) in real time, without stimulus from $rootScope.$apply(). The test framework pauses and waits until the server responds (or timesout) and the final then invokes the test harness' done function. Only then will it proceed to the next test in the suite.

Like the angular.mock.module function, you can add configuration arguments to decorate or mock other services:

beforeEach(bard.asyncModule('app', someDecorator, someMock));

inject

Inject angular and application components and store them by name on the global window object.

The bard.inject method tells the Angular mock dependency injector to inject components for the currently active test.

Here's how you might use inject within a beforeEach to get five dependent services while testing an Angular controller:

bard.inject(this, '$controller', '$log', '$q', '$rootScope', 'dataservice');

Now you can refer to these services by name in subsequent test functions as in these examples:

var controller = $controller('Avengers');
sinon.stub(dataservice, 'getAvengers').returns($q.when(avengers));
$rootScope.$apply();
expect(dataservice.getAvengers).to.have.been.calledOnce;
expect($log.error.logs[0]).to.match(/doomed/);

Compare the simplicity of

bard.inject(this, '$controller', '$log', '$q', '$rootScope', 'dataservice');

to the typical approach without bard:

// declare local variables for use within subsequent test functions
var $controller, $log, $q, $rootScope, dataservice;

// inject the services using Angular "underscore wrapping"
beforeEach(inject(function(_$controller_, _$log_, _$q_, _$rootScope_, _dataservice_) {
    // wire local vars to the injected services
    $controller = _$controller_;
    $log = _$log_;
    $q = _$q_;
    $rootScope = _$rootScope_;
    dataservice = _dataservice_;
}));

Which would you rather write? As importantly, which would you rather read ... on your way to the important business of the tests themselves?

"but globals are bad"

It's a terrible idea to toss variables into the global namespace in production.

It's tactically smart, productive, and convenient to do so in your tests. Disagree? Do you write your test code with beforeEach, it, expect, and module? Or would you rather write with the annoyingly verbose equivalents: mocha.beforeEach, jasmine.it, chai.expect and angular.mock.module?

the main risk of globals is cross-test pollution, the risk that the values you set in one test will carry over to a later test. Fortunately, bard inject deletes these variables from the global namespace at the end of each test. Each new test gets a clean slate.

what is this?

Notice the this argument in

bard.inject(this, '$controller', '$log', '$q', '$rootScope', 'dataservice');

Test frameworks set this to the test context (the spec context) object when the test runs. If we pass the context to inject, it can tell the test framework to ignore the new injected variables that it adds to the global namespace (the window object).

Do you care? You will care if you fear that your application code is leaking variables to the global namespace. You might then configure the test framework to detect such leaks.

For example, mocha has a "checkLeaks" configuration option that you can turn on like so:

<script>
    mocha.checkLeaks();
    var runner = mocha.run();
</script>

Thus enabled, mocha fails any test that adds variables to the global namespace between the time the test starts and when it finishes.

That's a problem for bard.inject which always adds new variables to globals. We don't want the tests to fail because of bard.inject.

Fortunately, inject can tell mocha to ignore the injected variables if we give it the spec context via this.

Internally inject calls another bard function, addGlobals. You should call this too if you deliberately extend globals yourself.

You don't have to pass this to inject if you aren't checking for global leaks. You are free to omit it as in:

bard.inject('$controller', '$log', '$q', '$rootScope', 'dataservice');

Of course you'll regret the omission later should you decide to turn on mocha's global leak checking. We think it's prudent to include this in your call.

inject a function

The angular.mock.inject function can both retrieve injectable "services" and do things with them in the function body.

The bard inject method accepts the same kind of function which may be useful if you want to inject and do work at the same time. For example:

beforeEach(bard.inject(function($controller, $log, $q, $rootScope, dataservice) { 
    ... do work ..
}));

After the function completes, bard inject promotes the injected services to global variables.

fake services

Register disabled services that you can spy on.

Our applications often depend on certain specific services that we like to disable during most of our tests.

Bard offers fake versions of these services. Their methods names begin with the word "fake" and include:

fakeLogger
fakeRouteHelperProvider
fakeRouteProvider
fakeStateProvider
fakeToastr

Look for details in bard.js. They all have two features in common:

  1. they do nothing
  2. their function members are stubbed with sinon spies

The spies allow a test to assert that one of the service methods was called in the expected manner.

expect(toastr.error).to.have.been.calledWith('uh oh!');

You typically register these faked services by including them among the arguments to the angular.mock.module function or one of its bard substitutes:

beforeEach(module('myMod', bard.fakeLogger));
beforeEach(appModule('myMod', bard.fakeLogger));
beforeEach(asyncModule('myMod', bard.fakeLogger));

log

The bard log method writes messages to console when bard debugging is turned on.

Our tests generally don't write to the console because the console is usually hidden when running tests in the browser or is crowded with other messages when running in karma.

But it can be helpful to sprinkle a little console logging in our code when trying to understand and debug complex tests.

it('should be good', function() {
    ... tricky stuff that might not work ...
    bard.log('we got the goods');    // conditional bard logging
    ... more tricky stuff ...
    expect(good).to.match(/good/);
});

We may wish to leave such diagnostic logging behind ... inert for the most part but ready to go again in a future visit. We can turn conditional logging on with bard.debugging(true) and off again with bard.debugging(false). When debugging is off, calls to bard.log do nothing.

Some of bard's own methods call bard.log.

mockService

Quickly create a mock for any service with spies and return values for every service member.

It can be painful to mock a dependency with a large API. Suppose, for example, that our app has a dataservice with 30 members. We want to test a particular controller that depends on this service.

That controller might call any of the service methods, either during initialization or when subjected to test conditions. For this round of tests, we only care when it calls the dataservice.getAvengers method.

No matter what the controller does, the dataservice must not dispatch requests to a server. It's obviously terrible if the controller calls a missing method and the mock blows up. We'll have to mock every dataservice member ... and remember to update it as the dataservice evolves.

Such a mock dataservice is tedious to write by hand, especially when we don't care what most of the members do. The bard mockService makes writing this fake a lot easier. The entire setup could be as simple as:

beforeEach(function() {

    bard.appModule('app.avengers');
    bard.inject(this, '$controller', '$q', '$rootScope', 'dataservice');


    bard.mockService(dataservice, {
        getAvengers: $q.when(avengers),
        _default:    $q.when([])
    });


    controller = $controller('Avengers');
    $rootScope.$apply();
});

The details of mockService configuration are described in bard.js. You'll find usage examples in the test coverage (look for ~/tests/bard.mockService.spec.js).

We trust you can see the core ideas in this example:

  • you give mockService an instance of the real dataservice to act as a template.
  • the mockService replaces every dataservice member with a fake implementation.
  • all methods are stubbed with sinon spies.
  • you can supply return values (such as fulfilled promises) for specific methods.
  • you determine default return values for the remaining unspecified methods.

In this case, we arranged for the getAvengers method to return a resolved promise with fake "avenger" objects. The other 29 methods return a resolved promise with an empty array.

That's easier to write and read than a mock dataservice with thirty hand-coded stub methods.

And here are two mocha/chai tests that could follow that setup:

it('controller activation gets avengers', function() {
    controller.activate(); // calls `dataservice.getAvengers`
    $rootScope.$apply();   // flush pending promises
        
    expect(controller.avengers).to.have.length(avengers.length); // same number as mocked

    expect(dataservice.getAvengers).to.have.been.calledOnce; // it's a spy
});

// Call one of the default mock methods which should return 
// a promise resolving to an empty array
// Note that the controller would not have called this on its own
it('can call fake `dataservice.getNews`', function() {

    dataservice.getNews().then(function(news) {
        expect(news).to.have.length(0);
    });

    $rootScope.$apply(); // flush pending promises

    // verify that `getNews` is actually a spy
    expect(dataservice.getNews).to.have.been.calledOnce;
});

Brackets code snippets

Code snippets make test authoring just a little easier. Here are instructions for loading our snippets into the Brackets editor.

Now try them in a JavaScript test file

  • mocha/jasmine

    • bdescribe - mocha/jasmine describe
    • bit - it test (synchronous)
    • bait - async it test
    • bbeforeEach - mocha/jasmine beforeEach
    • bafterEach - mocha/jasmine afterEach
    • bdone - tail of a mocha test promise chain: .then(done, done);
  • chai expectations

    • bexpect - expect(...).to
    • bcalled - expect(...).to.have.been.called
    • bequal - expect(...).to.equal(...)
    • blen - expect(...).to.have.length(...)
    • bmatch - expect(...).to.match(/.../i)
    • bprop - expect(...).to.have.been.property(..., ...)
    • bthrow - expect function to throw
  • bard.js

    • binject - bard.inject
    • bcinject - bard.inject for a controller
    • bmodule - bard.appModule
    • basyncmod - bard.asyncModule
    • bverify - bard.verifyNoOutstandingHttpRequests()
  • angular.js

    • bapply - $rootScope.$apply();
    • bwhen - $httpBackend.when('get', {url}).respond({status}, {data});
    • bflush - $httpBackend.flush();
  • miscellaneous

    • bfn - generates a function stub

bardjs's People

Contributors

barryrowe avatar johnpapa avatar valentinh avatar vcabbage avatar wardbell 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  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

bardjs's Issues

Type error 'undefined' evaluating 'bard.appModule....'

I am trying to get bard up and running with karma, but having issues right away with the appModule method (see below)

Is there a loading hierarchy for bard?

FAILED TESTS:
  LookupTestController
    โœ– "before each" hook for "should say hello"
      PhantomJS 1.9.8 (Linux 0.0.0)
    TypeError: 'undefined' is not a function (evaluating 'bard.appModule('lookup-test')')
        at /var/www/query_tool/web/bundles/test/js/specs/lookup.controller.spec.js:17

Here is my karam.conf.js

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['mocha','chai-as-promised','chai','sinon', 'sinon-chai'],

    files: [

      // add test polyfills (Promise)
      'web/bundles/test/js/Promise.js',
      'web/bundles/test/js/function.bind.polyfill.js',

      // module dependencies and angular mocks library
      'node_modules/angular/angular.js',
      'node_modules/angular-mocks/angular-mocks.js',
      'node_modules/angular-ui-select/select.js',
      'node_modules/bardjs/dist/bard.min.js',

      // add each js file which will be tested
      'web/bundles/test/js/myController.js',

      // testing lookup interface
      'web/bundles/test/js/ng-lodash.js',

      // loads all module dependencies (controller, filter, service, factory)
      'web/bundles/test/js/lookup.*.js',

      // reference spec directory (all specs will be run)
      'web/bundles/test/js/specs/**/*.spec.js'
    ],


    // list of files to exclude
    exclude: [
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress', 'mocha-clean'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}

Compile errors with Bard + Typescript + Jasmine

I'll warn you first that I'm a little new to typescript, so I might just have something wrong.

I'm using Definitely Typed typings with Bardjs, and I'm using Jasmine as my unit test framework.
When I tried to compile my typescript, I was getting errors because Bardjs.d.ts references Mocha and Chai typings.

So, I tried just pulling the mocha and chai typings into the project, but once I did that, the definitions of it, expect, etc all clashed with jasmine so I got multiple errors about expect being defined twice.

Is this something I've done wrong (seems weird that all of those types are globally scoped), or is this a bug?

MockService Doesn't Work with Services Defined as an ES6 Class

This fails (apologies for the whitespace issues)

 class MyService {

        doAThing(){
            return 'bad';
        }

    }

////

        bard.appModule('app');

        bard.inject(this, 'MyService');
        bard.mockService(MyService, {
            _default: false
        });

    it('returns the proper values', ()=> {
        expect(MyService.doAThing()).toBe(false);
    })

Meanwhile, this succeeds:

  function MyService() {
        var returnBad = function () {
            return 'bad';
        };
        this.doAThing = returnBad;
    }

////

        bard.appModule('app');

        bard.inject(this, 'MyService');
        bard.mockService(MyService, {
            _default: false
        });

    it('returns the proper values', ()=> {
        expect(MyService.doAThing()).toBe(false);
    })

How to test Controller with $scope?

Just starting to use bardjs and I donnot know how to set up the test for this test controller, how to inject $scope.

Controller example

(function () {

    'use strict';

    angular
        .module('test', [])
        .controller("TestCtrl", testController);

    testController.$inject = ["$scope"];

    function testController($scope) {

        console.log("TestCtrl Constructor");

        var vm = this;
        vm.activate = activate;
        vm.activate();

        function activate() {
            console.log("TestCtrl activate");

            angular.extend($scope, {
                mapBounds: [0, 0]
            });

        }
    }

})();

I tried to set up a test in the following way, but I get the following error:

Test example

describe("TestController Test 2", function () {

    var controller;
    var scope;

    beforeEach(function () {
        bard.appModule('test');
        bard.inject('$controller', '$log', '$q', '$rootScope', function ($rootScope) {
            scope = $rootScope.$new();
            return { $scope: scope };
        });
    });

    beforeEach(function () {
        controller = $controller('TestCtrl');
    });

    describe('Test 2', function () {
        it('should be created successfully', function () {
            expect(false).to.be.true;
            expect(controller).to.be.defined;
        });

    });

});

Error

Error: [$injector:unpr] http://errors.angularjs.org/1.4.8/$injector/unpr?
p0=$scopeProvider <- $scope <- TestCtrl
        at Error (native)

How can I setup bardjs correctly to test this type of controllers with $scope?

mockService cannot omit config

If you try to use mockService without the config you will get an error:

    TypeError: Cannot read property '_default' of undefined
        at node_modules/bardjs/dist/bard.js:560:37

The problem area is here where if the config has a key you use that key, otherwise you use the config._default, but if there is no config there can be no config._default...

  var value = configKeys.indexOf(key) > -1 ?
                config[key] : config._default;

Unable to test using PhantomJS

So, the following section of code is failing when using PhantomJS (with Karma) works fine with Chrome

beforeEach(function() {
    bard.appModule('app');
    bard.inject(this, '$controller', '$httpBackend', '$log', '$q', '$rootScope', 'dataservice', 'peopleService');
  });

I know all is loaded correctly (through karma.config.js) as the Chrome browser option is working just fine

The error in console is...

 "before each" hook for "should pass"
      PhantomJS 1.9.8 (Mac OS X 0.0.0)
    Error: [$injector:modulerr] Failed to instantiate module ng due to:
    TypeError: 'null' is not an object (evaluating 'this')

bardJS can't work well with JasmineJS+RequireJS+AngularJS

Hi Ward Bell,

I like your effort on this, i'm trying to use bardJS to optimize our unit test(Jasmine+RequireJS+Angular), but get stuck by some issues.

When i try to use bard.inject(this, '$q') in beforeEach-block, it throw errors.

  1. First error is that "sinon is not defined", so i have to download and refer SinonJS. Regarding to this, could you please update the documentation how to install and use bardJS? This is kind of hidden dependency....
  2. After i fixed the error above, i met another error:
    Error: [$injector:unpr] http://errors.angularjs.org/1.3.4/$injector/unpr?p0=%5Bobject%20Object%5DProvider%20%3C-%20%5Bobject%20Object%5D
    at Error (native)
    at Object.bardInject [as inject]

By debugging, i found the error happened in bard.js, is from here:
angular.forEach(args, function(name, ix) {
var value = $injector.get(name); //args=[this,'$q'] in my case.
So, the args is supposed to remove the first argument this, right? Why it's not?

Do you have any insight about this?

Thanks,
Carson Song

No Typescript type definitions available for bardjs

I have been using bardjs in my Typescript app and have been wanting a type definition file. When Typescript doesn't have a type definition file, it will complain that the bard functions don't exist. I created an issue on the DefinitelyTyped repository (the location of all Typescript definitions) to add this.

Publish v0.1.10 to npm

Thanks for maintaining this project and addressing the sinon issue. Can you please publish v0.1.10 to the npm repository?

how to fake $window

Hi Ward,
I need help with bardjs and I would highly appreciate if you could help me.

I am using John Papa's gulp pattern (https://github.com/johnpapa/gulp-patterns) where he uses bardjs. I want to fake $window because I have some stuff stored in the sessionstorage which is used within the application.
What would be the best way of adding additional fake providers?

I know that I can go ahead and add a file like this (https://github.com/johnpapa/ng-demos/blob/master/cc-bmean/src/client/test/lib/specHelper.js) and there define the fakeWindow within that file like this:

function fakeWindow($provide) {
        $provide.provider('$window', function () {
            /* jshint validthis:true */
            this.$window = sinon.stub();

            this.$get = function () {
                return {
                    sessionStorage: sinon.stub({
                        token: 'someToken'
                    })
                };
            };
        });
 }

and then for example in this file (https://github.com/johnpapa/gulp-patterns/blob/master/src/client/app/customers/customers.route.spec.js), instead of having :

beforeEach(function() {
        module('app.customers', bard.fakeToastr);
        bard.inject(this, '$location', '$rootScope', '$state', '$templateCache');
 });

do something like this:

beforeEach(function () {
        module('app.customers', function ($provide) {
            bard.fakeToastr($provide);
            specHelper.fakeWindow($provide);
        });
        bard.inject(this, '$location', '$rootScope', '$state', '$templateCache', '$window');
 });

obviously this approach will do exactly what I need, but it is getting drifted away from bardjs.

So my question is how would you do it ?

Many thanks in advance.

Farzan

bardInject error

I am getting the following issue when using bard.inject().

beforeEach(function() {
        bard.appModule('myModule');
        bard.inject(this, '$controller', '$log', '$q', '$rootScope');
    });

TypeError: 'undefined' is not a function (evaluating 'getCtxFromArgs.bind(this)') at bardInject (/bower_components/bardjs/dist/bard.js:273)

Any help would be really appreciated.

mockService unexpected behaviour

I am trying to use mockService in my sinon-chai tests. It looked really helpful when I read the README file. However, I ran into several problems trying to use it, and even now that I solved the problem, I don't fully understand the function's behaviour nor effect, yet. Using my example:

I have a service that injects UI-router's $state service. Since I am not really interested in having to deal with the effects of $state or any inconveniences, I thought in giving mockService a go. This was my beforeEach block on the first try:

beforeEach(function () {
    bard.appModule('mmApp.core');
    bard.inject(this, '$q',
                'userProgressService',
                'surveyDataService',
                'userInputService',
                '$state');
    bard.mockService($state);
});

I left the mockService with just one argument because I thought it would make every function return void and everything would be alright. When I ran the tests, though, I got the following error:

TypeError: 'undefined' is not an object (evaluating 'config._default')

This was in the exact line of mockService. In order to solve this I used an empty object as the second argument, like so

bard.mockServices($state, {});

based on the assumption that the function isn't prepared for not receiving the second argument. With this code, when I ran the tests, I got rid of the first error and got this one instead:

TypeError: 'undefined' is not a function (evaluating '$state.go('/phase/step', {phaseId:phaseNumber})')

I thought it was related to the $state.go function not being defined, not even as a stub or spy... I tried again, now with

bard.mockService($state, {
    go : sinon.stub()
});

in order to explicitly tell the function that I wanted an empty stub for $state.go (which, BTW, is the only function of $state I am currently using). This got rid of the errors!

Now, my question actually is... Why did those 2 errors happened in the first place?

Also, I recommend some more explanation for this function in the README, since it is one of the most useful of the provided. I checked the docs in the source and they are much more complete, you should try to make something more like it.

Anyway, great project, I don't even remember how to inject dependencies without this, anymore.

UPDATE

My workaround, though working, could lead to some errors. The other day I've noticed that what it was doing, actually, was telling that the stubbed function should return a sinon.stub(). I guess I forgot how the function worked.

So, a more correct workaround is to declare an appropriate return value for the functions to be mocked, even an undefined is enough. By doing exactly what I was doing, you could eventually get into trouble if ever using the return value of the mocked function.

Mock resolving promise

First of all, thanks Ward for writing such a nice test helper lib.

UPDATE 19.05.2016

I have solved it now. The issue in general is, that I have two services, whereas the PostService has a dependency to Api. Order seems to be the problem here.

The solution is to first include the Api Service with all the other Dependencies other than PostService, mock the Api Service and then finally include the Post Service via another bard.inject().

beforeEach(function() {
                bard.appModule('testingApp');
                bard.inject('Api', '$rootScope', '$q', '$httpBackend'); //first include Api

                testData = [
                    "post1", "post2", "post3"
                ];

        //second mock the Api
                bard.mockService(Api, {
                    getPosts: $q.when(testData)
                });

                //third inject the PostService which has Api as a dependency
                bard.inject('PostService');

                $httpBackend.whenGET(/\.*./).respond({anything: 123});
            });

Updated Plnkr: http://plnkr.co/edit/cGEWQMKgaRhoATF4Q2zf?p=preview


I am currently trying to mock a resolving promise and test some code that is inside the .then function of a service. Without bard.js it is working, but when trying to do the same thing with bard.js it is not working, and I am not able to find the bug (maybe it is a bug on my side?!).

I have set up a plnkr which is including both test cases (w/ and w/o bard.js) http://plnkr.co/edit/f8tH7XAiLoxlGbQFxfIH?p=preview

First of all, I have two services: PostService and Api.

function PostService(Api) {

        var svc = this;

        svc.posts = null;

        ////////////////////////// Init

        init();

        function init() {
            Api.getPosts()
                .then(function(result) {
                    svc.posts = result;
                })
        }
    }
function Api($http) {

        var svc = this;
        var root = 'http://jsonplaceholder.typicode.com';

        // Functions

        svc.getPosts = getPosts;

        ////////////////////////// Implementation

        function getPosts() {
            return $http({
                method: 'GET',
                url: root + '/posts'
            })
        }
    }

My test case is very simple: first, check if the PostService.posts is null. Second, after a $rootScope.$apply() the promise should be resolved and the PostService.posts should be equal to my mocked resolved promise's result.

it('should initially set the posts to null', function() {
                expect(PostService.posts).toBeNull();
            });

            it('should resolve a promise correctly', function() {
                $rootScope.$apply();
                expect(PostService.posts).toEqual(testData);
            });

The none bard.js test setup looks like this (Test No. 1 inside the plnkr):

var mockApi, $rootScope, PostService, testData, $httpBackend;

            beforeEach(function() {
                mockApi = {};

                testData = {
                    "data": [1, 2, 3]
                };

                module('testingApp', function($provide) {
                    $provide.value('Api', mockApi);
                });

                inject(function($q) {
                    mockApi.getPosts = function() {
                        return $q.when(testData);
                    }
                });

            });

            beforeEach(inject(function(_$rootScope_, _PostService_, _$httpBackend_) {
                $rootScope = _$rootScope_;
                PostService = _PostService_;
                $httpBackend = _$httpBackend_;

                $httpBackend.whenGET(/http\.*/).respond({anything: 123});
            }));

Whereas the bard.js setup looks like this, but is failing with the error (Test No. 2 inside the plnkr)

Error: Expected null to equal [ 'post1', 'post2', 'post3' ].

var testData;

            beforeEach(function() {
                bard.appModule('testingApp');
                bard.inject('PostService', 'Api', '$rootScope', '$q', '$httpBackend');

                testData = [
                    "post1", "post2", "post3"
                ];

                bard.mockService(Api, {
                    getPosts: $q.when(testData) // also tried with function() { $q.when(testData) }) - no success
                });

                $httpBackend.whenGET(/\.*./).respond({anything: 123});
            });

Am I missing something or doing it wrong? Or can't his case be handled with the bard.js lib?

I also tried combining both test setups, debugged it, but didn't have success to get it working. I would like to use bard.js for promise testing as well.

It would be nice if we could get this fixed together, either on my side or inside the lib (I don't want to use the angular mock inject() underscore stuff ๐Ÿ˜œ ) Thanks.

Failed to instantiate module function fakeRouteProvider

So, I've also watched your unit testing course on Pluralsight and this is basically an identical question to this. I'm getting this error when running my tests:

[$injector:modulerr] Failed to instantiate module function fakeRouteProvider($provide) due to:
TypeError: sinon.stub is not a function
at new (/Users/realph/../../../node_modules/bardjs/dist/bard.js:389:31)

Sorry for sounding stupid, but maybe I've placed my bard.js files in the wrong place. I'm just running my tests in the console for now with:

karma start karma.conf.js

I've installed bardjs via npm and am including it in my karma.conf.js file like this:

frameworks: ['mocha', 'chai', 'sinon', 'chai-sinon'],

files: [
  ...

  '../../node_modules/sinon/lib/sinon.js',
  '../../node_modules/bardjs/dist/bard.js',

  ...
],

Am I doing something wrong that would be causing this error?

Any help is appreciated. Thanks in advance!

Mocking a Data Service

I'm doing unit testing for the first time and I'm trying to work out how to mock a data call from a service so I can test if the data is coming back in the correct form:

My Service

angular.module('app.core')
   .factory('PeopleService', PeopleService)

  function PeopleService($http, $q, $filter) {

    var endpoint;
    var service = {
      customers: {
        value: null
      },
      getAllCustomers: getAllCustomers,
    };

    return service;

    function getCustomers(endpoint_) {
      endpoint = endpoint_;
      service.customers.value = [];

      return handleFetch($http.get(endpoint));
    }

    function handleFetch(promise) {
      return promise.then(function (resp) {
        service.customers.value = service.customers.value.concat(resp.data.data);
      });
    }

    function getAllCustomers() {
      return $q.all([
        getCustomers('/api/customers'),
      ]).then(function(responses) {
        return responses[0];
      });
    }
  }

My Controller

angular.module('app.people')
    .controller('peopleCtrl', peopleCtrl);

function peopleCtrl($scope, PeopleService) {
    $scope.customers = PeopleService.customers;

    getCustomers();

    function getCustomers() {
      return PeopleService.getAllCustomers().then(function () {
        return PeopleService.customers.value;
      });
    }
}

My Test

describe('People Service', function () {
    var controller;
    var customers = mockData.getMockCustomers(); // my fake customers array

    beforeEach(function() {
      bard.appModule('app');
      bard.inject('$controller', '$q', '$rootScope', 'PeopleService');

      var ps = {
        getAllCustomers: function() {
          return $q.when(customers);
        }
      };

      controller = $controller('peopleCtrl', {
        $scope: $rootScope,
        PeopleService: ps
      });
    });

    it('should return an array of 5 customers', function() {
      $rootScope.$apply();
      expect($rootScope.customers).to.have.length(5);
    });
});

I've got a controller set up that when loaded talks to the People Service and gets my customers and saves the array of customers to PeopleService.customers.value. Inside my controller, I have a variable $scope.customers which is equal to PeopleService.customers.

I'm trying to mock this with my test, without hitting the API, I'm using some mock data to do this (an array of 5 customers), but not sure if I understand correctly.

Is the idea to have my mock people service return exactly what the actual people service returns? I'm kind of confused at this point. I basically want that test to check if the mock data length is equal to five.

Any help with this is appreciated. Thanks in advance!

PhantomJS error, works well in Chrome and Firefox

Hi!

I was just trying out bardjs and it seams to work fine in Chrome and Firefox, but when i run it in PhantomJS i get this error:

PhantomJS 1.9.8 (Mac OS X) Template Controller "before each" hook FAILED
    TypeError: 'undefined' is not a function (evaluating 'getCtxFromArgs.bind(this)')
        at bardInject (/Users/lodnert/projects/myapp/app/bower_components/bardjs/dist/bard.js:277)
        at /Users/lodnert/projects/myapp/test/spec/app/registry/template.controller.js:8
PhantomJS 1.9.8 (Mac OS X): Executed 1 of 1 (1 FAILED) ERROR (0.002 secs / 0 secs)

Here is the spec-file.


describe('Controller: Auth', function () {
  var controller;
  beforeEach(function() {

      bard.appModule('myapp.auth');
      bard.inject('$controller', '$rootScope');

  });



  it('should be created successfully', function () {
    expect('hello').toBeDefined();
  });

});

Any ideas?

Issue testing routes using bardjs

I have a similar issue to "cannot test my routes using bardjs #14'

PhantomJS 1.9.8 (Mac OS X 0.0.0) UploadController "before each" hook for "should be created successfully" FAILED
Error: [$injector:unpr] Unknown provider: routerHelperProvider <- routerHelper
http://errors.angularjs.org/1.4.7/$injector/unpr?p0=routerHelperProvider%20%3C-%20routerHelper

I note your comment about whether the dependencies have been included in the test harness.
I am using gulp and from what i can tell all the required files have been loaded into specs.html - routerHelperProvider and routerHelper.
There are other tests that rely on these being there.

The only thing i can think is that I am doing something differetly with the test for this specific module:-

Controller looks like:-

(function () {
'use strict';

angular
    .module('app.upload',['angularFileUpload'])
    .controller('UploadController', UploadController);

UploadController.$inject = ['logger','FileUploader','$scope'];
/* @ngInject */
function UploadController(logger, FileUploader, scope) {
    var vm = this;
    vm.title = 'Upload';

    var uploader  = scope.uploader = new FileUploader({
        url: '/upload'
    });

    activate();

    function activate() {
        logger.info('Activated Upload View');
    }

    // FILTERS

    uploader.filters.push({
        name: 'customFilter',
        fn: function(item /*{File|FileLikeObject}*/, options) {
            return this.queue.length < 10;
        }
    });

    // CALLBACKS

    uploader.onWhenAddingFileFailed = function(item /*{File|FileLikeObject}*/, filter, options) {
        console.info('onWhenAddingFileFailed', item, filter, options);
    };
    uploader.onAfterAddingFile = function(fileItem) {
        console.info('onAfterAddingFile', fileItem);
    };
    uploader.onAfterAddingAll = function(addedFileItems) {
        console.info('onAfterAddingAll', addedFileItems);
    };
    uploader.onBeforeUploadItem = function(item) {
        console.info('onBeforeUploadItem', item);
    };
    uploader.onProgressItem = function(fileItem, progress) {
        console.info('onProgressItem', fileItem, progress);
    };
    uploader.onProgressAll = function(progress) {
        console.info('onProgressAll', progress);
    };
    uploader.onSuccessItem = function(fileItem, response, status, headers) {
        console.info('onSuccessItem', fileItem, response, status, headers);
    };
    uploader.onErrorItem = function(fileItem, response, status, headers) {
        console.info('onErrorItem', fileItem, response, status, headers);
    };
    uploader.onCancelItem = function(fileItem, response, status, headers) {
        console.info('onCancelItem', fileItem, response, status, headers);
    };
    uploader.onCompleteItem = function(fileItem, response, status, headers) {
        console.info('onCompleteItem', fileItem, response, status, headers);
    };
    uploader.onCompleteAll = function() {
        console.info('onCompleteAll');
    };

    console.info('uploader', uploader);

}

})();

Spec looks like:-

/* jshint -W117, -W030 */
describe('UploadController', function() {
var controller;

beforeEach(function() {
    bard.appModule('app.upload');
    bard.inject('$controller', '$log', '$rootScope');
});

beforeEach(function () {
    controller = $controller('UploadController');
    $rootScope.$apply();
});

bard.verifyNoOutstandingHttpRequests();

describe('Upload controller', function() {

    it('should be created successfully', function () {

        expect(controller).to.be.defined;
    });

    describe('after activate', function() {
        it('should have title of Upload', function() {
            expect(controller.title).to.equal('Upload');
        });

        it('should have logged "Activated"', function() {
            expect($log.info.logs).to.match(/Activated/);
        });
    });
});

});

If i understand correctly i dont need to pass dependencies to the module being tested within the spec - as they are instantiated by the module. Only dependencies to be passed are ones used in the spec.

Appreciate any thoughts you may have.

A mockService call using a replacement function doesn't result in a spy

If mockService is called with a replacement function in a scenario like below:

var isFirstCall = true;
function myReplacementFunc(){
    if(isFirstCall){
        isFirstCall = false;
        return {test:"value"};
    }else{
        return undefined;
    }
}
mockService(MyService, {
    get: myReplacementFunc
}

the get function on the mocked service is not spied on properly, and so something like this (using jasmine-sinon):

expect(MyService.get).toHaveBeenCalledOnce();

fails with an error like:

Expected spy "function myReplacementFunc() {
        if (isFirstCall ) {
            isFirstCall = false;
            return { test: "value" };
        } else {
            return undefined;
        }
    }" to have been called twice. "function myReplacementFunc() {
        if (isFirstCall ) {
            isFirstCall = false;
            return { test: "value" };
        } else {
            return undefined;
        }
    }" was called 0 times.

I would have expected this to work the same as if I had just manually wired up the sinon spies like:

sinon.stub(MyService, 'get', myReplacementFunc);

It appears that if line 564 of the current distribution were changed from:

service[key] = value;

to

sinon.stub(service, key, value);

this would work as expected.

How to test a service with mocked dependencies services

Hi
Thanks for creating this, really helps..

I'm facing issue when tried to write unit-tests for a service,
I need to mock the dependencies services that I need for this service with the help of bard.mockService,

The angular way without bardjs usages listed here:
https://docs.angularjs.org/guide/services

  • they use $provide service to override the service with mock version

For controller testing this wasn't a problem as we can instanciate a controller sending the service map it needs using $controller service.

Is there anyway to do this?

bard is not defined Karma

I installed bard via npm.

This is my karma.conf.js files

files: [
      'node_modules/bardjs/dist/bard.js',
      ...
]

running tests get Uncaught ReferenceError: bard is not defined

What am I doing wrong?

Update the Readme to point out bard also works for Jasmine

Hi Ward,

I stumbled upon your project some weeks ago and by only skimming the repo (or the description to be precise) I thought bard only offers help when testing with the mocha/chai combination. I returned today after watching parts of your (well made!) Pluralsight course on testing Angular in which bard is mentioned/used with Jasmine.

Maybe you could update the description from Mocha/chai spec helpers for testing angular v.1.x apps to something along the lines of Framework agnostic spec helpers for testing angular v.1.x apps. or Spec helpers for testing angular v.1.x apps with mocha or jasmine or QUnit.

PS: Thumbs up for this library, just by using the inject method I cleaned up my tests a lot.

Using Angular-ized third party libraries causes issues

In my case, I'm using lodash. I have an Angular service which wraps the global _ in a service called '_' so that it's obvious what it's supposed to be when you call things on it (e.g. _.extend). However, since bard injects my _ service as a global, it clobbers the library itself, then after the first test, it removes _ from the global scope. The end result is that only the first test of anything which uses the _ service passes. The rest error at dependency injection time because the _ factory no longer returns anything.

I have fixed this issue locally in my test helper file by copying over the library to a different variable stored locally, then running a global afterEach which restores it, but such a thing would probably be good to have as a core functionality of bard.

Edited to add that _.extend is a silly example because that functionality is available via angular.extend, but the idea carries for pretty much any global library which you might wrap in an angular service for mocking purposes.

Sinon undefined when using Jasmine

With setup:

bard.inject('$controller', '$q', '$rootScope', 'serviceName');

When calling

bard.mockService(serviceName, {
    method: $q.when({})
});

in my tests I get an error:

'undefined' is not an object (evaluating 'service[key] = sinon.spy(function() {
    return value;
})')

at /{myApp}/bower_components/bardjs/dist/bard.js:561

my bower file incldues:

"devDependencies": {
    "angular-mocks": "~1.4.0",
    "bardjs": "~0.1.3",
    "sinon": "~1.14.1"
}

and all bower_components are included in my karma.conf.js file

Unit testing with ng-html2js and Bard.js possible

I have enjoyed using your library on personal projects and a project that I worked on before. In the past I have followed the gulp build from John Papa's hot towel generator to do the $templateCaching. However, in this project that I am working with I am trying to incorporate the preprocessor

_ng-html2js_. I am wondering if it is possible to combine this with the bardjs library?

I have not been able to configure the two together with any luck yet, but am not sure if it is with me or the code.

Here is my karma.config file

preprocessors: {
        '../Templates/**/*.html' : ['ng-html2js']
    },

    ngHtml2JsPreprocessor: {
        // setting this option will create only a single module that contains templates
        // from all the files, so you can load them all with  angular.mock.module('foo')

        stripPrefix: "Templates/",
        prependPrefix: "/",
        moduleName: 'templatesCached'
    },

bard.appModule('templatesCached');
bard.appModule('ha.module.core');

My error message is

Error: [$injector:modulerr] Failed to instantiate module function fakeRouteProvider($provide) due to:
TypeError: sinon.stub is not a function
    at new <anonymous> 

fakeStateProvider

I wonder about following piece of code in fakeStateProvider
https://github.com/wardbell/bardjs/blob/master/dist/bard.js#L404-L407

// current: {},  // fake before each test as needed
// state:  {}  // fake before each test as needed
// more? You'll know when it fails :-)
_faked: 'this is the faked $state service'

How would I go about it, if I wanted e.g. fake state, current or sth. else. In my case I have get method that I'd like to fake (sinon.stub).

Thanks.

Failed to instantiate module function fakeRouteProvider

Sounds similar to some other closed issues, but no solution jumped out at me. Using 0.1.3 of bardjs I am getting the following error:

Error: [$injector:modulerr] Failed to instantiate module function fakeRouteProvider($provide) due to:
    TypeError: 'undefined' is not a function (evaluating 'sinon.stub()')
        at /Users/bbohling/Projects/itdz/itdz-ui/app/bower_components/bardjs/dist/bard.js:377

My spec is a complete rip off of something John Papa did in one of his Pluralsight trainings:

describe('itdz', function() {
    var controller;
    var page = mockPage.getPage();

    beforeEach(function() {
        bard.appModule('itdz');
        bard.inject('$controller', '$q', '$rootScope', 'pageService');
    });

    beforeEach(function() {
        sinon.stub(pageService, 'slug').returns($q.when(page));
        controller = $controller('Content');
        $rootScope.$apply();
    });

    bard.verifyNoOutstandingHttpRequests();

    describe('Content controller', function() {
        it('should be created successfully', function () {
            expect(controller).to.be.defined;
        });

        describe('after activate', function() {
            it('should have called pageService.slug 1 time', function () {
                expect(pageService.slug).to.have.been.calledOnce;
            });

        });
    });
});

And I verified that sinon is indeed included in the karma files array. Any ideas what I am doing wrong? I am assuming it's my fault. :)

Mock Data Undefined

Hiya folks, I'm trying to create a unit test that checks if a GET request returns the correct amount of items, but I'm using mock data to do this.

My test looks like this:

test.js

describe('Customer Controller', function () {
    var controller;
    var customers = mockData.getMockCustomers(); // fake customers (5 customers)

    beforeEach(function() {
      bard.appModule('app');
      bard.inject('$controller', '$q', '$rootScope');

      var cs = {
        getCustomers: function() {
          return $q.when(customers);
        }
      };

      controller = $controller('scoreListCtrl', {
        CustomerService: cs
      });
    });

    it('should return 5 customers', function() {
      $rootScope.$apply();
      expect(controller.customers).to.have.length(5);
    });
});

I keep getting this error when I run the test:

TypeError: Cannot read property 'length' of undefined

It looks like controller.customers is coming back as undefined for some reason. Am I mocking the data correctly?

My controller looks like this:

function customersCtrl(dataservice) {
  var vm = this;
  vm.customers = [];

  fetchCustomers();

  function fetchCustomers() {
    return dataservice.getCustomers()
    .then(function(data) {
      vm.customers = data.data;
      return vm.customers ;
    });
  }
}

I've put a console.log in the test, and my customers variable is returning 5 objects which appear to be empty. Perhaps this is the issue?

Image

I'm very new to this and can't work out what I'm doing wrong. I don't even know how to debug such an issue.

Any help is appreciated. Thanks in advance!

This repo needs a new caretaker

I no longer do AngularJS (aka Angular v.1.x) work and haven't for a while. That's why I haven't kept up on this library which isn't fair to all of you who have found it valuable.

BardJS needs a new caretaker. Please submit your bid to take over in a response.

Rules

There aren't many but ...

  1. You must be willing to stay current with issues and PRs.
  2. You must be courteous, kind, clean, brave, and reverent (part of the Boy Scout's Law].
  3. You must strive to limit breaking changes and maintain backwards compatibility where at all possible.
  4. You must do your best to follow semver, especially with breaking changes.

Thanks for your loyalty and understanding. I'm sure my successor will be great.

add components (angular 1.5 ) option to bardjs

Like many others I am starting to work on and test angular 1.5. The component option is very nice, but right now the only way to test it is with angular mocks. Please add this option when you have a chance.

Bower dependency issues with Angular 1.4

After upgrading to Angular 1.4, I am getting the following dependency issues with bardjs:

Unable to find a suitable version for angular, please choose one:
1) angular#~1.3.8 which resolved to 1.3.16 and is required by bardjs#0.1.3
2) angular#1.3.16 which resolved to 1.3.16 and is required by angular-mocks#1.3.16
3) angular#>=1.3.0 which resolved to 1.4.0 and is required by angular-bootstrap#0.13.0, angular-toastr#1.4.1
4) angular#~1.4.0 which resolved to 1.4.0 and is required by manage-my-money-client
5) angular#>= 1.0.8 which resolved to 1.4.0 and is required by angular-ui-router#0.2.15
6) angular#1.4.0 which resolved to 1.4.0 and is required by angular-animate#1.4.0

Could you please update bower.json to make the dependencies a little less stringent, e.g. >=1.3.8?

Also should the sinon dependency be updated to the latest release?

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.