{"id":13623625,"url":"https://github.com/wardbell/bardjs","last_synced_at":"2025-04-06T09:08:16.565Z","repository":{"id":24893373,"uuid":"28309666","full_name":"wardbell/bardjs","owner":"wardbell","description":"Spec helpers for testing angular v.1.x apps with Mocha, Jasmine and QUnit","archived":false,"fork":false,"pushed_at":"2017-02-27T16:16:38.000Z","size":88,"stargazers_count":178,"open_issues_count":21,"forks_count":31,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-30T07:08:45.682Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wardbell.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-21T19:03:19.000Z","updated_at":"2024-01-28T02:13:18.000Z","dependencies_parsed_at":"2022-08-23T03:50:46.278Z","dependency_job_id":null,"html_url":"https://github.com/wardbell/bardjs","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbell%2Fbardjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbell%2Fbardjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbell%2Fbardjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbell%2Fbardjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wardbell","download_url":"https://codeload.github.com/wardbell/bardjs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457801,"owners_count":20941906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T21:01:33.889Z","updated_at":"2025-04-06T09:08:16.541Z","avatar_url":"https://github.com/wardbell.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# bardjs Test Helpers\n[![NPM version](https://img.shields.io/npm/v/bardjs.svg?style=flat)](https://www.npmjs.com/package/bardjs)\n\n**bardjs** is a small library of functions to help you write **Angular v.1.x application tests** ... whether you write them in [mocha](http://mochajs.org/ \"mochajs\") or [jasmine](http://jasmine.github.io/ \"jasmine\") or [QUnit](http://qunitjs.com/ \"QUnit\").\n\nWhat kind of help? Help with **routine tasks** that would otherwise clutter your tests and obscure their intent. \n\nThe poster child in this respect is the [`inject` method](#inject).  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.\n\nThe [bardjs repo](https://github.com/wardbell/bardjs/snippets/ \"bard code snippets\") also contains code snippets to make writing tests a little easier. See [separate instructions](#snippets) for those below.\n\n# Installation\n\nMost folks bardjs install it with [bower](http://bower.io/search/?q=bardjs \"bard on bower\") or [npm](https://www.npmjs.com/package/bardjs):\n\n`bower install bardjs`\n\n`npm install bardjs`\n\nYou can also clone [bardjs from github](https://github.com/wardbell/bardjs \"bard on github\") and extract *bard.js*itself.\n\n\u003ebard depends on [sinon.js](http://sinonjs.org/) so make sure you have that library available; bower and npm bring that down for you.\n\nAlmost all of bard is in the *bard.js* file within the *dist* folder.\n\nIf you're running tests in a browser, add the appropriate script tag *below* the script for your test framework library:\n\n    \u003c!-- when installed with bower --\u003e\n    \u003cscript src=\"/bower_components/bardjs/dist/bard.js\"\u003e\u003c/script\u003e\n\n    \u003c!-- when installed with npm --\u003e\n    \u003cscript src=\"/npm_modules/bardjs/dist/bard.js\"\u003e\u003c/script\u003e\n\nYou'll need to add *sinon.js* as well\n\n    \u003c!-- when installed with bower --\u003e\n    \u003cscript src=\"/bower_components/sinon/index.js\"\u003e\u003c/script\u003e\n\n    \u003c!-- when installed with npm --\u003e\n    \u003cscript src=\"/npm_modules/sinon/lib/sinon.js\"\u003e\u003c/script\u003e\n\n## karma considerations\n\nIf you're running with [karma](http://karma-runner.github.io/0.12/index.html \"karma\"), reference *bard.js* in *karma.config.js* among the `files` to be loaded. See the [karma \"Config\" documentation](http://karma-runner.github.io/0.12/config/configuration-file.html \"karma config\") for details.\n\nBe sure to include *sinon* among the karma frameworks as in this example extract:\n\n    frameworks: ['mocha', 'chai', 'sinon', 'chai-sinon'],\n\nIn 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](https://docs.angularjs.org/api/ngRoute/service/$route \"Angular $route\"). \n\n# bard methods\n\nAfter loading `bard.js`, you'll find the global variable `bard` at your finger tips as you write your tests. \n\nThe bard methods are listed right at the top of the *bard.js* file. \n\nWe won't describe every method here. Each method is prefaced in the code with it own documentation in comments describing both purpose and usage.\n\nBut we will call out the methods that have proven most notable and useful:\n\n* [appModule](#appModule) - identify the application module to test and also disable certain routine services.\n* [asyncModule](#asyncModule) - enable async integration testing by restoring `$http` and `$q` while identifying the application module to test.\n* [inject](#inject) - inject angular and application components and store them by name on the global `window` object.\n* [fake services](#fakeServices) - register disabled services that you can spy on.\n* [log](#log) - writes messages to `console` when bard debugging is turned on.\n* [mockService](#mockService) - create a mock for any service with spies and return values for every service member.\n\n\n\u003ca name=\"appModule\"\u003e\u003c/a\u003e\n## appModule\n\n**Identify the application module to test and also disable certain routine services.**\n\nYou 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](https://docs.angularjs.org/api/ngMock/function/angular.mock.module \"mock module\").\n\nWe found that we routinely disable certain services at the same time. \n\nFor example, we don't want to see [**toastr**](https://github.com/CodeSeven/toastr \"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.\n\nWe 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.\n\nThe bard `appModule` method is a quick way to both identify the module to test and disable the *toastr* and routing services. This one line ...\n\n`beforeEach(bard.appModule('myModule'));`\n\ndoes the work of these seven ...\n\n    beforeEach(angular.mock.module(\n\t\t'myModule',\n\t\tbard.fakeToastr,\n\t\tbard.fakeRouteHelperProvider,\n\t\tbard.fakeRouteProvider,\n\t\tbard.fakeStateProvider)\n    );\n\n\u003eThe bard library offers [several methods](#fakeServices) (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.\n\nLike the [`angular.mock.module` function](https://docs.angularjs.org/api/ngMock/function/angular.mock.module \"mock module\"), you can add configuration arguments to the call to decorate or mock other services:\n\n`beforeEach(bard.appModule('myModule', someDecorator, someMock));`\n\n### don't use *appModule* when testing routes\n\nYou 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.\n\nInstead, simply fall back to `angular.mock.module`, adding specific fakes as desired:\n\n`beforeEach(module('myModule', bard.fakeToastr));`\n\n\u003ca name=\"asyncModule\"\u003e\u003c/a\u003e\n## asyncModule\n\n**Enable async integration testing by restoring `$httpBackend` and `$q` while identifying the application module to test.**\n\nThe [`angular.mock.module` function](https://docs.angularjs.org/api/ngMock/function/angular.mock.module \"mock module\") replaces  `$httpBackend` and `$q` with mocked versions.\n\nThe 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.\n\nThese 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. \n\nFor 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?\n\nYou'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.\n\nThe 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:\n\n`beforeEach(bard.asyncModule('app'));`\n\nThis is the equivalent of ...\n\n    beforeEach(module('app', bard.$httpBackendReal, bard.$qReal, bard.fakeToastr));\n\n\u003eThe bard library's `$httpBackendReal` and `$qReal` restore the original angular `$httpBackend` and `$q` implementations; they may be invoked independently.\n\u003e\n\u003eWe're also faking *toastr* for the same reason we faked it in [`appModule`](#appModule).\n\nNow you write asynchronous tests that look a lot like production code. Here's a mocha example:\n\n    it('should get at least 6 Avengers', function (done) {\n        dataservice\n            .getAvengers()\n            .then(function(data) {\n                expect(data).to.have.length.above(6);\n            })\n            .then(done, done);\n    });\n\nYou 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.\n\nLike the [`angular.mock.module` function](https://docs.angularjs.org/api/ngMock/function/angular.mock.module \"mock module\"), you can add configuration arguments to decorate or mock other services:\n\n`beforeEach(bard.asyncModule('app', someDecorator, someMock));`\n\n\n\n\u003ca name=\"inject\"\u003e\u003c/a\u003e\n## inject\n\n**Inject angular and application components and store them by name on the global `window` object.**\n\nThe `bard.inject` method tells the Angular [mock dependency injector](https://docs.angularjs.org/api/ngMock/function/angular.mock.inject \"mock inject\") to inject components for the currently active test.\n\nHere's how you might use `inject` within a `beforeEach` to get five dependent services while testing an Angular controller:\n\n    bard.inject(this, '$controller', '$log', '$q', '$rootScope', 'dataservice');\n\nNow you can refer to these services by name in subsequent test functions as in these examples:\n\n    var controller = $controller('Avengers');\n    sinon.stub(dataservice, 'getAvengers').returns($q.when(avengers));\n    $rootScope.$apply();\n    expect(dataservice.getAvengers).to.have.been.calledOnce;\n    expect($log.error.logs[0]).to.match(/doomed/);\n\nCompare the simplicity of \n\n    bard.inject(this, '$controller', '$log', '$q', '$rootScope', 'dataservice');\n\nto the typical approach without bard:\n\n    // declare local variables for use within subsequent test functions\n    var $controller, $log, $q, $rootScope, dataservice;\n\n    // inject the services using Angular \"underscore wrapping\"\n    beforeEach(inject(function(_$controller_, _$log_, _$q_, _$rootScope_, _dataservice_) {\n        // wire local vars to the injected services\n        $controller = _$controller_;\n        $log = _$log_;\n        $q = _$q_;\n        $rootScope = _$rootScope_;\n        dataservice = _dataservice_;\n    }));\n\nWhich would you rather write? As importantly, which would you rather *read* ... on your way to the important business of the tests themselves?\n\n### \"but globals are bad\"\n\nIt's a terrible idea to toss variables into the global namespace *in production*. \n\nIt'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`? \n\nthe 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.\n\n### what is `this`?\n\nNotice the *`this`* argument in \n\n\u003ccode\u003ebard.inject(\u003c/code\u003e\u003cstrong\u003e\u003ccode\u003ethis\u003c/code\u003e\u003c/strong\u003e\u003ccode\u003e, '$controller', '$log', '$q', '$rootScope', 'dataservice');\u003c/code\u003e\n\nTest 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).\n\nDo 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.\n\nFor example, mocha has a \"checkLeaks\" configuration option that you can turn on like so:\n\n    \u003cscript\u003e\n        mocha.checkLeaks();\n        var runner = mocha.run();\n    \u003c/script\u003e\n\nThus enabled, mocha fails any test that adds variables to the global namespace between the time the test starts and when it finishes.\n\nThat'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`.\n\nFortunately, `inject` can tell mocha to ignore the injected variables if we give it the spec context via `this`.\n\n\u003eInternally `inject` calls another bard function, `addGlobals`. You should call this too if you deliberately extend globals yourself.\n\n**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:\n\n    bard.inject('$controller', '$log', '$q', '$rootScope', 'dataservice');\n\nOf 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.\n\n### *inject* a function\n\nThe [`angular.mock.inject`](https://docs.angularjs.org/api/ngMock/function/angular.mock.inject \"mock inject\") function can both retrieve injectable \"services\" and do things with them in the function body.\n\nThe 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:\n\n    beforeEach(bard.inject(function($controller, $log, $q, $rootScope, dataservice) { \n        ... do work ..\n    }));\n\nAfter the function completes, bard `inject` promotes the injected services to global variables.\n\n\n\n\u003ca name=\"fakeServices\"\u003e\u003c/a\u003e\n## fake services\n\n**Register disabled services that you can spy on.**\n\nOur applications often depend on certain specific services that we like to disable during most of our tests.\n\nBard offers fake versions of these services. Their methods names begin with the word \"fake\" and include:\n\n    fakeLogger\n    fakeRouteHelperProvider\n    fakeRouteProvider\n    fakeStateProvider\n    fakeToastr\n\nLook for details in *bard.js*. They all have two features in common:\n\n1. they do nothing\n1. their function members are stubbed with [sinon spies](http://sinonjs.org/docs/#spies \"sinon spies\")\n\nThe spies allow a test to assert that one of the service methods was called in the expected manner.\n\n`expect(toastr.error).to.have.been.calledWith('uh oh!');`\n\nYou typically register these faked services by including them among the arguments to the [`angular.mock.module` function](https://docs.angularjs.org/api/ngMock/function/angular.mock.module \"mock module\") or one of its bard substitutes:\n\n    beforeEach(module('myMod', bard.fakeLogger));\n    beforeEach(appModule('myMod', bard.fakeLogger));\n    beforeEach(asyncModule('myMod', bard.fakeLogger));\n\n\n\n\u003ca name=\"log\"\u003e\u003c/a\u003e\n## log\n\n**The bard `log` method writes messages to `console` when bard debugging is turned on.**\n\nOur 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.\n\nBut it can be helpful to sprinkle a little console logging in our code when trying to understand and debug complex tests.\n\n    it('should be good', function() {\n        ... tricky stuff that might not work ...\n        bard.log('we got the goods');    // conditional bard logging\n        ... more tricky stuff ...\n        expect(good).to.match(/good/);\n    });\n\nWe 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.\n\nSome of bard's own methods call `bard.log`.\n\n\n\n\u003ca name=\"mockService\"\u003e\u003c/a\u003e\n## mockService\n\n**Quickly create a mock for any service with spies and return values for every service member.**\n\nIt 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. \n\nThat 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.\n\nNo 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.\n\nSuch 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:\n\n    beforeEach(function() {\n\n        bard.appModule('app.avengers');\n        bard.inject(this, '$controller', '$q', '$rootScope', 'dataservice');\n\n\n        bard.mockService(dataservice, {\n            getAvengers: $q.when(avengers),\n            _default:    $q.when([])\n        });\n\n\n        controller = $controller('Avengers');\n        $rootScope.$apply();\n    });\n\nThe 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*). \n\nWe trust you can see the core ideas in this example:\n\n* you give `mockService` an instance of the real `dataservice` to act as a template.\n* the `mockService` replaces every `dataservice` member with a fake implementation.\n* all methods are stubbed with [sinon spies](http://sinonjs.org/docs/#spies \"sinon spies\").\n* you can supply return values (such as fulfilled promises) for *specific* methods.\n* you determine default return values for the remaining *unspecified* methods.\n\nIn 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.\n\nThat's easier to write and read than a mock `dataservice` with thirty hand-coded stub methods.\n\nAnd here are two mocha/chai tests that could follow that setup:\n\n    it('controller activation gets avengers', function() {\n        controller.activate(); // calls `dataservice.getAvengers`\n        $rootScope.$apply();   // flush pending promises\n            \n        expect(controller.avengers).to.have.length(avengers.length); // same number as mocked\n\n        expect(dataservice.getAvengers).to.have.been.calledOnce; // it's a spy\n    });\n\n    // Call one of the default mock methods which should return \n    // a promise resolving to an empty array\n    // Note that the controller would not have called this on its own\n    it('can call fake `dataservice.getNews`', function() {\n\n        dataservice.getNews().then(function(news) {\n            expect(news).to.have.length(0);\n        });\n\n        $rootScope.$apply(); // flush pending promises\n\n        // verify that `getNews` is actually a spy\n        expect(dataservice.getNews).to.have.been.calledOnce;\n    });\n\n\u003ca name=\"snippets\"\u003e\u003c/a\u003e\n# Brackets code snippets\n\nCode snippets make test authoring just a little easier. Here\nare instructions for loading our snippets into the [Brackets editor](http://brackets.io/ \"Brackets editor\").\n\n- Open the Brackets Extension manager ( File \u003e Extension manager )\n- Install ['Brackets Snippets (by edc)'](https://github.com/chuyik/brackets-snippets)\n- Click the light bulb in Brackets' right gutter\n- Click `Settings` and then `Import`\n- Click `Choose File`\n- Locate and download [*~/snippets/brackets-testing-snippets.yaml*](https://github.com/wardbell/bardjs/blob/master/snippets/brackets-testing-snippets.yaml \"bard brackets snippets on github\") from github.\n- Choose either to `skip` or to `override`\n- Click `Start Import`\n\nNow try them in a JavaScript test file\n\n* mocha/jasmine\n\n    * `bdescribe` - mocha/jasmine `describe`\n    * `bit`  - `it` test (synchronous)\n    * `bait` - async `it` test\n    * `bbeforeEach` - mocha/jasmine `beforeEach`\n    * `bafterEach` - mocha/jasmine `afterEach`\n    * `bdone` - tail of a mocha test promise chain: `.then(done, done);`\n\n\n* chai expectations\n\n    * `bexpect` - expect(...).to\n    * `bcalled` - expect(...).to.have.been.called\n    * `bequal` - expect(...).to.equal(...)\n    * `blen` - expect(...).to.have.length(...)\n    * `bmatch` - expect(...).to.match(/.../i)\n    * `bprop` - expect(...).to.have.been.property(..., ...)\n    * `bthrow` - expect function to throw\n\n\n* bard.js\n\n    * `binject` - bard.inject\n    * `bcinject` - bard.inject for a controller\n    * `bmodule` - bard.appModule\n    * `basyncmod` - bard.asyncModule\n    * `bverify` - bard.verifyNoOutstandingHttpRequests()\n\n\n* angular.js\n\n    * `bapply` - $rootScope.$apply();\n    * `bwhen`  - $httpBackend.when('get', {url}).respond({status}, {data});\n    * `bflush` - $httpBackend.flush();\n\n* miscellaneous\n\n    * `bfn`    - generates a function stub\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwardbell%2Fbardjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwardbell%2Fbardjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwardbell%2Fbardjs/lists"}