Tomás Solar
Tomás Solar

Reputation: 133

Use a factory in protractor test

After a lot of searching and trying how to use a factory in an e2e test, I decided to finally ask here.

I have a factory defined, with some functions, as follows:

regFormApp.factory('myFactory', ['$moment', function($moment) {
        return {
            title: 'Super Title 2014!',
            dates: [
                {
                    date: '2014-10-21',
                    time: '08:30',
                    timezone: 'America/Mexico_City'
                },
                {
                    date: '2014-10-22',
                    time: '08:30',
                    timezone: 'America/Mexico_City'
                }
            ],
            prices: {
                earlyBird: 1250,
                twoMonths: 1375,
                last: 1700
            },
            salesEndDates: function(ticketType) {
                var endDate = this.dates[0].date;
                switch (ticketType) {
                    case 'earlyBird':
                        endDate = '2014-07-19';
                        break;
                    case 'twoMonths':
                        endDate = $moment(endDate)
                                .subtract('months', 2)
                                .format('YYYY-MM-DD');
                        break;
                    default:
                        break;
                }
                return endDate;
            },
            getSalesPeriod: function(_format) {
                var format = _format || 'YYYY-MM-DD';
                var now = $moment().format(format);
                if (now <= this.salesEndDates('earlyBird')) {
                    return 'earlyBird';
                } else if (now > this.salesEndDates('earlyBird')
                        && now <= this.salesEndDates('twoMonths')) {
                    return 'twoMonths'
                }
                return 'last';
            }
        };
    }]);

And I want to use getSalesPeriod() in my e2e test with protractor, in order to test if a select is enabled or not.

So, my form looks like this:

...
<select id="earlyBirdSelect" class="form-control" ng-model="qty.earlyBird" ng-change="updateTotal()" ng-disabled="disableEarlyBird()">
    <option>1</option>
    ...
</select>

<select id="twoMonthsSelect" class="form-control" ng-model="qty.twoMonths" ng-change="updateTotal()" ng-disabled="disableTwoMonths()">
    <option>1</option>
    ...
</select>

<select id="lastSelect" class="form-control" ng-model="qty.last" ng-change="updateTotal()" ng-disabled="disableLast()">
    <option>1</option>
    ...
</select>
...

What is used to enable or disable selects is:

regFormControllers.controller('MainCtrl', ['$scope', '$http', '$filter', 'myFactory',
    function($scope, $http, $filter, myFactory) {
        ...

        $scope.disableEarlyBird = function() {
            if (myFactory.getSalesPeriod() === 'earlyBird') {
                return false;
            }
            return true;
        };
        // and analogously for twoMonths and last

        ...
     };
}]);

So, I want to do something like this:

describe('form', function() {


    beforeEach(function() { 
        browser.get('app/#/'); // here is the form
    });


    it('should be enabled only earlyBird select', function() {
        var earlyBirdSelect = element(by.css('#earlybirdSelect'));
        var twoMonthsSelect = element(by.css('#earlybirdSelect'));
        var lastSelect = element(by.css('#earlybirdSelect'));

        // here I want to get 'earlyBird' from getSalesPeriod()
        var period = myFactory.getSalesPeriod(); // it depends to current date
        if (period === 'earlyBird') {
            expect(earlyBirdSelect.getAttribute('disabled')).toBeFalsy();
            expect(twoMonthsSelect.getAttribute('disabled')).toBeTruthy();
            expect(lastSelect.getAttribute('disabled')).toBeTruthy();
        }
    });

});

I have no idea how to test it. Any help is very appreciated!

Thank you very much in advance!

Upvotes: 2

Views: 1345

Answers (1)

Jmr
Jmr

Reputation: 12108

There is no easy way to do this unless you expose getSalesPeriod to the $scope, in which case you could do lastSelect.evaluate('getSalesPeriod()')

If you don't want to change the app to expose the function you want to call, you'll have to reach into your Angular module by executing JavaScript:

browser.executeScript(function() {
  return angular.element(document).injector().get('myFactory').getSalesPeriod();
});

Upvotes: 5

Related Questions