diff --git a/packages/core/test/acceptance/BUILD.bazel b/packages/core/test/acceptance/BUILD.bazel
index b3abaa7ccad..e6e0e5a7282 100644
--- a/packages/core/test/acceptance/BUILD.bazel
+++ b/packages/core/test/acceptance/BUILD.bazel
@@ -1,12 +1,17 @@
-load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ts_library")
+load("//tools:defaults.bzl", "jasmine_node_test", "karma_web_test_suite", "ng_module", "ts_library")
package(default_visibility = ["//visibility:private"])
+SPEC_FILES_WITH_FORWARD_REFS = [
+ "di_forward_ref_spec.ts",
+]
+
ts_library(
name = "acceptance_lib",
testonly = True,
srcs = glob(
["**/*.ts"],
+ exclude = SPEC_FILES_WITH_FORWARD_REFS,
),
# Visible to //:saucelabs_unit_tests
visibility = ["//:__pkg__"],
@@ -35,11 +40,28 @@ ts_library(
],
)
+# Note: The `forward_ref` example tests are built through this `ng_module` sub-target.
+# This is done so that DI decorator/type metadata is processed manually by the compiler
+# ahead of time. We cannot rely on the official TypeScript decorator downlevel emit (for JIT),
+# as the output is not compatible with `forwardRef` and ES2015+. More details here:
+# https://github.com/angular/angular/commit/323651bd38909b0f4226bcb6c8f5abafa91cf9d9.
+# https://github.com/microsoft/TypeScript/issues/27519.
+ng_module(
+ name = "forward_ref_test_lib",
+ testonly = True,
+ srcs = SPEC_FILES_WITH_FORWARD_REFS,
+ deps = [
+ "//packages/core",
+ "//packages/core/testing",
+ ],
+)
+
jasmine_node_test(
name = "acceptance",
bootstrap = ["//tools/testing:node_es2015"],
deps = [
":acceptance_lib",
+ ":forward_ref_test_lib",
"//packages/zone.js/lib:zone_d_ts",
"@npm//base64-js",
"@npm//source-map",
@@ -50,5 +72,6 @@ karma_web_test_suite(
name = "acceptance_web",
deps = [
":acceptance_lib",
+ ":forward_ref_test_lib",
],
)
diff --git a/packages/core/test/acceptance/di_forward_ref_spec.ts b/packages/core/test/acceptance/di_forward_ref_spec.ts
new file mode 100644
index 00000000000..4551399ee92
--- /dev/null
+++ b/packages/core/test/acceptance/di_forward_ref_spec.ts
@@ -0,0 +1,67 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {Component, Directive, forwardRef, Host, Inject, ViewChild} from '@angular/core';
+import {TestBed} from '@angular/core/testing';
+
+// **NOTE**: More details on why tests relying on `forwardRef` are put into this
+// file can be found in the `BUILD.bazel` file declaring the forward ref test target.
+
+describe('di with forwardRef', () => {
+ describe('directive injection', () => {
+ it('should throw if directives try to inject each other', () => {
+ @Directive({selector: '[dirB]'})
+ class DirectiveB {
+ constructor(@Inject(forwardRef(() => DirectiveA)) siblingDir: DirectiveA) {}
+ }
+
+ @Directive({selector: '[dirA]'})
+ class DirectiveA {
+ constructor(siblingDir: DirectiveB) {}
+ }
+
+ @Component({template: '
'})
+ class MyComp {
+ }
+
+ TestBed.configureTestingModule({declarations: [DirectiveA, DirectiveB, MyComp]});
+ expect(() => TestBed.createComponent(MyComp))
+ .toThrowError(
+ 'NG0200: Circular dependency in DI detected for DirectiveA. Find more at https://angular.io/errors/NG0200');
+ });
+
+ describe('flags', () => {
+ describe('@Host', () => {
+ it('should find host component on the host itself', () => {
+ @Directive({selector: '[dirComp]'})
+ class DirectiveComp {
+ constructor(@Inject(forwardRef(() => MyComp)) @Host() public comp: MyComp) {}
+ }
+
+ @Component({selector: 'my-comp', template: ''})
+ class MyComp {
+ @ViewChild(DirectiveComp) dirComp!: DirectiveComp;
+ }
+
+ @Component({template: '', jit: true})
+ class MyApp {
+ @ViewChild(MyComp) myComp!: MyComp;
+ }
+
+ TestBed.configureTestingModule({declarations: [DirectiveComp, MyComp, MyApp]});
+ const fixture = TestBed.createComponent(MyApp);
+ fixture.detectChanges();
+
+ const myComp = fixture.componentInstance.myComp;
+ const dirComp = myComp.dirComp;
+ expect(dirComp.comp).toBe(myComp);
+ });
+ });
+ });
+ });
+});
diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts
index 2824bec4b61..a348745229c 100644
--- a/packages/core/test/acceptance/di_spec.ts
+++ b/packages/core/test/acceptance/di_spec.ts
@@ -684,27 +684,6 @@ describe('di', () => {
expect(cmp.componentInstance.testB.a).toBeNull();
});
- it('should throw if directives try to inject each other', () => {
- @Directive({selector: '[dirB]'})
- class DirectiveB {
- constructor(@Inject(forwardRef(() => DirectiveA)) siblingDir: DirectiveA) {}
- }
-
- @Directive({selector: '[dirA]'})
- class DirectiveA {
- constructor(siblingDir: DirectiveB) {}
- }
-
- @Component({template: ''})
- class MyComp {
- }
-
- TestBed.configureTestingModule({declarations: [DirectiveA, DirectiveB, MyComp]});
- expect(() => TestBed.createComponent(MyComp))
- .toThrowError(
- 'NG0200: Circular dependency in DI detected for DirectiveA. Find more at https://angular.io/errors/NG0200');
- });
-
it('should throw if directive tries to inject itself', () => {
@Directive({selector: '[dirA]'})
class DirectiveA {
@@ -1781,31 +1760,6 @@ describe('di', () => {
expect(dirString.s).toBe('Foo');
});
- it('should find host component on the host itself', () => {
- @Directive({selector: '[dirComp]'})
- class DirectiveComp {
- constructor(@Inject(forwardRef(() => MyComp)) @Host() public comp: MyComp) {}
- }
-
- @Component({selector: 'my-comp', template: ''})
- class MyComp {
- @ViewChild(DirectiveComp) dirComp!: DirectiveComp;
- }
-
- @Component({template: ''})
- class MyApp {
- @ViewChild(MyComp) myComp!: MyComp;
- }
-
- TestBed.configureTestingModule({declarations: [DirectiveComp, MyComp, MyApp]});
- const fixture = TestBed.createComponent(MyApp);
- fixture.detectChanges();
-
- const myComp = fixture.componentInstance.myComp;
- const dirComp = myComp.dirComp;
- expect(dirComp.comp).toBe(myComp);
- });
-
it('should not find providers on the host itself', () => {
@Component({
selector: 'my-comp',
@@ -1882,19 +1836,19 @@ describe('di', () => {
});
it('should not find component above the host', () => {
+ @Component({template: ''})
+ class MyApp {
+ }
+
@Directive({selector: '[dirComp]'})
class DirectiveComp {
- constructor(@Inject(forwardRef(() => MyApp)) @Host() public comp: MyApp) {}
+ constructor(@Host() public comp: MyApp) {}
}
@Component({selector: 'my-comp', template: ''})
class MyComp {
}
- @Component({template: ''})
- class MyApp {
- }
-
TestBed.configureTestingModule({declarations: [DirectiveComp, MyComp, MyApp]});
expect(() => TestBed.createComponent(MyApp))
.toThrowError(
diff --git a/packages/core/test/acceptance/property_binding_spec.ts b/packages/core/test/acceptance/property_binding_spec.ts
index 3a5b9645a34..a6cada6e8fc 100644
--- a/packages/core/test/acceptance/property_binding_spec.ts
+++ b/packages/core/test/acceptance/property_binding_spec.ts
@@ -510,7 +510,12 @@ describe('property bindings', () => {
const fixture = TestBed.createComponent(App);
const myDir = fixture.debugElement.query(By.directive(MyDir)).injector.get(MyDir);
const myDirB = fixture.debugElement.query(By.directive(MyDirB)).injector.get(MyDirB);
- const [buttonEl, listboxEl] = fixture.nativeElement.children;
+ const fixtureElements = fixture.nativeElement.children;
+
+ // TODO: Use destructuring once Domino supports native ES2015, or when jsdom is used.
+ const buttonEl = fixtureElements[0];
+ const listboxEl = fixtureElements[1];
+
fixture.detectChanges();
expect(buttonEl.getAttribute('role')).toBe('button');
@@ -581,7 +586,11 @@ describe('property bindings', () => {
expect(fixture.nativeElement.children.length).toBe(2);
- const [comp1, comp2] = fixture.nativeElement.children;
+ const compElements = fixture.nativeElement.children;
+
+ // TODO: Use destructuring once Domino supports native ES2015, or when jsdom is used.
+ const comp1 = compElements[0];
+ const comp2 = compElements[1];
expect(comp1.tagName).toBe('COMP');
expect(comp2.tagName).toBe('COMP');
diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts
index 032ed10a109..7fecb884fba 100644
--- a/packages/core/test/acceptance/styling_spec.ts
+++ b/packages/core/test/acceptance/styling_spec.ts
@@ -60,8 +60,8 @@ describe('styling', () => {
TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp);
+ const staticDiv = fixture.nativeElement.querySelectorAll('div')[0];
- const [staticDiv] = fixture.nativeElement.querySelectorAll('div');
expect(getSortedClassName(staticDiv)).toEqual('STATIC');
expect(getSortedStyle(staticDiv)).toEqual('color: blue;');
});
@@ -335,7 +335,12 @@ describe('styling', () => {
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
- const [div1, div2] = fixture.nativeElement.querySelectorAll('div');
+ const divs = fixture.nativeElement.querySelectorAll('div');
+
+ // TODO: Use destructuring once Domino supports native ES2015, or when jsdom is used.
+ const div1 = divs[0];
+ const div2 = divs[1];
+
// Static value `class="s1"` is always written to the DOM.
expect(div1.className).toEqual('s1');
expect(div1.getAttribute('shadow-class')).toEqual('s1 d1');
@@ -367,7 +372,12 @@ describe('styling', () => {
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
- const [divStatic, divBinding] = fixture.nativeElement.querySelectorAll('div');
+ const divs = fixture.nativeElement.querySelectorAll('div');
+
+ // TODO: Use destructuring once Domino supports native ES2015, or when jsdom is used.
+ const divStatic = divs[0];
+ const divBinding = divs[1];
+
expectClass(divStatic).toEqual({'DIRECTIVE': true, 's1': true});
expect(divStatic.getAttribute('shadow-class')).toEqual('s1');
@@ -398,7 +408,12 @@ describe('styling', () => {
const fixture = TestBed.createComponent(Cmp);
fixture.detectChanges();
- const [divStatic, divBinding] = fixture.nativeElement.querySelectorAll('div');
+ const divs = fixture.nativeElement.querySelectorAll('div');
+
+ // TODO: Use destructuring once Domino supports native ES2015, or when jsdom is used.
+ const divStatic = divs[0];
+ const divBinding = divs[1];
+
expectStyle(divStatic).toEqual({'color': 'red', 'width': '1px'});
expect(divStatic.getAttribute('shadow-style')).toEqual('width: 1px;');
@@ -2451,11 +2466,10 @@ describe('styling', () => {
const items = fixture.nativeElement.querySelectorAll('.item');
expect(items.length).toEqual(4);
- const [a, b, c, d] = items;
- expect(a.style.height).toEqual('0px');
- expect(b.style.height).toEqual('100px');
- expect(c.style.height).toEqual('200px');
- expect(d.style.height).toEqual('300px');
+ expect(items[0].style.height).toEqual('0px');
+ expect(items[1].style.height).toEqual('100px');
+ expect(items[2].style.height).toEqual('200px');
+ expect(items[3].style.height).toEqual('300px');
const section = fixture.nativeElement.querySelector('section');
const p = fixture.nativeElement.querySelector('p');
@@ -3342,7 +3356,11 @@ describe('styling', () => {
const fixture = TestBed.createComponent(MyComp);
fixture.detectChanges();
- const [div1, div2] = fixture.nativeElement.querySelectorAll('div') as HTMLDivElement[];
+ const divs = fixture.nativeElement.querySelectorAll('div') as HTMLDivElement[];
+
+ // TODO: Use destructuring once Domino supports native ES2015, or when jsdom is used.
+ const div1 = divs[0];
+ const div2 = divs[1];
expect(div1.className).toBe('');
expect(div2.className).toBe('');