'use strict'; describe('compiler', function(){ var compiler, markup, attrMarkup, directives, widgets, compile, log, scope; beforeEach(function(){ log = ""; directives = { hello: function(expression, element){ log += "hello "; return function() { log += expression; }; }, observe: function(expression, element){ return function() { this.$watch(expression, function(scope, val){ if (val) log += ":" + val; }); }; } }; markup = []; attrMarkup = []; widgets = extensionMap({}, 'widget'); compiler = new Compiler(markup, attrMarkup, directives, widgets); compile = function(html){ var e = jqLite("
" + html + "
"); return scope = compiler.compile(e)(); }; }); afterEach(function(){ dealoc(scope); }); it('should not allow compilation of multiple roots', function(){ expect(function(){ compiler.compile('
A
'); }).toThrow("Cannot compile multiple element roots: " + ie("
A
")); function ie(text) { return msie < 9 ? uppercase(text) : text; } }); it('should recognize a directive', function(){ var e = jqLite('
'); directives.directive = function(expression, element){ log += "found"; expect(expression).toEqual("expr"); expect(element).toEqual(e); return function initFn() { log += ":init"; }; }; var template = compiler.compile(e); expect(log).toEqual("found"); scope = template(angular.scope()); expect(e.hasClass('ng-directive')).toEqual(true); expect(log).toEqual("found:init"); }); it('should recurse to children', function(){ scope = compile('
'); expect(log).toEqual("hello misko"); }); it('should observe scope', function(){ scope = compile(''); expect(log).toEqual(""); scope.$digest(); scope.name = 'misko'; scope.$digest(); scope.$digest(); scope.name = 'adam'; scope.$digest(); scope.$digest(); expect(log).toEqual(":misko:adam"); }); it('should prevent descend', function(){ directives.stop = function(){ this.descend(false); }; scope = compile(''); expect(log).toEqual("hello misko"); }); it('should allow creation of templates', function(){ directives.duplicate = function(expr, element){ element.replaceWith(document.createComment("marker")); element.removeAttr("duplicate"); var linker = this.compile(element); return function(marker) { this.$watch('value', function() { var scope = linker(angular.scope(), noop); marker.after(scope.$element); }); }; }; scope = compile('beforexafter'); scope.value = 1; scope.$digest(); expect(sortedHtml(scope.$element)).toEqual('
before<#comment>xafter
'); scope.value = 2; scope.$digest(); expect(sortedHtml(scope.$element)).toEqual('
before<#comment>xxafter
'); scope.value = 3; scope.$digest(); expect(sortedHtml(scope.$element)).toEqual('
before<#comment>xxxafter
'); }); it('should process markup before directives', function(){ markup.push(function(text, textNode, parentNode) { if (text == 'middle') { expect(textNode.text()).toEqual(text); parentNode.attr('hello', text); textNode[0].nodeValue = 'replaced'; } }); scope = compile('beforemiddleafter'); expect(sortedHtml(scope.$element[0], true)).toEqual('
beforereplacedafter
'); expect(log).toEqual("hello middle"); }); it('should replace widgets', function(){ widgets['NG:BUTTON'] = function(element) { expect(element.hasClass('ng-widget')).toEqual(true); element.replaceWith('
button
'); return function(element) { log += 'init'; }; }; scope = compile('push me'); expect(lowercase(scope.$element[0].innerHTML)).toEqual('
button
'); expect(log).toEqual('init'); }); it('should use the replaced element after calling widget', function(){ widgets['H1'] = function(element) { // HTML elements which are augmented by acting as widgets, should not be marked as so expect(element.hasClass('ng-widget')).toEqual(false); var span = angular.element('{{1+2}}'); element.replaceWith(span); this.descend(true); this.directives(true); return noop; }; markup.push(function(text, textNode, parent){ if (text == '{{1+2}}') parent.text('3'); }); scope = compile('

ignore me

'); expect(scope.$element.text()).toEqual('3'); }); it('should allow multiple markups per text element', function(){ markup.push(function(text, textNode, parent){ var index = text.indexOf('---'); if (index > -1) { textNode.after(text.substring(index + 3)); textNode.after("
"); textNode.after(text.substring(0, index)); textNode.remove(); } }); markup.push(function(text, textNode, parent){ var index = text.indexOf('==='); if (index > -1) { textNode.after(text.substring(index + 3)); textNode.after("

"); textNode.after(text.substring(0, index)); textNode.remove(); } }); scope = compile('A---B---C===D'); expect(sortedHtml(scope.$element)).toEqual('

A
B
C

D
'); }); it('should add class for namespace elements', function(){ scope = compile('abc'); var space = jqLite(scope.$element[0].firstChild); expect(space.hasClass('ng-space')).toEqual(true); }); });