diff --git a/lib/mock/module.dart b/lib/mock/module.dart index 89fa2a709..2b5e9f13b 100644 --- a/lib/mock/module.dart +++ b/lib/mock/module.dart @@ -59,14 +59,16 @@ part 'mock_cache_register.dart'; */ class AngularMockModule extends Module { AngularMockModule() { + bind(MockApplication); + bind(Application, toImplementation: MockApplication); bind(ExceptionHandler, toImplementation: RethrowExceptionHandler); bind(TestBed); bind(Probe); bind(Logger); bind(MockHttpBackend); bind(CacheRegister, toImplementation: MockCacheRegister); - bind(Element, toValue: document.body); - bind(Node, toValue: document.body); + bind(Element, toFactory: (app) => app.element, inject: [MockApplication]); + bind(Node, inject: [Element]); bind(HttpBackend, toInstanceOf: MOCK_HTTP_BACKEND_KEY); bind(VmTurnZone, toFactory: () { return new VmTurnZone() @@ -78,3 +80,20 @@ class AngularMockModule extends Module { bind(DefaultPlatformShim, toInstanceOf: MockWebPlatformShim); } } + +class MockApplication extends Application { + var _element; + + Element get element { + if (_element == null) { + _element = new DivElement()..attributes['ng-app'] = ''; + } + return _element; + } + + void destroyElement() { + _element = null; + } + + Injector createInjector() => throw 'MockApplications can not create injectors'; +} diff --git a/lib/mock/test_injection.dart b/lib/mock/test_injection.dart index 9450dbf92..4762458d6 100644 --- a/lib/mock/test_injection.dart +++ b/lib/mock/test_injection.dart @@ -1,9 +1,13 @@ library angular.mock.test_injection; +import 'dart:html'; + +import 'package:angular/application.dart'; import 'package:angular/application_factory.dart'; import 'package:angular/mock/module.dart'; import 'package:di/di.dart'; import 'dart:mirrors'; +import 'module.dart'; _SpecInjector _currentSpecInjector = null; @@ -61,7 +65,7 @@ class _SpecInjector { } } - reset() { + void reset() { injector = null; injectorCreateLocation = null; } @@ -161,3 +165,12 @@ void setUpInjector() { void tearDownInjector() { _currentSpecInjector = null; } + +void cleanUpAppRoot() { + if (_currentSpecInjector.injector != null) { + var app = _currentSpecInjector.injector.get(Application); + assert(app is MockApplication); + app.destroyElement(); + } + document.body.setInnerHtml(''); +} diff --git a/test/_specs.dart b/test/_specs.dart index b1a4923f6..7f4adc3d1 100644 --- a/test/_specs.dart +++ b/test/_specs.dart @@ -215,6 +215,7 @@ _removeNgBinding(node) { main() { gns.beforeEach(setUpInjector, priority:3); + gns.afterEach(cleanUpAppRoot); gns.afterEach(tearDownInjector); gns.guinnessEnableHtmlMatchers(); diff --git a/test/animate/ng_animate_spec.dart b/test/animate/ng_animate_spec.dart index 86406a8c1..6ac5849b4 100644 --- a/test/animate/ng_animate_spec.dart +++ b/test/animate/ng_animate_spec.dart @@ -26,10 +26,6 @@ main() { }); }); - afterEach(() { - tearDownInjector(); - }); - it('should control animations on elements', () { _.compile('
'); _.rootScope.apply(); diff --git a/test/core_dom/event_handler_spec.dart b/test/core_dom/event_handler_spec.dart index 3511527f6..25063bd89 100644 --- a/test/core_dom/event_handler_spec.dart +++ b/test/core_dom/event_handler_spec.dart @@ -20,49 +20,37 @@ main() { describe('EventHandler', () { Element ngAppElement; beforeEachModule((Module module) { - ngAppElement = new DivElement()..attributes['ng-app'] = ''; module..bind(BarComponent); - module..bind(Node, toValue: ngAppElement); - document.body.append(ngAppElement); }); - afterEach(() { - ngAppElement.remove(); - ngAppElement = null; - }); - - compile(_, html) { - ngAppElement.setInnerHtml(html, treeSanitizer: new NullTreeSanitizer()); - _.compile(ngAppElement); - return ngAppElement.firstChild; - } - it('should register and handle event', (TestBed _) { - var e = compile(_, + it('should register and handle event', (TestBed _, Application app) { + var e = _.compile( '''
'''); _.triggerEvent(e, 'abc'); expect(_.rootScope.context['invoked']).toEqual(true); }); - it('shoud register and handle event with long name', (TestBed _) { - var e = compile(_, + it('shoud register and handle event with long name', (TestBed _, Application app) { + var e = _.compile( '''
'''); _.triggerEvent(e, 'my-new-event'); expect(_.rootScope.context['invoked']).toEqual(true); }); - it('shoud have model updates applied correctly', (TestBed _) { - var e = compile(_, + it('should have model updates applied correctly', (TestBed _, Application app) { + var e = _.compile( '''
{{description}}
'''); e.dispatchEvent(new Event('abc')); _.rootScope.apply(); expect(e.text).toEqual("new description"); }); - it('shoud register event when shadow dom is used', async((TestBed _) { - var e = compile(_,''); + it('should register event when shadow dom is used', async((TestBed _, Application app) { + var e = _.compile(''); + document.body.append(app.element..append(e)); microLeap(); @@ -73,8 +61,8 @@ main() { expect(ctrl.invoked).toEqual(true); })); - it('shoud handle event within content only once', async((TestBed _) { - var e = compile(_, + it('shoud handle event within content only once', async((TestBed _, Application app) { + var e = _.compile( '''
diff --git a/test/directive/ng_model_select_spec.dart b/test/directive/ng_model_select_spec.dart index 0c263e71e..ba6266bad 100644 --- a/test/directive/ng_model_select_spec.dart +++ b/test/directive/ng_model_select_spec.dart @@ -7,16 +7,17 @@ import 'package:browser_detect/browser_detect.dart'; main() { describe('input-select', () { - describe('ng-value', () { TestBed _; beforeEach((TestBed tb) => _ = tb); - it('should retrieve using ng-value', () { - _.compile( + it('should retrieve using ng-value', (Application app) { + var selectElement = _.compile( ''); + document.body.append(app.element..append(selectElement)); + var r2d2 = {"name":"r2d2"}; var c3p0 = {"name":"c3p0"}; _.rootScope.context['robots'] = [ r2d2, c3p0 ]; @@ -27,14 +28,15 @@ main() { _.rootScope.context['robot'] = r2d2; _.rootScope.apply(); expect(_.rootScope.context['robot']).toEqual(r2d2); - expect(_.rootElement).toEqualSelect([['r2d2'], 'c3p0']); + expect(selectElement).toEqualSelect([['r2d2'], 'c3p0']); }); - it('should retrieve using ng-value', () { - _.compile( + it('should retrieve using ng-value', (Application app) { + var selectElement = _.compile( ''); + document.body.append(app.element..append(selectElement)); var r2d2 = { "name":"r2d2"}; var c3p0 = {"name":"c3p0"}; _.rootScope.context['robots'] = [ r2d2, c3p0 ]; @@ -45,7 +47,7 @@ main() { _.rootScope.context['robot'] = [r2d2]; _.rootScope.apply(); expect(_.rootScope.context['robot']).toEqual([r2d2]); - expect(_.rootElement).toEqualSelect([['r2d2'], 'c3p0']); + expect(selectElement).toEqualSelect([['r2d2'], 'c3p0']); }); }); @@ -56,7 +58,7 @@ main() { describe('select-one', () { it('should compile children of a select without a ngModel, but not create a model for it', () { - _.compile( + var selectElement = _.compile( '' '' ''); - + document.body.append(app.element..append(e)); + var selectElement = document.querySelector('select'); _.rootScope.context['robots'] = ['c3p0', 'r2d2']; _.rootScope.context['robot'] = 'r2d2'; _.rootScope.apply(); @@ -143,23 +146,24 @@ main() { expect(_.rootElement).toEqualSelect(['x', [''], 'y']); }); - it('should set the model to empty string when empty option is selected', () { + it('should set the model to empty string when empty option is selected', (Application app) { _.rootScope.context['robot'] = 'x'; - _.compile( + var selectElement = _.compile( ''); + document.body.append(app.element..append(selectElement)); _.rootScope.apply(); var select = _.rootScope.context['p'].directive(InputSelect); - expect(_.rootElement).toEqualSelect(['', ['x'], 'y']); + expect(selectElement).toEqualSelect(['', ['x'], 'y']); - _.selectOption(_.rootElement, '--select--'); + _.selectOption(selectElement, '--select--'); - expect(_.rootElement).toEqualSelect([[''], 'x', 'y']); + expect(selectElement).toEqualSelect([[''], 'x', 'y']); expect(_.rootScope.context['robot']).toEqual(null); }); @@ -175,23 +179,24 @@ main() { expect(_.rootElement).toEqualSelect([[''], 'c3p0', 'r2d2']); }); - it('should set model to empty string when selected', () { + it('should set model to empty string when selected', (Application app) { _.rootScope.context['robots'] = ['c3p0', 'r2d2']; - _.compile( + var selectElement = _.compile( ''); + document.body.append(app.element..append(selectElement)); _.rootScope.apply(); var select = _.rootScope.context['p'].directive(InputSelect); - _.selectOption(_.rootElement, 'c3p0'); - expect(_.rootElement).toEqualSelect(['', ['c3p0'], 'r2d2']); + _.selectOption(selectElement, 'c3p0'); + expect(selectElement).toEqualSelect(['', ['c3p0'], 'r2d2']); expect( _.rootScope.context['robot']).toEqual('c3p0'); - _.selectOption(_.rootElement, '--select--'); + _.selectOption(selectElement, '--select--'); - expect(_.rootElement).toEqualSelect([[''], 'c3p0', 'r2d2']); + expect(selectElement).toEqualSelect([[''], 'c3p0', 'r2d2']); expect( _.rootScope.context['robot']).toEqual(null); }); @@ -421,33 +426,39 @@ main() { describe('select from angular.js', () { - TestBed _; - beforeEach((TestBed tb) => _ = tb); - var scope, formElement, element; - - compile(html) { - _.compile('
' + html + '
'); - element = _.rootElement.querySelector('select'); - scope.apply(); - } - - beforeEach((Scope rootScope) { + TestBed _; +// Element ngAppElement; +// beforeEachModule((Module module) { +// ngAppElement = new DivElement()..attributes['ng-app'] = ''; +// module..bind(Node, toValue: ngAppElement); +// document.body.append(ngAppElement); +// }); + + beforeEach((TestBed tb, Scope rootScope) { + _ = tb; scope = rootScope; formElement = element = null; }); + compile(html) { + var el = _.compile('
' + html + '
'); + element = el.querySelector('select'); + scope.apply(); + return el; + } afterEach(() { scope.destroy(); //disables unknown option work during destruction + cleanUpAppRoot(); }); - describe('select-one', () { it('should compile children of a select without a ngModel, but not create a model for it', () { - compile('' + '' + '' + '' + @@ -463,7 +474,8 @@ main() { it('should not interfere with selection via selected attr if ngModel directive is not present', () { - compile('' + '' + '' + '' + @@ -493,12 +505,13 @@ main() { }); - it('should require', () { - compile( + it('should require', (Application app) { + var e = compile( ''); + document.body.append(app.element..append(e)); var element = scope.context['i'].element; @@ -550,7 +563,8 @@ main() { describe('empty option', () { it('should select the empty option when model is undefined', () { - compile('' + '' + '' + '' + @@ -561,7 +575,8 @@ main() { it('should support defining an empty option anywhere in the option list', () { - compile('' + '' + '' + '' + @@ -596,7 +611,8 @@ main() { }); it('should work with optgroups', () { - compile('' + '' + '' + '' + @@ -617,12 +633,13 @@ main() { expect(element).toEqualSelect([['A'], ['B']]); }); - it('should require', () { - compile( + it('should require', (Application app) { + var e = compile( ''); + document.body.append(app.element..append(e)); var element = scope.context['i'].element; scope.apply('selection = []'); @@ -662,17 +679,17 @@ main() { (ngRepeat != null ? '' : '') + ''; - compile(html); + return compile(html); } createSingleSelect([blank, unknown]) { - createSelect({ + return createSelect({ 'ng-model':'selected' }, blank, unknown, 'value in values', 'value.name', 'value'); } createMultiSelect([blank, unknown]) { - createSelect({ + return createSelect({ 'ng-model':'selected', 'multiple':true }, blank, unknown, 'value in values', 'value.name', 'value'); @@ -982,8 +999,10 @@ main() { }); - it('should select correct input if previously selected option was "?"', () { - createSingleSelect(); + it('should select correct input if previously selected option was "?"', + (Application app) { + var e = createSingleSelect(); + document.body.append(app.element..append(e)); scope.apply(() { scope.context['values'] = [{'name': 'A'}, {'name': 'B'}]; @@ -1099,8 +1118,9 @@ main() { describe('on change', () { - it('should update model on change', () { - createSingleSelect(); + it('should update model on change', (Application app) { + var e = createSingleSelect(); + document.body.append(app.element..append(e)); scope.apply(() { scope.context['values'] = [{'name': 'A'}, {'name': 'B'}]; @@ -1115,9 +1135,10 @@ main() { }); - it('should update model on change through expression', () { - createSelect({'ng-model': 'selected'}, null, null, + it('should update model on change through expression', (Application app) { + var e = createSelect({'ng-model': 'selected'}, null, null, 'item in values', 'item.name', 'item.id'); + document.body.append(app.element..append(e)); scope.apply(() { scope.context['values'] = [{'id': 10, 'name': 'A'}, {'id': 20, 'name': 'B'}]; @@ -1132,8 +1153,9 @@ main() { }); - it('should update model to null on change', () { - createSingleSelect(true); + it('should update model to null on change', (Application app) { + var e = createSingleSelect(true); + document.body.append(app.element..append(e)); scope.apply(() { scope.context['values'] = [{'name': 'A'}, {'name': 'B'}]; @@ -1181,8 +1203,9 @@ main() { }); - it('should update model on change', () { - createMultiSelect(); + it('should update model on change', (Application app) { + var e = createMultiSelect(); + document.body.append(app.element..append(e)); scope.apply(() { scope.context['values'] = [{'name': 'A'}, {'name': 'B'}];