7

Angular-scenario works well when your angular app is ready on DOM ready. Is not the case when using requirejs or an other AMD lib. How to add support for AMD in angular-scenario?

Francis
  • 3,335
  • 20
  • 46

3 Answers3

9

What you have to do is to override the default frame load behaviour and to emit a new event when you amd app is ready.

The first thing is to add the following lines in your angular application along with the angular.bootstrap call. This data is required by angular-scenario.

angular.bootstrap(document, ['app']);

var html = document.getElementsByTagName('html')[0];

html.setAttribute('ng-app', 'app');
html.dataset.ngApp = 'app';

if (top !== window) {
    top.postMessage({
        type: 'loadamd'
    }, '*');
}

Next, in your e2e runner, you have to include those lines. If it's an external script, it must be loaded after angular-scenario and it must be parsed before the DOM is ready :

/**
 *  Hack to support amd with angular-scenario
 */
(function() {
    var setUpAndRun = angular.scenario.setUpAndRun;

    angular.scenario.setUpAndRun = function(config) {
        if (config.useamd) {
            amdSupport();
        }
        return setUpAndRun.apply(this, arguments);
    };

    function amdSupport() {
        var getFrame_ = angular.scenario.Application.prototype.getFrame_;

        /**
         *  This function should be added to angular-scenario to support amd. It overrides the load behavior to wait from
         *  the inner amd frame to be ready.
         */
        angular.scenario.Application.prototype.getFrame_ = function() {
            var frame = getFrame_.apply(this, arguments);
            var load = frame.load;

            frame.load = function(fn) {
                if (typeof fn === 'function') {
                    angular.element(window).bind('message', function(e) {
                        if (e.data && e.source === frame.prop('contentWindow') && e.data.type === 'loadamd') {
                            fn.call(frame, e);
                        }
                    });
                    return this;
                }
                return load.apply(this, arguments);
            }

            return frame;
        };
    }
})();

Finally, to enable the amd configuration, you must add the attribute ng-useamd to angular-scenario's script tag.

<script type="text/javascript" src="lib/angular-1.0.3/angular-scenario.js" ng-autotest ng-useamd></script>

You're now ready to go

tested with angular-scenario v1.0.3

Francis
  • 3,335
  • 20
  • 46
  • Any chance you can provide a github repo or fiddle? – Subtubes Aug 16 '13 at 15:34
  • Thanks very much Francis. Just a note that if you are including JQuery in the runner page for any reason, you need to unwrap the message event when it arrives, like: if (e.originalEvent) e = e.originalEvent; – Tim Stewart Sep 06 '13 at 06:21
4

The above answer failed partly in my scenario (Angular 1.1.4, fresh Karma). In the debug view it ran fine, in the normal overview page it failed. I noticed an extra nested .

I changed the code to message to the parent iframe of the tested application.

if (top !== window) {
    window.parent.postMessage({
        type: 'loadamd'
    }, '*');
}
  • Yes, that's a good point. Karma create another frame that includes angular scenario's frame which includes you app's frame. So in this case, it's indeed the parent frame and not the top frame. – Francis May 14 '13 at 19:55
1

The accepted answer is absolutely correct, but it's a shame that you have to put that code into your page.

So, if it helps, I created a preprocessor for karma to inject the 'fix' in as part of the test run.

Code: https://github.com/tapmantwo/karma-ng-bootstrap-fix-preprocessor npm: https://www.npmjs.org/package/karma-ng-bootstrap-fix-preprocessor

Note, this only works if you are serving the files through karma. If you are proxying them, they dont go through the pre-processor. So, as an alternative I have a fork of ng-scenario which does something similar to allow manually bootstrapped sites to run;

https://github.com/tapmantwo/karma-ng-scenario

This isn't a node module, so you'll have to set it up manually, but its better (IMHO) to have something like this in place instead of infecting production code with something just to get tests to pass.

tapmantwo
  • 121
  • 2
  • 7