????4???????
?????????????о???Щ?????
????????? TradeService ???????????????????????? TradeService ?????????????????????????????????????????? TradeService ??????????????????г????????????????????
?????????
????????Angular???????DI??????????????????????????????????????????????????????????????????????????????г?????????????????????????
???????? TradeService ????????? UserService ????????????????? UserService ????????????
??????????????????????????????????????
????Stub
????trade-list ??????? TradeService ???? TradeService ?????? UserService ??????β?????????????????? TradeService ???????????????????????
????Angular???DI????????????????????????????????? trade-list ????????
const tradeServiceStub = {
    query(): Observable<any[]> {
        return Observable.of(tradeData);
    }
};
beforeEach(async(() => {
    TestBed.configureTestingModule({
        declarations: [TradeListComponent?? TradePipe]??
        providers: [
            { provide: TradeService?? useValue: tradeServiceStub }
        ]
    }).compileComponents();
    // ???????
}));
????@NgModule ????????д????????????????????????????????????? tradeServiceStub ??????????? TradeService ???????????????????????……
???????????????? HttpModule ?? UserService ?????????
????5??С??
????????????????????????????????????????а?????Directive??Pipe??Service??Щ??????????
??????????????????????????????Щ??Component??????????
????????Directive
????1?????
???????????ε???
@Directive({ selector: '[log]' })
export class LogDirective {
    tick: number = 0;
   
    @Output() change = new EventEmitter();

    @HostListener('click'?? [ '$event' ])
    click(event: any) {
        ++this.tick;
        this.change.emit(this.tick);
    }
}

  2????????? @NgModule
// ???????????
@Component({
    template: `<div log (change)="change($event)"></div>`
})
class TestComponent {
    @Output() changeNotify = new EventEmitter();

    change(value) {
        this.changeNotify.emit(value);
    }
}

beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [TestComponent?? LogDirective]
    });
    fixture = TestBed.createComponent(TestComponent);
    context = fixture.componentInstance;
    el = fixture.nativeElement;

    let directives = fixture.debugElement.queryAll(By.directive(LogDirective));
    directive = directives.map((d: DebugElement) => d.injector.get(LogDirective) as LogDirective)[0];
????});
????????????漰?????????????????????? beforeEach ????
?????????????????в??????????????? By.directive ?????????????????? LogDirective ??
????By
????By ??Angular???????????????????????????? Type ?????????????????????????????????????? css ?? all ??
????3??????????
????A??????????
??????????? beforeEach ??????????????????????????????????????????????????
??it('should be defined on the test component'?? () => {
    expect(directive).not.toBeUndefined();
});
????B??HostListener????
????[log] ??????????????? click ????????????????? change ???????????????????????????????????? (change) ?????????????????????????????????????????е??????????????????
it('should increment tick (fakeAsync)'?? fakeAsync(() => {
    context.changeNotify.subscribe(val => {
        expect(val).toBe(1);
    });
    el.click();
    tick();
}));
??????????? fakeAsync ?????????????? changeNotify ?????????????????????????????
????????????????????????? changeNotify ???????????????? 1 ???????????????????????????+1???????????0????
??????Σ?????DOM???? click() ?????
?????? tick() ???ж???У???????????????
???????Pipe
????1?????
?????????????????????????????Pipe??
@Pipe({ name: 'trade' })
export class TradePipe implements PipeTransform {
    transform(value: any?? ...args: any[]) {
        switch (value) {
            case 'new':
                return '?????';
            case 'wait_pay':
                return '?????';
            case 'cancel':
                return `<a title="${args && args.length > 0 ? args[0] : ''}">?????</a>`;
            default:
                throw new Error(`??Ч????${value}`);
        }
    }
}
????2??????????
????A??????????
????Pipe??????????????????????????????????????????????
?????????????????? async ?? fakeAsync ????Angular??????????????
let pipe = new TradePipe();

