?????????????Angular????????????????????????磺Component??Directive??Pipe ???Service?????????????????????????????????????????????????????????????????????????Щ?????????????????????磺Router??
???????????????????????????е? ????? ?????????????????Angular???????????Щ????????
?????????????????????????????1???
??????С????????????????????????
??????С??????????????????????
??????????????????????? TestComponent ??
???????beforeEach
?????? beforeEach ??????????????Angular??????????棬???????÷?????????????е???ж??????????????
????beforeEach ?????????????????????Щ??????????????
?????????????д???Angular????????????????????????????飬??????? TestBed.configureTestingModule ????????Angular?????????????????????????? NgModule???????????????????? NgModule ?????κβ???
beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [HttpModule]??
        declarations: [TestComponent]
    });
});
????????????κζ??????в????????????????????磺Http?????????? imports: [HttpModule] ??????ж??? NgModule д???????á?
????????????????????????????????????????????????????????????????ЩHTML????????????磺???????????????????????????????????????????????????????????????????????????????в????
?????????????????? Pipe ???????κ?HTML????????????????????????????????????
????1???????
??????ν????壬??????????????????????????????κ? HTML ?????????????????????????????????????????????????????????????????????DI???????????????????????????????????????????????????Service????????
let directive: LogDirective;
beforeEach(() => TestBed.configureTestingModule({
    providers: [ LogDirective ]
}));

beforeEach(inject([ LogDirective ]?? c => {
    directive = c;
}));
???????????????????????????????? inject ??????? LogDirective ???????????????????????????????
????2???????
????????????????????????????????????????????????????????????????????????????
@Component({
    template: `<trade-view [id]="id" (close)="_close()"></trade-view>`
})
class TestComponent {
    id: number = 0;
    _close() { }
}

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [HttpModule]??
        declarations: [TestComponent]
    });
    fixture = TestBed.createComponent(TestComponent);
    context = fixture.componentInstance;
    el = fixture.nativeElement;
    dl = fixture.debugElement;
});
????????? TestComponent ?????????????? ?????????? export ????????????????????????????????????á?
??????????????????? close ?????в?????????????????????????????????????????С?
??????Σ???? TestBed.createComponent(TestComponent) ??????????????????????洢??????
????fixture ?????????????????????DOM????????????????????????д?????????????????????????????????????????????? it ???????????á?
????nativeElement??debugElement??????
??????????DOM????????????Angular???а?????????磺
????    query ??????????????
????    triggerEventHandler ????DOM?????
????????Щ????????д?????????????????????и?????????????С????????????????
????????Component
????1?????

?????????б? ngOnInit ????????????????????????????
// trade-list.component.ts
@Component({
    selector: 'trade-list'??
    templateUrl: './trade-list.component.html'??
    styleUrls: [ './trade-list.component.scss' ]
})
export class TradeListComponent {

    constructor(private srv: TradeService) {}

    ngOnInit() {
        this.query();
    }

    ls: any[] = [];
    query() {
        this.srv.query().subscribe(res => {
            this.ls = res;
        });
    }
}
?????????????? id ???????????????????????????????????? close ???????????????????
// trade-view.component.ts
@Component({
    selector: 'trade-view'??
    template: `
    <h1>trade {{id}}</h1>
    <dl *ngIf="item">
        <dt>sku_id</dt><dd>{{item.sku_id}}</dd>
        <dt>title</dt><dd>{{item.title}}</dd>
    </dl>
    <button (click)="_close()">Close</button>
    `??
    host: {
        '[class.trade-view]': 'true'
    }??
    styles: [ `.trade-view { display: block; }` ]??
    encapsulation: ViewEncapsulation.None
})
export class TradeViewComponent {
    @Input() id: number;

    @Output() close = new EventEmitter();

    constructor(private srv: TradeService) {}

    ngOnInit() {
        this.get();
    }

    item: any;
    get() {
        this.srv.get(this.id).then(res => {
            this.item = res;
        });
    }

    _close() {
        this.close.emit();
    }
}
?????????????????????????????????????????????????@Input??@Output????????HTTP??????????????
???????????????????????????????????????????衣
????2????????? @NgModule
??????????? beforeEach ????????? ????? ??????????????飬???????????????
@Component({
    template: `<trade-view [id]="id" (close)="_close()"></trade-view>`
})
class TestComponent {
    @ViewChild(TradeViewComponent) comp: TradeViewComponent;
    id: number = 0;
    _close() { }
}

