test: make NgMatchers type-aware (#19904)

PR Close #19904
This commit is contained in:
George Kalpakas
2018-07-05 15:24:53 +03:00
committed by Miško Hevery
parent 00c110b055
commit 809e8f742e
9 changed files with 39 additions and 59 deletions

View File

@ -217,7 +217,7 @@ function factoryFn(a: any){}
const injector = Injector.create([CarWithOptionalEngine.PROVIDER]); const injector = Injector.create([CarWithOptionalEngine.PROVIDER]);
const car = injector.get<CarWithOptionalEngine>(CarWithOptionalEngine); const car = injector.get<CarWithOptionalEngine>(CarWithOptionalEngine);
expect(car.engine).toEqual(null); expect(car.engine).toBeNull();
}); });
it('should flatten passed-in providers', () => { it('should flatten passed-in providers', () => {
@ -288,8 +288,8 @@ function factoryFn(a: any){}
Injector.create([CarWithDashboard.PROVIDER, Engine.PROVIDER, Dashboard.PROVIDER]); Injector.create([CarWithDashboard.PROVIDER, Engine.PROVIDER, Dashboard.PROVIDER]);
expect(() => injector.get(CarWithDashboard)) expect(() => injector.get(CarWithDashboard))
.toThrowError( .toThrowError(
`StaticInjectorError[${stringify(CarWithDashboard)} -> ${stringify(Dashboard)} -> DashboardSoftware]: `StaticInjectorError[${stringify(CarWithDashboard)} -> ${stringify(Dashboard)} -> DashboardSoftware]: \n` +
NullInjectorError: No provider for DashboardSoftware!`); ' NullInjectorError: No provider for DashboardSoftware!');
}); });
it('should throw when trying to instantiate a cyclic dependency', () => { it('should throw when trying to instantiate a cyclic dependency', () => {
@ -415,8 +415,9 @@ function factoryFn(a: any){}
parent); parent);
expect(() => child.get(Car)) expect(() => child.get(Car))
.toThrowError(`StaticInjectorError[${stringify(Car)} -> ${stringify(Engine)}]: .toThrowError(
NullInjectorError: No provider for Engine!`); `StaticInjectorError[${stringify(Car)} -> ${stringify(Engine)}]: \n` +
' NullInjectorError: No provider for Engine!');
}); });
}); });

View File

