npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

angular-test-context

v0.1.10

Published

A simple API that implements core ngMock capabilities needed for unit testing.

Downloads

10

Readme

AngularTestContext

AngularTestContext provides a simple API that implements core ngMock capabilities needed for unit testing. Based upon your needs, it can replace the need for ngMock, or it can be used in conjunction with ngMock.

This utility was originally created to make it easier to build unit tests for directives using the Page Object design pattern.

Table of Contents

Features

  • Compatible with Angular 1.2.x and beyond.
  • Can be used in other testing frameworks besides Jasmine and Mocha.
  • Compatible with CommonJS, AMD, and non-module build environments.

Installation

To install the package:

npm install angular-test-context

To require the package:

var AngularTestContext = require("angular-test-context");

Usage

Creating a Test Context

First, make available any Angular modules needed by your test. In this example, we want to test myDirective, so we create a module and add the directive to the module:

angular.module('testApp', [])
    .directive('myDirective', myDirective); 

Next, create the AngularTestContext instance. AngularTestContext needs to know which Angular modules are used by your test. The names of the Angular modules can be passed in as an array, or as comma separated strings, or both.

var testContext = new AngularTestContext('testApp');

Compiling HTML with Scope Variables

To compile the HTML to be tested, call the .compile() method with the appropriate HTML and any optional scope variables:

var scope = {
    data: {
        value: 'hello'
    }
};
var element = testContext.compile('<div my-directive="data"></div>', scope);

The .compile() method returns the Angular wrapped DOM element, which can then be inspected during your tests to validate the directive's behavior.

Changing a Scope Value

To change a scope value, modify the value, and then call the .digest() method:

scope.data.value = 'goodbye';
testContext.digest();

Alternatively, you can access the Angular scope object used to compile the HTML, using the .scope() method:

scope.data.value = 'goodbye';
testContext.scope().$digest();

Injecting A Dependency

To inject a dependency into a function, use the .inject() method:

testContext.inject(function($timeout) {
    ...
});

To inject a dependency into a constructor, use the .instantiate() method:


function MyController($timeout) {
    ...
}

var controller = testContext.instantiate(MyController);

Page Object Design Pattern

AngularTestContext's GitHub project contains a calculator directive example for writing unit tests using the Page Object design pattern and the AngularTestContext utility.

If you haven't used the Page Object design pattern for writing unit tests, I highly recommend it. It will transform your tests from being unwieldy and fragile, to being robust and easily maintained.

The main benefits are:

  • It eliminates fragile tests. If the underlying implementation of your code changes, you modify the Page Object, not your tests.
  • Tests are much easier to understand since all implementation details are encapsulated in the Page Object.
  • Tests are much easier to write since the DRY (Don't Repeat Yourself) code is encapsulated within the Page Object.
  • Since the implementation is encapsulated within the Page Object, tests have the potential to be portable across different frameworks - preserving your investment in tests. Instead of changing your tests for each framework, create a different Page Object for each framework.

Calculator Unit Tests

Here are the unit tests for the calculator directive using the CalculatorPageObject.

A couple of points to observe:

  • There are no implementation details in the tests. The tests simply execute logical calls against the calculator's Page Object.
  • You can't determine from the tests what underlying framework is used to implement the calculator.

Note: Abstracting out the underlying framework in your tests may not always be feasible or desirable, but it's a choice worth considering.


/*
 * Unit tests for the calculator directive.
 */
'use strict';

//-------------------------------------
// Module dependencies and variables
//-------------------------------------

var Calculator = require('./CalculatorPageObject');

//-------------------------------------
// Unit tests
//-------------------------------------

describe('calculator directive:', function() {

    var calc;

    beforeEach(function() {
        calc = new Calculator();
    });

    describe('adding two numbers', function() {

        it('should be 3', function() {
            calc.operand1(1);
            calc.operand2(2);
            expect(calc.add()).toBe(3);
        });

        it('should be -2', function() {
            calc.operand1(0);
            calc.operand2(-2);
            expect(calc.add()).toBe(-2);
        });
    });

    describe('button state', function() {

        it('should be disabled if only first operand set', function() {
            expect(calc.isButtonDisabled()).toBe(true);
            calc.operand1(1);
            expect(calc.isButtonDisabled()).toBe(true);
        });

        it('should be disabled if only second operand set', function() {
            expect(calc.isButtonDisabled()).toBe(true);
            calc.operand2(2);
            expect(calc.isButtonDisabled()).toBe(true);
        });

        it('should be enabled if both operands set', function() {
            expect(calc.isButtonDisabled()).toBe(true);
            calc.operand1(1);
            calc.operand2(2);
            expect(calc.isButtonDisabled()).toBe(false);
        });
    });
});

Calculator Page Object

Here is the source code for the CalculatorPageObject, which uses the AngularTestContext utility.

/*
 * Page Object for the calculator directive.
 */
'use strict';

//-------------------------------------
// Module exports
//-------------------------------------

module.exports = CalculatorPageObject;

//-------------------------------------
// Module dependencies and variables
//-------------------------------------

var AngularTestContext = require('angular-test-context');
var calculatorDirective = require('./calculatorDirective');

// Private model name.
var MODEL = '_calculatorPageObject';

//-------------------------------------
// Page Object
//-------------------------------------

/*
 * @constructor
 */
function CalculatorPageObject() {
    var m = this[MODEL] = {};

    // Add directive to module.
    angular.module('testApp', [])
        .directive('calculator', calculatorDirective);

    // Create test context.
    var testContext = new AngularTestContext('testApp');

    // Compile and find elements.
    var element = testContext.compile('<calculator></calculator>');

    var inputs = element.find('input');
    expect(inputs.length).toBe(2);

    var button = element.find('button');
    expect(button.length).toBe(1);

    var result = element.find('span span');
    expect(result.length).toBe(1);

    m.input1 = $(inputs[0]);
    m.input2 = $(inputs[1]);
    m.button = button;
    m.result = result;
}

var proto = CalculatorPageObject.prototype;

/*
 * Sets the value of the first operand.
 *
 * @param {string} value
 */
proto.operand1 = function(value) {
    var m = this[MODEL];
    m.input1.val(value).trigger('input');
};

/*
 * Sets the value of the second operand.
 *
 * @param {string} value
 */
proto.operand2 = function(value) {
    var m = this[MODEL];
    m.input2.val(value).trigger('input');
};

/*
 * Adds the two operands.
 *
 * @returns {number} The result.
 */
proto.add = function() {
    var m = this[MODEL];
    m.button.trigger('click');
    return parseInt(m.result.html());
};

/*
 * Indicates whether add button is disabled.
 *
 * @returns {boolean}
 */
proto.isButtonDisabled = function() {
    var m = this[MODEL];
    return m.button.prop('disabled');
};