Make sure that context (`this`) that is passed to functions generated by test helpers is passed through to the callback functions. Enables usage of Jasmine's variable sharing system to prevent accidental memory leaks during test runs.
643 lines
23 KiB
TypeScript
643 lines
23 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. 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 {CompilerConfig, ResourceLoader} from '@angular/compiler';
|
|
import {CUSTOM_ELEMENTS_SCHEMA, Component, Directive, Injectable, Input, NgModule, Pipe} from '@angular/core';
|
|
import {TestBed, async, fakeAsync, getTestBed, inject, tick, withModule} from '@angular/core/testing';
|
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
|
|
|
import {stringify} from '../src/facade/lang';
|
|
|
|
// Services, and components for the tests.
|
|
|
|
@Component({selector: 'child-comp', template: `<span>Original {{childBinding}}</span>`})
|
|
@Injectable()
|
|
class ChildComp {
|
|
childBinding: string;
|
|
constructor() { this.childBinding = 'Child'; }
|
|
}
|
|
|
|
@Component({selector: 'child-comp', template: `<span>Mock</span>`})
|
|
@Injectable()
|
|
class MockChildComp {
|
|
}
|
|
|
|
@Component({
|
|
selector: 'parent-comp',
|
|
template: `Parent(<child-comp></child-comp>)`,
|
|
})
|
|
@Injectable()
|
|
class ParentComp {
|
|
}
|
|
|
|
@Component({selector: 'my-if-comp', template: `MyIf(<span *ngIf="showMore">More</span>)`})
|
|
@Injectable()
|
|
class MyIfComp {
|
|
showMore: boolean = false;
|
|
}
|
|
|
|
@Component({selector: 'child-child-comp', template: `<span>ChildChild</span>`})
|
|
@Injectable()
|
|
class ChildChildComp {
|
|
}
|
|
|
|
@Component({
|
|
selector: 'child-comp',
|
|
template: `<span>Original {{childBinding}}(<child-child-comp></child-child-comp>)</span>`,
|
|
})
|
|
@Injectable()
|
|
class ChildWithChildComp {
|
|
childBinding: string;
|
|
constructor() { this.childBinding = 'Child'; }
|
|
}
|
|
|
|
class FancyService {
|
|
value: string = 'real value';
|
|
getAsyncValue() { return Promise.resolve('async value'); }
|
|
getTimeoutValue() {
|
|
return new Promise<string>((resolve, reject) => setTimeout(() => resolve('timeout value'), 10));
|
|
}
|
|
}
|
|
|
|
class MockFancyService extends FancyService {
|
|
value: string = 'mocked out value';
|
|
}
|
|
|
|
@Component({
|
|
selector: 'my-service-comp',
|
|
providers: [FancyService],
|
|
template: `injected value: {{fancyService.value}}`
|
|
})
|
|
class TestProvidersComp {
|
|
constructor(private fancyService: FancyService) {}
|
|
}
|
|
|
|
@Component({
|
|
selector: 'my-service-comp',
|
|
viewProviders: [FancyService],
|
|
template: `injected value: {{fancyService.value}}`
|
|
})
|
|
class TestViewProvidersComp {
|
|
constructor(private fancyService: FancyService) {}
|
|
}
|
|
|
|
@Directive({selector: '[someDir]', host: {'[title]': 'someDir'}})
|
|
class SomeDirective {
|
|
@Input()
|
|
someDir: string;
|
|
}
|
|
|
|
@Pipe({name: 'somePipe'})
|
|
class SomePipe {
|
|
transform(value: string) { return `transformed ${value}`; }
|
|
}
|
|
|
|
@Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`})
|
|
class CompUsingModuleDirectiveAndPipe {
|
|
}
|
|
|
|
@NgModule()
|
|
class SomeLibModule {
|
|
}
|
|
|
|
@Component({
|
|
selector: 'comp',
|
|
templateUrl: '/base/modules/@angular/platform-browser/test/static_assets/test.html'
|
|
})
|
|
class CompWithUrlTemplate {
|
|
}
|
|
|
|
export function main() {
|
|
describe('public testing API', () => {
|
|
describe('using the async helper with context passing', () => {
|
|
beforeEach(function() { this.actuallyDone = false; });
|
|
|
|
afterEach(function() { expect(this.actuallyDone).toEqual(true); });
|
|
|
|
it('should run normal tests', function() { this.actuallyDone = true; });
|
|
|
|
it('should run normal async tests', function(done) {
|
|
setTimeout(() => {
|
|
this.actuallyDone = true;
|
|
done();
|
|
}, 0);
|
|
});
|
|
|
|
it('should run async tests with tasks',
|
|
async(function() { setTimeout(() => this.actuallyDone = true, 0); }));
|
|
|
|
it('should run async tests with promises', async(function() {
|
|
const p = new Promise((resolve, reject) => setTimeout(resolve, 10));
|
|
p.then(() => this.actuallyDone = true);
|
|
}));
|
|
});
|
|
|
|
describe('basic context passing to inject, fakeAsync and withModule helpers', () => {
|
|
const moduleConfig = {
|
|
providers: [FancyService],
|
|
};
|
|
|
|
beforeEach(function() { this.contextModified = false; });
|
|
|
|
afterEach(function() { expect(this.contextModified).toEqual(true); });
|
|
|
|
it('should pass context to inject helper',
|
|
inject([], function() { this.contextModified = true; }));
|
|
|
|
it('should pass context to fakeAsync helper',
|
|
fakeAsync(function() { this.contextModified = true; }));
|
|
|
|
it('should pass context to withModule helper - simple',
|
|
withModule(moduleConfig, function() { this.contextModified = true; }));
|
|
|
|
it('should pass context to withModule helper - advanced',
|
|
withModule(moduleConfig).inject([FancyService], function(service: FancyService) {
|
|
expect(service.value).toBe('real value');
|
|
this.contextModified = true;
|
|
}));
|
|
|
|
it('should preserve context when async and inject helpers are combined',
|
|
async(inject([], function() { setTimeout(() => this.contextModified = true, 0); })));
|
|
|
|
it('should preserve context when fakeAsync and inject helpers are combined',
|
|
fakeAsync(inject([], function() {
|
|
setTimeout(() => this.contextModified = true, 0);
|
|
tick(1);
|
|
})));
|
|
});
|
|
|
|
describe('using the test injector with the inject helper', () => {
|
|
describe('setting up Providers', () => {
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule(
|
|
{providers: [{provide: FancyService, useValue: new FancyService()}]});
|
|
|
|
it('should use set up providers', inject([FancyService], (service: FancyService) => {
|
|
expect(service.value).toEqual('real value');
|
|
}));
|
|
|
|
it('should wait until returned promises',
|
|
async(inject([FancyService], (service: FancyService) => {
|
|
service.getAsyncValue().then((value) => expect(value).toEqual('async value'));
|
|
service.getTimeoutValue().then((value) => expect(value).toEqual('timeout value'));
|
|
})));
|
|
|
|
it('should allow the use of fakeAsync',
|
|
fakeAsync(inject([FancyService], (service: FancyService) => {
|
|
let value: string;
|
|
service.getAsyncValue().then((val) => value = val);
|
|
tick();
|
|
expect(value).toEqual('async value');
|
|
})));
|
|
|
|
it('should allow use of "done"', (done) => {
|
|
inject([FancyService], (service: FancyService) => {
|
|
let count = 0;
|
|
const id = setInterval(() => {
|
|
count++;
|
|
if (count > 2) {
|
|
clearInterval(id);
|
|
done();
|
|
}
|
|
}, 5);
|
|
})(); // inject needs to be invoked explicitly with ().
|
|
});
|
|
|
|
describe('using beforeEach', () => {
|
|
beforeEach(inject([FancyService], (service: FancyService) => {
|
|
service.value = 'value modified in beforeEach';
|
|
}));
|
|
|
|
it('should use modified providers', inject([FancyService], (service: FancyService) => {
|
|
expect(service.value).toEqual('value modified in beforeEach');
|
|
}));
|
|
});
|
|
|
|
describe('using async beforeEach', () => {
|
|
beforeEach(async(inject([FancyService], (service: FancyService) => {
|
|
service.getAsyncValue().then((value) => service.value = value);
|
|
})));
|
|
|
|
it('should use asynchronously modified value',
|
|
inject([FancyService], (service: FancyService) => {
|
|
expect(service.value).toEqual('async value');
|
|
}));
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('using the test injector with modules', () => {
|
|
const moduleConfig = {
|
|
providers: [FancyService],
|
|
imports: [SomeLibModule],
|
|
declarations: [SomeDirective, SomePipe, CompUsingModuleDirectiveAndPipe],
|
|
};
|
|
|
|
describe('setting up a module', () => {
|
|
beforeEach(() => TestBed.configureTestingModule(moduleConfig));
|
|
|
|
it('should use set up providers', inject([FancyService], (service: FancyService) => {
|
|
expect(service.value).toEqual('real value');
|
|
}));
|
|
|
|
it('should be able to create any declared components', () => {
|
|
const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe);
|
|
expect(compFixture.componentInstance).toBeAnInstanceOf(CompUsingModuleDirectiveAndPipe);
|
|
});
|
|
|
|
it('should use set up directives and pipes', () => {
|
|
const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe);
|
|
const el = compFixture.debugElement;
|
|
|
|
compFixture.detectChanges();
|
|
expect(el.children[0].properties['title']).toBe('transformed someValue');
|
|
});
|
|
|
|
it('should use set up imported modules',
|
|
inject([SomeLibModule], (libModule: SomeLibModule) => {
|
|
expect(libModule).toBeAnInstanceOf(SomeLibModule);
|
|
}));
|
|
|
|
describe('provided schemas', () => {
|
|
@Component({template: '<some-element [someUnknownProp]="true"></some-element>'})
|
|
class ComponentUsingInvalidProperty {
|
|
}
|
|
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule(
|
|
{schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: [ComponentUsingInvalidProperty]});
|
|
});
|
|
|
|
it('should not error on unknown bound properties on custom elements when using the CUSTOM_ELEMENTS_SCHEMA',
|
|
() => {
|
|
expect(TestBed.createComponent(ComponentUsingInvalidProperty).componentInstance)
|
|
.toBeAnInstanceOf(ComponentUsingInvalidProperty);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('per test modules', () => {
|
|
it('should use set up providers',
|
|
withModule(moduleConfig).inject([FancyService], (service: FancyService) => {
|
|
expect(service.value).toEqual('real value');
|
|
}));
|
|
|
|
it('should use set up directives and pipes', withModule(moduleConfig, () => {
|
|
const compFixture = TestBed.createComponent(CompUsingModuleDirectiveAndPipe);
|
|
const el = compFixture.debugElement;
|
|
|
|
compFixture.detectChanges();
|
|
expect(el.children[0].properties['title']).toBe('transformed someValue');
|
|
}));
|
|
|
|
it('should use set up library modules',
|
|
withModule(moduleConfig).inject([SomeLibModule], (libModule: SomeLibModule) => {
|
|
expect(libModule).toBeAnInstanceOf(SomeLibModule);
|
|
}));
|
|
});
|
|
|
|
describe('components with template url', () => {
|
|
beforeEach(async(() => {
|
|
TestBed.configureTestingModule({declarations: [CompWithUrlTemplate]});
|
|
TestBed.compileComponents();
|
|
}));
|
|
|
|
it('should allow to createSync components with templateUrl after explicit async compilation',
|
|
() => {
|
|
const fixture = TestBed.createComponent(CompWithUrlTemplate);
|
|
expect(fixture.nativeElement).toHaveText('from external template\n');
|
|
});
|
|
});
|
|
|
|
describe('overwriting metadata', () => {
|
|
@Pipe({name: 'undefined'})
|
|
class SomePipe {
|
|
transform(value: string): string { return `transformed ${value}`; }
|
|
}
|
|
|
|
@Directive({selector: '[undefined]'})
|
|
class SomeDirective {
|
|
someProp = 'hello';
|
|
}
|
|
|
|
@Component({selector: 'comp', template: 'someText'})
|
|
class SomeComponent {
|
|
}
|
|
|
|
@Component({selector: 'comp', template: 'someOtherText'})
|
|
class SomeOtherComponent {
|
|
}
|
|
|
|
@NgModule({declarations: [SomeComponent, SomeDirective, SomePipe]})
|
|
class SomeModule {
|
|
}
|
|
|
|
beforeEach(() => TestBed.configureTestingModule({imports: [SomeModule]}));
|
|
|
|
describe('module', () => {
|
|
beforeEach(() => {
|
|
TestBed.overrideModule(SomeModule, {set: {declarations: [SomeOtherComponent]}});
|
|
});
|
|
it('should work', () => {
|
|
expect(TestBed.createComponent(SomeOtherComponent).componentInstance)
|
|
.toBeAnInstanceOf(SomeOtherComponent);
|
|
});
|
|
});
|
|
|
|
describe('component', () => {
|
|
beforeEach(() => {
|
|
TestBed.overrideComponent(
|
|
SomeComponent, {set: {selector: 'comp', template: 'newText'}});
|
|
});
|
|
it('should work', () => {
|
|
expect(TestBed.createComponent(SomeComponent).nativeElement).toHaveText('newText');
|
|
});
|
|
});
|
|
|
|
describe('directive', () => {
|
|
beforeEach(() => {
|
|
TestBed
|
|
.overrideComponent(
|
|
SomeComponent, {set: {selector: 'comp', template: `<div someDir></div>`}})
|
|
.overrideDirective(
|
|
SomeDirective, {set: {selector: '[someDir]', host: {'[title]': 'someProp'}}});
|
|
});
|
|
it('should work', () => {
|
|
const compFixture = TestBed.createComponent(SomeComponent);
|
|
compFixture.detectChanges();
|
|
expect(compFixture.debugElement.children[0].properties['title']).toEqual('hello');
|
|
});
|
|
});
|
|
|
|
describe('pipe', () => {
|
|
beforeEach(() => {
|
|
TestBed
|
|
.overrideComponent(
|
|
SomeComponent, {set: {selector: 'comp', template: `{{'hello' | somePipe}}`}})
|
|
.overridePipe(SomePipe, {set: {name: 'somePipe'}});
|
|
});
|
|
it('should work', () => {
|
|
const compFixture = TestBed.createComponent(SomeComponent);
|
|
compFixture.detectChanges();
|
|
expect(compFixture.nativeElement).toHaveText('transformed hello');
|
|
});
|
|
});
|
|
|
|
describe('template', () => {
|
|
let testBedSpy: any;
|
|
beforeEach(() => {
|
|
testBedSpy = spyOn(getTestBed(), 'overrideComponent').and.callThrough();
|
|
TestBed.overrideTemplate(SomeComponent, 'newText');
|
|
});
|
|
it(`should override component's template`, () => {
|
|
const fixture = TestBed.createComponent(SomeComponent);
|
|
expect(fixture.nativeElement).toHaveText('newText');
|
|
expect(testBedSpy).toHaveBeenCalledWith(SomeComponent, {
|
|
set: {template: 'newText', templateUrl: null}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('setting up the compiler', () => {
|
|
|
|
describe('providers', () => {
|
|
beforeEach(() => {
|
|
const resourceLoaderGet = jasmine.createSpy('resourceLoaderGet')
|
|
.and.returnValue(Promise.resolve('Hello world!'));
|
|
TestBed.configureTestingModule({declarations: [CompWithUrlTemplate]});
|
|
TestBed.configureCompiler(
|
|
{providers: [{provide: ResourceLoader, useValue: {get: resourceLoaderGet}}]});
|
|
});
|
|
|
|
it('should use set up providers', fakeAsync(() => {
|
|
TestBed.compileComponents();
|
|
tick();
|
|
const compFixture = TestBed.createComponent(CompWithUrlTemplate);
|
|
expect(compFixture.nativeElement).toHaveText('Hello world!');
|
|
}));
|
|
});
|
|
|
|
describe('useJit true', () => {
|
|
beforeEach(() => TestBed.configureCompiler({useJit: true}));
|
|
it('should set the value into CompilerConfig',
|
|
inject([CompilerConfig], (config: CompilerConfig) => {
|
|
expect(config.useJit).toBe(true);
|
|
}));
|
|
});
|
|
describe('useJit false', () => {
|
|
beforeEach(() => TestBed.configureCompiler({useJit: false}));
|
|
it('should set the value into CompilerConfig',
|
|
inject([CompilerConfig], (config: CompilerConfig) => {
|
|
expect(config.useJit).toBe(false);
|
|
}));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('errors', () => {
|
|
let originalJasmineIt: (description: string, func: () => void) => jasmine.Spec;
|
|
let originalJasmineBeforeEach: (beforeEachFunction: () => void) => void;
|
|
|
|
const patchJasmineIt = () => {
|
|
let resolve: (result: any) => void;
|
|
let reject: (error: any) => void;
|
|
const promise = new Promise((res, rej) => {
|
|
resolve = res;
|
|
reject = rej;
|
|
});
|
|
originalJasmineIt = jasmine.getEnv().it;
|
|
jasmine.getEnv().it = (description: string, fn: (done: DoneFn) => void) => {
|
|
const done = <DoneFn>(() => resolve(null));
|
|
done.fail = (err) => reject(err);
|
|
fn(done);
|
|
return null;
|
|
};
|
|
return promise;
|
|
};
|
|
|
|
const restoreJasmineIt = () => jasmine.getEnv().it = originalJasmineIt;
|
|
|
|
const patchJasmineBeforeEach = () => {
|
|
let resolve: (result: any) => void;
|
|
let reject: (error: any) => void;
|
|
const promise = new Promise((res, rej) => {
|
|
resolve = res;
|
|
reject = rej;
|
|
});
|
|
originalJasmineBeforeEach = jasmine.getEnv().beforeEach;
|
|
jasmine.getEnv().beforeEach = (fn: (done: DoneFn) => void) => {
|
|
const done = <DoneFn>(() => resolve(null));
|
|
done.fail = (err) => reject(err);
|
|
fn(done);
|
|
};
|
|
return promise;
|
|
};
|
|
|
|
const restoreJasmineBeforeEach = () => jasmine.getEnv().beforeEach =
|
|
originalJasmineBeforeEach;
|
|
|
|
it('should fail when an asynchronous error is thrown', (done) => {
|
|
const itPromise = patchJasmineIt();
|
|
const barError = new Error('bar');
|
|
|
|
it('throws an async error',
|
|
async(inject([], () => setTimeout(() => { throw barError; }, 0))));
|
|
|
|
itPromise.then(() => done.fail('Expected test to fail, but it did not'), (err) => {
|
|
expect(err).toEqual(barError);
|
|
done();
|
|
});
|
|
restoreJasmineIt();
|
|
});
|
|
|
|
it('should fail when a returned promise is rejected', (done) => {
|
|
const itPromise = patchJasmineIt();
|
|
|
|
it('should fail with an error from a promise', async(inject([], () => {
|
|
let reject: (error: any) => void;
|
|
const promise = new Promise((_, rej) => reject = rej);
|
|
const p = promise.then(() => expect(1).toEqual(2));
|
|
|
|
reject('baz');
|
|
return p;
|
|
})));
|
|
|
|
itPromise.then(() => done.fail('Expected test to fail, but it did not'), (err) => {
|
|
expect(err.message).toEqual('Uncaught (in promise): baz');
|
|
done();
|
|
});
|
|
restoreJasmineIt();
|
|
});
|
|
|
|
describe('components', () => {
|
|
let resourceLoaderGet: jasmine.Spy;
|
|
beforeEach(() => {
|
|
resourceLoaderGet = jasmine.createSpy('resourceLoaderGet')
|
|
.and.returnValue(Promise.resolve('Hello world!'));
|
|
TestBed.configureCompiler(
|
|
{providers: [{provide: ResourceLoader, useValue: {get: resourceLoaderGet}}]});
|
|
});
|
|
|
|
it('should report an error for declared components with templateUrl which never call TestBed.compileComponents',
|
|
() => {
|
|
const itPromise = patchJasmineIt();
|
|
|
|
expect(
|
|
() =>
|
|
it('should fail', withModule(
|
|
{declarations: [CompWithUrlTemplate]},
|
|
() => TestBed.createComponent(CompWithUrlTemplate))))
|
|
.toThrowError(
|
|
`This test module uses the component ${stringify(CompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` +
|
|
`Please call "TestBed.compileComponents" before your test.`);
|
|
|
|
restoreJasmineIt();
|
|
});
|
|
|
|
});
|
|
|
|
it('should error on unknown bound properties on custom elements by default', () => {
|
|
@Component({template: '<some-element [someUnknownProp]="true"></some-element>'})
|
|
class ComponentUsingInvalidProperty {
|
|
}
|
|
|
|
const itPromise = patchJasmineIt();
|
|
|
|
expect(
|
|
() => it(
|
|
'should fail', withModule(
|
|
{declarations: [ComponentUsingInvalidProperty]},
|
|
() => TestBed.createComponent(ComponentUsingInvalidProperty))))
|
|
.toThrowError(/Can't bind to 'someUnknownProp'/);
|
|
|
|
restoreJasmineIt();
|
|
});
|
|
});
|
|
|
|
describe('creating components', () => {
|
|
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule({
|
|
declarations: [
|
|
ChildComp,
|
|
MyIfComp,
|
|
ChildChildComp,
|
|
ParentComp,
|
|
TestProvidersComp,
|
|
TestViewProvidersComp,
|
|
]
|
|
});
|
|
});
|
|
|
|
it('should instantiate a component with valid DOM', async(() => {
|
|
const fixture = TestBed.createComponent(ChildComp);
|
|
fixture.detectChanges();
|
|
|
|
expect(fixture.nativeElement).toHaveText('Original Child');
|
|
}));
|
|
|
|
it('should allow changing members of the component', async(() => {
|
|
const componentFixture = TestBed.createComponent(MyIfComp);
|
|
componentFixture.detectChanges();
|
|
expect(componentFixture.nativeElement).toHaveText('MyIf()');
|
|
|
|
componentFixture.componentInstance.showMore = true;
|
|
componentFixture.detectChanges();
|
|
expect(componentFixture.nativeElement).toHaveText('MyIf(More)');
|
|
}));
|
|
|
|
it('should override a template', async(() => {
|
|
TestBed.overrideComponent(ChildComp, {set: {template: '<span>Mock</span>'}});
|
|
const componentFixture = TestBed.createComponent(ChildComp);
|
|
componentFixture.detectChanges();
|
|
expect(componentFixture.nativeElement).toHaveText('Mock');
|
|
|
|
}));
|
|
|
|
it('should override a provider', async(() => {
|
|
TestBed.overrideComponent(
|
|
TestProvidersComp,
|
|
{set: {providers: [{provide: FancyService, useClass: MockFancyService}]}});
|
|
const componentFixture = TestBed.createComponent(TestProvidersComp);
|
|
componentFixture.detectChanges();
|
|
expect(componentFixture.nativeElement).toHaveText('injected value: mocked out value');
|
|
}));
|
|
|
|
|
|
it('should override a viewProvider', async(() => {
|
|
TestBed.overrideComponent(
|
|
TestViewProvidersComp,
|
|
{set: {viewProviders: [{provide: FancyService, useClass: MockFancyService}]}});
|
|
|
|
const componentFixture = TestBed.createComponent(TestViewProvidersComp);
|
|
componentFixture.detectChanges();
|
|
expect(componentFixture.nativeElement).toHaveText('injected value: mocked out value');
|
|
}));
|
|
});
|
|
describe('using alternate components', () => {
|
|
beforeEach(() => {
|
|
TestBed.configureTestingModule({
|
|
declarations: [
|
|
MockChildComp,
|
|
ParentComp,
|
|
]
|
|
});
|
|
});
|
|
|
|
it('should override component dependencies', async(() => {
|
|
|
|
const componentFixture = TestBed.createComponent(ParentComp);
|
|
componentFixture.detectChanges();
|
|
expect(componentFixture.nativeElement).toHaveText('Parent(Mock)');
|
|
}));
|
|
});
|
|
});
|
|
}
|