it('should be defined'?? () => {
    expect(pipe).not.toBeUndefined();
});
  B??new ????
it(`should be return '?????' with 'new' string`?? () => {
    expect(pipe.transform('new')).toEqual('?????');
});
  C??????DOM???
  ???????????????Pipe????????У?????????DOM????????????á????????????????????????????
@Component({ template: `<h1>{{ value | trade }}</h1>` })
class TestComponent {
    value: string = 'new';
}

let fixture: ComponentFixture<TestComponent>??
    context: TestComponent??
    el: HTMLElement??
    de: DebugElement;
beforeEach(() => {
    TestBed.configureTestingModule({
        declarations: [TestComponent?? TradePipe]
    });
    fixture = TestBed.createComponent(TestComponent);
    context = fixture.componentInstance;
    el = fixture.nativeElement;
    de = fixture.debugElement;
});
?????????????? NgModule ?????????????
????????????
???????? h1 DOM????????????????????????????ɡ?
it('should display `?????`'?? () => {
    context.value = 'wait_pay';
    fixture.detectChanges();
    expect(el.querySelector('h1').textContent).toBe('?????');
});
  ?塢Service
  1?????
  ??????
@Injectable()
export class TradeService {
    constructor(private http: Http?? private userSrv: UserService) { }

    query(): Observable<any[]> {
        return this.http
            .get('./assets/trade-list.json?token' + this.userSrv.token)
            .map(response => response.json());
    }

    private getTrade() {
        return {
            "id": 10000??
            "user_id": 1??
            "user_name": "asdf"??
            "sku_id": 10000??
            "title": "???????"
        }
    }

    get(tid: number): Promise<any> {
        return new Promise(resolve => {
            setTimeout(() => {
                resolve(this.getTrade());
            }?? 500);
        })
    }
}
  ?????
@Injectable()
export class UserService {

    token: string = 'wx';

    get() {
        return {
            "id": 1??
            "name": "asdf"
        };
    }

    type() {
        return ['??????'?? 'VIP???'];
    }
}
????2??????????
????A??????????
??????Service???κ????????????????? Pipe ??????????????????????ɡ?
?????????????????? async ?? fakeAsync ????Angular??????????????
let srv: UserService = new UserService();

it(`#token should return 'wx'`?? () => {
    expect(srv.token).toBe('wx');
});
???????????????2????????????????????????????? Http ??飬???????????? Angular??????????????????? NgModule ??
let srv: TradeService;
beforeEach(() => TestBed.configureTestingModule({
    imports: [HttpModule]??
    providers: [TradeService?? UserService]
}));
beforeEach(inject([TradeService]?? s => { srv = s; }));
??????????????????κ???????????????
it('#query should return trade array'?? (done: DoneFn) => {
    srv.query().subscribe(res => {
        expect(Array.isArray(res)).toBe(true);
        expect(res.length).toBe(2);
        done();
    });
});
????B??????????? async ?? fakeAsync
???????Service????????????????????????????????κ? async ?? fakeAsync ??????????????????? Observable ?? Promise??
?????????????????????Ρ?
?????????????????? async ?? fakeAsync ????Angular??????????????
????????????????檔
????????????汾???????? Angular ??????????? NgModule ??????????2????????????
it('#get should return trade (fakeAsync)'?? fakeAsync((done: DoneFn) => {
    srv.get(1).then(res => {
        expect(res).not.toBeNull();
        expect(res.id).toBe(10000);
    });
    tick();
}));
??????????? tick() ?????????????DOM????????????Observable???Promise????????????????????? get() ????? setTimeout ????????????? 500ms ???????? tick() ?????????????????????????
????????????????????
????tick(600);
??????????????????? seTimeout ????????????
????????????
????Angular??????????????????????????????????????????????????к?????????? TestBed ???????DI????????????? spy ?????????????????
?????????????24???????????е????????? plnkr ??????????????? templateUrl ??plnkr?в???????????????plnkr??????? template ???????