diff --git a/package.json b/package.json index 3a30fd43c..baebcfe7a 100644 --- a/package.json +++ b/package.json @@ -66,14 +66,14 @@ "moment": "^2.18.1", "node-watch": "^0.5.8", "nyc": "^11.2.1", - "reactivedb": "~0.10.2", + "reactivedb": "0.11.1-alpha.0-rxnotreeshake", "rollup": "^0.60.5", "rollup-plugin-alias": "^1.3.1", "rollup-plugin-commonjs": "^8.4.1", "rollup-plugin-node-resolve": "^3.0.0", "rrule": "2.2.0", - "rxjs": "^5.4.3", - "rxjs-marbles": "^2.4.1", + "rxjs": "6", + "rxjs-marbles": "^4.3.1", "semver": "^5.5.0", "sinon": "^4.0.0", "sinon-chai": "^2.14.0", diff --git a/src/Net/Http.ts b/src/Net/Http.ts index fd296bc3a..ad7f545fd 100644 --- a/src/Net/Http.ts +++ b/src/Net/Http.ts @@ -1,12 +1,4 @@ -import 'rxjs/add/observable/throw' -import 'rxjs/add/observable/dom/ajax' -import 'rxjs/add/observable/empty' -import 'rxjs/add/operator/catch' -import 'rxjs/add/operator/map' -import { AjaxError } from 'rxjs/observable/dom/AjaxObservable' -import { Observable } from 'rxjs/Observable' -import { Observer } from 'rxjs/Observer' -import { Subject } from 'rxjs/Subject' +import * as rx from '../rx' import { parseHeaders } from '../utils/index' import { testable } from '../testable' import { forEach } from '../utils' @@ -30,7 +22,7 @@ type MethodParams = { url: string, body?: any, _opts: any, - errorAdapter$: Subject, + errorAdapter$: rx.Subject, includeHeaders: boolean } @@ -40,9 +32,9 @@ const rxAjaxDefaultHeaderKey2NormKey = { } /** - * Observable.ajax 目前的实现,对请求头字段的已有设置检查没有遵循 + * rxjs ajax 目前的实现,对请求头字段的已有设置检查没有遵循 * 头字段 key 不区分大小写的原则,比如:如果用户已經设置 `content-type`, - * Observable.ajax 内部会发现 `Content-Type` 没有设置,结果会 + * rxjs ajax 内部会发现 `Content-Type` 没有设置,结果会 * 额外添加一个 `Content-Type` 字段,结果导致浏览器发现请求头字段里 * 既有 `content-type` 又有 `Content-Type`,出现问题。 */ @@ -55,46 +47,48 @@ const coverRxAjaxHeadersBug = (normHeaders: {}) => { }) } -export const HttpError$ = new Subject() as any as Observable +export const HttpError$ = new rx.Subject() as any as rx.Observable -export const createMethod = (method: AllowedHttpMethod) => (params: MethodParams): Observable => { +export const createMethod = (method: AllowedHttpMethod) => (params: MethodParams): rx.Observable => { const { url, body, _opts, errorAdapter$, includeHeaders } = params /* istanbul ignore if */ if (testable.UseXMLHTTPRequest && typeof window !== 'undefined') { coverRxAjaxHeadersBug(_opts.headers) - return Observable.ajax({ + return rx.ajax({ url, body, method, headers: _opts.headers, withCredentials: _opts.credentials === 'include', responseType: _opts.responseType || 'json', crossDomain: typeof _opts.crossDomain !== 'undefined' ? !!_opts.crossDomain : true }) - .map(value => { - const respBody = value.response - if (!includeHeaders) { - return respBody - } - const respHeaders = parseHeaders(value.xhr.getAllResponseHeaders()) - return { headers: respHeaders, body: respBody } - }) - .catch((e: AjaxError) => { - const headers = e.xhr.getAllResponseHeaders() - const errorResponse = new Response(new Blob([JSON.stringify(e.xhr.response)]), { - status: e.xhr.status, - statusText: e.xhr.statusText, - headers: headers.length ? parseHeaders(headers) : new Headers() + .pipe( + rx.map(value => { + const respBody = value.response + if (!includeHeaders) { + return respBody + } + const respHeaders = parseHeaders(value.xhr.getAllResponseHeaders()) + return { headers: respHeaders, body: respBody } + }), + rx.catch((e: rx.AjaxError) => { + const headers = e.xhr.getAllResponseHeaders() + const errorResponse = new Response(new Blob([JSON.stringify(e.xhr.response)]), { + status: e.xhr.status, + statusText: e.xhr.statusText, + headers: headers.length ? parseHeaders(headers) : new Headers() + }) + const requestInfo = { method, url, body } + const errorResponseClone = errorResponse.clone() + + setTimeout(() => { + errorAdapter$.next({ ...requestInfo, error: errorResponseClone }) + }, 10) + return rx.throw({ ...requestInfo, error: errorResponse }) }) - const requestInfo = { method, url, body } - const errorResponseClone = errorResponse.clone() - - setTimeout(() => { - errorAdapter$.next({ ...requestInfo, error: errorResponseClone }) - }, 10) - return Observable.throw({ ...requestInfo, error: errorResponse }) - }) + ) } else { // 测试用分支 - return Observable.create((observer: Observer) => { + return new rx.Observable((observer) => { const _options = { ... _opts, method: method @@ -138,16 +132,16 @@ export const createMethod = (method: AllowedHttpMethod) => (params: MethodParams export const getHttpWithResponseHeaders = ( url?: string, - errorAdapter$?: Subject + errorAdapter$?: rx.Subject ): Http> => { return new Http>(url, errorAdapter$, true) } export class Http { - private errorAdapter$: Subject + private errorAdapter$: rx.Subject private cloned = false - private request: Observable | undefined - public mapFn: (v$: Observable) => Observable = (dist$ => dist$) + private request: rx.Observable | undefined + public mapFn: (v$: rx.Observable) => rx.Observable = (dist$ => dist$) private static get = createMethod('get') private static put = createMethod('put') @@ -161,13 +155,13 @@ export class Http { constructor( private url: string = '', - errorAdapter$?: Subject, + errorAdapter$?: rx.Subject, private readonly includeHeaders: boolean = false ) { if (errorAdapter$) { this.errorAdapter$ = errorAdapter$ } else { - this.errorAdapter$ = HttpError$ as Subject + this.errorAdapter$ = HttpError$ as rx.Subject } } @@ -225,14 +219,14 @@ export class Http { return this } - send(): Observable { - return this.request ? this.mapFn(this.request) : Observable.empty() + send(): rx.Observable { + return this.request ? this.mapFn(this.request) : rx.empty() } clone() { const result = new Http(this.url, this.errorAdapter$) if (!this.cloned && this.request) { - this.request = this.request.publishReplay(1).refCount() + this.request = this.request.pipe(rx.publishReplay(1), rx.refCount()) this.cloned = true result.cloned = true } diff --git a/src/Net/Net.ts b/src/Net/Net.ts index 451adde44..1ebd9d5da 100644 --- a/src/Net/Net.ts +++ b/src/Net/Net.ts @@ -1,18 +1,9 @@ -import 'rxjs/add/observable/forkJoin' -import 'rxjs/add/observable/of' -import 'rxjs/add/operator/concatAll' -import 'rxjs/add/operator/do' -import 'rxjs/add/operator/mapTo' -import 'rxjs/add/operator/mergeMap' -import 'rxjs/add/operator/switchMap' -import 'rxjs/add/operator/filter' -import { Observable } from 'rxjs/Observable' -import { BehaviorSubject } from 'rxjs/BehaviorSubject' +import * as rx from '../rx' import { QueryToken, SelectorMeta, ProxySelector } from 'reactivedb/proxy' import { JoinMode } from 'reactivedb/interface' import { Database, Query, Predicate, ExecutorResult } from 'reactivedb' -import { forEach, ParsedWSMsg, WSMsgToDBHandler, GeneralSchemaDef } from '../utils' +import { forEach, identity, ParsedWSMsg, WSMsgToDBHandler, GeneralSchemaDef } from '../utils' import { SDKLogger } from '../utils/Logger' /** @@ -61,7 +52,7 @@ export enum CacheStrategy { } export interface ApiResult { - request: Observable | Observable + request: rx.Observable | rx.Observable /** * 使用 fields 指定需要查询的字段,where 指定查询条件, * orderBy 指定结果排序规则。更多支持的选项请见具体类型定义。 @@ -86,19 +77,19 @@ export interface ApiResult { * 或为空([])。 */ excludeFields?: string[] - padding?: (missedId: string) => Observable + padding?: (missedId: string) => rx.Observable } export type AssocField = { [P in keyof T]?: AssocField | string[] } export interface CApiResult { - request: Observable + request: rx.Observable tableName: string method: 'create' } export interface UDResult { - request: Observable + request: rx.Observable tableName: string method: 'update' | 'delete' clause: Predicate @@ -121,7 +112,7 @@ export type SocketCUDBufferObject = { export type SelectorBufferObject = { kind: 'Selector' realSelectorInfo: ApiResult - proxySelector: BehaviorSubject> + proxySelector: rx.BehaviorSubject> } export type BufferObject = CUDBufferObject | SocketCUDBufferObject | SelectorBufferObject @@ -148,32 +139,27 @@ export class Net { public persistedDataBuffer: BufferObject[] = [] private msgToDB: WSMsgToDBHandler | undefined - private validate = (result: ApiResult) => { - const { tableName, required, padding } = result - - const hasRequiredFields = Array.isArray(required) - const hasPaddingFunction = typeof padding === 'function' + private validate = ({ tableName, required, padding }: ApiResult) => { const pk = this.primaryKeys.get(tableName) - - const fn = (stream$: Observable) => - stream$.switchMap(data => !data.length - ? Observable.of(data) - : Observable.forkJoin( - Observable.from(data) - .mergeMap(datum => { - if (!hasRequiredFields || !hasPaddingFunction || !pk || - required!.every(k => typeof datum[k] !== 'undefined') - ) { - return Observable.of(datum) - } - const patch = padding!(datum[pk]).filter(r => r != null) as Observable - return patch - .concatMap(r => this.database!.upsert(tableName, r).mapTo(r)) - .do(r => Object.assign(datum, r)) - }) + const noRequiredPadding = !Array.isArray(required) || typeof padding !== 'function' || !pk + + const fn = rx.switchMap((results) => { + return !results.length + ? rx.of([]) + : rx.from(results).pipe( + rx.mergeMap((result) => { + return noRequiredPadding || required!.every(k => typeof result[k] !== 'undefined') + ? rx.empty() + : padding!(result[pk!]).pipe( + rx.filter((r): r is T => r != null), + rx.concatMap((r) => this.database!.upsert(tableName, r).pipe( + rx.tap(() => Object.assign(result, r)) + )) + ) + }), + rx.reduce(identity, results) ) - .mapTo(data) - ) + }) fn.toString = () => 'SDK_VALIDATE' return fn } @@ -204,7 +190,7 @@ export class Net { lift(result: ApiResult): QueryToken - lift(result: CUDApiResult): Observable + lift(result: CUDApiResult): rx.Observable lift(result: ApiResult | CUDApiResult) { if ((result as ApiResult).cacheValidate) { @@ -232,25 +218,24 @@ export class Net { const database = this.database! - const { request, method, tableName } = result as CUDApiResult - let destination: Observable | Observable - return request - .concatMap(v => { - switch (method) { - case 'create': - destination = database.upsert(tableName, v) - break - case 'update': - destination = database.upsert(tableName, v) - break - case 'delete': - destination = database.delete(tableName, (result as UDResult).clause) - break - default: - throw new Error() - } - return destination.mapTo(v) - }) + const { request, method, tableName } = result + let destination: rx.Observable + return request.pipe(rx.concatMap(v => { + switch (method) { + case 'create': + destination = database.upsert(tableName, v) + break + case 'update': + destination = database.upsert(tableName, v) + break + case 'delete': + destination = database.delete(tableName, (result as UDResult).clause) + break + default: + throw new Error() + } + return destination.pipe(rx.mapTo(v)) + })) } persist(database: Database) { @@ -258,10 +243,10 @@ export class Net { this.database = database } - const asyncQueue: Observable[] = [] + const asyncQueue: rx.Observable[] = [] forEach(this.persistedDataBuffer, (v: BufferObject) => { - let p: Observable | null = null + let p: rx.Observable | null = null switch (v.kind) { case 'CUD': @@ -277,12 +262,11 @@ export class Net { const token = this.handleRequestCache(v.realSelectorInfo) const selector$ = token.selector$ - p = selector$ - .do({ - next(selector) { - cacheControl$.next(selector) - } - }) + p = selector$.pipe(rx.tap({ + next(selector) { + cacheControl$.next(selector) + } + })) break default: break @@ -295,12 +279,15 @@ export class Net { this.persistedDataBuffer.length = 0 - return Observable.from(asyncQueue).concatAll().do({ - error: async (err: Observable) => { - const errObj = await err.toPromise() - SDKLogger.error(errObj.message) - } - }) + return rx.from(asyncQueue).pipe( + rx.concatAll(), + rx.tap({ + error: async (err: rx.Observable) => { + const errObj = await err.toPromise() + SDKLogger.error(errObj.message) + } + }) + ) } bufferResponse(result: ApiResult) { @@ -311,7 +298,7 @@ export class Net { q, tableName ) - const cacheControl$ = new BehaviorSubject>(proxySelector) + const cacheControl$ = new rx.BehaviorSubject>(proxySelector) this.persistedDataBuffer.push({ kind: 'Selector', realSelectorInfo: result, @@ -323,15 +310,14 @@ export class Net { bufferCUDResponse(result: CUDApiResult) { const { request, method, tableName } = result as CUDApiResult - return request - .do((v: T | T[]) => { + return request.pipe(rx.tap((v: T | T[]) => { this.persistedDataBuffer.push({ kind: 'CUD', tableName, method: (method === 'create' || method === 'update') ? 'upsert' : method, value: method === 'delete' ? (result as UDResult).clause : v }) - }) + })) } bufferSocketPush(socketMessage: ParsedWSMsg) { @@ -339,7 +325,7 @@ export class Net { kind: 'SocketCUD', socketMessage }) - return Observable.of(null) + return rx.of(null) } private genCacheKey(tableName: string, q: Readonly>) { @@ -357,7 +343,7 @@ export class Net { } = this.getInfoFromResult(result) // 将类型 Observalbe | Observable 弱化为 Observable - const response$: Observable = request + const response$: rx.Observable = request const cacheKey = this.genCacheKey(tableName, q) const requestCache = this.requestMap.get(cacheKey) @@ -366,10 +352,11 @@ export class Net { case CacheStrategy.Request: if (!requestCache) { /*tslint:disable no-shadowed-variable*/ - const selector$ = response$ - .concatMap(v => database.upsert(tableName, v)) - .do(() => this.requestMap.set(cacheKey, true)) - .concatMap(() => dbGetWithSelfJoinEnabled(database, tableName, q).selector$) + const selector$ = response$.pipe( + rx.concatMap(v => database.upsert(tableName, v)), + rx.tap(() => this.requestMap.set(cacheKey, true)), + rx.concatMap(() => dbGetWithSelfJoinEnabled(database, tableName, q).selector$) + ) token = new QueryToken(selector$) } else { token = dbGetWithSelfJoinEnabled(database, tableName, q) @@ -377,9 +364,10 @@ export class Net { token.map(this.validate(result)) break case CacheStrategy.Cache: - const selector$ = response$ - .concatMap(v => database.upsert(tableName, v)) - .concatMap(() => dbGetWithSelfJoinEnabled(database, tableName, q).selector$) + const selector$ = response$.pipe( + rx.concatMap(v => database.upsert(tableName, v)), + rx.concatMap(() => dbGetWithSelfJoinEnabled(database, tableName, q).selector$) + ) return new QueryToken(selector$) default: throw new TypeError('unreachable code path') diff --git a/src/Net/Pagination.ts b/src/Net/Pagination.ts index 2dadd0182..64c2b9bdb 100644 --- a/src/Net/Pagination.ts +++ b/src/Net/Pagination.ts @@ -1,9 +1,4 @@ -import 'rxjs/add/observable/throw' -import 'rxjs/add/operator/startWith' -import 'rxjs/add/operator/withLatestFrom' -import { Observable } from 'rxjs/Observable' -import { Observer } from 'rxjs/Observer' -import { OperatorFunction } from 'rxjs/interfaces' +import * as rx from '../rx' export type PageToken = string & { kind: 'PageToken' } @@ -70,26 +65,29 @@ export const accumulateResultByConcat = (state: State, resp: OriginalRespo } export const loadAndExpand = ( - step: (curr: State) => Observable>, + step: (curr: State) => rx.Observable>, initState: State, - loadMore$: Observable<{}> = Observable.empty() -): Observable> => { - return loadMore$.startWith({}) - .pipe(expand(step, accumulateResultByConcat, initState)) - .mergeAll() + loadMore$: rx.Observable<{}> = rx.empty() +): rx.Observable> => { + return loadMore$ + .pipe( + rx.startWith({}), + expand(step, accumulateResultByConcat, initState), + rx.mergeAll() + ) } export const expand = ( - step: (curr: State) => Observable>, + step: (curr: State) => rx.Observable>, accumulator: (state: State, resp: OriginalResponse) => State, initState: State -): OperatorFunction<{}, Observable>> => ( +): rx.OperatorFunction<{}, rx.Observable>> => ( source$ ) => { const state = { ...initState } let isLoading = false - return Observable.create((observer: Observer>>) => { + return new rx.Observable((observer) => { const subs = source$.subscribe({ next: (_) => { if (!state.hasMore) { @@ -99,10 +97,12 @@ export const expand = ( if (!isLoading) { isLoading = true observer.next(step(state) - .map((stepResult) => accumulator(state, stepResult)) - .do((expanded) => Object.assign(state, expanded)) - .catch((err) => Observable.throw(err)) - .finally(() => { isLoading = false }) + .pipe( + rx.map((stepResult) => accumulator(state, stepResult)), + rx.tap((expanded) => Object.assign(state, expanded)), + rx.catch((err) => rx.throw(err)), + rx.finalize(() => { isLoading = false }) + ) ) } }, @@ -118,5 +118,5 @@ export const expand = ( return () => { subs.unsubscribe() } - }) as Observable>> + }) } diff --git a/src/SDK.ts b/src/SDK.ts index b430cdf5a..757388793 100644 --- a/src/SDK.ts +++ b/src/SDK.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from './rx' import { Database } from 'reactivedb' import { Net } from './Net' import { forEach } from './utils' diff --git a/src/SDKFetch.ts b/src/SDKFetch.ts index c96293dc7..0b120d200 100644 --- a/src/SDKFetch.ts +++ b/src/SDKFetch.ts @@ -1,10 +1,4 @@ -import 'rxjs/add/observable/defer' -import 'rxjs/add/observable/throw' -import 'rxjs/add/operator/catch' -import 'rxjs/add/operator/map' -import 'rxjs/add/operator/publishReplay' -import 'rxjs/add/operator/finally' -import { Observable } from 'rxjs/Observable' +import * as rx from './rx' import { Http, HttpErrorMessage, HttpResponseWithHeaders, getHttpWithResponseHeaders } from './Net/Http' import { UserMe } from './schemas/UserMe' import { forEach, uuid } from './utils' @@ -90,7 +84,7 @@ export class SDKFetch { private options: {} = {} ) {} - static FetchStack = new Map>() + static FetchStack = new Map>() static fetchTail: string | undefined | 0 get(path: string, query: any, options: SDKFetchOptions & { @@ -103,27 +97,33 @@ export class SDKFetch { get(path: string, query: any, options: SDKFetchOptions & { includeHeaders: true - }): Observable> + }): rx.Observable> - get(path: string, query?: any, options?: SDKFetchOptions): Observable + get(path: string, query?: any, options?: SDKFetchOptions): rx.Observable get(path: string, query?: any, options: SDKFetchOptions = {}) { const url = this.urlWithPath(path, options.apiHost) const urlWithQuery = appendQueryString(url, toQueryString(query)) const http = options.includeHeaders ? getHttpWithResponseHeaders() : new Http() - let dist: Observable | Observable> + let dist: rx.Observable | rx.Observable> this.setOptionsPerRequest(http, options) if (!SDKFetch.FetchStack.has(urlWithQuery)) { const tail = SDKFetch.fetchTail || Date.now() const urlWithTail = appendQueryString(urlWithQuery, `_=${ tail }`) - dist = Observable.defer(() => http.setUrl(urlWithTail).get().send() as any) - .publishReplay(1) - .refCount() - .finally(() => { + dist = rx.defer(() => { + const request = http.setUrl(urlWithTail).get() + // 将 Observable | Observable> 弱化 + // 为 Observable> + return request.send() as rx.Observable> + }).pipe( + rx.publishReplay(1), + rx.refCount(), + rx.finalize(() => { SDKFetch.FetchStack.delete(urlWithQuery) }) + ) as rx.Observable | rx.Observable> SDKFetch.FetchStack.set(urlWithQuery, dist) } @@ -149,9 +149,9 @@ export class SDKFetch { post(path: string, body: any, options: SDKFetchOptions & { includeHeaders: true - }): Observable> + }): rx.Observable> - post(path: string, body?: any, options?: SDKFetchOptions): Observable + post(path: string, body?: any, options?: SDKFetchOptions): rx.Observable post(path: string, body?: any, options: SDKFetchOptions = {}) { const http = options.includeHeaders ? getHttpWithResponseHeaders() : new Http() @@ -174,9 +174,9 @@ export class SDKFetch { put(path: string, body: any, options: SDKFetchOptions & { includeHeaders: true - }): Observable> + }): rx.Observable> - put(path: string, body?: any, options?: SDKFetchOptions): Observable + put(path: string, body?: any, options?: SDKFetchOptions): rx.Observable put(path: string, body?: any, options: SDKFetchOptions = {}) { const http = options.includeHeaders ? getHttpWithResponseHeaders() : new Http() @@ -199,9 +199,9 @@ export class SDKFetch { delete(path: string, body: any, options: SDKFetchOptions & { includeHeaders: true - }): Observable> + }): rx.Observable> - delete(path: string, body?: any, options?: SDKFetchOptions): Observable + delete(path: string, body?: any, options?: SDKFetchOptions): rx.Observable delete(path: string, body?: any, options: SDKFetchOptions = {}) { const http = options.includeHeaders ? getHttpWithResponseHeaders() : new Http() @@ -277,12 +277,12 @@ export class SDKFetch { // todo(dingwen): 待实现更有效的 HTTP interceptor,替换这里的实现。 http['mapFn'] = ((source) => { - return source.catch((error: HttpErrorMessage) => { + return source.pipe(rx.catch((error: HttpErrorMessage) => { if (!fetchOptions.disableRequestId) { error['requestId'] = headers[HttpHeaders.Key.RequestId] } - return Observable.throw(error) - }) + return rx.throw(error) + })) }) } diff --git a/src/apis/activity/request.ts b/src/apis/activity/request.ts index 8f0108212..406519eb0 100644 --- a/src/apis/activity/request.ts +++ b/src/apis/activity/request.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { ActivitySchema } from '../../schemas' import { ActivityId } from 'teambition-types' diff --git a/src/apis/customfieldlink/get.ts b/src/apis/customfieldlink/get.ts index 0db51675e..0a03d4114 100644 --- a/src/apis/customfieldlink/get.ts +++ b/src/apis/customfieldlink/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { CacheStrategy } from '../../Net' diff --git a/src/apis/event/get.ts b/src/apis/event/get.ts index 566d75ee5..6cdd0ff76 100644 --- a/src/apis/event/get.ts +++ b/src/apis/event/get.ts @@ -1,4 +1,4 @@ -import 'rxjs/add/operator/toArray' +import { map } from '../../rx' import { QueryToken } from 'reactivedb' import { SDK, CacheStrategy } from '../../SDK' import { EventSchema } from '../../schemas/Event' @@ -23,7 +23,7 @@ export function getEvent( excludeFields: [ 'project' ] }) - return token.map(e$ => e$.map(events => events.map(e => new EventGenerator(e)))) + return token.map(map(events => events.map(e => new EventGenerator(e)))) } SDK.prototype.getEvent = getEvent diff --git a/src/apis/event/request.ts b/src/apis/event/request.ts index 618a15084..b6bb44628 100644 --- a/src/apis/event/request.ts +++ b/src/apis/event/request.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { EventSchema } from '../../schemas/Event' import { EventId, ProjectId, UserId } from 'teambition-types' @@ -40,7 +40,7 @@ export function commentsRepeatEvent( options: CommentsRepeatEvent.Options ): Observable { return this.post(`events/${_id}/comments_repeat_event`, options) - .map(CommentsRepeatEvent.api.parse) + .pipe(map(CommentsRepeatEvent.api.parse)) } export namespace UpdateInvolveMembers { @@ -77,7 +77,7 @@ export function fetchAnEvent( query?: any ): Observable { return this.get(`events/${eventId}`, query) - .map(eventMarshaler.parse) + .pipe(map(eventMarshaler.parse)) } export function fetchProjectEventsCount( @@ -94,7 +94,7 @@ export function fetchProjectEvents( query: EventSpan ): Observable { return this.get(`projects/${_projectId}/events`, query) - .map((rawEvents) => rawEvents.map(eventMarshaler.parse)) + .pipe(map((rawEvents) => rawEvents.map(eventMarshaler.parse))) } SDKFetch.prototype.commentsRepeatEvent = commentsRepeatEvent diff --git a/src/apis/file/get.ts b/src/apis/file/get.ts index acf6fbb32..7c7903498 100644 --- a/src/apis/file/get.ts +++ b/src/apis/file/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { SDK, CacheStrategy } from '../../SDK' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/group/index.ts b/src/apis/group/index.ts index a5a41235c..30a73027e 100644 --- a/src/apis/group/index.ts +++ b/src/apis/group/index.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { GroupId } from 'teambition-types' diff --git a/src/apis/like/get.ts b/src/apis/like/get.ts index af3b91992..025da9417 100644 --- a/src/apis/like/get.ts +++ b/src/apis/like/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { LikeSchema } from '../../schemas/Like' import { SDKFetch } from '../../SDKFetch' @@ -12,7 +12,7 @@ export function getLikeFetch ( ): Observable { const fetchNamespace = objectType !== 'entry' ? `${objectType}s` : 'entries' return this.get(`${fetchNamespace}/${objectId}/like`, { all: '1' }) - .map(r => ({ ...r, _id: `${objectId}:like` })) + .pipe(map(r => ({ ...r, _id: `${objectId}:like` }))) } SDKFetch.prototype.getLike = getLikeFetch diff --git a/src/apis/like/toggleLike.ts b/src/apis/like/toggleLike.ts index c40d2f942..a4945dc20 100644 --- a/src/apis/like/toggleLike.ts +++ b/src/apis/like/toggleLike.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, Observable } from '../../rx' import { LikeSchema } from '../../schemas/Like' import { SDKFetch } from '../../SDKFetch' import { SDK } from '../../SDK' @@ -13,10 +13,10 @@ export function toggleLikeFetch ( const fetchNamespace = objectType !== 'entry' ? `${objectType}s` : 'entries' const uri = `${fetchNamespace}/${objectId}/like` const dist = isLike ? this.delete(uri) : this.post(uri) - return dist.map(r => { + return dist.pipe(map(r => { r._id = `${objectId}:like` return r - }) + })) } SDKFetch.prototype.toggleLike = toggleLikeFetch diff --git a/src/apis/message/request.ts b/src/apis/message/request.ts index c3e13c8f9..35f68db1a 100644 --- a/src/apis/message/request.ts +++ b/src/apis/message/request.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { MessageSchema } from '../../schemas/Message' import { MessageId } from 'teambition-types' diff --git a/src/apis/my/count.ts b/src/apis/my/count.ts index 860e354f6..a647cccef 100644 --- a/src/apis/my/count.ts +++ b/src/apis/my/count.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { SDK } from '../../SDK' diff --git a/src/apis/my/file.ts b/src/apis/my/file.ts index 4da3cbcaa..8477957ab 100644 --- a/src/apis/my/file.ts +++ b/src/apis/my/file.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { FileSchema } from '../../schemas/File' diff --git a/src/apis/my/recent.ts b/src/apis/my/recent.ts index 48056c0be..7c019bfed 100644 --- a/src/apis/my/recent.ts +++ b/src/apis/my/recent.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, tap, Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { forEach } from '../../utils' import { SDKFetch } from '../../SDKFetch' @@ -53,7 +53,7 @@ export function getMyRecent( cacheValidate: CacheStrategy.Request, tableName: 'Task', request: this.fetch.getMyRecent(query) - .map(r => r.filter(t => t.type === 'task')), + .pipe(map(r => r.filter(t => t.type === 'task'))), query: { where: { dueDate: { @@ -80,9 +80,9 @@ export function getMyRecent( }) taskToken = taskToken.map(task$ => task$ - .do(tasks => forEach(tasks, task => { + .pipe(tap(tasks => forEach(tasks, task => { task.type = 'task' - }) + })) )) const eventQuery = { @@ -120,7 +120,7 @@ export function getMyRecent( cacheValidate: CacheStrategy.Request, tableName: 'Event', request: this.fetch.getMyRecent(query) - .map(r => r.filter(t => t.type === 'event')), + .pipe(map(r => r.filter(t => t.type === 'event'))), query: eventQuery, assocFields: { project: ['_id', 'name', 'isArchived'] @@ -137,13 +137,13 @@ export function getMyRecent( ] }) - eventToken = eventToken.map(e$ => e$.map(events => events.map(e => new EventGenerator(e)))) + eventToken = eventToken.map(map(events => events.map(e => new EventGenerator(e)))) let subtaskToken = this.lift({ cacheValidate: CacheStrategy.Request, tableName: 'Subtask', request: this.fetch.getMyRecent(query) - .map(r => r.filter(t => t.type === 'subtask')), + .pipe(map(r => r.filter(t => t.type === 'subtask'))), query: { where: { _executorId: userId, @@ -160,9 +160,9 @@ export function getMyRecent( }) subtaskToken = subtaskToken.map(task$ => task$ - .do(subtasks => forEach(subtasks, subtask => { + .pipe(tap(subtasks => forEach(subtasks, subtask => { subtask.type = 'subtask' - }) + })) )) return taskToken.combine(eventToken, subtaskToken) diff --git a/src/apis/organization/projects.ts b/src/apis/organization/projects.ts index 989efe4aa..f83761a13 100644 --- a/src/apis/organization/projects.ts +++ b/src/apis/organization/projects.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { OrganizationId, TagId } from 'teambition-types' import { SDKFetch } from '../../SDKFetch' import { ProjectSchema } from '../../schemas/Project' diff --git a/src/apis/pagination.ts b/src/apis/pagination.ts index c90630e66..96502daeb 100644 --- a/src/apis/pagination.ts +++ b/src/apis/pagination.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, tap, Observable } from '../rx' import { SDKFetch, SDKFetchOptions } from '../SDKFetch' import { Page } from '../Net' @@ -27,7 +27,7 @@ export function page( .get>(state.urlPath, paginationUrlQuery, { ...requestOptions, wrapped: false, includeHeaders: true }) - .map(({ headers, body: { nextPageToken, totalSize, result } }) => { + .pipe(map(({ headers, body: { nextPageToken, totalSize, result } }) => { return { nextPageToken, totalSize, @@ -35,7 +35,7 @@ export function page( ? result as any as K[] : result.map((x, i, arr) => options.mapFn!(x, i, arr, headers)), } - }) + })) } /** @@ -43,7 +43,7 @@ export function page( * @param state 当前分页的状态 * @param options 主要用于自定义每一次调用需要的请求参数。另外,如果 * `mutate` 为 true,传入的 `state` 对象将自动得到更新,不需要在外部 - * 自行 `.do((nextState) => state = nextState)`(注:推出的对象依然是 + * 自行 `tap((nextState) => state = nextState)`(注:推出的对象依然是 * 全新的)。 */ export function expandPage( @@ -61,7 +61,7 @@ export function expandPage( ): Observable> { const { mutate, loadMore$, ...requestOptions } = options const page$ = Page.loadAndExpand((s) => this.page(s, requestOptions), state, loadMore$) - return !mutate ? page$ : page$.do((nextState) => Object.assign(state, nextState)) + return !mutate ? page$ : page$.pipe(tap((nextState) => Object.assign(state, nextState))) } SDKFetch.prototype.expandPage = expandPage diff --git a/src/apis/post/create.ts b/src/apis/post/create.ts index 12f32f518..40a66b0e3 100644 --- a/src/apis/post/create.ts +++ b/src/apis/post/create.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDK } from '../../SDK' import { SDKFetch } from '../../SDKFetch' import { PostModeOptions, PostSchema } from '../../schemas/Post' diff --git a/src/apis/post/delete.ts b/src/apis/post/delete.ts index 3c2f566dc..365f377d2 100644 --- a/src/apis/post/delete.ts +++ b/src/apis/post/delete.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDK } from '../../SDK' import { SDKFetch } from '../../SDKFetch' import { PostId } from 'teambition-types' diff --git a/src/apis/post/get.ts b/src/apis/post/get.ts index 5b83ddbe7..0cb5244e2 100644 --- a/src/apis/post/get.ts +++ b/src/apis/post/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { SDK, CacheStrategy } from '../../SDK' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/post/getByTagId.ts b/src/apis/post/getByTagId.ts index 8f49b305a..753043c78 100644 --- a/src/apis/post/getByTagId.ts +++ b/src/apis/post/getByTagId.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken, OrderDescription } from 'reactivedb' import { SDK, CacheStrategy } from '../../SDK' import { TagId } from 'teambition-types' diff --git a/src/apis/post/getProjects.ts b/src/apis/post/getProjects.ts index f5cf5de0b..0147d18de 100644 --- a/src/apis/post/getProjects.ts +++ b/src/apis/post/getProjects.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken, OrderDescription } from 'reactivedb' import { SDK, CacheStrategy } from '../../SDK' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/post/update.ts b/src/apis/post/update.ts index 4aac21c77..d663a4e0c 100644 --- a/src/apis/post/update.ts +++ b/src/apis/post/update.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { FileId, UserId, PostId } from 'teambition-types' import { SDK } from '../../SDK' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/project/get.ts b/src/apis/project/get.ts index 59f1b2804..e0665e45c 100644 --- a/src/apis/project/get.ts +++ b/src/apis/project/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { SDK, CacheStrategy } from '../../SDK' diff --git a/src/apis/project/personal.ts b/src/apis/project/personal.ts index f0307b83b..78a398222 100644 --- a/src/apis/project/personal.ts +++ b/src/apis/project/personal.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { ProjectSchema } from '../../schemas/Project' import { UrlPagingQuery } from '../../utils/internalTypes' diff --git a/src/apis/room/request.ts b/src/apis/room/request.ts index e30c5b928..396886c4d 100644 --- a/src/apis/room/request.ts +++ b/src/apis/room/request.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDKFetch } from '../../SDKFetch' import { ActivitySchema, RoomSchema } from '../../schemas' import { RoomId } from 'teambition-types' diff --git a/src/apis/scenariofieldconfig/get-by-org-id.ts b/src/apis/scenariofieldconfig/get-by-org-id.ts index 191090600..e3e7f6579 100644 --- a/src/apis/scenariofieldconfig/get-by-org-id.ts +++ b/src/apis/scenariofieldconfig/get-by-org-id.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { OrganizationId, ScenarioFieldConfigObjectType } from 'teambition-types' @@ -37,7 +37,7 @@ export function getOrgScenarioFieldConfigsFetch( return this.get<{ nextPageToken: string, result: ScenarioFieldConfigSchema[] }>( `organizations/${organizationId}/scenariofieldconfigs`, { ...query, objectType }, - ).map(({ result }) => result) + ).pipe(map(({ result }) => result)) } declare module '../../SDKFetch' { diff --git a/src/apis/scenariofieldconfig/get-by-project-id.ts b/src/apis/scenariofieldconfig/get-by-project-id.ts index 1e9bdca52..94c64434f 100644 --- a/src/apis/scenariofieldconfig/get-by-project-id.ts +++ b/src/apis/scenariofieldconfig/get-by-project-id.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { ProjectId, ScenarioFieldConfigObjectType } from 'teambition-types' diff --git a/src/apis/scenariofieldconfig/get.ts b/src/apis/scenariofieldconfig/get.ts index 6fdab0018..e7c285ac5 100644 --- a/src/apis/scenariofieldconfig/get.ts +++ b/src/apis/scenariofieldconfig/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { ScenarioFieldConfigId, OrganizationId, ScenarioFieldConfigObjectType } from 'teambition-types' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/scenariofieldconfig/post.ts b/src/apis/scenariofieldconfig/post.ts index 87bb528ad..ca1da7570 100644 --- a/src/apis/scenariofieldconfig/post.ts +++ b/src/apis/scenariofieldconfig/post.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { ProjectId, ScenarioFieldConfigObjectType, ScenarioFieldConfigId, OrganizationId } from 'teambition-types' import { SDK } from '../../SDK' diff --git a/src/apis/scenariofieldconfig/put.ts b/src/apis/scenariofieldconfig/put.ts index 1125af85a..cf27e6386 100644 --- a/src/apis/scenariofieldconfig/put.ts +++ b/src/apis/scenariofieldconfig/put.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { map, Observable } from '../../rx' import { ScenarioFieldConfigId } from 'teambition-types' import { SDK } from '../../SDK' @@ -56,7 +56,7 @@ export function syncScenarioFieldConfig( method: 'update', request: this.fetch.syncScenarioFieldConfig( scenarioFieldConfigId - ).map(() => ({ _id: scenarioFieldConfigId })), + ).pipe(map(() => ({ _id: scenarioFieldConfigId }))), clause: {} }) } diff --git a/src/apis/search/members.ts b/src/apis/search/members.ts index 4251216e6..d710e951e 100644 --- a/src/apis/search/members.ts +++ b/src/apis/search/members.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { UserId, TeamId, ProjectId, OrganizationId, GroupId } from 'teambition-types' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/tag/get.ts b/src/apis/tag/get.ts index a3e8c56ca..358f53e3f 100644 --- a/src/apis/tag/get.ts +++ b/src/apis/tag/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { SDK } from '../../SDK' diff --git a/src/apis/task/get.ts b/src/apis/task/get.ts index 6ac1da13d..2d06bc1b3 100644 --- a/src/apis/task/get.ts +++ b/src/apis/task/get.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { QueryToken } from 'reactivedb' import { SDKFetch } from '../../SDKFetch' import { SDK, CacheStrategy } from '../../SDK' diff --git a/src/apis/user/addEmail.ts b/src/apis/user/addEmail.ts index 201f16f0e..7a784c93a 100644 --- a/src/apis/user/addEmail.ts +++ b/src/apis/user/addEmail.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDK } from '../../SDK' import { SDKFetch } from '../../SDKFetch' diff --git a/src/apis/user/update.ts b/src/apis/user/update.ts index 78b2a6611..b5228608a 100644 --- a/src/apis/user/update.ts +++ b/src/apis/user/update.ts @@ -1,4 +1,4 @@ -import { Observable } from 'rxjs/Observable' +import { Observable } from '../../rx' import { SDK } from '../../SDK' import { SDKFetch } from '../../SDKFetch' diff --git a/src/rx.ts b/src/rx.ts new file mode 100644 index 000000000..0f82d5901 --- /dev/null +++ b/src/rx.ts @@ -0,0 +1,41 @@ +import 'rxjs/internal/symbol/observable' + +export { defer } from 'rxjs/internal/observable/defer' +export { empty } from 'rxjs/internal/observable/empty' +export { forkJoin } from 'rxjs/internal/observable/forkJoin' +export { from } from 'rxjs/internal/observable/from' +export { merge } from 'rxjs/internal/observable/merge' +export { of } from 'rxjs/internal/observable/of' +export { throwError as throw } from 'rxjs/internal/observable/throwError' +export { ConnectableObservable } from 'rxjs/internal/observable/ConnectableObservable' + +export { catchError as catch } from 'rxjs/internal/operators/catchError' +export { concatAll } from 'rxjs/internal/operators/concatAll' +export { concatMap } from 'rxjs/internal/operators/concatMap' +export { filter } from 'rxjs/internal/operators/filter' +export { finalize } from 'rxjs/internal/operators/finalize' +export { map } from 'rxjs/internal/operators/map' +export { mapTo } from 'rxjs/internal/operators/mapTo' +export { mergeAll } from 'rxjs/internal/operators/mergeAll' +export { mergeMap } from 'rxjs/internal/operators/mergeMap' +export { publish } from 'rxjs/internal/operators/publish' +export { publishReplay } from 'rxjs/internal/operators/publishReplay' +export { reduce } from 'rxjs/internal/operators/reduce' +export { refCount } from 'rxjs/internal/operators/refCount' +export { startWith } from 'rxjs/internal/operators/startWith' +export { switchMap } from 'rxjs/internal/operators/switchMap' +export { take } from 'rxjs/internal/operators/take' +export { takeLast } from 'rxjs/internal/operators/takeLast' +export { takeUntil } from 'rxjs/internal/operators/takeUntil' +export { tap } from 'rxjs/internal/operators/tap' + +export { BehaviorSubject } from 'rxjs/internal/BehaviorSubject' +export { Observable } from 'rxjs/internal/Observable' +export { ReplaySubject } from 'rxjs/internal/ReplaySubject' +export { Subject } from 'rxjs/internal/Subject' +export { Subscription } from 'rxjs/internal/Subscription' + +export { OperatorFunction } from 'rxjs/internal/types' + +export { ajax } from 'rxjs/internal/observable/dom/ajax' +export { AjaxError } from 'rxjs/internal/observable/dom/AjaxObservable' diff --git a/src/sockets/EventMaps.ts b/src/sockets/EventMaps.ts index 81b0cf685..f4b52929e 100644 --- a/src/sockets/EventMaps.ts +++ b/src/sockets/EventMaps.ts @@ -1,6 +1,4 @@ -import 'rxjs/add/observable/from' -import 'rxjs/add/operator/mergeAll' -import { Observable } from 'rxjs/Observable' +import { from, of, merge, mergeAll, Observable } from '../rx' import { RequestEvent } from 'snapper-consumer' import { Database } from 'reactivedb' import { Net } from '../Net' @@ -22,7 +20,7 @@ export const createMsgHandler = ( msg: ParsedWSMsg ): Observable => { proxy.apply(msg) - return Observable.of(null) + return of(null) } /** @@ -37,7 +35,7 @@ export const createMsgToDBHandler = ( ): Observable => { const tabInfo = mapToTable.getTableInfo(msg.type) if (!tabInfo) { - return Observable.of(null) + return of(null) } const { method, id, data } = msg @@ -61,7 +59,7 @@ export const createMsgToDBHandler = ( where: Array.isArray(data) ? { [pkName]: { $in: data } } : { [pkName]: data } }) default: - return Observable.of(null) + return of(null) } } @@ -87,14 +85,13 @@ export function socketHandler( let interceptorsTask$: Observable if (!db) { net.bufferSocketPush(msg) - interceptorsTask$ = Observable.of(null) + interceptorsTask$ = of(null) } else { interceptorsTask$ = handleMsgToDb(msg, db) } - return Observable.merge(interceptorsTask$, proxyTask$) + return merge(interceptorsTask$, proxyTask$) }) - return Observable.from(signals) - .mergeAll() + return from(signals).pipe(mergeAll()) } diff --git a/src/sockets/Middleware.ts b/src/sockets/Middleware.ts index 4709d4c43..de85c3019 100644 --- a/src/sockets/Middleware.ts +++ b/src/sockets/Middleware.ts @@ -1,13 +1,5 @@ -import 'rxjs/add/operator/publish' -import 'rxjs/add/operator/takeUntil' -import 'rxjs/add/operator/takeLast' -import 'rxjs/add/observable/merge' +import { merge, publish, refCount, switchMap, takeLast, takeUntil, ConnectableObservable, Observable, Subject, Subscription } from '../rx' import { Database } from 'reactivedb' -import { Observable } from 'rxjs/Observable' -import { Observer } from 'rxjs/Observer' -import { Subscription } from 'rxjs/Subscription' -import { ConnectableObservable } from 'rxjs/observable/ConnectableObservable' -import { Subject } from 'rxjs/Subject' import { forEach, ParsedWSMsg, createProxy, eventToRE, WSMsgToDBHandler } from '../utils' @@ -175,7 +167,7 @@ export class Proxy { // 当订阅数降到 0 时,移除该条目 this.publishedHandler.delete(pattern) }) - this.publishedHandler.set(pattern, source.publish().refCount()) + this.publishedHandler.set(pattern, source.pipe(publish(), refCount())) } return this.publishedHandler.get(pattern)! } @@ -190,16 +182,16 @@ export class Proxy { if (!/^:refresh:/.test(pattern)) { pattern = `:refresh:${pattern}` } - return Observable.create((observer: Observer) => { + return new Observable((observer) => { return this.onRefreshEvent(pattern, appNamespace, (msg) => observer.next(msg)) - }) as Observable + }) } /** * 结合 on/off 方法,创建一个监听符合 pattern 事件的流,并包含 teardown 逻辑。 */ private createMsg$(pattern: string, teardown?: MsgHandlerRemoval): Observable { - return Observable.create((observer: Observer) => { + return new Observable((observer) => { const nexter: MsgHandler = (msg) => observer.next(msg) const off = this.on(pattern, nexter) @@ -217,10 +209,10 @@ export class Proxy { const start$ = new Subject() const suspend$ = new Subject() - const published$ = Observable.merge( - suspend$.switchMap(() => this.createMsg$(pattern).takeUntil(start$).takeLast(1)), - start$.switchMap(() => this.createMsg$(pattern).takeUntil(suspend$)) - ).publish() + const published$ = merge( + suspend$.pipe(switchMap(() => this.createMsg$(pattern).pipe(takeUntil(start$), takeLast(1)))), + start$.pipe(switchMap(() => this.createMsg$(pattern).pipe(takeUntil(suspend$)))) + ).pipe(publish()) as ConnectableObservable const connection = published$.connect() diff --git a/src/sockets/SocketClient.ts b/src/sockets/SocketClient.ts index 6ce835911..14c86e993 100644 --- a/src/sockets/SocketClient.ts +++ b/src/sockets/SocketClient.ts @@ -1,13 +1,4 @@ -/** - * bundle socket 的时候,这个文件是 tsc 的一个 entry - * import 一下需要的 Rx 操作符 - */ -import 'rxjs/add/operator/catch' -import 'rxjs/add/operator/toPromise' -import 'rxjs/add/operator/concatMap' -import 'rxjs/add/operator/take' -import { Observable } from 'rxjs/Observable' -import { ReplaySubject } from 'rxjs/ReplaySubject' +import { of, take, Observable, ReplaySubject } from '../rx' import { Net } from '../Net' import { Database } from 'reactivedb' import { SDKFetch } from '../SDKFetch' @@ -63,7 +54,7 @@ export class SocketClient { this.interceptors = new Interceptors(createMsgToDBHandler(mapToTable)) this.handleMsgToDB = (msg, db) => { const ret = this.interceptors.apply(msg, db) - return ret instanceof Observable ? ret : Observable.of(null) + return ret instanceof Observable ? ret : of(null) } this.net.initMsgToDBHandler(this.handleMsgToDB) @@ -107,9 +98,7 @@ export class SocketClient { } async connect(): Promise { - const userMe = await this._getUserMeStream - .take(1) - .toPromise() + const userMe = await this._getUserMeStream.pipe(take(1)).toPromise() const auth = userMe.tcmToken.split('.')[1] const token: { exp: number @@ -165,8 +154,7 @@ export class SocketClient { } private _connect(): Promise { - return this._getUserMeStream - .take(1) + return this._getUserMeStream.pipe(take(1)) .toPromise() .then(userMe => { if (this._client) { diff --git a/src/sockets/interceptor/like-message.ts b/src/sockets/interceptor/like-message.ts index e9c875ac2..e1a1f5f70 100644 --- a/src/sockets/interceptor/like-message.ts +++ b/src/sockets/interceptor/like-message.ts @@ -1,5 +1,4 @@ -import 'rxjs/add/observable/forkJoin' -import { Observable } from 'rxjs/Observable' +import { forkJoin, Observable } from '../../rx' import { ExecutorResult } from 'reactivedb' import { MsgToDBHandler } from '../Middleware' import { mapMsgTypeToTable } from '../MapToTable' @@ -32,5 +31,5 @@ export const redirectLike: MsgToDBHandler = (msg, db) => { ops.push(db.upsert(task.tabName, { ...data, [task.pkName]: id })) } - return Observable.forkJoin(ops) + return forkJoin(ops) } diff --git a/src/utils/internalTypes.ts b/src/utils/internalTypes.ts index a5da2075c..b8a2c3f61 100644 --- a/src/utils/internalTypes.ts +++ b/src/utils/internalTypes.ts @@ -4,7 +4,7 @@ */ import { Database, SchemaDef } from 'reactivedb' -import { Observable } from 'rxjs/Observable' +import { Observable } from '../rx' export type GeneralSchemaDef = SchemaDef<{}> diff --git a/test/SDKFetch.spec.ts b/test/SDKFetch.spec.ts index e6d341ac3..853787521 100644 --- a/test/SDKFetch.spec.ts +++ b/test/SDKFetch.spec.ts @@ -1,8 +1,10 @@ import { expect } from 'chai' -import { Observable, Scheduler } from 'rxjs' import { describe, it, beforeEach, afterEach } from 'tman' +import { asapScheduler, concat, defer, empty, forkJoin, merge, of, timer, Observable } from 'rxjs' +import { catchError, delay, subscribeOn, switchMap, tap, take } from 'rxjs/operators' import { SDKFetch, forEach, Http, HttpErrorMessage, headers2Object } from '.' import { clone } from './' +import { tapAsap } from './utils' import { defaultSDKFetchHeaders, HttpHeaders } from '../src/SDKFetch' @@ -111,26 +113,25 @@ describe('SDKFetch', () => { fetchMock.get(urlMatcher, {}) // 无 query 的 GET - yield sdkFetch.get(path) - .subscribeOn(Scheduler.asap) - .do(() => { + yield sdkFetch.get(path).pipe( + tapAsap(() => { const delimiter = '?_=' const [prefix, timestamp] = fetchMock.lastUrl(urlMatcher).split(delimiter, 2) expect(prefix).to.equal(testUrl) expect(new Date(Number(timestamp)).valueOf()).to.closeTo(new Date().valueOf(), 100) }) + ) // 带 query 的 GET const query = { value: 'A' } const urlWithQuery = testUrl + '?value=A' - yield sdkFetch.get(path, query) - .subscribeOn(Scheduler.asap) - .do(() => { + yield sdkFetch.get(path, query).pipe( + tapAsap(() => { const delimiter = '&_=' const [prefix, timestamp] = fetchMock.lastUrl(urlMatcher).split(delimiter, 2) expect(prefix).to.equal(urlWithQuery) expect(new Date(Number(timestamp)).valueOf()).to.closeTo(new Date().valueOf(), 100) - }) + })) }) it('get with empty query object should work correctly', function* () { @@ -145,44 +146,49 @@ describe('SDKFetch', () => { for (const query of emptyQueryObjects) { yield sdkFetch.get(path, query) - .subscribeOn(Scheduler.asap) - .do(() => { - const [beforeTimestamp] = fetchMock.lastUrl(urlMatcher).split('_=') - expect(beforeTimestamp).to.equal(testUrl + '?') - }) + .pipe( + tapAsap(() => { + const [beforeTimestamp] = fetchMock.lastUrl(urlMatcher).split('_=') + expect(beforeTimestamp).to.equal(testUrl + '?') + }) + ) } }) it('should re-use a matching request A if A is in progress', function* () { fetchMock.mock(urlMatcher, { body: { 'A': 'aaaa' } }) - const getA = sdkFetch.get(path, { value: 'A' }).delay(20) + const getA = sdkFetch.get(path, { value: 'A' }).pipe(delay(20)) const getAImmediatelyAfter = sdkFetch.get(path, { value: 'A' }) - yield Observable.merge(getA, getAImmediatelyAfter) - .take(2) - .subscribeOn(Scheduler.asap) + yield merge(getA, getAImmediatelyAfter) + .pipe( + take(2), + subscribeOn(asapScheduler) + ) - yield Observable.of(fetchMock.calls(urlMatcher).length) - .do((numberOfRequestsReceived) => { + yield of(fetchMock.calls(urlMatcher).length) + .pipe(tap((numberOfRequestsReceived) => { expect(numberOfRequestsReceived).to.equal(1) - }) + })) }) it('shouldn not re-use a matching request A if A is in finished', function* () { fetchMock.mock(urlMatcher, { body: { 'A': 'aaaa' } }) const getA = sdkFetch.get(path, { value: 'A' }) - const getAAWhileAfter = Observable.defer(() => sdkFetch.get(path, { value: 'A' })) + const getAAWhileAfter = defer(() => sdkFetch.get(path, { value: 'A' })) - yield Observable.concat(getA, Observable.timer(40), getAAWhileAfter) - .take(3) - .subscribeOn(Scheduler.asap) + yield concat(getA, timer(40), getAAWhileAfter) + .pipe( + take(3), + subscribeOn(asapScheduler) + ) - yield Observable.of(fetchMock.calls(urlMatcher).length) - .do((numberOfRequestsReceived) => { + yield of(fetchMock.calls(urlMatcher).length) + .pipe(tap((numberOfRequestsReceived) => { expect(numberOfRequestsReceived).to.equal(2) - }) + })) }) allowedMethods.forEach((httpMethod: string) => { @@ -204,11 +210,12 @@ describe('SDKFetch', () => { break } - yield Observable.forkJoin(httpObj.send(), raw) - .subscribeOn(Scheduler.asap) - .do(([respFromHttpObj, respFromRaw]) => { - expect(respFromHttpObj).to.deep.equal(respFromRaw) - }) + yield forkJoin(httpObj.send(), raw) + .pipe( + tapAsap(([respFromHttpObj, respFromRaw]) => { + expect(respFromHttpObj).to.deep.equal(respFromRaw) + }) + ) }) }) @@ -239,11 +246,12 @@ describe('SDKFetch', () => { } yield withRespHeaders$ - .subscribeOn(Scheduler.asap) - .do((resp) => { - expect(resp.body).to.deep.equal(responseData) - expect(resp.headers.get('x-request-id')).to.equal(sampleValue) - }) + .pipe( + tapAsap((resp) => { + expect(resp.body).to.deep.equal(responseData) + expect(resp.headers.get('x-request-id')).to.equal(sampleValue) + }) + ) }) }) @@ -263,20 +271,22 @@ describe('SDKFetch', () => { .setAPIHost(apiHost) yield sdkFetch[httpMethod](path, httpMethod === 'get' ? null : body) - .catch((info: HttpErrorMessage) => { - expect(info.error.status).to.equal(status) - expect(info.error.headers.get('hello')).to.equal('world') - expect(info.method).to.equal(httpMethod) - expect(info.url).to.equal(fetchMock.lastUrl(urlMatcher)) - if (httpMethod === 'get') { - expect(info.body).to.be.undefined - } else { - expect(info.body).to.deep.equal(body) - } - expect(info.requestId).to.equal(fetchMock.lastOptions(urlMatcher).headers[HttpHeaders.Key.RequestId]) - return Observable.empty() - }) - .subscribeOn(Scheduler.asap) + .pipe( + catchError((info: HttpErrorMessage) => { + expect(info.error.status).to.equal(status) + expect(info.error.headers.get('hello')).to.equal('world') + expect(info.method).to.equal(httpMethod) + expect(info.url).to.equal(fetchMock.lastUrl(urlMatcher)) + if (httpMethod === 'get') { + expect(info.body).to.be.undefined + } else { + expect(info.body).to.deep.equal(body) + } + expect(info.requestId).to.equal(fetchMock.lastOptions(urlMatcher).headers[HttpHeaders.Key.RequestId]) + return empty() + }), + subscribeOn(asapScheduler) + ) }) }) }) @@ -304,13 +314,14 @@ describe('SDKFetch options', () => { fetchMock.mock(new RegExp(newHost), {}) yield getCustomizedRequest() - .subscribeOn(Scheduler.asap) - .do(() => { - expect(fetchMock.lastOptions()).to.deep.equal({ - method: httpMethod, - ...newMockOptions + .pipe( + tapAsap(() => { + expect(fetchMock.lastOptions()).to.deep.equal({ + method: httpMethod, + ...newMockOptions + }) }) - }) + ) } beforeEach(() => { @@ -346,12 +357,13 @@ describe('SDKFetch options', () => { .setOptions(newOption) yield sdkFetch[httpMethod](path, undefined, { disableRequestId: true } ) - .subscribeOn(Scheduler.asap) - .do(() => { - expect(fetchMock.lastOptions().headers).to.deep.equal({ - ...defaultSDKFetchHeaders() + .pipe( + tapAsap(() => { + expect(fetchMock.lastOptions().headers).to.deep.equal({ + ...defaultSDKFetchHeaders() + }) }) - }) + ) }) }) @@ -379,7 +391,7 @@ describe('SDKFetch options', () => { .setOptions(newOption) return sdkFetch[httpMethod1](path) - .switchMap(() => sdkFetch[httpMethod2](path)) + .pipe(switchMap(() => sdkFetch[httpMethod2](path))) }) }) }) @@ -405,12 +417,13 @@ describe('SDKFetch options', () => { yield sdkFetch[httpMethod](path, undefined, { headers: { ...newHeader, merge: true }, }) - .subscribeOn(Scheduler.asap) - .do(() => { - expect(fetchMock.lastOptions().headers).to.deep.equal({ - ...defaultSDKFetchHeaders(), ...newHeader + .pipe( + tapAsap(() => { + expect(fetchMock.lastOptions().headers).to.deep.equal({ + ...defaultSDKFetchHeaders(), ...newHeader + }) }) - }) + ) }) }) @@ -432,7 +445,7 @@ describe('SDKFetch options', () => { .setOptions(newOption) return sdkFetch[httpMethod1](path, undefined, perRequestOptions) - .switchMap(() => sdkFetch[httpMethod2](path)) + .pipe(switchMap(() => sdkFetch[httpMethod2](path))) }) }) }) @@ -447,10 +460,11 @@ describe('SDKFetch options', () => { .setHeaders({ hello: 'world' }) yield sdkFetch[httpMethod](path) - .subscribeOn(Scheduler.asap) - .do(() => { - expect(Boolean(fetchMock.lastOptions().headers[HttpHeaders.Key.RequestId])).to.be.true - }) + .pipe( + tapAsap(() => { + expect(Boolean(fetchMock.lastOptions().headers[HttpHeaders.Key.RequestId])).to.be.true + }) + ) }) }) @@ -467,12 +481,13 @@ describe('SDKFetch options', () => { merge: true, [HttpHeaders.Key.RequestId]: userDefinedRequestId } }) - .subscribeOn(Scheduler.asap) - .do(() => { - expect(fetchMock.lastOptions().headers).to.deep.equal({ - hello: 'world', [HttpHeaders.Key.RequestId]: userDefinedRequestId + .pipe( + tapAsap(() => { + expect(fetchMock.lastOptions().headers).to.deep.equal({ + hello: 'world', [HttpHeaders.Key.RequestId]: userDefinedRequestId + }) }) - }) + ) }) }) @@ -489,11 +504,13 @@ describe('SDKFetch options', () => { merge: true, [HttpHeaders.Key.RequestId]: userDefinedRequestId } }) - .catch((info: HttpErrorMessage) => { - expect(info.requestId).to.equal(String(userDefinedRequestId)) - return Observable.empty() - }) - .subscribeOn(Scheduler.asap) + .pipe( + catchError((info: HttpErrorMessage) => { + expect(info.requestId).to.equal(String(userDefinedRequestId)) + return empty() + }), + subscribeOn(asapScheduler) + ) }) }) diff --git a/test/apis/customfieldlink.spec.ts b/test/apis/customfieldlink.spec.ts index 170505c5e..49db5a7db 100644 --- a/test/apis/customfieldlink.spec.ts +++ b/test/apis/customfieldlink.spec.ts @@ -1,10 +1,9 @@ import { describe, before, beforeEach, afterEach, it, after } from 'tman' -import { Scheduler } from 'rxjs' import { expect } from 'chai' import { SDKFetch, createSdk, SDK } from '../' import { customFieldLink } from '../fixtures/customfieldlinks.fixture' -import { mock, expectToDeepEqualForFieldsOfTheExpected } from '../utils' +import { mock, expectToDeepEqualForFieldsOfTheExpected, tapAsap } from '../utils' import { ProjectId } from 'teambition-types' const fetchMock = require('fetch-mock') @@ -37,8 +36,9 @@ describe('CustomFieldLinkApi request spec: ', () => { fetchMock.once(url, customFieldLinks) yield sdkFetch.getCustomFieldLinks(projectId, 'application') - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(customFieldLinks)) + .pipe(tapAsap( + (result) => expect(result).to.deep.equal(customFieldLinks)) + ) }) }) @@ -58,9 +58,8 @@ describe('CustomFieldLinkApi spec: ', () => { yield sdk.getCustomFieldLinks(projectId, 'application') .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, customFieldLinks[0]) - }) + .pipe(tapAsap( + ([ result ]) => expectToDeepEqualForFieldsOfTheExpected(result, customFieldLinks[0]) + )) }) }) diff --git a/test/apis/event/event.spec.ts b/test/apis/event/event.spec.ts index e02a0c9f0..8e9886c6a 100644 --- a/test/apis/event/event.spec.ts +++ b/test/apis/event/event.spec.ts @@ -1,4 +1,5 @@ import * as moment from 'moment' +import { take, tap } from 'rxjs/operators' import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' import { createSdk, SDK, SocketMock, EventSchema } from '../../index' @@ -25,10 +26,10 @@ describe('EventApi request spec', () => { yield sdk.getEvent(fixture._id as EventId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { const result = r.next().value equals(result, fixture) - }) + })) }) it('should get recurrnece event', function* () { @@ -37,22 +38,22 @@ describe('EventApi request spec', () => { yield sdk.getEvent(fixture._id as EventId) .values() - .do(([r]) => { - const result = r.next().value + .pipe(tap(([r]) => { + const result = r.next().value! const _id = fixture._id delete result._id delete fixture._id equals(result, fixture) - const next = r.next().value + const next = r.next().value! expect(next.sourceDate).to.equal(fixture.startDate) expect(next.startDate).to.equal(moment(fixture.startDate).add(1, 'month').toISOString()) expect(next.endDate).to.equal(moment(fixture.endDate).add(1, 'month').toISOString()) - const next2 = r.next().value + const next2 = r.next().value! expect(next2.sourceDate).to.equal(fixture.startDate) expect(next2.startDate).to.equal(moment(fixture.startDate).add(2, 'month').toISOString()) expect(next2.endDate).to.equal(moment(fixture.endDate).add(2, 'month').toISOString()) fixture._id = _id - }) + })) }) it('should observe recurrnece event change', function* () { @@ -64,7 +65,7 @@ describe('EventApi request spec', () => { signal.subscribe() - yield signal.take(1) + yield signal.pipe(take(1)) const mockContent = 'mockContent' @@ -74,10 +75,12 @@ describe('EventApi request spec', () => { content: mockContent }) - yield signal.take(1) - .do(([r]) => { + yield signal.pipe( + take(1), + tap(([r]) => { expect(r.next().value.content).to.equal(mockContent) }) + ) }) it('should combine two QueryToken', function* () { @@ -94,13 +97,13 @@ describe('EventApi request spec', () => { yield token1.combine(token2) .values() - .do(([r1, r2]) => { - const result1 = r1.next().value - const result2 = r2.next().value + .pipe(tap(([r1, r2]) => { + const result1 = r1.next().value! + const result2 = r2.next().value! delete result1._id delete result2._id expect(result1).to.deep.equal(result2) - }) + })) }) }) @@ -124,9 +127,9 @@ describe('EventsAPI socket spec', () => { yield sdk.database.get('Event', { where: { _id: fixture._id } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { looseDeepEqual(r, fixture) - }) + })) }) it('update event should change cache', function* () { @@ -141,7 +144,7 @@ describe('EventsAPI socket spec', () => { yield sdk.database.get('Event', { where: { _id: fixture._id } }) .values() - .do(([r]) => expect(r.content).to.equal('fixture')) + .pipe(tap(([r]) => expect(r.content).to.equal('fixture'))) }) it('delete event should delete cache', function* () { @@ -153,6 +156,6 @@ describe('EventsAPI socket spec', () => { yield sdk.database.get('Event', { where: { _id: fixture._id } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) }) diff --git a/test/apis/file.spec.ts b/test/apis/file.spec.ts index 20e835c23..21047bfd6 100644 --- a/test/apis/file.spec.ts +++ b/test/apis/file.spec.ts @@ -1,5 +1,6 @@ import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' +import { tap } from 'rxjs/operators' import { createSdk, SDK, SocketMock, FileSchema } from '../index' import * as Fixture from '../fixtures/files.fixture' import { mock, restore, looseDeepEqual, expectToDeepEqualForFieldsOfTheExpected } from '../utils' @@ -24,9 +25,9 @@ describe('FileApi request spec', () => { yield sdk.getFile(fixture._id as FileId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expectToDeepEqualForFieldsOfTheExpected(r, fixture) - }) + })) }) }) @@ -50,9 +51,9 @@ describe('FileApi socket spec', () => { yield sdk.database.get('File', { where: { _id: fixture._id } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { looseDeepEqual(r, fixture) - }) + })) }) it('update file should change cache', function* () { @@ -67,7 +68,7 @@ describe('FileApi socket spec', () => { yield sdk.database.get('File', { where: { _id: fixture._id } }) .values() - .do(([r]) => expect(r.fileName).to.equal('fixture')) + .pipe(tap(([r]) => expect(r.fileName).to.equal('fixture'))) }) it('delete file should delete cache', function* () { @@ -79,6 +80,6 @@ describe('FileApi socket spec', () => { yield sdk.database.get('File', { where: { _id: fixture._id } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) }) diff --git a/test/apis/like.spec.ts b/test/apis/like.spec.ts index 86ea648cb..00cf8a365 100644 --- a/test/apis/like.spec.ts +++ b/test/apis/like.spec.ts @@ -1,6 +1,7 @@ 'use strict' import { expect } from 'chai' import { describe, it, beforeEach, afterEach } from 'tman' +import { tap } from 'rxjs/operators' import { createSdk, SDK, LikeSchema } from '../index' import like from '../fixtures/like.fixture' import { mock, restore } from '../utils' @@ -26,10 +27,10 @@ describe('LikeApi request spec: ', () => { yield sdk.getLike('task', mockTaskId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { delete r._id expect(r).to.deep.equal(like) - }) + })) }) it('toggle like should pass', function* () { @@ -46,9 +47,9 @@ describe('LikeApi request spec: ', () => { where: { _id: mockTaskLikeId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r.isLike).to.be.false - }) + })) mockResponse({ ...like, isLike: true }) @@ -58,8 +59,8 @@ describe('LikeApi request spec: ', () => { where: { _id: mockTaskLikeId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r.isLike).to.be.true - }) + })) }) }) diff --git a/test/apis/my.spec.ts b/test/apis/my.spec.ts index e6372f628..71b6621f3 100644 --- a/test/apis/my.spec.ts +++ b/test/apis/my.spec.ts @@ -1,5 +1,6 @@ -import { describe, it, beforeEach, afterEach } from 'tman' import { expect } from 'chai' +import { describe, it, beforeEach, afterEach } from 'tman' +import { tap } from 'rxjs/operators' import { createSdk, SDK, TaskSchema } from '../index' import { EventGenerator } from '../../src/apis/event/EventGenerator' import * as Fixture from '../fixtures/my.fixture' @@ -29,7 +30,7 @@ describe('MyApi request spec', () => { }) yield token.values() - .do(r => { + .pipe(tap(r => { const compareFn = (x: any, y: any) => { return new Date(x.updated).valueOf() - new Date(y.updated).valueOf() + new Date(x.created).valueOf() - new Date(y.created).valueOf() @@ -56,7 +57,7 @@ describe('MyApi request spec', () => { expected.forEach((expectedResult, i) => { expectToDeepEqualForFieldsOfTheExpected(actual[i], expectedResult) }) - }) + })) }) it('should get my count', function* () { diff --git a/test/apis/organization.spec.ts b/test/apis/organization.spec.ts index b7537da70..6c6bb70f1 100644 --- a/test/apis/organization.spec.ts +++ b/test/apis/organization.spec.ts @@ -1,7 +1,7 @@ import { describe, before, beforeEach, it, afterEach, after } from 'tman' import { expect } from 'chai' -import { Scheduler } from 'rxjs' import { SDKFetch } from '../' +import { tapAsap } from '../utils' import { getAllOrganizationProjects, getJoinedOrganizationProjects, @@ -64,10 +64,9 @@ describe('get organization projects', () => { fetchMock.getOnce(expectedUrl, expectedResponse) yield fn.call(sdkFetch, sampleOrgId) - .subscribeOn(Scheduler.asap) - .do((x: any) => { - expect(x).to.deep.equal(expectedResponse) - }) + .pipe(tapAsap( + (x: any) => expect(x).to.deep.equal(expectedResponse) + )) }) }) @@ -79,10 +78,9 @@ describe('get organization projects', () => { fetchMock.getOnce(expectedUrl, expectedResponse) yield sdkFetch.getOrganizationProjectsByTagId(sampleOrgId, sampleTagId) - .subscribeOn(Scheduler.asap) - .do((x: any) => { - expect(x).to.deep.equal(expectedResponse) - }) + .pipe(tapAsap( + (x: any) => expect(x).to.deep.equal(expectedResponse) + )) }) }) diff --git a/test/apis/post.spec.ts b/test/apis/post.spec.ts index 4d9f738d8..0b8de2f24 100644 --- a/test/apis/post.spec.ts +++ b/test/apis/post.spec.ts @@ -1,5 +1,6 @@ -import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' +import { describe, beforeEach, afterEach, it } from 'tman' +import { tap } from 'rxjs/operators' import { createSdk, SDK, PostSchema, SocketMock } from '../index' import { projectPosts, myProjectPosts, tagPosts } from '../fixtures/posts.fixture' import { mock, restore, equals } from '../utils' @@ -32,9 +33,9 @@ describe('PostApi request spec', () => { yield sdk.getPost(fixture._id as PostId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r).to.deep.equal(fixture) - }) + })) }) it('getAllProjects should response correct data', function* () { @@ -49,9 +50,9 @@ describe('PostApi request spec', () => { count: 20 }) .values() - .do(r => { + .pipe(tap(r => { expect(r).to.deep.equal(fixture) - }) + })) const fixture2 = projectPosts.slice(20, 40) @@ -63,9 +64,9 @@ describe('PostApi request spec', () => { count: 20 }) .values() - .do(r => { + .pipe(tap(r => { expect(r).to.deep.equal(fixture2) - }) + })) }) it('getAllProjects should response ordered data', function* () { @@ -82,9 +83,9 @@ describe('PostApi request spec', () => { orderBy: defaultOrderBy }) .values() - .do(r => { + .pipe(tap(r => { expect(r).to.deep.equal(fixture) - }) + })) }) it('getMyProjectPosts should response correct data', function* () { @@ -100,9 +101,9 @@ describe('PostApi request spec', () => { type: 'my' }) .values() - .do(r => { + .pipe(tap(r => { expect(r).to.deep.equal(fixture) - }) + })) const fixture2 = myProjectPosts.slice(20) @@ -114,7 +115,7 @@ describe('PostApi request spec', () => { type: 'my' }) .values() - .do(r => expect(r).to.deep.equal(fixture2)) + .pipe(tap(r => expect(r).to.deep.equal(fixture2))) }) it('getMyProjectPosts should response ordered data', function* () { @@ -132,9 +133,9 @@ describe('PostApi request spec', () => { orderBy: defaultOrderBy }) .values() - .do(r => { + .pipe(tap(r => { expect(r).to.deep.equal(fixture) - }) + })) }) it('getPostsByTagId should response correct data', function* () { @@ -147,7 +148,7 @@ describe('PostApi request spec', () => { count: 500 }) .values() - .do(r => expect(r).to.deep.equal(tagPosts)) + .pipe(tap(r => expect(r).to.deep.equal(tagPosts))) }) it('getPostsByTagId should response ordered data', function* () { @@ -162,7 +163,7 @@ describe('PostApi request spec', () => { orderBy: defaultOrderBy }) .values() - .do(r => expect(r).to.deep.equal(tagPosts)) + .pipe(tap(r => expect(r).to.deep.equal(tagPosts))) }) it('createPost should create new post', function* () { @@ -179,9 +180,9 @@ describe('PostApi request spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { equals(r, fixture) - }) + })) }) it('updatePost should update cache in ReactiveDB', function* () { @@ -200,7 +201,7 @@ describe('PostApi request spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do(([r]) => expect(r.title).to.equal(fixture.title)) + .pipe(tap(([r]) => expect(r.title).to.equal(fixture.title))) }) it('deletePost should delete cache in ReactiveDB', function* () { @@ -214,7 +215,7 @@ describe('PostApi request spec', () => { yield sdk.database.get('Post', { where: { _id: placeholder._id } }) .values() - .do(r => expect(r.length).to.equal(0)) + .pipe(tap(r => expect(r.length).to.equal(0))) }) }) @@ -238,7 +239,7 @@ describe('PostsAPI socket spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do((r) => equals(r, [ fixture ])) + .pipe(tap((r) => equals(r, [ fixture ]))) }) it('should do response for socket::change', function* () { @@ -254,7 +255,7 @@ describe('PostsAPI socket spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do(([r]) => expect(r.content).to.equal('fixture')) + .pipe(tap(([r]) => expect(r.content).to.equal('fixture'))) }) it('should do response for socket::destory', function* () { @@ -266,6 +267,6 @@ describe('PostsAPI socket spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) }) diff --git a/test/apis/project.spec.ts b/test/apis/project.spec.ts index fd0350d28..476b31204 100644 --- a/test/apis/project.spec.ts +++ b/test/apis/project.spec.ts @@ -1,12 +1,12 @@ import { describe, before, beforeEach, it, afterEach, after } from 'tman' import { expect } from 'chai' -import { Scheduler } from 'rxjs' +import { asapScheduler } from 'rxjs' import { GetPersonalProjectsQueryParams } from '../../src/apis/project/personal' import { SDKFetch, createSdk, SDK } from '../' import { normalProject } from '../fixtures/projects.fixture' -import { mock, expectToDeepEqualForFieldsOfTheExpected } from '../utils' +import { mock, expectToDeepEqualForFieldsOfTheExpected, tapAsap } from '../utils' import { ProjectId } from 'teambition-types' const fetchMock = require('fetch-mock') @@ -78,10 +78,9 @@ describe('get personal projects', () => { } yield sdkFetch.getPersonalProjects(params as any) - .subscribeOn(Scheduler.asap) - .do((x: any) => { - expect(x).to.deep.equal(expectedResponse) - }) + .pipe(tapAsap( + (x: any) => expect(x).to.deep.equal(expectedResponse) + )) }) }) }) @@ -115,8 +114,9 @@ describe('ProjectApi request spec: ', () => { fetchMock.getOnce(url, project) yield sdkFetch.getProject(projectId) - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(project)) + .pipe(tapAsap( + (result) => expect(result).to.deep.equal(project) + )) }) }) @@ -136,9 +136,8 @@ describe('ProjectApi spec: ', () => { yield sdk.getProject(fixture._id as ProjectId) .values() - .subscribeOn(Scheduler.asap) - .do(([project]) => { - expectToDeepEqualForFieldsOfTheExpected(project, fixture, 'organization', 'role', 'creator', 'isTemplate') - }) + .pipe(tapAsap( + ([ project ]) => expectToDeepEqualForFieldsOfTheExpected(project, fixture, 'organization', 'role', 'creator', 'isTemplate') + )) }) }) diff --git a/test/apis/scenariofieldconfig.spec.ts b/test/apis/scenariofieldconfig.spec.ts index b12e40535..ef5b6c7fc 100644 --- a/test/apis/scenariofieldconfig.spec.ts +++ b/test/apis/scenariofieldconfig.spec.ts @@ -1,15 +1,14 @@ import { describe, before, beforeEach, afterEach, it, after } from 'tman' -import { Scheduler } from 'rxjs' import { expect } from 'chai' -import { SDKFetch, createSdk, SDK, ScenarioFieldConfigSchema } from '../' +import { SDKFetch, createSdk, SDK } from '../' import { taskScenarioFieldConfig, eventScenarioFieldConfig, orgTaskScenarioFieldConfig, orgEventScenarioFieldConfig } from '../fixtures/scenariofieldconfigs.fixture' -import { mock, expectToDeepEqualForFieldsOfTheExpected } from '../utils' +import { mock, expectToDeepEqualForFieldsOfTheExpected, tapAsap } from '../utils' import { OrganizationId, ProjectId, ScenarioFieldConfigId } from 'teambition-types' const fetchMock = require('fetch-mock') @@ -42,8 +41,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.once(url, configs) yield sdkFetch.getScenarioFieldConfigs(projectId, 'task', true) - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(configs)) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(configs)))) }) it('should return an EventScenarioFieldConfig array', function* () { @@ -54,8 +52,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.once(url, configs) yield sdkFetch.getScenarioFieldConfigs(projectId, 'event', true) - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(configs)) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(configs)))) }) it('should return a TaskScenarioFieldConfig array bound to Organization', function* () { @@ -66,8 +63,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.once(url, { result: configs, nextPageToken: '' }) yield sdkFetch.getOrgScenarioFieldConfigs(orgId, 'task', { sort: 'project_desc' }) - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(configs)) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(configs)))) }) it('should return an EventScenarioFieldConfig array bound to Organization', function* () { @@ -78,8 +74,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.once(url, { result: configs, nextPageToken: '' }) yield sdkFetch.getOrgScenarioFieldConfigs(orgId, 'event') - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(configs)) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(configs)))) }) it('should add a TaskScenarioFieldConfig array to Project', function* () { @@ -95,10 +90,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { }, configs) yield sdkFetch.bulkAddScenarioFieldConfigs(projectId, 'task', configIds) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(configs) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(configs)))) }) it('should add an EventScenarioFieldConfig array to Project', function* () { @@ -114,10 +106,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { }, configs) yield sdkFetch.bulkAddScenarioFieldConfigs(projectId, 'event', configIds) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(configs) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(configs)))) }) it('should restore ScenarioFieldConfig to the Base', function* () { @@ -127,10 +116,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.putOnce(`/scenariofieldconfigs/${configId}/restore`, config) yield sdkFetch.restoreScenarioFieldConfig(configId) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(config) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(config)))) }) it('should save ScenarioFieldConfig as the Base', function* () { @@ -139,10 +125,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.putOnce(`/scenariofieldconfigs/${configId}/sync`, {}) yield sdkFetch.syncScenarioFieldConfig(configId) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal({}) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal({})))) }) it('should return an array of Project using the ScenarioFieldConfig', function* () { @@ -152,10 +135,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.once(`/scenariofieldconfigs/${sfcId}/projects?_=666`, resp) yield sdkFetch.getOrgScenarioFieldConfigProjects(sfcId) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(resp) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(resp)))) }) it('should create a new ScenarioFieldConfig', function* () { @@ -166,10 +146,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { fetchMock.postOnce(`/organizations/${orgId}/scenariofieldconfigs`, config) yield sdkFetch.createOrgScenarioFieldConfig(orgId, config) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(config) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(config)))) }) it('should return Boolean as the validation result', function* () { @@ -185,10 +162,7 @@ describe('ScenarioFieldConfigApi request spec: ', () => { objectType, name ) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(resp) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(resp)))) }) }) @@ -209,10 +183,7 @@ describe('ScenarioFieldConfigApi spec: ', () => { yield sdk.getScenarioFieldConfigs(projectId, 'task') .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) }) it('should return an EventScenarioFieldConfig array', function* () { @@ -223,10 +194,7 @@ describe('ScenarioFieldConfigApi spec: ', () => { yield sdk.getScenarioFieldConfigs(projectId, 'event') .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) }) it('should return a TaskScenarioFieldConfig array bound to Organization', function* () { @@ -237,10 +205,7 @@ describe('ScenarioFieldConfigApi spec: ', () => { yield sdk.getOrgScenarioFieldConfigs(organizationId, 'task') .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) }) it('should return an EventScenarioFieldConfig array bound to Organization', function* () { @@ -251,10 +216,7 @@ describe('ScenarioFieldConfigApi spec: ', () => { yield sdk.getOrgScenarioFieldConfigs(organizationId, 'event') .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) }) it('should add a TaskScenarioFieldConfig array to Project', function* () { @@ -268,23 +230,17 @@ describe('ScenarioFieldConfigApi spec: ', () => { const configs$ = sdk.getScenarioFieldConfigs(projectId, 'task') .values() - .subscribeOn(Scheduler.asap) - yield configs$.do((result) => { - expectToDeepEqualForFieldsOfTheExpected(result, []) - }) + yield configs$ + .pipe(tapAsap((result) => expectToDeepEqualForFieldsOfTheExpected(result, []))) mockResponse(configs) yield sdk.bulkAddScenarioFieldConfigs(projectId, 'task', configIds) - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) - - yield configs$.do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) + + yield configs$ + .pipe(tapAsap(([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0]))) }) it('should add an EventScenarioFieldConfig array to Project', function* () { @@ -298,23 +254,17 @@ describe('ScenarioFieldConfigApi spec: ', () => { const configs$ = sdk.getScenarioFieldConfigs(projectId, 'event') .values() - .subscribeOn(Scheduler.asap) - yield configs$.do((result) => { - expectToDeepEqualForFieldsOfTheExpected(result, []) - }) + yield configs$ + .pipe(tapAsap(((result) => expectToDeepEqualForFieldsOfTheExpected(result, [])))) mockResponse(configs) yield sdk.bulkAddScenarioFieldConfigs(projectId, 'event', configIds) - .subscribeOn(Scheduler.asap) - .do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) - - yield configs$.do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) + + yield configs$ + .pipe(tapAsap(([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0]))) }) it('should restore ScenarioFieldConfig to the Base', function* () { @@ -329,23 +279,17 @@ describe('ScenarioFieldConfigApi spec: ', () => { const configs$ = sdk.getScenarioFieldConfigs(projectId, 'event') .values() - .subscribeOn(Scheduler.asap) - yield configs$.do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configs[0]) - }) + yield configs$ + .pipe(tapAsap((([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configs[0])))) mockResponse(configBase) yield sdk.restoreScenarioFieldConfig(configId) - .subscribeOn(Scheduler.asap) - .do((result) => { - expectToDeepEqualForFieldsOfTheExpected(result, configBase) - }) - - yield configs$.do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, configsBase[0]) - }) + .pipe(tapAsap(((result) => expectToDeepEqualForFieldsOfTheExpected(result, configBase)))) + + yield configs$ + .pipe(tapAsap(([result]) => expectToDeepEqualForFieldsOfTheExpected(result, configsBase[0]))) }) it('should save ScenarioFieldConfig as the Base', function* () { @@ -354,10 +298,7 @@ describe('ScenarioFieldConfigApi spec: ', () => { mockResponse({}) yield sdk.syncScenarioFieldConfig(configId) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal({ _id: configId }) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal({ _id: configId })))) }) it('should create a new ScenarioFieldConfig', function* () { @@ -370,22 +311,16 @@ describe('ScenarioFieldConfigApi spec: ', () => { const configs$ = sdk.getOrgScenarioFieldConfigs(orgId, objectType) .values() - .subscribeOn(Scheduler.asap) - yield configs$.do((result) => { - expect(result).to.deep.equal([]) - }) + yield configs$ + .pipe(tapAsap(((result) => expect(result).to.deep.equal([])))) mockResponse(config) yield sdk.createOrgScenarioFieldConfig(orgId, { _boundToObjectId: orgId, objectType } as any) - .subscribeOn(Scheduler.asap) - .do((result) => { - expect(result).to.deep.equal(config) - }) - - yield configs$.do(([result]) => { - expectToDeepEqualForFieldsOfTheExpected(result, config) - }) + .pipe(tapAsap(((result) => expect(result).to.deep.equal(config)))) + + yield configs$ + .pipe(tapAsap(([result]) => expectToDeepEqualForFieldsOfTheExpected(result, config))) }) }) diff --git a/test/apis/search.spec.ts b/test/apis/search.spec.ts index 8c584b4ef..71b0d0955 100644 --- a/test/apis/search.spec.ts +++ b/test/apis/search.spec.ts @@ -1,6 +1,5 @@ import { describe, before, beforeEach, it, afterEach, after } from 'tman' import { expect } from 'chai' -import { Scheduler } from 'rxjs' import { searchMembersInTeam, searchMembersInProject, @@ -10,6 +9,7 @@ import { buildPath as buildPathForMemberSearching } from '../../src/apis/search/members' import { SDKFetch } from '../' +import { tapAsap } from '../utils' import { GroupId, OrganizationId, ProjectId, TeamId } from 'teambition-types' const fetchMock = require('fetch-mock') @@ -103,10 +103,9 @@ describe('search for members', () => { fetchMock.getOnce(`/${namespace}/${sampleId}/members/search?q=&_=666`, expectedResultSet) yield fn.call(sdkFetch, sampleId as any, '') - .subscribeOn(Scheduler.asap) - .do((x: any) => { + .pipe(tapAsap((x: any) => { expect(x).to.deep.equal(expectedResultSet) - }) + })) }) }) @@ -116,10 +115,9 @@ describe('search for members', () => { fetchMock.getOnce(`/${namespace}/${sampleId}/members/search?q=nonExistence&_=666`, expectedResultSet) yield fn.call(sdkFetch, sampleId as any, 'nonExistence') - .subscribeOn(Scheduler.asap) - .do((x: any) => { + .pipe(tapAsap((x: any) => { expect(x).to.deep.equal(expectedResultSet) - }) + })) }) }) @@ -129,10 +127,9 @@ describe('search for members', () => { fetchMock.getOnce(`/${namespace}/${sampleId}/members/search?q=shuai&_=666`, expectedResultSet) yield fn.call(sdkFetch, sampleId as any, 'shuai') - .subscribeOn(Scheduler.asap) - .do((x: any) => { + .pipe(tapAsap((x: any) => { expect(x).to.deep.equal(expectedResultSet) - }) + })) }) }) @@ -140,20 +137,18 @@ describe('search for members', () => { fetchMock.get('/members/search?q=&_=666', allMembers) yield sdkFetch.searchMembers('') - .subscribeOn(Scheduler.asap) - .do((x) => { + .pipe(tapAsap((x) => { expect(x).to.deep.equal(allMembers) - }) + })) }) it('searchMembers should return empty result set as it is', function* () { fetchMock.get('/members/search?q=nonExistence&_=666', []) yield sdkFetch.searchMembers('nonExistence') - .subscribeOn(Scheduler.asap) - .do((x) => { + .pipe(tapAsap((x) => { expect(x).to.deep.equal([]) - }) + })) }) it('searchMembers should handle normal cases correctly', function* () { @@ -161,10 +156,9 @@ describe('search for members', () => { fetchMock.get('/members/search?q=shuai&_=666', expectedResultSet) yield sdkFetch.searchMembers('shuai') - .subscribeOn(Scheduler.asap) - .do((x) => { + .pipe(tapAsap((x) => { expect(x).to.deep.equal(expectedResultSet) - }) + })) }) }) }) diff --git a/test/apis/tag.spec.ts b/test/apis/tag.spec.ts index 7036971bb..0edb07486 100644 --- a/test/apis/tag.spec.ts +++ b/test/apis/tag.spec.ts @@ -1,10 +1,9 @@ import { describe, before, beforeEach, afterEach, it, after } from 'tman' -import { Scheduler } from 'rxjs' import { expect } from 'chai' import { SDKFetch, createSdk, SDK } from '../' import { projectTag, organizationTag } from '../fixtures/tags.fixture' -import { mock, expectToDeepEqualForFieldsOfTheExpected } from '../utils' +import { mock, expectToDeepEqualForFieldsOfTheExpected, tapAsap } from '../utils' import { OrganizationId, ProjectId } from 'teambition-types' const fetchMock = require('fetch-mock') @@ -37,8 +36,7 @@ describe('TagApi request spec: ', () => { fetchMock.once(url, tags) yield sdkFetch.getTags(projectId) - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(tags)) + .pipe(tapAsap((result) => expect(result).to.deep.equal(tags))) }) it('should return an Organization Tag array', function* () { @@ -49,8 +47,7 @@ describe('TagApi request spec: ', () => { fetchMock.once(url, tags) yield sdkFetch.getTags(orgId, 'organization') - .subscribeOn(Scheduler.asap) - .do((result) => expect(result).to.deep.equal(tags)) + .pipe(tapAsap((result) => expect(result).to.deep.equal(tags))) }) }) @@ -70,10 +67,9 @@ describe('TagApi spec: ', () => { yield sdk.getTags(projectId) .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { + .pipe(tapAsap(([result]) => { expectToDeepEqualForFieldsOfTheExpected(result, tags[0]) - }) + })) }) it('should return an Organization Tag array', function* () { @@ -83,9 +79,8 @@ describe('TagApi spec: ', () => { yield sdk.getTags(orgId, 'organization') .values() - .subscribeOn(Scheduler.asap) - .do(([result]) => { + .pipe(tapAsap(([result]) => { expectToDeepEqualForFieldsOfTheExpected(result, tags[0]) - }) + })) }) }) diff --git a/test/apis/task.spec.ts b/test/apis/task.spec.ts index 3e1cb4b92..25a2926dc 100644 --- a/test/apis/task.spec.ts +++ b/test/apis/task.spec.ts @@ -1,3 +1,4 @@ +import { tap } from 'rxjs/operators' import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' import { createSdk, SDK, SocketMock, TaskSchema } from '../index' @@ -24,9 +25,9 @@ describe('TaskApi request Spec', () => { yield sdk.getTask(fixture._id as TaskId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expectToDeepEqualForFieldsOfTheExpected(r, fixture, 'subtasks', 'ancestors') - }) + })) }) }) @@ -50,11 +51,11 @@ describe('TaskApi socket spec', () => { yield sdk.database.get('Task', { where: { _id: fixture._id } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { delete r.creator delete r.project looseDeepEqual(r, fixture) - }) + })) }) it('update task should change cache', function* () { @@ -69,7 +70,7 @@ describe('TaskApi socket spec', () => { yield sdk.database.get('Task', { where: { _id: fixture._id } }) .values() - .do(([r]) => expect(r.content).to.equal('fixture')) + .pipe(tap(([r]) => expect(r.content).to.equal('fixture'))) }) it('delete task should delete cache', function* () { @@ -81,6 +82,6 @@ describe('TaskApi socket spec', () => { yield sdk.database.get('Task', { where: { _id: fixture._id } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) }) diff --git a/test/apis/user.spec.ts b/test/apis/user.spec.ts index ae54a0708..0c5c79fbd 100644 --- a/test/apis/user.spec.ts +++ b/test/apis/user.spec.ts @@ -1,3 +1,4 @@ +import { tap } from 'rxjs/operators' import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' import { createSdk, SDK, SocketMock, UserMe } from '../index' @@ -23,9 +24,9 @@ describe('UserApi request spec', () => { yield sdk.getUserMe() .values() - .do(([user]) => { + .pipe(tap(([user]) => { expect(user).to.deep.equal(userMe) - }) + })) }) it('update should update cache', function* () { @@ -43,9 +44,9 @@ describe('UserApi request spec', () => { yield sdk.database.get('User') .values() - .do(([user]) => { + .pipe(tap(([user]) => { expect(user.name).to.equal(newName) - }) + })) }) it('addEmail should add email to cache', function* () { @@ -69,9 +70,9 @@ describe('UserApi request spec', () => { yield sdk.database.get('User') .values() - .do(([user]) => { + .pipe(tap(([user]) => { expect(user.emails).to.deep.equal(newEmail) - }) + })) }) }) @@ -101,8 +102,8 @@ describe('UserAPI socket spec', () => { yield sdk.database.get('User') .values() - .do(([user]) => { + .pipe(tap(([user]) => { expect(user.name).to.equal(newName) - }) + })) }) }) diff --git a/test/mock/MockFetch.ts b/test/mock/MockFetch.ts index a21932c00..2f92a15dd 100644 --- a/test/mock/MockFetch.ts +++ b/test/mock/MockFetch.ts @@ -1,4 +1,5 @@ -import { Backend, SDKFetch } from '../index' +import { Backend } from '../index' +import { SDKFetch } from '../../src/SDKFetch' function throwIfSlashPath(path: string) { if (path.charAt(0) === '/') { diff --git a/test/net/asyncLoadRDB.ts b/test/net/asyncLoadRDB.ts index 90ca2607d..a5b6ec948 100644 --- a/test/net/asyncLoadRDB.ts +++ b/test/net/asyncLoadRDB.ts @@ -1,5 +1,6 @@ -import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' +import { describe, beforeEach, afterEach, it } from 'tman' +import { tap } from 'rxjs/operators' import { createSdkWithoutRDB, loadRDB, @@ -46,9 +47,9 @@ describe('Async load reactivedb Spec', () => { mockResponse(fixture) yield sdk.getPost(fixture._id as PostId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r).to.deep.equal(fixture) - }) + })) }) @@ -68,9 +69,9 @@ describe('Async load reactivedb Spec', () => { yield sdk.getUserMe() .values() - .do(([user]) => { + .pipe(tap(([user]) => { expect(user).to.deep.equal(userMe) - }) + })) }) it('getTask should response correct data without reactivedb', function* () { @@ -78,9 +79,9 @@ describe('Async load reactivedb Spec', () => { mockResponse(fixture) yield sdk.getTask(fixture._id as TaskId) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r).to.deep.equal(fixture) - }) + })) }) }) describe('ReactiveDB async load in', () => { @@ -95,7 +96,7 @@ describe('Async load reactivedb Spec', () => { yield loadRDB(sdk) yield result$ - .do(r => { + .pipe(tap(r => { const compareFn = (x: any, y: any) => { return new Date(x.updated).valueOf() - new Date(y.updated).valueOf() + new Date(x.created).valueOf() - new Date(y.created).valueOf() @@ -122,7 +123,7 @@ describe('Async load reactivedb Spec', () => { expected.forEach((expectedResult, i) => { expectToDeepEqualForFieldsOfTheExpected(actual[i], expectedResult) }) - }) + })) }) it('response cache should work when reactivedb async load in', function* () { @@ -136,9 +137,9 @@ describe('Async load reactivedb Spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do((r) => { + .pipe(tap((r) => { expect(r.length).to.equal(1) - }) + })) }) it('reactiveDb opearator should work when reactivedb load in', function* () { @@ -157,9 +158,9 @@ describe('Async load reactivedb Spec', () => { where: { _id: 'mocktask:like' } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r.isLike).to.be.false - }) + })) }) describe('Socket spec when reactivedb async load in', () => { @@ -177,9 +178,9 @@ describe('Async load reactivedb Spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do((r) => { + .pipe(tap((r) => { expect(r.length).to.equal(0) - }) + })) }) it('socket::change should work when reactivedb load in', function* () { @@ -199,7 +200,7 @@ describe('Async load reactivedb Spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do(([r]) => expect(r.content).to.equal('fixture')) + .pipe(tap(([r]) => expect(r.content).to.equal('fixture'))) }) it('socket::new should work when reactivedb load in', function* () { @@ -211,7 +212,7 @@ describe('Async load reactivedb Spec', () => { yield sdk.database.get('Post', { where: { _id: fixture._id } }) .values() - .do((r) => equals(r, [fixture])) + .pipe(tap((r) => equals(r, [fixture]))) }) }) diff --git a/test/net/http.ts b/test/net/http.ts index e3927b187..b29e71a91 100644 --- a/test/net/http.ts +++ b/test/net/http.ts @@ -1,8 +1,10 @@ -import { Observable, Scheduler, Subject } from 'rxjs' import { expect } from 'chai' import { describe, it, beforeEach, afterEach } from 'tman' +import { asapScheduler, empty, forkJoin, from, of, zip, Observable, Subject } from 'rxjs' +import { catchError, flatMap, subscribeOn, tap } from 'rxjs/operators' import { HttpErrorMessage, Http } from '../index' +import { tapAsap } from '../utils' import * as http from '../../src/Net/Http' const fetchMock = require('fetch-mock') @@ -28,8 +30,7 @@ export default describe('net/http', () => { const data = { test: 'test' } fetchMock.mock(url, data) yield fetchInstance.get().send() - .subscribeOn(Scheduler.asap) - .do(() => { + .pipe(tapAsap(() => { expect(fetchMock.calls().matched.length).to.equal(1) expect(fetchMock.lastUrl()).to.equal(url) expect(fetchMock.lastOptions()).to.deep.equal({ @@ -37,7 +38,7 @@ export default describe('net/http', () => { headers: {}, credentials: 'include' }) - }) + })) }) it('should set headers', function* () { @@ -46,8 +47,7 @@ export default describe('net/http', () => { fetchMock.mock(url, {}) yield fetchInstance.get() .send() - .subscribeOn(Scheduler.asap) - .do(() => { + .pipe(tapAsap(() => { expect(fetchMock.lastOptions()).to.deep.equal({ method: 'get', headers: { @@ -55,7 +55,7 @@ export default describe('net/http', () => { }, credentials: 'include' }) - }) + })) }) it('should set headers with copy of the input headers', function* () { @@ -69,10 +69,9 @@ export default describe('net/http', () => { fetchMock.mock(url, {}) yield fetchInstance.get() .send() - .subscribeOn(Scheduler.asap) - .do(() => { + .pipe(tapAsap(() => { expect(fetchMock.lastOptions().headers).to.deep.equal({}) - }) + })) }) it('should set token', function* () { @@ -81,15 +80,14 @@ export default describe('net/http', () => { fetchMock.mock(url, {}) yield fetchInstance.get() .send() - .subscribeOn(Scheduler.asap) - .do(() => { + .pipe(tapAsap(() => { expect(fetchMock.lastOptions()).to.deep.equal({ method: 'get', headers: { 'Authorization': `OAuth2 ${token}` } }) - }) + })) }) allowedMethods.forEach(httpMethod => { @@ -102,14 +100,13 @@ export default describe('net/http', () => { yield fetchInstance[httpMethod](httpMethod === 'get' || httpMethod === 'delete' ? null : body) .send() - .subscribeOn(Scheduler.asap) - .do((res: any) => { + .pipe(tapAsap((res: any) => { expect(fetchMock.lastOptions().method).to.equal(httpMethod) expect(res).to.deep.equal(responseData) if (httpMethod === 'put' || httpMethod === 'post') { expect(fetchMock.lastOptions().body).to.deep.equal(body) } - }) + })) }) }) @@ -122,12 +119,11 @@ export default describe('net/http', () => { yield fetchInstance.delete(body) .send() - .subscribeOn(Scheduler.asap) - .do((res: any) => { + .pipe(tapAsap((res: any) => { expect(fetchMock.lastOptions().method).to.equal('delete') expect(fetchMock.lastOptions().body).to.deep.equal(body) expect(res).to.deep.equal(responseData) - }) + })) }) allowedMethods.forEach(httpMethod => { @@ -149,11 +145,10 @@ export default describe('net/http', () => { yield fetchInstance2[httpMethod](path, httpMethod === 'get' || httpMethod === 'delete' ? null : body) .send() - .subscribeOn(Scheduler.asap) - .do((resp: any) => { + .pipe(tapAsap((resp: any) => { expect(resp.body).to.deep.equal(responseData) expect(resp.headers.get('x-request-id')).to.equal(sampleValue) - }) + })) }) }) @@ -163,18 +158,20 @@ export default describe('net/http', () => { const responseData = { body: { test: 'test' }, method: httpMethod, status } const body = { body: 'body' } fetchMock.mock(url, responseData ) - yield fetchInstance[httpMethod](path, httpMethod === 'get' ? null : body) + yield (fetchInstance[httpMethod](path, httpMethod === 'get' ? null : body) as Http<{}>) .send() - .catch((res: HttpErrorMessage) => { - if (fetchMock.lastOptions()) { - expect(fetchMock.lastOptions().method).to.equal(httpMethod) - } - expect(res.error.status).to.equal(status) - expect(res.method).to.equal(httpMethod) - expect(res.url).to.equal(url) - return Observable.empty() - }) - .subscribeOn(Scheduler.asap) + .pipe( + catchError((res: HttpErrorMessage) => { + if (fetchMock.lastOptions()) { + expect(fetchMock.lastOptions().method).to.equal(httpMethod) + } + expect(res.error.status).to.equal(status) + expect(res.method).to.equal(httpMethod) + expect(res.url).to.equal(url) + return empty() + }), + subscribeOn(asapScheduler) + ) }) }) }) @@ -189,24 +186,26 @@ export default describe('net/http', () => { const caught$ = fetchInstance2.get() .send() - .catch((res: HttpErrorMessage) => Observable.of(res)) as Observable - - yield Observable.zip(caught$, errorAdaptor$) - .flatMap(([caught, adaptor]) => { - return Observable.zip( - Observable.fromPromise(caught.error.json()), - Observable.fromPromise(adaptor.error.json()) - ) - }) - .do(([caught, errorMsg]) => { - expect(caught).to.deep.equal(body) - expect(errorMsg).to.deep.equal(body) - }) - .catch(() => { - expect('Should not reach here!').to.equal('') - return Observable.empty() - }) - .subscribeOn(Scheduler.asap) + .pipe(catchError((res: HttpErrorMessage) => of(res))) as Observable + + yield zip(caught$, errorAdaptor$) + .pipe( + flatMap(([caught, adaptor]) => { + return zip( + from(caught.error.json()), + from(adaptor.error.json()) + ) + }), + tap(([caught, errorMsg]) => { + expect(caught).to.deep.equal(body) + expect(errorMsg).to.deep.equal(body) + }), + catchError(() => { + expect('Should not reach here!').to.equal('') + return empty() + }), + subscribeOn(asapScheduler) + ) }) it('createMethod() should give response text when it cannot be parsed successfully', function* () { @@ -214,10 +213,9 @@ export default describe('net/http', () => { fetchMock.getOnce(url, letJSONparseThrow) yield http.createMethod('get')({ url } as any) - .subscribeOn(Scheduler.asap) - .do((x: any) => { + .pipe(tapAsap((x: any) => { expect(x).to.equal(letJSONparseThrow) - }) + })) }) it('correctly clone-ed Http instance should use cached response', function* () { @@ -233,19 +231,18 @@ export default describe('net/http', () => { fetchMock.get(url, { body: JSON.stringify(expectedResp) }) - yield Observable.forkJoin( + yield forkJoin( fetchInstance.send(), fetchInstanceClone1.send(), fetchInstanceClone2.send(), fetchInstanceClone1Clone.send() ) - .subscribeOn(Scheduler.asap) - .do(([res, resClone1, resClone2, resClone1Clone]) => { + .pipe(tapAsap(([res, resClone1, resClone2, resClone1Clone]) => { expect(res).to.deep.equal(expectedResp) expect(resClone1).to.deep.equal(expectedResp) expect(resClone2).to.deep.equal(expectedResp) expect(resClone1Clone).to.deep.equal(expectedResp) expect(fetchMock.calls(url)).lengthOf(1) - }) + })) }) }) diff --git a/test/net/net.ts b/test/net/net.ts index 55be17fe8..fe06448bf 100644 --- a/test/net/net.ts +++ b/test/net/net.ts @@ -1,5 +1,6 @@ -import { Observable, Subscription, Scheduler } from 'rxjs' import { describe, beforeEach, afterEach, it } from 'tman' +import { asapScheduler, defer, of } from 'rxjs' +import { subscribeOn, take, tap } from 'rxjs/operators' import { Database, DataStoreType } from 'reactivedb' import { expect, use } from 'chai' import { spy } from 'sinon' @@ -11,7 +12,7 @@ import { ApiResult } from '../../src/Net/Net' import { createMsgToDBHandler } from '../../src/sockets/EventMaps' import { normalEvent, projectEvents } from '../fixtures/events.fixture' -import { expectToDeepEqualForFieldsOfTheExpected } from '../utils' +import { expectToDeepEqualForFieldsOfTheExpected, tapAsap } from '../utils' import { mapMsgTypeToTable } from '../../src/sockets/MapToTable' use(SinonChai) @@ -21,7 +22,6 @@ describe('Net test', () => { let httpBackend: Backend let database: Database let version = 1 - let subscription: Subscription | undefined let spyFetch: sinon.SinonSpy const sdkFetch = new SDKFetch() @@ -45,9 +45,6 @@ describe('Net test', () => { afterEach(function* () { httpBackend.restore() spyFetch && spyFetch.restore() - if (subscription instanceof Subscription) { - subscription.unsubscribe() - } yield database.dispose() }) @@ -68,9 +65,9 @@ describe('Net test', () => { excludeFields: ['isDeleted', 'source', 'type', 'url'] } as ApiResult) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expectToDeepEqualForFieldsOfTheExpected(r, normalEvent) - }) + })) }) it('should handle Object type response and consumed by `changes`', function* () { @@ -90,10 +87,9 @@ describe('Net test', () => { excludeFields: ['isDeleted', 'source', 'type', 'url'] } as ApiResult) .changes() - .take(1) - .do(([r]) => { + .pipe(take(1), tap(([r]) => { expectToDeepEqualForFieldsOfTheExpected(r, normalEvent) - }) + })) }) it('should handle Object type response and get changes', function* () { @@ -114,9 +110,7 @@ describe('Net test', () => { }) .changes() - subscription = stream$.subscribe() - - yield stream$.take(1) + yield stream$.pipe(take(1)) const newLocation = 'test_new_location' @@ -127,10 +121,9 @@ describe('Net test', () => { }) yield stream$ - .take(1) - .do(([r]) => { + .pipe(take(1), tap(([r]) => { expect(r.location).to.deep.equal(newLocation) - }) + })) }) it('should handle Array type response and consumed by `values`', function* () { @@ -150,11 +143,11 @@ describe('Net test', () => { ] }) .values() - .do(rs => { + .pipe(tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) }) it('should handle Array type response and consumed by `changes`', function* () { @@ -174,12 +167,14 @@ describe('Net test', () => { ] }) .changes() - .take(1) - .do(rs => { - projectEvents.forEach((expected, i) => { - expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) + .pipe( + take(1), + tap(rs => { + projectEvents.forEach((expected, i) => { + expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) + }) }) - }) + ) }) it('should handle Array type response and get changes', function* () { @@ -200,9 +195,7 @@ describe('Net test', () => { } as ApiResult) .changes() - subscription = stream$.subscribe() - - yield stream$.take(1) + yield stream$.pipe(take(1)) const newLocation = 'new_event_location' @@ -212,10 +205,9 @@ describe('Net test', () => { location: newLocation }) - yield stream$.take(1) - .do(([e]) => { - expect(e.location).to.equal(newLocation) - }) + yield stream$.pipe(take(1), tap(([e]) => { + expect(e.location).to.equal(newLocation) + })) }) it('should handle Array type response and validate cache', function* () { @@ -248,9 +240,7 @@ describe('Net test', () => { }) .changes() - subscription = stream$.subscribe() - - yield stream$.take(1) + yield stream$.pipe(take(1)) httpBackend.whenGET(`${apiHost}/api/events/${partialEvent._id}`) .respond({ ...projectEvents[0], ...partialEvent }) @@ -258,13 +248,10 @@ describe('Net test', () => { yield database.insert('Event', partialEvent) yield stream$ - .subscribeOn(Scheduler.asap) - .take(1) - .do((events: typeof projectEvents) => { + .pipe(take(1), tapAsap((events: typeof projectEvents) => { expect(spyFetch.callCount).to.equal(2) expect(events.length).to.equal(projectEvents.length + 1) - }) - + })) }) it('should handle empty Array', function* () { @@ -297,9 +284,7 @@ describe('Net test', () => { }) .changes() - subscription = stream$.subscribe() - - yield stream$.take(1) + yield stream$.pipe(take(1)) httpBackend.whenGET(`${apiHost}/api/events/${partialEvent._id}`) .respond({ ...projectEvents[0], ...partialEvent }) @@ -307,12 +292,13 @@ describe('Net test', () => { yield database.insert('Event', partialEvent) yield stream$ - .subscribeOn(Scheduler.asap) - .take(1) - .do((events: typeof projectEvents) => { - expect(spyFetch.callCount).to.equal(2) - expect(events.length).to.equal(1) - }) + .pipe( + take(1), + tapAsap((events: typeof projectEvents) => { + expect(spyFetch.callCount).to.equal(2) + expect(events.length).to.equal(1) + }) + ) }) it('should get result from cached Response and consumed by `values`', function* () { @@ -334,19 +320,19 @@ describe('Net test', () => { yield getToken() .values() - .do(rs => { + .pipe(tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) yield getToken() .values() - .do(rs => { + .pipe(tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) }) it('should get result from cached Response and consumed by `changes`', function* () { @@ -368,20 +354,19 @@ describe('Net test', () => { yield getToken() .values() - .do(rs => { + .pipe(tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) yield getToken() .changes() - .take(1) - .do(rs => { + .pipe(take(1), tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) }) it('should get result from cached Response and get changes', function* () { @@ -403,18 +388,16 @@ describe('Net test', () => { yield getToken() .values() - .do(rs => { + .pipe(tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) const stream$ = getToken() .changes() - subscription = stream$.subscribe() - - yield stream$.take(1) + yield stream$.pipe(take(1)) const newLocation = 'new_event_location' @@ -424,10 +407,10 @@ describe('Net test', () => { location: newLocation }) - yield stream$.take(1) - .do(([r]) => { + yield stream$ + .pipe(take(1), tap(([r]) => { expect(r.location).to.equal(newLocation) - }) + })) }) it('should get result from cached Response and validate cache', function* () { @@ -451,11 +434,11 @@ describe('Net test', () => { yield getToken() .values() - .do(rs => { + .pipe(tap(rs => { projectEvents.forEach((expected, i) => { expectToDeepEqualForFieldsOfTheExpected(rs[i], expected) }) - }) + })) spyFetch = spy(sdkFetch, 'get') @@ -467,30 +450,22 @@ describe('Net test', () => { location: newLocation } - const stream$ = getToken() - .changes() - - subscription = stream$.subscribe() + const stream$ = getToken().changes() - yield stream$.take(1) + yield stream$.pipe(take(1)) httpBackend.whenGET(`${apiHost}/api/events/${partialEvent._id}`) .respond({ ...projectEvents[0], ...partialEvent }) yield database.insert('Event', partialEvent) - yield stream$ - .subscribeOn(Scheduler.asap) - .take(1) + yield stream$.pipe(subscribeOn(asapScheduler), take(1)) // 多请求一次,保证 padding 被执行之后,再次从 ReactiveDB 里面拿数据的时候应该能拿到完整的数据 - yield stream$ - .subscribeOn(Scheduler.asap) - .take(1) - .do((events: typeof projectEvents) => { - expect(spyFetch.callCount).to.equal(2) - expect(events.length).to.equal(projectEvents.length + 1) - }) + yield stream$.pipe(take(1), tapAsap((events: typeof projectEvents) => { + expect(spyFetch.callCount).to.equal(2) + expect(events.length).to.equal(projectEvents.length + 1) + })) http.restore() }) @@ -527,9 +502,9 @@ describe('Net test', () => { tableName: 'Event' } as ApiResult) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r).to.deep.equal({ _id: normalEvent._id }) - }) + })) }) it(`should allow query.fields to specify field names to be selected, ignoring 'excludeFields'`, function* () { @@ -546,12 +521,12 @@ describe('Net test', () => { excludeFields: ['title'] } as ApiResult) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r).to.deep.equal({ _id: normalEvent._id, title: normalEvent.title }) - }) + })) }) it(`should allow query.fields to specify field names to be selected, ignoring non-existing ones`, function* () { @@ -567,11 +542,11 @@ describe('Net test', () => { tableName: 'Event' } as ApiResult) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect(r).to.deep.equal({ _id: normalEvent._id }) - }) + })) }) it(`should ignore empty query.fields, i.e. []`, function* () { @@ -587,9 +562,9 @@ describe('Net test', () => { tableName: 'Event' } as ApiResult) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expectToDeepEqualForFieldsOfTheExpected(r, normalEvent, 'creator') - }) + })) }) }) @@ -614,11 +589,11 @@ describe('Net CacheStrategy Spec', () => { }) database.connect() - server = spy(() => Observable.of(projectEvents[0])) + server = spy(() => of(projectEvents[0])) getEventOptions = (strategy: CacheStrategy, options = {}): any => { const defaultOptions = { cacheValidate: strategy, - request: Observable.defer(server), + request: defer(server), tableName: 'Event', query: { where: { diff --git a/test/net/pagination.ts b/test/net/pagination.ts index 85541efe2..d0d89994c 100644 --- a/test/net/pagination.ts +++ b/test/net/pagination.ts @@ -1,7 +1,9 @@ import { expect } from 'chai' import { describe, it, beforeEach, afterEach } from 'tman' -import { Observable, Scheduler } from 'rxjs' +import { empty, from, interval, of, throwError, timer } from 'rxjs' +import { catchError, delay, mergeAll, mergeMap, take, takeUntil, tap, retry, publishReplay, refCount } from 'rxjs/operators' import { SDKFetch } from '..' +import { tapAsap } from '../utils' import * as page from '../../src/Net/Pagination' import { expandPage } from '../../src/apis/pagination' @@ -38,22 +40,21 @@ describe('Pagination Spec', () => { }) it(`${page.expand.name} should complete on source$ completion`, function* () { - const source$ = Observable.empty() + const source$ = empty() const expandOp = page.expand( - () => Observable.of(sampleResponse), + () => of(sampleResponse), page.accumulateResultByConcat, page.defaultState('') ) let isCompleted = false - yield source$.pipe(expandOp).mergeAll().do({ + yield source$.pipe(expandOp, mergeAll(), tap({ complete: () => { isCompleted = true } - }) - yield Observable.of(isCompleted) - .do((x) => { - expect(x).to.be.true - }) + })) + yield of(isCompleted).pipe(tap((x) => { + expect(x).to.be.true + })) }) it(`${page.expand.name} should complete on hasMore: false`, function* () { @@ -66,97 +67,93 @@ describe('Pagination Spec', () => { () => { if (!hasMore) { hasMore = false - return Observable.of(sampleHasNoMoreResponse) + return of(sampleHasNoMoreResponse) } - return Observable.of(sampleResponse) + return of(sampleResponse) }, page.accumulateResultByConcat, page.defaultState('') ) let isCompleted = false - const infiniteSource$ = Observable.interval() - yield infiniteSource$.pipe(expandOp).mergeAll().do({ - complete: () => { + const infiniteSource$ = interval() + yield infiniteSource$.pipe( + expandOp, + mergeAll(), + take(10), // 避免出错时,由 infiniteSource$ 造成的无限溢出的问题 + tap({ complete: () => { isCompleted = true - } - }).take(10) // 避免出错时,由 infiniteSource$ 造成的无限溢出的问题 - yield Observable.of(isCompleted) - .do((x) => { - expect(x).to.be.true - }) + } })) + yield of(isCompleted).pipe(tap((x) => { + expect(x).to.be.true + })) }) it(`${page.expand.name} should error on source$ error`, function* () { const sampleError = new Error('source$ error') - const source$ = Observable.throw(sampleError) + const source$ = throwError(sampleError) const expandOp = page.expand( - () => Observable.of(sampleResponse), + () => of(sampleResponse), page.accumulateResultByConcat, page.defaultState('') ) let isErrorPassedThrough = false - yield source$.pipe(expandOp).mergeAll().do({ + yield source$.pipe(expandOp, mergeAll(), tap({ error: () => { isErrorPassedThrough = true } - }).catch(() => Observable.empty()) - yield Observable.of(isErrorPassedThrough) - .do((x) => { - expect(x).to.be.true - }) + }), catchError(() => empty())) + yield of(isErrorPassedThrough).pipe(tap((x) => { + expect(x).to.be.true + })) }) it(`${page.expand.name} should allow retry on source$ error`, function* () { const sampleError = new Error('source$ error') let hasThrown = false - const source$ = Observable.of('fail at first, succeed for the rest').do(() => { + const source$ = of('fail at first, succeed for the rest').pipe(tap(() => { if (!hasThrown) { hasThrown = true throw sampleError } - }) + })) const expandOp = page.expand( - () => Observable.of(sampleResponse), + () => of(sampleResponse), page.accumulateResultByConcat, page.defaultState('') ) - yield source$.pipe(expandOp).mergeAll().do((x) => { + yield source$.pipe(expandOp, mergeAll(), tap((x) => { expect(x.nextPageToken).to.equal('456') expect(x.result.slice(-pageSize)).to.deep.equal([1, 2, 3]) - }).retry(2) + }), retry(2)) }) // todo(dingwen): use marble test instead it(`${page.expand.name} should ignore source$ when the current load is yet to be completed`, function* () { - const source$ = Observable.interval(10).take(3) + const source$ = interval(10).pipe(take(3)) const expandOp = page.expand( - () => Observable.of(sampleResponse).delay(25), + () => of(sampleResponse).pipe>(delay(25)), page.accumulateResultByConcat, page.defaultState('') ) - const page$ = source$.pipe(expandOp).mergeAll().publishReplay(1).refCount() + const page$ = source$.pipe(expandOp, mergeAll(), publishReplay(1), refCount()) let earliestFirst: any = null - const earliestFirst$ = page$.takeUntil(Observable.timer(40)) - yield earliestFirst$ - .do((x) => { - earliestFirst = x - }) - yield Observable.of(earliestFirst) - .do((x) => { - expect(x.result).to.deep.equal([1, 2, 3]) - }) + const earliestFirst$ = page$.pipe(takeUntil(timer(40))) + yield earliestFirst$.pipe(tap((x) => { + earliestFirst = x + })) + yield of(earliestFirst).pipe(tap((x) => { + expect(x.result).to.deep.equal([1, 2, 3]) + })) let emitOnlyOnce: any = null - const emitOnlyOnce$ = page$.takeUntil(Observable.timer(60)) - yield emitOnlyOnce$ - .do((x) => { - emitOnlyOnce = x - }) - yield Observable.of(emitOnlyOnce) - .do((x) => { - expect(x.result).to.deep.equal([1, 2, 3]) - }) + const emitOnlyOnce$ = page$.pipe(takeUntil(timer(60))) + yield emitOnlyOnce$.pipe(tap((x) => { + emitOnlyOnce = x + })) + yield of(emitOnlyOnce).pipe(tap((x) => { + expect(x.result).to.deep.equal([1, 2, 3]) + })) }) it(`${page.expand.name} should not block second load when the first load has failed`, function* () { @@ -166,22 +163,22 @@ describe('Pagination Spec', () => { () => { if (!hasThrown) { hasThrown = true - return Observable.throw(sampleError) + return throwError(sampleError) } - return Observable.of(sampleResponse) + return of(sampleResponse) }, page.accumulateResultByConcat, page.defaultState('') ) - yield Observable.from(['first load', 'second load']) - .pipe(expandOp) - .mergeMap((stream) => stream.catch(() => Observable.empty())) - .take(1) - .subscribeOn(Scheduler.asap) - .do((state: any) => { - expect(state.nextPageToken).to.equal(sampleResponse.nextPageToken) - expect(state.result.slice(-pageSize)).to.deep.equal(sampleResponse.result) - }) + yield from(['first load', 'second load']) + .pipe( + expandOp, + mergeMap((stream) => stream.pipe(catchError(() => empty()))), + tapAsap((state: any) => { + expect(state.nextPageToken).to.equal(sampleResponse.nextPageToken) + expect(state.result.slice(-pageSize)).to.deep.equal(sampleResponse.result) + }) + ) }) it(`${page.expand.name} should not block next load when current load has failed`, function* () { @@ -195,9 +192,9 @@ describe('Pagination Spec', () => { () => { if (!hasThrown) { hasThrown = true - return Observable.throw(sampleError) + return throwError(sampleError) } - return Observable.of(sampleNextResponse) + return of(sampleNextResponse) }, page.accumulateResultByConcat, { @@ -207,15 +204,16 @@ describe('Pagination Spec', () => { result: [1, 2, 3] } ) - yield Observable.from(['current load', 'next load']) - .pipe(expandOp) - .mergeMap((stream) => stream.catch(() => Observable.empty())) - .take(1) - .subscribeOn(Scheduler.asap) - .do((state: any) => { - expect(state.nextPageToken).to.equal(sampleNextResponse.nextPageToken) - expect(state.result.slice(-pageSize)).to.deep.equal(sampleNextResponse.result) - }) + yield from(['current load', 'next load']) + .pipe( + expandOp, + mergeMap((stream) => stream.pipe(catchError(() => empty()))), + take(1), + tapAsap((state: any) => { + expect(state.nextPageToken).to.equal(sampleNextResponse.nextPageToken) + expect(state.result.slice(-pageSize)).to.deep.equal(sampleNextResponse.result) + }) + ) }) }) @@ -256,8 +254,7 @@ describe(`${expandPage.name}`, () => { }) const initial = page.defaultState(urlPath, { pageSize: 5 }) - return sdkFetch.expandPage(initial) - .take(1) + return sdkFetch.expandPage(initial).pipe(take(1)) .toPromise() .then((resultState) => { expect(resultState).to.deep.equal({ @@ -288,8 +285,7 @@ describe(`${expandPage.name}`, () => { hasMore: true, pageSize: 5 } - return sdkFetch.expandPage(currState) - .take(1) + return sdkFetch.expandPage(currState).pipe(take(1)) .toPromise() .then((resultState) => { expect(resultState).to.deep.equal({ @@ -312,8 +308,7 @@ describe(`${expandPage.name}`, () => { }) const initial = page.defaultState(urlPath, { pageSize: 5 }) - return sdkFetch.expandPage(initial, { mutate: true }) - .take(1) + return sdkFetch.expandPage(initial, { mutate: true }).pipe(take(1)) .toPromise() .then(() => { expect(initial).to.deep.equal({ @@ -348,7 +343,7 @@ describe(`${expandPage.name}`, () => { urlQuery: {}, mapFn: (i) => i - 1 }) - .take(1) + .pipe(take(1)) .toPromise() .then((resultState) => { expect(resultState).to.deep.equal({ @@ -398,7 +393,7 @@ describe(`${expandPage.name}`, () => { }) } ) - .take(1) + .pipe(take(1)) .toPromise() .then((resultState) => { expect(resultState).to.deep.equal({ diff --git a/test/sockets/interceptors.spec.ts b/test/sockets/interceptors.spec.ts index 5c513de96..86c789809 100644 --- a/test/sockets/interceptors.spec.ts +++ b/test/sockets/interceptors.spec.ts @@ -1,7 +1,7 @@ import { describe, it } from 'tman' import { expect } from 'chai' -import { Observable } from 'rxjs/Observable' +import { of, Observable } from 'rxjs' import { QueryToken } from 'reactivedb' import { redirectLike } from '../../src/sockets/interceptor' @@ -100,11 +100,11 @@ const createTest = ( } /** - * 利用 Observable.of() 会默认使用同步(非异步) scheduer 的特性,方便测试 + * 利用 of() 会默认使用同步(非异步) scheduer 的特性,方便测试 */ const synchronousDB: MockDatabase = { upsert: (tabName: string, data: any) => { - return Observable.of({ + return of({ table: tabName, row: data, kind: 'upsert' @@ -113,7 +113,7 @@ const synchronousDB: MockDatabase = { get: () => { return { values: () => { - return Observable.of([]) + return of([]) } } as any } diff --git a/test/sockets/middleware.spec.ts b/test/sockets/middleware.spec.ts index 9f0bd21cd..7b01e6c9e 100644 --- a/test/sockets/middleware.spec.ts +++ b/test/sockets/middleware.spec.ts @@ -1,8 +1,7 @@ -import { describe, it, beforeEach, afterEach } from 'tman' -import { Observable } from 'rxjs/Observable' -import { Subject } from 'rxjs/Subject' -import { Subscription } from 'rxjs/Subscription' import { expect } from 'chai' +import { describe, it, beforeEach, afterEach } from 'tman' +import { of, Observable, Subject, Subscription } from 'rxjs' +import { scan, tap } from 'rxjs/operators' import * as sinon from 'sinon' import { clone } from '../utils' import * as midware from '../../src/sockets/Middleware' @@ -90,23 +89,23 @@ describe('Socket interceptor creator', () => { const expectedResult = { say: 'hello' } const interceptor: any = midware.createInterceptor((message) => { simpleTransFn(message) - return Observable.of(expectedResult) + return of(expectedResult) }) const result = interceptor(msg) expect(msg).to.deep.equal(msgClone) expect(errStub).to.called - return (result as Observable).do((x) => { + return (result as Observable).pipe(tap((x) => { expect(x).to.deep.equal(expectedResult) - }) + })) }) it('mutateMessage + Observable', () => { const expectedResult = { say: 'world' } const intercept: any = midware.createInterceptor((message) => { simpleTransFn(message) - return Observable.of(expectedResult) + return of(expectedResult) }, { mutate: true }) @@ -117,9 +116,9 @@ describe('Socket interceptor creator', () => { msg.data.key = 'value' expect(msg).to.deep.equal(msgClone) - return (result as Observable).do((x) => { + return (result as Observable).pipe(tap((x) => { expect(x).to.deep.equal(expectedResult) - }) + })) }) }) @@ -207,7 +206,7 @@ describe('Socket Interceptors', () => { it('should shortcircuit when an interceptor returns an Observable', () => { interceptors.append((message: any) => { transDataKey(message) - return Observable.of(null) + return of(null) }, { mutate: true }) interceptors.append(transType, { mutate: true }) @@ -516,14 +515,14 @@ describe('WSProxy fromRefresh() method', () => { }) afterEach(() => { - for (let [key] of proxy['daemonManager'].entries()) { + for (const [key] of proxy['daemonManager'].entries()) { proxy.stopDaemon(key) } }) it('should trigger callback after first being activated', marbles((m) => { const wsMsg$ = m.hot('^-a-b---c-----d--e-', matchingMessages) - const daemon = m.cold('-------u-----------', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon = m.cold('-------u-----------', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected = m.cold('--------c-----d--e-', matchingMessages) wsMsg$.subscribe(proxy.apply) @@ -534,7 +533,7 @@ describe('WSProxy fromRefresh() method', () => { it('should not trigger callback after suspension', marbles((m) => { const wsMsg$ = m.hot('^-a-b---c-----d--e-', matchingMessages) - const daemon = m.cold('-------u-----d-----', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon = m.cold('-------u-----d-----', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected = m.cold('--------c----------', matchingMessages) wsMsg$.subscribe(proxy.apply) @@ -545,7 +544,7 @@ describe('WSProxy fromRefresh() method', () => { it('should not trigger callback after re-activation if there is no matching message during suspension', marbles((m) => { const wsMsg$ = m.hot('^-a-b---c----------', matchingMessages) - const daemon = m.cold('-------u-----d---u-', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon = m.cold('-------u-----d---u-', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected = m.cold('--------c----------', matchingMessages) wsMsg$.subscribe(proxy.apply) @@ -556,7 +555,7 @@ describe('WSProxy fromRefresh() method', () => { it('should trigger callback after re-activation if there is one matching message during suspension', marbles((m) => { const wsMsg$ = m.hot('^-a-b---c------d---', matchingMessages) - const daemon = m.cold('-------u-----d---u-', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon = m.cold('-------u-----d---u-', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected = m.cold('--------c--------d-', matchingMessages) wsMsg$.subscribe(proxy.apply) @@ -567,7 +566,7 @@ describe('WSProxy fromRefresh() method', () => { it('should trigger callback after re-activation with the last of the matching messages during suspension', marbles((m) => { const wsMsg$ = m.hot('^-a-b---c-----d-e--', matchingMessages) - const daemon = m.cold('-------u-----d---u-', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon = m.cold('-------u-----d---u-', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected = m.cold('--------c--------e-', matchingMessages) wsMsg$.subscribe(proxy.apply) @@ -579,7 +578,7 @@ describe('WSProxy fromRefresh() method', () => { it(`overall, should trigger callback actively when the daemon is active, \tand select the last matching during suspension to trigger callback on re-activation`, marbles((m) => { const wsMsg$ = m.hot('^-a-b---c-----d-e--f---g-----h-', matchingMessages) - const daemon = m.cold('-------u-----d---u---d-----u---', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon = m.cold('-------u-----d---u---d-----u---', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected = m.cold('--------c--------e-f-------g-h-', matchingMessages) wsMsg$.subscribe(proxy.apply) @@ -590,11 +589,11 @@ describe('WSProxy fromRefresh() method', () => { it('should allow more than one differently namespaced callers to work independently', marbles((m) => { const wsMsg$ = m.hot('^-a-b---c-----d-e--f---g-----h-', matchingMessages) - const daemon1 = m.cold('-------u-----d---u---d-----u---', daemonStatusChange).scan(onStatusChange('test1'), null) + const daemon1 = m.cold('-------u-----d---u---d-----u---', daemonStatusChange).pipe(scan(onStatusChange('test1'), null)) const expected1 = m.cold('--------c--------e-f-------g-h-', matchingMessages) - const daemon2 = m.cold('-u----d------u----d----------u-', daemonStatusChange).scan(onStatusChange('test2'), null) + const daemon2 = m.cold('-u----d------u----d----------u-', daemonStatusChange).pipe(scan(onStatusChange('test2'), null)) const expected2 = m.cold('--a-b--------cd-e------------(gh)-', matchingMessages) - const daemon3 = m.cold('----------u------d----------u--', daemonStatusChange).scan(onStatusChange('test3'), null) + const daemon3 = m.cold('----------u------d----------u--', daemonStatusChange).pipe(scan(onStatusChange('test3'), null)) const expected3 = m.cold('--------------d-e-----------gh-', matchingMessages) wsMsg$.subscribe(proxy.apply) diff --git a/test/sockets/sockets.spec.ts b/test/sockets/sockets.spec.ts index afc9537bf..f79b4fe9d 100644 --- a/test/sockets/sockets.spec.ts +++ b/test/sockets/sockets.spec.ts @@ -1,6 +1,7 @@ -import { Observable } from 'rxjs/Observable' -import { describe, beforeEach, afterEach, it } from 'tman' import { expect } from 'chai' +import { describe, beforeEach, afterEach, it } from 'tman' +import { of } from 'rxjs' +import { tap } from 'rxjs/operators' import { createSdk, SDK, SocketMock, SDKFetch, Socket } from '../' import * as midware from '../../src/sockets/Middleware' import { restore, expectToDeepEqualForFieldsOfTheExpected } from '../utils' @@ -63,13 +64,13 @@ describe('Socket handling Spec', () => { yield sdk.database.get('Task', { where: { isDone: true } }) .values() - .do((rs) => { + .pipe(tap((rs) => { expect(rs).to.have.lengthOf(taskDone.length) rs.forEach((r: any) => { const expectedTask = { ...taskUndone.find(({ _id }) => _id === r._id), isDone: true } expectToDeepEqualForFieldsOfTheExpected(r, expectedTask) }) - }) + })) }) it('should do db:remove for all the PKs to be deleted in { e: ":remove:{modelType}s/{boundToObjectId}", d: "[pk1, pk2, ...]"}', function* () { @@ -86,11 +87,11 @@ describe('Socket handling Spec', () => { yield sdk.database.get('Task') .values() - .do((rs) => { + .pipe(tap((rs) => { expect(rs).to.have.lengthOf(1) const [r] = rs expectToDeepEqualForFieldsOfTheExpected(r, tasks[2]) - }) + })) }) it('should do db:remove on { e: ":destroy:{modelType}/{modelId}", d: "" }', function* () { @@ -106,7 +107,7 @@ describe('Socket handling Spec', () => { yield sdk.database.get('Post', { where: { _id: modelId } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) it('should do db:remove on { e: ":remove:{collectionType}/{collectionId}", d: "{modelId}" }', function* () { @@ -123,7 +124,7 @@ describe('Socket handling Spec', () => { yield sdk.database.get('Stage', { where: { _id: modelId } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) it('should do db:remove on { e: ":remove:{collectionType}", d: "{modelId}" }', function* () { @@ -139,7 +140,7 @@ describe('Socket handling Spec', () => { yield sdk.database.get('Activity', { where: { _id: modelId } }) .values() - .do((r) => expect(r.length).to.equal(0)) + .pipe(tap((r) => expect(r.length).to.equal(0))) }) }) @@ -179,23 +180,23 @@ describe('Socket interceptors', () => { // 添加 message title 字段有效:得到数据库中相应行的 title 为 'hello' yield sdk.database.get('Event', { where: { _id: modelId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect((r as any).title).to.equal('hello') - }) + })) yield server.emit('change', 'event' as any, modelId, { title: 'hello world' }) // 删除 message title 字段有效:使得数据库中相应行的 title 保持不变,为 'hello' yield sdk.database.get('Event', { where: { _id: modelId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect((r as any).title).to.equal('hello') - }) + })) }) it('should allow interceptor to ignore default DB ops', function* () { client.interceptors.append((_) => { - return Observable.of(null) + return of(null) }) const server = new SocketMock(client) @@ -206,9 +207,9 @@ describe('Socket interceptors', () => { yield sdk.database.get('Activity', { where: { _id: modelId } }) .values() - .do((r) => { + .pipe(tap((r) => { expect(r.length).to.equal(1) - }) + })) }) it('should allow an interceptor to shortcircuit a sequence of interceptors', function* () { @@ -231,9 +232,9 @@ describe('Socket interceptors', () => { yield sdk.database.get('Event', { where: { _id: modelId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect((r as any).title).to.equal('hello world') - }) + })) }) it('should not allow a UserFunc to mutate message when mutateMessage flag is not set', function* () { @@ -249,11 +250,11 @@ describe('Socket interceptors', () => { yield sdk.database.get('Event', { where: { _id: modelId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect((r as any).title).to.be.undefined expect(stub).called stub.restore() - }) + })) }) it('should allow a UserFunc to give up control flow flags set on interceptor creation', function* () { @@ -276,17 +277,17 @@ describe('Socket interceptors', () => { yield sdk.database.get('Event', { where: { _id: modelId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect((r as any).title).to.equal('hello') - }) + })) yield server.emit('change', 'event', modelId, { title: 'hello' }) yield sdk.database.get('Event', { where: { _id: modelId } }) .values() - .do(([r]) => { + .pipe(tap(([r]) => { expect((r as any).title).to.equal('hello world') - }) + })) }) }) diff --git a/test/utils.ts b/test/utils.ts index 006f6886d..b9c9fb05e 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,6 +1,8 @@ 'use strict' import { expect } from 'chai' import { capitalize } from 'lodash' +import { asapScheduler, OperatorFunction } from 'rxjs' +import { subscribeOn, tap } from 'rxjs/operators' import { forEach, SDK, SDKFetch } from './index' import { MockFetch } from './mock/MockFetch' @@ -108,3 +110,10 @@ export function forEachFalsyValueOfProperty( { [prop]: NaN } ].forEach(f) } + +export const tapAsap = (tapFn: (emitted: T) => any): OperatorFunction => + (source$) => source$ + .pipe( + subscribeOn(asapScheduler), + tap(tapFn) + ) diff --git a/test/utils/httpErrorSpec.ts b/test/utils/httpErrorSpec.ts index 88dc5f1c5..8e555a9be 100644 --- a/test/utils/httpErrorSpec.ts +++ b/test/utils/httpErrorSpec.ts @@ -1,6 +1,8 @@ import * as chai from 'chai' -import { Observable, Scheduler, Subject } from 'rxjs' import { describe, it, beforeEach, afterEach } from 'tman' +import { of, zip, Subject } from 'rxjs' +import { catchError, concat, skip } from 'rxjs/operators' +import { tapAsap } from '../utils' import { Http, Backend, HttpErrorMessage } from '../index' @@ -10,7 +12,7 @@ export default describe('HttpError$ test: ', () => { const url = 'www.example.com' const silentRequest = (req: Http) => - req.get().send().catch(() => Observable.of(null)) + req.get().send().pipe(catchError(() => of(null))) let httpBackend: Backend let mockFetch: Http @@ -32,16 +34,15 @@ export default describe('HttpError$ test: ', () => { status: 400 }) - yield Observable.zip( + yield zip( silentRequest(mockFetch), error$, (_, { error }) => error ) - .subscribeOn(Scheduler.asap) - .do(({ statusText, body }) => { + .pipe(tapAsap(({ statusText, body }) => { expect(statusText).to.equal('Bad Request') expect(body).equal('testing') - }) + })) }) it('handler sequence error should ok', function* () { @@ -55,16 +56,17 @@ export default describe('HttpError$ test: ', () => { status: 400 }) - yield Observable.zip( - silentRequest(mockFetch).concat(silentRequest(mockFetch)), + yield zip( + silentRequest(mockFetch).pipe(concat(silentRequest(mockFetch))), error$, (_, { error }) => error ) - .skip(1) - .subscribeOn(Scheduler.asap) - .do(({ statusText, body }) => { - expect(statusText).to.equal('Bad Request') - expect(body).to.equal('testing 2') - }) + .pipe( + skip(1), + tapAsap(({ statusText, body }) => { + expect(statusText).to.equal('Bad Request') + expect(body).to.equal('testing 2') + }) + ) }) }) diff --git a/tools/tasks/test.ts b/tools/tasks/test.ts index 2cd198d58..8af1b144c 100644 --- a/tools/tasks/test.ts +++ b/tools/tasks/test.ts @@ -1,5 +1,6 @@ import * as path from 'path' -import { Observable, Observer } from 'rxjs' +import { from, Observable, Observer } from 'rxjs' +import { debounceTime, flatMap, map } from 'rxjs/operators' const fileWatcher = require('node-watch') const testDir = path.join(process.cwd(), 'spec-js/test') @@ -20,15 +21,17 @@ export function runTman() { } function watch (paths: string[]) { - return Observable.from(paths) - .map(p => path.join(process.cwd(), p)) - .flatMap(path => Observable.create((observer: Observer) => { - fileWatcher(path, { recursive: true }, (_: any, fileName: string) => { - observer.next(fileName) - }) - return () => fileWatcher.close() - })) - .debounceTime(500) + return from(paths) + .pipe( + map(p => path.join(process.cwd(), p)), + flatMap(path => Observable.create((observer: Observer) => { + fileWatcher(path, { recursive: true }, (_: any, fileName: string) => { + observer.next(fileName) + }) + return () => fileWatcher.close() + })), + debounceTime(500) + ) } watch(['spec-js']) @@ -44,7 +47,7 @@ process.on('uncaughtException', (err: any) => { process.on('SIGINT', () => { const watchCompilePid = Number(process.argv[2]) - if (watchCompilePid){ + if (watchCompilePid) { process.kill(watchCompilePid) } process.exit() diff --git a/yarn.lock b/yarn.lock index a79aa9497..62e132863 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,17 +12,10 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/lodash-es@^4.0.0": - version "4.17.0" - resolved "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.0.tgz#ed9044d62ee36a93e0650b112701986b1c74c766" - integrity sha512-h8lkWQSgT4qjs9PcIhcL2nWubZeXRVzjZxYlRFmcX9BW1PIk5qRc0djtRWZqtM+GDDFhwBt0ztRu72D/YxIcEw== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.101" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.101.tgz#512f6c9e1749890f4d024e98cb995a63f562d458" - integrity sha512-QLOgVuUtCm23+4crlMKAeFfk9KGFXpRAwQeH7rYByu57hD074lX4uXMLJ0F1B7AO5kDhBRgQc6Dv0lCiiquUCw== +"@types/lodash@^4.0.0": + version "4.14.116" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz#5ccf215653e3e8c786a58390751033a9adca0eb9" + integrity sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg== "@types/lodash@^4.14.74": version "4.14.92" @@ -1747,31 +1740,51 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -lodash-es@^4.0.0: - version "4.17.5" - resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.5.tgz#9fc6e737b1c4d151d8f9cae2247305d552ce748f" - integrity sha512-Ez3ONp3TK9gX1HYKp6IhetcVybD+2F+Yp6GS9dfH8ue6EOCEzQtQEh4K0FYWBP9qLv+lzeQAYXw+3ySfxyZqkw== - lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= +lodash.isarray@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-4.0.0.tgz#2aca496b28c4ca6d726715313590c02e6ea34403" + integrity sha1-KspJayjEym1yZxUxNZDALm6jRAM= + +lodash.isfunction@^3.0.9: + version "3.0.9" + resolved "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" + integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.keys@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" + integrity sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU= + lodash.unescape@4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= -lodash@4.13.1: - version "4.13.1" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz#83e4b10913f48496d4d16fec4a560af2ee744b68" - integrity sha1-g+SxCRP0hJbU0W/sSlYK8u50S2g= +lodash.values@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347" + integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c= lodash@^4.17.4: version "4.17.4" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= +lodash@^4.17.5: + version "4.17.11" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + log-driver@^1.2.5: version "1.2.5" resolved "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" @@ -1995,12 +2008,16 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nesthydrationjs@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/nesthydrationjs/-/nesthydrationjs-1.0.3.tgz#fc3975747be72604eeaeea1761261e5c868ed5d8" - integrity sha512-Lt8tUy2MplpulivRHL97IolqpmVbcejaEvf+ZUYmFUKi3G009rIsa9vKk7G9fpfix5AdDE+olMmm6CtB9W6yEA== +nesthydrationjs@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/nesthydrationjs/-/nesthydrationjs-1.0.5.tgz#89fe5be87055184461de5a550475ac515491f921" + integrity sha512-LnqhV0LfczSX5LTp3UP1QIIyP8iEd0tn5ckslsPsnnbFxHWU25VXmR4cj/Ast/4MuEEYC8hxjrTQSHaZYwmBDQ== dependencies: - lodash "4.13.1" + lodash.isarray "^4.0.0" + lodash.isfunction "^3.0.9" + lodash.isplainobject "^4.0.6" + lodash.keys "^4.2.0" + lodash.values "^4.3.0" nise@^1.2.0: version "1.2.0" @@ -2432,14 +2449,14 @@ rc@1.2.5: minimist "^1.2.0" strip-json-comments "~2.0.1" -reactivedb@~0.10.2: - version "0.10.2" - resolved "https://registry.npmjs.org/reactivedb/-/reactivedb-0.10.2.tgz#297c0b05599b5c4fab4f7bf6c82cb81e50915b43" - integrity sha1-KXwLBVmbXE+rT3v2yCy4HlCRW0M= +reactivedb@0.11.1-alpha.0-rxnotreeshake: + version "0.11.1-alpha.0-rxnotreeshake" + resolved "https://registry.npmjs.org/reactivedb/-/reactivedb-0.11.1-alpha.0-rxnotreeshake.tgz#35ab43d561f039d063bb6ef06f00c511396c51f2" + integrity sha512-PtRRrdWTfO6FBoeiFq9iZet4ALu+n1z/WmYDJ2BVQBaM2T31cHgJu+t3uxV0INleE4mVKI8lkVkuKLu+bxoRgA== dependencies: "@types/lovefield" "^2.1.1" lovefield "2.1.12" - nesthydrationjs "^1.0.2" + nesthydrationjs "^1.0.5" read-pkg-up@^1.0.1: version "1.0.1" @@ -2656,20 +2673,20 @@ rrule@2.2.0: resolved "https://registry.npmjs.org/rrule/-/rrule-2.2.0.tgz#f346c523bf73707dafe562c222650467b49f6d5c" integrity sha1-80bFI79zcH2v5WLCImUEZ7SfbVw= -rxjs-marbles@^2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/rxjs-marbles/-/rxjs-marbles-2.4.1.tgz#0b1ae8f66fb3d3b6a6e5be9de35de1b47582771c" - integrity sha512-LQo0ZYan28k5uD4nSv2EI7OYVxNmxmjlaN6A8juN1H0a5y4bY6cuU58vS3DdN0MNfTOvltGgXHZ9Y3PgBIGWdg== +rxjs-marbles@^4.3.1: + version "4.3.1" + resolved "https://registry.npmjs.org/rxjs-marbles/-/rxjs-marbles-4.3.1.tgz#b20156be06106003c0164fe75a9cab871fdf9fc4" + integrity sha512-ZstjS6vTF+9kbNV3ENj7Uah7k5g7hs0DFHs+4vdxelphccqK6/v6rNH0MVzps2alYOs1Wqap/qfzT05UmwP3nw== dependencies: - "@types/lodash-es" "^4.0.0" - lodash-es "^4.0.0" + "@types/lodash" "^4.0.0" + lodash "^4.17.5" -rxjs@^5.4.3: - version "5.5.6" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz#e31fb96d6fd2ff1fd84bcea8ae9c02d007179c02" - integrity sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg== +rxjs@6: + version "6.3.2" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.3.2.tgz#6a688b16c4e6e980e62ea805ec30648e1c60907f" + integrity sha512-hV7criqbR0pe7EeL3O66UYVg92IR0XsA97+9y+BWTePK9SKmEI5Qd3Zj6uPnGkNzXsBywBQWTvujPl+1Kn9Zjw== dependencies: - symbol-observable "1.0.1" + tslib "^1.9.0" safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" @@ -2954,11 +2971,6 @@ supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= - tapable@^0.2.7: version "0.2.8" resolved "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"