0

I'm trying to access $scope's within an E2E test without success...

As a test I tried this: (My site does not use JQuery..)

The runner has my site in a nested iframe, so I'm accessing it directly, then getting all ng-scopes and trying .scope() on them as in this post and code below...

var frameDocument = document.getElementById('test-frames').children[0].contentDocument;
var scopeElements = frameDocument.getElementsByClassName('ng-scope');
var scopes = [].map.call(scopeElements, function (e) {
return angular.element(e).scope();
});

The above code finds the proper elements, but calling scope() on them returns undefined for each....

Can someone confirm or deny that we can access the scope in E2E? I'd assume there is a way?

Thank-you

Community
  • 1
  • 1
Thibs
  • 8,058
  • 13
  • 54
  • 85

2 Answers2

3

Here is my trick based on previous answer.

You can extend it to dynamic scopes. The main part is getting the reference to appWindow from addFutureAction.

//HTML CODE

<body id="main-controller" ng-controller="mainCtrl" ng-init="__init__()">


//Scenario helper.

/*
Run `callback` with scope from `selector`.
*/
angular.scenario.dsl('scope', function() {
    return function(selector, callback) {
        return this.addFutureAction(
            'Executing scope at ' + selector,
            function(appWindow, $document, done) {
                var body = appWindow.document.getElementById(selector)
                var scope = appWindow.angular.element(body).scope()
                callback(scope)
                scope.$apply()
                done(null, 'OK');
            })
    }
})

//Actual test.

it(
'When alerts are defined, they are displayed.',
function() {
    scope('main-controller', function(scope) {
        scope.alerts.push({'type': 'error', 'msg': 'Some error.'})
    })

    expect(element('#alerts').css('display')).toEqual('block')
})
Adi Roiban
  • 1,293
  • 2
  • 13
  • 28
2

In E2E tests, accessing scope that way is not good option. Instead You can use helper functions like element() to select elements in page, and use expect() to check model data.

What you might need is unit testing. You can access $scope in unit tests easily.

There is a very good guide here: http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-testacular.html

Also it might be a timing issue, i can reach scopes in testacular runner like this. It runs tests in iframe. To make it work you need to add sleep(3) to your test. But this is very fragile.

    setTimeout(function () {
        console.log('try to reach frames');
        var frame = window.frames[0].window.frames['senario_frame'];
        if (!frame) {
            console.log('too late');
        } else {

            var scopeElements = frame.document.getElementsByClassName('ng-scope');
            var scopes = [].map.call(scopeElements, function (e) {
                return frame.angular.element(e).scope();
            });
            console.log(scopes);
        }
    }, 2000);
ozan.turksever
  • 121
  • 1
  • 4
  • Thanks for the reply, I do understand this is bad practice. However, there was a specific case where I am trying to bypass the use of futures. So knowing it is not a good option, I'm still not sure if there 'is' a way to access the $scope... – Thibs Apr 15 '13 at 14:27
  • I edited the answer. I try to do it with testacular runner, it also uses iframe to run tests. – ozan.turksever Apr 15 '13 at 18:42