Test ViewModel KnockOut with CucumberJs

2

I have the feature definition as follows:

Feature: Shoper can add an item to ShoppingCart

  Scenario: First item added to ShoppingCart
    Given I have an Empty ShoppingCart
    When I add an Item to ShoppingCart
    Then The ShoppingCart must have 1 item

  Scenario: Second item added to ShoppingCart
    Given I already have 1 item on my ShoppingCart
    When I add a second item to ShoppingCart
    Then The ShoppingCart must have 2 items

and the generated Step code is

'use strict';
module.exports = function () {
  this.Given(/^I have an Empty ShoppingCart$/, function (callback) {
    // Write code here that turns the phrase above into concrete actions
    callback.pending();
  });

  this.When(/^I add an Item to ShoppingCart$/, function (callback) {
    // Write code here that turns the phrase above into concrete actions
    callback.pending();
  });

  this.Then(/^The ShoppingCart must have (\d+) item$/, function (arg1, callback) {

    // Write code here that turns the phrase above into concrete actions
    callback.pending();
  });
}

but the object I need to test is a Observable of KnockOut

function ShopCartViewModel() {
    var self = this;
    self.items = ko.observableArray([]);
    self.grandTotal = ko.computed(function() {
        var total = 0;
        ko.utils.arrayForEach(this.items(), function(item) {
            total += item.price();
        });

        return total.toFixed(2);
    }, this);

    self.getItemFromList    = function ( id ) {
        return ko.utils.arrayFirst(self.items(), function (item)
        {
            if (item.ProductId() === id()) {
                return item;
            }
        });
    }
}

How can I instantiate an object ViewModel within the steps of Cucumber ?

    
asked by anonymous 02.07.2014 / 04:29

1 answer

2

This required the use of RequireJs

To the page

Download RequireJS and place it in the folder along with the other javascript scripts

create a main.js or init.js which will be the definition file of the modules that will be loaded

require(['knockout-3.1.0', 'appViewModel'], function(ko, appViewModel) {
    ko.applyBindings(new appViewModel());
});

create your viewModel using the define function of requireJS

define(['knockout-3.1.0', 'shopCartItemViewModel'], function (ko, ShopCartItem) {
    return function ShopCart() {
        var self = this;
        self.items = ko.observableArray([]);
        self.grandTotal = ko.computed(function() {
            var total = 0;

            ko.utils.arrayForEach(self.items(), function(item) {
                total += parseFloat(item.NetValue());
            });

            return total;
        }, self.items);
    }
});

In the HTML page you initialize all scripts using requireJS

<script type="text/javascript" data-main="js/main.js" src="js/require.js"></script>

For the part of the tests

install requireJs for the node

npm install requirejs -g

create another main file because, in the node the require function already exists and the way to initialize the RequireJs in the node is different

file: main_node.js

var requirejs = require('requirejs');

requirejs(['knockout-3.1.0', 'shopCartViewModel' /*, 'appViewModel'*/], function(ko, appViewModel) {
    //ko.applyBindings(new appViewModel());
});

Then, just initialize the RequireJs in the steps of the feature itself or in the beforeHook of the tests with cucumber

'use strict';
module.exports = function () {

    var assert = require('assert');
    var requirejs = require('requirejs');    
    var item = function (itemId) {
        return {
            id : itemId,
            nome: "Biscoito " + itemId,
            itemQtd: 1,
            valorUnitario: 3.00,
            tipo: "Biscoito",
            unitDiscount: 0.4
        }
    }

    requirejs.config({
      //caminho para seus arquivos js do knockout
      baseUrl: __dirname + '\..\..\js',
      //Caminho para o arquivo main, que servirá de referencia para o carregamento dos demais módulos
      nodeRequire: require('../../js/main_node')
    });

    var ShopCart = requirejs('shopCartViewModel');

    var cart;

    this.Given(/^I have an Empty ShoppingCart$/, function (callback) {

        cart = new ShopCart();
        cart.items.removeAll();
        callback();
    });

    this.When(/^I add an Item to ShoppingCart$/, function (callback) {

        cart.addItemToCart(item(1));
        callback();
    });

    this.Then(/^The ShoppingCart must have (\d+) items$/, function (cartItemsCount, callback) {

        assert.equal(cart.getItemsCount(), cartItemsCount, 'ShopCart should have ' + cartItemsCount + ' items but have ' + cart.getItemsCount());
        callback();
    });

    this.Given(/^I already have (\d+) items on my ShoppingCart$/, function (itemsCount, callback) {

        cart.items.removeAll();
        for (i = 1; i <= itemsCount; i++) {
            (function (j) {
                cart.addItemToCart(item(j));
            }(i));
        }
        callback();
    });

    this.When(/^I add a second item to ShoppingCart$/, function (callback) {
        cart.addItemToCart(item(2));
        callback();
    });

    this.When(/^I add quantity of (\d+) to the first item$/, function (incrementCount, callback) {
        var itemFromCart = cart.getItemFromList(1);
        cart.addToItem(itemFromCart, incrementCount);
        callback();
    });

    this.Then(/^The first item must have a quantity of (\d+)$/, function (expectedItemCount, callback) {
        var itemFromCart = cart.getItemFromList(1);
        assert.equal(itemFromCart.quantidade(), expectedItemCount, 'Deveriam haver ' + expectedItemCount + ' mas haviam ' + itemFromCart.quantidade());
        callback();
    });

    this.When(/^I add (\d+) items to ShoppingCart$/, function (itemsCount, callback) {
        for (i = 1; i <= itemsCount; i++) {
            (function (j) {
                cart.addItemToCart(item(j));
            }(i));
        }
        callback();
    });

    this.Then(/^Shopping cart must have (\d+) value$/, function (netValue, callback) {
        console.log(cart.grandTotal());
        assert.equal(parseFloat(cart.grandTotal()), netValue, 'Total must be ' + netValue + ' but was ' + parseFloat(cart.grandTotal()));
        callback();
    });
}

Final result:

D:\Private\node\Projetos\siteBiscoitaria\public_www>cucumber-js
............

4 scenarios (4 passed)
12 steps (12 passed)
    
16.07.2014 / 05:55