@ -343,7 +343,7 @@ function declareTests({useJit}: {useJit: boolean}) {
const fixture = TestBed.createComponent(MyComp); const fixture = TestBed.createComponent(MyComp);
const tc = fixture.debugElement.children[0]; const tc = fixture.debugElement.children[0];
expect(tc.injector.get(EventDir)).not.toBe(null); expect(tc.injector.get(EventDir)).not.toBeNull();
}); });
it('should read directives metadata from their binding token', () => { it('should read directives metadata from their binding token', () => {
@ -1237,7 +1237,7 @@ function declareTests({useJit}: {useJit: boolean}) {
const needsAttribute = tc.injector.get(NeedsAttribute); const needsAttribute = tc.injector.get(NeedsAttribute);
expect(needsAttribute.typeAttribute).toEqual('text'); expect(needsAttribute.typeAttribute).toEqual('text');
expect(needsAttribute.staticAttribute).toEqual(''); expect(needsAttribute.staticAttribute).toEqual('');
expect(needsAttribute.fooAttribute).toEqual(null); expect(needsAttribute.fooAttribute).toBeNull();
}); });
it('should support custom interpolation', () => { it('should support custom interpolation', () => {

View File

@ -33,37 +33,27 @@ class TurboEngine extends Engine {}
const CARS = new InjectionToken<Car[]>('Cars'); const CARS = new InjectionToken<Car[]>('Cars');
@Injectable() @Injectable()
class Car { class Car {
engine: Engine; constructor(public engine: Engine) {}
constructor(engine: Engine) { this.engine = engine; }
} }
@Injectable() @Injectable()
class CarWithOptionalEngine { class CarWithOptionalEngine {
engine: Engine; constructor(@Optional() public engine: Engine) {}
constructor(@Optional() engine: Engine) { this.engine = engine; }
} }
@Injectable() @Injectable()
class CarWithDashboard { class CarWithDashboard {
engine: Engine; constructor(public engine: Engine, public dashboard: Dashboard) {}
dashboard: Dashboard;
constructor(engine: Engine, dashboard: Dashboard) {
this.engine = engine;
this.dashboard = dashboard;
}
} }
@Injectable() @Injectable()
class SportsCar extends Car { class SportsCar extends Car {
// TODO(issue/24571): remove '!'.
engine !: Engine;
constructor(engine: Engine) { super(engine); } constructor(engine: Engine) { super(engine); }
} }
@Injectable() @Injectable()
class CarWithInject { class CarWithInject {
engine: Engine; constructor(@Inject(TurboEngine) public engine: Engine) {}
constructor(@Inject(TurboEngine) engine: Engine) { this.engine = engine; }
} }
@Injectable() @Injectable()
@ -747,7 +737,7 @@ function declareTests({useJit}: {useJit: boolean}) {
const injector = createInjector([CarWithOptionalEngine]); const injector = createInjector([CarWithOptionalEngine]);
const car = injector.get(CarWithOptionalEngine); const car = injector.get(CarWithOptionalEngine);
expect(car.engine).toEqual(null); expect(car.engine).toBeNull();
}); });
it('should flatten passed-in providers', () => { it('should flatten passed-in providers', () => {

View File

@ -659,7 +659,7 @@ class TestComp {
TestBed.configureTestingModule({declarations: [OptionallyNeedsDirective]}); TestBed.configureTestingModule({declarations: [OptionallyNeedsDirective]});
const el = createComponent('<div optionallyNeedsDirective></div>'); const el = createComponent('<div optionallyNeedsDirective></div>');
const d = el.children[0].injector.get(OptionallyNeedsDirective); const d = el.children[0].injector.get(OptionallyNeedsDirective);
expect(d.dependency).toEqual(null); expect(d.dependency).toBeNull();
}); });
it('should instantiate directives that depends on the host component', () => { it('should instantiate directives that depends on the host component', () => {

View File

@ -115,12 +115,8 @@ class MockBrowserJsonp extends BrowserJsonp {
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp()); const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp());
connection.response.subscribe( connection.response.subscribe(
(res: Response) => { () => async.fail('Response listener should not be called'), (err: Response) => {
expect('response listener called').toBe(false); expect(err.text()).toBe('JSONP injected script did not invoke callback.');
async.done();
},
(err: Response) => {
expect(err.text()).toEqual('JSONP injected script did not invoke callback.');
async.done(); async.done();
}); });
@ -132,11 +128,7 @@ class MockBrowserJsonp extends BrowserJsonp {
const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp()); const connection = new (JSONPConnection as any)(sampleRequest, new MockBrowserJsonp());
connection.response.subscribe( connection.response.subscribe(
(res: Response) => { () => async.fail('Response listener should not be called'), (err: Response) => {
expect('response listener called').toBe(false);
async.done();
},
(err: Response) => {
expect(err.text()).toBe('Oops!'); expect(err.text()).toBe('Oops!');
async.done(); async.done();
}); });

View File

@ -212,9 +212,10 @@ function bootstrap(
bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [ bootstrap(RootCmp, [{provide: ErrorHandler, useValue: errorHandler}], [], [
CustomModule CustomModule
]).then(null, (e: Error) => { ]).then(null, (e: Error) => {
expect(e.message).toContain(`StaticInjectorError(TestModule)[CustomCmp -> IDontExist]: expect(e.message).toContain(
StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]: 'StaticInjectorError(TestModule)[CustomCmp -> IDontExist]: \n' +
NullInjectorError: No provider for IDontExist!`); ' StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]: \n' +
' NullInjectorError: No provider for IDontExist!');
async.done(); async.done();
return null; return null;
}); });
@ -255,7 +256,7 @@ function bootstrap(
it('should create an injector promise', () => { it('should create an injector promise', () => {
const refPromise = bootstrap(HelloRootCmp, testProviders); const refPromise = bootstrap(HelloRootCmp, testProviders);
expect(refPromise).not.toBe(null); expect(refPromise).toEqual(jasmine.any(Promise));
}); });
it('should set platform name to browser', it('should set platform name to browser',

View File

@ -15,7 +15,7 @@ import {ɵgetDOM as getDOM} from '@angular/platform-browser';
/** /**
* Jasmine matchers that check Angular specific conditions. * Jasmine matchers that check Angular specific conditions.
*/ */
export interface NgMatchers extends jasmine.Matchers<any> { export interface NgMatchers<T = any> extends jasmine.Matchers<T> {
/** /**
* Expect the value to be a `Promise`. * Expect the value to be a `Promise`.
* *
@ -82,7 +82,7 @@ export interface NgMatchers extends jasmine.Matchers<any> {
/** /**
* Invert the matchers. * Invert the matchers.
*/ */
not: NgMatchers; not: NgMatchers<T>;
} }
const _global = <any>(typeof window === 'undefined' ? global : window); const _global = <any>(typeof window === 'undefined' ? global : window);
@ -94,7 +94,7 @@ const _global = <any>(typeof window === 'undefined' ? global : window);
* *
* {@example testing/ts/matchers.ts region='toHaveText'} * {@example testing/ts/matchers.ts region='toHaveText'}
*/ */
export const expect: (actual: any) => NgMatchers = <any>_global.expect; export const expect: <T = any>(actual: T) => NgMatchers<T> = _global.expect;
// Some Map polyfills don't polyfill Map.toString correctly, which // Some Map polyfills don't polyfill Map.toString correctly, which

View File

@ -98,7 +98,7 @@ let lastCreatedRenderer: Renderer2;
.createComponent(MyComp2); .createComponent(MyComp2);
const checkSetters = (componentRef: ComponentRef<any>, workerEl: any) => { const checkSetters = (componentRef: ComponentRef<any>, workerEl: any) => {
expect(lastCreatedRenderer).not.toEqual(null); expect(lastCreatedRenderer).not.toBeNull();
const el = getRenderElement(workerEl); const el = getRenderElement(workerEl);
lastCreatedRenderer.setProperty(workerEl, 'tabIndex', 1); lastCreatedRenderer.setProperty(workerEl, 'tabIndex', 1);

View File

@ -187,8 +187,6 @@ describe('Integration', () => {
}); });
describe('should advance the parent route after deactivating its children', () => { describe('should advance the parent route after deactivating its children', () => {
let log: string[] = [];
@Component({template: '<router-outlet></router-outlet>'}) @Component({template: '<router-outlet></router-outlet>'})
class Parent { class Parent {
constructor(route: ActivatedRoute) { constructor(route: ActivatedRoute) {
@ -214,10 +212,7 @@ describe('Integration', () => {
class TestModule { class TestModule {
} }
beforeEach(() => { beforeEach(() => TestBed.configureTestingModule({imports: [TestModule]}));
log = [];
TestBed.configureTestingModule({imports: [TestModule]});
});
it('should work', it('should work',
fakeAsync(inject([Router, Location], (router: Router, location: Location) => { fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
@ -874,8 +869,8 @@ describe('Integration', () => {
}))); })));
it('should dispatch NavigationError after the url has been reset back', fakeAsync(() => { it('should dispatch NavigationError after the url has been reset back', fakeAsync(() => {
const router = TestBed.get(Router); const router: Router = TestBed.get(Router);
const location = TestBed.get(Location); const location: SpyLocation = TestBed.get(Location);
const fixture = createRoot(router, RootCmp); const fixture = createRoot(router, RootCmp);
router.resetConfig( router.resetConfig(
@ -884,9 +879,9 @@ describe('Integration', () => {
router.navigateByUrl('/simple'); router.navigateByUrl('/simple');
advance(fixture); advance(fixture);
let routerUrlBeforeEmittingError; let routerUrlBeforeEmittingError = '';
let locationUrlBeforeEmittingError; let locationUrlBeforeEmittingError = '';
router.events.forEach((e: any) => { router.events.forEach(e => {
if (e instanceof NavigationError) { if (e instanceof NavigationError) {
routerUrlBeforeEmittingError = router.url; routerUrlBeforeEmittingError = router.url;
locationUrlBeforeEmittingError = location.path(); locationUrlBeforeEmittingError = location.path();
@ -965,8 +960,8 @@ describe('Integration', () => {
TestBed.configureTestingModule( TestBed.configureTestingModule(
{providers: [{provide: 'returnsFalse', useValue: () => false}]}); {providers: [{provide: 'returnsFalse', useValue: () => false}]});
const router = TestBed.get(Router); const router: Router = TestBed.get(Router);
const location = TestBed.get(Location); const location: SpyLocation = TestBed.get(Location);
const fixture = createRoot(router, RootCmp); const fixture = createRoot(router, RootCmp);
@ -978,18 +973,19 @@ describe('Integration', () => {
router.navigateByUrl('/simple'); router.navigateByUrl('/simple');
advance(fixture); advance(fixture);
let routerUrlBeforeEmittingError; let routerUrlBeforeEmittingError = '';
let locationUrlBeforeEmittingError; let locationUrlBeforeEmittingError = '';
router.events.forEach((e: any) => { router.events.forEach(e => {
if (e instanceof NavigationCancel) { if (e instanceof NavigationCancel) {
routerUrlBeforeEmittingError = router.url; routerUrlBeforeEmittingError = router.url;
locationUrlBeforeEmittingError = location.path(); locationUrlBeforeEmittingError = location.path();
} }
}); });
(<any>location).simulateHashChange('/throwing'); location.simulateHashChange('/throwing');
advance(fixture); advance(fixture);
expect(routerUrlBeforeEmittingError).toEqual('/simple');
expect(locationUrlBeforeEmittingError).toEqual('/simple'); expect(locationUrlBeforeEmittingError).toEqual('/simple');
})); }));