beforeEach(() => {
    TestBed.configureTestingModule({
        imports: [HttpModule]??
        declarations: [TradeViewComponent?? TestComponent]??
        providers: [TradeService?? UserService]
    });
    fixture = TestBed.createComponent(TestComponent);
    context = fixture.componentInstance;
    el = fixture.nativeElement;
    de = fixture.debugElement;
});
???????? TradeViewComponent ??????????? TradeService ?????????? UserService ??????????????????????????? HttpModule ??顣
??????????????????????????????????????????????????????????????С???????????????????????????????????????????????????????Ч??????????????
?????????????????? spyOn ??jasmine????????????????? TradeService ?? get ????????????Щ?????????????
let spy: jasmine.Spy;
const testTrade = { id: 10000 };
beforeEach(() => {
  // ...
  spy = spyOn(tradeService?? 'get').and.returnValue(Promise.resolve(testTrade));
  // ...
});
????????????????????????е?????????? spyOn ?????????
??????beforeEach
????trade-list ????? trade-view ???????????????????HTML?????????????????????URL?????????????Щ????????????????????????????????????? @NgModule ????????????????????????????? NgModule ??
beforeEach(async(() => {
    TestBed.configureTestingModule({
      // ???
    }).compileComponents();
    // ???
????}));
???????? async() ??????????? compileComponents() ???????????κ????????????????????????????????????????????????????????????????????к????????ɡ??????? compileComponents() ?????????????????? templateUrl ?? styleUrls ?????????????????
????3??????????
???????????????????????????????????????????????????????????????????????????????????
????A??????????
???????? TradeViewComponent ???? ngOnInit ??????????????л?????????У????????????????
it('should be component initialized'?? () => {
    context.id = 1;
    fixture.detectChanges();
    expect(el.querySelector('h1').innerText).toBe('trade 1');
????});
????context.id = 1; ?е? context ?????????????????????????????? id ????? 1 ??????Angular???????????????仯????????????????? fixture.detectChanges(); ????????Angular?仯???????????????????DOM????????????????? h1 DOM??????????? trade 1 ???????
????????仯???
?????????????????????????? ComponentFixtureAutoDetect ??????仯?? Angular ??????????
????TestBed.configureTestingModule({
????  { provide: ComponentFixtureAutoDetect?? useValue: true }
????});
?????????????????????Щ???????????????????????????????????????????
????B??spy ????
??????????????????????????????????????DOM?????????????? spyOn ??????????????????????????????? spy ????????????????????DOM?????????????????????????
it('should be component initialized (done)'?? (done: DoneFn) => {
    context.id = 1;
    fixture.detectChanges();
    expect(spy.calls.any()).toBe(true?? 'get called');
    spy.calls.mostRecent().returnValue.then(res => {
        fixture.detectChanges();
        expect(context.comp.item.id).toBe(testTrade.id);
        expect(el.querySelector('dl')).not.toBeNull();
        expect(el.querySelector('.sku-id').textContent).toBe('' + testTrade.sku_id);
        expect(el.querySelector('.ware-title').textContent).toBe(testTrade.title);
        done();
    });
});
????????? spy.calls.any() ????е????κμ???????????????? true ??????????????????? ngOnInit ???????????Ρ?
??????Σ? spy.calls.mostRecent().returnValue ????? TradeServie ?? get() ?????????????????????????????????????????????????????????????????
????C????????
????????????У????????jasmine???????????????? get() ???????????????????????????????? then() ????????????????????????ɡ?
???????????????????д????
????async
it('should be component initialized (async)'?? async(() => {
    fixture.detectChanges();
    fixture.whenStable().then(() => {
        fixture.detectChanges();
        expect(context.comp.item.id).toBe(testTrade.id);
        expect(el.querySelector('dl')).not.toBeNull();
        expect(el.querySelector('.sku-id').textContent).toBe('' + testTrade.sku_id);
        expect(el.querySelector('.ware-title').textContent).toBe(testTrade.title);
    });
}));
   ?? spy.calls.mostRecent().returnValue ?滻?? fixture.whenStable() ?????????Promise????Angular??????????????????Promise.resolve??
   fakeAsync

it('should be component initialized (fakeAsync)'?? fakeAsync(() => {
    fixture.detectChanges();
    tick();
    fixture.detectChanges();
    expect(context.comp.item.id).toBe(testTrade.id);
    expect(el.querySelector('dl')).not.toBeNull();
    expect(el.querySelector('.sku-id').textContent).toBe('' + testTrade.sku_id);
    expect(el.querySelector('.ware-title').textContent).toBe(testTrade.title);
}));
   ???? async ?????????????????????????????????
????fakeAsync??async????
????????????????????????????????? fixture.whenStable() ???? tick() ?????
????D?? @Input() ???????
??????????????????????????? context.id = 1; ?????????? trade-view ????????????????? 1 ???????????DOM??? trade 1 ??
????E?? @Output() ????????
????trade-view ?????????? (close) ?????????????????????????????????????????????????????????????????????????????????????????????
???????????? spyOn ????? ??????? ???????????????
??????????????????????? _close() ??
beforeEach(() => {
  // ...
  spyOn(context?? '_close');
  // ...
});

  ??
it('should be call `close`'?? () => {
    el.querySelector('button').click();
    fixture.detectChanges();
    expect(context._close).toHaveBeenCalled();
});
??????? close ??????????? Close ?????????????????????????e?????????? click ????????? toHaveBeenCalled ????????????е? _close() ??????????????????????? close ?????????????????????????????