From b6e80aae312b45d7c407f2aa1be7dbe0c08d00ae Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Mon, 15 Feb 2016 19:34:23 -0800 Subject: [PATCH 1/8] chore(test): setup test environment for typescript --- package.json | 2 +- spec/support/jasmine.json | 2 +- spec/tsconfig.json | 11 + typings/jasmine/jasmine.d.ts | 182 +- typings/lodash/lodash.d.ts | 18010 +++++++++++++++++++++++++++++++++ 5 files changed, 18123 insertions(+), 84 deletions(-) create mode 100644 spec/tsconfig.json create mode 100644 typings/lodash/lodash.d.ts diff --git a/package.json b/package.json index c041df97e1..cd25907caa 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "copy_src": "cp -r src/ dist/cjs/src && cp -r src/ dist/amd/src && cp -r src/ dist/es6/src", "cover": "istanbul cover -x \"*-spec.js index.js *-helper.js spec/helpers/*\" ./node_modules/jasmine/bin/jasmine.js && npm run cover_remapping", "cover_remapping": "remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped.json && remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped.lcov -t lcovonly && remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped -t html", - "test": "jasmine", + "test": "tsc --project ./spec --pretty && jasmine", "test_karma": "karma start karma.conf.js", "tests2png": "mkdirp tmp/docs/img && JASMINE_CONFIG_PATH=spec/support/tests2png.json jasmine", "watch": "watch \"echo triggering build && npm run build_test && echo build completed\" src -d -u -w=15", diff --git a/spec/support/jasmine.json b/spec/support/jasmine.json index ef7f685568..89907e5bbb 100644 --- a/spec/support/jasmine.json +++ b/spec/support/jasmine.json @@ -1,5 +1,5 @@ { - "spec_dir": "spec", + "spec_dir": "tmp", "spec_files": [ "**/*[sS]pec.js" ], diff --git a/spec/tsconfig.json b/spec/tsconfig.json new file mode 100644 index 0000000000..535b61be55 --- /dev/null +++ b/spec/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "removeComments": false, + "preserveConstEnums": true, + "sourceMap": false, + "declaration": false, + "target": "es5", + "module": "commonjs", + "outDir": "../tmp" + } +} \ No newline at end of file diff --git a/typings/jasmine/jasmine.d.ts b/typings/jasmine/jasmine.d.ts index 6e378543e2..7edec40e57 100644 --- a/typings/jasmine/jasmine.d.ts +++ b/typings/jasmine/jasmine.d.ts @@ -1,4 +1,6 @@ -// Type definitions for Jasmine 2.1 +// Compiled using typings@0.6.8 +// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/dd638012d63e069f2c99d06ef4dcc9616a943ee4/jasmine/jasmine.d.ts +// Type definitions for Jasmine 2.2 // Project: http://jasmine.github.io/ // Definitions by: Boris Yankov , Theodore Brown , David Pärsson // Definitions: https://github.com/borisyankov/DefinitelyTyped @@ -10,25 +12,25 @@ declare function describe(description: string, specDefinitions: () => void): voi declare function fdescribe(description: string, specDefinitions: () => void): void; declare function xdescribe(description: string, specDefinitions: () => void): void; -declare function it(expectation: string, assertion?: () => void): void; -declare function it(expectation: string, assertion?: (done: () => void) => void): void; -declare function fit(expectation: string, assertion?: () => void): void; -declare function fit(expectation: string, assertion?: (done: () => void) => void): void; -declare function xit(expectation: string, assertion?: () => void): void; -declare function xit(expectation: string, assertion?: (done: () => void) => void): void; +declare function it(expectation: string, assertion?: () => void, timeout?: number): void; +declare function it(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; +declare function fit(expectation: string, assertion?: () => void, timeout?: number): void; +declare function fit(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; +declare function xit(expectation: string, assertion?: () => void, timeout?: number): void; +declare function xit(expectation: string, assertion?: (done: () => void) => void, timeout?: number): void; /** If you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending. */ -declare function pending(): void; +declare function pending(reason?: string): void; -declare function beforeEach(action: () => void): void; -declare function beforeEach(action: (done: () => void) => void): void; -declare function afterEach(action: () => void): void; -declare function afterEach(action: (done: () => void) => void): void; +declare function beforeEach(action: () => void, timeout?: number): void; +declare function beforeEach(action: (done: () => void) => void, timeout?: number): void; +declare function afterEach(action: () => void, timeout?: number): void; +declare function afterEach(action: (done: () => void) => void, timeout?: number): void; -declare function beforeAll(action: () => void): void; -declare function beforeAll(action: (done: () => void) => void): void; -declare function afterAll(action: () => void): void; -declare function afterAll(action: (done: () => void) => void): void; +declare function beforeAll(action: () => void, timeout?: number): void; +declare function beforeAll(action: (done: () => void) => void, timeout?: number): void; +declare function afterAll(action: () => void, timeout?: number): void; +declare function afterAll(action: (done: () => void) => void, timeout?: number): void; declare function expect(spy: Function): jasmine.Matchers; declare function expect(actual: any): jasmine.Matchers; @@ -46,13 +48,18 @@ declare module jasmine { var clock: () => Clock; function any(aclass: any): Any; + function anything(): Any; + function arrayContaining(sample: any[]): ArrayContaining; function objectContaining(sample: any): ObjectContaining; - export function createSpy(name: string, originalFn?: Function): Spy; - export function createSpyObj(baseName: string, methodNames: any[]): any; - export function createSpyObj(baseName: string, methodNames: any[]): T; + function createSpy(name: string, originalFn?: Function): Spy; + function createSpyObj(baseName: string, methodNames: any[]): any; + function createSpyObj(baseName: string, methodNames: any[]): T; function pp(value: any): string; function getEnv(): Env; - function addMatchers(matchers: any): Any; + function addCustomEqualityTester(equalityTester: CustomEqualityTester): void; + function addMatchers(matchers: CustomMatcherFactories): void; + function stringMatching(str: string): Any; + function stringMatching(str: RegExp): Any; interface Any { @@ -62,6 +69,19 @@ declare module jasmine { jasmineToString(): string; } + // taken from TypeScript lib.core.es6.d.ts, applicable to CustomMatchers.contains() + interface ArrayLike { + length: number; + [n: number]: T; + } + + interface ArrayContaining { + new (sample: any[]): any; + + asymmetricMatch(other: any): boolean; + jasmineToString(): string; + } + interface ObjectContaining { new (sample: any): any; @@ -89,6 +109,35 @@ declare module jasmine { uninstall(): void; /** Calls to any registered callback are triggered when the clock is ticked forward via the jasmine.clock().tick function, which takes a number of milliseconds. */ tick(ms: number): void; + mockDate(date?: Date): void; + } + + interface CustomEqualityTester { + (first: any, second: any): boolean; + } + + interface CustomMatcher { + compare(actual: T, expected: T): CustomMatcherResult; + compare(actual: any, expected: any): CustomMatcherResult; + } + + interface CustomMatcherFactory { + (util: MatchersUtil, customEqualityTesters: Array): CustomMatcher; + } + + interface CustomMatcherFactories { + [index: string]: CustomMatcherFactory; + } + + interface CustomMatcherResult { + pass: boolean; + message?: string; + } + + interface MatchersUtil { + equals(a: any, b: any, customTesters?: Array): boolean; + contains(haystack: ArrayLike | string, needle: any, customTesters?: Array): boolean; + buildFailureMessage(matcherName: string, isNot: boolean, actual: any, ...expected: Array): string; } interface Env { @@ -122,7 +171,8 @@ declare module jasmine { compareObjects_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; equals_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean; contains_(haystack: any, needle: any): boolean; - addEqualityTester(equalityTester: (a: any, b: any, env: Env, mismatchKeys: string[], mismatchValues: string[]) => boolean): void; + addCustomEqualityTester(equalityTester: CustomEqualityTester): void; + addMatchers(matchers: CustomMatcherFactories): void; specFilter(spec: Spec): boolean; } @@ -231,27 +281,25 @@ declare module jasmine { isNot?: boolean; message(): any; - - (expected: any): boolean; - toEqual(expected: any): boolean; - toMatch(expected: any): boolean; - toBeDefined(): boolean; - toBeUndefined(): boolean; - toBeNull(): boolean; + toBe(expected: any, expectationFailOutput?: any): boolean; + toEqual(expected: any, expectationFailOutput?: any): boolean; + toMatch(expected: string | RegExp, expectationFailOutput?: any): boolean; + toBeDefined(expectationFailOutput?: any): boolean; + toBeUndefined(expectationFailOutput?: any): boolean; + toBeNull(expectationFailOutput?: any): boolean; toBeNaN(): boolean; - toBeTruthy(): boolean; - toBeFalsy(): boolean; + toBeTruthy(expectationFailOutput?: any): boolean; + toBeFalsy(expectationFailOutput?: any): boolean; toHaveBeenCalled(): boolean; toHaveBeenCalledWith(...params: any[]): boolean; - toContain(expected: any): boolean; - toBeLessThan(expected: any): boolean; - toBeGreaterThan(expected: any): boolean; - toBeCloseTo(expected: any, precision: any): boolean; - toContainHtml(expected: string): boolean; - toContainText(expected: string): boolean; + toHaveBeenCalledTimes(expected: number): boolean; + toContain(expected: any, expectationFailOutput?: any): boolean; + toBeLessThan(expected: number, expectationFailOutput?: any): boolean; + toBeGreaterThan(expected: number, expectationFailOutput?: any): boolean; + toBeCloseTo(expected: number, precision: any, expectationFailOutput?: any): boolean; toThrow(expected?: any): boolean; - toThrowError(expected?: any): boolean; - + toThrowError(message?: string | RegExp): boolean; + toThrowError(expected?: Error, message?: string | RegExp): boolean; not: Matchers; Any: Any; @@ -322,7 +370,7 @@ declare module jasmine { waitsFor(latchFunction: SpecFunction, timeoutMessage?: string, timeout?: number): Spec; fail(e?: any): void; getMatchersClass_(): Matchers; - addMatchers(matchersPrototype: any): void; + addMatchers(matchersPrototype: CustomMatcherFactories): void; finishCallback(): void; finish(onComplete?: () => void): void; after(doAfter: SpecFunction): void; @@ -371,18 +419,17 @@ declare module jasmine { mostRecentCall: { args: any[]; }; argsForCall: any[]; wasCalled: boolean; - callCount: number; } interface SpyAnd { /** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */ callThrough(): Spy; /** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */ - returnValue(val: any): void; + returnValue(val: any): Spy; /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */ callFake(fn: Function): Spy; /** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */ - throwError(msg: string): void; + throwError(msg: string): Spy; /** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */ stub(): Spy; } @@ -397,15 +444,22 @@ declare module jasmine { /** By chaining the spy with calls.allArgs(), will return the arguments to all calls **/ allArgs(): any[]; /** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls **/ - all(): any; + all(): CallInfo[]; /** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call **/ - mostRecent(): any; + mostRecent(): CallInfo; /** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call **/ - first(): any; + first(): CallInfo; /** By chaining the spy with calls.reset(), will clears all tracking for a spy **/ reset(): void; } + interface CallInfo { + /** The context (the this) for the call */ + object: any; + /** All arguments passed to the call */ + args: any[]; + } + interface Util { inherit(childClass: Function, parentClass: Function): any; formatException(e: any): any; @@ -441,40 +495,4 @@ declare module jasmine { export var HtmlReporter: HtmlReporter; export var HtmlSpecFilter: HtmlSpecFilter; export var DEFAULT_TIMEOUT_INTERVAL: number; - - export interface GlobalPolluter { - describe(description: string, specDefinitions: () => void): void; - fdescribe(description: string, specDefinitions: () => void): void; - xdescribe(description: string, specDefinitions: () => void): void; - - it(expectation: string, assertion?: () => void): void; - it(expectation: string, assertion?: (done: () => void) => void): void; - fit(expectation: string, assertion?: () => void): void; - fit(expectation: string, assertion?: (done: () => void) => void): void; - xit(expectation: string, assertion?: () => void): void; - xit(expectation: string, assertion?: (done: () => void) => void): void; - - pending(): void; - - beforeEach(action: () => void): void; - beforeEach(action: (done: () => void) => void): void; - afterEach(action: () => void): void; - afterEach(action: (done: () => void) => void): void; - - beforeAll(action: () => void): void; - beforeAll(action: (done: () => void) => void): void; - afterAll(action: () => void): void; - afterAll(action: (done: () => void) => void): void; - - expect(spy: Function): jasmine.Matchers; - expect(actual: any): jasmine.Matchers; - - fail(e?: any): void; - - spyOn(object: any, method: string): jasmine.Spy; - - runs(asyncMethod: Function): void; - waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void; - waits(timeout?: number): void; - } -} +} \ No newline at end of file diff --git a/typings/lodash/lodash.d.ts b/typings/lodash/lodash.d.ts new file mode 100644 index 0000000000..b0a3f1466a --- /dev/null +++ b/typings/lodash/lodash.d.ts @@ -0,0 +1,18010 @@ +// Compiled using typings@0.6.8 +// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/c8630523ef2ee3fb42fe65cc17af5b1b56e611bc/lodash/lodash.d.ts +// Type definitions for Lo-Dash +// Project: http://lodash.com/ +// Definitions by: Brian Zengel , Ilya Mochalov +// Definitions: https://github.com/borisyankov/DefinitelyTyped + + +/** +### 4.0.0 Changelog (https://github.com/lodash/lodash/wiki/Changelog) + +#### TODO: +removed: +- [x] Removed _.support +- [x] Removed _.findWhere in favor of _.find with iteratee shorthand +- [x] Removed _.where in favor of _.filter with iteratee shorthand +- [x] Removed _.pluck in favor of _.map with iteratee shorthand + +renamed: +- [x] Renamed _.first to _.head +- [x] Renamed _.indexBy to _.keyBy +- [x] Renamed _.invoke to _.invokeMap +- [x] Renamed _.overArgs to _.overArgs +- [x] Renamed _.padLeft & _.padRight to _.padStart & _.padEnd +- [x] Renamed _.pairs to _.toPairs +- [x] Renamed _.rest to _.tail +- [x] Renamed _.restParam to _.rest +- [x] Renamed _.sortByOrder to _.orderBy +- [x] Renamed _.trimLeft & _.trimRight to _.trimStart & _.trimEnd +- [x] Renamed _.trunc to _.truncate + +split: +- [x] Split _.indexOf & _.lastIndexOf into _.sortedIndexOf & _.sortedLastIndexOf +- [x] Split _.max & _.min into _.maxBy & _.minBy +- [x] Split _.omit & _.pick into _.omitBy & _.pickBy +- [x] Split _.sample into _.sampleSize +- [x] Split _.sortedIndex into _.sortedIndexBy +- [x] Split _.sortedLastIndex into _.sortedLastIndexBy +- [x] Split _.uniq into _.sortedUniq, _.sortedUniqBy, & _.uniqBy + +changes: +- [x] Absorbed _.sortByAll into _.sortBy +- [x] Changed the category of _.at to “Object” +- [x] Changed the category of _.bindAll to “Utility” +- [x] Made _.capitalize uppercase the first character & lowercase the rest +- [x] Made _.functions return only own method names + + +added 23 array methods: +- [x] _.concat +- [x] _.differenceBy +- [x] _.differenceWith +- [x] _.flatMap +- [x] _.fromPairs +- [x] _.intersectionBy +- [x] _.intersectionWith +- [x] _.join +- [x] _.pullAll +- [x] _.pullAllBy +- [x] _.reverse +- [x] _.sortedIndexBy +- [x] _.sortedIndexOf +- [x] _.sortedLastIndexBy +- [x] _.sortedLastIndexOf +- [x] _.sortedUniq +- [x] _.sortedUniqBy +- [x] _.unionBy +- [x] _.unionWith +- [x] _.uniqBy +- [x] _.uniqWith +- [x] _.xorBy +- [x] _.xorWith + +added 18 lang methods: +- [x] _.cloneDeepWith +- [x] _.cloneWith +- [x] _.eq +- [x] _.isArrayLike +- [x] _.isArrayLikeObject +- [x] _.isEqualWith +- [x] _.isInteger +- [x] _.isLength +- [x] _.isMatchWith +- [x] _.isNil +- [x] _.isObjectLike +- [x] _.isSafeInteger +- [x] _.isSymbol +- [x] _.toInteger +- [x] _.toLength +- [x] _.toNumber +- [x] _.toSafeInteger +- [x] _.toString + +added 13 object methods: +- [x] _.assignIn +- [x] _.assignInWith +- [x] _.assignWith +- [x] _.functionsIn +- [x] _.hasIn +- [x] _.mergeWith +- [x] _.omitBy +- [x] _.pickBy + + +added 8 string methods: +- [x] _.lowerCase +- [x] _.lowerFirst +- [x] _.upperCase +- [x] _.upperFirst +- [x] _.toLower +- [x] _.toUpper + +added 8 utility methods: +- [x] _.toPath + +added 4 math methods: +- [x] _.maxBy +- [x] _.mean +- [x] _.minBy +- [x] _.sumBy + +added 2 function methods: +- [x] _.flip +- [x] _.unary + +added 2 number methods: +- [x] _.clamp +- [x] _.subtract + +added collection method: +- [x] _.sampleSize + +Added 3 aliases + +- [x] _.first as an alias of _.head + +Removed 17 aliases +- [x] Removed aliase _.all +- [x] Removed aliase _.any +- [x] Removed aliase _.backflow +- [x] Removed aliase _.callback +- [x] Removed aliase _.collect +- [x] Removed aliase _.compose +- [x] Removed aliase _.contains +- [x] Removed aliase _.detect +- [x] Removed aliase _.foldl +- [x] Removed aliase _.foldr +- [x] Removed aliase _.include +- [x] Removed aliase _.inject +- [x] Removed aliase _.methods +- [x] Removed aliase _.object +- [x] Removed aliase _.run +- [x] Removed aliase _.select +- [x] Removed aliase _.unique + +Other changes +- [x] Added support for array buffers to _.isEqual +- [x] Added support for converting iterators to _.toArray +- [x] Added support for deep paths to _.zipObject +- [x] Changed UMD to export to window or self when available regardless of other exports +- [x] Ensured debounce cancel clears args & thisArg references +- [x] Ensured _.add, _.subtract, & _.sum don’t skip NaN values +- [x] Ensured _.clone treats generators like functions +- [x] Ensured _.clone produces clones with the source’s [[Prototype]] +- [x] Ensured _.defaults assigns properties that shadow Object.prototype +- [x] Ensured _.defaultsDeep doesn’t merge a string into an array +- [x] Ensured _.defaultsDeep & _.merge don’t modify sources +- [x] Ensured _.defaultsDeep works with circular references +- [x] Ensured _.keys skips “length” on strict mode arguments objects in Safari 9 +- [x] Ensured _.merge doesn’t convert strings to arrays +- [x] Ensured _.merge merges plain-objects onto non plain-objects +- [x] Ensured _#plant resets iterator data of cloned sequences +- [x] Ensured _.random swaps min & max if min is greater than max +- [x] Ensured _.range preserves the sign of start of -0 +- [x] Ensured _.reduce & _.reduceRight use getIteratee in their array branch +- [x] Fixed rounding issue with the precision param of _.floor + +** LATER ** +Misc: +- [ ] Made _.forEach, _.forIn, _.forOwn, & _.times implicitly end a chain sequence +- [ ] Removed thisArg params from most methods +- [ ] Made “By” methods provide a single param to iteratees +- [ ] Made _.words chainable by default +- [ ] Removed isDeep params from _.clone & _.flatten +- [ ] Removed _.bindAll support for binding all methods when no names are provided +- [ ] Removed func-first param signature from _.before & _.after +- [ ] _.extend as an alias of _.assignIn +- [ ] _.extendWith as an alias of _.assignInWith +- [ ] Added clear method to _.memoize.Cache +- [ ] Added flush method to debounced & throttled functions +- [ ] Added support for ES6 maps, sets, & symbols to _.clone, _.isEqual, & _.toArray +- [ ] Enabled _.flow & _.flowRight to accept an array of functions +- [ ] Ensured “Collection” methods treat functions as objects +- [ ] Ensured _.assign, _.defaults, & _.merge coerce object values to objects +- [ ] Ensured _.bindKey bound functions call object[key] when called with the new operator +- [ ] Ensured _.isFunction returns true for generator functions +- [ ] Ensured _.merge assigns typed arrays directly +- [ ] Made _(...) an iterator & iterable +- [ ] Made _.drop, _.take, & right forms coerce n of undefined to 0 + +Methods: +- [ ] _.concat +- [ ] _.differenceBy +- [ ] _.differenceWith +- [ ] _.flatMap +- [ ] _.fromPairs +- [ ] _.intersectionBy +- [ ] _.intersectionWith +- [ ] _.join +- [ ] _.pullAll +- [ ] _.pullAllBy +- [ ] _.reverse +- [ ] _.sortedLastIndexOf +- [ ] _.unionBy +- [ ] _.unionWith +- [ ] _.uniqWith +- [ ] _.xorBy +- [ ] _.xorWith +- [ ] _.toString + +- [ ] _.invoke +- [ ] _.setWith +- [ ] _.toPairs +- [ ] _.toPairsIn +- [ ] _.unset + +- [ ] _.replace +- [ ] _.split + +- [ ] _.cond +- [ ] _.conforms +- [ ] _.nthArg +- [ ] _.over +- [ ] _.overEvery +- [ ] _.overSome +- [ ] _.rangeRight + +- [ ] _.next +*/ + +declare var _: _.LoDashStatic; + +declare module _ { + interface LoDashStatic { + /** + * Creates a lodash object which wraps the given value to enable intuitive method chaining. + * + * In addition to Lo-Dash methods, wrappers also have the following Array methods: + * concat, join, pop, push, reverse, shift, slice, sort, splice, and unshift + * + * Chaining is supported in custom builds as long as the value method is implicitly or + * explicitly included in the build. + * + * The chainable wrapper functions are: + * after, assign, bind, bindAll, bindKey, chain, chunk, compact, compose, concat, countBy, + * createCallback, curry, debounce, defaults, defer, delay, difference, filter, flatten, + * forEach, forEachRight, forIn, forInRight, forOwn, forOwnRight, functions, groupBy, + * keyBy, initial, intersection, invert, invoke, keys, map, max, memoize, merge, min, + * object, omit, once, pairs, partial, partialRight, pick, pluck, pull, push, range, reject, + * remove, rest, reverse, sample, shuffle, slice, sort, sortBy, splice, tap, throttle, times, + * toArray, transform, union, uniq, unset, unshift, unzip, values, where, without, wrap, and zip + * + * The non-chainable wrapper functions are: + * clone, cloneDeep, contains, escape, every, find, findIndex, findKey, findLast, + * findLastIndex, findLastKey, has, identity, indexOf, isArguments, isArray, isBoolean, + * isDate, isElement, isEmpty, isEqual, isFinite, isFunction, isNaN, isNull, isNumber, + * isObject, isPlainObject, isRegExp, isString, isUndefined, join, lastIndexOf, mixin, + * noConflict, parseInt, pop, random, reduce, reduceRight, result, shift, size, some, + * sortedIndex, runInContext, template, unescape, uniqueId, and value + * + * The wrapper functions first and last return wrapped values when n is provided, otherwise + * they return unwrapped values. + * + * Explicit chaining can be enabled by using the _.chain method. + **/ + (value: number): LoDashImplicitWrapper; + (value: string): LoDashImplicitStringWrapper; + (value: boolean): LoDashImplicitWrapper; + (value: Array): LoDashImplicitNumberArrayWrapper; + (value: Array): LoDashImplicitArrayWrapper; + (value: T): LoDashImplicitObjectWrapper; + (value: any): LoDashImplicitWrapper; + + /** + * The semantic version number. + **/ + VERSION: string; + + /** + * By default, the template delimiters used by Lo-Dash are similar to those in embedded Ruby + * (ERB). Change the following template settings to use alternative delimiters. + **/ + templateSettings: TemplateSettings; + } + + /** + * By default, the template delimiters used by Lo-Dash are similar to those in embedded Ruby + * (ERB). Change the following template settings to use alternative delimiters. + **/ + interface TemplateSettings { + /** + * The "escape" delimiter. + **/ + escape?: RegExp; + + /** + * The "evaluate" delimiter. + **/ + evaluate?: RegExp; + + /** + * An object to import into the template as local variables. + **/ + imports?: Dictionary; + + /** + * The "interpolate" delimiter. + **/ + interpolate?: RegExp; + + /** + * Used to reference the data object in the template text. + **/ + variable?: string; + } + + /** + * Creates a cache object to store key/value pairs. + */ + interface MapCache { + /** + * Removes `key` and its value from the cache. + * @param key The key of the value to remove. + * @return Returns `true` if the entry was removed successfully, else `false`. + */ + delete(key: string): boolean; + + /** + * Gets the cached value for `key`. + * @param key The key of the value to get. + * @return Returns the cached value. + */ + get(key: string): any; + + /** + * Checks if a cached value for `key` exists. + * @param key The key of the entry to check. + * @return Returns `true` if an entry for `key` exists, else `false`. + */ + has(key: string): boolean; + + /** + * Sets `value` to `key` of the cache. + * @param key The key of the value to cache. + * @param value The value to cache. + * @return Returns the cache object. + */ + set(key: string, value: any): _.Dictionary; + } + + interface LoDashWrapperBase { } + + interface LoDashImplicitWrapperBase extends LoDashWrapperBase { } + + interface LoDashExplicitWrapperBase extends LoDashWrapperBase { } + + interface LoDashImplicitWrapper extends LoDashImplicitWrapperBase> { } + + interface LoDashExplicitWrapper extends LoDashExplicitWrapperBase> { } + + interface LoDashImplicitStringWrapper extends LoDashImplicitWrapper { } + + interface LoDashExplicitStringWrapper extends LoDashExplicitWrapper { } + + interface LoDashImplicitObjectWrapper extends LoDashImplicitWrapperBase> { } + + interface LoDashExplicitObjectWrapper extends LoDashExplicitWrapperBase> { } + + interface LoDashImplicitArrayWrapper extends LoDashImplicitWrapperBase> { + pop(): T; + push(...items: T[]): LoDashImplicitArrayWrapper; + shift(): T; + sort(compareFn?: (a: T, b: T) => number): LoDashImplicitArrayWrapper; + splice(start: number): LoDashImplicitArrayWrapper; + splice(start: number, deleteCount: number, ...items: any[]): LoDashImplicitArrayWrapper; + unshift(...items: T[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper extends LoDashExplicitWrapperBase> { } + + interface LoDashImplicitNumberArrayWrapper extends LoDashImplicitArrayWrapper { } + + interface LoDashExplicitNumberArrayWrapper extends LoDashExplicitArrayWrapper { } + + /********* + * Array * + *********/ + + //_.chunk + interface LoDashStatic { + /** + * Creates an array of elements split into groups the length of size. If collection can’t be split evenly, the + * final chunk will be the remaining elements. + * + * @param array The array to process. + * @param size The length of each chunk. + * @return Returns the new array containing chunks. + */ + chunk( + array: List, + size?: number + ): T[][]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.chunk + */ + chunk(size?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.chunk + */ + chunk(size?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.chunk + */ + chunk(size?: number): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.chunk + */ + chunk(size?: number): LoDashExplicitArrayWrapper; + } + + //_.compact + interface LoDashStatic { + /** + * Creates an array with all falsey values removed. The values false, null, 0, "", undefined, and NaN are + * falsey. + * + * @param array The array to compact. + * @return (Array) Returns the new array of filtered values. + */ + compact(array?: List): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.compact + */ + compact(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.compact + */ + compact(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.compact + */ + compact(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.compact + */ + compact(): LoDashExplicitArrayWrapper; + } + + //_.concat DUMMY + interface LoDashStatic { + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + concat(...values: (T[]|List)[]) : T[]; + } + + //_.difference + interface LoDashStatic { + /** + * Creates an array of unique array values not included in the other provided arrays using SameValueZero for + * equality comparisons. + * + * @param array The array to inspect. + * @param values The arrays of values to exclude. + * @return Returns the new array of filtered values. + */ + difference( + array: any[]|List, + ...values: any[] + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.difference + */ + difference(...values: (T[]|List)[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.difference + */ + difference(...values: (TValue[]|List)[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.difference + */ + difference(...values: (T[]|List)[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.difference + */ + difference(...values: (TValue[]|List)[]): LoDashExplicitArrayWrapper; + } + + //_.differenceBy + interface LoDashStatic { + /** + * This method is like _.difference except that it accepts iteratee which is invoked for each element of array + * and values to generate the criterion by which uniqueness is computed. The iteratee is invoked with one + * argument: (value). + * + * @param array The array to inspect. + * @param values The values to exclude. + * @param iteratee The iteratee invoked per element. + * @returns Returns the new array of filtered values. + */ + differenceBy( + array: T[]|List, + values?: T[]|List, + iteratee?: ((value: T) => any)|string + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values?: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + iteratee?: ((value: T) => any)|string + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: ((value: T) => any)|string + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: ((value: T) => any)|string + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: ((value: T) => any)|string + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.differenceBy + */ + differenceBy( + array: T[]|List, + ...values: any[] + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + ...values: any[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + ...values: any[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + ...values: any[] + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: ((value: T) => any)|string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + values1?: T[]|List, + values2?: T[]|List, + values3?: T[]|List, + values4?: T[]|List, + values5?: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.differenceBy + */ + differenceBy( + ...values: any[] + ): LoDashExplicitArrayWrapper; + } + + //_.differenceWith DUMMY + interface LoDashStatic { + /** + * Creates an array of unique `array` values not included in the other + * provided arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.difference([3, 2, 1], [4, 2]); + * // => [3, 1] + */ + differenceWith( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.drop + interface LoDashStatic { + /** + * Creates a slice of array with n elements dropped from the beginning. + * + * @param array The array to query. + * @param n The number of elements to drop. + * @return Returns the slice of array. + */ + drop(array: T[]|List, n?: number): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.drop + */ + drop(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.drop + */ + drop(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.drop + */ + drop(n?: number): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.drop + */ + drop(n?: number): LoDashExplicitArrayWrapper; + } + + //_.dropRight + interface LoDashStatic { + /** + * Creates a slice of array with n elements dropped from the end. + * + * @param array The array to query. + * @param n The number of elements to drop. + * @return Returns the slice of array. + */ + dropRight( + array: List, + n?: number + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.dropRight + */ + dropRight(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.dropRight + */ + dropRight(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.dropRight + */ + dropRight(n?: number): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.dropRight + */ + dropRight(n?: number): LoDashExplicitArrayWrapper; + } + + //_.dropRightWhile + interface LoDashStatic { + /** + * Creates a slice of array excluding elements dropped from the end. Elements are dropped until predicate + * returns falsey. The predicate is bound to thisArg and invoked with three arguments: (value, index, array). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * match the properties of the given object, else false. + * + * @param array The array to query. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the slice of array. + */ + dropRightWhile( + array: List, + predicate?: ListIterator, + thisArg?: any + ): TValue[]; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + array: List, + predicate?: string, + thisArg?: any + ): TValue[]; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + array: List, + predicate?: TWhere + ): TValue[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropRightWhile + */ + dropRightWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + //_.dropWhile + interface LoDashStatic { + /** + * Creates a slice of array excluding elements dropped from the beginning. Elements are dropped until predicate + * returns falsey. The predicate is bound to thisArg and invoked with three arguments: (value, index, array). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param array The array to query. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the slice of array. + */ + dropWhile( + array: List, + predicate?: ListIterator, + thisArg?: any + ): TValue[]; + + /** + * @see _.dropWhile + */ + dropWhile( + array: List, + predicate?: string, + thisArg?: any + ): TValue[]; + + /** + * @see _.dropWhile + */ + dropWhile( + array: List, + predicate?: TWhere + ): TValue[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.dropWhile + */ + dropWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + //_.fill + interface LoDashStatic { + /** + * Fills elements of array with value from start up to, but not including, end. + * + * Note: This method mutates array. + * + * @param array The array to fill. + * @param value The value to fill array with. + * @param start The start position. + * @param end The end position. + * @return Returns array. + */ + fill( + array: any[], + value: T, + start?: number, + end?: number + ): T[]; + + /** + * @see _.fill + */ + fill( + array: List, + value: T, + start?: number, + end?: number + ): List; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.fill + */ + fill( + value: T, + start?: number, + end?: number + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.fill + */ + fill( + value: T, + start?: number, + end?: number + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.fill + */ + fill( + value: T, + start?: number, + end?: number + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.fill + */ + fill( + value: T, + start?: number, + end?: number + ): LoDashExplicitObjectWrapper>; + } + + //_.findIndex + interface LoDashStatic { + /** + * This method is like _.find except that it returns the index of the first element predicate returns truthy + * for instead of the element itself. + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param array The array to search. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the index of the found element, else -1. + */ + findIndex( + array: List, + predicate?: ListIterator, + thisArg?: any + ): number; + + /** + * @see _.findIndex + */ + findIndex( + array: List, + predicate?: string, + thisArg?: any + ): number; + + /** + * @see _.findIndex + */ + findIndex( + array: List, + predicate?: W + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.findIndex + */ + findIndex( + predicate?: ListIterator, + thisArg?: any + ): number; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: string, + thisArg?: any + ): number; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: W + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.findIndex + */ + findIndex( + predicate?: ListIterator, + thisArg?: any + ): number; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: string, + thisArg?: any + ): number; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: W + ): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.findIndex + */ + findIndex( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: string, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: W + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.findIndex + */ + findIndex( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: string, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findIndex + */ + findIndex( + predicate?: W + ): LoDashExplicitWrapper; + } + + //_.findLastIndex + interface LoDashStatic { + /** + * This method is like _.findIndex except that it iterates over elements of collection from right to left. + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param array The array to search. + * @param predicate The function invoked per iteration. + * @param thisArg The function invoked per iteration. + * @return Returns the index of the found element, else -1. + */ + findLastIndex( + array: List, + predicate?: ListIterator, + thisArg?: any + ): number; + + /** + * @see _.findLastIndex + */ + findLastIndex( + array: List, + predicate?: string, + thisArg?: any + ): number; + + /** + * @see _.findLastIndex + */ + findLastIndex( + array: List, + predicate?: W + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: ListIterator, + thisArg?: any + ): number; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: string, + thisArg?: any + ): number; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: W + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: ListIterator, + thisArg?: any + ): number; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: string, + thisArg?: any + ): number; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: W + ): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: string, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: W + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: string, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastIndex + */ + findLastIndex( + predicate?: W + ): LoDashExplicitWrapper; + } + + //_.first + interface LoDashStatic { + /** + * @see _.head + */ + first(array: List): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.head + */ + first(): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.head + */ + first(): TResult; + } + + interface RecursiveArray extends Array> {} + interface ListOfRecursiveArraysOrValues extends List> {} + + //_.flatMap DUMMY + interface LoDashStatic { + /** + * Creates an array of flattened values by running each element in `array` + * through `iteratee` and concating its result to the other mapped values. + * The iteratee is invoked with three arguments: (value, index|key, array). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new array. + * @example + * + * function duplicate(n) { + * return [n, n]; + * } + * + * _.flatMap([1, 2], duplicate); + * // => [1, 1, 2, 2] + */ + flatMap( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.flatten + interface LoDashStatic { + /** + * Flattens a nested array. If isDeep is true the array is recursively flattened, otherwise it’s only + * flattened a single level. + * + * @param array The array to flatten. + * @param isDeep Specify a deep flatten. + * @return Returns the new flattened array. + */ + flatten(array: ListOfRecursiveArraysOrValues, isDeep: boolean): T[]; + + /** + * @see _.flatten + */ + flatten(array: List): T[]; + + /** + * @see _.flatten + */ + flatten(array: ListOfRecursiveArraysOrValues): RecursiveArray; + } + + interface LoDashImplicitWrapper { + /** + * @see _.flatten + */ + flatten(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.flatten + */ + flatten(isDeep?: boolean): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.flatten + */ + flatten(isDeep?: boolean): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.flatten + */ + flatten(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.flatten + */ + flatten(isDeep?: boolean): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.flatten + */ + flatten(isDeep?: boolean): LoDashExplicitArrayWrapper; + } + + //_.flattenDeep + interface LoDashStatic { + /** + * Recursively flattens a nested array. + * + * @param array The array to recursively flatten. + * @return Returns the new flattened array. + */ + flattenDeep(array: ListOfRecursiveArraysOrValues): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.flattenDeep + */ + flattenDeep(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.flattenDeep + */ + flattenDeep(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.flattenDeep + */ + flattenDeep(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.flattenDeep + */ + flattenDeep(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.flattenDeep + */ + flattenDeep(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.flattenDeep + */ + flattenDeep(): LoDashExplicitArrayWrapper; + } + + //_.fromPairs DUMMY + interface LoDashStatic { + /** + * The inverse of `_.toPairs`; this method returns an object composed + * from key-value `pairs`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} pairs The key-value pairs. + * @returns {Object} Returns the new object. + * @example + * + * _.fromPairs([['fred', 30], ['barney', 40]]); + * // => { 'fred': 30, 'barney': 40 } + */ + fromPairs( + array: any[]|List + ): any[]; + } + + //_.head + interface LoDashStatic { + /** + * Gets the first element of array. + * + * @alias _.first + * + * @param array The array to query. + * @return Returns the first element of array. + */ + head(array: List): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.first + */ + head(): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.first + */ + head(): TResult; + } + + //_.indexOf + interface LoDashStatic { + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the offset + * from the end of `array`. If `array` is sorted providing `true` for `fromIndex` + * performs a faster binary search. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // using `fromIndex` + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + indexOf( + array: List, + value: T, + fromIndex?: boolean|number + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.indexOf + */ + indexOf( + value: T, + fromIndex?: boolean|number + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.indexOf + */ + indexOf( + value: TValue, + fromIndex?: boolean|number + ): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.indexOf + */ + indexOf( + value: T, + fromIndex?: boolean|number + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.indexOf + */ + indexOf( + value: TValue, + fromIndex?: boolean|number + ): LoDashExplicitWrapper; + } + + //_.intersectionBy DUMMY + interface LoDashStatic { + /** + * This method is like `_.intersection` except that it accepts `iteratee` + * which is invoked for each element of each `arrays` to generate the criterion + * by which uniqueness is computed. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of shared values. + * @example + * + * _.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor); + * // => [2.1] + * + * // using the `_.property` iteratee shorthand + * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }] + */ + intersectionBy( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.intersectionWith DUMMY + interface LoDashStatic { + /** + * This method is like `_.intersection` except that it accepts `comparator` + * which is invoked to compare elements of `arrays`. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.intersectionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }] + */ + intersectionWith( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.join + interface LoDashStatic { + /** + * Converts all elements in `array` into a string separated by `separator`. + * + * @param array The array to convert. + * @param separator The element separator. + * @returns Returns the joined string. + */ + join( + array: List, + separator?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.join + */ + join(separator?: string): string; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.join + */ + join(separator?: string): string; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.join + */ + join(separator?: string): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.join + */ + join(separator?: string): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.join + */ + join(separator?: string): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.join + */ + join(separator?: string): LoDashExplicitWrapper; + } + + //_.pullAll DUMMY + interface LoDashStatic { + /** + * This method is like `_.pull` except that it accepts an array of values to remove. + * + * **Note:** Unlike `_.difference`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3, 1, 2, 3]; + * + * _.pull(array, [2, 3]); + * console.log(array); + * // => [1, 1] + */ + pullAll( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.pullAllBy DUMMY + interface LoDashStatic { + /** + * This method is like `_.pullAll` except that it accepts `iteratee` which is + * invoked for each element of `array` and `values` to to generate the criterion + * by which uniqueness is computed. The iteratee is invoked with one argument: (value). + * + * **Note:** Unlike `_.differenceBy`, this method mutates `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to modify. + * @param {Array} values The values to remove. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns `array`. + * @example + * + * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }]; + * + * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x'); + * console.log(array); + * // => [{ 'x': 2 }] + */ + pullAllBy( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.reverse DUMMY + interface LoDashStatic { + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @memberOf _ + * @category Array + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + reverse( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.sortedIndexOf + interface LoDashStatic { + /** + * This method is like `_.indexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedIndexOf([1, 1, 2, 2], 2); + * // => 2 + */ + sortedIndexOf( + array: List, + value: T + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedIndexOf + */ + sortedIndexOf( + value: T + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortedIndexOf + */ + sortedIndexOf( + value: TValue + ): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedIndexOf + */ + sortedIndexOf( + value: T + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedIndexOf + */ + sortedIndexOf( + value: TValue + ): LoDashExplicitWrapper; + } + + //_.initial + interface LoDashStatic { + /** + * Gets all but the last element of array. + * + * @param array The array to query. + * @return Returns the slice of array. + */ + initial(array: List): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.initial + */ + initial(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.initial + */ + initial(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.initial + */ + initial(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.initial + */ + initial(): LoDashExplicitArrayWrapper; + } + + //_.intersection + interface LoDashStatic { + /** + * Creates an array of unique values that are included in all of the provided arrays using SameValueZero for + * equality comparisons. + * + * @param arrays The arrays to inspect. + * @return Returns the new array of shared values. + */ + intersection(...arrays: (T[]|List)[]): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.intersection + */ + intersection(...arrays: (TResult[]|List)[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.intersection + */ + intersection(...arrays: (TResult[]|List)[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.intersection + */ + intersection(...arrays: (TResult[]|List)[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.intersection + */ + intersection(...arrays: (TResult[]|List)[]): LoDashExplicitArrayWrapper; + } + + //_.last + interface LoDashStatic { + /** + * Gets the last element of array. + * + * @param array The array to query. + * @return Returns the last element of array. + */ + last(array: List): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.last + */ + last(): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.last + */ + last(): T; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.last + */ + last(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.last + */ + last(): LoDashExplicitObjectWrapper; + } + + //_.lastIndexOf + interface LoDashStatic { + /** + * This method is like _.indexOf except that it iterates over elements of array from right to left. + * + * @param array The array to search. + * @param value The value to search for. + * @param fromIndex The index to search from or true to perform a binary search on a sorted array. + * @return Returns the index of the matched value, else -1. + */ + lastIndexOf( + array: List, + value: T, + fromIndex?: boolean|number + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.lastIndexOf + */ + lastIndexOf( + value: T, + fromIndex?: boolean|number + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.lastIndexOf + */ + lastIndexOf( + value: TResult, + fromIndex?: boolean|number + ): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.lastIndexOf + */ + lastIndexOf( + value: T, + fromIndex?: boolean|number + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.lastIndexOf + */ + lastIndexOf( + value: TResult, + fromIndex?: boolean|number + ): LoDashExplicitWrapper; + } + + //_.pull + interface LoDashStatic { + /** + * Removes all provided values from array using SameValueZero for equality comparisons. + * + * Note: Unlike _.without, this method mutates array. + * + * @param array The array to modify. + * @param values The values to remove. + * @return Returns array. + */ + pull( + array: T[], + ...values: T[] + ): T[]; + + /** + * @see _.pull + */ + pull( + array: List, + ...values: T[] + ): List; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.pull + */ + pull(...values: T[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.pull + */ + pull(...values: TValue[]): LoDashImplicitObjectWrapper>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.pull + */ + pull(...values: T[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.pull + */ + pull(...values: TValue[]): LoDashExplicitObjectWrapper>; + } + + //_.pullAt + interface LoDashStatic { + /** + * Removes elements from array corresponding to the given indexes and returns an array of the removed elements. + * Indexes may be specified as an array of indexes or as individual arguments. + * + * Note: Unlike _.at, this method mutates array. + * + * @param array The array to modify. + * @param indexes The indexes of elements to remove, specified as individual indexes or arrays of indexes. + * @return Returns the new array of removed elements. + */ + pullAt( + array: List, + ...indexes: (number|number[])[] + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.pullAt + */ + pullAt(...indexes: (number|number[])[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.pullAt + */ + pullAt(...indexes: (number|number[])[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.pullAt + */ + pullAt(...indexes: (number|number[])[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.pullAt + */ + pullAt(...indexes: (number|number[])[]): LoDashExplicitArrayWrapper; + } + + //_.remove + interface LoDashStatic { + /** + * Removes all elements from array that predicate returns truthy for and returns an array of the removed + * elements. The predicate is bound to thisArg and invoked with three arguments: (value, index, array). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * Note: Unlike _.filter, this method mutates array. + * + * @param array The array to modify. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the new array of removed elements. + */ + remove( + array: List, + predicate?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.remove + */ + remove( + array: List, + predicate?: string, + thisArg?: any + ): T[]; + + /** + * @see _.remove + */ + remove( + array: List, + predicate?: W + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.remove + */ + remove( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: W + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.remove + */ + remove( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: W + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.remove + */ + remove( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: W + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.remove + */ + remove( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.remove + */ + remove( + predicate?: W + ): LoDashExplicitArrayWrapper; + } + + //_.tail + interface LoDashStatic { + /** + * Gets all but the first element of array. + * + * @alias _.tail + * + * @param array The array to query. + * @return Returns the slice of array. + */ + tail(array: List): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.tail + */ + tail(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.tail + */ + tail(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.tail + */ + tail(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.tail + */ + tail(): LoDashExplicitArrayWrapper; + } + + //_.slice + interface LoDashStatic { + /** + * Creates a slice of array from start up to, but not including, end. + * + * @param array The array to slice. + * @param start The start position. + * @param end The end position. + * @return Returns the slice of array. + */ + slice( + array: T[], + start?: number, + end?: number + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.slice + */ + slice( + start?: number, + end?: number + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.slice + */ + slice( + start?: number, + end?: number + ): LoDashExplicitArrayWrapper; + } + + //_.sortedIndex + interface LoDashStatic { + /** + * Uses a binary search to determine the lowest index at which `value` should + * be inserted into `array` in order to maintain its sort order. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * _.sortedIndex([30, 50], 40); + * // => 1 + * + * _.sortedIndex([4, 5], 4); + * // => 0 + */ + sortedIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + array: List, + value: T + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.sortedIndex + */ + sortedIndex( + value: string + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): number; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.sortedIndex + */ + sortedIndex( + value: string + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndex + */ + sortedIndex( + value: T + ): LoDashExplicitWrapper; + + + } + + //_.sortedIndexBy + interface LoDashStatic { + /** + * This method is like `_.sortedIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 }; + * + * _.sortedIndexBy(['thirty', 'fifty'], 'forty', _.propertyOf(dict)); + * // => 1 + * + * // using the `_.property` iteratee shorthand + * _.sortedIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * // => 0 + */ + sortedIndexBy( + array: List, + value: T, + iteratee: (x: T) => TSort + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + array: List, + value: T, + iteratee: (x: T) => any + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + array: List, + value: T, + iteratee: string + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + array: List, + value: T, + iteratee: W + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + array: List, + value: T, + iteratee: Object + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: string, + iteratee: (x: string) => TSort + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: (x: T) => TSort + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: string + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: W + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: (x: T) => TSort + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: (x: T) => any + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: string + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: W + ): number; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: Object + ): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: string, + iteratee: (x: string) => TSort + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: (x: T) => TSort + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: string + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: W + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: (x: T) => TSort + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: (x: T) => any + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: string + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: W + ): LoDashExplicitWrapper; + + /** + * @see _.sortedIndexBy + */ + sortedIndexBy( + value: T, + iteratee: Object + ): LoDashExplicitWrapper; + } + + //_.sortedLastIndex + interface LoDashStatic { + /** + * This method is like `_.sortedIndex` except that it returns the highest + * index at which `value` should be inserted into `array` in order to + * maintain its sort order. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * _.sortedLastIndex([4, 5], 4); + * // => 1 + */ + sortedLastIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + array: List, + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + array: List, + value: T + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: string + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): number; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: string + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndex + */ + sortedLastIndex( + value: T + ): LoDashExplicitWrapper; + } + + //_.sortedLastIndexBy + interface LoDashStatic { + /** + * This method is like `_.sortedLastIndex` except that it accepts `iteratee` + * which is invoked for `value` and each element of `array` to compute their + * sort ranking. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The sorted array to inspect. + * @param {*} value The value to evaluate. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the index at which `value` should be inserted into `array`. + * @example + * + * // using the `_.property` iteratee shorthand + * _.sortedLastIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x'); + * // => 1 + */ + sortedLastIndexBy( + array: List, + value: T, + iteratee: (x: T) => TSort + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + array: List, + value: T, + iteratee: (x: T) => any + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + array: List, + value: T, + iteratee: string + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + array: List, + value: T, + iteratee: W + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + array: List, + value: T, + iteratee: Object + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: string, + iteratee: (x: string) => TSort + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: (x: T) => TSort + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: string + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: W + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: (x: T) => TSort + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: (x: T) => any + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: string + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: W + ): number; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: Object + ): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: string, + iteratee: (x: string) => TSort + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: (x: T) => TSort + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: string + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: W + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: (x: T) => TSort + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: (x: T) => any + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: string + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: W + ): LoDashExplicitWrapper; + + /** + * @see _.sortedLastIndexBy + */ + sortedLastIndexBy( + value: T, + iteratee: Object + ): LoDashExplicitWrapper; + } + + //_.sortedLastIndexOf DUMMY + interface LoDashStatic { + /** + * This method is like `_.lastIndexOf` except that it performs a binary + * search on a sorted `array`. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to search. + * @param {*} value The value to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.sortedLastIndexOf([1, 1, 2, 2], 2); + * // => 3 + */ + sortedLastIndexOf( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.tail + interface LoDashStatic { + /** + * @see _.rest + */ + tail(array: List): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.rest + */ + tail(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.rest + */ + tail(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.rest + */ + tail(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.rest + */ + tail(): LoDashExplicitArrayWrapper; + } + + //_.take + interface LoDashStatic { + /** + * Creates a slice of array with n elements taken from the beginning. + * + * @param array The array to query. + * @param n The number of elements to take. + * @return Returns the slice of array. + */ + take( + array: List, + n?: number + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.take + */ + take(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.take + */ + take(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.take + */ + take(n?: number): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.take + */ + take(n?: number): LoDashExplicitArrayWrapper; + } + + //_.takeRight + interface LoDashStatic { + /** + * Creates a slice of array with n elements taken from the end. + * + * @param array The array to query. + * @param n The number of elements to take. + * @return Returns the slice of array. + */ + takeRight( + array: List, + n?: number + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.takeRight + */ + takeRight(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.takeRight + */ + takeRight(n?: number): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.takeRight + */ + takeRight(n?: number): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.takeRight + */ + takeRight(n?: number): LoDashExplicitArrayWrapper; + } + + //_.takeRightWhile + interface LoDashStatic { + /** + * Creates a slice of array with elements taken from the end. Elements are taken until predicate returns + * falsey. The predicate is bound to thisArg and invoked with three arguments: (value, index, array). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param array The array to query. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the slice of array. + */ + takeRightWhile( + array: List, + predicate?: ListIterator, + thisArg?: any + ): TValue[]; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + array: List, + predicate?: string, + thisArg?: any + ): TValue[]; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + array: List, + predicate?: TWhere + ): TValue[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeRightWhile + */ + takeRightWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + //_.takeWhile + interface LoDashStatic { + /** + * Creates a slice of array with elements taken from the beginning. Elements are taken until predicate returns + * falsey. The predicate is bound to thisArg and invoked with three arguments: (value, index, array). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param array The array to query. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the slice of array. + */ + takeWhile( + array: List, + predicate?: ListIterator, + thisArg?: any + ): TValue[]; + + /** + * @see _.takeWhile + */ + takeWhile( + array: List, + predicate?: string, + thisArg?: any + ): TValue[]; + + /** + * @see _.takeWhile + */ + takeWhile( + array: List, + predicate?: TWhere + ): TValue[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.takeWhile + */ + takeWhile( + predicate?: TWhere + ): LoDashExplicitArrayWrapper; + } + + //_.union + interface LoDashStatic { + /** + * Creates an array of unique values, in order, from all of the provided arrays using SameValueZero for + * equality comparisons. + * + * @param arrays The arrays to inspect. + * @return Returns the new array of combined values. + */ + union(...arrays: List[]): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.union + */ + union(...arrays: List[]): LoDashImplicitArrayWrapper; + + /** + * @see _.union + */ + union(...arrays: List[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.union + */ + union(...arrays: List[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.union + */ + union(...arrays: List[]): LoDashExplicitArrayWrapper; + + /** + * @see _.union + */ + union(...arrays: List[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.union + */ + union(...arrays: List[]): LoDashExplicitArrayWrapper; + } + + //_.unionBy + interface LoDashStatic { + /** + * This method is like `_.union` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by which + * uniqueness is computed. The iteratee is invoked with one argument: (value). + * + * @param arrays The arrays to inspect. + * @param iteratee The iteratee invoked per element. + * @return Returns the new array of combined values. + */ + unionBy( + arrays: T[]|List, + iteratee?: (value: T) => any + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + iteratee?: (value: T) => any + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: (value: T) => any + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: (value: T) => any + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: (value: T) => any + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays1: T[]|List, + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: W + ): T[]; + + /** + * @see _.unionBy + */ + unionBy( + arrays: T[]|List, + ...iteratee: any[] + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.unionBy + */ + unionBy( + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + ...iteratee: any[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.unionBy + */ + unionBy( + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: (value: T) => any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: W + ): LoDashImplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + ...iteratee: any[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.unionBy + */ + unionBy( + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + ...iteratee: any[] + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.unionBy + */ + unionBy( + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: (value: T) => any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + arrays2: T[]|List, + arrays3: T[]|List, + arrays4: T[]|List, + arrays5: T[]|List, + iteratee?: W + ): LoDashExplicitArrayWrapper; + + /** + * @see _.unionBy + */ + unionBy( + ...iteratee: any[] + ): LoDashExplicitArrayWrapper; + } + + //_.uniq + interface LoDashStatic { + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + uniq( + array: List + ): T[]; + + /** + * @see _.uniq + */ + uniq( + array: List + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.uniq + */ + uniq(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.uniq + */ + uniq(): LoDashImplicitArrayWrapper; + + /** + * @see _.uniq + */ + uniq(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + uniq(): LoDashImplicitArrayWrapper; + + /** + * @see _.uniq + */ + uniq(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.uniq + */ + uniq(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.uniq + */ + uniq(): LoDashExplicitArrayWrapper; + + /** + * @see _.uniq + */ + uniq(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.uniq + */ + uniq(): LoDashExplicitArrayWrapper; + + /** + * @see _.uniq + */ + uniq(): LoDashExplicitArrayWrapper; + } + + //_.uniqBy + interface LoDashStatic { + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // using the `_.property` iteratee shorthand + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + uniqBy( + array: List, + iteratee: ListIterator + ): T[]; + + /** + * @see _.uniqBy + */ + uniqBy( + array: List, + iteratee: ListIterator + ): T[]; + + /** + * @see _.uniqBy + */ + uniqBy( + array: List, + iteratee: string + ): T[]; + + /** + * @see _.uniqBy + */ + uniqBy( + array: List, + iteratee: Object + ): T[]; + + /** + * @see _.uniqBy + */ + uniqBy( + array: List, + iteratee: TWhere + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: Object + ): LoDashImplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: TWhere + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: Object + ): LoDashExplicitArrayWrapper; + + /** + * @see _.uniqBy + */ + uniqBy( + iteratee: TWhere + ): LoDashExplicitArrayWrapper; + } + + //_.sortedUniq + interface LoDashStatic { + /** + * This method is like `_.uniq` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniq([1, 1, 2]); + * // => [1, 2] + */ + sortedUniq( + array: List + ): T[]; + + /** + * @see _.sortedUniq + */ + sortedUniq( + array: List + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + sortedUniq(): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniq + */ + sortedUniq(): LoDashExplicitArrayWrapper; + } + + //_.sortedUniqBy + interface LoDashStatic { + /** + * This method is like `_.uniqBy` except that it's designed and optimized + * for sorted arrays. + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor); + * // => [1.1, 2.2] + */ + sortedUniqBy( + array: List, + iteratee: ListIterator + ): T[]; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + array: List, + iteratee: ListIterator + ): T[]; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + array: List, + iteratee: string + ): T[]; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + array: List, + iteratee: Object + ): T[]; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + array: List, + iteratee: TWhere + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: Object + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: TWhere + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: TWhere + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: Object + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortedUniqBy + */ + sortedUniqBy( + iteratee: TWhere + ): LoDashExplicitArrayWrapper; + } + + //_.unionWith DUMMY + interface LoDashStatic { + /** + * This method is like `_.union` except that it accepts `comparator` which + * is invoked to compare elements of `arrays`. The comparator is invoked + * with two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of combined values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.unionWith(objects, others, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + unionWith( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.uniqWith DUMMY + interface LoDashStatic { + /** + * This method is like `_.uniq` except that it accepts `comparator` which + * is invoked to compare elements of `array`. The comparator is invoked with + * two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.uniqWith(objects, _.isEqual); + * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }] + */ + uniqWith( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.unzip + interface LoDashStatic { + /** + * This method is like _.zip except that it accepts an array of grouped elements and creates an array + * regrouping the elements to their pre-zip configuration. + * + * @param array The array of grouped elements to process. + * @return Returns the new array of regrouped elements. + */ + unzip(array: List>): T[][]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.unzip + */ + unzip(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.unzip + */ + unzip(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.unzip + */ + unzip(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.unzip + */ + unzip(): LoDashExplicitArrayWrapper; + } + + //_.unzipWith + interface LoDashStatic { + /** + * This method is like _.unzip except that it accepts an iteratee to specify how regrouped values should be + * combined. The iteratee is bound to thisArg and invoked with four arguments: (accumulator, value, index, + * group). + * + * @param array The array of grouped elements to process. + * @param iteratee The function to combine regrouped values. + * @param thisArg The this binding of iteratee. + * @return Returns the new array of regrouped elements. + */ + unzipWith( + array: List>, + iteratee?: MemoIterator, + thisArg?: any + ): TResult[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.unzipWith + */ + unzipWith( + iteratee?: MemoIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.unzipWith + */ + unzipWith( + iteratee?: MemoIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + //_.without + interface LoDashStatic { + /** + * Creates an array excluding all provided values using SameValueZero for equality comparisons. + * + * @param array The array to filter. + * @param values The values to exclude. + * @return Returns the new array of filtered values. + */ + without( + array: List, + ...values: T[] + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.without + */ + without(...values: T[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.without + */ + without(...values: T[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.without + */ + without(...values: T[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.without + */ + without(...values: T[]): LoDashExplicitArrayWrapper; + } + + //_.xor + interface LoDashStatic { + /** + * Creates an array of unique values that is the symmetric difference of the provided arrays. + * + * @param arrays The arrays to inspect. + * @return Returns the new array of values. + */ + xor(...arrays: List[]): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.xor + */ + xor(...arrays: List[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.xor + */ + xor(...arrays: List[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.xor + */ + xor(...arrays: List[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.xor + */ + xor(...arrays: List[]): LoDashExplicitArrayWrapper; + } + + //_.xorBy DUMMY + interface LoDashStatic { + /** + * This method is like `_.xor` except that it accepts `iteratee` which is + * invoked for each element of each `arrays` to generate the criterion by which + * uniqueness is computed. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new array of values. + * @example + * + * _.xorBy([2.1, 1.2], [4.3, 2.4], Math.floor); + * // => [1.2, 4.3] + * + * // using the `_.property` iteratee shorthand + * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 2 }] + */ + xorBy( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.xorWith DUMMY + interface LoDashStatic { + /** + * This method is like `_.xor` except that it accepts `comparator` which is + * invoked to compare elements of `arrays`. The comparator is invoked with + * two arguments: (arrVal, othVal). + * + * @static + * @memberOf _ + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of values. + * @example + * + * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]; + * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }]; + * + * _.xorWith(objects, others, _.isEqual); + * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }] + */ + xorWith( + array: any[]|List, + ...values: any[] + ): any[]; + } + + //_.zip + interface LoDashStatic { + /** + * Creates an array of grouped elements, the first of which contains the first elements of the given arrays, + * the second of which contains the second elements of the given arrays, and so on. + * + * @param arrays The arrays to process. + * @return Returns the new array of grouped elements. + */ + zip(...arrays: List[]): T[][]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.zip + */ + zip(...arrays: List[]): _.LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.zip + */ + zip(...arrays: List[]): _.LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.zip + */ + zip(...arrays: List[]): _.LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.zip + */ + zip(...arrays: List[]): _.LoDashExplicitArrayWrapper; + } + + //_.zipObject + interface LoDashStatic { + /** + * The inverse of _.pairs; this method returns an object composed from arrays of property names and values. + * Provide either a single two dimensional array, e.g. [[key1, value1], [key2, value2]] or two arrays, one of + * property names and one of corresponding values. + * + * @param props The property names. + * @param values The property values. + * @return Returns the new object. + */ + zipObject( + props: List|List>, + values?: List + ): TResult; + + /** + * @see _.zipObject + */ + zipObject( + props: List|List>, + values?: List + ): TResult; + + /** + * @see _.zipObject + */ + zipObject( + props: List|List>, + values?: List + ): _.Dictionary; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashImplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashImplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashImplicitObjectWrapper<_.Dictionary>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashImplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashImplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashImplicitObjectWrapper<_.Dictionary>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashExplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashExplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashExplicitObjectWrapper<_.Dictionary>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashExplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashExplicitObjectWrapper; + + /** + * @see _.zipObject + */ + zipObject( + values?: List + ): _.LoDashExplicitObjectWrapper<_.Dictionary>; + } + + //_.zipWith + interface LoDashStatic { + /** + * This method is like _.zip except that it accepts an iteratee to specify how grouped values should be + * combined. The iteratee is bound to thisArg and invoked with four arguments: (accumulator, value, index, + * group). + * @param {...Array} [arrays] The arrays to process. + * @param {Function} [iteratee] The function to combine grouped values. + * @param {*} [thisArg] The `this` binding of `iteratee`. + * @return Returns the new array of grouped elements. + */ + zipWith(...args: any[]): TResult[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.zipWith + */ + zipWith(...args: any[]): LoDashImplicitArrayWrapper; + } + + /********* + * Chain * + *********/ + + //_.chain + interface LoDashStatic { + /** + * Creates a lodash object that wraps value with explicit method chaining enabled. + * + * @param value The value to wrap. + * @return Returns the new lodash wrapper instance. + */ + chain(value: number): LoDashExplicitWrapper; + chain(value: string): LoDashExplicitWrapper; + chain(value: boolean): LoDashExplicitWrapper; + chain(value: T[]): LoDashExplicitArrayWrapper; + chain(value: T): LoDashExplicitObjectWrapper; + chain(value: any): LoDashExplicitWrapper; + } + + interface LoDashImplicitWrapper { + /** + * @see _.chain + */ + chain(): LoDashExplicitWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.chain + */ + chain(): LoDashExplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.chain + */ + chain(): LoDashExplicitObjectWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.chain + */ + chain(): TWrapper; + } + + //_.tap + interface LoDashStatic { + /** + * This method invokes interceptor and returns value. The interceptor is bound to thisArg and invoked with one + * argument; (value). The purpose of this method is to "tap into" a method chain in order to perform operations + * on intermediate results within the chain. + * + * @param value The value to provide to interceptor. + * @param interceptor The function to invoke. + * @parem thisArg The this binding of interceptor. + * @return Returns value. + **/ + tap( + value: T, + interceptor: (value: T) => void, + thisArg?: any + ): T; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.tap + */ + tap( + interceptor: (value: T) => void, + thisArg?: any + ): TWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.tap + */ + tap( + interceptor: (value: T) => void, + thisArg?: any + ): TWrapper; + } + + //_.thru + interface LoDashStatic { + /** + * This method is like _.tap except that it returns the result of interceptor. + * + * @param value The value to provide to interceptor. + * @param interceptor The function to invoke. + * @param thisArg The this binding of interceptor. + * @return Returns the result of interceptor. + */ + thru( + value: T, + interceptor: (value: T) => TResult, + thisArg?: any + ): TResult; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any): LoDashImplicitWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any): LoDashImplicitWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any): LoDashImplicitWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any): LoDashImplicitObjectWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult[], + thisArg?: any): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult, + thisArg?: any + ): LoDashExplicitObjectWrapper; + + /** + * @see _.thru + */ + thru( + interceptor: (value: T) => TResult[], + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + //_.prototype.commit + interface LoDashImplicitWrapperBase { + /** + * Executes the chained sequence and returns the wrapped result. + * + * @return Returns the new lodash wrapper instance. + */ + commit(): TWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.commit + */ + commit(): TWrapper; + } + + //_.prototype.concat + interface LoDashImplicitWrapperBase { + /** + * Creates a new array joining a wrapped array with any additional arrays and/or values. + * + * @param items + * @return Returns the new concatenated array. + */ + concat(...items: Array>): LoDashImplicitArrayWrapper; + + /** + * @see _.concat + */ + concat(...items: Array>): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.concat + */ + concat(...items: Array>): LoDashExplicitArrayWrapper; + + /** + * @see _.concat + */ + concat(...items: Array>): LoDashExplicitArrayWrapper; + } + + //_.prototype.plant + interface LoDashImplicitWrapperBase { + /** + * Creates a clone of the chained sequence planting value as the wrapped value. + * @param value The value to plant as the wrapped value. + * @return Returns the new lodash wrapper instance. + */ + plant(value: number): LoDashImplicitWrapper; + + /** + * @see _.plant + */ + plant(value: string): LoDashImplicitStringWrapper; + + /** + * @see _.plant + */ + plant(value: boolean): LoDashImplicitWrapper; + + /** + * @see _.plant + */ + plant(value: number[]): LoDashImplicitNumberArrayWrapper; + + /** + * @see _.plant + */ + plant(value: T[]): LoDashImplicitArrayWrapper; + + /** + * @see _.plant + */ + plant(value: T): LoDashImplicitObjectWrapper; + + /** + * @see _.plant + */ + plant(value: any): LoDashImplicitWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.plant + */ + plant(value: number): LoDashExplicitWrapper; + + /** + * @see _.plant + */ + plant(value: string): LoDashExplicitStringWrapper; + + /** + * @see _.plant + */ + plant(value: boolean): LoDashExplicitWrapper; + + /** + * @see _.plant + */ + plant(value: number[]): LoDashExplicitNumberArrayWrapper; + + /** + * @see _.plant + */ + plant(value: T[]): LoDashExplicitArrayWrapper; + + /** + * @see _.plant + */ + plant(value: T): LoDashExplicitObjectWrapper; + + /** + * @see _.plant + */ + plant(value: any): LoDashExplicitWrapper; + } + + //_.prototype.reverse + interface LoDashImplicitArrayWrapper { + /** + * Reverses the wrapped array so the first element becomes the last, the second element becomes the second to + * last, and so on. + * + * Note: This method mutates the wrapped array. + * + * @return Returns the new reversed lodash wrapper instance. + */ + reverse(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.reverse + */ + reverse(): LoDashExplicitArrayWrapper; + } + + //_.prototype.toJSON + interface LoDashWrapperBase { + /** + * @see _.value + */ + toJSON(): T; + } + + //_.prototype.toString + interface LoDashWrapperBase { + /** + * Produces the result of coercing the unwrapped value to a string. + * + * @return Returns the coerced string value. + */ + toString(): string; + } + + //_.prototype.value + interface LoDashWrapperBase { + /** + * Executes the chained sequence to extract the unwrapped value. + * + * @alias _.toJSON, _.valueOf + * + * @return Returns the resolved unwrapped value. + */ + value(): T; + } + + //_.valueOf + interface LoDashWrapperBase { + /** + * @see _.value + */ + valueOf(): T; + } + + /************** + * Collection * + **************/ + + //_.at + interface LoDashStatic { + /** + * Creates an array of elements corresponding to the given keys, or indexes, of collection. Keys may be + * specified as individual arguments or as arrays of keys. + * + * @param collection The collection to iterate over. + * @param props The property names or indexes of elements to pick, specified individually or in arrays. + * @return Returns the new array of picked elements. + */ + at( + collection: List|Dictionary, + ...props: (number|string|(number|string)[])[] + ): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.at + */ + at(...props: (number|string|(number|string)[])[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.at + */ + at(...props: (number|string|(number|string)[])[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.at + */ + at(...props: (number|string|(number|string)[])[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.at + */ + at(...props: (number|string|(number|string)[])[]): LoDashExplicitArrayWrapper; + } + + //_.countBy + interface LoDashStatic { + /** + * Creates an object composed of keys generated from the results of running each element of collection through + * iteratee. The corresponding value of each key is the number of times the key was returned by iteratee. The + * iteratee is bound to thisArg and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for iteratee the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for iteratee the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param collection The collection to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns the composed aggregate object. + */ + countBy( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.countBy + */ + countBy( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.countBy + */ + countBy( + collection: NumericDictionary, + iteratee?: NumericDictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.countBy + */ + countBy( + collection: List|Dictionary|NumericDictionary, + iteratee?: string, + thisArg?: any + ): Dictionary; + + /** + * @see _.countBy + */ + countBy( + collection: List|Dictionary|NumericDictionary, + iteratee?: W + ): Dictionary; + + /** + * @see _.countBy + */ + countBy( + collection: List|Dictionary|NumericDictionary, + iteratee?: Object + ): Dictionary; + } + + interface LoDashImplicitWrapper { + /** + * @see _.countBy + */ + countBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.countBy + */ + countBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: W + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.countBy + */ + countBy( + iteratee?: ListIterator|DictionaryIterator|NumericDictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: W + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashExplicitWrapper { + /** + * @see _.countBy + */ + countBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.countBy + */ + countBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: W + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.countBy + */ + countBy( + iteratee?: ListIterator|DictionaryIterator|NumericDictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.countBy + */ + countBy( + iteratee?: W + ): LoDashExplicitObjectWrapper>; + } + + //_.each + interface LoDashStatic { + /** + * @see _.forEach + */ + each( + collection: T[], + iteratee?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.forEach + */ + each( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): List; + + /** + * @see _.forEach + */ + each( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forEach + */ + each( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + + /** + * @see _.forEach + */ + each( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.forEach + */ + each( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.forEach + */ + each( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forEach + */ + each( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.forEach + */ + each( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.forEach + */ + each( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forEach + */ + each( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper; + } + + //_.eachRight + interface LoDashStatic { + /** + * @see _.forEachRight + */ + eachRight( + collection: T[], + iteratee?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.forEachRight + */ + eachRight( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): List; + + /** + * @see _.forEachRight + */ + eachRight( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forEachRight + */ + eachRight( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + + /** + * @see _.forEachRight + */ + eachRight( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.forEachRight + */ + eachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.forEachRight + */ + eachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forEachRight + */ + eachRight( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.forEachRight + */ + eachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.forEachRight + */ + eachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forEachRight + */ + eachRight( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper; + } + + //_.every + interface LoDashStatic { + /** + * Checks if predicate returns truthy for all elements of collection. Iteration is stopped once predicate + * returns falsey. The predicate is invoked with three arguments: (value, index|key, collection). + * + * @param collection The collection to iterate over. + * @param predicate The function invoked per iteration. + * @return Returns true if all elements pass the predicate check, else false. + */ + every( + collection: List, + predicate?: ListIterator + ): boolean; + + /** + * @see _.every + */ + every( + collection: Dictionary, + predicate?: DictionaryIterator + ): boolean; + + /** + * @see _.every + */ + every( + collection: NumericDictionary, + predicate?: NumericDictionaryIterator + ): boolean; + + /** + * @see _.every + */ + every( + collection: List|Dictionary|NumericDictionary, + predicate?: string|any[] + ): boolean; + + /** + * @see _.every + */ + every( + collection: List|Dictionary|NumericDictionary, + predicate?: TObject + ): boolean; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.every + */ + every( + predicate?: ListIterator|NumericDictionaryIterator + ): boolean; + + /** + * @see _.every + */ + every( + predicate?: string|any[] + ): boolean; + + /** + * @see _.every + */ + every( + predicate?: TObject + ): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.every + */ + every( + predicate?: ListIterator|DictionaryIterator|NumericDictionaryIterator + ): boolean; + + /** + * @see _.every + */ + every( + predicate?: string|any[] + ): boolean; + + /** + * @see _.every + */ + every( + predicate?: TObject + ): boolean; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.every + */ + every( + predicate?: ListIterator|NumericDictionaryIterator + ): LoDashExplicitWrapper; + + /** + * @see _.every + */ + every( + predicate?: string|any[] + ): LoDashExplicitWrapper; + + /** + * @see _.every + */ + every( + predicate?: TObject + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.every + */ + every( + predicate?: ListIterator|DictionaryIterator|NumericDictionaryIterator + ): LoDashExplicitWrapper; + + /** + * @see _.every + */ + every( + predicate?: string|any[] + ): LoDashExplicitWrapper; + + /** + * @see _.every + */ + every( + predicate?: TObject + ): LoDashExplicitWrapper; + } + + //_.filter + interface LoDashStatic { + /** + * Iterates over elements of collection, returning an array of all elements predicate returns truthy for. The + * predicate is bound to thisArg and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param collection The collection to iterate over. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the new filtered array. + */ + filter( + collection: List, + predicate?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.filter + */ + filter( + collection: Dictionary, + predicate?: DictionaryIterator, + thisArg?: any + ): T[]; + + /** + * @see _.filter + */ + filter( + collection: string, + predicate?: StringIterator, + thisArg?: any + ): string[]; + + /** + * @see _.filter + */ + filter( + collection: List|Dictionary, + predicate: string, + thisArg?: any + ): T[]; + + /** + * @see _.filter + */ + filter( + collection: List|Dictionary, + predicate: W + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.filter + */ + filter( + predicate?: StringIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.filter + */ + filter( + predicate: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.filter + */ + filter( + predicate: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.filter + */ + filter(predicate: W): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.filter + */ + filter( + predicate: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.filter + */ + filter( + predicate: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.filter + */ + filter(predicate: W): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.filter + */ + filter( + predicate?: StringIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.filter + */ + filter( + predicate: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.filter + */ + filter( + predicate: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.filter + */ + filter(predicate: W): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.filter + */ + filter( + predicate: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.filter + */ + filter( + predicate: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.filter + */ + filter(predicate: W): LoDashExplicitArrayWrapper; + } + + //_.find + interface LoDashStatic { + /** + * Iterates over elements of collection, returning the first element predicate returns truthy for. + * The predicate is bound to thisArg and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param collection The collection to search. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the matched element, else undefined. + */ + find( + collection: List, + predicate?: ListIterator, + thisArg?: any + ): T; + + /** + * @see _.find + */ + find( + collection: Dictionary, + predicate?: DictionaryIterator, + thisArg?: any + ): T; + + /** + * @see _.find + */ + find( + collection: List|Dictionary, + predicate?: string, + thisArg?: any + ): T; + + /** + * @see _.find + */ + find( + collection: List|Dictionary, + predicate?: TObject + ): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.find + */ + find( + predicate?: ListIterator, + thisArg?: any + ): T; + + /** + * @see _.find + */ + find( + predicate?: string, + thisArg?: any + ): T; + + /** + * @see _.find + */ + find( + predicate?: TObject + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.find + */ + find( + predicate?: ListIterator|DictionaryIterator, + thisArg?: any + ): TResult; + + /** + * @see _.find + */ + find( + predicate?: string, + thisArg?: any + ): TResult; + + /** + * @see _.find + */ + find( + predicate?: TObject + ): TResult; + } + + //_.findLast + interface LoDashStatic { + /** + * This method is like _.find except that it iterates over elements of a collection from + * right to left. + * @param collection Searches for a value in this list. + * @param callback The function called per iteration. + * @param thisArg The this binding of callback. + * @return The found element, else undefined. + **/ + findLast( + collection: Array, + callback: ListIterator, + thisArg?: any): T; + + /** + * @see _.find + **/ + findLast( + collection: List, + callback: ListIterator, + thisArg?: any): T; + + /** + * @see _.find + **/ + findLast( + collection: Dictionary, + callback: DictionaryIterator, + thisArg?: any): T; + + /** + * @see _.find + * @param _.pluck style callback + **/ + findLast( + collection: Array, + whereValue: W): T; + + /** + * @see _.find + * @param _.pluck style callback + **/ + findLast( + collection: List, + whereValue: W): T; + + /** + * @see _.find + * @param _.pluck style callback + **/ + findLast( + collection: Dictionary, + whereValue: W): T; + + /** + * @see _.find + * @param _.where style callback + **/ + findLast( + collection: Array, + pluckValue: string): T; + + /** + * @see _.find + * @param _.where style callback + **/ + findLast( + collection: List, + pluckValue: string): T; + + /** + * @see _.find + * @param _.where style callback + **/ + findLast( + collection: Dictionary, + pluckValue: string): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.findLast + */ + findLast( + callback: ListIterator, + thisArg?: any): T; + /** + * @see _.findLast + * @param _.where style callback + */ + findLast( + whereValue: W): T; + + /** + * @see _.findLast + * @param _.where style callback + */ + findLast( + pluckValue: string): T; + } + + //_.forEach + interface LoDashStatic { + /** + * Iterates over elements of collection invoking iteratee for each element. The iteratee is bound to thisArg + * and invoked with three arguments: + * (value, index|key, collection). Iteratee functions may exit iteration early by explicitly returning false. + * + * Note: As with other "Collections" methods, objects with a "length" property are iterated like arrays. To + * avoid this behavior _.forIn or _.forOwn may be used for object iteration. + * + * @alias _.each + * + * @param collection The collection to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + */ + forEach( + collection: T[], + iteratee?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.forEach + */ + forEach( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): List; + + /** + * @see _.forEach + */ + forEach( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forEach + */ + forEach( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + + /** + * @see _.forEach + */ + forEach( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.forEach + */ + forEach( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.forEach + */ + forEach( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forEach + */ + forEach( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.forEach + */ + forEach( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.forEach + */ + forEach( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forEach + */ + forEach( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper; + } + + //_.forEachRight + interface LoDashStatic { + /** + * This method is like _.forEach except that it iterates over elements of collection from right to left. + * + * @alias _.eachRight + * + * @param collection The collection to iterate over. + * @param iteratee The function called per iteration. + * @param thisArg The this binding of callback. + */ + forEachRight( + collection: T[], + iteratee?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.forEachRight + */ + forEachRight( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): List; + + /** + * @see _.forEachRight + */ + forEachRight( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forEachRight + */ + forEachRight( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + + /** + * @see _.forEachRight + */ + forEachRight( + collection: T, + iteratee?: ObjectIterator, + thisArgs?: any + ): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.forEachRight + */ + forEachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.forEachRight + */ + forEachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forEachRight + */ + forEachRight( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.forEachRight + */ + forEachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.forEachRight + */ + forEachRight( + iteratee: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forEachRight + */ + forEachRight( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper; + } + + //_.groupBy + interface LoDashStatic { + /** + * Creates an object composed of keys generated from the results of running each element of collection through + * iteratee. The corresponding value of each key is an array of the elements responsible for generating the + * key. The iteratee is bound to thisArg and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for iteratee the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for iteratee the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param collection The collection to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns the composed aggregate object. + */ + groupBy( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: List|Dictionary, + iteratee?: string, + thisArg?: TValue + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: List|Dictionary, + iteratee?: string, + thisArg?: any + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: List|Dictionary, + iteratee?: TWhere + ): Dictionary; + + /** + * @see _.groupBy + */ + groupBy( + collection: List|Dictionary, + iteratee?: Object + ): Dictionary; + } + + interface LoDashImplicitWrapper { + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: string, + thisArg?: TValue + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: TWhere + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: string, + thisArg?: TValue + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: TWhere + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: Object + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashExplicitWrapper { + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: string, + thisArg?: TValue + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: TWhere + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: string, + thisArg?: TValue + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: TWhere + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.groupBy + */ + groupBy( + iteratee?: Object + ): LoDashExplicitObjectWrapper>; + } + + //_.includes + interface LoDashStatic { + /** + * Checks if target is in collection using SameValueZero for equality comparisons. If fromIndex is negative, + * it’s used as the offset from the end of collection. + * + * @param collection The collection to search. + * @param target The value to search for. + * @param fromIndex The index to search from. + * @return True if the target element is found, else false. + */ + includes( + collection: List|Dictionary, + target: T, + fromIndex?: number + ): boolean; + + /** + * @see _.includes + */ + includes( + collection: string, + target: string, + fromIndex?: number + ): boolean; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.includes + */ + includes( + target: T, + fromIndex?: number + ): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.includes + */ + includes( + target: TValue, + fromIndex?: number + ): boolean; + } + + interface LoDashImplicitWrapper { + /** + * @see _.includes + */ + includes( + target: string, + fromIndex?: number + ): boolean; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.includes + */ + includes( + target: T, + fromIndex?: number + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.includes + */ + includes( + target: TValue, + fromIndex?: number + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.includes + */ + includes( + target: string, + fromIndex?: number + ): LoDashExplicitWrapper; + } + + //_.keyBy + interface LoDashStatic { + /** + * Creates an object composed of keys generated from the results of running each element of collection through + * iteratee. The corresponding value of each key is the last element responsible for generating the key. The + * iteratee function is bound to thisArg and invoked with three arguments: + * (value, index|key, collection). + * + * If a property name is provided for iteratee the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for iteratee the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param collection The collection to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns the composed aggregate object. + */ + keyBy( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.keyBy + */ + keyBy( + collection: NumericDictionary, + iteratee?: NumericDictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.keyBy + */ + keyBy( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.keyBy + */ + keyBy( + collection: List|NumericDictionary|Dictionary, + iteratee?: string, + thisArg?: any + ): Dictionary; + + /** + * @see _.keyBy + */ + keyBy( + collection: List|NumericDictionary|Dictionary, + iteratee?: W + ): Dictionary; + + /** + * @see _.keyBy + */ + keyBy( + collection: List|NumericDictionary|Dictionary, + iteratee?: Object + ): Dictionary; + } + + interface LoDashImplicitWrapper { + /** + * @see _.keyBy + */ + keyBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.keyBy + */ + keyBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: W + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.keyBy + */ + keyBy( + iteratee?: ListIterator|NumericDictionaryIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: W + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: Object + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashExplicitWrapper { + /** + * @see _.keyBy + */ + keyBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.keyBy + */ + keyBy( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: W + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.keyBy + */ + keyBy( + iteratee?: ListIterator|NumericDictionaryIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: W + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.keyBy + */ + keyBy( + iteratee?: Object + ): LoDashExplicitObjectWrapper>; + } + + //_.invokeMap + interface LoDashStatic { + /** + * Invokes the method named by methodName on each element in the collection returning + * an array of the results of each invoked method. Additional arguments will be provided + * to each invoked method. If methodName is a function it will be invoked for, and this + * bound to, each element in the collection. + * @param collection The collection to iterate over. + * @param methodName The name of the method to invoke. + * @param args Arguments to invoke the method with. + **/ + invokeMap( + collection: TValue[], + methodName: string, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: Dictionary, + methodName: string, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: {}[], + methodName: string, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: Dictionary<{}>, + methodName: string, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: TValue[], + method: (...args: any[]) => TResult, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: Dictionary, + method: (...args: any[]) => TResult, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: {}[], + method: (...args: any[]) => TResult, + ...args: any[]): TResult[]; + + /** + * @see _.invokeMap + **/ + invokeMap( + collection: Dictionary<{}>, + method: (...args: any[]) => TResult, + ...args: any[]): TResult[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.invokeMap + **/ + invokeMap( + methodName: string, + ...args: any[]): LoDashImplicitArrayWrapper; + + /** + * @see _.invokeMap + **/ + invokeMap( + method: (...args: any[]) => TResult, + ...args: any[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.invokeMap + **/ + invokeMap( + methodName: string, + ...args: any[]): LoDashImplicitArrayWrapper; + + /** + * @see _.invokeMap + **/ + invokeMap( + method: (...args: any[]) => TResult, + ...args: any[]): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.invokeMap + **/ + invokeMap( + methodName: string, + ...args: any[]): LoDashExplicitArrayWrapper; + + /** + * @see _.invokeMap + **/ + invokeMap( + method: (...args: any[]) => TResult, + ...args: any[]): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.invokeMap + **/ + invokeMap( + methodName: string, + ...args: any[]): LoDashExplicitArrayWrapper; + + /** + * @see _.invokeMap + **/ + invokeMap( + method: (...args: any[]) => TResult, + ...args: any[]): LoDashExplicitArrayWrapper; + } + + //_.map + interface LoDashStatic { + /** + * Creates an array of values by running each element in collection through iteratee. The iteratee is bound to + * thisArg and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for iteratee the created _.property style callback returns the property value + * of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for iteratee the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * Many lodash methods are guarded to work as iteratees for methods like _.every, _.filter, _.map, _.mapValues, + * _.reject, and _.some. + * + * The guarded methods are: + * ary, callback, chunk, clone, create, curry, curryRight, drop, dropRight, every, fill, flatten, invert, max, + * min, parseInt, slice, sortBy, take, takeRight, template, trim, trimLeft, trimRight, trunc, random, range, + * sample, some, sum, uniq, and words + * + * @param collection The collection to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns the new mapped array. + */ + map( + collection: List, + iteratee?: ListIterator, + thisArg?: any + ): TResult[]; + + /** + * @see _.map + */ + map( + collection: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): TResult[]; + + /** + * @see _.map + */ + map( + collection: List|Dictionary, + iteratee?: string + ): TResult[]; + + /** + * @see _.map + */ + map( + collection: List|Dictionary, + iteratee?: TObject + ): boolean[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.map + */ + map( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: TObject + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.map + */ + map( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: string + ): LoDashImplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: TObject + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.map + */ + map( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: TObject + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.map + */ + map( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: string + ): LoDashExplicitArrayWrapper; + + /** + * @see _.map + */ + map( + iteratee?: TObject + ): LoDashExplicitArrayWrapper; + } + + //_.partition + interface LoDashStatic { + /** + * Creates an array of elements split into two groups, the first of which contains elements predicate returns truthy for, + * while the second of which contains elements predicate returns falsey for. + * The predicate is bound to thisArg and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for predicate the created _.property style callback + * returns the property value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback + * returns true for elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns + * true for elements that have the properties of the given object, else false. + * + * @param collection The collection to iterate over. + * @param callback The function called per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the array of grouped elements. + **/ + partition( + collection: List, + callback: ListIterator, + thisArg?: any): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: Dictionary, + callback: DictionaryIterator, + thisArg?: any): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: List, + whereValue: W): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: Dictionary, + whereValue: W): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: List, + path: string, + srcValue: any): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: Dictionary, + path: string, + srcValue: any): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: List, + pluckValue: string): T[][]; + + /** + * @see _.partition + **/ + partition( + collection: Dictionary, + pluckValue: string): T[][]; + } + + interface LoDashImplicitStringWrapper { + /** + * @see _.partition + */ + partition( + callback: ListIterator, + thisArg?: any): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.partition + */ + partition( + callback: ListIterator, + thisArg?: any): LoDashImplicitArrayWrapper; + /** + * @see _.partition + */ + partition( + whereValue: W): LoDashImplicitArrayWrapper; + /** + * @see _.partition + */ + partition( + path: string, + srcValue: any): LoDashImplicitArrayWrapper; + /** + * @see _.partition + */ + partition( + pluckValue: string): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.partition + */ + partition( + callback: ListIterator, + thisArg?: any): LoDashImplicitArrayWrapper; + + /** + * @see _.partition + */ + partition( + callback: DictionaryIterator, + thisArg?: any): LoDashImplicitArrayWrapper; + + /** + * @see _.partition + */ + partition( + whereValue: W): LoDashImplicitArrayWrapper; + + /** + * @see _.partition + */ + partition( + path: string, + srcValue: any): LoDashImplicitArrayWrapper; + + /** + * @see _.partition + */ + partition( + pluckValue: string): LoDashImplicitArrayWrapper; + } + + //_.reduce + interface LoDashStatic { + /** + * Reduces a collection to a value which is the accumulated result of running each + * element in the collection through the callback, where each successive callback execution + * consumes the return value of the previous execution. If accumulator is not provided the + * first element of the collection will be used as the initial accumulator value. The callback + * is bound to thisArg and invoked with four arguments; (accumulator, value, index|key, collection). + * @param collection The collection to iterate over. + * @param callback The function called per iteration. + * @param accumulator Initial value of the accumulator. + * @param thisArg The this binding of callback. + * @return Returns the accumulated value. + **/ + reduce( + collection: Array, + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + collection: List, + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + collection: Dictionary, + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + collection: Array, + callback: MemoIterator, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + collection: List, + callback: MemoIterator, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + collection: Dictionary, + callback: MemoIterator, + thisArg?: any): TResult; + + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.reduce + **/ + reduce( + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + callback: MemoIterator, + thisArg?: any): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.reduce + **/ + reduce( + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduce + **/ + reduce( + callback: MemoIterator, + thisArg?: any): TResult; + } + + //_.reduceRight + interface LoDashStatic { + /** + * This method is like _.reduce except that it iterates over elements of a collection from + * right to left. + * @param collection The collection to iterate over. + * @param callback The function called per iteration. + * @param accumulator Initial value of the accumulator. + * @param thisArg The this binding of callback. + * @return The accumulated value. + **/ + reduceRight( + collection: Array, + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduceRight + **/ + reduceRight( + collection: List, + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduceRight + **/ + reduceRight( + collection: Dictionary, + callback: MemoIterator, + accumulator: TResult, + thisArg?: any): TResult; + + /** + * @see _.reduceRight + **/ + reduceRight( + collection: Array, + callback: MemoIterator, + thisArg?: any): TResult; + + /** + * @see _.reduceRight + **/ + reduceRight( + collection: List, + callback: MemoIterator, + thisArg?: any): TResult; + + /** + * @see _.reduceRight + **/ + reduceRight( + collection: Dictionary, + callback: MemoIterator, + thisArg?: any): TResult; + } + + //_.reject + interface LoDashStatic { + /** + * The opposite of _.filter; this method returns the elements of collection that predicate does not return + * truthy for. + * + * @param collection The collection to iterate over. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the new filtered array. + */ + reject( + collection: List, + predicate?: ListIterator, + thisArg?: any + ): T[]; + + /** + * @see _.reject + */ + reject( + collection: Dictionary, + predicate?: DictionaryIterator, + thisArg?: any + ): T[]; + + /** + * @see _.reject + */ + reject( + collection: string, + predicate?: StringIterator, + thisArg?: any + ): string[]; + + /** + * @see _.reject + */ + reject( + collection: List|Dictionary, + predicate: string, + thisArg?: any + ): T[]; + + /** + * @see _.reject + */ + reject( + collection: List|Dictionary, + predicate: W + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.reject + */ + reject( + predicate?: StringIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.reject + */ + reject( + predicate: ListIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.reject + */ + reject( + predicate: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.reject + */ + reject(predicate: W): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.reject + */ + reject( + predicate: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.reject + */ + reject( + predicate: string, + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.reject + */ + reject(predicate: W): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.reject + */ + reject( + predicate?: StringIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.reject + */ + reject( + predicate: ListIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.reject + */ + reject( + predicate: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.reject + */ + reject(predicate: W): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.reject + */ + reject( + predicate: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.reject + */ + reject( + predicate: string, + thisArg?: any + ): LoDashExplicitArrayWrapper; + + /** + * @see _.reject + */ + reject(predicate: W): LoDashExplicitArrayWrapper; + } + + //_.sample + interface LoDashStatic { + /** + * Gets a random element from `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @returns {*} Returns the random element. + * @example + * + * _.sample([1, 2, 3, 4]); + * // => 2 + */ + sample(collection: Array): T; + + /** + * @see _.sample + **/ + sample(collection: List): T; + + /** + * @see _.sample + **/ + sample(collection: Dictionary): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sample + **/ + sample(): LoDashImplicitWrapper; + } + + //_.sampleSize + interface LoDashStatic { + /** + * Gets `n` random elements from `collection`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object} collection The collection to sample. + * @param {number} [n=0] The number of elements to sample. + * @returns {Array} Returns the random elements. + * @example + * + * _.sampleSize([1, 2, 3, 4], 2); + * // => [3, 1] + */ + sampleSize(collection: Array, n: number): T[]; + + /** + * @see _.sampleSize + **/ + sampleSize(collection: List, n: number): T[]; + + /** + * @see _.sampleSize + **/ + sampleSize(collection: Dictionary, n: number): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sampleSize + **/ + sampleSize(n: number): LoDashImplicitArrayWrapper; + + /** + * @see _.sampleSize + **/ + sampleSize(): LoDashImplicitWrapper; + } + + //_.shuffle + interface LoDashStatic { + /** + * Creates an array of shuffled values, using a version of the Fisher-Yates shuffle. + * + * @param collection The collection to shuffle. + * @return Returns the new shuffled array. + */ + shuffle(collection: List|Dictionary): T[]; + + /** + * @see _.shuffle + */ + shuffle(collection: string): string[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.shuffle + */ + shuffle(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.shuffle + */ + shuffle(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.shuffle + */ + shuffle(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.shuffle + */ + shuffle(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.shuffle + */ + shuffle(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.shuffle + */ + shuffle(): LoDashExplicitArrayWrapper; + } + + //_.size + interface LoDashStatic { + /** + * Gets the size of collection by returning its length for array-like values or the number of own enumerable + * properties for objects. + * + * @param collection The collection to inspect. + * @return Returns the size of collection. + */ + size(collection: List|Dictionary): number; + + /** + * @see _.size + */ + size(collection: string): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.size + */ + size(): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.size + */ + size(): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.size + */ + size(): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.size + */ + size(): LoDashExplicitWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.size + */ + size(): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.size + */ + size(): LoDashExplicitWrapper; + } + + //_.some + interface LoDashStatic { + /** + * Checks if predicate returns truthy for any element of collection. Iteration is stopped once predicate + * returns truthy. The predicate is invoked with three arguments: (value, index|key, collection). + * + * @param collection The collection to iterate over. + * @param predicate The function invoked per iteration. + * @return Returns true if any element passes the predicate check, else false. + */ + some( + collection: List, + predicate?: ListIterator + ): boolean; + + /** + * @see _.some + */ + some( + collection: Dictionary, + predicate?: DictionaryIterator + ): boolean; + + /** + * @see _.some + */ + some( + collection: NumericDictionary, + predicate?: NumericDictionaryIterator + ): boolean; + + /** + * @see _.some + */ + some( + collection: List|Dictionary|NumericDictionary, + predicate?: string|any[] + ): boolean; + + /** + * @see _.some + */ + some( + collection: List|Dictionary|NumericDictionary, + predicate?: TObject + ): boolean; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.some + */ + some( + predicate?: ListIterator|NumericDictionaryIterator + ): boolean; + + /** + * @see _.some + */ + some( + predicate?: string|any[] + ): boolean; + + /** + * @see _.some + */ + some( + predicate?: TObject + ): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.some + */ + some( + predicate?: ListIterator|DictionaryIterator|NumericDictionaryIterator + ): boolean; + + /** + * @see _.some + */ + some( + predicate?: string|any[] + ): boolean; + + /** + * @see _.some + */ + some( + predicate?: TObject + ): boolean; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.some + */ + some( + predicate?: ListIterator|NumericDictionaryIterator + ): LoDashExplicitWrapper; + + /** + * @see _.some + */ + some( + predicate?: string|any[] + ): LoDashExplicitWrapper; + + /** + * @see _.some + */ + some( + predicate?: TObject + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.some + */ + some( + predicate?: ListIterator|DictionaryIterator|NumericDictionaryIterator + ): LoDashExplicitWrapper; + + /** + * @see _.some + */ + some( + predicate?: string|any[] + ): LoDashExplicitWrapper; + + /** + * @see _.some + */ + some( + predicate?: TObject + ): LoDashExplicitWrapper; + } + + //_.sortBy + interface LoDashStatic { + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection through each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[]|Object|Object[]|string|string[])} [iteratees=[_.identity]] + * The iteratees to sort by, specified individually or in arrays. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 42 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, function(o) { return o.user; }); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]] + * + * _.sortBy(users, 'user', function(o) { + * return Math.floor(o.age / 10); + * }); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + */ + sortBy( + collection: List, + iteratee?: ListIterator + ): T[]; + + /** + * @see _.sortBy + */ + sortBy( + collection: Dictionary, + iteratee?: DictionaryIterator + ): T[]; + + /** + * @see _.sortBy + */ + sortBy( + collection: List|Dictionary, + iteratee: string + ): T[]; + + /** + * @see _.sortBy + */ + sortBy( + collection: List|Dictionary, + whereValue: W + ): T[]; + + /** + * @see _.sortBy + */ + sortBy( + collection: List|Dictionary + ): T[]; + + /** + * @see _.sortBy + */ + sortBy( + collection: (Array|List), + iteratees: (ListIterator|string|Object)[]): T[]; + + /** + * @see _.sortBy + */ + sortBy( + collection: (Array|List), + ...iteratees: (ListIterator|Object|string)[]): T[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sortBy + */ + sortBy( + iteratee?: ListIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(iteratee: string): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(whereValue: W): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(...iteratees: (ListIterator|Object|string)[]): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + **/ + sortBy(iteratees: (ListIterator|string|Object)[]): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sortBy + */ + sortBy( + iteratee?: ListIterator|DictionaryIterator + ): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(iteratee: string): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(whereValue: W): LoDashImplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sortBy + */ + sortBy( + iteratee?: ListIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(iteratee: string): LoDashExplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(whereValue: W): LoDashExplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sortBy + */ + sortBy( + iteratee?: ListIterator|DictionaryIterator + ): LoDashExplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(iteratee: string): LoDashExplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(whereValue: W): LoDashExplicitArrayWrapper; + + /** + * @see _.sortBy + */ + sortBy(): LoDashExplicitArrayWrapper; + } + + //_.orderBy + interface LoDashStatic { + /** + * This method is like `_.sortBy` except that it allows specifying the sort + * orders of the iteratees to sort by. If `orders` is unspecified, all values + * are sorted in ascending order. Otherwise, specify an order of "desc" for + * descending or "asc" for ascending sort order of corresponding values. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} [iteratees=[_.identity]] The iteratees to sort by. + * @param {string[]} [orders] The sort orders of `iteratees`. + * @param- {Object} [guard] Enables use as an iteratee for functions like `_.reduce`. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 34 }, + * { 'user': 'fred', 'age': 42 }, + * { 'user': 'barney', 'age': 36 } + * ]; + * + * // sort by `user` in ascending order and by `age` in descending order + * _.orderBy(users, ['user', 'age'], ['asc', 'desc']); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]] + */ + orderBy( + collection: List, + iteratees: ListIterator|string|W|(ListIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): T[]; + + /** + * @see _.orderBy + */ + orderBy( + collection: List, + iteratees: ListIterator|string|Object|(ListIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): T[]; + + /** + * @see _.orderBy + */ + orderBy( + collection: NumericDictionary, + iteratees: NumericDictionaryIterator|string|W|(NumericDictionaryIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): T[]; + + /** + * @see _.orderBy + */ + orderBy( + collection: NumericDictionary, + iteratees: NumericDictionaryIterator|string|Object|(NumericDictionaryIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): T[]; + + /** + * @see _.orderBy + */ + orderBy( + collection: Dictionary, + iteratees: DictionaryIterator|string|W|(DictionaryIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): T[]; + + /** + * @see _.orderBy + */ + orderBy( + collection: Dictionary, + iteratees: DictionaryIterator|string|Object|(DictionaryIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): T[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|(ListIterator|string)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|W|(ListIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|W|(ListIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|Object|(ListIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: NumericDictionaryIterator|string|W|(NumericDictionaryIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: NumericDictionaryIterator|string|Object|(NumericDictionaryIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: DictionaryIterator|string|W|(DictionaryIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: DictionaryIterator|string|Object|(DictionaryIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|(ListIterator|string)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|W|(ListIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|W|(ListIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: ListIterator|string|Object|(ListIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: NumericDictionaryIterator|string|W|(NumericDictionaryIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: NumericDictionaryIterator|string|Object|(NumericDictionaryIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: DictionaryIterator|string|W|(DictionaryIterator|string|W)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + + /** + * @see _.orderBy + */ + orderBy( + iteratees: DictionaryIterator|string|Object|(DictionaryIterator|string|Object)[], + orders?: boolean|string|(boolean|string)[] + ): LoDashExplicitArrayWrapper; + } + + /******** + * Date * + ********/ + + //_.now + interface LoDashStatic { + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @return The number of milliseconds. + */ + now(): number; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.now + */ + now(): number; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.now + */ + now(): LoDashExplicitWrapper; + } + + /************* + * Functions * + *************/ + + //_.after + interface LoDashStatic { + /** + * The opposite of _.before; this method creates a function that invokes func once it’s called n or more times. + * + * @param n The number of calls before func is invoked. + * @param func The function to restrict. + * @return Returns the new restricted function. + */ + after( + n: number, + func: TFunc + ): TFunc; + } + + interface LoDashImplicitWrapper { + /** + * @see _.after + **/ + after(func: TFunc): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.after + **/ + after(func: TFunc): LoDashExplicitObjectWrapper; + } + + //_.ary + interface LoDashStatic { + /** + * Creates a function that accepts up to n arguments ignoring any additional arguments. + * + * @param func The function to cap arguments for. + * @param n The arity cap. + * @returns Returns the new function. + */ + ary( + func: Function, + n?: number + ): TResult; + + ary( + func: T, + n?: number + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.ary + */ + ary(n?: number): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.ary + */ + ary(n?: number): LoDashExplicitObjectWrapper; + } + + //_.before + interface LoDashStatic { + /** + * Creates a function that invokes func, with the this binding and arguments of the created function, while + * it’s called less than n times. Subsequent calls to the created function return the result of the last func + * invocation. + * + * @param n The number of calls at which func is no longer invoked. + * @param func The function to restrict. + * @return Returns the new restricted function. + */ + before( + n: number, + func: TFunc + ): TFunc; + } + + interface LoDashImplicitWrapper { + /** + * @see _.before + **/ + before(func: TFunc): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.before + **/ + before(func: TFunc): LoDashExplicitObjectWrapper; + } + + //_.bind + interface FunctionBind { + placeholder: any; + + ( + func: T, + thisArg: any, + ...partials: any[] + ): TResult; + + ( + func: Function, + thisArg: any, + ...partials: any[] + ): TResult; + } + + interface LoDashStatic { + /** + * Creates a function that invokes func with the this binding of thisArg and prepends any additional _.bind + * arguments to those provided to the bound function. + * + * The _.bind.placeholder value, which defaults to _ in monolithic builds, may be used as a placeholder for + * partially applied arguments. + * + * Note: Unlike native Function#bind this method does not set the "length" property of bound functions. + * + * @param func The function to bind. + * @param thisArg The this binding of func. + * @param partials The arguments to be partially applied. + * @return Returns the new bound function. + */ + bind: FunctionBind; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.bind + */ + bind( + thisArg: any, + ...partials: any[] + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.bind + */ + bind( + thisArg: any, + ...partials: any[] + ): LoDashExplicitObjectWrapper; + } + + //_.bindAll + interface LoDashStatic { + /** + * Binds methods of an object to the object itself, overwriting the existing method. Method names may be + * specified as individual arguments or as arrays of method names. If no method names are provided all + * enumerable function properties, own and inherited, of object are bound. + * + * Note: This method does not set the "length" property of bound functions. + * + * @param object The object to bind and assign the bound methods to. + * @param methodNames The object method names to bind, specified as individual method names or arrays of + * method names. + * @return Returns object. + */ + bindAll( + object: T, + ...methodNames: (string|string[])[] + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.bindAll + */ + bindAll(...methodNames: (string|string[])[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.bindAll + */ + bindAll(...methodNames: (string|string[])[]): LoDashExplicitObjectWrapper; + } + + //_.bindKey + interface FunctionBindKey { + placeholder: any; + + ( + object: T, + key: any, + ...partials: any[] + ): TResult; + + ( + object: Object, + key: any, + ...partials: any[] + ): TResult; + } + + interface LoDashStatic { + /** + * Creates a function that invokes the method at object[key] and prepends any additional _.bindKey arguments + * to those provided to the bound function. + * + * This method differs from _.bind by allowing bound functions to reference methods that may be redefined + * or don’t yet exist. See Peter Michaux’s article for more details. + * + * The _.bindKey.placeholder value, which defaults to _ in monolithic builds, may be used as a placeholder + * for partially applied arguments. + * + * @param object The object the method belongs to. + * @param key The key of the method. + * @param partials The arguments to be partially applied. + * @return Returns the new bound function. + */ + bindKey: FunctionBindKey; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.bindKey + */ + bindKey( + key: any, + ...partials: any[] + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.bindKey + */ + bindKey( + key: any, + ...partials: any[] + ): LoDashExplicitObjectWrapper; + } + + //_.createCallback + interface LoDashStatic { + /** + * Produces a callback bound to an optional thisArg. If func is a property name the created + * callback will return the property value for a given element. If func is an object the created + * callback will return true for elements that contain the equivalent object properties, + * otherwise it will return false. + * @param func The value to convert to a callback. + * @param thisArg The this binding of the created callback. + * @param argCount The number of arguments the callback accepts. + * @return A callback function. + **/ + createCallback( + func: string, + thisArg?: any, + argCount?: number): () => any; + + /** + * @see _.createCallback + **/ + createCallback( + func: Dictionary, + thisArg?: any, + argCount?: number): () => boolean; + } + + interface LoDashImplicitWrapper { + /** + * @see _.createCallback + **/ + createCallback( + thisArg?: any, + argCount?: number): LoDashImplicitObjectWrapper<() => any>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.createCallback + **/ + createCallback( + thisArg?: any, + argCount?: number): LoDashImplicitObjectWrapper<() => any>; + } + + //_.curry + interface LoDashStatic { + /** + * Creates a function that accepts one or more arguments of func that when called either invokes func returning + * its result, if all func arguments have been provided, or returns a function that accepts one or more of the + * remaining func arguments, and so on. The arity of func may be specified if func.length is not sufficient. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curry(func: (t1: T1) => R): + CurriedFunction1; + /** + * Creates a function that accepts one or more arguments of func that when called either invokes func returning + * its result, if all func arguments have been provided, or returns a function that accepts one or more of the + * remaining func arguments, and so on. The arity of func may be specified if func.length is not sufficient. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curry(func: (t1: T1, t2: T2) => R): + CurriedFunction2; + /** + * Creates a function that accepts one or more arguments of func that when called either invokes func returning + * its result, if all func arguments have been provided, or returns a function that accepts one or more of the + * remaining func arguments, and so on. The arity of func may be specified if func.length is not sufficient. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curry(func: (t1: T1, t2: T2, t3: T3) => R): + CurriedFunction3; + /** + * Creates a function that accepts one or more arguments of func that when called either invokes func returning + * its result, if all func arguments have been provided, or returns a function that accepts one or more of the + * remaining func arguments, and so on. The arity of func may be specified if func.length is not sufficient. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curry(func: (t1: T1, t2: T2, t3: T3, t4: T4) => R): + CurriedFunction4; + /** + * Creates a function that accepts one or more arguments of func that when called either invokes func returning + * its result, if all func arguments have been provided, or returns a function that accepts one or more of the + * remaining func arguments, and so on. The arity of func may be specified if func.length is not sufficient. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curry(func: (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5) => R): + CurriedFunction5; + /** + * Creates a function that accepts one or more arguments of func that when called either invokes func returning + * its result, if all func arguments have been provided, or returns a function that accepts one or more of the + * remaining func arguments, and so on. The arity of func may be specified if func.length is not sufficient. + * @param func The function to curry. + * @param arity The arity of func. + * @return Returns the new curried function. + */ + curry( + func: Function, + arity?: number): TResult; + } + + interface CurriedFunction1 { + (): CurriedFunction1; + (t1: T1): R; + } + + interface CurriedFunction2 { + (): CurriedFunction2; + (t1: T1): CurriedFunction1; + (t1: T1, t2: T2): R; + } + + interface CurriedFunction3 { + (): CurriedFunction3; + (t1: T1): CurriedFunction2; + (t1: T1, t2: T2): CurriedFunction1; + (t1: T1, t2: T2, t3: T3): R; + } + + interface CurriedFunction4 { + (): CurriedFunction4; + (t1: T1): CurriedFunction3; + (t1: T1, t2: T2): CurriedFunction2; + (t1: T1, t2: T2, t3: T3): CurriedFunction1; + (t1: T1, t2: T2, t3: T3, t4: T4): R; + } + + interface CurriedFunction5 { + (): CurriedFunction5; + (t1: T1): CurriedFunction4; + (t1: T1, t2: T2): CurriedFunction3; + (t1: T1, t2: T2, t3: T3): CurriedFunction2; + (t1: T1, t2: T2, t3: T3, t4: T4): CurriedFunction1; + (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5): R; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.curry + **/ + curry(arity?: number): LoDashImplicitObjectWrapper; + } + + //_.curryRight + interface LoDashStatic { + /** + * This method is like _.curry except that arguments are applied to func in the manner of _.partialRight + * instead of _.partial. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curryRight(func: (t1: T1) => R): + CurriedFunction1; + /** + * This method is like _.curry except that arguments are applied to func in the manner of _.partialRight + * instead of _.partial. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curryRight(func: (t1: T1, t2: T2) => R): + CurriedFunction2; + /** + * This method is like _.curry except that arguments are applied to func in the manner of _.partialRight + * instead of _.partial. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curryRight(func: (t1: T1, t2: T2, t3: T3) => R): + CurriedFunction3; + /** + * This method is like _.curry except that arguments are applied to func in the manner of _.partialRight + * instead of _.partial. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curryRight(func: (t1: T1, t2: T2, t3: T3, t4: T4) => R): + CurriedFunction4; + /** + * This method is like _.curry except that arguments are applied to func in the manner of _.partialRight + * instead of _.partial. + * @param func The function to curry. + * @return Returns the new curried function. + */ + curryRight(func: (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5) => R): + CurriedFunction5; + /** + * This method is like _.curry except that arguments are applied to func in the manner of _.partialRight + * instead of _.partial. + * @param func The function to curry. + * @param arity The arity of func. + * @return Returns the new curried function. + */ + curryRight( + func: Function, + arity?: number): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.curryRight + **/ + curryRight(arity?: number): LoDashImplicitObjectWrapper; + } + + //_.debounce + interface DebounceSettings { + /** + * Specify invoking on the leading edge of the timeout. + */ + leading?: boolean; + + /** + * The maximum time func is allowed to be delayed before it’s invoked. + */ + maxWait?: number; + + /** + * Specify invoking on the trailing edge of the timeout. + */ + trailing?: boolean; + } + + interface LoDashStatic { + /** + * Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since + * the last time the debounced function was invoked. The debounced function comes with a cancel method to + * cancel delayed invocations. Provide an options object to indicate that func should be invoked on the + * leading and/or trailing edge of the wait timeout. Subsequent calls to the debounced function return the + * result of the last func invocation. + * + * Note: If leading and trailing options are true, func is invoked on the trailing edge of the timeout only + * if the the debounced function is invoked more than once during the wait timeout. + * + * See David Corbacho’s article for details over the differences between _.debounce and _.throttle. + * + * @param func The function to debounce. + * @param wait The number of milliseconds to delay. + * @param options The options object. + * @param options.leading Specify invoking on the leading edge of the timeout. + * @param options.maxWait The maximum time func is allowed to be delayed before it’s invoked. + * @param options.trailing Specify invoking on the trailing edge of the timeout. + * @return Returns the new debounced function. + */ + debounce( + func: T, + wait?: number, + options?: DebounceSettings + ): T & Cancelable; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.debounce + */ + debounce( + wait?: number, + options?: DebounceSettings + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.debounce + */ + debounce( + wait?: number, + options?: DebounceSettings + ): LoDashExplicitObjectWrapper; + } + + //_.defer + interface LoDashStatic { + /** + * Defers invoking the func until the current call stack has cleared. Any additional arguments are provided to + * func when it’s invoked. + * + * @param func The function to defer. + * @param args The arguments to invoke the function with. + * @return Returns the timer id. + */ + defer( + func: T, + ...args: any[] + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.defer + */ + defer(...args: any[]): LoDashImplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.defer + */ + defer(...args: any[]): LoDashExplicitWrapper; + } + + //_.delay + interface LoDashStatic { + /** + * Invokes func after wait milliseconds. Any additional arguments are provided to func when it’s invoked. + * + * @param func The function to delay. + * @param wait The number of milliseconds to delay invocation. + * @param args The arguments to invoke the function with. + * @return Returns the timer id. + */ + delay( + func: T, + wait: number, + ...args: any[] + ): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.delay + */ + delay( + wait: number, + ...args: any[] + ): LoDashImplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.delay + */ + delay( + wait: number, + ...args: any[] + ): LoDashExplicitWrapper; + } + + interface LoDashStatic { + /** + * Creates a function that invokes `func` with arguments reversed. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to flip arguments for. + * @returns {Function} Returns the new function. + * @example + * + * var flipped = _.flip(function() { + * return _.toArray(arguments); + * }); + * + * flipped('a', 'b', 'c', 'd'); + * // => ['d', 'c', 'b', 'a'] + */ + flip(func: T): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.flip + */ + flip(): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.flip + */ + flip(): LoDashExplicitObjectWrapper; + } + + //_.flow + interface LoDashStatic { + /** + * Creates a function that returns the result of invoking the provided functions with the this binding of the + * created function, where each successive invocation is supplied the return value of the previous. + * + * @param funcs Functions to invoke. + * @return Returns the new function. + */ + flow(...funcs: Function[]): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.flow + */ + flow(...funcs: Function[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.flow + */ + flow(...funcs: Function[]): LoDashExplicitObjectWrapper; + } + + //_.flowRight + interface LoDashStatic { + /** + * This method is like _.flow except that it creates a function that invokes the provided functions from right + * to left. + * + * @param funcs Functions to invoke. + * @return Returns the new function. + */ + flowRight(...funcs: Function[]): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.flowRight + */ + flowRight(...funcs: Function[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.flowRight + */ + flowRight(...funcs: Function[]): LoDashExplicitObjectWrapper; + } + + + //_.memoize + interface MemoizedFunction extends Function { + cache: MapCache; + } + + interface LoDashStatic { + /** + * Creates a function that memoizes the result of func. If resolver is provided it determines the cache key for + * storing the result based on the arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is coerced to a string and used as the cache key. The func is invoked with + * the this binding of the memoized function. + * @param func The function to have its output memoized. + * @param resolver The function to resolve the cache key. + * @return Returns the new memoizing function. + */ + memoize: { + (func: T, resolver?: Function): T & MemoizedFunction; + Cache: MapCache; + } + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.memoize + */ + memoize(resolver?: Function): LoDashImplicitObjectWrapper; + } + + //_.overArgs (was _.modArgs) + interface LoDashStatic { + /** + * Creates a function that runs each argument through a corresponding transform function. + * + * @param func The function to wrap. + * @param transforms The functions to transform arguments, specified as individual functions or arrays + * of functions. + * @return Returns the new function. + */ + overArgs( + func: T, + ...transforms: Function[] + ): TResult; + + /** + * @see _.overArgs + */ + overArgs( + func: T, + transforms: Function[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.overArgs + */ + overArgs(...transforms: Function[]): LoDashImplicitObjectWrapper; + + /** + * @see _.overArgs + */ + overArgs(transforms: Function[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.overArgs + */ + overArgs(...transforms: Function[]): LoDashExplicitObjectWrapper; + + /** + * @see _.overArgs + */ + overArgs(transforms: Function[]): LoDashExplicitObjectWrapper; + } + + //_.negate + interface LoDashStatic { + /** + * Creates a function that negates the result of the predicate func. The func predicate is invoked with + * the this binding and arguments of the created function. + * + * @param predicate The predicate to negate. + * @return Returns the new function. + */ + negate(predicate: T): (...args: any[]) => boolean; + + /** + * @see _.negate + */ + negate(predicate: T): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.negate + */ + negate(): LoDashImplicitObjectWrapper<(...args: any[]) => boolean>; + + /** + * @see _.negate + */ + negate(): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.negate + */ + negate(): LoDashExplicitObjectWrapper<(...args: any[]) => boolean>; + + /** + * @see _.negate + */ + negate(): LoDashExplicitObjectWrapper; + } + + //_.once + interface LoDashStatic { + /** + * Creates a function that is restricted to invoking func once. Repeat calls to the function return the value + * of the first call. The func is invoked with the this binding and arguments of the created function. + * + * @param func The function to restrict. + * @return Returns the new restricted function. + */ + once(func: T): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.once + */ + once(): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.once + */ + once(): LoDashExplicitObjectWrapper; + } + + //_.partial + interface LoDashStatic { + /** + * Creates a function that, when called, invokes func with any additional partial arguments + * prepended to those provided to the new function. This method is similar to _.bind except + * it does not alter the this binding. + * @param func The function to partially apply arguments to. + * @param args Arguments to be partially applied. + * @return The new partially applied function. + **/ + partial: Partial; + } + + type PH = LoDashStatic; + + interface Function0 { + (): R; + } + interface Function1 { + (t1: T1): R; + } + interface Function2 { + (t1: T1, t2: T2): R; + } + interface Function3 { + (t1: T1, t2: T2, t3: T3): R; + } + interface Function4 { + (t1: T1, t2: T2, t3: T3, t4: T4): R; + } + + interface Partial { + // arity 0 + (func: Function0): Function0; + // arity 1 + (func: Function1): Function1; + (func: Function1, arg1: T1): Function0; + // arity 2 + (func: Function2): Function2; + (func: Function2, arg1: T1): Function1< T2, R>; + (func: Function2, plc1: PH, arg2: T2): Function1; + (func: Function2, arg1: T1, arg2: T2): Function0< R>; + // arity 3 + (func: Function3): Function3; + (func: Function3, arg1: T1): Function2< T2, T3, R>; + (func: Function3, plc1: PH, arg2: T2): Function2; + (func: Function3, arg1: T1, arg2: T2): Function1< T3, R>; + (func: Function3, plc1: PH, plc2: PH, arg3: T3): Function2; + (func: Function3, arg1: T1, plc2: PH, arg3: T3): Function1< T2, R>; + (func: Function3, plc1: PH, arg2: T2, arg3: T3): Function1; + (func: Function3, arg1: T1, arg2: T2, arg3: T3): Function0< R>; + // arity 4 + (func: Function4): Function4; + (func: Function4, arg1: T1): Function3< T2, T3, T4, R>; + (func: Function4, plc1: PH, arg2: T2): Function3; + (func: Function4, arg1: T1, arg2: T2): Function2< T3, T4, R>; + (func: Function4, plc1: PH, plc2: PH, arg3: T3): Function3; + (func: Function4, arg1: T1, plc2: PH, arg3: T3): Function2< T2, T4, R>; + (func: Function4, plc1: PH, arg2: T2, arg3: T3): Function2; + (func: Function4, arg1: T1, arg2: T2, arg3: T3): Function1< T4, R>; + (func: Function4, plc1: PH, plc2: PH, plc3: PH, arg4: T4): Function3; + (func: Function4, arg1: T1, plc2: PH, plc3: PH, arg4: T4): Function2< T2, T3, R>; + (func: Function4, plc1: PH, arg2: T2, plc3: PH, arg4: T4): Function2; + (func: Function4, arg1: T1, arg2: T2, plc3: PH, arg4: T4): Function1< T3, R>; + (func: Function4, plc1: PH, plc2: PH, arg3: T3, arg4: T4): Function2; + (func: Function4, arg1: T1, plc2: PH, arg3: T3, arg4: T4): Function1< T2, R>; + (func: Function4, plc1: PH, arg2: T2, arg3: T3, arg4: T4): Function1; + (func: Function4, arg1: T1, arg2: T2, arg3: T3, arg4: T4): Function0< R>; + // catch-all + (func: Function, ...args: any[]): Function; + } + + //_.partialRight + interface LoDashStatic { + /** + * This method is like _.partial except that partial arguments are appended to those provided + * to the new function. + * @param func The function to partially apply arguments to. + * @param args Arguments to be partially applied. + * @return The new partially applied function. + **/ + partialRight: PartialRight + } + + interface PartialRight { + // arity 0 + (func: Function0): Function0; + // arity 1 + (func: Function1): Function1; + (func: Function1, arg1: T1): Function0; + // arity 2 + (func: Function2): Function2; + (func: Function2, arg1: T1, plc2: PH): Function1< T2, R>; + (func: Function2, arg2: T2): Function1; + (func: Function2, arg1: T1, arg2: T2): Function0< R>; + // arity 3 + (func: Function3): Function3; + (func: Function3, arg1: T1, plc2: PH, plc3: PH): Function2< T2, T3, R>; + (func: Function3, arg2: T2, plc3: PH): Function2; + (func: Function3, arg1: T1, arg2: T2, plc3: PH): Function1< T3, R>; + (func: Function3, arg3: T3): Function2; + (func: Function3, arg1: T1, plc2: PH, arg3: T3): Function1< T2, R>; + (func: Function3, arg2: T2, arg3: T3): Function1; + (func: Function3, arg1: T1, arg2: T2, arg3: T3): Function0< R>; + // arity 4 + (func: Function4): Function4; + (func: Function4, arg1: T1, plc2: PH, plc3: PH, plc4: PH): Function3< T2, T3, T4, R>; + (func: Function4, arg2: T2, plc3: PH, plc4: PH): Function3; + (func: Function4, arg1: T1, arg2: T2, plc3: PH, plc4: PH): Function2< T3, T4, R>; + (func: Function4, arg3: T3, plc4: PH): Function3; + (func: Function4, arg1: T1, plc2: PH, arg3: T3, plc4: PH): Function2< T2, T4, R>; + (func: Function4, arg2: T2, arg3: T3, plc4: PH): Function2; + (func: Function4, arg1: T1, arg2: T2, arg3: T3, plc4: PH): Function1< T4, R>; + (func: Function4, arg4: T4): Function3; + (func: Function4, arg1: T1, plc2: PH, plc3: PH, arg4: T4): Function2< T2, T3, R>; + (func: Function4, arg2: T2, plc3: PH, arg4: T4): Function2; + (func: Function4, arg1: T1, arg2: T2, plc3: PH, arg4: T4): Function1< T3, R>; + (func: Function4, arg3: T3, arg4: T4): Function2; + (func: Function4, arg1: T1, plc2: PH, arg3: T3, arg4: T4): Function1< T2, R>; + (func: Function4, arg2: T2, arg3: T3, arg4: T4): Function1; + (func: Function4, arg1: T1, arg2: T2, arg3: T3, arg4: T4): Function0< R>; + // catch-all + (func: Function, ...args: any[]): Function; + } + + //_.rearg + interface LoDashStatic { + /** + * Creates a function that invokes func with arguments arranged according to the specified indexes where the + * argument value at the first index is provided as the first argument, the argument value at the second index + * is provided as the second argument, and so on. + * @param func The function to rearrange arguments for. + * @param indexes The arranged argument indexes, specified as individual indexes or arrays of indexes. + * @return Returns the new function. + */ + rearg(func: Function, indexes: number[]): TResult; + + /** + * @see _.rearg + */ + rearg(func: Function, ...indexes: number[]): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.rearg + */ + rearg(indexes: number[]): LoDashImplicitObjectWrapper; + + /** + * @see _.rearg + */ + rearg(...indexes: number[]): LoDashImplicitObjectWrapper; + } + + //_.rest + interface LoDashStatic { + /** + * Creates a function that invokes func with the this binding of the created function and arguments from start + * and beyond provided as an array. + * + * Note: This method is based on the rest parameter. + * + * @param func The function to apply a rest parameter to. + * @param start The start position of the rest parameter. + * @return Returns the new function. + */ + rest( + func: Function, + start?: number + ): TResult; + + /** + * @see _.rest + */ + rest( + func: TFunc, + start?: number + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.rest + */ + rest(start?: number): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.rest + */ + rest(start?: number): LoDashExplicitObjectWrapper; + } + + //_.spread + interface LoDashStatic { + /** + * Creates a function that invokes func with the this binding of the created function and an array of arguments + * much like Function#apply. + * + * Note: This method is based on the spread operator. + * + * @param func The function to spread arguments over. + * @return Returns the new function. + */ + spread(func: F): T; + + /** + * @see _.spread + */ + spread(func: Function): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.spread + */ + spread(): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.spread + */ + spread(): LoDashExplicitObjectWrapper; + } + + //_.throttle + interface ThrottleSettings { + /** + * If you'd like to disable the leading-edge call, pass this as false. + */ + leading?: boolean; + + /** + * If you'd like to disable the execution on the trailing-edge, pass false. + */ + trailing?: boolean; + } + + interface LoDashStatic { + /** + * Creates a throttled function that only invokes func at most once per every wait milliseconds. The throttled + * function comes with a cancel method to cancel delayed invocations. Provide an options object to indicate + * that func should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent calls to + * the throttled function return the result of the last func call. + * + * Note: If leading and trailing options are true, func is invoked on the trailing edge of the timeout only if + * the the throttled function is invoked more than once during the wait timeout. + * + * @param func The function to throttle. + * @param wait The number of milliseconds to throttle invocations to. + * @param options The options object. + * @param options.leading Specify invoking on the leading edge of the timeout. + * @param options.trailing Specify invoking on the trailing edge of the timeout. + * @return Returns the new throttled function. + */ + throttle( + func: T, + wait?: number, + options?: ThrottleSettings + ): T & Cancelable; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.throttle + */ + throttle( + wait?: number, + options?: ThrottleSettings + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.throttle + */ + throttle( + wait?: number, + options?: ThrottleSettings + ): LoDashExplicitObjectWrapper; + } + + //_.unary + interface LoDashStatic { + /** + * Creates a function that accepts up to one argument, ignoring any + * additional arguments. + * + * @static + * @memberOf _ + * @category Function + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new function. + * @example + * + * _.map(['6', '8', '10'], _.unary(parseInt)); + * // => [6, 8, 10] + */ + unary(func: T): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.unary + */ + unary(): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.unary + */ + unary(): LoDashExplicitObjectWrapper; + } + + //_.wrap + interface LoDashStatic { + /** + * Creates a function that provides value to the wrapper function as its first argument. Any additional + * arguments provided to the function are appended to those provided to the wrapper function. The wrapper is + * invoked with the this binding of the created function. + * + * @param value The value to wrap. + * @param wrapper The wrapper function. + * @return Returns the new function. + */ + wrap( + value: V, + wrapper: W + ): R; + + /** + * @see _.wrap + */ + wrap( + value: V, + wrapper: Function + ): R; + + /** + * @see _.wrap + */ + wrap( + value: any, + wrapper: Function + ): R; + } + + interface LoDashImplicitWrapper { + /** + * @see _.wrap + */ + wrap(wrapper: W): LoDashImplicitObjectWrapper; + + /** + * @see _.wrap + */ + wrap(wrapper: Function): LoDashImplicitObjectWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.wrap + */ + wrap(wrapper: W): LoDashImplicitObjectWrapper; + + /** + * @see _.wrap + */ + wrap(wrapper: Function): LoDashImplicitObjectWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.wrap + */ + wrap(wrapper: W): LoDashImplicitObjectWrapper; + + /** + * @see _.wrap + */ + wrap(wrapper: Function): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.wrap + */ + wrap(wrapper: W): LoDashExplicitObjectWrapper; + + /** + * @see _.wrap + */ + wrap(wrapper: Function): LoDashExplicitObjectWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.wrap + */ + wrap(wrapper: W): LoDashExplicitObjectWrapper; + + /** + * @see _.wrap + */ + wrap(wrapper: Function): LoDashExplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.wrap + */ + wrap(wrapper: W): LoDashExplicitObjectWrapper; + + /** + * @see _.wrap + */ + wrap(wrapper: Function): LoDashExplicitObjectWrapper; + } + + /******** + * Lang * + ********/ + + //_.clone + interface LoDashStatic { + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + clone(value: T): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.clone + */ + clone(): T; + } + + interface LoDashImplicitArrayWrapper { + + /** + * @see _.clone + */ + clone(): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.clone + */ + clone(): T; + } + + //_.cloneDeep + interface LoDashStatic { + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + cloneDeep(value: T): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.cloneDeep + */ + cloneDeep(): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.cloneDeep + */ + cloneDeep(): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.cloneDeep + */ + cloneDeep(): T; + } + + //_.cloneWith + interface LoDashStatic { + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + clone( + value: T, + customizer: (value: any) => any): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.clone + */ + clone(customizer: (value: any) => any): T; + } + + interface LoDashImplicitArrayWrapper { + + /** + * @see _.clone + */ + clone(customizer: (value: any) => any): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.clone + */ + clone(customizer: (value: any) => any): T; + } + + //_.cloneDeepWith + interface LoDashStatic { + /** + * Creates a deep clone of value. If customizer is provided it’s invoked to produce the cloned values. If + * customizer returns undefined cloning is handled by the method instead. The customizer is bound to thisArg + * and invoked with up to three argument; (value [, index|key, object]). + * Note: This method is loosely based on the structured clone algorithm. The enumerable properties of arguments + * objects and objects created by constructors other than Object are cloned to plain Object objects. An empty + * object is returned for uncloneable values such as functions, DOM nodes, Maps, Sets, and WeakMaps. + * @param value The value to deep clone. + * @param customizer The function to customize cloning values. + * @param thisArg The this binding of customizer. + * @return Returns the deep cloned value. + */ + cloneDeep( + value: T, + customizer: (value: any) => any): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.cloneDeep + */ + cloneDeep(customizer: (value: any) => any): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.cloneDeep + */ + cloneDeep(customizer: (value: any) => any): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.cloneDeep + */ + cloneDeep(customizer: (value: any) => any): T; + } + + //_.eq + interface LoDashStatic { + /** + * Performs a [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + eq( + value: any, + other: any + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isEqual + */ + eq( + other: any + ): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isEqual + */ + eq( + other: any + ): LoDashExplicitWrapper; + } + + //_.gt + interface LoDashStatic { + /** + * Checks if value is greater than other. + * + * @param value The value to compare. + * @param other The other value to compare. + * @return Returns true if value is greater than other, else false. + */ + gt( + value: any, + other: any + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.gt + */ + gt(other: any): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.gt + */ + gt(other: any): LoDashExplicitWrapper; + } + + //_.gte + interface LoDashStatic { + /** + * Checks if value is greater than or equal to other. + * + * @param value The value to compare. + * @param other The other value to compare. + * @return Returns true if value is greater than or equal to other, else false. + */ + gte( + value: any, + other: any + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.gte + */ + gte(other: any): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.gte + */ + gte(other: any): LoDashExplicitWrapper; + } + + //_.isArguments + interface LoDashStatic { + /** + * Checks if value is classified as an arguments object. + * + * @param value The value to check. + * @return Returns true if value is correctly classified, else false. + */ + isArguments(value?: any): value is IArguments; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isArguments + */ + isArguments(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isArguments + */ + isArguments(): LoDashExplicitWrapper; + } + + //_.isArray + interface LoDashStatic { + /** + * Checks if value is classified as an Array object. + * @param value The value to check. + * + * @return Returns true if value is correctly classified, else false. + */ + isArray(value?: any): value is T[]; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isArray + */ + isArray(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isArray + */ + isArray(): LoDashExplicitWrapper; + } + + //_.isArrayLike + interface LoDashStatic { + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @type Function + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + isArrayLike(value?: any): value is T[]; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isArrayLike + */ + isArrayLike(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isArrayLike + */ + isArrayLike(): LoDashExplicitWrapper; + } + + //_.isArrayLikeObject + interface LoDashStatic { + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @type Function + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + isArrayLikeObject(value?: any): value is T[]; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isArrayLikeObject + */ + isArrayLikeObject(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isArrayLikeObject + */ + isArrayLikeObject(): LoDashExplicitWrapper; + } + + //_.isBoolean + interface LoDashStatic { + /** + * Checks if value is classified as a boolean primitive or object. + * + * @param value The value to check. + * @return Returns true if value is correctly classified, else false. + */ + isBoolean(value?: any): value is boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isBoolean + */ + isBoolean(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isBoolean + */ + isBoolean(): LoDashExplicitWrapper; + } + + //_.isDate + interface LoDashStatic { + /** + * Checks if value is classified as a Date object. + * @param value The value to check. + * + * @return Returns true if value is correctly classified, else false. + */ + isDate(value?: any): value is Date; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isDate + */ + isDate(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isDate + */ + isDate(): LoDashExplicitWrapper; + } + + //_.isElement + interface LoDashStatic { + /** + * Checks if value is a DOM element. + * + * @param value The value to check. + * @return Returns true if value is a DOM element, else false. + */ + isElement(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isElement + */ + isElement(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isElement + */ + isElement(): LoDashExplicitWrapper; + } + + //_.isEmpty + interface LoDashStatic { + /** + * Checks if value is empty. A value is considered empty unless it’s an arguments object, array, string, or + * jQuery-like collection with a length greater than 0 or an object with own enumerable properties. + * + * @param value The value to inspect. + * @return Returns true if value is empty, else false. + */ + isEmpty(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isEmpty + */ + isEmpty(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isEmpty + */ + isEmpty(): LoDashExplicitWrapper; + } + + //_.isEqual + interface LoDashStatic { + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are **not** supported. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'user': 'fred' }; + * var other = { 'user': 'fred' }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + isEqual( + value: any, + other: any + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isEqual + */ + isEqual( + other: any + ): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isEqual + */ + isEqual( + other: any + ): LoDashExplicitWrapper; + } + + // _.isEqualWith + interface IsEqualCustomizer { + (value: any, other: any, indexOrKey?: number|string): boolean; + } + + interface LoDashStatic { + /** + * This method is like `_.isEqual` except that it accepts `customizer` which is + * invoked to compare values. If `customizer` returns `undefined` comparisons are + * handled by the method instead. The `customizer` is invoked with up to seven arguments: + * (objValue, othValue [, index|key, object, other, stack]). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, othValue) { + * if (isGreeting(objValue) && isGreeting(othValue)) { + * return true; + * } + * } + * + * var array = ['hello', 'goodbye']; + * var other = ['hi', 'goodbye']; + * + * _.isEqualWith(array, other, customizer); + * // => true + */ + isEqualWith( + value: any, + other: any, + customizer: IsEqualCustomizer + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isEqualWith + */ + isEqualWith( + other: any, + customizer: IsEqualCustomizer + ): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isEqualWith + */ + isEqualWith( + other: any, + customizer: IsEqualCustomizer + ): LoDashExplicitWrapper; + } + + //_.isError + interface LoDashStatic { + /** + * Checks if value is an Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, or URIError + * object. + * + * @param value The value to check. + * @return Returns true if value is an error object, else false. + */ + isError(value: any): value is Error; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isError + */ + isError(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isError + */ + isError(): LoDashExplicitWrapper; + } + + //_.isFinite + interface LoDashStatic { + /** + * Checks if value is a finite primitive number. + * + * Note: This method is based on Number.isFinite. + * + * @param value The value to check. + * @return Returns true if value is a finite number, else false. + */ + isFinite(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isFinite + */ + isFinite(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isFinite + */ + isFinite(): LoDashExplicitWrapper; + } + + //_.isFunction + interface LoDashStatic { + /** + * Checks if value is classified as a Function object. + * + * @param value The value to check. + * @return Returns true if value is correctly classified, else false. + */ + isFunction(value?: any): value is Function; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isFunction + */ + isFunction(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isFunction + */ + isFunction(): LoDashExplicitWrapper; + } + + //_.isInteger + interface LoDashStatic { + /** + * Checks if `value` is an integer. + * + * **Note:** This method is based on [`Number.isInteger`](https://mdn.io/Number/isInteger). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an integer, else `false`. + * @example + * + * _.isInteger(3); + * // => true + * + * _.isInteger(Number.MIN_VALUE); + * // => false + * + * _.isInteger(Infinity); + * // => false + * + * _.isInteger('3'); + * // => false + */ + isInteger(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isInteger + */ + isInteger(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isInteger + */ + isInteger(): LoDashExplicitWrapper; + } + + //_.isLength + interface LoDashStatic { + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This function is loosely based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + isLength(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isLength + */ + isLength(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isLength + */ + isLength(): LoDashExplicitWrapper; + } + + //_.isMatch + interface isMatchCustomizer { + (value: any, other: any, indexOrKey?: number|string): boolean; + } + + interface LoDashStatic { + /** + * Performs a deep comparison between `object` and `source` to determine if + * `object` contains equivalent property values. + * + * **Note:** This method supports comparing the same values as `_.isEqual`. + * + * @static + * @memberOf _ + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * var object = { 'user': 'fred', 'age': 40 }; + * + * _.isMatch(object, { 'age': 40 }); + * // => true + * + * _.isMatch(object, { 'age': 36 }); + * // => false + */ + isMatch(object: Object, source: Object): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.isMatch + */ + isMatch(source: Object): boolean; + } + + //_.isMatchWith + interface isMatchWithCustomizer { + (value: any, other: any, indexOrKey?: number|string): boolean; + } + + interface LoDashStatic { + /** + * This method is like `_.isMatch` except that it accepts `customizer` which + * is invoked to compare values. If `customizer` returns `undefined` comparisons + * are handled by the method instead. The `customizer` is invoked with three + * arguments: (objValue, srcValue, index|key, object, source). + * + * @static + * @memberOf _ + * @category Lang + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + * @example + * + * function isGreeting(value) { + * return /^h(?:i|ello)$/.test(value); + * } + * + * function customizer(objValue, srcValue) { + * if (isGreeting(objValue) && isGreeting(srcValue)) { + * return true; + * } + * } + * + * var object = { 'greeting': 'hello' }; + * var source = { 'greeting': 'hi' }; + * + * _.isMatchWith(object, source, customizer); + * // => true + */ + isMatchWith(object: Object, source: Object, customizer: isMatchWithCustomizer): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.isMatchWith + */ + isMatchWith(source: Object, customizer: isMatchWithCustomizer): boolean; + } + + //_.isNaN + interface LoDashStatic { + /** + * Checks if value is NaN. + * + * Note: This method is not the same as isNaN which returns true for undefined and other non-numeric values. + * + * @param value The value to check. + * @return Returns true if value is NaN, else false. + */ + isNaN(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.isNaN + */ + isNaN(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.isNaN + */ + isNaN(): LoDashExplicitWrapper; + } + + //_.isNative + interface LoDashStatic { + /** + * Checks if value is a native function. + * @param value The value to check. + * + * @retrun Returns true if value is a native function, else false. + */ + isNative(value: any): value is Function; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isNative + */ + isNative(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isNative + */ + isNative(): LoDashExplicitWrapper; + } + + //_.isNil + interface LoDashStatic { + /** + * Checks if `value` is `null` or `undefined`. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is nullish, else `false`. + * @example + * + * _.isNil(null); + * // => true + * + * _.isNil(void 0); + * // => true + * + * _.isNil(NaN); + * // => false + */ + isNil(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isNil + */ + isNil(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isNil + */ + isNil(): LoDashExplicitWrapper; + } + + //_.isNull + interface LoDashStatic { + /** + * Checks if value is null. + * + * @param value The value to check. + * @return Returns true if value is null, else false. + */ + isNull(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isNull + */ + isNull(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isNull + */ + isNull(): LoDashExplicitWrapper; + } + + //_.isNumber + interface LoDashStatic { + /** + * Checks if value is classified as a Number primitive or object. + * + * Note: To exclude Infinity, -Infinity, and NaN, which are classified as numbers, use the _.isFinite method. + * + * @param value The value to check. + * @return Returns true if value is correctly classified, else false. + */ + isNumber(value?: any): value is number; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isNumber + */ + isNumber(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isNumber + */ + isNumber(): LoDashExplicitWrapper; + } + + //_.isObject + interface LoDashStatic { + /** + * Checks if value is the language type of Object. (e.g. arrays, functions, objects, regexes, new Number(0), + * and new String('')) + * + * @param value The value to check. + * @return Returns true if value is an object, else false. + */ + isObject(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isObject + */ + isObject(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isObject + */ + isObject(): LoDashExplicitWrapper; + } + + //_.isObjectLike + interface LoDashStatic { + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + isObjectLike(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isObjectLike + */ + isObjectLike(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isObjectLike + */ + isObjectLike(): LoDashExplicitWrapper; + } + + //_.isPlainObject + interface LoDashStatic { + /** + * Checks if value is a plain object, that is, an object created by the Object constructor or one with a + * [[Prototype]] of null. + * + * Note: This method assumes objects created by the Object constructor have no inherited enumerable properties. + * + * @param value The value to check. + * @return Returns true if value is a plain object, else false. + */ + isPlainObject(value?: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isPlainObject + */ + isPlainObject(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isPlainObject + */ + isPlainObject(): LoDashExplicitWrapper; + } + + //_.isRegExp + interface LoDashStatic { + /** + * Checks if value is classified as a RegExp object. + * @param value The value to check. + * + * @return Returns true if value is correctly classified, else false. + */ + isRegExp(value?: any): value is RegExp; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isRegExp + */ + isRegExp(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isRegExp + */ + isRegExp(): LoDashExplicitWrapper; + } + + //_.isSafeInteger + interface LoDashStatic { + /** + * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754 + * double precision number which isn't the result of a rounded unsafe integer. + * + * **Note:** This method is based on [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`. + * @example + * + * _.isSafeInteger(3); + * // => true + * + * _.isSafeInteger(Number.MIN_VALUE); + * // => false + * + * _.isSafeInteger(Infinity); + * // => false + * + * _.isSafeInteger('3'); + * // => false + */ + isSafeInteger(value: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isSafeInteger + */ + isSafeInteger(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isSafeInteger + */ + isSafeInteger(): LoDashExplicitWrapper; + } + + //_.isString + interface LoDashStatic { + /** + * Checks if value is classified as a String primitive or object. + * + * @param value The value to check. + * @return Returns true if value is correctly classified, else false. + */ + isString(value?: any): value is string; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isString + */ + isString(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isString + */ + isString(): LoDashExplicitWrapper; + } + + //_.isSymbol + interface LoDashStatic { + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + isSymbol(value: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isSymbol + */ + isSymbol(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isSymbol + */ + isSymbol(): LoDashExplicitWrapper; + } + + //_.isTypedArray + interface LoDashStatic { + /** + * Checks if value is classified as a typed array. + * + * @param value The value to check. + * @return Returns true if value is correctly classified, else false. + */ + isTypedArray(value: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isTypedArray + */ + isTypedArray(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isTypedArray + */ + isTypedArray(): LoDashExplicitWrapper; + } + + //_.isUndefined + interface LoDashStatic { + /** + * Checks if value is undefined. + * + * @param value The value to check. + * @return Returns true if value is undefined, else false. + */ + isUndefined(value: any): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * see _.isUndefined + */ + isUndefined(): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * see _.isUndefined + */ + isUndefined(): LoDashExplicitWrapper; + } + + //_.lt + interface LoDashStatic { + /** + * Checks if value is less than other. + * + * @param value The value to compare. + * @param other The other value to compare. + * @return Returns true if value is less than other, else false. + */ + lt( + value: any, + other: any + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.lt + */ + lt(other: any): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.lt + */ + lt(other: any): LoDashExplicitWrapper; + } + + //_.lte + interface LoDashStatic { + /** + * Checks if value is less than or equal to other. + * + * @param value The value to compare. + * @param other The other value to compare. + * @return Returns true if value is less than or equal to other, else false. + */ + lte( + value: any, + other: any + ): boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.lte + */ + lte(other: any): boolean; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.lte + */ + lte(other: any): LoDashExplicitWrapper; + } + + //_.toArray + interface LoDashStatic { + /** + * Converts value to an array. + * + * @param value The value to convert. + * @return Returns the converted array. + */ + toArray(value: List|Dictionary|NumericDictionary): T[]; + + /** + * @see _.toArray + */ + toArray(value: TValue): TResult[]; + + /** + * @see _.toArray + */ + toArray(value?: any): TResult[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.toArray + */ + toArray(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.toArray + */ + toArray(): LoDashImplicitArrayWrapper; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.toArray + */ + toArray(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.toArray + */ + toArray(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.toArray + */ + toArray(): LoDashExplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.toArray + */ + toArray(): LoDashExplicitArrayWrapper; + } + + //_.toPlainObject + interface LoDashStatic { + /** + * Converts value to a plain object flattening inherited enumerable properties of value to own properties + * of the plain object. + * + * @param value The value to convert. + * @return Returns the converted plain object. + */ + toPlainObject(value?: any): TResult; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.toPlainObject + */ + toPlainObject(): LoDashImplicitObjectWrapper; + } + + //_.toInteger + interface LoDashStatic { + /** + * Converts `value` to an integer. + * + * **Note:** This function is loosely based on [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3'); + * // => 3 + */ + toInteger(value: any): number; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.toInteger + */ + toInteger(): LoDashImplicitWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.toInteger + */ + toInteger(): LoDashExplicitWrapper; + } + + //_.toLength + interface LoDashStatic { + /** + * Converts `value` to an integer suitable for use as the length of an + * array-like object. + * + * **Note:** This method is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength). + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @return {number} Returns the converted integer. + * @example + * + * _.toLength(3); + * // => 3 + * + * _.toLength(Number.MIN_VALUE); + * // => 0 + * + * _.toLength(Infinity); + * // => 4294967295 + * + * _.toLength('3'); + * // => 3 + */ + toLength(value: any): number; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.toLength + */ + toLength(): LoDashImplicitWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.toLength + */ + toLength(): LoDashExplicitWrapper; + } + + //_.toNumber + interface LoDashStatic { + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3); + * // => 3 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3'); + * // => 3 + */ + toNumber(value: any): number; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.toNumber + */ + toNumber(): LoDashImplicitWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.toNumber + */ + toNumber(): LoDashExplicitWrapper; + } + + //_.toSafeInteger + interface LoDashStatic { + /** + * Converts `value` to a safe integer. A safe integer can be compared and + * represented correctly. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toSafeInteger(3); + * // => 3 + * + * _.toSafeInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toSafeInteger(Infinity); + * // => 9007199254740991 + * + * _.toSafeInteger('3'); + * // => 3 + */ + toSafeInteger(value: any): number; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.toSafeInteger + */ + toSafeInteger(): LoDashImplicitWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.toSafeInteger + */ + toSafeInteger(): LoDashExplicitWrapper; + } + + //_.toString DUMMY + interface LoDashStatic { + /** + * Converts `value` to a string if it's not one. An empty string is returned + * for `null` and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @category Lang + * @param {*} value The value to process. + * @returns {string} Returns the string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + toString(value: any): string; + } + + /******** + * Math * + ********/ + + //_.add + interface LoDashStatic { + /** + * Adds two numbers. + * + * @param augend The first number to add. + * @param addend The second number to add. + * @return Returns the sum. + */ + add( + augend: number, + addend: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.add + */ + add(addend: number): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.add + */ + add(addend: number): LoDashExplicitWrapper; + } + + //_.ceil + interface LoDashStatic { + /** + * Calculates n rounded up to precision. + * + * @param n The number to round up. + * @param precision The precision to round up to. + * @return Returns the rounded up number. + */ + ceil( + n: number, + precision?: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.ceil + */ + ceil(precision?: number): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.ceil + */ + ceil(precision?: number): LoDashExplicitWrapper; + } + + //_.floor + interface LoDashStatic { + /** + * Calculates n rounded down to precision. + * + * @param n The number to round down. + * @param precision The precision to round down to. + * @return Returns the rounded down number. + */ + floor( + n: number, + precision?: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.floor + */ + floor(precision?: number): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.floor + */ + floor(precision?: number): LoDashExplicitWrapper; + } + + //_.max + interface LoDashStatic { + /** + * Computes the maximum value of `array`. If `array` is empty or falsey + * `undefined` is returned. + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @returns {*} Returns the maximum value. + */ + max( + collection: List + ): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.max + */ + max(): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.max + */ + max(): T; + } + + //_.maxBy + interface LoDashStatic { + /** + * This method is like `_.max` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * the value is ranked. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {*} Returns the maximum value. + * @example + * + * var objects = [{ 'n': 1 }, { 'n': 2 }]; + * + * _.maxBy(objects, function(o) { return o.a; }); + * // => { 'n': 2 } + * + * // using the `_.property` iteratee shorthand + * _.maxBy(objects, 'n'); + * // => { 'n': 2 } + */ + maxBy( + collection: List, + iteratee?: ListIterator + ): T; + + /** + * @see _.maxBy + */ + maxBy( + collection: Dictionary, + iteratee?: DictionaryIterator + ): T; + + /** + * @see _.maxBy + */ + maxBy( + collection: List|Dictionary, + iteratee?: string + ): T; + + /** + * @see _.maxBy + */ + maxBy( + collection: List|Dictionary, + whereValue?: TObject + ): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.maxBy + */ + maxBy( + iteratee?: ListIterator + ): T; + + /** + * @see _.maxBy + */ + maxBy( + iteratee?: string + ): T; + + /** + * @see _.maxBy + */ + maxBy( + whereValue?: TObject + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.maxBy + */ + maxBy( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): T; + + /** + * @see _.maxBy + */ + maxBy( + iteratee?: string, + thisArg?: any + ): T; + + /** + * @see _.maxBy + */ + maxBy( + whereValue?: TObject + ): T; + } + + //_.mean + interface LoDashStatic { + /** + * Computes the mean of the values in `array`. + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @returns {number} Returns the mean. + * @example + * + * _.mean([4, 2, 8, 6]); + * // => 5 + */ + mean( + collection: List + ): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.mean + */ + mean(): number; + + /** + * @see _.mean + */ + mean(): number; + } + + //_.min + interface LoDashStatic { + /** + * Computes the minimum value of `array`. If `array` is empty or falsey + * `undefined` is returned. + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @returns {*} Returns the minimum value. + */ + min( + collection: List + ): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.min + */ + min(): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.min + */ + min(): T; + } + + //_.minBy + interface LoDashStatic { + /** + * This method is like `_.min` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * the value is ranked. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {*} Returns the minimum value. + * @example + * + * var objects = [{ 'n': 1 }, { 'n': 2 }]; + * + * _.minBy(objects, function(o) { return o.a; }); + * // => { 'n': 1 } + * + * // using the `_.property` iteratee shorthand + * _.minBy(objects, 'n'); + * // => { 'n': 1 } + */ + minBy( + collection: List, + iteratee?: ListIterator + ): T; + + /** + * @see _.minBy + */ + minBy( + collection: Dictionary, + iteratee?: DictionaryIterator + ): T; + + /** + * @see _.minBy + */ + minBy( + collection: List|Dictionary, + iteratee?: string + ): T; + + /** + * @see _.minBy + */ + minBy( + collection: List|Dictionary, + whereValue?: TObject + ): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.minBy + */ + minBy( + iteratee?: ListIterator + ): T; + + /** + * @see _.minBy + */ + minBy( + iteratee?: string + ): T; + + /** + * @see _.minBy + */ + minBy( + whereValue?: TObject + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.minBy + */ + minBy( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): T; + + /** + * @see _.minBy + */ + minBy( + iteratee?: string, + thisArg?: any + ): T; + + /** + * @see _.minBy + */ + minBy( + whereValue?: TObject + ): T; + } + + //_.round + interface LoDashStatic { + /** + * Calculates n rounded to precision. + * + * @param n The number to round. + * @param precision The precision to round to. + * @return Returns the rounded number. + */ + round( + n: number, + precision?: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.round + */ + round(precision?: number): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.round + */ + round(precision?: number): LoDashExplicitWrapper; + } + + //_.sum + interface LoDashStatic { + /** + * Computes the sum of the values in `array`. + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @returns {number} Returns the sum. + * @example + * + * _.sum([4, 2, 8, 6]); + * // => 20 + */ + sum(collection: List): number; + + /** + * @see _.sum + */ + sum(collection: List|Dictionary): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sum + */ + sum(): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sum + **/ + sum(): number; + + /** + * @see _.sum + */ + sum(): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sum + */ + sum(): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sum + */ + sum(): LoDashExplicitWrapper; + + /** + * @see _.sum + */ + sum(): LoDashExplicitWrapper; + } + + //_.sumBy + interface LoDashStatic { + /** + * This method is like `_.sum` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the value to be summed. + * The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The iteratee invoked per element. + * @returns {number} Returns the sum. + * @example + * + * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }]; + * + * _.sumBy(objects, function(o) { return o.n; }); + * // => 20 + * + * // using the `_.property` iteratee shorthand + * _.sumBy(objects, 'n'); + * // => 20 + */ + sumBy( + collection: List, + iteratee: ListIterator + ): number; + + /** + * @see _.sumBy + **/ + sumBy( + collection: Dictionary, + iteratee: DictionaryIterator + ): number; + + /** + * @see _.sumBy + */ + sumBy( + collection: List|Dictionary, + iteratee: string + ): number; + + /** + * @see _.sumBy + */ + sumBy(collection: List|Dictionary): number; + + /** + * @see _.sumBy + */ + sumBy(collection: List|Dictionary): number; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.sumBy + */ + sumBy( + iteratee: ListIterator + ): number; + + /** + * @see _.sumBy + */ + sumBy(iteratee: string): number; + + /** + * @see _.sumBy + */ + sumBy(): number; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.sumBy + **/ + sumBy( + iteratee: ListIterator|DictionaryIterator + ): number; + + /** + * @see _.sumBy + */ + sumBy(iteratee: string): number; + + /** + * @see _.sumBy + */ + sumBy(): number; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.sumBy + */ + sumBy( + iteratee: ListIterator + ): LoDashExplicitWrapper; + + /** + * @see _.sumBy + */ + sumBy(iteratee: string): LoDashExplicitWrapper; + + /** + * @see _.sumBy + */ + sumBy(): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.sumBy + */ + sumBy( + iteratee: ListIterator|DictionaryIterator + ): LoDashExplicitWrapper; + + /** + * @see _.sumBy + */ + sumBy(iteratee: string): LoDashExplicitWrapper; + + /** + * @see _.sumBy + */ + sumBy(): LoDashExplicitWrapper; + } + + /********** + * Number * + **********/ + + //_.subtract + interface LoDashStatic { + /** + * Subtract two numbers. + * + * @static + * @memberOf _ + * @category Math + * @param {number} minuend The first number in a subtraction. + * @param {number} subtrahend The second number in a subtraction. + * @returns {number} Returns the difference. + * @example + * + * _.subtract(6, 4); + * // => 2 + */ + subtract( + minuend: number, + subtrahend: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.subtract + */ + subtract( + subtrahend: number + ): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.subtract + */ + subtract( + subtrahend: number + ): LoDashExplicitWrapper; + } + + //_.clamp + interface LoDashStatic { + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + clamp( + number: number, + lower: number, + upper: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.clamp + */ + clamp( + lower: number, + upper: number + ): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.clamp + */ + clamp( + lower: number, + upper: number + ): LoDashExplicitWrapper; + } + + //_.inRange + interface LoDashStatic { + /** + * Checks if n is between start and up to but not including, end. If end is not specified it’s set to start + * with start then set to 0. + * + * @param n The number to check. + * @param start The start of the range. + * @param end The end of the range. + * @return Returns true if n is in the range, else false. + */ + inRange( + n: number, + start: number, + end: number + ): boolean; + + + /** + * @see _.inRange + */ + inRange( + n: number, + end: number + ): boolean; + } + + interface LoDashImplicitWrapper { + /** + * @see _.inRange + */ + inRange( + start: number, + end: number + ): boolean; + + /** + * @see _.inRange + */ + inRange(end: number): boolean; + } + + interface LoDashExplicitWrapper { + /** + * @see _.inRange + */ + inRange( + start: number, + end: number + ): LoDashExplicitWrapper; + + /** + * @see _.inRange + */ + inRange(end: number): LoDashExplicitWrapper; + } + + //_.random + interface LoDashStatic { + /** + * Produces a random number between min and max (inclusive). If only one argument is provided a number between + * 0 and the given number is returned. If floating is true, or either min or max are floats, a floating-point + * number is returned instead of an integer. + * + * @param min The minimum possible value. + * @param max The maximum possible value. + * @param floating Specify returning a floating-point number. + * @return Returns the random number. + */ + random( + min?: number, + max?: number, + floating?: boolean + ): number; + + /** + * @see _.random + */ + random( + min?: number, + floating?: boolean + ): number; + + /** + * @see _.random + */ + random(floating?: boolean): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.random + */ + random( + max?: number, + floating?: boolean + ): number; + + /** + * @see _.random + */ + random(floating?: boolean): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.random + */ + random( + max?: number, + floating?: boolean + ): LoDashExplicitWrapper; + + /** + * @see _.random + */ + random(floating?: boolean): LoDashExplicitWrapper; + } + + /********** + * Object * + **********/ + + //_.assign + interface LoDashStatic { + /** + * Assigns own enumerable properties of source objects to the destination + * object. Source objects are applied from left to right. Subsequent sources + * overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object` and is loosely based on + * [`Object.assign`](https://mdn.io/Object/assign). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.c = 3; + * } + * + * function Bar() { + * this.e = 5; + * } + * + * Foo.prototype.d = 4; + * Bar.prototype.f = 6; + * + * _.assign({ 'a': 1 }, new Foo, new Bar); + * // => { 'a': 1, 'c': 3, 'e': 5 } + */ + assign( + object: TObject, + source: TSource + ): TResult; + + /** + * @see assign + */ + assign( + object: TObject, + source1: TSource1, + source2: TSource2 + ): TResult; + + /** + * @see assign + */ + assign( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): TResult; + + /** + * @see assign + */ + assign + ( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): TResult; + + /** + * @see _.assign + */ + assign(object: TObject): TObject; + + /** + * @see _.assign + */ + assign( + object: TObject, ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.assign + */ + assign( + source: TSource + ): LoDashImplicitObjectWrapper; + + /** + * @see assign + */ + assign( + source1: TSource1, + source2: TSource2 + ): LoDashImplicitObjectWrapper; + + /** + * @see assign + */ + assign( + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): LoDashImplicitObjectWrapper; + + /** + * @see assign + */ + assign( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): LoDashImplicitObjectWrapper; + + /** + * @see _.assign + */ + assign(): LoDashImplicitObjectWrapper; + + /** + * @see _.assign + */ + assign(...otherArgs: any[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.assign + */ + assign( + source: TSource + ): LoDashExplicitObjectWrapper; + + /** + * @see assign + */ + assign( + source1: TSource1, + source2: TSource2 + ): LoDashExplicitObjectWrapper; + + /** + * @see assign + */ + assign( + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): LoDashExplicitObjectWrapper; + + /** + * @see assign + */ + assign( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): LoDashExplicitObjectWrapper; + + /** + * @see _.assign + */ + assign(): LoDashExplicitObjectWrapper; + + /** + * @see _.assign + */ + assign(...otherArgs: any[]): LoDashExplicitObjectWrapper; + } + + //_.assignWith + interface AssignCustomizer { + (objectValue: any, sourceValue: any, key?: string, object?: {}, source?: {}): any; + } + + interface LoDashStatic { + /** + * This method is like `_.assign` except that it accepts `customizer` which + * is invoked to produce the assigned values. If `customizer` returns `undefined` + * assignment is handled by the method instead. The `customizer` is invoked + * with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + assignWith( + object: TObject, + source: TSource, + customizer: AssignCustomizer + ): TResult; + + /** + * @see assignWith + */ + assignWith( + object: TObject, + source1: TSource1, + source2: TSource2, + customizer: AssignCustomizer + ): TResult; + + /** + * @see assignWith + */ + assignWith( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: AssignCustomizer + ): TResult; + + /** + * @see assignWith + */ + assignWith + ( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: AssignCustomizer + ): TResult; + + /** + * @see _.assignWith + */ + assignWith(object: TObject): TObject; + + /** + * @see _.assignWith + */ + assignWith( + object: TObject, ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.assignWith + */ + assignWith( + source: TSource, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see assignWith + */ + assignWith( + source1: TSource1, + source2: TSource2, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see assignWith + */ + assignWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see assignWith + */ + assignWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.assignWith + */ + assignWith(): LoDashImplicitObjectWrapper; + + /** + * @see _.assignWith + */ + assignWith(...otherArgs: any[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.assignWith + */ + assignWith( + source: TSource, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see assignWith + */ + assignWith( + source1: TSource1, + source2: TSource2, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see assignWith + */ + assignWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see assignWith + */ + assignWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see _.assignWith + */ + assignWith(): LoDashExplicitObjectWrapper; + + /** + * @see _.assignWith + */ + assignWith(...otherArgs: any[]): LoDashExplicitObjectWrapper; + } + + //_.assignIn + interface LoDashStatic { + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * function Bar() { + * this.d = 4; + * } + * + * Foo.prototype.c = 3; + * Bar.prototype.e = 5; + * + * _.assignIn({ 'a': 1 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5 } + */ + assignIn( + object: TObject, + source: TSource + ): TResult; + + /** + * @see assignIn + */ + assignIn( + object: TObject, + source1: TSource1, + source2: TSource2 + ): TResult; + + /** + * @see assignIn + */ + assignIn( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): TResult; + + /** + * @see assignIn + */ + assignIn + ( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): TResult; + + /** + * @see _.assignIn + */ + assignIn(object: TObject): TObject; + + /** + * @see _.assignIn + */ + assignIn( + object: TObject, ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.assignIn + */ + assignIn( + source: TSource + ): LoDashImplicitObjectWrapper; + + /** + * @see assignIn + */ + assignIn( + source1: TSource1, + source2: TSource2 + ): LoDashImplicitObjectWrapper; + + /** + * @see assignIn + */ + assignIn( + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): LoDashImplicitObjectWrapper; + + /** + * @see assignIn + */ + assignIn( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): LoDashImplicitObjectWrapper; + + /** + * @see _.assignIn + */ + assignIn(): LoDashImplicitObjectWrapper; + + /** + * @see _.assignIn + */ + assignIn(...otherArgs: any[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.assignIn + */ + assignIn( + source: TSource + ): LoDashExplicitObjectWrapper; + + /** + * @see assignIn + */ + assignIn( + source1: TSource1, + source2: TSource2 + ): LoDashExplicitObjectWrapper; + + /** + * @see assignIn + */ + assignIn( + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): LoDashExplicitObjectWrapper; + + /** + * @see assignIn + */ + assignIn( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): LoDashExplicitObjectWrapper; + + /** + * @see _.assignIn + */ + assignIn(): LoDashExplicitObjectWrapper; + + /** + * @see _.assignIn + */ + assignIn(...otherArgs: any[]): LoDashExplicitObjectWrapper; + } + + //_.assignInWith + interface AssignCustomizer { + (objectValue: any, sourceValue: any, key?: string, object?: {}, source?: {}): any; + } + + interface LoDashStatic { + /** + * This method is like `_.assignIn` except that it accepts `customizer` which + * is invoked to produce the assigned values. If `customizer` returns `undefined` + * assignment is handled by the method instead. The `customizer` is invoked + * with five arguments: (objValue, srcValue, key, object, source). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @alias extendWith + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} [customizer] The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * return _.isUndefined(objValue) ? srcValue : objValue; + * } + * + * var defaults = _.partialRight(_.assignInWith, customizer); + * + * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + assignInWith( + object: TObject, + source: TSource, + customizer: AssignCustomizer + ): TResult; + + /** + * @see assignInWith + */ + assignInWith( + object: TObject, + source1: TSource1, + source2: TSource2, + customizer: AssignCustomizer + ): TResult; + + /** + * @see assignInWith + */ + assignInWith( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: AssignCustomizer + ): TResult; + + /** + * @see assignInWith + */ + assignInWith + ( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: AssignCustomizer + ): TResult; + + /** + * @see _.assignInWith + */ + assignInWith(object: TObject): TObject; + + /** + * @see _.assignInWith + */ + assignInWith( + object: TObject, ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.assignInWith + */ + assignInWith( + source: TSource, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see assignInWith + */ + assignInWith( + source1: TSource1, + source2: TSource2, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see assignInWith + */ + assignInWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see assignInWith + */ + assignInWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: AssignCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.assignInWith + */ + assignInWith(): LoDashImplicitObjectWrapper; + + /** + * @see _.assignInWith + */ + assignInWith(...otherArgs: any[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.assignInWith + */ + assignInWith( + source: TSource, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see assignInWith + */ + assignInWith( + source1: TSource1, + source2: TSource2, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see assignInWith + */ + assignInWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see assignInWith + */ + assignInWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: AssignCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see _.assignInWith + */ + assignInWith(): LoDashExplicitObjectWrapper; + + /** + * @see _.assignInWith + */ + assignInWith(...otherArgs: any[]): LoDashExplicitObjectWrapper; + } + + //_.create + interface LoDashStatic { + /** + * Creates an object that inherits from the given prototype object. If a properties object is provided its own + * enumerable properties are assigned to the created object. + * + * @param prototype The object to inherit from. + * @param properties The properties to assign to the object. + * @return Returns the new object. + */ + create( + prototype: T, + properties?: U + ): T & U; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.create + */ + create(properties?: U): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.create + */ + create(properties?: U): LoDashExplicitObjectWrapper; + } + + //_.defaults + interface LoDashStatic { + /** + * Assigns own enumerable properties of source object(s) to the destination object for all destination + * properties that resolve to undefined. Once a property is set, additional values of the same property are + * ignored. + * + * Note: This method mutates object. + * + * @param object The destination object. + * @param sources The source objects. + * @return The destination object. + */ + defaults( + object: Obj, + ...sources: {}[] + ): TResult; + + /** + * @see _.defaults + */ + defaults( + object: Obj, + source1: S1, + ...sources: {}[] + ): TResult; + + /** + * @see _.defaults + */ + defaults( + object: Obj, + source1: S1, + source2: S2, + ...sources: {}[] + ): TResult; + + /** + * @see _.defaults + */ + defaults( + object: Obj, + source1: S1, + source2: S2, + source3: S3, + ...sources: {}[] + ): TResult; + + /** + * @see _.defaults + */ + defaults( + object: Obj, + source1: S1, + source2: S2, + source3: S3, + source4: S4, + ...sources: {}[] + ): TResult; + + /** + * @see _.defaults + */ + defaults( + object: {}, + ...sources: {}[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.defaults + */ + defaults( + source1: S1, + ...sources: {}[] + ): LoDashImplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults( + source1: S1, + source2: S2, + ...sources: {}[] + ): LoDashImplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults( + source1: S1, + source2: S2, + source3: S3, + ...sources: {}[] + ): LoDashImplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults( + source1: S1, + source2: S2, + source3: S3, + source4: S4, + ...sources: {}[] + ): LoDashImplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults(): LoDashImplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults(...sources: {}[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.defaults + */ + defaults( + source1: S1, + ...sources: {}[] + ): LoDashExplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults( + source1: S1, + source2: S2, + ...sources: {}[] + ): LoDashExplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults( + source1: S1, + source2: S2, + source3: S3, + ...sources: {}[] + ): LoDashExplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults( + source1: S1, + source2: S2, + source3: S3, + source4: S4, + ...sources: {}[] + ): LoDashExplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults(): LoDashExplicitObjectWrapper; + + /** + * @see _.defaults + */ + defaults(...sources: {}[]): LoDashExplicitObjectWrapper; + } + + //_.defaultsDeep + interface LoDashStatic { + /** + * This method is like _.defaults except that it recursively assigns default properties. + * @param object The destination object. + * @param sources The source objects. + * @return Returns object. + **/ + defaultsDeep( + object: T, + ...sources: any[]): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.defaultsDeep + **/ + defaultsDeep(...sources: any[]): LoDashImplicitObjectWrapper + } + + //_.extend + interface LoDashStatic { + /** + * @see assign + */ + extend( + object: TObject, + source: TSource, + customizer?: AssignCustomizer, + thisArg?: any + ): TResult; + + /** + * @see assign + */ + extend( + object: TObject, + source1: TSource1, + source2: TSource2, + customizer?: AssignCustomizer, + thisArg?: any + ): TResult; + + /** + * @see assign + */ + extend( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer?: AssignCustomizer, + thisArg?: any + ): TResult; + + /** + * @see assign + */ + extend + ( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer?: AssignCustomizer, + thisArg?: any + ): TResult; + + /** + * @see _.assign + */ + extend(object: TObject): TObject; + + /** + * @see _.assign + */ + extend( + object: TObject, ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.assign + */ + extend( + source: TSource, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashImplicitObjectWrapper; + + /** + * @see assign + */ + extend( + source1: TSource1, + source2: TSource2, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashImplicitObjectWrapper; + + /** + * @see assign + */ + extend( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashImplicitObjectWrapper; + + /** + * @see assign + */ + extend( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashImplicitObjectWrapper; + + /** + * @see _.assign + */ + extend(): LoDashImplicitObjectWrapper; + + /** + * @see _.assign + */ + extend(...otherArgs: any[]): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.assign + */ + extend( + source: TSource, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashExplicitObjectWrapper; + + /** + * @see assign + */ + extend( + source1: TSource1, + source2: TSource2, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashExplicitObjectWrapper; + + /** + * @see assign + */ + extend( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashExplicitObjectWrapper; + + /** + * @see assign + */ + extend( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer?: AssignCustomizer, + thisArg?: any + ): LoDashExplicitObjectWrapper; + + /** + * @see _.assign + */ + extend(): LoDashExplicitObjectWrapper; + + /** + * @see _.assign + */ + extend(...otherArgs: any[]): LoDashExplicitObjectWrapper; + } + + //_.findKey + interface LoDashStatic { + /** + * This method is like _.find except that it returns the key of the first element predicate returns truthy for + * instead of the element itself. + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param object The object to search. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the key of the matched element, else undefined. + */ + findKey( + object: TObject, + predicate?: DictionaryIterator, + thisArg?: any + ): string; + + /** + * @see _.findKey + */ + findKey( + object: TObject, + predicate?: ObjectIterator, + thisArg?: any + ): string; + + /** + * @see _.findKey + */ + findKey( + object: TObject, + predicate?: string, + thisArg?: any + ): string; + + /** + * @see _.findKey + */ + findKey, TObject>( + object: TObject, + predicate?: TWhere + ): string; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.findKey + */ + findKey( + predicate?: DictionaryIterator, + thisArg?: any + ): string; + + /** + * @see _.findKey + */ + findKey( + predicate?: ObjectIterator, + thisArg?: any + ): string; + + /** + * @see _.findKey + */ + findKey( + predicate?: string, + thisArg?: any + ): string; + + /** + * @see _.findKey + */ + findKey>( + predicate?: TWhere + ): string; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.findKey + */ + findKey( + predicate?: DictionaryIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findKey + */ + findKey( + predicate?: ObjectIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findKey + */ + findKey( + predicate?: string, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findKey + */ + findKey>( + predicate?: TWhere + ): LoDashExplicitWrapper; + } + + //_.findLastKey + interface LoDashStatic { + /** + * This method is like _.findKey except that it iterates over elements of a collection in the opposite order. + * + * If a property name is provided for predicate the created _.property style callback returns the property + * value of the given element. + * + * If a value is also provided for thisArg the created _.matchesProperty style callback returns true for + * elements that have a matching property value, else false. + * + * If an object is provided for predicate the created _.matches style callback returns true for elements that + * have the properties of the given object, else false. + * + * @param object The object to search. + * @param predicate The function invoked per iteration. + * @param thisArg The this binding of predicate. + * @return Returns the key of the matched element, else undefined. + */ + findLastKey( + object: TObject, + predicate?: DictionaryIterator, + thisArg?: any + ): string; + + /** + * @see _.findLastKey + */ + findLastKey( + object: TObject, + predicate?: ObjectIterator, + thisArg?: any + ): string; + + /** + * @see _.findLastKey + */ + findLastKey( + object: TObject, + predicate?: string, + thisArg?: any + ): string; + + /** + * @see _.findLastKey + */ + findLastKey, TObject>( + object: TObject, + predicate?: TWhere + ): string; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.findLastKey + */ + findLastKey( + predicate?: DictionaryIterator, + thisArg?: any + ): string; + + /** + * @see _.findLastKey + */ + findLastKey( + predicate?: ObjectIterator, + thisArg?: any + ): string; + + /** + * @see _.findLastKey + */ + findLastKey( + predicate?: string, + thisArg?: any + ): string; + + /** + * @see _.findLastKey + */ + findLastKey>( + predicate?: TWhere + ): string; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.findLastKey + */ + findLastKey( + predicate?: DictionaryIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastKey + */ + findLastKey( + predicate?: ObjectIterator, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastKey + */ + findLastKey( + predicate?: string, + thisArg?: any + ): LoDashExplicitWrapper; + + /** + * @see _.findLastKey + */ + findLastKey>( + predicate?: TWhere + ): LoDashExplicitWrapper; + } + + //_.forIn + interface LoDashStatic { + /** + * Iterates over own and inherited enumerable properties of an object invoking iteratee for each property. The + * iteratee is bound to thisArg and invoked with three arguments: (value, key, object). Iteratee functions may + * exit iteration early by explicitly returning false. + * + * @param object The object to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns object. + */ + forIn( + object: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forIn + */ + forIn( + object: T, + iteratee?: ObjectIterator, + thisArg?: any + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forIn + */ + forIn( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forIn + */ + forIn( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashExplicitObjectWrapper; + } + + //_.forInRight + interface LoDashStatic { + /** + * This method is like _.forIn except that it iterates over properties of object in the opposite order. + * + * @param object The object to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns object. + */ + forInRight( + object: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forInRight + */ + forInRight( + object: T, + iteratee?: ObjectIterator, + thisArg?: any + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forInRight + */ + forInRight( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forInRight + */ + forInRight( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashExplicitObjectWrapper; + } + + //_.forOwn + interface LoDashStatic { + /** + * Iterates over own enumerable properties of an object invoking iteratee for each property. The iteratee is + * bound to thisArg and invoked with three arguments: (value, key, object). Iteratee functions may exit + * iteration early by explicitly returning false. + * + * @param object The object to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns object. + */ + forOwn( + object: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forOwn + */ + forOwn( + object: T, + iteratee?: ObjectIterator, + thisArg?: any + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forOwn + */ + forOwn( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forOwn + */ + forOwn( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashExplicitObjectWrapper; + } + + //_.forOwnRight + interface LoDashStatic { + /** + * This method is like _.forOwn except that it iterates over properties of object in the opposite order. + * + * @param object The object to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns object. + */ + forOwnRight( + object: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.forOwnRight + */ + forOwnRight( + object: T, + iteratee?: ObjectIterator, + thisArg?: any + ): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.forOwnRight + */ + forOwnRight( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.forOwnRight + */ + forOwnRight( + iteratee?: DictionaryIterator, + thisArg?: any + ): _.LoDashExplicitObjectWrapper; + } + + //_.functions + interface LoDashStatic { + /** + * Creates an array of function property names from own enumerable properties + * of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of property names. + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functions(new Foo); + * // => ['a', 'b'] + */ + functions(object: any): string[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.functions + */ + functions(): _.LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.functions + */ + functions(): _.LoDashExplicitArrayWrapper; + } + + //_.functionsIn + interface LoDashStatic { + /** + * Creates an array of function property names from own and inherited + * enumerable properties of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to inspect. + * @returns {Array} Returns the new array of property names. + * @example + * + * function Foo() { + * this.a = _.constant('a'); + * this.b = _.constant('b'); + * } + * + * Foo.prototype.c = _.constant('c'); + * + * _.functionsIn(new Foo); + * // => ['a', 'b', 'c'] + */ + functionsIn(object: any): string[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.functionsIn + */ + functionsIn(): _.LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.functionsIn + */ + functionsIn(): _.LoDashExplicitArrayWrapper; + } + + //_.get + interface LoDashStatic { + /** + * Gets the property value at path of object. If the resolved + * value is undefined the defaultValue is used in its place. + * @param object The object to query. + * @param path The path of the property to get. + * @param defaultValue The value returned if the resolved value is undefined. + * @return Returns the resolved value. + **/ + get(object: Object, + path: string|number|boolean|Array, + defaultValue?:TResult + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.get + **/ + get(path: string|number|boolean|Array, + defaultValue?: TResult + ): TResult; + } + + //_.has + interface LoDashStatic { + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': { 'c': 3 } } }; + * var other = _.create({ 'a': _.create({ 'b': _.create({ 'c': 3 }) }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b.c'); + * // => true + * + * _.has(object, ['a', 'b', 'c']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + has( + object: T, + path: StringRepresentable|StringRepresentable[] + ): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.has + */ + has(path: StringRepresentable|StringRepresentable[]): boolean; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.has + */ + has(path: StringRepresentable|StringRepresentable[]): LoDashExplicitWrapper; + } + + //_.hasIn + interface LoDashStatic { + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': _.create({ 'c': 3 }) }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b.c'); + * // => true + * + * _.hasIn(object, ['a', 'b', 'c']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + hasIn( + object: T, + path: StringRepresentable|StringRepresentable[] + ): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.hasIn + */ + hasIn(path: StringRepresentable|StringRepresentable[]): boolean; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.hasIn + */ + hasIn(path: StringRepresentable|StringRepresentable[]): LoDashExplicitWrapper; + } + + //_.invert + interface LoDashStatic { + /** + * Creates an object composed of the inverted keys and values of object. If object contains duplicate values, + * subsequent values overwrite property assignments of previous values unless multiValue is true. + * + * @param object The object to invert. + * @param multiValue Allow multiple values per key. + * @return Returns the new inverted object. + */ + invert( + object: T, + multiValue?: boolean + ): TResult; + + /** + * @see _.invert + */ + invert( + object: Object, + multiValue?: boolean + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.invert + */ + invert(multiValue?: boolean): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.invert + */ + invert(multiValue?: boolean): LoDashExplicitObjectWrapper; + } + + //_.keys + interface LoDashStatic { + /** + * Creates an array of the own enumerable property names of object. + * + * Note: Non-object values are coerced to objects. See the ES spec for more details. + * + * @param object The object to query. + * @return Returns the array of property names. + */ + keys(object?: any): string[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.keys + */ + keys(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.keys + */ + keys(): LoDashExplicitArrayWrapper; + } + + //_.keysIn + interface LoDashStatic { + /** + * Creates an array of the own and inherited enumerable property names of object. + * + * Note: Non-object values are coerced to objects. + * + * @param object The object to query. + * @return An array of property names. + */ + keysIn(object?: any): string[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.keysIn + */ + keysIn(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.keysIn + */ + keysIn(): LoDashExplicitArrayWrapper; + } + + //_.mapKeys + interface LoDashStatic { + /** + * The opposite of _.mapValues; this method creates an object with the same values as object and keys generated + * by running each own enumerable property of object through iteratee. + * + * @param object The object to iterate over. + * @param iteratee The function invoked per iteration. + * @param thisArg The this binding of iteratee. + * @return Returns the new mapped object. + */ + mapKeys( + object: List, + iteratee?: ListIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.mapKeys + */ + mapKeys( + object: Dictionary, + iteratee?: DictionaryIterator, + thisArg?: any + ): Dictionary; + + /** + * @see _.mapKeys + */ + mapKeys( + object: List|Dictionary, + iteratee?: TObject + ): Dictionary; + + /** + * @see _.mapKeys + */ + mapKeys( + object: List|Dictionary, + iteratee?: string, + thisArg?: any + ): Dictionary; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: ListIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: TObject + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: TObject + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: string, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: ListIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: TObject + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: ListIterator|DictionaryIterator, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: TObject + ): LoDashExplicitObjectWrapper>; + + /** + * @see _.mapKeys + */ + mapKeys( + iteratee?: string, + thisArg?: any + ): LoDashExplicitObjectWrapper>; + } + + //_.mapValues + interface LoDashStatic { + /** + * Creates an object with the same keys as object and values generated by running each own + * enumerable property of object through iteratee. The iteratee function is bound to thisArg + * and invoked with three arguments: (value, key, object). + * + * If a property name is provided iteratee the created "_.property" style callback returns + * the property value of the given element. + * + * If a value is also provided for thisArg the creted "_.matchesProperty" style callback returns + * true for elements that have a matching property value, else false;. + * + * If an object is provided for iteratee the created "_.matches" style callback returns true + * for elements that have the properties of the given object, else false. + * + * @param {Object} object The object to iterate over. + * @param {Function|Object|string} [iteratee=_.identity] The function invoked per iteration. + * @param {Object} [thisArg] The `this` binding of `iteratee`. + * @return {Object} Returns the new mapped object. + */ + mapValues(obj: Dictionary, callback: ObjectIterator, thisArg?: any): Dictionary; + mapValues(obj: Dictionary, where: Dictionary): Dictionary; + mapValues(obj: T, pluck: string): TMapped; + mapValues(obj: T, callback: ObjectIterator, thisArg?: any): T; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.mapValues + * TValue is the type of the property values of T. + * TResult is the type output by the ObjectIterator function + */ + mapValues(callback: ObjectIterator, thisArg?: any): LoDashImplicitObjectWrapper>; + + /** + * @see _.mapValues + * TResult is the type of the property specified by pluck. + * T should be a Dictionary> + */ + mapValues(pluck: string): LoDashImplicitObjectWrapper>; + + /** + * @see _.mapValues + * TResult is the type of the properties on the object specified by pluck. + * T should be a Dictionary>> + */ + mapValues(pluck: string, where: Dictionary): LoDashImplicitArrayWrapper>; + + /** + * @see _.mapValues + * TResult is the type of the properties of each object in the values of T + * T should be a Dictionary> + */ + mapValues(where: Dictionary): LoDashImplicitArrayWrapper; + } + + //_.merge + interface LoDashStatic { + /** + * Recursively merges own and inherited enumerable properties of source + * objects into the destination object, skipping source properties that resolve + * to `undefined`. Array and plain object properties are merged recursively. + * Other objects and value types are overridden by assignment. Source objects + * are applied from left to right. Subsequent sources overwrite property + * assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var users = { + * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] + * }; + * + * var ages = { + * 'data': [{ 'age': 36 }, { 'age': 40 }] + * }; + * + * _.merge(users, ages); + * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } + */ + merge( + object: TObject, + source: TSource + ): TObject & TSource; + + /** + * @see _.merge + */ + merge( + object: TObject, + source1: TSource1, + source2: TSource2 + ): TObject & TSource1 & TSource2; + + /** + * @see _.merge + */ + merge( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): TObject & TSource1 & TSource2 & TSource3; + + /** + * @see _.merge + */ + merge( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): TObject & TSource1 & TSource2 & TSource3 & TSource4; + + /** + * @see _.merge + */ + merge( + object: any, + ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.merge + */ + merge( + source: TSource + ): LoDashImplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + source1: TSource1, + source2: TSource2 + ): LoDashImplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): LoDashImplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4 + ): LoDashImplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + ...otherArgs: any[] + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.merge + */ + merge( + source: TSource + ): LoDashExplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + source1: TSource1, + source2: TSource2 + ): LoDashExplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + source1: TSource1, + source2: TSource2, + source3: TSource3 + ): LoDashExplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + ): LoDashExplicitObjectWrapper; + + /** + * @see _.merge + */ + merge( + ...otherArgs: any[] + ): LoDashExplicitObjectWrapper; + } + + //_.mergeWith + interface MergeWithCustomizer { + (value: any, srcValue: any, key?: string, object?: Object, source?: Object): any; + } + + interface LoDashStatic { + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined` merging is handled by the + * method instead. The `customizer` is invoked with seven arguments: + * (objValue, srcValue, key, object, source, stack). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { + * 'fruits': ['apple'], + * 'vegetables': ['beet'] + * }; + * + * var other = { + * 'fruits': ['banana'], + * 'vegetables': ['carrot'] + * }; + * + * _.merge(object, other, customizer); + * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } + */ + mergeWith( + object: TObject, + source: TSource, + customizer: MergeWithCustomizer + ): TObject & TSource; + + /** + * @see _.mergeWith + */ + mergeWith( + object: TObject, + source1: TSource1, + source2: TSource2, + customizer: MergeWithCustomizer + ): TObject & TSource1 & TSource2; + + /** + * @see _.mergeWith + */ + mergeWith( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: MergeWithCustomizer + ): TObject & TSource1 & TSource2 & TSource3; + + /** + * @see _.mergeWith + */ + mergeWith( + object: TObject, + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: MergeWithCustomizer + ): TObject & TSource1 & TSource2 & TSource3 & TSource4; + + /** + * @see _.mergeWith + */ + mergeWith( + object: any, + ...otherArgs: any[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.mergeWith + */ + mergeWith( + source: TSource, + customizer: MergeWithCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.mergeWith + */ + mergeWith( + source1: TSource1, + source2: TSource2, + customizer: MergeWithCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.mergeWith + */ + mergeWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + customizer: MergeWithCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.mergeWith + */ + mergeWith( + source1: TSource1, + source2: TSource2, + source3: TSource3, + source4: TSource4, + customizer: MergeWithCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.mergeWith + */ + mergeWith( + ...otherArgs: any[] + ): LoDashImplicitObjectWrapper; + } + + //_.omit + interface LoDashStatic { + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that are not omitted. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [props] The property names to omit, specified + * individually or in arrays.. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + + omit( + object: T, + ...predicate: (StringRepresentable|StringRepresentable[])[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + + /** + * @see _.omit + */ + omit( + ...predicate: (StringRepresentable|StringRepresentable[])[] + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + + /** + * @see _.omit + */ + omit( + ...predicate: (StringRepresentable|StringRepresentable[])[] + ): LoDashExplicitObjectWrapper; + } + + //_.omitBy + interface LoDashStatic { + /** + * The opposite of `_.pickBy`; this method creates an object composed of the + * own and inherited enumerable properties of `object` that `predicate` + * doesn't return truthy for. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + omitBy( + object: T, + predicate: ObjectIterator + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.omitBy + */ + omitBy( + predicate: ObjectIterator + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.omitBy + */ + omitBy( + predicate: ObjectIterator + ): LoDashExplicitObjectWrapper; + } + + //_.pick + interface LoDashStatic { + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [props] The property names to pick, specified + * individually or in arrays. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + pick( + object: T, + ...predicate: (StringRepresentable|StringRepresentable[])[] + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.pick + */ + pick( + ...predicate: (StringRepresentable|StringRepresentable[])[] + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.pick + */ + pick( + ...predicate: (StringRepresentable|StringRepresentable[])[] + ): LoDashExplicitObjectWrapper; + } + + //_.pickBy + interface LoDashStatic { + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {Function|Object|string} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + pickBy( + object: T, + predicate: ObjectIterator + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.pickBy + */ + pickBy( + predicate: ObjectIterator + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.pickBy + */ + pickBy( + predicate: ObjectIterator + ): LoDashExplicitObjectWrapper; + } + + //_.result + interface LoDashStatic { + /** + * This method is like _.get except that if the resolved value is a function it’s invoked with the this binding + * of its parent object and its result is returned. + * + * @param object The object to query. + * @param path The path of the property to resolve. + * @param defaultValue The value returned if the resolved value is undefined. + * @return Returns the resolved value. + */ + result( + object: TObject, + path: number|string|boolean|Array, + defaultValue?: TResult + ): TResult; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.result + */ + result( + path: number|string|boolean|Array, + defaultValue?: TResult + ): TResult; + } + + //_.set + interface LoDashStatic { + /** + * Sets the value at path of object. If a portion of path doesn’t exist it’s created. Arrays are created for + * missing index properties while objects are created for all other missing properties. Use _.setWith to + * customize path creation. + * + * @param object The object to modify. + * @param path The path of the property to set. + * @param value The value to set. + * @return Returns object. + */ + set( + object: Object, + path: StringRepresentable|StringRepresentable[], + value: any + ): TResult; + + /** + * @see _.set + */ + set( + object: Object, + path: StringRepresentable|StringRepresentable[], + value: V + ): TResult; + + /** + * @see _.set + */ + set( + object: O, + path: StringRepresentable|StringRepresentable[], + value: V + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.set + */ + set( + path: StringRepresentable|StringRepresentable[], + value: any + ): LoDashImplicitObjectWrapper; + + /** + * @see _.set + */ + set( + path: StringRepresentable|StringRepresentable[], + value: V + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.set + */ + set( + path: StringRepresentable|StringRepresentable[], + value: any + ): LoDashExplicitObjectWrapper; + + /** + * @see _.set + */ + set( + path: StringRepresentable|StringRepresentable[], + value: V + ): LoDashExplicitObjectWrapper; + } + + //_.setWith + interface SetWithCustomizer { + (nsValue: any, key: string, nsObject: T): any; + } + + interface LoDashStatic { + /** + * This method is like _.set except that it accepts customizer which is invoked to produce the objects of + * path. If customizer returns undefined path creation is handled by the method instead. The customizer is + * invoked with three arguments: (nsValue, key, nsObject). + * + * @param object The object to modify. + * @param path The path of the property to set. + * @param value The value to set. + * @parem customizer The function to customize assigned values. + * @return Returns object. + */ + setWith( + object: Object, + path: StringRepresentable|StringRepresentable[], + value: any, + customizer?: SetWithCustomizer + ): TResult; + + /** + * @see _.setWith + */ + setWith( + object: Object, + path: StringRepresentable|StringRepresentable[], + value: V, + customizer?: SetWithCustomizer + ): TResult; + + /** + * @see _.setWith + */ + setWith( + object: O, + path: StringRepresentable|StringRepresentable[], + value: V, + customizer?: SetWithCustomizer + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.setWith + */ + setWith( + path: StringRepresentable|StringRepresentable[], + value: any, + customizer?: SetWithCustomizer + ): LoDashImplicitObjectWrapper; + + /** + * @see _.setWith + */ + setWith( + path: StringRepresentable|StringRepresentable[], + value: V, + customizer?: SetWithCustomizer + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.setWith + */ + setWith( + path: StringRepresentable|StringRepresentable[], + value: any, + customizer?: SetWithCustomizer + ): LoDashExplicitObjectWrapper; + + /** + * @see _.setWith + */ + setWith( + path: StringRepresentable|StringRepresentable[], + value: V, + customizer?: SetWithCustomizer + ): LoDashExplicitObjectWrapper; + } + + //_.toPairs + interface LoDashStatic { + /** + * Creates an array of own enumerable key-value pairs for object. + * + * @param object The object to query. + * @return Returns the new array of key-value pairs. + */ + toPairs(object?: T): any[][]; + + toPairs(object?: T): TResult[][]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.toPairs + */ + toPairs(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.toPairs + */ + toPairs(): LoDashExplicitArrayWrapper; + } + + //_.toPairsIn + interface LoDashStatic { + /** + * Creates an array of own and inherited enumerable key-value pairs for object. + * + * @param object The object to query. + * @return Returns the new array of key-value pairs. + */ + toPairsIn(object?: T): any[][]; + + toPairsIn(object?: T): TResult[][]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.toPairsIn + */ + toPairsIn(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.toPairsIn + */ + toPairsIn(): LoDashExplicitArrayWrapper; + } + + //_.transform + interface LoDashStatic { + /** + * An alternative to _.reduce; this method transforms object to a new accumulator object which is the result of + * running each of its own enumerable properties through iteratee, with each invocation potentially mutating + * the accumulator object. The iteratee is bound to thisArg and invoked with four arguments: (accumulator, + * value, key, object). Iteratee functions may exit iteration early by explicitly returning false. + * + * @param object The object to iterate over. + * @param iteratee The function invoked per iteration. + * @param accumulator The custom accumulator value. + * @param thisArg The this binding of iteratee. + * @return Returns the accumulated value. + */ + transform( + object: T[], + iteratee?: MemoVoidArrayIterator, + accumulator?: TResult[], + thisArg?: any + ): TResult[]; + + /** + * @see _.transform + */ + transform( + object: T[], + iteratee?: MemoVoidArrayIterator>, + accumulator?: Dictionary, + thisArg?: any + ): Dictionary; + + /** + * @see _.transform + */ + transform( + object: Dictionary, + iteratee?: MemoVoidDictionaryIterator>, + accumulator?: Dictionary, + thisArg?: any + ): Dictionary; + + /** + * @see _.transform + */ + transform( + object: Dictionary, + iteratee?: MemoVoidDictionaryIterator, + accumulator?: TResult[], + thisArg?: any + ): TResult[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.transform + */ + transform( + iteratee?: MemoVoidArrayIterator, + accumulator?: TResult[], + thisArg?: any + ): LoDashImplicitArrayWrapper; + + /** + * @see _.transform + */ + transform( + iteratee?: MemoVoidArrayIterator>, + accumulator?: Dictionary, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.transform + */ + transform( + iteratee?: MemoVoidDictionaryIterator>, + accumulator?: Dictionary, + thisArg?: any + ): LoDashImplicitObjectWrapper>; + + /** + * @see _.transform + */ + transform( + iteratee?: MemoVoidDictionaryIterator, + accumulator?: TResult[], + thisArg?: any + ): LoDashImplicitArrayWrapper; + } + + //_.unset + interface LoDashStatic { + /** + * Removes the property at path of object. + * + * Note: This method mutates object. + * + * @param object The object to modify. + * @param path The path of the property to unset. + * @return Returns true if the property is deleted, else false. + */ + unset( + object: T, + path: StringRepresentable|StringRepresentable[] + ): boolean; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.unset + */ + unset(path: StringRepresentable|StringRepresentable[]): LoDashImplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.unset + */ + unset(path: StringRepresentable|StringRepresentable[]): LoDashExplicitWrapper; + } + + //_.values + interface LoDashStatic { + /** + * Creates an array of the own enumerable property values of object. + * + * @param object The object to query. + * @return Returns an array of property values. + */ + values(object?: any): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.values + */ + values(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.values + */ + values(): LoDashExplicitArrayWrapper; + } + + //_.valuesIn + interface LoDashStatic { + /** + * Creates an array of the own and inherited enumerable property values of object. + * + * @param object The object to query. + * @return Returns the array of property values. + */ + valuesIn(object?: any): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.valuesIn + */ + valuesIn(): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.valuesIn + */ + valuesIn(): LoDashExplicitArrayWrapper; + } + + /********** + * String * + **********/ + + //_.camelCase + interface LoDashStatic { + /** + * Converts string to camel case. + * + * @param string The string to convert. + * @return Returns the camel cased string. + */ + camelCase(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.camelCase + */ + camelCase(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.camelCase + */ + camelCase(): LoDashExplicitWrapper; + } + + //_.capitalize + interface LoDashStatic { + /** + * Converts the first character of string to upper case and the remaining to lower case. + * + * @param string The string to capitalize. + * @return Returns the capitalized string. + */ + capitalize(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.capitalize + */ + capitalize(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.capitalize + */ + capitalize(): LoDashExplicitWrapper; + } + + //_.deburr + interface LoDashStatic { + /** + * Deburrs string by converting latin-1 supplementary letters to basic latin letters and removing combining + * diacritical marks. + * + * @param string The string to deburr. + * @return Returns the deburred string. + */ + deburr(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.deburr + */ + deburr(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.deburr + */ + deburr(): LoDashExplicitWrapper; + } + + //_.endsWith + interface LoDashStatic { + /** + * Checks if string ends with the given target string. + * + * @param string The string to search. + * @param target The string to search for. + * @param position The position to search from. + * @return Returns true if string ends with target, else false. + */ + endsWith( + string?: string, + target?: string, + position?: number + ): boolean; + } + + interface LoDashImplicitWrapper { + /** + * @see _.endsWith + */ + endsWith( + target?: string, + position?: number + ): boolean; + } + + interface LoDashExplicitWrapper { + /** + * @see _.endsWith + */ + endsWith( + target?: string, + position?: number + ): LoDashExplicitWrapper; + } + + // _.escape + interface LoDashStatic { + /** + * Converts the characters "&", "<", ">", '"', "'", and "`" in string to their corresponding HTML entities. + * + * Note: No other characters are escaped. To escape additional characters use a third-party library like he. + * + * hough the ">" character is escaped for symmetry, characters like ">" and "/" don’t need escaping in HTML + * and have no special meaning unless they're part of a tag or unquoted attribute value. See Mathias Bynens’s + * article (under "semi-related fun fact") for more details. + * + * Backticks are escaped because in IE < 9, they can break out of attribute values or HTML comments. See #59, + * #102, #108, and #133 of the HTML5 Security Cheatsheet for more details. + * + * When working with HTML you should always quote attribute values to reduce XSS vectors. + * + * @param string The string to escape. + * @return Returns the escaped string. + */ + escape(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.escape + */ + escape(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.escape + */ + escape(): LoDashExplicitWrapper; + } + + // _.escapeRegExp + interface LoDashStatic { + /** + * Escapes the RegExp special characters "^", "$", "\", ".", "*", "+", "?", "(", ")", "[", "]", + * "{", "}", and "|" in string. + * + * @param string The string to escape. + * @return Returns the escaped string. + */ + escapeRegExp(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.escapeRegExp + */ + escapeRegExp(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.escapeRegExp + */ + escapeRegExp(): LoDashExplicitWrapper; + } + + //_.kebabCase + interface LoDashStatic { + /** + * Converts string to kebab case. + * + * @param string The string to convert. + * @return Returns the kebab cased string. + */ + kebabCase(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.kebabCase + */ + kebabCase(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.kebabCase + */ + kebabCase(): LoDashExplicitWrapper; + } + + //_.lowerCase + interface LoDashStatic { + /** + * Converts `string`, as space separated words, to lower case. + * + * @param string The string to convert. + * @return Returns the lower cased string. + */ + lowerCase(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.lowerCase + */ + lowerCase(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.lowerCase + */ + lowerCase(): LoDashExplicitWrapper; + } + + //_.lowerFirst + interface LoDashStatic { + /** + * Converts the first character of `string` to lower case. + * + * @param string The string to convert. + * @return Returns the converted string. + */ + lowerFirst(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.lowerFirst + */ + lowerFirst(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.lowerFirst + */ + lowerFirst(): LoDashExplicitWrapper; + } + + //_.pad + interface LoDashStatic { + /** + * Pads string on the left and right sides if it’s shorter than length. Padding characters are truncated if + * they can’t be evenly divided by length. + * + * @param string The string to pad. + * @param length The padding length. + * @param chars The string used as padding. + * @return Returns the padded string. + */ + pad( + string?: string, + length?: number, + chars?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.pad + */ + pad( + length?: number, + chars?: string + ): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.pad + */ + pad( + length?: number, + chars?: string + ): LoDashExplicitWrapper; + } + + //_.padEnd + interface LoDashStatic { + /** + * Pads string on the right side if it’s shorter than length. Padding characters are truncated if they exceed + * length. + * + * @param string The string to pad. + * @param length The padding length. + * @param chars The string used as padding. + * @return Returns the padded string. + */ + padEnd( + string?: string, + length?: number, + chars?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.padEnd + */ + padEnd( + length?: number, + chars?: string + ): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.padEnd + */ + padEnd( + length?: number, + chars?: string + ): LoDashExplicitWrapper; + } + + //_.padStart + interface LoDashStatic { + /** + * Pads string on the left side if it’s shorter than length. Padding characters are truncated if they exceed + * length. + * + * @param string The string to pad. + * @param length The padding length. + * @param chars The string used as padding. + * @return Returns the padded string. + */ + padStart( + string?: string, + length?: number, + chars?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.padStart + */ + padStart( + length?: number, + chars?: string + ): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.padStart + */ + padStart( + length?: number, + chars?: string + ): LoDashExplicitWrapper; + } + + //_.parseInt + interface LoDashStatic { + /** + * Converts string to an integer of the specified radix. If radix is undefined or 0, a radix of 10 is used + * unless value is a hexadecimal, in which case a radix of 16 is used. + * + * Note: This method aligns with the ES5 implementation of parseInt. + * + * @param string The string to convert. + * @param radix The radix to interpret value by. + * @return Returns the converted integer. + */ + parseInt( + string: string, + radix?: number + ): number; + } + + interface LoDashImplicitWrapper { + /** + * @see _.parseInt + */ + parseInt(radix?: number): number; + } + + interface LoDashExplicitWrapper { + /** + * @see _.parseInt + */ + parseInt(radix?: number): LoDashExplicitWrapper; + } + + //_.repeat + interface LoDashStatic { + /** + * Repeats the given string n times. + * + * @param string The string to repeat. + * @param n The number of times to repeat the string. + * @return Returns the repeated string. + */ + repeat( + string?: string, + n?: number + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.repeat + */ + repeat(n?: number): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.repeat + */ + repeat(n?: number): LoDashExplicitWrapper; + } + + //_.replace + interface LoDashStatic { + /** + * Replaces matches for pattern in string with replacement. + * + * Note: This method is based on String#replace. + * + * @param string + * @param pattern + * @param replacement + * @return Returns the modified string. + */ + replace( + string: string, + pattern: RegExp|string, + replacement: Function|string + ): string; + + /** + * @see _.replace + */ + replace( + pattern?: RegExp|string, + replacement?: Function|string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.replace + */ + replace( + pattern?: RegExp|string, + replacement?: Function|string + ): string; + + /** + * @see _.replace + */ + replace( + replacement?: Function|string + ): string; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.replace + */ + replace( + pattern?: RegExp|string, + replacement?: Function|string + ): string; + + /** + * @see _.replace + */ + replace( + replacement?: Function|string + ): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.replace + */ + replace( + pattern?: RegExp|string, + replacement?: Function|string + ): LoDashExplicitWrapper; + + /** + * @see _.replace + */ + replace( + replacement?: Function|string + ): LoDashExplicitWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.replace + */ + replace( + pattern?: RegExp|string, + replacement?: Function|string + ): LoDashExplicitWrapper; + + /** + * @see _.replace + */ + replace( + replacement?: Function|string + ): LoDashExplicitWrapper; + } + + //_.snakeCase + interface LoDashStatic { + /** + * Converts string to snake case. + * + * @param string The string to convert. + * @return Returns the snake cased string. + */ + snakeCase(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.snakeCase + */ + snakeCase(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.snakeCase + */ + snakeCase(): LoDashExplicitWrapper; + } + + //_.split + interface LoDashStatic { + /** + * Splits string by separator. + * + * Note: This method is based on String#split. + * + * @param string + * @param separator + * @param limit + * @return Returns the new array of string segments. + */ + split( + string: string, + separator?: RegExp|string, + limit?: number + ): string[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.split + */ + split( + separator?: RegExp|string, + limit?: number + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.split + */ + split( + separator?: RegExp|string, + limit?: number + ): LoDashExplicitArrayWrapper; + } + + //_.startCase + interface LoDashStatic { + /** + * Converts string to start case. + * + * @param string The string to convert. + * @return Returns the start cased string. + */ + startCase(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.startCase + */ + startCase(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.startCase + */ + startCase(): LoDashExplicitWrapper; + } + + //_.startsWith + interface LoDashStatic { + /** + * Checks if string starts with the given target string. + * + * @param string The string to search. + * @param target The string to search for. + * @param position The position to search from. + * @return Returns true if string starts with target, else false. + */ + startsWith( + string?: string, + target?: string, + position?: number + ): boolean; + } + + interface LoDashImplicitWrapper { + /** + * @see _.startsWith + */ + startsWith( + target?: string, + position?: number + ): boolean; + } + + interface LoDashExplicitWrapper { + /** + * @see _.startsWith + */ + startsWith( + target?: string, + position?: number + ): LoDashExplicitWrapper; + } + + //_.template + interface TemplateOptions extends TemplateSettings { + /** + * The sourceURL of the template's compiled source. + */ + sourceURL?: string; + } + + interface TemplateExecutor { + (data?: Object): string; + source: string; + } + + interface LoDashStatic { + /** + * Creates a compiled template function that can interpolate data properties in "interpolate" delimiters, + * HTML-escape interpolated data properties in "escape" delimiters, and execute JavaScript in "evaluate" + * delimiters. Data properties may be accessed as free variables in the template. If a setting object is + * provided it takes precedence over _.templateSettings values. + * + * Note: In the development build _.template utilizes + * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier + * debugging. + * + * For more information on precompiling templates see + * [lodash's custom builds documentation](https://lodash.com/custom-builds). + * + * For more information on Chrome extension sandboxes see + * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval). + * + * @param string The template string. + * @param options The options object. + * @param options.escape The HTML "escape" delimiter. + * @param options.evaluate The "evaluate" delimiter. + * @param options.imports An object to import into the template as free variables. + * @param options.interpolate The "interpolate" delimiter. + * @param options.sourceURL The sourceURL of the template's compiled source. + * @param options.variable The data object variable name. + * @return Returns the compiled template function. + */ + template( + string: string, + options?: TemplateOptions + ): TemplateExecutor; + } + + interface LoDashImplicitWrapper { + /** + * @see _.template + */ + template(options?: TemplateOptions): TemplateExecutor; + } + + interface LoDashExplicitWrapper { + /** + * @see _.template + */ + template(options?: TemplateOptions): LoDashExplicitObjectWrapper; + } + + //_.toLower + interface LoDashStatic { + /** + * Converts `string`, as a whole, to lower case. + * + * @param string The string to convert. + * @return Returns the lower cased string. + */ + toLower(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.toLower + */ + toLower(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.toLower + */ + toLower(): LoDashExplicitWrapper; + } + + //_.toUpper + interface LoDashStatic { + /** + * Converts `string`, as a whole, to upper case. + * + * @param string The string to convert. + * @return Returns the upper cased string. + */ + toUpper(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.toUpper + */ + toUpper(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.toUpper + */ + toUpper(): LoDashExplicitWrapper; + } + + //_.trim + interface LoDashStatic { + /** + * Removes leading and trailing whitespace or specified characters from string. + * + * @param string The string to trim. + * @param chars The characters to trim. + * @return Returns the trimmed string. + */ + trim( + string?: string, + chars?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.trim + */ + trim(chars?: string): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.trim + */ + trim(chars?: string): LoDashExplicitWrapper; + } + + //_.trimEnd + interface LoDashStatic { + /** + * Removes trailing whitespace or specified characters from string. + * + * @param string The string to trim. + * @param chars The characters to trim. + * @return Returns the trimmed string. + */ + trimEnd( + string?: string, + chars?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.trimEnd + */ + trimEnd(chars?: string): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.trimEnd + */ + trimEnd(chars?: string): LoDashExplicitWrapper; + } + + //_.trimStart + interface LoDashStatic { + /** + * Removes leading whitespace or specified characters from string. + * + * @param string The string to trim. + * @param chars The characters to trim. + * @return Returns the trimmed string. + */ + trimStart( + string?: string, + chars?: string + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.trimStart + */ + trimStart(chars?: string): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.trimStart + */ + trimStart(chars?: string): LoDashExplicitWrapper; + } + + //_.truncate + interface TruncateOptions { + /** The maximum string length. */ + length?: number; + /** The string to indicate text is omitted. */ + omission?: string; + /** The separator pattern to truncate to. */ + separator?: string|RegExp; + } + + interface LoDashStatic { + /** + * Truncates string if it’s longer than the given maximum string length. The last characters of the truncated + * string are replaced with the omission string which defaults to "…". + * + * @param string The string to truncate. + * @param options The options object or maximum string length. + * @return Returns the truncated string. + */ + truncate( + string?: string, + options?: TruncateOptions + ): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.truncate + */ + truncate(options?: TruncateOptions): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.truncate + */ + truncate(options?: TruncateOptions): LoDashExplicitWrapper; + } + + //_.unescape + interface LoDashStatic { + /** + * The inverse of _.escape; this method converts the HTML entities &, <, >, ", ', and ` + * in string to their corresponding characters. + * + * Note: No other HTML entities are unescaped. To unescape additional HTML entities use a third-party library + * like he. + * + * @param string The string to unescape. + * @return Returns the unescaped string. + */ + unescape(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.unescape + */ + unescape(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.unescape + */ + unescape(): LoDashExplicitWrapper; + } + + //_.upperCase + interface LoDashStatic { + /** + * Converts `string`, as space separated words, to upper case. + * + * @param string The string to convert. + * @return Returns the upper cased string. + */ + upperCase(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.upperCase + */ + upperCase(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.upperCase + */ + upperCase(): LoDashExplicitWrapper; + } + + //_.upperFirst + interface LoDashStatic { + /** + * Converts the first character of `string` to upper case. + * + * @param string The string to convert. + * @return Returns the converted string. + */ + upperFirst(string?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.upperFirst + */ + upperFirst(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.upperFirst + */ + upperFirst(): LoDashExplicitWrapper; + } + + //_.words + interface LoDashStatic { + /** + * Splits `string` into an array of its words. + * + * @param string The string to inspect. + * @param pattern The pattern to match words. + * @return Returns the words of `string`. + */ + words( + string?: string, + pattern?: string|RegExp + ): string[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.words + */ + words(pattern?: string|RegExp): string[]; + } + + interface LoDashExplicitWrapper { + /** + * @see _.words + */ + words(pattern?: string|RegExp): LoDashExplicitArrayWrapper; + } + + /*********** + * Utility * + ***********/ + + //_.attempt + interface LoDashStatic { + /** + * Attempts to invoke func, returning either the result or the caught error object. Any additional arguments + * are provided to func when it’s invoked. + * + * @param func The function to attempt. + * @return Returns the func result or error object. + */ + attempt(func: (...args: any[]) => TResult, ...args: any[]): TResult|Error; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.attempt + */ + attempt(...args: any[]): TResult|Error; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.attempt + */ + attempt(...args: any[]): LoDashExplicitObjectWrapper; + } + + //_.constant + interface LoDashStatic { + /** + * Creates a function that returns value. + * + * @param value The value to return from the new function. + * @return Returns the new function. + */ + constant(value: T): () => T; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.constant + */ + constant(): LoDashImplicitObjectWrapper<() => TResult>; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.constant + */ + constant(): LoDashExplicitObjectWrapper<() => TResult>; + } + + //_.identity + interface LoDashStatic { + /** + * This method returns the first argument provided to it. + * @param value Any value. + * @return Returns value. + */ + identity(value?: T): T; + } + + interface LoDashImplicitWrapper { + /** + * @see _.identity + */ + identity(): T; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.identity + */ + identity(): T[]; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.identity + */ + identity(): T; + } + + //_.iteratee + interface LoDashStatic { + /** + * Creates a function that invokes `func` with the arguments of the created + * function. If `func` is a property name the created callback returns the + * property value for a given element. If `func` is an object the created + * callback returns `true` for elements that contain the equivalent object properties, otherwise it returns `false`. + * + * @static + * @memberOf _ + * @category Util + * @param {*} [func=_.identity] The value to convert to a callback. + * @returns {Function} Returns the callback. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // create custom iteratee shorthands + * _.iteratee = _.wrap(_.iteratee, function(callback, func) { + * var p = /^(\S+)\s*([<>])\s*(\S+)$/.exec(func); + * return !p ? callback(func) : function(object) { + * return (p[2] == '>' ? object[p[1]] > p[3] : object[p[1]] < p[3]); + * }; + * }); + * + * _.filter(users, 'age > 36'); + * // => [{ 'user': 'fred', 'age': 40 }] + */ + iteratee( + func: Function, + thisArg?: any + ): (...args: any[]) => TResult; + + /** + * @see _.iteratee + */ + iteratee( + func: string, + thisArg?: any + ): (object: any) => TResult; + + /** + * @see _.iteratee + */ + iteratee( + func: Object, + thisArg?: any + ): (object: any) => boolean; + + /** + * @see _.iteratee + */ + iteratee(): (value: TResult) => TResult; + } + + interface LoDashImplicitWrapper { + /** + * @see _.iteratee + */ + iteratee(thisArg?: any): LoDashImplicitObjectWrapper<(object: any) => TResult>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.iteratee + */ + iteratee(thisArg?: any): LoDashImplicitObjectWrapper<(object: any) => boolean>; + + /** + * @see _.iteratee + */ + iteratee(thisArg?: any): LoDashImplicitObjectWrapper<(...args: any[]) => TResult>; + } + + interface LoDashExplicitWrapper { + /** + * @see _.iteratee + */ + iteratee(thisArg?: any): LoDashExplicitObjectWrapper<(object: any) => TResult>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.iteratee + */ + iteratee(thisArg?: any): LoDashExplicitObjectWrapper<(object: any) => boolean>; + + /** + * @see _.iteratee + */ + iteratee(thisArg?: any): LoDashExplicitObjectWrapper<(...args: any[]) => TResult>; + } + + //_.matches + interface LoDashStatic { + /** + * Creates a function that performs a deep comparison between a given object and source, returning true if the + * given object has equivalent property values, else false. + * + * Note: This method supports comparing arrays, booleans, Date objects, numbers, Object objects, regexes, and + * strings. Objects are compared by their own, not inherited, enumerable properties. For comparing a single own + * or inherited property value see _.matchesProperty. + * + * @param source The object of property values to match. + * @return Returns the new function. + */ + matches(source: T): (value: any) => boolean; + + /** + * @see _.matches + */ + matches(source: T): (value: V) => boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.matches + */ + matches(): LoDashImplicitObjectWrapper<(value: V) => boolean>; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.matches + */ + matches(): LoDashExplicitObjectWrapper<(value: V) => boolean>; + } + + //_.matchesProperty + interface LoDashStatic { + /** + * Creates a function that compares the property value of path on a given object to value. + * + * Note: This method supports comparing arrays, booleans, Date objects, numbers, Object objects, regexes, and + * strings. Objects are compared by their own, not inherited, enumerable properties. + * + * @param path The path of the property to get. + * @param srcValue The value to match. + * @return Returns the new function. + */ + matchesProperty( + path: StringRepresentable|StringRepresentable[], + srcValue: T + ): (value: any) => boolean; + + /** + * @see _.matchesProperty + */ + matchesProperty( + path: StringRepresentable|StringRepresentable[], + srcValue: T + ): (value: V) => boolean; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.matchesProperty + */ + matchesProperty( + srcValue: SrcValue + ): LoDashImplicitObjectWrapper<(value: any) => boolean>; + + /** + * @see _.matchesProperty + */ + matchesProperty( + srcValue: SrcValue + ): LoDashImplicitObjectWrapper<(value: Value) => boolean>; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.matchesProperty + */ + matchesProperty( + srcValue: SrcValue + ): LoDashExplicitObjectWrapper<(value: any) => boolean>; + + /** + * @see _.matchesProperty + */ + matchesProperty( + srcValue: SrcValue + ): LoDashExplicitObjectWrapper<(value: Value) => boolean>; + } + + //_.method + interface LoDashStatic { + /** + * Creates a function that invokes the method at path on a given object. Any additional arguments are provided + * to the invoked method. + * + * @param path The path of the method to invoke. + * @param args The arguments to invoke the method with. + * @return Returns the new function. + */ + method( + path: string|StringRepresentable[], + ...args: any[] + ): (object: TObject) => TResult; + + /** + * @see _.method + */ + method( + path: string|StringRepresentable[], + ...args: any[] + ): (object: any) => TResult; + } + + interface LoDashImplicitWrapper { + /** + * @see _.method + */ + method(...args: any[]): LoDashImplicitObjectWrapper<(object: TObject) => TResult>; + + /** + * @see _.method + */ + method(...args: any[]): LoDashImplicitObjectWrapper<(object: any) => TResult>; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.method + */ + method(...args: any[]): LoDashImplicitObjectWrapper<(object: TObject) => TResult>; + + /** + * @see _.method + */ + method(...args: any[]): LoDashImplicitObjectWrapper<(object: any) => TResult>; + } + + interface LoDashExplicitWrapper { + /** + * @see _.method + */ + method(...args: any[]): LoDashExplicitObjectWrapper<(object: TObject) => TResult>; + + /** + * @see _.method + */ + method(...args: any[]): LoDashExplicitObjectWrapper<(object: any) => TResult>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.method + */ + method(...args: any[]): LoDashExplicitObjectWrapper<(object: TObject) => TResult>; + + /** + * @see _.method + */ + method(...args: any[]): LoDashExplicitObjectWrapper<(object: any) => TResult>; + } + + //_.methodOf + interface LoDashStatic { + /** + * The opposite of _.method; this method creates a function that invokes the method at a given path on object. + * Any additional arguments are provided to the invoked method. + * + * @param object The object to query. + * @param args The arguments to invoke the method with. + * @return Returns the new function. + */ + methodOf( + object: TObject, + ...args: any[] + ): (path: StringRepresentable|StringRepresentable[]) => TResult; + + /** + * @see _.methodOf + */ + methodOf( + object: {}, + ...args: any[] + ): (path: StringRepresentable|StringRepresentable[]) => TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.methodOf + */ + methodOf( + ...args: any[] + ): LoDashImplicitObjectWrapper<(path: StringRepresentable|StringRepresentable[]) => TResult>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.methodOf + */ + methodOf( + ...args: any[] + ): LoDashExplicitObjectWrapper<(path: StringRepresentable|StringRepresentable[]) => TResult>; + } + + //_.mixin + interface MixinOptions { + chain?: boolean; + } + + interface LoDashStatic { + /** + * Adds all own enumerable function properties of a source object to the destination object. If object is a + * function then methods are added to its prototype as well. + * + * Note: Use _.runInContext to create a pristine lodash function to avoid conflicts caused by modifying + * the original. + * + * @param object The destination object. + * @param source The object of functions to add. + * @param options The options object. + * @param options.chain Specify whether the functions added are chainable. + * @return Returns object. + */ + mixin( + object: TObject, + source: Dictionary, + options?: MixinOptions + ): TResult; + + /** + * @see _.mixin + */ + mixin( + source: Dictionary, + options?: MixinOptions + ): TResult; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.mixin + */ + mixin( + source: Dictionary, + options?: MixinOptions + ): LoDashImplicitObjectWrapper; + + /** + * @see _.mixin + */ + mixin( + options?: MixinOptions + ): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.mixin + */ + mixin( + source: Dictionary, + options?: MixinOptions + ): LoDashExplicitObjectWrapper; + + /** + * @see _.mixin + */ + mixin( + options?: MixinOptions + ): LoDashExplicitObjectWrapper; + } + + //_.noConflict + interface LoDashStatic { + /** + * Reverts the _ variable to its previous value and returns a reference to the lodash function. + * + * @return Returns the lodash function. + */ + noConflict(): typeof _; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.noConflict + */ + noConflict(): typeof _; + } + + //_.noop + interface LoDashStatic { + /** + * A no-operation function that returns undefined regardless of the arguments it receives. + * + * @return undefined + */ + noop(...args: any[]): void; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.noop + */ + noop(...args: any[]): void; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.noop + */ + noop(...args: any[]): _.LoDashExplicitWrapper; + } + + //_.nthArg + interface LoDashStatic { + /** + * Creates a function that returns its nth argument. + * + * @param n The index of the argument to return. + * @return Returns the new function. + */ + nthArg(n?: number): TResult; + } + + interface LoDashImplicitWrapper { + /** + * @see _.nthArg + */ + nthArg(): LoDashImplicitObjectWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.nthArg + */ + nthArg(): LoDashExplicitObjectWrapper; + } + + //_.over + interface LoDashStatic { + /** + * Creates a function that invokes iteratees with the arguments provided to the created function and returns + * their results. + * + * @param iteratees The iteratees to invoke. + * @return Returns the new function. + */ + over(...iteratees: (Function|Function[])[]): (...args: any[]) => TResult[]; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.over + */ + over(...iteratees: (Function|Function[])[]): LoDashImplicitObjectWrapper<(...args: any[]) => TResult[]>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.over + */ + over(...iteratees: (Function|Function[])[]): LoDashImplicitObjectWrapper<(...args: any[]) => TResult[]>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.over + */ + over(...iteratees: (Function|Function[])[]): LoDashExplicitObjectWrapper<(...args: any[]) => TResult[]>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.over + */ + over(...iteratees: (Function|Function[])[]): LoDashExplicitObjectWrapper<(...args: any[]) => TResult[]>; + } + + //_.overEvery + interface LoDashStatic { + /** + * Creates a function that checks if all of the predicates return truthy when invoked with the arguments + * provided to the created function. + * + * @param predicates The predicates to check. + * @return Returns the new function. + */ + overEvery(...predicates: (Function|Function[])[]): (...args: any[]) => boolean; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.overEvery + */ + overEvery(...predicates: (Function|Function[])[]): LoDashImplicitObjectWrapper<(...args: any[]) => boolean>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.overEvery + */ + overEvery(...predicates: (Function|Function[])[]): LoDashImplicitObjectWrapper<(...args: any[]) => boolean>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.overEvery + */ + overEvery(...predicates: (Function|Function[])[]): LoDashExplicitObjectWrapper<(...args: any[]) => boolean>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.overEvery + */ + overEvery(...predicates: (Function|Function[])[]): LoDashExplicitObjectWrapper<(...args: any[]) => boolean>; + } + + //_.overSome + interface LoDashStatic { + /** + * Creates a function that checks if any of the predicates return truthy when invoked with the arguments + * provided to the created function. + * + * @param predicates The predicates to check. + * @return Returns the new function. + */ + overSome(...predicates: (Function|Function[])[]): (...args: any[]) => boolean; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.overSome + */ + overSome(...predicates: (Function|Function[])[]): LoDashImplicitObjectWrapper<(...args: any[]) => boolean>; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.overSome + */ + overSome(...predicates: (Function|Function[])[]): LoDashImplicitObjectWrapper<(...args: any[]) => boolean>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.overSome + */ + overSome(...predicates: (Function|Function[])[]): LoDashExplicitObjectWrapper<(...args: any[]) => boolean>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.overSome + */ + overSome(...predicates: (Function|Function[])[]): LoDashExplicitObjectWrapper<(...args: any[]) => boolean>; + } + + //_.property + interface LoDashStatic { + /** + * Creates a function that returns the property value at path on a given object. + * + * @param path The path of the property to get. + * @return Returns the new function. + */ + property(path: StringRepresentable|StringRepresentable[]): (obj: TObj) => TResult; + } + + interface LoDashImplicitWrapper { + /** + * @see _.property + */ + property(): LoDashImplicitObjectWrapper<(obj: TObj) => TResult>; + } + + interface LoDashImplicitArrayWrapper { + /** + * @see _.property + */ + property(): LoDashImplicitObjectWrapper<(obj: TObj) => TResult>; + } + + interface LoDashExplicitWrapper { + /** + * @see _.property + */ + property(): LoDashExplicitObjectWrapper<(obj: TObj) => TResult>; + } + + interface LoDashExplicitArrayWrapper { + /** + * @see _.property + */ + property(): LoDashExplicitObjectWrapper<(obj: TObj) => TResult>; + } + + //_.propertyOf + interface LoDashStatic { + /** + * The opposite of _.property; this method creates a function that returns the property value at a given path + * on object. + * + * @param object The object to query. + * @return Returns the new function. + */ + propertyOf(object: T): (path: string|string[]) => any; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.propertyOf + */ + propertyOf(): LoDashImplicitObjectWrapper<(path: string|string[]) => any>; + } + + interface LoDashExplicitObjectWrapper { + /** + * @see _.propertyOf + */ + propertyOf(): LoDashExplicitObjectWrapper<(path: string|string[]) => any>; + } + + //_.range + interface LoDashStatic { + /** + * Creates an array of numbers (positive and/or negative) progressing from start up to, but not including, end. + * If end is not specified it’s set to start with start then set to 0. If end is less than start a zero-length + * range is created unless a negative step is specified. + * + * @param start The start of the range. + * @param end The end of the range. + * @param step The value to increment or decrement by. + * @return Returns a new range array. + */ + range( + start: number, + end: number, + step?: number + ): number[]; + + /** + * @see _.range + */ + range( + end: number, + step?: number + ): number[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.range + */ + range( + end?: number, + step?: number + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.range + */ + range( + end?: number, + step?: number + ): LoDashExplicitArrayWrapper; + } + + //_.rangeRight + interface LoDashStatic { + /** + * This method is like `_.range` except that it populates values in + * descending order. + * + * @static + * @memberOf _ + * @category Util + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @param {number} [step=1] The value to increment or decrement by. + * @returns {Array} Returns the new array of numbers. + * @example + * + * _.rangeRight(4); + * // => [3, 2, 1, 0] + * + * _.rangeRight(-4); + * // => [-3, -2, -1, 0] + * + * _.rangeRight(1, 5); + * // => [4, 3, 2, 1] + * + * _.rangeRight(0, 20, 5); + * // => [15, 10, 5, 0] + * + * _.rangeRight(0, -4, -1); + * // => [-3, -2, -1, 0] + * + * _.rangeRight(1, 4, 0); + * // => [1, 1, 1] + * + * _.rangeRight(0); + * // => [] + */ + rangeRight( + start: number, + end: number, + step?: number + ): number[]; + + /** + * @see _.rangeRight + */ + rangeRight( + end: number, + step?: number + ): number[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.rangeRight + */ + rangeRight( + end?: number, + step?: number + ): LoDashImplicitArrayWrapper; + } + + interface LoDashExplicitWrapper { + /** + * @see _.rangeRight + */ + rangeRight( + end?: number, + step?: number + ): LoDashExplicitArrayWrapper; + } + + //_.runInContext + interface LoDashStatic { + /** + * Create a new pristine lodash function using the given context object. + * + * @param context The context object. + * @return Returns a new lodash function. + */ + runInContext(context?: Object): typeof _; + } + + interface LoDashImplicitObjectWrapper { + /** + * @see _.runInContext + */ + runInContext(): typeof _; + } + + //_.times + interface LoDashStatic { + /** + * Invokes the iteratee function n times, returning an array of the results of each invocation. The iteratee + * is invoked with one argument; (index). + * + * @param n The number of times to invoke iteratee. + * @param iteratee The function invoked per iteration. + * @return Returns the array of results. + */ + times( + n: number, + iteratee: (num: number) => TResult + ): TResult[]; + + /** + * @see _.times + */ + times(n: number): number[]; + } + + interface LoDashImplicitWrapper { + /** + * @see _.times + */ + times( + iteratee: (num: number) => TResult + ): TResult[]; + + /** + * @see _.times + */ + times(): number[]; + } + + interface LoDashExplicitWrapper { + /** + * @see _.times + */ + times( + iteratee: (num: number) => TResult + ): LoDashExplicitArrayWrapper; + + /** + * @see _.times + */ + times(): LoDashExplicitArrayWrapper; + } + + //_.toPath + interface LoDashStatic { + /** + * Converts `value` to a property path array. + * + * @static + * @memberOf _ + * @category Util + * @param {*} value The value to convert. + * @returns {Array} Returns the new property path array. + * @example + * + * _.toPath('a.b.c'); + * // => ['a', 'b', 'c'] + * + * _.toPath('a[0].b.c'); + * // => ['a', '0', 'b', 'c'] + * + * var path = ['a', 'b', 'c'], + * newPath = _.toPath(path); + * + * console.log(newPath); + * // => ['a', 'b', 'c'] + * + * console.log(path === newPath); + * // => false + */ + toPath(value: any): string[]; + } + + interface LoDashImplicitWrapperBase { + /** + * @see _.toPath + */ + toPath(): LoDashImplicitWrapper; + } + + interface LoDashExplicitWrapperBase { + /** + * @see _.toPath + */ + toPath(): LoDashExplicitWrapper; + } + + //_.uniqueId + interface LoDashStatic { + /** + * Generates a unique ID. If prefix is provided the ID is appended to it. + * + * @param prefix The value to prefix the ID with. + * @return Returns the unique ID. + */ + uniqueId(prefix?: string): string; + } + + interface LoDashImplicitWrapper { + /** + * @see _.uniqueId + */ + uniqueId(): string; + } + + interface LoDashExplicitWrapper { + /** + * @see _.uniqueId + */ + uniqueId(): LoDashExplicitWrapper; + } + + interface ListIterator { + (value: T, index: number, collection: List): TResult; + } + + interface DictionaryIterator { + (value: T, key?: string, collection?: Dictionary): TResult; + } + + interface NumericDictionaryIterator { + (value: T, key?: number, collection?: Dictionary): TResult; + } + + interface ObjectIterator { + (element: T, key?: string, collection?: any): TResult; + } + + interface StringIterator { + (char: string, index?: number, string?: string): TResult; + } + + interface MemoVoidIterator { + (prev: TResult, curr: T, indexOrKey?: any, list?: T[]): void; + } + interface MemoIterator { + (prev: TResult, curr: T, indexOrKey?: any, list?: T[]): TResult; + } + + interface MemoVoidArrayIterator { + (acc: TResult, curr: T, index?: number, arr?: T[]): void; + } + interface MemoVoidDictionaryIterator { + (acc: TResult, curr: T, key?: string, dict?: Dictionary): void; + } + + //interface Collection {} + + // Common interface between Arrays and jQuery objects + interface List { + [index: number]: T; + length: number; + } + + interface Dictionary { + [index: string]: T; + } + + interface NumericDictionary { + [index: number]: T; + } + + interface StringRepresentable { + toString(): string; + } + + interface Cancelable { + cancel(): void; + } +} + +declare module "lodash" { + export = _; +} \ No newline at end of file From e4ff1fcaed19143c5607e48141ccd6a84c227310 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Mon, 15 Feb 2016 19:56:52 -0800 Subject: [PATCH 2/8] test(helper): migrate test into typescript compatible - migrate helper to typescript, primitive port focus on build pass without regression --- package.json | 4 +- spec/helpers/ajax-helper.js | 120 ------------------ spec/helpers/ajax-helper.ts | 221 +++++++++++++++++++++++++++++++++ spec/helpers/marble-testing.js | 47 ------- spec/helpers/marble-testing.ts | 48 +++++++ spec/helpers/test-helper.js | 157 ----------------------- spec/helpers/test-helper.ts | 148 ++++++++++++++++++++++ 7 files changed, 420 insertions(+), 325 deletions(-) delete mode 100644 spec/helpers/ajax-helper.js create mode 100644 spec/helpers/ajax-helper.ts delete mode 100644 spec/helpers/marble-testing.js create mode 100644 spec/helpers/marble-testing.ts delete mode 100644 spec/helpers/test-helper.js create mode 100644 spec/helpers/test-helper.ts diff --git a/package.json b/package.json index cd25907caa..85d015679c 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,9 @@ "copy_src": "cp -r src/ dist/cjs/src && cp -r src/ dist/amd/src && cp -r src/ dist/es6/src", "cover": "istanbul cover -x \"*-spec.js index.js *-helper.js spec/helpers/*\" ./node_modules/jasmine/bin/jasmine.js && npm run cover_remapping", "cover_remapping": "remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped.json && remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped.lcov -t lcovonly && remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped -t html", - "test": "tsc --project ./spec --pretty && jasmine", + "test_nobuild": "jasmine", + "test_buildonly": "rm -rf tmp && tsc --project ./spec --pretty", + "test": "npm run test_buildonly && npm run test_nobuild", "test_karma": "karma start karma.conf.js", "tests2png": "mkdirp tmp/docs/img && JASMINE_CONFIG_PATH=spec/support/tests2png.json jasmine", "watch": "watch \"echo triggering build && npm run build_test && echo build completed\" src -d -u -w=15", diff --git a/spec/helpers/ajax-helper.js b/spec/helpers/ajax-helper.js deleted file mode 100644 index 20b293abd1..0000000000 --- a/spec/helpers/ajax-helper.js +++ /dev/null @@ -1,120 +0,0 @@ -var root = require('../../dist/cjs/util/root').root; - -var requests = []; -var recentRequest = null; - -function MockXMLHttpRequest() { - this.previousRequest = recentRequest; - recentRequest = this; - requests.push(this); - this.requestHeaders = {}; - this.responseType = ''; - this.eventHandlers = []; - this.readyState = 0; -} - -MockXMLHttpRequest.prototype = { - send: function (data) { - this.data = data; - }, - - open: function (method, url, async, user, password) { - this.method = method; - this.url = url; - this.async = async; - this.user = user; - this.password = password; - this.readyState = 1; - this.triggerEvent('readystatechange'); - }, - - setRequestHeader: function (key, value) { - this.requestHeaders[key] = value; - }, - - addEventListener: function (name, handler) { - this.eventHandlers.push({ name: name, handler: handler }); - }, - - removeEventListener: function (name, handler) { - for (var i = this.eventHandlers.length - 1; i--;) { - var eh = this.eventHandlers[i]; - if (eh.name === name && eh.handler === handler) { - this.eventHandlers.splice(i, 1); - } - } - }, - - throwError: function (err) { - // TODO: something better with errors - this.triggerEvent('error'); - }, - - respondWith: function (response) { - this.readyState = 4; - this.responseHeaders = { - 'Content-Type': response.contentType || 'text/plain' - }; - this.status = response.status || 200; - this.responseText = response.responseText; - if (!('response' in response)) { - switch (this.responseType) { - case 'json': - try { - this.response = JSON.parse(response.responseText); - } catch (err) { - throw new Error('unable to JSON.parse: \n' + response.responseText); - } - break; - case 'text': - this.response = response.responseText; - break; - default: - throw new Error('unhandled type "' + this.responseType + '"'); - } - } - // TODO: pass better event to onload. - this.triggerEvent('load'); - this.triggerEvent('readystatechange'); - }, - - triggerEvent: function (name, eventObj) { - // TODO: create a better default event - e = eventObj || {}; - - if (this['on' + name]) { - this['on' + name](e); - } - - this.eventHandlers.forEach(function (eh) { - if (eh.name === name) { - eh.handler.call(this, e); - } - }); - } -}; - -MockXMLHttpRequest.mostRecent = function () { - return recentRequest; -}; - -MockXMLHttpRequest.allRequests = function () { - return requests; -}; - -var gXHR; -var rXHR; - -global.setupMockXHR = function () { - gXHR = global.XMLHttpRequest; - rXHR = root.XMLHttpRequest; - global.XMLHttpRequest = MockXMLHttpRequest; - root.XMLHttpRequest = MockXMLHttpRequest; -}; - -global.teardownMockXHR = function () { - global.XMLHttpRequest = gXHR; - root.XMLHttpRequest = rXHR; - requests.length = 0; - recentRequest = null; -}; \ No newline at end of file diff --git a/spec/helpers/ajax-helper.ts b/spec/helpers/ajax-helper.ts new file mode 100644 index 0000000000..4bb943ffb3 --- /dev/null +++ b/spec/helpers/ajax-helper.ts @@ -0,0 +1,221 @@ +declare const __root__: any; + +export class MockWebSocket { + static sockets: Array = []; + static get lastSocket(): MockWebSocket { + const socket = MockWebSocket.sockets; + const length = socket.length; + return length > 0 ? socket[length - 1] : undefined; + } + + static clearSockets(): void { + MockWebSocket.sockets.length = 0; + } + + sent: Array = []; + handlers: any = {}; + readyState: number = 0; + closeCode: any; + closeReason: any; + + constructor(public url: string, public protocol: string) { + MockWebSocket.sockets.push(this); + } + + send(data: any): void { + this.sent.push(data); + } + + get lastMessageSent(): any { + const sent = this.sent; + const length = sent.length; + + return length > 0 ? sent[length -1] : undefined; + } + + triggerClose(e: any): void { + this.readyState = 3; + this.trigger('close', e); + } + + triggerError(err: any): void { + this.readyState = 3; + this.trigger('error', err); + } + + triggerMessage(data: any): void { + const messageEvent = { + data: data, + origin: 'mockorigin', + ports: undefined, + source: __root__, + }; + + this.trigger('message', messageEvent); + } + + open(): void { + this.readyState = 1; + this.trigger('open', {}); + } + + close(code: any, reason: any): void { + if (this.readyState < 2) { + this.readyState = 2; + this.closeCode = code; + this.closeReason = reason; + this.triggerClose({ wasClean: true }); + } + } + + addEventListener(name: string, handler: any): void { + const lookup = this.handlers[name] = this.handlers[name] || []; + lookup.push(handler); + } + + removeEventListener(name: string, handler: any): void { + const lookup = this.handlers[name]; + if(lookup) { + for (let i = lookup.length - 1; i--;) { + if (lookup[i] === handler) { + lookup.splice(i, 1); + } + } + } + } + + trigger(name: string, e: any) { + if (this['on' + name]) { + this['on' + name](e); + } + + const lookup = this.handlers[name]; + if (lookup) { + for (let i = 0; i < lookup.length; i++) { + lookup[i](e); + } + } + } +} + +export class MockXMLHttpRequest { + private static requests: Array = []; + private static recentRequest: MockXMLHttpRequest; + + static get mostRecent(): MockXMLHttpRequest { + return MockXMLHttpRequest.recentRequest; + } + + static get allRequests(): Array { + return MockXMLHttpRequest.requests; + } + + static clearRequest(): void { + MockXMLHttpRequest.requests.length = 0; + MockXMLHttpRequest.recentRequest = null; + } + + private previousRequest: MockXMLHttpRequest; + + private responseType: string = ''; + private eventHandlers: Array = []; + private readyState: number = 0; + + private async: any; + private user: any; + private password: any; + + private responseHeaders: any; + private status: any; + private responseText: string; + private response: any; + + url: any; + method: any; + data: any; + requestHeaders: any = {}; + + constructor() { + this.previousRequest = MockXMLHttpRequest.recentRequest; + MockXMLHttpRequest.recentRequest = this; + MockXMLHttpRequest.requests.push(this); + } + + send(data: any): void { + this.data = data; + } + + open(method: any, url: any, async: any, user: any, password: any): void { + this.method = method; + this.url = url; + this.user = user; + this.password = password; + this.readyState = 1; + this.triggerEvent('readyStateChange'); + } + + setRequestHeader(key: any, value: any): void { + this.requestHeaders[key] = value; + } + + addEventListener(name: string, handler: any): void { + this.eventHandlers.push({ name: name, handler: handler }); + } + + removeEventListener(name: string, handler: any): void { + for (let i = this.eventHandlers.length - 1; i--;) { + let eh = this.eventHandlers[i]; + if (eh.name === name && eh.handler === handler) { + this.eventHandlers.splice(i, 1); + } + } + } + + throwError(err: any): void { + // TODO: something better with errors + this.triggerEvent('error'); + } + + respondWith(response: any): void { + this.readyState = 4; + this.responseHeaders = { + 'Content-Type': response.contentType || 'text/plain' + }; + this.status = response.status || 200; + this.responseText = response.responseText; + if (!('response' in response)) { + switch (this.responseType) { + case 'json': + try { + this.response = JSON.parse(response.responseText); + } catch (err) { + throw new Error('unable to JSON.parse: \n' + response.responseText); + } + break; + case 'text': + this.response = response.responseText; + break; + default: + throw new Error('unhandled type "' + this.responseType + '"'); + } + } + // TODO: pass better event to onload. + this.triggerEvent('load'); + this.triggerEvent('readystatechange'); + } + + triggerEvent(name: any, eventObj?: any): void { + // TODO: create a better default event + const e: any = eventObj || {}; + + if (this['on' + name]) { + this['on' + name](e); + } + + this.eventHandlers.forEach(function (eh) { + if (eh.name === name) { + eh.handler.call(this, e); + } + }); + } +} \ No newline at end of file diff --git a/spec/helpers/marble-testing.js b/spec/helpers/marble-testing.js deleted file mode 100644 index 513af63d0f..0000000000 --- a/spec/helpers/marble-testing.js +++ /dev/null @@ -1,47 +0,0 @@ -function hot() { - if (!global.rxTestScheduler) { - throw 'tried to use hot() in async test'; - } - return global.rxTestScheduler.createHotObservable.apply(global.rxTestScheduler, arguments); -} - -function cold() { - if (!global.rxTestScheduler) { - throw 'tried to use cold() in async test'; - } - return global.rxTestScheduler.createColdObservable.apply(global.rxTestScheduler, arguments); -} - -function time() { - if (!global.rxTestScheduler) { - throw 'tried to use time() in async test'; - } - return global.rxTestScheduler.createTime.apply(global.rxTestScheduler, arguments); -} - -function expectObservable() { - if (!global.rxTestScheduler) { - throw 'tried to use expectObservable() in async test'; - } - return global.rxTestScheduler.expectObservable.apply(global.rxTestScheduler, arguments); -} - -function expectSubscriptions() { - if (!global.rxTestScheduler) { - throw 'tried to use expectSubscriptions() in async test'; - } - return global.rxTestScheduler.expectSubscriptions.apply(global.rxTestScheduler, arguments); -} - -function assertDeepEqual(actual, expected) { - expect(actual).toDeepEqual(expected); -} - -module.exports = { - hot: hot, - cold: cold, - time: time, - expectObservable: expectObservable, - expectSubscriptions: expectSubscriptions, - assertDeepEqual: assertDeepEqual -}; diff --git a/spec/helpers/marble-testing.ts b/spec/helpers/marble-testing.ts new file mode 100644 index 0000000000..827ab2e991 --- /dev/null +++ b/spec/helpers/marble-testing.ts @@ -0,0 +1,48 @@ +/// +import {Observable} from '../../dist/cjs/Observable'; +import {SubscriptionLog} from '../../dist/cjs/testing/SubscriptionLog'; +import {ColdObservable} from '../../dist/cjs/testing/ColdObservable'; +import {HotObservable} from '../../dist/cjs/testing/HotObservable'; +import {observableToBeFn, subscriptionLogsToBeFn} from '../../dist/cjs/testing/TestScheduler'; + +declare const global: any; + +export function hot(marbles: string, values?: any, error?: any): HotObservable { + if (!global.rxTestScheduler) { + throw 'tried to use hot() in async test'; + } + return global.rxTestScheduler.createHotObservable.apply(global.rxTestScheduler, arguments); +} + +export function cold(marbles: string, values?: any, error?: any): ColdObservable { + if (!global.rxTestScheduler) { + throw 'tried to use cold() in async test'; + } + return global.rxTestScheduler.createColdObservable.apply(global.rxTestScheduler, arguments); +} + +export function expectObservable(observable: Observable, + unsubscriptionMarbles: string = null): ({ toBe: observableToBeFn }) { + if (!global.rxTestScheduler) { + throw 'tried to use expectObservable() in async test'; + } + return global.rxTestScheduler.expectObservable.apply(global.rxTestScheduler, arguments); +} + +export function expectSubscriptions(actualSubscriptionLogs: SubscriptionLog[]): ({ toBe: subscriptionLogsToBeFn }) { + if (!global.rxTestScheduler) { + throw 'tried to use expectSubscriptions() in async test'; + } + return global.rxTestScheduler.expectSubscriptions.apply(global.rxTestScheduler, arguments); +} + +export function assertDeepEqual(actual: any, expected: any): void { + (expect(actual)).toDeepEqual(expected); +} + +export function time(marbles: string): number { + if (!global.rxTestScheduler) { + throw 'tried to use time() in async test'; + } + return global.rxTestScheduler.createTime.apply(global.rxTestScheduler, arguments); +} \ No newline at end of file diff --git a/spec/helpers/test-helper.js b/spec/helpers/test-helper.js deleted file mode 100644 index 97bf5e80d8..0000000000 --- a/spec/helpers/test-helper.js +++ /dev/null @@ -1,157 +0,0 @@ -//Fail timeouts faster -//Individual suites/specs should specify longer timeouts if needed. -jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; - -var _ = require('lodash'); -var root = require('../../dist/cjs/util/root').root; -var Rx = require('../../dist/cjs/Rx.KitchenSink'); - -var marbleHelpers = require('./marble-testing'); - -global.rxTestScheduler = null; -global.cold = marbleHelpers.cold; -global.hot = marbleHelpers.hot; -global.time = marbleHelpers.time; -global.expectObservable = marbleHelpers.expectObservable; -global.expectSubscriptions = marbleHelpers.expectSubscriptions; - -var assertDeepEqual = marbleHelpers.assertDeepEqual; - -var glit = global.it; - -global.it = function (description, cb, timeout) { - if (cb.length === 0) { - glit(description, function (done) { - global.rxTestScheduler = new Rx.TestScheduler(assertDeepEqual); - var error; - var errorHappened = false; - try { - cb(); - global.rxTestScheduler.flush(); - } catch (e) { - errorHappened = true; - error = e; - } finally { - if (errorHappened) { - setTimeout(function () { done.fail(error); }); - } else { - setTimeout(function () { done(); }); - } - } - }); - } else { - glit.apply(this, arguments); - } -}; - -global.it.asDiagram = function () { - return global.it; -}; - -var glfit = global.fit; - -global.fit = function (description, cb, timeout) { - if (cb.length === 0) { - glfit(description, function (done) { - global.rxTestScheduler = new Rx.TestScheduler(assertDeepEqual); - var error; - var errorHappened = false; - try { - cb(); - global.rxTestScheduler.flush(); - } catch (e) { - errorHappened = true; - error = e; - } finally { - if (errorHappened) { - setTimeout(function () { done.fail(error); }); - } else { - setTimeout(function () { done(); }); - } - } - }); - } else { - glfit.apply(this, arguments); - } -}; - -function stringify(x) { - return JSON.stringify(x, function (key, value) { - if (Array.isArray(value)) { - return '[' + value - .map(function (i) { - return '\n\t' + stringify(i); - }) + '\n]'; - } - return value; - }) - .replace(/\\"/g, '"') - .replace(/\\t/g, '\t') - .replace(/\\n/g, '\n'); -} - -beforeEach(function () { - jasmine.addMatchers({ - toDeepEqual: function (util, customEqualityTesters) { - return { - compare: function (actual, expected) { - var result = { pass: _.isEqual(actual, expected) }; - - if (!result.pass && Array.isArray(actual) && Array.isArray(expected)) { - result.message = 'Expected \n'; - actual.forEach(function (x) { - result.message += stringify(x) + '\n'; - }); - result.message += '\nto deep equal \n'; - expected.forEach(function (x) { - result.message += stringify(x) + '\n'; - }); - } - - return result; - } - }; - } - }); -}); - -afterEach(function () { - global.rxTestScheduler = null; -}); - -(function () { - Object.defineProperty(Error.prototype, 'toJSON', { - value: function () { - var alt = {}; - - Object.getOwnPropertyNames(this).forEach(function (key) { - if (key !== 'stack') { - alt[key] = this[key]; - } - }, this); - return alt; - }, - configurable: true - }); - - global.__root__ = root; -})(); - -global.lowerCaseO = function lowerCaseO() { - var values = [].slice.apply(arguments); - - var o = { - subscribe: function (observer) { - values.forEach(function (v) { - observer.next(v); - }); - observer.complete(); - } - }; - - o[Symbol.observable] = function () { - return this; - }; - - return o; -}; diff --git a/spec/helpers/test-helper.ts b/spec/helpers/test-helper.ts new file mode 100644 index 0000000000..ea95d640ed --- /dev/null +++ b/spec/helpers/test-helper.ts @@ -0,0 +1,148 @@ +/// +/// +/// +declare const global: any; +declare const Symbol: any; + +//Fail timeouts faster +//Individual suites/specs should specify longer timeouts if needed. +jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; + +import * as _ from 'lodash'; +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {root} from '../../dist/cjs/util/root'; +import {assertDeepEqual} from './marble-testing'; + +global.rxTestScheduler = null; + +//amending type definition of jasmine which seems doesn't have this +export interface DoneSignature { + (): void; + fail(description?: string): void; +} + +const defaultAssertion: (expectation: string, assertion?: (done: DoneSignature) => void, timeout?: number) => void = global.it; +const singleAssertion: (expectation: string, assertion?: (done: DoneSignature) => void, timeout?: number) => void = global.fit; + +function assertAction(done: DoneSignature, assertion: (done?: DoneSignature) => void): void { + global.rxTestScheduler = new Rx.TestScheduler(assertDeepEqual); + let error: any; + let errorHappened: boolean = false; + + try { + assertion(); + global.rxTestScheduler.flush(); + } catch (e) { + errorHappened = true; + error = e; + } finally { + if (errorHappened) { + setTimeout(function () { done.fail(error); }); + } else { + setTimeout(function () { done(); }); + } + } +} + +export function asDiagram(expectation: string): (expectation: string, assertion?: (done: DoneSignature) => void, timeout?: number) => void { + return it; +} + +export function it(expectation: string, assertion?: (done?: DoneSignature) => void, timeout?: number): void { + if (assertion.length === 0) { + defaultAssertion(expectation, (done: DoneSignature) => { + assertAction(done, assertion); + }); + } else { + defaultAssertion.apply(this, arguments); + } +} + +export function fit(expectation: string, assertion?: (done?: DoneSignature) => void, timeout?: number): void { + if (assertion.length === 0) { + singleAssertion(expectation, (done: DoneSignature) => { + assertAction(done, assertion); + }); + } else { + singleAssertion.apply(this, arguments); + } +} + +export function lowerCaseO(...args): Rx.Observable { + const values = [].slice.apply(arguments); + + const o = { + subscribe: function (observer) { + values.forEach(function (v) { + observer.next(v); + }); + observer.complete(); + } + }; + + o[Symbol.observable] = function () { + return this; + }; + + return o; +}; + +function stringify(x) { + return JSON.stringify(x, function (key, value) { + if (Array.isArray(value)) { + return '[' + value + .map(function (i) { + return '\n\t' + stringify(i); + }) + '\n]'; + } + return value; + }) + .replace(/\\"/g, '"') + .replace(/\\t/g, '\t') + .replace(/\\n/g, '\n'); +} + +beforeEach(function () { + jasmine.addMatchers({ + toDeepEqual: function (util, customEqualityTesters) { + return { + compare: function (actual, expected) { + let result: any = { pass: _.isEqual(actual, expected) }; + + if (!result.pass && Array.isArray(actual) && Array.isArray(expected)) { + result.message = 'Expected \n'; + actual.forEach(function (x) { + result.message += stringify(x) + '\n'; + }); + result.message += '\nto deep equal \n'; + expected.forEach(function (x) { + result.message += stringify(x) + '\n'; + }); + } + + return result; + } + }; + } + }); +}); + +Object.defineProperty(Error.prototype, 'toJSON', { + value: function () { + const alt = {}; + + Object.getOwnPropertyNames(this).forEach(function (key) { + if (key !== 'stack') { + alt[key] = this[key]; + } + }, this); + return alt; + }, + configurable: true +}); + +global.__root__ = root; + +afterEach(function () { + global.rxTestScheduler = null; +}); \ No newline at end of file From 93ca5a16d2027f6789b7fbca256c1d0a705c4bc8 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Thu, 18 Feb 2016 16:57:28 -0800 Subject: [PATCH 3/8] test(ALL): migrate test cases into typescript --- spec/Notification-spec.js | 281 ---- spec/Notification-spec.ts | 282 ++++ ...{Observable-spec.js => Observable-spec.ts} | 274 ++-- spec/Scheduler-spec.js | 36 - spec/Scheduler-spec.ts | 36 + spec/{Subject-spec.js => Subject-spec.ts} | 352 ++--- spec/Subscriber-spec.js | 35 - spec/Subscriber-spec.ts | 35 + spec/Subscription-spec.js | 79 - spec/Subscription-spec.ts | 80 + spec/observables/ErrorObservable-spec.js | 24 - spec/observables/ErrorObservable-spec.ts | 27 + ...ble-spec.js => IteratorObservable-spec.ts} | 118 +- spec/observables/ScalarObservable-spec.js | 28 - spec/observables/ScalarObservable-spec.ts | 27 + .../observables/SubscribeOnObservable-spec.js | 50 - .../observables/SubscribeOnObservable-spec.ts | 54 + ...dCallback-spec.js => bindCallback-spec.ts} | 170 +- ...lback-spec.js => bindNodeCallback-spec.ts} | 175 ++- spec/observables/combineLatest-spec.js | 472 ------ spec/observables/combineLatest-spec.ts | 473 ++++++ spec/observables/concat-spec.js | 343 ---- spec/observables/concat-spec.ts | 345 ++++ spec/observables/defer-spec.js | 82 - spec/observables/defer-spec.ts | 75 + spec/observables/dom/ajax-spec.js | 356 ----- spec/observables/dom/ajax-spec.ts | 362 +++++ spec/observables/dom/webSocket-spec.js | 445 ------ spec/observables/dom/webSocket-spec.ts | 389 +++++ .../{forkJoin-spec.js => forkJoin-spec.ts} | 151 +- spec/observables/from-promise-spec.js | 158 -- spec/observables/from-promise-spec.ts | 161 ++ spec/observables/from-spec.js | 168 -- spec/observables/from-spec.ts | 170 ++ .../{fromEvent-spec.js => fromEvent-spec.ts} | 158 +- spec/observables/fromEventPattern-spec.js | 104 -- spec/observables/fromEventPattern-spec.ts | 115 ++ spec/observables/interval-spec.js | 49 - spec/observables/interval-spec.ts | 52 + spec/observables/jasmine-is-weird-spec.js | 38 - spec/observables/merge-spec.js | 231 --- spec/observables/merge-spec.ts | 233 +++ spec/observables/of-spec.js | 79 - spec/observables/of-spec.ts | 82 + spec/observables/race-spec.js | 193 --- spec/observables/race-spec.ts | 194 +++ spec/observables/range-spec.js | 82 - spec/observables/range-spec.ts | 86 + spec/observables/throw-spec.js | 16 - spec/observables/throw-spec.ts | 17 + spec/observables/timer-spec.js | 73 - spec/observables/timer-spec.ts | 76 + spec/observables/zip-spec.js | 574 ------- spec/observables/zip-spec.ts | 577 +++++++ spec/operators/buffer-spec.js | 220 --- spec/operators/buffer-spec.ts | 222 +++ spec/operators/bufferCount-spec.js | 118 -- spec/operators/bufferCount-spec.ts | 120 ++ spec/operators/bufferTime-spec.js | 227 --- spec/operators/bufferTime-spec.ts | 230 +++ spec/operators/bufferToggle-spec.js | 342 ---- spec/operators/bufferToggle-spec.ts | 344 ++++ spec/operators/bufferWhen-spec.js | 350 ----- spec/operators/bufferWhen-spec.ts | 350 +++++ spec/operators/cache-spec.js | 182 --- spec/operators/cache-spec.ts | 184 +++ spec/operators/catch-spec.js | 228 --- spec/operators/catch-spec.ts | 227 +++ spec/operators/combineAll-spec.js | 472 ------ spec/operators/combineAll-spec.ts | 475 ++++++ spec/operators/combineLatest-spec.js | 463 ------ spec/operators/combineLatest-spec.ts | 465 ++++++ spec/operators/concat-spec.js | 309 ---- spec/operators/concat-spec.ts | 311 ++++ spec/operators/concatAll-spec.js | 426 ----- spec/operators/concatAll-spec.ts | 428 +++++ spec/operators/concatMap-spec.js | 787 ---------- spec/operators/concatMap-spec.ts | 748 +++++++++ spec/operators/concatMapTo-spec.js | 386 ----- spec/operators/concatMapTo-spec.ts | 384 +++++ spec/operators/count-spec.js | 266 ---- spec/operators/count-spec.ts | 258 +++ .../{debounce-spec.js => debounce-spec.ts} | 333 ++-- spec/operators/debounceTime-spec.js | 147 -- spec/operators/debounceTime-spec.ts | 150 ++ spec/operators/defaultIfEmpty-spec.js | 84 - spec/operators/defaultIfEmpty-spec.ts | 86 + spec/operators/delay-spec.js | 142 -- spec/operators/delay-spec.ts | 145 ++ spec/operators/delayWhen-spec.js | 211 --- spec/operators/delayWhen-spec.ts | 214 +++ spec/operators/dematerialize-spec.js | 161 -- spec/operators/dematerialize-spec.ts | 163 ++ spec/operators/distinct-spec.js | 241 --- spec/operators/distinct-spec.ts | 235 +++ spec/operators/distinctKey-spec.js | 272 ---- spec/operators/distinctKey-spec.ts | 226 +++ spec/operators/distinctUntilChanged-spec.js | 220 --- spec/operators/distinctUntilChanged-spec.ts | 216 +++ .../operators/distinctUntilKeyChanged-spec.js | 226 --- .../operators/distinctUntilKeyChanged-spec.ts | 224 +++ spec/operators/do-spec.js | 212 --- spec/operators/do-spec.ts | 214 +++ spec/operators/elementAt-spec.js | 120 -- spec/operators/elementAt-spec.ts | 122 ++ spec/operators/every-spec.js | 264 ---- spec/operators/every-spec.ts | 260 +++ spec/operators/exhaust-spec.js | 215 --- spec/operators/exhaust-spec.ts | 215 +++ ...{exhaustMap-spec.js => exhaustMap-spec.ts} | 124 +- .../{expand-spec.js => expand-spec.ts} | 252 +-- spec/operators/filter-spec.js | 274 ---- spec/operators/filter-spec.ts | 272 ++++ .../{finally-spec.js => finally-spec.ts} | 39 +- spec/operators/find-spec.js | 155 -- spec/operators/find-spec.ts | 157 ++ spec/operators/findIndex-spec.js | 149 -- spec/operators/findIndex-spec.ts | 151 ++ spec/operators/first-spec.js | 199 --- spec/operators/first-spec.ts | 202 +++ spec/operators/groupBy-spec.js | 1390 ----------------- spec/operators/groupBy-spec.ts | 1383 ++++++++++++++++ spec/operators/ignoreElements-spec.js | 77 - spec/operators/ignoreElements-spec.ts | 79 + spec/operators/inspect-spec.js | 329 ---- spec/operators/inspect-spec.ts | 330 ++++ spec/operators/inspectTime-spec.js | 136 -- spec/operators/inspectTime-spec.ts | 139 ++ spec/operators/isEmpty-spec.js | 74 - spec/operators/isEmpty-spec.ts | 75 + spec/operators/last-spec.js | 144 -- spec/operators/last-spec.ts | 144 ++ spec/operators/let-spec.js | 24 - spec/operators/let-spec.ts | 18 + spec/operators/map-spec.js | 252 --- spec/operators/map-spec.ts | 254 +++ spec/operators/mapTo-spec.js | 99 -- spec/operators/mapTo-spec.ts | 101 ++ spec/operators/materialize-spec.js | 136 -- spec/operators/materialize-spec.ts | 138 ++ spec/operators/max-spec.js | 248 --- spec/operators/max-spec.ts | 250 +++ spec/operators/merge-spec.js | 287 ---- spec/operators/merge-spec.ts | 290 ++++ spec/operators/mergeAll-spec.js | 410 ----- spec/operators/mergeAll-spec.ts | 411 +++++ spec/operators/mergeMap-spec.js | 700 --------- spec/operators/mergeMap-spec.ts | 665 ++++++++ spec/operators/mergeMapTo-spec.js | 406 ----- spec/operators/mergeMapTo-spec.ts | 404 +++++ spec/operators/mergeScan-spec.js | 400 ----- spec/operators/mergeScan-spec.ts | 390 +++++ spec/operators/min-spec.js | 256 --- spec/operators/min-spec.ts | 258 +++ spec/operators/multicast-spec.js | 573 ------- spec/operators/multicast-spec.ts | 563 +++++++ spec/operators/observeOn-spec.js | 77 - spec/operators/observeOn-spec.ts | 80 + spec/operators/pairwise-spec.js | 88 -- spec/operators/pairwise-spec.ts | 90 ++ .../{partition-spec.js => partition-spec.ts} | 157 +- spec/operators/pluck-spec.js | 152 -- spec/operators/pluck-spec.ts | 154 ++ spec/operators/publish-spec.js | 324 ---- spec/operators/publish-spec.ts | 326 ++++ spec/operators/publishBehavior-spec.js | 347 ---- spec/operators/publishBehavior-spec.ts | 349 +++++ spec/operators/publishLast-spec.js | 250 --- spec/operators/publishLast-spec.ts | 252 +++ spec/operators/publishReplay-spec.js | 383 ----- spec/operators/publishReplay-spec.ts | 386 +++++ spec/operators/race-spec.js | 149 -- spec/operators/race-spec.ts | 150 ++ spec/operators/reduce-spec.js | 232 --- spec/operators/reduce-spec.ts | 234 +++ spec/operators/refCount-spec.js | 58 - spec/operators/refCount-spec.ts | 59 + .../{repeat-spec.js => repeat-spec.ts} | 231 +-- spec/operators/retry-spec.js | 208 --- spec/operators/retry-spec.ts | 210 +++ spec/operators/retryWhen-spec.js | 335 ---- spec/operators/retryWhen-spec.ts | 327 ++++ spec/operators/sample-spec.js | 204 --- spec/operators/sample-spec.ts | 206 +++ spec/operators/sampleTime-spec.js | 109 -- spec/operators/sampleTime-spec.ts | 112 ++ spec/operators/scan-spec.js | 177 --- spec/operators/scan-spec.ts | 179 +++ spec/operators/share-spec.js | 309 ---- spec/operators/share-spec.ts | 310 ++++ spec/operators/single-spec.js | 148 -- spec/operators/single-spec.ts | 149 ++ spec/operators/skip-spec.js | 147 -- spec/operators/skip-spec.ts | 149 ++ spec/operators/skipUntil-spec.js | 235 --- spec/operators/skipUntil-spec.ts | 237 +++ spec/operators/skipWhile-spec.js | 189 --- spec/operators/skipWhile-spec.ts | 191 +++ spec/operators/startWith-spec.js | 153 -- spec/operators/startWith-spec.ts | 156 ++ spec/operators/subscribeOn-spec.js | 77 - spec/operators/subscribeOn-spec.ts | 80 + spec/operators/switch-spec.js | 219 --- spec/operators/switch-spec.ts | 218 +++ spec/operators/switchMap-spec.js | 408 ----- spec/operators/switchMap-spec.ts | 373 +++++ spec/operators/switchMapTo-spec.js | 251 --- spec/operators/switchMapTo-spec.ts | 251 +++ spec/operators/take-spec.js | 125 -- spec/operators/take-spec.ts | 127 ++ spec/operators/takeLast-spec.js | 125 -- spec/operators/takeLast-spec.ts | 127 ++ spec/operators/takeUntil-spec.js | 192 --- spec/operators/takeUntil-spec.ts | 194 +++ spec/operators/takeWhile-spec.js | 200 --- spec/operators/takeWhile-spec.ts | 201 +++ spec/operators/throttle-spec.js | 333 ---- spec/operators/throttle-spec.ts | 333 ++++ spec/operators/throttleTime-spec.js | 135 -- spec/operators/throttleTime-spec.ts | 138 ++ spec/operators/timeInterval-spec.js | 144 -- spec/operators/timeInterval-spec.ts | 147 ++ spec/operators/timeout-spec.js | 139 -- spec/operators/timeout-spec.ts | 142 ++ spec/operators/timeoutWith-spec.js | 260 --- spec/operators/timeoutWith-spec.ts | 263 ++++ spec/operators/toArray-spec.js | 102 -- spec/operators/toArray-spec.ts | 104 ++ spec/operators/toPromise-spec.js | 38 - spec/operators/toPromise-spec.ts | 40 + spec/operators/window-spec.js | 255 --- spec/operators/window-spec.ts | 258 +++ spec/operators/windowCount-spec.js | 171 -- spec/operators/windowCount-spec.ts | 174 +++ spec/operators/windowTime-spec.js | 215 --- spec/operators/windowTime-spec.ts | 218 +++ spec/operators/windowToggle-spec.js | 407 ----- spec/operators/windowToggle-spec.ts | 410 +++++ spec/operators/windowWhen-spec.js | 355 ----- spec/operators/windowWhen-spec.ts | 358 +++++ spec/operators/withLatestFrom-spec.js | 260 --- spec/operators/withLatestFrom-spec.ts | 261 ++++ spec/operators/zip-spec.js | 591 ------- spec/operators/zip-spec.ts | 594 +++++++ spec/operators/zipAll-spec.js | 722 --------- spec/operators/zipAll-spec.ts | 719 +++++++++ spec/root-module-spec.js | 8 - spec/root-module-spec.ts | 8 + spec/schedulers/AsapScheduler-spec.js | 47 - spec/schedulers/AsapScheduler-spec.ts | 47 + spec/schedulers/TestScheduler-spec.js | 255 --- spec/schedulers/TestScheduler-spec.ts | 259 +++ ...r-spec.js => VirtualTimeScheduler-spec.ts} | 44 +- ...ncSubject-spec.js => AsyncSubject-spec.ts} | 92 +- spec/subjects/BehaviorSubject-spec.js | 179 --- spec/subjects/BehaviorSubject-spec.ts | 181 +++ spec/subjects/ReplaySubject-spec.js | 232 --- spec/subjects/ReplaySubject-spec.ts | 235 +++ spec/symbol/rxSubscriber-spec.js | 13 - spec/symbol/rxSubscriber-spec.ts | 14 + .../util/{FastMap-spec.js => FastMap-spec.ts} | 51 +- .../{Immediate-spec.js => Immediate-spec.ts} | 363 ++--- ...apPolyfill-spec.js => MapPolyfill-spec.ts} | 48 +- spec/util/SymbolShim-spec.js | 123 -- spec/util/SymbolShim-spec.ts | 123 ++ 265 files changed, 30340 insertions(+), 30393 deletions(-) delete mode 100644 spec/Notification-spec.js create mode 100644 spec/Notification-spec.ts rename spec/{Observable-spec.js => Observable-spec.ts} (53%) delete mode 100644 spec/Scheduler-spec.js create mode 100644 spec/Scheduler-spec.ts rename spec/{Subject-spec.js => Subject-spec.ts} (59%) delete mode 100644 spec/Subscriber-spec.js create mode 100644 spec/Subscriber-spec.ts delete mode 100644 spec/Subscription-spec.js create mode 100644 spec/Subscription-spec.ts delete mode 100644 spec/observables/ErrorObservable-spec.js create mode 100644 spec/observables/ErrorObservable-spec.ts rename spec/observables/{IteratorObservable-spec.js => IteratorObservable-spec.ts} (55%) delete mode 100644 spec/observables/ScalarObservable-spec.js create mode 100644 spec/observables/ScalarObservable-spec.ts delete mode 100644 spec/observables/SubscribeOnObservable-spec.js create mode 100644 spec/observables/SubscribeOnObservable-spec.ts rename spec/observables/{bindCallback-spec.js => bindCallback-spec.ts} (50%) rename spec/observables/{bindNodeCallback-spec.js => bindNodeCallback-spec.ts} (54%) delete mode 100644 spec/observables/combineLatest-spec.js create mode 100644 spec/observables/combineLatest-spec.ts delete mode 100644 spec/observables/concat-spec.js create mode 100644 spec/observables/concat-spec.ts delete mode 100644 spec/observables/defer-spec.js create mode 100644 spec/observables/defer-spec.ts delete mode 100644 spec/observables/dom/ajax-spec.js create mode 100644 spec/observables/dom/ajax-spec.ts delete mode 100644 spec/observables/dom/webSocket-spec.js create mode 100644 spec/observables/dom/webSocket-spec.ts rename spec/observables/{forkJoin-spec.js => forkJoin-spec.ts} (58%) delete mode 100644 spec/observables/from-promise-spec.js create mode 100644 spec/observables/from-promise-spec.ts delete mode 100644 spec/observables/from-spec.js create mode 100644 spec/observables/from-spec.ts rename spec/observables/{fromEvent-spec.js => fromEvent-spec.ts} (52%) delete mode 100644 spec/observables/fromEventPattern-spec.js create mode 100644 spec/observables/fromEventPattern-spec.ts delete mode 100644 spec/observables/interval-spec.js create mode 100644 spec/observables/interval-spec.ts delete mode 100644 spec/observables/jasmine-is-weird-spec.js delete mode 100644 spec/observables/merge-spec.js create mode 100644 spec/observables/merge-spec.ts delete mode 100644 spec/observables/of-spec.js create mode 100644 spec/observables/of-spec.ts delete mode 100644 spec/observables/race-spec.js create mode 100644 spec/observables/race-spec.ts delete mode 100644 spec/observables/range-spec.js create mode 100644 spec/observables/range-spec.ts delete mode 100644 spec/observables/throw-spec.js create mode 100644 spec/observables/throw-spec.ts delete mode 100644 spec/observables/timer-spec.js create mode 100644 spec/observables/timer-spec.ts delete mode 100644 spec/observables/zip-spec.js create mode 100644 spec/observables/zip-spec.ts delete mode 100644 spec/operators/buffer-spec.js create mode 100644 spec/operators/buffer-spec.ts delete mode 100644 spec/operators/bufferCount-spec.js create mode 100644 spec/operators/bufferCount-spec.ts delete mode 100644 spec/operators/bufferTime-spec.js create mode 100644 spec/operators/bufferTime-spec.ts delete mode 100644 spec/operators/bufferToggle-spec.js create mode 100644 spec/operators/bufferToggle-spec.ts delete mode 100644 spec/operators/bufferWhen-spec.js create mode 100644 spec/operators/bufferWhen-spec.ts delete mode 100644 spec/operators/cache-spec.js create mode 100644 spec/operators/cache-spec.ts delete mode 100644 spec/operators/catch-spec.js create mode 100644 spec/operators/catch-spec.ts delete mode 100644 spec/operators/combineAll-spec.js create mode 100644 spec/operators/combineAll-spec.ts delete mode 100644 spec/operators/combineLatest-spec.js create mode 100644 spec/operators/combineLatest-spec.ts delete mode 100644 spec/operators/concat-spec.js create mode 100644 spec/operators/concat-spec.ts delete mode 100644 spec/operators/concatAll-spec.js create mode 100644 spec/operators/concatAll-spec.ts delete mode 100644 spec/operators/concatMap-spec.js create mode 100644 spec/operators/concatMap-spec.ts delete mode 100644 spec/operators/concatMapTo-spec.js create mode 100644 spec/operators/concatMapTo-spec.ts delete mode 100644 spec/operators/count-spec.js create mode 100644 spec/operators/count-spec.ts rename spec/operators/{debounce-spec.js => debounce-spec.ts} (50%) delete mode 100644 spec/operators/debounceTime-spec.js create mode 100644 spec/operators/debounceTime-spec.ts delete mode 100644 spec/operators/defaultIfEmpty-spec.js create mode 100644 spec/operators/defaultIfEmpty-spec.ts delete mode 100644 spec/operators/delay-spec.js create mode 100644 spec/operators/delay-spec.ts delete mode 100644 spec/operators/delayWhen-spec.js create mode 100644 spec/operators/delayWhen-spec.ts delete mode 100644 spec/operators/dematerialize-spec.js create mode 100644 spec/operators/dematerialize-spec.ts delete mode 100644 spec/operators/distinct-spec.js create mode 100644 spec/operators/distinct-spec.ts delete mode 100644 spec/operators/distinctKey-spec.js create mode 100644 spec/operators/distinctKey-spec.ts delete mode 100644 spec/operators/distinctUntilChanged-spec.js create mode 100644 spec/operators/distinctUntilChanged-spec.ts delete mode 100644 spec/operators/distinctUntilKeyChanged-spec.js create mode 100644 spec/operators/distinctUntilKeyChanged-spec.ts delete mode 100644 spec/operators/do-spec.js create mode 100644 spec/operators/do-spec.ts delete mode 100644 spec/operators/elementAt-spec.js create mode 100644 spec/operators/elementAt-spec.ts delete mode 100644 spec/operators/every-spec.js create mode 100644 spec/operators/every-spec.ts delete mode 100644 spec/operators/exhaust-spec.js create mode 100644 spec/operators/exhaust-spec.ts rename spec/operators/{exhaustMap-spec.js => exhaustMap-spec.ts} (79%) rename spec/operators/{expand-spec.js => expand-spec.ts} (56%) delete mode 100644 spec/operators/filter-spec.js create mode 100644 spec/operators/filter-spec.ts rename spec/operators/{finally-spec.js => finally-spec.ts} (57%) delete mode 100644 spec/operators/find-spec.js create mode 100644 spec/operators/find-spec.ts delete mode 100644 spec/operators/findIndex-spec.js create mode 100644 spec/operators/findIndex-spec.ts delete mode 100644 spec/operators/first-spec.js create mode 100644 spec/operators/first-spec.ts delete mode 100644 spec/operators/groupBy-spec.js create mode 100644 spec/operators/groupBy-spec.ts delete mode 100644 spec/operators/ignoreElements-spec.js create mode 100644 spec/operators/ignoreElements-spec.ts delete mode 100644 spec/operators/inspect-spec.js create mode 100644 spec/operators/inspect-spec.ts delete mode 100644 spec/operators/inspectTime-spec.js create mode 100644 spec/operators/inspectTime-spec.ts delete mode 100644 spec/operators/isEmpty-spec.js create mode 100644 spec/operators/isEmpty-spec.ts delete mode 100644 spec/operators/last-spec.js create mode 100644 spec/operators/last-spec.ts delete mode 100644 spec/operators/let-spec.js create mode 100644 spec/operators/let-spec.ts delete mode 100644 spec/operators/map-spec.js create mode 100644 spec/operators/map-spec.ts delete mode 100644 spec/operators/mapTo-spec.js create mode 100644 spec/operators/mapTo-spec.ts delete mode 100644 spec/operators/materialize-spec.js create mode 100644 spec/operators/materialize-spec.ts delete mode 100644 spec/operators/max-spec.js create mode 100644 spec/operators/max-spec.ts delete mode 100644 spec/operators/merge-spec.js create mode 100644 spec/operators/merge-spec.ts delete mode 100644 spec/operators/mergeAll-spec.js create mode 100644 spec/operators/mergeAll-spec.ts delete mode 100644 spec/operators/mergeMap-spec.js create mode 100644 spec/operators/mergeMap-spec.ts delete mode 100644 spec/operators/mergeMapTo-spec.js create mode 100644 spec/operators/mergeMapTo-spec.ts delete mode 100644 spec/operators/mergeScan-spec.js create mode 100644 spec/operators/mergeScan-spec.ts delete mode 100644 spec/operators/min-spec.js create mode 100644 spec/operators/min-spec.ts delete mode 100644 spec/operators/multicast-spec.js create mode 100644 spec/operators/multicast-spec.ts delete mode 100644 spec/operators/observeOn-spec.js create mode 100644 spec/operators/observeOn-spec.ts delete mode 100644 spec/operators/pairwise-spec.js create mode 100644 spec/operators/pairwise-spec.ts rename spec/operators/{partition-spec.js => partition-spec.ts} (56%) delete mode 100644 spec/operators/pluck-spec.js create mode 100644 spec/operators/pluck-spec.ts delete mode 100644 spec/operators/publish-spec.js create mode 100644 spec/operators/publish-spec.ts delete mode 100644 spec/operators/publishBehavior-spec.js create mode 100644 spec/operators/publishBehavior-spec.ts delete mode 100644 spec/operators/publishLast-spec.js create mode 100644 spec/operators/publishLast-spec.ts delete mode 100644 spec/operators/publishReplay-spec.js create mode 100644 spec/operators/publishReplay-spec.ts delete mode 100644 spec/operators/race-spec.js create mode 100644 spec/operators/race-spec.ts delete mode 100644 spec/operators/reduce-spec.js create mode 100644 spec/operators/reduce-spec.ts delete mode 100644 spec/operators/refCount-spec.js create mode 100644 spec/operators/refCount-spec.ts rename spec/operators/{repeat-spec.js => repeat-spec.ts} (50%) delete mode 100644 spec/operators/retry-spec.js create mode 100644 spec/operators/retry-spec.ts delete mode 100644 spec/operators/retryWhen-spec.js create mode 100644 spec/operators/retryWhen-spec.ts delete mode 100644 spec/operators/sample-spec.js create mode 100644 spec/operators/sample-spec.ts delete mode 100644 spec/operators/sampleTime-spec.js create mode 100644 spec/operators/sampleTime-spec.ts delete mode 100644 spec/operators/scan-spec.js create mode 100644 spec/operators/scan-spec.ts delete mode 100644 spec/operators/share-spec.js create mode 100644 spec/operators/share-spec.ts delete mode 100644 spec/operators/single-spec.js create mode 100644 spec/operators/single-spec.ts delete mode 100644 spec/operators/skip-spec.js create mode 100644 spec/operators/skip-spec.ts delete mode 100644 spec/operators/skipUntil-spec.js create mode 100644 spec/operators/skipUntil-spec.ts delete mode 100644 spec/operators/skipWhile-spec.js create mode 100644 spec/operators/skipWhile-spec.ts delete mode 100644 spec/operators/startWith-spec.js create mode 100644 spec/operators/startWith-spec.ts delete mode 100644 spec/operators/subscribeOn-spec.js create mode 100644 spec/operators/subscribeOn-spec.ts delete mode 100644 spec/operators/switch-spec.js create mode 100644 spec/operators/switch-spec.ts delete mode 100644 spec/operators/switchMap-spec.js create mode 100644 spec/operators/switchMap-spec.ts delete mode 100644 spec/operators/switchMapTo-spec.js create mode 100644 spec/operators/switchMapTo-spec.ts delete mode 100644 spec/operators/take-spec.js create mode 100644 spec/operators/take-spec.ts delete mode 100644 spec/operators/takeLast-spec.js create mode 100644 spec/operators/takeLast-spec.ts delete mode 100644 spec/operators/takeUntil-spec.js create mode 100644 spec/operators/takeUntil-spec.ts delete mode 100644 spec/operators/takeWhile-spec.js create mode 100644 spec/operators/takeWhile-spec.ts delete mode 100644 spec/operators/throttle-spec.js create mode 100644 spec/operators/throttle-spec.ts delete mode 100644 spec/operators/throttleTime-spec.js create mode 100644 spec/operators/throttleTime-spec.ts delete mode 100644 spec/operators/timeInterval-spec.js create mode 100644 spec/operators/timeInterval-spec.ts delete mode 100644 spec/operators/timeout-spec.js create mode 100644 spec/operators/timeout-spec.ts delete mode 100644 spec/operators/timeoutWith-spec.js create mode 100644 spec/operators/timeoutWith-spec.ts delete mode 100644 spec/operators/toArray-spec.js create mode 100644 spec/operators/toArray-spec.ts delete mode 100644 spec/operators/toPromise-spec.js create mode 100644 spec/operators/toPromise-spec.ts delete mode 100644 spec/operators/window-spec.js create mode 100644 spec/operators/window-spec.ts delete mode 100644 spec/operators/windowCount-spec.js create mode 100644 spec/operators/windowCount-spec.ts delete mode 100644 spec/operators/windowTime-spec.js create mode 100644 spec/operators/windowTime-spec.ts delete mode 100644 spec/operators/windowToggle-spec.js create mode 100644 spec/operators/windowToggle-spec.ts delete mode 100644 spec/operators/windowWhen-spec.js create mode 100644 spec/operators/windowWhen-spec.ts delete mode 100644 spec/operators/withLatestFrom-spec.js create mode 100644 spec/operators/withLatestFrom-spec.ts delete mode 100644 spec/operators/zip-spec.js create mode 100644 spec/operators/zip-spec.ts delete mode 100644 spec/operators/zipAll-spec.js create mode 100644 spec/operators/zipAll-spec.ts delete mode 100644 spec/root-module-spec.js create mode 100644 spec/root-module-spec.ts delete mode 100644 spec/schedulers/AsapScheduler-spec.js create mode 100644 spec/schedulers/AsapScheduler-spec.ts delete mode 100644 spec/schedulers/TestScheduler-spec.js create mode 100644 spec/schedulers/TestScheduler-spec.ts rename spec/schedulers/{VirtualTimeScheduler-spec.js => VirtualTimeScheduler-spec.ts} (63%) rename spec/subjects/{AsyncSubject-spec.js => AsyncSubject-spec.ts} (59%) delete mode 100644 spec/subjects/BehaviorSubject-spec.js create mode 100644 spec/subjects/BehaviorSubject-spec.ts delete mode 100644 spec/subjects/ReplaySubject-spec.js create mode 100644 spec/subjects/ReplaySubject-spec.ts delete mode 100644 spec/symbol/rxSubscriber-spec.js create mode 100644 spec/symbol/rxSubscriber-spec.ts rename spec/util/{FastMap-spec.js => FastMap-spec.ts} (52%) rename spec/util/{Immediate-spec.js => Immediate-spec.ts} (64%) rename spec/util/{MapPolyfill-spec.js => MapPolyfill-spec.ts} (53%) delete mode 100644 spec/util/SymbolShim-spec.js create mode 100644 spec/util/SymbolShim-spec.ts diff --git a/spec/Notification-spec.js b/spec/Notification-spec.js deleted file mode 100644 index 6e91d2ecce..0000000000 --- a/spec/Notification-spec.js +++ /dev/null @@ -1,281 +0,0 @@ -/* globals describe, it, expect, expectObservable */ -var Rx = require('../dist/cjs/Rx'); - -var Notification = Rx.Notification; - -describe('Notification', function () { - it('should exist', function () { - expect(Notification).toBeDefined(); - expect(typeof Notification).toBe('function'); - }); - - describe('createNext', function () { - it('should return a Notification', function () { - var n = Notification.createNext('test'); - expect(n instanceof Notification).toBe(true); - expect(n.value).toBe('test'); - expect(n.kind).toBe('N'); - expect(typeof n.exception).toBe('undefined'); - expect(n.hasValue).toBe(true); - }); - }); - - describe('createError', function () { - it('should return a Notification', function () { - var n = Notification.createError('test'); - expect(n instanceof Notification).toBe(true); - expect(typeof n.value).toBe('undefined'); - expect(n.kind).toBe('E'); - expect(n.exception).toBe('test'); - expect(n.hasValue).toBe(false); - }); - }); - - describe('createComplete', function () { - it('should return a Notification', function () { - var n = Notification.createComplete(); - expect(n instanceof Notification).toBe(true); - expect(typeof n.value).toBe('undefined'); - expect(n.kind).toBe('C'); - expect(typeof n.exception).toBe('undefined'); - expect(n.hasValue).toBe(false); - }); - }); - - describe('toObservable', function () { - it('should create observable from a next Notification', function () { - var value = 'a'; - var next = Notification.createNext(value); - expectObservable(next.toObservable()).toBe('(a|)'); - }); - - it('should create observable from a complete Notification', function () { - var complete = Notification.createComplete(); - expectObservable(complete.toObservable()).toBe('|'); - }); - - it('should create observable from a error Notification', function () { - var error = Notification.createError('error'); - expectObservable(error.toObservable()).toBe('#'); - }); - }); - - describe('static reference', function () { - it('should create new next Notification with value', function () { - var value = 'a'; - var first = Notification.createNext(value); - var second = Notification.createNext(value); - - expect(first).not.toBe(second); - }); - - it('should create new error Notification', function () { - var first = Notification.createError(); - var second = Notification.createError(); - - expect(first).not.toBe(second); - }); - - it('should return static next Notification reference without value', function () { - var first = Notification.createNext(undefined); - var second = Notification.createNext(undefined); - - expect(first).toBe(second); - }); - - it('should return static complete Notification reference', function () { - var first = Notification.createComplete(); - var second = Notification.createComplete(); - - expect(first).toBe(second); - }); - }); - - describe('do', function () { - it('should invoke on next', function () { - var n = Notification.createNext('a'); - var invoked = false; - n.do(function (x) { - invoked = true; - }, function (x) { - throw 'should not be called'; - }, function () { - throw 'should not be called'; - }); - - expect(invoked).toBe(true); - }); - - it('should invoke on error', function () { - var n = Notification.createError(); - var invoked = false; - n.do(function (x) { - throw 'should not be called'; - }, function (x) { - invoked = true; - }, function () { - throw 'should not be called'; - }); - - expect(invoked).toBe(true); - }); - - it('should invoke on complete', function () { - var n = Notification.createComplete(); - var invoked = false; - n.do(function (x) { - throw 'should not be called'; - }, function (x) { - throw 'should not be called'; - }, function () { - invoked = true; - }); - - expect(invoked).toBe(true); - }); - }); - - describe('accept', function () { - it('should accept observer for next Notification', function () { - var value = 'a'; - var observed = false; - var n = Notification.createNext(value); - var observer = Rx.Subscriber.create(function (x) { - expect(x).toBe(value); - observed = true; - }, function (x) { - throw 'should not be called'; - }, function () { - throw 'should not be called'; - }); - - n.accept(observer); - expect(observed).toBe(true); - }); - - it('should accept observer for error Notification', function () { - var observed = false; - var n = Notification.createError(); - var observer = Rx.Subscriber.create(function (x) { - throw 'should not be called'; - }, function (x) { - observed = true; - }, function () { - throw 'should not be called'; - }); - - n.accept(observer); - expect(observed).toBe(true); - }); - - it('should accept observer for complete Notification', function () { - var observed = false; - var n = Notification.createComplete(); - var observer = Rx.Subscriber.create(function (x) { - throw 'should not be called'; - }, function (x) { - throw 'should not be called'; - }, function () { - observed = true; - }); - - n.accept(observer); - expect(observed).toBe(true); - }); - - it('should accept function for next Notification', function () { - var value = 'a'; - var observed = false; - var n = Notification.createNext(value); - - n.accept(function (x) { - expect(x).toBe(value); - observed = true; - }, function (x) { - throw 'should not be called'; - }, function () { - throw 'should not be called'; - }); - expect(observed).toBe(true); - }); - - it('should accept function for error Notification', function () { - var observed = false; - var error = 'error'; - var n = Notification.createError(error); - - n.accept(function (x) { - throw 'should not be called'; - }, function (x) { - expect(x).toBe(error); - observed = true; - }, function () { - throw 'should not be called'; - }); - expect(observed).toBe(true); - }); - - it('should accept function for complete Notification', function () { - var observed = false; - var n = Notification.createComplete(); - - n.accept(function (x) { - throw 'should not be called'; - }, function (x) { - throw 'should not be called'; - }, function () { - observed = true; - }); - expect(observed).toBe(true); - }); - }); - - describe('observe', function () { - it('should observe for next Notification', function () { - var value = 'a'; - var observed = false; - var n = Notification.createNext(value); - var observer = Rx.Subscriber.create(function (x) { - expect(x).toBe(value); - observed = true; - }, function (x) { - throw 'should not be called'; - }, function () { - throw 'should not be called'; - }); - - n.observe(observer); - expect(observed).toBe(true); - }); - - it('should observe for error Notification', function () { - var observed = false; - var n = Notification.createError(); - var observer = Rx.Subscriber.create(function (x) { - throw 'should not be called'; - }, function (x) { - observed = true; - }, function () { - throw 'should not be called'; - }); - - n.observe(observer); - expect(observed).toBe(true); - }); - - it('should observe for complete Notification', function () { - var observed = false; - var n = Notification.createComplete(); - var observer = Rx.Subscriber.create(function (x) { - throw 'should not be called'; - }, function (x) { - throw 'should not be called'; - }, function () { - observed = true; - }); - - n.observe(observer); - expect(observed).toBe(true); - }); - }); -}); diff --git a/spec/Notification-spec.ts b/spec/Notification-spec.ts new file mode 100644 index 0000000000..4e68619c0d --- /dev/null +++ b/spec/Notification-spec.ts @@ -0,0 +1,282 @@ +import * as Rx from '../dist/cjs/Rx'; +import {expectObservable} from './helpers/marble-testing'; +import {it, DoneSignature} from './helpers/test-helper'; + +const Notification = Rx.Notification; + +describe('Notification', () => { + it('should exist', () => { + expect(Notification).toBeDefined(); + expect(typeof Notification).toBe('function'); + }); + + describe('createNext', () => { + it('should return a Notification', () => { + const n = Notification.createNext('test'); + expect(n instanceof Notification).toBe(true); + expect(n.value).toBe('test'); + expect(n.kind).toBe('N'); + expect(typeof n.exception).toBe('undefined'); + expect(n.hasValue).toBe(true); + }); + }); + + describe('createError', () => { + it('should return a Notification', () => { + const n = Notification.createError('test'); + expect(n instanceof Notification).toBe(true); + expect(typeof n.value).toBe('undefined'); + expect(n.kind).toBe('E'); + expect(n.exception).toBe('test'); + expect(n.hasValue).toBe(false); + }); + }); + + describe('createComplete', () => { + it('should return a Notification', () => { + const n = Notification.createComplete(); + expect(n instanceof Notification).toBe(true); + expect(typeof n.value).toBe('undefined'); + expect(n.kind).toBe('C'); + expect(typeof n.exception).toBe('undefined'); + expect(n.hasValue).toBe(false); + }); + }); + + describe('toObservable', () => { + it('should create observable from a next Notification', () => { + const value = 'a'; + const next = Notification.createNext(value); + expectObservable(next.toObservable()).toBe('(a|)'); + }); + + it('should create observable from a complete Notification', () => { + const complete = Notification.createComplete(); + expectObservable(complete.toObservable()).toBe('|'); + }); + + it('should create observable from a error Notification', () => { + const error = Notification.createError('error'); + expectObservable(error.toObservable()).toBe('#'); + }); + }); + + describe('static reference', () => { + it('should create new next Notification with value', () => { + const value = 'a'; + const first = Notification.createNext(value); + const second = Notification.createNext(value); + + expect(first).not.toBe(second); + }); + + it('should create new error Notification', () => { + const first = Notification.createError(); + const second = Notification.createError(); + + expect(first).not.toBe(second); + }); + + it('should return static next Notification reference without value', () => { + const first = Notification.createNext(undefined); + const second = Notification.createNext(undefined); + + expect(first).toBe(second); + }); + + it('should return static complete Notification reference', () => { + const first = Notification.createComplete(); + const second = Notification.createComplete(); + + expect(first).toBe(second); + }); + }); + + describe('do', () => { + it('should invoke on next', () => { + const n = Notification.createNext('a'); + let invoked = false; + n.do((x: string) => { + invoked = true; + }, (err: any) => { + throw 'should not be called'; + }, () => { + throw 'should not be called'; + }); + + expect(invoked).toBe(true); + }); + + it('should invoke on error', () => { + const n = Notification.createError(); + let invoked = false; + n.do((x: any) => { + throw 'should not be called'; + }, (err: any) => { + invoked = true; + }, () => { + throw 'should not be called'; + }); + + expect(invoked).toBe(true); + }); + + it('should invoke on complete', () => { + const n = Notification.createComplete(); + let invoked = false; + n.do((x: any) => { + throw 'should not be called'; + }, (err: any) => { + throw 'should not be called'; + }, () => { + invoked = true; + }); + + expect(invoked).toBe(true); + }); + }); + + describe('accept', () => { + it('should accept observer for next Notification', () => { + const value = 'a'; + let observed = false; + const n = Notification.createNext(value); + const observer = Rx.Subscriber.create((x: string) => { + expect(x).toBe(value); + observed = true; + }, (err: any) => { + throw 'should not be called'; + }, () => { + throw 'should not be called'; + }); + + n.accept(observer); + expect(observed).toBe(true); + }); + + it('should accept observer for error Notification', () => { + let observed = false; + const n = Notification.createError(); + const observer = Rx.Subscriber.create((x: string) => { + throw 'should not be called'; + }, (err: any) => { + observed = true; + }, () => { + throw 'should not be called'; + }); + + n.accept(observer); + expect(observed).toBe(true); + }); + + it('should accept observer for complete Notification', () => { + let observed = false; + const n = Notification.createComplete(); + const observer = Rx.Subscriber.create((x: string) => { + throw 'should not be called'; + }, (err: any) => { + throw 'should not be called'; + }, () => { + observed = true; + }); + + n.accept(observer); + expect(observed).toBe(true); + }); + + it('should accept function for next Notification', () => { + const value = 'a'; + let observed = false; + const n = Notification.createNext(value); + + n.accept((x: string) => { + expect(x).toBe(value); + observed = true; + }, (err: any) => { + throw 'should not be called'; + }, () => { + throw 'should not be called'; + }); + expect(observed).toBe(true); + }); + + it('should accept function for error Notification', () => { + let observed = false; + const error = 'error'; + const n = Notification.createError(error); + + n.accept((x: any) => { + throw 'should not be called'; + }, (err: any) => { + expect(err).toBe(error); + observed = true; + }, () => { + throw 'should not be called'; + }); + expect(observed).toBe(true); + }); + + it('should accept function for complete Notification', () => { + let observed = false; + const n = Notification.createComplete(); + + n.accept((x: any) => { + throw 'should not be called'; + }, (err: any) => { + throw 'should not be called'; + }, () => { + observed = true; + }); + expect(observed).toBe(true); + }); + }); + + describe('observe', () => { + it('should observe for next Notification', () => { + const value = 'a'; + let observed = false; + const n = Notification.createNext(value); + const observer = Rx.Subscriber.create((x: string) => { + expect(x).toBe(value); + observed = true; + }, (err: any) => { + throw 'should not be called'; + }, () => { + throw 'should not be called'; + }); + + n.observe(observer); + expect(observed).toBe(true); + }); + + it('should observe for error Notification', () => { + let observed = false; + const n = Notification.createError(); + const observer = Rx.Subscriber.create((x: any) => { + throw 'should not be called'; + }, (err: any) => { + observed = true; + }, () => { + throw 'should not be called'; + }); + + n.observe(observer); + expect(observed).toBe(true); + }); + + it('should observe for complete Notification', () => { + let observed = false; + const n = Notification.createComplete(); + const observer = Rx.Subscriber.create((x: any) => { + throw 'should not be called'; + }, (err: any) => { + throw 'should not be called'; + }, () => { + observed = true; + }); + + n.observe(observer); + expect(observed).toBe(true); + }); + }); +}); diff --git a/spec/Observable-spec.js b/spec/Observable-spec.ts similarity index 53% rename from spec/Observable-spec.js rename to spec/Observable-spec.ts index f40ce26ebd..c77472d81d 100644 --- a/spec/Observable-spec.js +++ b/spec/Observable-spec.ts @@ -1,8 +1,11 @@ -/* globals describe, it, expect */ -var Rx = require('../dist/cjs/Rx'); -var Promise = require('promise'); -var Subscriber = Rx.Subscriber; -var Observable = Rx.Observable; +import * as Rx from '../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from './helpers/marble-testing'; +import {it, DoneSignature} from './helpers/test-helper'; + +const Subscriber = Rx.Subscriber; +const Observable = Rx.Observable; + +declare var __root__: any; function expectFullObserver(val) { expect(typeof val).toBe('object'); @@ -12,9 +15,9 @@ function expectFullObserver(val) { expect(typeof val.isUnsubscribed).toBe('boolean'); } -describe('Observable', function () { - it('should be constructed with a subscriber function', function (done) { - var source = new Observable(function (observer) { +describe('Observable', () => { + it('should be constructed with a subscriber function', (done: DoneSignature) => { + const source = new Observable(function (observer) { expectFullObserver(observer); observer.next(1); observer.complete(); @@ -23,10 +26,10 @@ describe('Observable', function () { source.subscribe(function (x) { expect(x).toBe(1); }, null, done); }); - describe('forEach', function () { - it('should iterate and return a Promise', function (done) { - var expected = [1,2,3]; - var result = Observable.of(1,2,3).forEach(function (x) { + describe('forEach', () => { + it('should iterate and return a Promise', (done: DoneSignature) => { + const expected = [1,2,3]; + const result = Observable.of(1,2,3).forEach(function (x) { expect(x).toBe(expected.shift()); }, null, Promise) .then(done); @@ -34,19 +37,20 @@ describe('Observable', function () { expect(typeof result.then).toBe('function'); }); - it('should reject promise when in error', function (done) { - Observable.throw('bad').forEach(function (x) { + it('should reject promise when in error', (done: DoneSignature) => { + Observable.throw('bad').forEach((x: any) => { done.fail('should not be called'); - }, null, Promise).then(function () { + }, null, Promise).then(() => { done.fail('should not complete'); - }, function (err) { + }, (err: any) => { expect(err).toBe('bad'); done(); - }, null, Promise); + }); }); - it('should allow Promise to be globally configured', function (done) { - var wasCalled = false; + it('should allow Promise to be globally configured', (done: DoneSignature) => { + let wasCalled = false; + __root__.Rx = {}; __root__.Rx.config = {}; __root__.Rx.config.Promise = function MyPromise(callback) { @@ -54,18 +58,18 @@ describe('Observable', function () { return new Promise(callback); }; - Observable.of(42).forEach(function (x) { + Observable.of(42).forEach((x: number) => { expect(x).toBe(42); - }).then(function () { + }, null).then(() => { expect(wasCalled).toBe(true); done(); }); }); - it('should accept a thisArg argument', function (done) { - var expected = [1,2,3]; - var thisArg = {}; - var result = Observable.of(1,2,3).forEach(function (x) { + it('should accept a thisArg argument', (done: DoneSignature) => { + const expected = [1,2,3]; + const thisArg = {}; + const result = Observable.of(1,2,3).forEach(function (x) { expect(this).toBe(thisArg); expect(x).toBe(expected.shift()); }, thisArg, Promise) @@ -74,15 +78,15 @@ describe('Observable', function () { expect(typeof result.then).toBe('function'); }); - it('should reject promise if nextHandler throws', function (done) { - var results = []; - Observable.of(1,2,3).forEach(function (x) { + it('should reject promise if nextHandler throws', (done: DoneSignature) => { + const results = []; + Observable.of(1,2,3).forEach((x: number) => { if (x === 3) { throw new Error('NO THREES!'); } results.push(x); - }) - .then(done.fail, function (err) { + }, null) + .then(done.fail, function (err) { expect(err).toEqual(new Error('NO THREES!')); expect(results).toEqual([1,2]); }) @@ -90,27 +94,28 @@ describe('Observable', function () { }); }); - describe('subscribe', function () { - it('should be synchronous', function () { - var subscribed = false; - var nexted; - var completed; - var source = new Observable(function (observer) { + describe('subscribe', () => { + it('should be synchronous', () => { + let subscribed = false; + let nexted; + let completed; + const source = new Observable((observer: Rx.Observer) => { subscribed = true; observer.next('wee'); expect(nexted).toBe('wee'); observer.complete(); expect(completed).toBe(true); }); + expect(subscribed).toBe(false); - var mutatedByNext = false; - var mutatedByComplete = false; + let mutatedByNext = false; + let mutatedByComplete = false; - source.subscribe(function (x) { + source.subscribe((x: string) => { nexted = x; mutatedByNext = true; - }, null, function () { + }, null, () => { completed = true; mutatedByComplete = true; }); @@ -119,8 +124,8 @@ describe('Observable', function () { expect(mutatedByComplete).toBe(true); }); - it('should work when subscribe is called with no arguments', function () { - var source = new Observable(function (subscriber) { + it('should work when subscribe is called with no arguments', () => { + const source = new Observable((subscriber: Rx.Subscriber) => { subscriber.next('foo'); subscriber.complete(); }); @@ -128,16 +133,16 @@ describe('Observable', function () { source.subscribe(); }); - it('should return a Subscription that calls the unsubscribe function returned by the subscriber', function () { - var unsubscribeCalled = false; + it('should return a Subscription that calls the unsubscribe function returned by the subscriber', () => { + let unsubscribeCalled = false; - var source = new Observable(function () { - return function () { + const source = new Observable(() => { + return () => { unsubscribeCalled = true; }; }); - var sub = source.subscribe(function () { }); + const sub = source.subscribe(() => { }); expect(sub instanceof Rx.Subscription).toBe(true); expect(unsubscribeCalled).toBe(false); expect(typeof sub.unsubscribe).toBe('function'); @@ -146,21 +151,21 @@ describe('Observable', function () { expect(unsubscribeCalled).toBe(true); }); - it('should run unsubscription logic when an error is thrown sending messages synchronously', function () { - var messageError = false; - var messageErrorValue = false; - var unsubscribeCalled = false; + it('should run unsubscription logic when an error is thrown sending messages synchronously', () => { + let messageError = false; + let messageErrorValue = false; + let unsubscribeCalled = false; - var sub; - var source = new Observable(function (observer) { + let sub; + const source = new Observable((observer: Rx.Observer) => { observer.next('boo!'); - return function () { + return () => { unsubscribeCalled = true; }; }); try { - sub = source.subscribe(function (x) { throw x; }); + sub = source.subscribe((x: string) => { throw x; }); } catch (e) { messageError = true; messageErrorValue = e; @@ -172,16 +177,16 @@ describe('Observable', function () { expect(messageErrorValue).toBe('boo!'); }); - it('should dispose of the subscriber when an error is thrown sending messages synchronously', function () { - var messageError = false; - var messageErrorValue = false; - var unsubscribeCalled = false; + it('should dispose of the subscriber when an error is thrown sending messages synchronously', () => { + let messageError = false; + let messageErrorValue = false; + let unsubscribeCalled = false; - var sub; - var subscriber = new Subscriber(function (x) { throw x; }); - var source = new Observable(function (observer) { + let sub; + const subscriber = new Subscriber((x: string) => { throw x; }); + const source = new Observable((observer: Rx.Observer) => { observer.next('boo!'); - return function () { + return () => { unsubscribeCalled = true; }; }); @@ -200,62 +205,72 @@ describe('Observable', function () { expect(messageErrorValue).toBe('boo!'); }); - describe('when called with an anonymous observer', function () { + describe('when called with an anonymous observer', () => { it('should accept an anonymous observer with just a next function and call the next function in the context' + - ' of the anonymous observer', function () { + ' of the anonymous observer', (done: DoneSignature) => { + //intentionally not using lambda to avoid typescript's this context capture var o = { next: function next(x) { expect(this).toBe(o); expect(x).toBe(1); + done(); } }; + Observable.of(1).subscribe(o); }); it('should accept an anonymous observer with just an error function and call the error function in the context' + - ' of the anonymous observer', function () { + ' of the anonymous observer', (done: DoneSignature) => { + //intentionally not using lambda to avoid typescript's this context capture var o = { error: function error(err) { expect(this).toBe(o); expect(err).toBe('bad'); + done(); } }; + Observable.throw('bad').subscribe(o); }); it('should accept an anonymous observer with just a complete function and call the complete function in the' + - ' context of the anonymous observer', function (done) { - var o = { + ' context of the anonymous observer', (done: DoneSignature) => { + //intentionally not using lambda to avoid typescript's this context capture + var o = { complete: function complete() { expect(this).toBe(o); done(); } }; + Observable.empty().subscribe(o); }); - it('should accept an anonymous observer with no functions at all', function () { - expect(function testEmptyObject() { - Observable.empty().subscribe({}); + it('should accept an anonymous observer with no functions at all', () => { + expect(() => { + Observable.empty().subscribe({}); }).not.toThrow(); }); it('should not run unsubscription logic when an error is thrown sending messages synchronously to an' + - ' anonymous observer', function () { - var messageError = false; - var messageErrorValue = false; - var unsubscribeCalled = false; + ' anonymous observer', () => { + let messageError = false; + let messageErrorValue = false; + let unsubscribeCalled = false; + //intentionally not using lambda to avoid typescript's this context capture var o = { next: function next(x) { expect(this).toBe(o); throw x; } }; - var sub; - var source = new Observable(function (observer) { + + let sub; + const source = new Observable((observer: Rx.Observer) => { observer.next('boo!'); - return function () { + return () => { unsubscribeCalled = true; }; }); @@ -276,50 +291,47 @@ describe('Observable', function () { }); }); -describe('Observable.create', function () { - it('should create an Observable', function () { - var result = Observable.create(function () { }); +describe('Observable.create', () => { + it('should create an Observable', () => { + const result = Observable.create(() => { }); expect(result instanceof Observable).toBe(true); }); - it('should provide an observer to the function', function () { - var called = false; - var result = Observable.create(function (observer) { + it('should provide an observer to the function', () => { + let called = false; + const result = Observable.create((observer: Rx.Observer) => { called = true; expectFullObserver(observer); observer.complete(); }); expect(called).toBe(false); - result.subscribe(function () { }); + result.subscribe(() => { }); expect(called).toBe(true); }); }); -describe('Observable.lift', function () { - it('should be overrideable in a custom Observable type that composes', function (done) { - function MyCustomObservable() { - Observable.apply(this, arguments); +describe('Observable.lift', () => { + it('should be overrideable in a custom Observable type that composes', (done: DoneSignature) => { + class MyCustomObservable extends Rx.Observable{ + lift(operator: Rx.Operator): Rx.Observable { + const observable = new MyCustomObservable(); + (observable).source = this; + (observable).operator = operator; + return observable; + } } - MyCustomObservable.prototype = Object.create(Observable.prototype); - MyCustomObservable.prototype.constructor = MyCustomObservable; - MyCustomObservable.prototype.lift = function (operator) { - var obs = new MyCustomObservable(); - obs.source = this; - obs.operator = operator; - return obs; - }; - - var result = new MyCustomObservable(function (observer) { + + const result = new MyCustomObservable((observer: Rx.Observer) => { observer.next(1); observer.next(2); observer.next(3); observer.complete(); - }).map(function (x) { return 10 * x; }); + }).map((x: number) => { return 10 * x; }); expect(result instanceof MyCustomObservable).toBe(true); - var expected = [10, 20, 30]; + const expected = [10, 20, 30]; result.subscribe( function (x) { @@ -330,61 +342,61 @@ describe('Observable.lift', function () { }); it('should allow injecting behaviors into all subscribers in an operator ' + - 'chain when overridden', function (done) { + 'chain when overridden', (done: DoneSignature) => { // The custom Subscriber - var log = []; - function LogSubscriber() { - Subscriber.apply(this, arguments); + const log: Array = []; + + class LogSubscriber extends Rx.Subscriber { + next(value?: T): void { + log.push('next ' + value); + if (!this.isStopped) { + this._next(value); + } + } } - LogSubscriber.prototype = Object.create(Subscriber.prototype); - LogSubscriber.prototype.constructor = LogSubscriber; - LogSubscriber.prototype.next = function (x) { - log.push('next ' + x); - this.destination.next(x); - }; // The custom Operator - function LogOperator(childOperator) { - this.childOperator = childOperator; + class LogOperator extends Rx.Operator { + constructor(private childOperator: Rx.Operator) { + super(); + } + + call(subscriber: Rx.Subscriber): Rx.Subscriber { + return this.childOperator.call(new LogSubscriber(subscriber)); + } } - LogOperator.prototype.call = function (subscriber) { - return this.childOperator.call(new LogSubscriber(subscriber)); - }; // The custom Observable - function LogObservable() { - Observable.apply(this, arguments); + class LogObservable extends Observable { + lift(operator: Rx.Operator): Rx.Observable { + const observable = new LogObservable(); + (observable).source = this; + (observable).operator = new LogOperator(operator); + return observable; + } } - LogObservable.prototype = Object.create(Observable.prototype); - LogObservable.prototype.constructor = LogObservable; - LogObservable.prototype.lift = function (operator) { - var obs = new LogObservable(); - obs.source = this; - obs.operator = new LogOperator(operator); - return obs; - }; // Use the LogObservable - var result = new LogObservable(function (observer) { + const result = new LogObservable((observer: Rx.Observer) => { observer.next(1); observer.next(2); observer.next(3); observer.complete(); }) - .map(function (x) { return 10 * x; }) - .filter(function (x) { return x > 15; }) + .map((x: number) => { return 10 * x; }) + .filter((x: number) => { return x > 15; }) .count(); expect(result instanceof LogObservable).toBe(true); - var expected = [2]; + const expected = [2]; result.subscribe( function (x) { expect(x).toBe(expected.shift()); }, done.fail, - function () { + () => { expect(log).toEqual([ 'next 10', // map 'next 20', // map diff --git a/spec/Scheduler-spec.js b/spec/Scheduler-spec.js deleted file mode 100644 index 3aac013c0b..0000000000 --- a/spec/Scheduler-spec.js +++ /dev/null @@ -1,36 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../dist/cjs/Rx'); - -var Scheduler = Rx.Scheduler; - -describe('Scheduler.queue', function () { - it('should schedule things recursively', function () { - var call1 = false; - var call2 = false; - Scheduler.queue.active = false; - Scheduler.queue.schedule(function () { - call1 = true; - Scheduler.queue.schedule(function () { - call2 = true; - }); - }); - expect(call1).toBe(true); - expect(call2).toBe(true); - }); - - it('should schedule things in the future too', function (done) { - var called = false; - Scheduler.queue.schedule(function () { - called = true; - }, 50); - - setTimeout(function () { - expect(called).toBe(false); - }, 40); - - setTimeout(function () { - expect(called).toBe(true); - done(); - }, 70); - }); -}); \ No newline at end of file diff --git a/spec/Scheduler-spec.ts b/spec/Scheduler-spec.ts new file mode 100644 index 0000000000..b3018977d8 --- /dev/null +++ b/spec/Scheduler-spec.ts @@ -0,0 +1,36 @@ +import * as Rx from '../dist/cjs/Rx'; +import {it, DoneSignature} from './helpers/test-helper'; + +const Scheduler = Rx.Scheduler; + +describe('Scheduler.queue', () => { + it('should schedule things recursively', () => { + let call1 = false; + let call2 = false; + Scheduler.queue.active = false; + Scheduler.queue.schedule(() => { + call1 = true; + Scheduler.queue.schedule(() => { + call2 = true; + }); + }); + expect(call1).toBe(true); + expect(call2).toBe(true); + }); + + it('should schedule things in the future too', (done: DoneSignature) => { + let called = false; + Scheduler.queue.schedule(() => { + called = true; + }, 50); + + setTimeout(() => { + expect(called).toBe(false); + }, 40); + + setTimeout(() => { + expect(called).toBe(true); + done(); + }, 70); + }); +}); \ No newline at end of file diff --git a/spec/Subject-spec.js b/spec/Subject-spec.ts similarity index 59% rename from spec/Subject-spec.js rename to spec/Subject-spec.ts index dff48247e6..6db731037e 100644 --- a/spec/Subject-spec.js +++ b/spec/Subject-spec.ts @@ -1,16 +1,17 @@ -/* globals describe, it, expect, hot, expectObservable */ -var Rx = require('../dist/cjs/Rx'); +import * as Rx from '../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from './helpers/marble-testing'; +import {it, DoneSignature} from './helpers/test-helper'; -var Subject = Rx.Subject; -var asap = Rx.Scheduler.asap; -var Observable = Rx.Observable; +const Subject = Rx.Subject; +const asap = Rx.Scheduler.asap; +const Observable = Rx.Observable; -describe('Subject', function () { - it('should pump values right on through itself', function (done) { - var subject = new Subject(); - var expected = ['foo', 'bar']; +describe('Subject', () => { + it('should pump values right on through itself', (done: DoneSignature) => { + const subject = new Subject(); + const expected = ['foo', 'bar']; - subject.subscribe(function (x) { + subject.subscribe((x: string) => { expect(x).toBe(expected.shift()); }, null, done); @@ -19,16 +20,17 @@ describe('Subject', function () { subject.complete(); }); - it('should have the rxSubscriber Symbol', function () { - var subject = new Subject(); + it('should have the rxSubscriber Symbol', () => { + const subject = new Subject(); expect(typeof subject[Rx.Symbol.rxSubscriber]).toBe('function'); }); - it('should pump values to multiple subscribers', function (done) { - var subject = new Subject(); - var expected = ['foo', 'bar']; - var i = 0; - var j = 0; + it('should pump values to multiple subscribers', (done: DoneSignature) => { + const subject = new Subject(); + const expected = ['foo', 'bar']; + + let i = 0; + let j = 0; subject.subscribe(function (x) { expect(x).toBe(expected[i++]); @@ -45,29 +47,29 @@ describe('Subject', function () { }); it('should handle subscribers that arrive and leave at different times, ' + - 'subject does not complete', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; - var results3 = []; + 'subject does not complete', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; + const results3 = []; subject.next(1); subject.next(2); subject.next(3); subject.next(4); - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); subject.next(5); - var subscription2 = subject.subscribe( + const subscription2 = subject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subject.next(6); @@ -82,10 +84,10 @@ describe('Subject', function () { subject.next(9); subject.next(10); - var subscription3 = subject.subscribe( + const subscription3 = subject.subscribe( function (x) { results3.push(x); }, function (e) { results3.push('E'); }, - function () { results3.push('C'); } + () => { results3.push('C'); } ); subject.next(11); @@ -98,29 +100,29 @@ describe('Subject', function () { }); it('should handle subscribers that arrive and leave at different times, ' + - 'subject completes', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; - var results3 = []; + 'subject completes', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; + const results3 = []; subject.next(1); subject.next(2); subject.next(3); subject.next(4); - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); subject.next(5); - var subscription2 = subject.subscribe( + const subscription2 = subject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subject.next(6); @@ -132,10 +134,10 @@ describe('Subject', function () { subscription2.unsubscribe(); - var subscription3 = subject.subscribe( + const subscription3 = subject.subscribe( function (x) { results3.push(x); }, function (e) { results3.push('E'); }, - function () { results3.push('C'); } + () => { results3.push('C'); } ); subscription3.unsubscribe(); @@ -146,29 +148,29 @@ describe('Subject', function () { }); it('should handle subscribers that arrive and leave at different times, ' + - 'subject terminates with an error', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; - var results3 = []; + 'subject terminates with an error', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; + const results3 = []; subject.next(1); subject.next(2); subject.next(3); subject.next(4); - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); subject.next(5); - var subscription2 = subject.subscribe( + const subscription2 = subject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subject.next(6); @@ -180,10 +182,10 @@ describe('Subject', function () { subscription2.unsubscribe(); - var subscription3 = subject.subscribe( + const subscription3 = subject.subscribe( function (x) { results3.push(x); }, function (e) { results3.push('E'); }, - function () { results3.push('C'); } + () => { results3.push('C'); } ); subscription3.unsubscribe(); @@ -194,22 +196,22 @@ describe('Subject', function () { }); it('should handle subscribers that arrive and leave at different times, ' + - 'subject completes before nexting any value', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; - var results3 = []; + 'subject completes before nexting any value', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; + const results3 = []; - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); - var subscription2 = subject.subscribe( + const subscription2 = subject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subscription1.unsubscribe(); @@ -218,10 +220,10 @@ describe('Subject', function () { subscription2.unsubscribe(); - var subscription3 = subject.subscribe( + const subscription3 = subject.subscribe( function (x) { results3.push(x); }, function (e) { results3.push('E'); }, - function () { results3.push('C'); } + () => { results3.push('C'); } ); subscription3.unsubscribe(); @@ -231,25 +233,25 @@ describe('Subject', function () { expect(results3).toEqual(['C']); }); - it('should disallow new subscriber once subject has been disposed', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; - var results3 = []; + it('should disallow new subscriber once subject has been disposed', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; + const results3 = []; - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); subject.next(1); subject.next(2); - var subscription2 = subject.subscribe( + const subscription2 = subject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subject.next(3); @@ -260,11 +262,11 @@ describe('Subject', function () { subscription2.unsubscribe(); subject.unsubscribe(); - expect(function () { - var subscription3 = subject.subscribe( + expect(() => { + const subscription3 = subject.subscribe( function (x) { results3.push(x); }, function (e) { results3.push('E'); }, - function () { results3.push('C'); } + () => { results3.push('C'); } ); }).toThrow(); @@ -273,22 +275,22 @@ describe('Subject', function () { expect(results3).toEqual([]); }); - it('should allow ad-hoc subscription to be added to itself', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; + it('should allow ad-hoc subscription to be added to itself', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; - var auxSubject = new Subject(); + const auxSubject = new Subject(); - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); - var subscription2 = auxSubject.subscribe( + const subscription2 = auxSubject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subject.add(subscription2); @@ -310,22 +312,22 @@ describe('Subject', function () { expect(results2).toEqual(['a','b']); }); - it('should allow ad-hoc subscription to be removed from itself', function () { - var subject = new Subject(); - var results1 = []; - var results2 = []; + it('should allow ad-hoc subscription to be removed from itself', () => { + const subject = new Subject(); + const results1 = []; + const results2 = []; - var auxSubject = new Subject(); + const auxSubject = new Subject(); - var subscription1 = subject.subscribe( + const subscription1 = subject.subscribe( function (x) { results1.push(x); }, function (e) { results1.push('E'); }, - function () { results1.push('C'); } + () => { results1.push('C'); } ); - var subscription2 = auxSubject.subscribe( + const subscription2 = auxSubject.subscribe( function (x) { results2.push(x); }, function (e) { results2.push('E'); }, - function () { results2.push('C'); } + () => { results2.push('C'); } ); subject.add(subscription2); @@ -348,9 +350,9 @@ describe('Subject', function () { expect(results2).toEqual(['a','b','c','d']); }); - it('should not allow values to be nexted after a return', function (done) { - var subject = new Subject(); - var expected = ['foo']; + it('should not allow values to be nexted after a return', (done: DoneSignature) => { + const subject = new Subject(); + const expected = ['foo']; subject.subscribe(function (x) { expect(x).toBe(expected.shift()); @@ -361,13 +363,13 @@ describe('Subject', function () { subject.next('bar'); }); - it('should clean out unsubscribed subscribers', function (done) { - var subject = new Subject(); + it('should clean out unsubscribed subscribers', (done: DoneSignature) => { + const subject = new Subject(); - var sub1 = subject.subscribe(function (x) { + const sub1 = subject.subscribe(function (x) { }); - var sub2 = subject.subscribe(function (x) { + const sub2 = subject.subscribe(function (x) { }); expect(subject.observers.length).toBe(2); @@ -378,16 +380,17 @@ describe('Subject', function () { done(); }); - it('should have a static create function that works', function () { + it('should have a static create function that works', () => { expect(typeof Subject.create).toBe('function'); - var source = Observable.of(1,2,3,4,5); - var nexts = []; - var error; - var complete = false; - var output = []; - var outputComplete = false; - - var destination = { + const source = Observable.of(1,2,3,4,5); + const nexts = []; + const output = []; + + let error: any; + let complete = false; + let outputComplete = false; + + const destination = { isUnsubscribed: false, next: function (x) { nexts.push(x); @@ -396,17 +399,17 @@ describe('Subject', function () { error = err; this.isUnsubscribed = true; }, - complete: function () { + complete: () => { complete = true; this.isUnsubscribed = true; } }; - var sub = Subject.create(destination, source); + const sub = Subject.create(destination, source); sub.subscribe(function (x) { output.push(x); - }, null, function () { + }, null, () => { outputComplete = true; }); @@ -423,16 +426,17 @@ describe('Subject', function () { expect(outputComplete).toBe(true); }); - it('should have a static create function that works also to raise errors', function () { + it('should have a static create function that works also to raise errors', () => { expect(typeof Subject.create).toBe('function'); - var source = Observable.of(1,2,3,4,5); - var nexts = []; - var error; - var complete = false; - var output = []; - var outputComplete = false; - - var destination = { + const source = Observable.of(1,2,3,4,5); + const nexts = []; + const output = []; + + let error: any; + let complete = false; + let outputComplete = false; + + const destination = { isUnsubscribed: false, next: function (x) { nexts.push(x); @@ -441,17 +445,17 @@ describe('Subject', function () { error = err; this.isUnsubscribed = true; }, - complete: function () { + complete: () => { complete = true; this.isUnsubscribed = true; } }; - var sub = Subject.create(destination, source); + const sub = Subject.create(destination, source); sub.subscribe(function (x) { output.push(x); - }, null, function () { + }, null, () => { outputComplete = true; }); @@ -468,10 +472,10 @@ describe('Subject', function () { expect(outputComplete).toBe(true); }); - it('should be an Observer which can be given to Observable.subscribe', function (done) { - var source = Observable.of(1, 2, 3, 4, 5); - var subject = new Subject(); - var expected = [1, 2, 3, 4, 5]; + it('should be an Observer which can be given to Observable.subscribe', (done: DoneSignature) => { + const source = Observable.of(1, 2, 3, 4, 5); + const subject = new Subject(); + const expected = [1, 2, 3, 4, 5]; subject.subscribe( function (x) { @@ -484,11 +488,11 @@ describe('Subject', function () { source.subscribe(subject); }); - it('should be usable as an Observer of a finite delayed Observable', function (done) { - var source = Rx.Observable.of(1, 2, 3).delay(50); - var subject = new Rx.Subject(); + it('should be usable as an Observer of a finite delayed Observable', (done: DoneSignature) => { + const source = Rx.Observable.of(1, 2, 3).delay(50); + const subject = new Rx.Subject(); - var expected = [1, 2, 3]; + const expected = [1, 2, 3]; subject.subscribe( function (x) { @@ -500,61 +504,61 @@ describe('Subject', function () { source.subscribe(subject); }); - it('should throw ObjectUnsubscribedError when emit after unsubscribed', function () { - var subject = new Rx.Subject(); + it('should throw ObjectUnsubscribedError when emit after unsubscribed', () => { + const subject = new Rx.Subject(); subject.unsubscribe(); - expect(function () { + expect(() => { subject.next('a'); }).toThrow(new Rx.ObjectUnsubscribedError()); - expect(function () { + expect(() => { subject.error('a'); }).toThrow(new Rx.ObjectUnsubscribedError()); - expect(function () { + expect(() => { subject.complete(); }).toThrow(new Rx.ObjectUnsubscribedError()); }); - it('should throw ObjectUnsubscribedError when emit after completed', function () { - var subject = new Rx.Subject(); + it('should throw ObjectUnsubscribedError when emit after completed', () => { + const subject = new Rx.Subject(); subject.complete(); - expect(function () { + expect(() => { subject.next('a'); }).toThrow(new Rx.ObjectUnsubscribedError()); - expect(function () { + expect(() => { subject.error('a'); }).toThrow(new Rx.ObjectUnsubscribedError()); - expect(function () { + expect(() => { subject.complete(); }).toThrow(new Rx.ObjectUnsubscribedError()); }); - it('should throw ObjectUnsubscribedError when emit after error', function () { - var subject = new Rx.Subject(); + it('should throw ObjectUnsubscribedError when emit after error', () => { + const subject = new Rx.Subject(); subject.error('e'); - expect(function () { + expect(() => { subject.next('a'); }).toThrow(new Rx.ObjectUnsubscribedError()); - expect(function () { + expect(() => { subject.error('a'); }).toThrow(new Rx.ObjectUnsubscribedError()); - expect(function () { + expect(() => { subject.complete(); }).toThrow(new Rx.ObjectUnsubscribedError()); }); - describe('asObservable', function () { - it('should hide subject', function () { - var subject = new Rx.Subject(); - var observable = subject.asObservable(); + describe('asObservable', () => { + it('should hide subject', () => { + const subject = new Rx.Subject(); + const observable = subject.asObservable(); expect(subject).not.toEqual(observable); @@ -562,66 +566,66 @@ describe('Subject', function () { expect(observable instanceof Subject).toBe(false); }); - it('should handle subject never emits', function () { - var observable = hot('-').asObservable(); + it('should handle subject never emits', () => { + const observable = hot('-').asObservable(); - expectObservable(observable).toBe([]); + expectObservable(observable).toBe([]); }); - it('should handle subject completes without emits', function () { - var observable = hot('--^--|').asObservable(); - var expected = '---|'; + it('should handle subject completes without emits', () => { + const observable = hot('--^--|').asObservable(); + const expected = '---|'; expectObservable(observable).toBe(expected); }); - it('should handle subject throws', function () { - var observable = hot('--^--#').asObservable(); - var expected = '---#'; + it('should handle subject throws', () => { + const observable = hot('--^--#').asObservable(); + const expected = '---#'; expectObservable(observable).toBe(expected); }); - it('should handle subject emits', function () { - var observable = hot('--^--x--|').asObservable(); - var expected = '---x--|'; + it('should handle subject emits', () => { + const observable = hot('--^--x--|').asObservable(); + const expected = '---x--|'; expectObservable(observable).toBe(expected); }); - it('should work with inherited subject', function (done) { - var subject = new Rx.AsyncSubject(); + it('should work with inherited subject', (done: DoneSignature) => { + const subject = new Rx.AsyncSubject(); subject.next(42); subject.complete(); - var observable = subject.asObservable(); + const observable = subject.asObservable(); - var expected = [new Rx.Notification('N', 42), + const expected = [new Rx.Notification('N', 42), new Rx.Notification('C')]; - observable.materialize().subscribe(function (x) { + observable.materialize().subscribe((x: Rx.Notification) => { expect(x).toEqual(expected.shift()); - }, function (err) { + }, (err: any) => { done.fail(err); - }, function () { + }, () => { expect(expected).toEqual([]); done(); }); }); - it('should not eager', function () { - var subscribed = false; + it('should not eager', () => { + let subscribed = false; - var subject = new Rx.Subject(null, new Rx.Observable(function (observer) { + const subject = new Rx.Subject(null, new Rx.Observable((observer: Rx.Observer) => { subscribed = true; - var subscription = Rx.Observable.of('x').subscribe(observer); - return function () { + const subscription = Rx.Observable.of('x').subscribe(observer); + return () => { subscription.unsubscribe(); }; })); - var observable = subject.asObservable(); + const observable = subject.asObservable(); expect(subscribed).toBe(false); observable.subscribe(); diff --git a/spec/Subscriber-spec.js b/spec/Subscriber-spec.js deleted file mode 100644 index 969dc48ce9..0000000000 --- a/spec/Subscriber-spec.js +++ /dev/null @@ -1,35 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../dist/cjs/Rx'); -var Subscriber = Rx.Subscriber; - -describe('Subscriber', function () { - it('should have the rxSubscriber symbol', function () { - var sub = new Subscriber(); - expect(sub[Rx.Symbol.rxSubscriber]()).toBe(sub); - }); - - describe('when created through create()', function () { - it('should not call error() if next() handler throws an error', function () { - var errorSpy = jasmine.createSpy('error'); - var completeSpy = jasmine.createSpy('complete'); - - var subscriber = Subscriber.create( - function next(value) { - if (value === 2) { - throw 'error!'; - } - }, - errorSpy, - completeSpy - ); - - subscriber.next(1); - expect(function () { - subscriber.next(2); - }).toThrow('error!'); - - expect(errorSpy).not.toHaveBeenCalled(); - expect(completeSpy).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/Subscriber-spec.ts b/spec/Subscriber-spec.ts new file mode 100644 index 0000000000..9cdf3e2f46 --- /dev/null +++ b/spec/Subscriber-spec.ts @@ -0,0 +1,35 @@ +import * as Rx from '../dist/cjs/Rx'; +import {it} from './helpers/test-helper'; +const Subscriber = Rx.Subscriber; + +describe('Subscriber', () => { + it('should have the rxSubscriber symbol', () => { + const sub = new Subscriber(); + expect(sub[Rx.Symbol.rxSubscriber]()).toBe(sub); + }); + + describe('when created through create()', () => { + it('should not call error() if next() handler throws an error', () => { + const errorSpy = jasmine.createSpy('error'); + const completeSpy = jasmine.createSpy('complete'); + + const subscriber = Subscriber.create( + (value: any) => { + if (value === 2) { + throw 'error!'; + } + }, + errorSpy, + completeSpy + ); + + subscriber.next(1); + expect(() => { + subscriber.next(2); + }).toThrow('error!'); + + expect(errorSpy).not.toHaveBeenCalled(); + expect(completeSpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/Subscription-spec.js b/spec/Subscription-spec.js deleted file mode 100644 index c43a63c528..0000000000 --- a/spec/Subscription-spec.js +++ /dev/null @@ -1,79 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../dist/cjs/Rx'); -var Subscription = Rx.Subscription; -var Observable = Rx.Observable; - -describe('Subscription', function () { - it('should not leak', function (done) { - var tearDowns = []; - - var source1 = Observable.create(function (observer) { - return function () { - tearDowns.push(1); - }; - }); - - var source2 = Observable.create(function (observer) { - return function () { - tearDowns.push(2); - throw new Error('oops, I am a bad unsubscribe!'); - }; - }); - - var source3 = Observable.create(function (observer) { - return function () { - tearDowns.push(3); - }; - }); - - var subscription = Observable.merge(source1, source2, source3).subscribe(); - - setTimeout(function () { - expect(function () { - subscription.unsubscribe(); - }).toThrow(new Rx.UnsubscriptionError([new Error('oops, I am a bad unsubscribe!')])); - expect(tearDowns).toEqual([1, 2, 3]); - done(); - }); - }); - - it('should not leak when adding a bad custom subscription to a subscription', function (done) { - var tearDowns = []; - - var sub = new Subscription(); - - var source1 = Observable.create(function (observer) { - return function () { - tearDowns.push(1); - }; - }); - - var source2 = Observable.create(function (observer) { - return function () { - tearDowns.push(2); - sub.add({ - unsubscribe: function () { - expect(sub.isUnsubscribed).toBe(true); - throw new Error('Who is your daddy, and what does he do?'); - } - }); - }; - }); - - var source3 = Observable.create(function (observer) { - return function () { - tearDowns.push(3); - }; - }); - - sub.add(Observable.merge(source1, source2, source3).subscribe()); - - setTimeout(function () { - expect(function () { - sub.unsubscribe(); - }).toThrow(new Rx.UnsubscriptionError([new Error('Who is your daddy, and what does he do?')])); - expect(tearDowns).toEqual([1, 2, 3]); - done(); - }); - }); -}); \ No newline at end of file diff --git a/spec/Subscription-spec.ts b/spec/Subscription-spec.ts new file mode 100644 index 0000000000..92569fa611 --- /dev/null +++ b/spec/Subscription-spec.ts @@ -0,0 +1,80 @@ +import * as Rx from '../dist/cjs/Rx'; +import {it, DoneSignature} from './helpers/test-helper'; + +const Observable = Rx.Observable; +const Subscription = Rx.Subscription; + +describe('Subscription', () => { + it('should not leak', (done: DoneSignature) => { + const tearDowns = []; + + const source1 = Observable.create((observer: Rx.Observer) => { + return () => { + tearDowns.push(1); + }; + }); + + const source2 = Observable.create((observer: Rx.Observer) => { + return () => { + tearDowns.push(2); + throw new Error('oops, I am a bad unsubscribe!'); + }; + }); + + const source3 = Observable.create((observer: Rx.Observer) => { + return () => { + tearDowns.push(3); + }; + }); + + const subscription = Observable.merge(source1, source2, source3).subscribe(); + + setTimeout(() => { + expect(() => { + subscription.unsubscribe(); + }).toThrow(new Rx.UnsubscriptionError([new Error('oops, I am a bad unsubscribe!')])); + expect(tearDowns).toEqual([1, 2, 3]); + done(); + }); + }); + + it('should not leak when adding a bad custom subscription to a subscription', (done: DoneSignature) => { + const tearDowns = []; + + const sub = new Subscription(); + + const source1 = Observable.create((observer: Rx.Observer) => { + return () => { + tearDowns.push(1); + }; + }); + + const source2 = Observable.create((observer: Rx.Observer) => { + return () => { + tearDowns.push(2); + sub.add(({ + unsubscribe: () => { + expect(sub.isUnsubscribed).toBe(true); + throw new Error('Who is your daddy, and what does he do?'); + } + })); + }; + }); + + const source3 = Observable.create((observer: Rx.Observer) => { + return () => { + tearDowns.push(3); + }; + }); + + sub.add(Observable.merge(source1, source2, source3).subscribe()); + + setTimeout(() => { + expect(() => { + sub.unsubscribe(); + }).toThrow(new Rx.UnsubscriptionError([new Error('Who is your daddy, and what does he do?')])); + expect(tearDowns).toEqual([1, 2, 3]); + done(); + }); + }); +}); \ No newline at end of file diff --git a/spec/observables/ErrorObservable-spec.js b/spec/observables/ErrorObservable-spec.js deleted file mode 100644 index 87e20eab20..0000000000 --- a/spec/observables/ErrorObservable-spec.js +++ /dev/null @@ -1,24 +0,0 @@ -/* globals describe, it, expect, rxTestScheduler, expectObservable*/ -var Rx = require('../../dist/cjs/Rx'); -var ErrorObservable = require('../../dist/cjs/observable/ErrorObservable').ErrorObservable; -var Observable = Rx.Observable; - -describe('ErrorObservable', function () { - it('should create expose a error property', function () { - var e = new ErrorObservable('error'); - expect(e.error).toBe('error'); - }); - - it('should create ErrorObservable via static create function', function () { - var e = new ErrorObservable('error'); - var r = ErrorObservable.create('error'); - - expect(e).toEqual(r); - }); - - it('should accept scheduler', function () { - var e = ErrorObservable.create('error', rxTestScheduler); - - expectObservable(e).toBe('#'); - }); -}); diff --git a/spec/observables/ErrorObservable-spec.ts b/spec/observables/ErrorObservable-spec.ts new file mode 100644 index 0000000000..d350b24afb --- /dev/null +++ b/spec/observables/ErrorObservable-spec.ts @@ -0,0 +1,27 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {ErrorObservable} from '../../dist/cjs/observable/ErrorObservable'; +import {expectObservable} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; + +describe('ErrorObservable', () => { + it('should create expose a error property', () => { + const e = new ErrorObservable('error'); + + expect(e.error).toBe('error'); + }); + + it('should create ErrorObservable via static create function', () => { + const e = new ErrorObservable('error'); + const r = ErrorObservable.create('error'); + + expect(e).toEqual(r); + }); + + it('should accept scheduler', () => { + const e = ErrorObservable.create('error', rxTestScheduler); + + expectObservable(e).toBe('#'); + }); +}); diff --git a/spec/observables/IteratorObservable-spec.js b/spec/observables/IteratorObservable-spec.ts similarity index 55% rename from spec/observables/IteratorObservable-spec.js rename to spec/observables/IteratorObservable-spec.ts index 81813d8ef1..5a89fafca7 100644 --- a/spec/observables/IteratorObservable-spec.js +++ b/spec/observables/IteratorObservable-spec.ts @@ -1,71 +1,73 @@ -/* globals describe, it, expect, rxTestScheduler*/ -var Rx = require('../../dist/cjs/Rx'); -var IteratorObservable = require('../../dist/cjs/observable/IteratorObservable').IteratorObservable; -var Observable = Rx.Observable; - -describe('IteratorObservable', function () { - it('should create an Observable via constructor', function () { - var source = new IteratorObservable([]); +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {IteratorObservable} from '../../dist/cjs/observable/IteratorObservable'; +import {expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; + +describe('IteratorObservable', () => { + it('should create an Observable via constructor', () => { + const source = new IteratorObservable([]); expect(source instanceof IteratorObservable).toBe(true); }); - it('should create IteratorObservable via static create function', function () { - var s = new IteratorObservable([]); - var r = IteratorObservable.create([]); + it('should create IteratorObservable via static create function', () => { + const s = new IteratorObservable([]); + const r = IteratorObservable.create([]); expect(s).toEqual(r); }); - it('should not accept null (or truthy-equivalent to null) iterator', function () { - expect(function () { + it('should not accept null (or truthy-equivalent to null) iterator', () => { + expect(() => { IteratorObservable.create(null); }).toThrowError('iterator cannot be null.'); - expect(function () { + expect(() => { IteratorObservable.create(void 0); }).toThrowError('iterator cannot be null.'); }); - it('should not accept boolean as iterator', function () { - expect(function () { + it('should not accept boolean as iterator', () => { + expect(() => { IteratorObservable.create(false); }).toThrowError('Object is not iterable'); }); - it('should not accept non-function project', function () { - expect(function () { + it('should not accept non-function project', () => { + expect(() => { IteratorObservable.create([], 42); }).toThrowError('When provided, `project` must be a function.'); }); - it('should emit members of an array iterator', function (done) { - var expected = [10, 20, 30, 40]; + it('should emit members of an array iterator', (done: DoneSignature) => { + const expected = [10, 20, 30, 40]; IteratorObservable.create([10, 20, 30, 40]) .subscribe( - function (x) { expect(x).toBe(expected.shift()); }, + (x: number) => { expect(x).toBe(expected.shift()); }, done.fail, - function () { + () => { expect(expected.length).toBe(0); done(); } ); }); - it('should emit members of an array iterator on a particular scheduler', function () { - var source = IteratorObservable.create( + it('should emit members of an array iterator on a particular scheduler', () => { + const source = IteratorObservable.create( [10, 20, 30, 40], - function (x) { return x; }, + (x: number) => x, null, rxTestScheduler ); - var values = { a: 10, b: 20, c: 30, d: 40 }; + const values = { a: 10, b: 20, c: 30, d: 40 }; expectObservable(source).toBe('(abcd|)', values); }); - it('should emit members of an array iterator on a particular scheduler, project throws', function () { - var source = IteratorObservable.create( + it('should emit members of an array iterator on a particular scheduler, project throws', () => { + const source = IteratorObservable.create( [10, 20, 30, 40], - function (x) { + (x: number) => { if (x === 30) { throw 'error'; } @@ -75,24 +77,24 @@ describe('IteratorObservable', function () { rxTestScheduler ); - var values = { a: 100, b: 400 }; + const values = { a: 100, b: 400 }; expectObservable(source).toBe('(ab#)', values); }); it('should emit members of an array iterator on a particular scheduler, ' + - 'but is unsubscribed early', function (done) { - var expected = [10, 20, 30, 40]; + 'but is unsubscribed early', (done: DoneSignature) => { + const expected = [10, 20, 30, 40]; - var source = IteratorObservable.create( + const source = IteratorObservable.create( [10, 20, 30, 40], - function (x) { return x; }, + (x: number) => x, null, Rx.Scheduler.queue ); - var subscriber = Rx.Subscriber.create( - function (x) { + const subscriber = Rx.Subscriber.create( + (x: number) => { expect(x).toBe(expected.shift()); if (x === 30) { subscriber.unsubscribe(); @@ -106,21 +108,21 @@ describe('IteratorObservable', function () { source.subscribe(subscriber); }); - it('should emit members of an array iterator, and project them', function (done) { - var expected = [100, 400, 900, 1600]; - IteratorObservable.create([10, 20, 30, 40], function (x) { return x * x; }) + it('should emit members of an array iterator, and project them', (done: DoneSignature) => { + const expected = [100, 400, 900, 1600]; + IteratorObservable.create([10, 20, 30, 40], (x: number) => x * x) .subscribe( - function (x) { expect(x).toBe(expected.shift()); }, + (x: number) => { expect(x).toBe(expected.shift()); }, done.fail, - function () { + () => { expect(expected.length).toBe(0); done(); } ); }); - it('should emit members of an array iterator, and project but raise an error', function (done) { - var expected = [100, 400]; + it('should emit members of an array iterator, and project but raise an error', (done: DoneSignature) => { + const expected = [100, 400]; function project(x) { if (x === 30) { throw new Error('boom'); @@ -130,10 +132,10 @@ describe('IteratorObservable', function () { } IteratorObservable.create([10, 20, 30, 40], project) .subscribe( - function (x) { + (x: number) => { expect(x).toBe(expected.shift()); }, - function (err) { + (err: any) => { expect(expected.length).toBe(0); expect(err.message).toBe('boom'); done(); @@ -142,37 +144,37 @@ describe('IteratorObservable', function () { ); }); - it('should emit characters of a string iterator', function (done) { - var expected = ['f', 'o', 'o']; + it('should emit characters of a string iterator', (done: DoneSignature) => { + const expected = ['f', 'o', 'o']; IteratorObservable.create('foo') .subscribe( - function (x) { expect(x).toBe(expected.shift()); }, + (x: number) => { expect(x).toBe(expected.shift()); }, done.fail, - function () { + () => { expect(expected.length).toBe(0); done(); } ); }); - it('should emit characters of a string iterator, and project them', function (done) { - var expected = ['F', 'O', 'O']; - IteratorObservable.create('foo', function (x) { return x.toUpperCase(); }) + it('should emit characters of a string iterator, and project them', (done: DoneSignature) => { + const expected = ['F', 'O', 'O']; + IteratorObservable.create('foo', (x: string) => x.toUpperCase()) .subscribe( - function (x) { expect(x).toBe(expected.shift()); }, + (x: string) => { expect(x).toBe(expected.shift()); }, done.fail, - function () { + () => { expect(expected.length).toBe(0); done(); } ); }); - it('should be possible to unsubscribe in the middle of the iteration', function (done) { - var expected = [10, 20, 30]; + it('should be possible to unsubscribe in the middle of the iteration', (done: DoneSignature) => { + const expected = [10, 20, 30]; - var subscriber = Rx.Subscriber.create( - function (x) { + const subscriber = Rx.Subscriber.create( + (x: number) => { expect(x).toBe(expected.shift()); if (x === 30) { subscriber.unsubscribe(); diff --git a/spec/observables/ScalarObservable-spec.js b/spec/observables/ScalarObservable-spec.js deleted file mode 100644 index 5dbc6f065a..0000000000 --- a/spec/observables/ScalarObservable-spec.js +++ /dev/null @@ -1,28 +0,0 @@ -/* globals describe, it, expect, rxTestScheduler*/ -var Rx = require('../../dist/cjs/Rx'); -var ScalarObservable = require('../../dist/cjs/observable/ScalarObservable').ScalarObservable; -var EmptyObservable = require('../../dist/cjs/observable/EmptyObservable').EmptyObservable; -var ErrorObservable = require('../../dist/cjs/observable/ErrorObservable').ErrorObservable; -var Observable = Rx.Observable; - -describe('ScalarObservable', function () { - it('should create expose a value property', function () { - var s = new ScalarObservable(1); - expect(s.value).toBe(1); - }); - - it('should create ScalarObservable via static create function', function () { - var s = new ScalarObservable(1); - var r = ScalarObservable.create(1); - - expect(s).toEqual(r); - }); - - it('should not schedule further if subscriber unsubscribed', function () { - var s = new ScalarObservable(1, rxTestScheduler); - var subscriber = new Rx.Subscriber(); - s.subscribe(subscriber); - subscriber.isUnsubscribed = true; - rxTestScheduler.flush(); - }); -}); \ No newline at end of file diff --git a/spec/observables/ScalarObservable-spec.ts b/spec/observables/ScalarObservable-spec.ts new file mode 100644 index 0000000000..0b21da45c3 --- /dev/null +++ b/spec/observables/ScalarObservable-spec.ts @@ -0,0 +1,27 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {ScalarObservable} from '../../dist/cjs/observable/ScalarObservable'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; + +describe('ScalarObservable', () => { + it('should create expose a value property', () => { + const s = new ScalarObservable(1); + expect(s.value).toBe(1); + }); + + it('should create ScalarObservable via static create function', () => { + const s = new ScalarObservable(1); + const r = ScalarObservable.create(1); + + expect(s).toEqual(r); + }); + + it('should not schedule further if subscriber unsubscribed', () => { + const s = new ScalarObservable(1, rxTestScheduler); + const subscriber = new Rx.Subscriber(); + s.subscribe(subscriber); + subscriber.isUnsubscribed = true; + rxTestScheduler.flush(); + }); +}); \ No newline at end of file diff --git a/spec/observables/SubscribeOnObservable-spec.js b/spec/observables/SubscribeOnObservable-spec.js deleted file mode 100644 index 8d5751d4af..0000000000 --- a/spec/observables/SubscribeOnObservable-spec.js +++ /dev/null @@ -1,50 +0,0 @@ -/* globals describe, it, expect, hot, expectObservable, expectSubscriptions, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var SubscribeOnObservable = require('../../dist/cjs/observable/SubscribeOnObservable').SubscribeOnObservable; -var Observable = Rx.Observable; - -describe('SubscribeOnObservable', function () { - it('should create Observable to be subscribed on specified scheduler', function () { - var e1 = hot('--a--b--|'); - var expected = '--a--b--|'; - var sub = '^ !'; - var subscribe = new SubscribeOnObservable(e1, 0, rxTestScheduler); - - expectObservable(subscribe).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should specify default scheduler if incorrect scheduler specified', function () { - var e1 = hot('--a--b--|'); - var scheduler = new SubscribeOnObservable(e1, 0, jasmine.createSpy('dummy')).scheduler; - - expect(scheduler).toBe(Rx.Scheduler.asap); - }); - - it('should create observable via staic create function', function () { - var s = new SubscribeOnObservable(rxTestScheduler); - var r = SubscribeOnObservable.create(rxTestScheduler); - - expect(s).toEqual(r); - }); - - it('should subscribe after specified delay', function () { - var e1 = hot('--a--b--|'); - var expected = '-----b--|'; - var sub = ' ^ !'; - var subscribe = new SubscribeOnObservable(e1, 30, rxTestScheduler); - - expectObservable(subscribe).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should consider negative delay as zero', function () { - var e1 = hot('--a--b--|'); - var expected = '--a--b--|'; - var sub = '^ !'; - var subscribe = new SubscribeOnObservable(e1, -10, rxTestScheduler); - - expectObservable(subscribe).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); -}); diff --git a/spec/observables/SubscribeOnObservable-spec.ts b/spec/observables/SubscribeOnObservable-spec.ts new file mode 100644 index 0000000000..32366b427e --- /dev/null +++ b/spec/observables/SubscribeOnObservable-spec.ts @@ -0,0 +1,54 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {SubscribeOnObservable} from '../../dist/cjs/observable/SubscribeOnObservable'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; + +describe('SubscribeOnObservable', () => { + it('should create Observable to be subscribed on specified scheduler', () => { + const e1 = hot('--a--b--|'); + const expected = '--a--b--|'; + const sub = '^ !'; + const subscribe = new SubscribeOnObservable(e1, 0, rxTestScheduler); + + expectObservable(subscribe).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should specify default scheduler if incorrect scheduler specified', () => { + const e1 = hot('--a--b--|'); + const obj: any = jasmine.createSpy('dummy'); + + const scheduler = (new SubscribeOnObservable(e1, 0, obj)).scheduler; + + expect(scheduler).toBe(Rx.Scheduler.asap); + }); + + it('should create observable via staic create function', () => { + const s = new SubscribeOnObservable(null, null, rxTestScheduler); + const r = SubscribeOnObservable.create(null, null, rxTestScheduler); + + expect(s).toEqual(r); + }); + + it('should subscribe after specified delay', () => { + const e1 = hot('--a--b--|'); + const expected = '-----b--|'; + const sub = ' ^ !'; + const subscribe = new SubscribeOnObservable(e1, 30, rxTestScheduler); + + expectObservable(subscribe).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should consider negative delay as zero', () => { + const e1 = hot('--a--b--|'); + const expected = '--a--b--|'; + const sub = '^ !'; + const subscribe = new SubscribeOnObservable(e1, -10, rxTestScheduler); + + expectObservable(subscribe).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); +}); diff --git a/spec/observables/bindCallback-spec.js b/spec/observables/bindCallback-spec.ts similarity index 50% rename from spec/observables/bindCallback-spec.js rename to spec/observables/bindCallback-spec.ts index e6f3adb85a..3c7ad5d150 100644 --- a/spec/observables/bindCallback-spec.js +++ b/spec/observables/bindCallback-spec.ts @@ -1,78 +1,80 @@ -/* globals describe, it, expect, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {it, DoneSignature} from '../helpers/test-helper'; -describe('Observable.bindCallback', function () { - describe('when not scheduled', function () { - it('should emit one value from a callback', function () { +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.bindCallback', () => { + describe('when not scheduled', () => { + it('should emit one value from a callback', () => { function callback(datum, cb) { cb(datum); } - var boundCallback = Observable.bindCallback(callback); - var results = []; + const boundCallback = Observable.bindCallback(callback); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); expect(results).toEqual([42, 'done']); }); - it('should emit one value chosen by a selector', function () { + it('should emit one value chosen by a selector', () => { function callback(datum, cb) { cb(datum); } - var boundCallback = Observable.bindCallback(callback, function (datum) { return datum; }); - var results = []; + const boundCallback = Observable.bindCallback(callback, (datum: any) => datum); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); expect(results).toEqual([42, 'done']); }); - it('should emit an error when the selector throws', function () { + it('should emit an error when the selector throws', () => { function callback(cb) { cb(42); } - var boundCallback = Observable.bindCallback(callback, function (err) { throw new Error('Yikes!'); }); - var results = []; + const boundCallback = Observable.bindCallback(callback, (err: any) => { throw new Error('Yikes!'); }); + const results = []; boundCallback() - .subscribe(function () { + .subscribe(() => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); expect(results).toEqual([new Error('Yikes!')]); }); - it('should not emit, throw or complete if immediately unsubscribed', function (done) { - var nextSpy = jasmine.createSpy('next'); - var throwSpy = jasmine.createSpy('throw'); - var completeSpy = jasmine.createSpy('complete'); - var timeout; + it('should not emit, throw or complete if immediately unsubscribed', (done: DoneSignature) => { + const nextSpy = jasmine.createSpy('next'); + const throwSpy = jasmine.createSpy('throw'); + const completeSpy = jasmine.createSpy('complete'); + let timeout; function callback(datum, cb) { // Need to cb async in order for the unsub to trigger - timeout = setTimeout(function () { + timeout = setTimeout(() => { cb(datum); }); } - var subscription = Observable.bindCallback(callback)(42) + const subscription = Observable.bindCallback(callback)(42) .subscribe(nextSpy, throwSpy, completeSpy); subscription.unsubscribe(); - setTimeout(function () { + setTimeout(() => { expect(nextSpy).not.toHaveBeenCalled(); expect(throwSpy).not.toHaveBeenCalled(); expect(completeSpy).not.toHaveBeenCalled(); @@ -83,18 +85,18 @@ describe('Observable.bindCallback', function () { }); }); - describe('when scheduled', function () { - it('should emit one value from a callback', function () { + describe('when scheduled', () => { + it('should emit one value from a callback', () => { function callback(datum, cb) { cb(datum); } - var boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -103,19 +105,19 @@ describe('Observable.bindCallback', function () { expect(results).toEqual([42, 'done']); }); - it('should error if callback throws', function () { + it('should error if callback throws', () => { function callback(datum, cb) { throw new Error('haha no callback for you'); } - var boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); @@ -124,22 +126,22 @@ describe('Observable.bindCallback', function () { expect(results).toEqual([new Error('haha no callback for you')]); }); - it('should error if selector throws', function () { + it('should error if selector throws', () => { function callback(datum, cb) { cb(datum); } function selector() { throw new Error('what? a selector? I don\'t think so'); } - var boundCallback = Observable.bindCallback(callback, selector, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindCallback(callback, selector, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: any) => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); @@ -148,20 +150,20 @@ describe('Observable.bindCallback', function () { expect(results).toEqual([new Error('what? a selector? I don\'t think so')]); }); - it('should use a selector', function () { + it('should use a selector', () => { function callback(datum, cb) { cb(datum); } function selector(x) { return x + '!!!'; } - var boundCallback = Observable.bindCallback(callback, selector, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindCallback(callback, selector, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: string) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -171,17 +173,17 @@ describe('Observable.bindCallback', function () { }); }); - it('should pass multiple inner arguments as an array', function () { + it('should pass multiple inner arguments as an array', () => { function callback(datum, cb) { cb(datum, 1, 2, 3); } - var boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -190,7 +192,7 @@ describe('Observable.bindCallback', function () { expect(results).toEqual([[42, 1, 2, 3], 'done']); }); - it('should pass multiple inner arguments to the selector if there is one', function () { + it('should pass multiple inner arguments to the selector if there is one', () => { function callback(datum, cb) { cb(datum, 1, 2, 3); } @@ -198,13 +200,13 @@ describe('Observable.bindCallback', function () { expect([a, b, c, d]).toEqual([42, 1, 2, 3]); return a + b + c + d; } - var boundCallback = Observable.bindCallback(callback, selector, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindCallback(callback, selector, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -213,27 +215,27 @@ describe('Observable.bindCallback', function () { expect(results).toEqual([48, 'done']); }); - it('should cache value for next subscription and not call callbackFunc again', function () { - var calls = 0; + it('should cache value for next subscription and not call callbackFunc again', () => { + let calls = 0; function callback(datum, cb) { calls++; cb(datum); } - var boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); - var results1 = []; - var results2 = []; + const boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); + const results1 = []; + const results2 = []; - var source = boundCallback(42); + const source = boundCallback(42); - source.subscribe(function (x) { + source.subscribe((x: number) => { results1.push(x); - }, null, function () { + }, null, () => { results1.push('done'); }); - source.subscribe(function (x) { + source.subscribe((x: number) =>{ results2.push(x); - }, null, function () { + }, null, () => { results2.push('done'); }); @@ -243,4 +245,28 @@ describe('Observable.bindCallback', function () { expect(results1).toEqual([42, 'done']); expect(results2).toEqual([42, 'done']); }); + + it('should not even call the callbackFn if immediately unsubscribed', () => { + let calls = 0; + function callback(datum, cb) { + calls++; + cb(datum); + } + const boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); + const results1 = []; + + const source = boundCallback(42); + + const subscription = source.subscribe((x: any) => { + results1.push(x); + }, null, () => { + results1.push('done'); + }); + + subscription.unsubscribe(); + + rxTestScheduler.flush(); + + expect(calls).toBe(0); + }); }); \ No newline at end of file diff --git a/spec/observables/bindNodeCallback-spec.js b/spec/observables/bindNodeCallback-spec.ts similarity index 54% rename from spec/observables/bindNodeCallback-spec.js rename to spec/observables/bindNodeCallback-spec.ts index e12ecbb988..c1d88ad703 100644 --- a/spec/observables/bindNodeCallback-spec.js +++ b/spec/observables/bindNodeCallback-spec.ts @@ -1,100 +1,103 @@ -/* globals describe, it, expect, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; -describe('Observable.bindNodeCallback', function () { - describe('when not scheduled', function () { - it('should emit one value from a callback', function () { +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.bindNodeCallback', () => { + describe('when not scheduled', () => { + it('should emit one value from a callback', () => { function callback(datum, cb) { cb(null, datum); } - var boundCallback = Observable.bindNodeCallback(callback); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); expect(results).toEqual([42, 'done']); }); - it('should emit one value chosen by a selector', function () { + it('should emit one value chosen by a selector', () => { function callback(datum, cb) { cb(null, datum); } - var boundCallback = Observable.bindNodeCallback(callback, function (datum) { return datum; }); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, (datum: any) => datum); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); expect(results).toEqual([42, 'done']); }); - it('should raise error from callback', function () { - var error = new Error(); + it('should raise error from callback', () => { + const error = new Error(); function callback(cb) { cb(error); } - var boundCallback = Observable.bindNodeCallback(callback); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback); + const results = []; boundCallback() - .subscribe(function () { + .subscribe(() => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); expect(results).toEqual([error]); }); - it('should emit an error when the selector throws', function () { + it('should emit an error when the selector throws', () => { function callback(cb) { cb(null, 42); } - var boundCallback = Observable.bindNodeCallback(callback, function (err) { throw new Error('Yikes!'); }); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, (err: any) => { throw new Error('Yikes!'); }); + const results = []; boundCallback() - .subscribe(function () { + .subscribe(() => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); expect(results).toEqual([new Error('Yikes!')]); }); - it('should not emit, throw or complete if immediately unsubscribed', function (done) { - var nextSpy = jasmine.createSpy('next'); - var throwSpy = jasmine.createSpy('throw'); - var completeSpy = jasmine.createSpy('complete'); - var timeout; + it('should not emit, throw or complete if immediately unsubscribed', (done: DoneSignature) => { + const nextSpy = jasmine.createSpy('next'); + const throwSpy = jasmine.createSpy('throw'); + const completeSpy = jasmine.createSpy('complete'); + let timeout; function callback(datum, cb) { // Need to cb async in order for the unsub to trigger - timeout = setTimeout(function () { + timeout = setTimeout(() => { cb(null, datum); }); } - var subscription = Observable.bindNodeCallback(callback)(42) + const subscription = Observable.bindNodeCallback(callback)(42) .subscribe(nextSpy, throwSpy, completeSpy); subscription.unsubscribe(); - setTimeout(function () { + setTimeout(() => { expect(nextSpy).not.toHaveBeenCalled(); expect(throwSpy).not.toHaveBeenCalled(); expect(completeSpy).not.toHaveBeenCalled(); @@ -105,18 +108,18 @@ describe('Observable.bindNodeCallback', function () { }); }); - describe('when scheduled', function () { - it('should emit one value from a callback', function () { + describe('when scheduled', () => { + it('should emit one value from a callback', () => { function callback(datum, cb) { cb(null, datum); } - var boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -125,19 +128,19 @@ describe('Observable.bindNodeCallback', function () { expect(results).toEqual([42, 'done']); }); - it('should error if callback throws', function () { + it('should error if callback throws', () => { function callback(datum, cb) { throw new Error('haha no callback for you'); } - var boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); @@ -146,22 +149,22 @@ describe('Observable.bindNodeCallback', function () { expect(results).toEqual([new Error('haha no callback for you')]); }); - it('should raise error from callback', function () { - var error = new Error(); + it('should raise error from callback', () => { + const error = new Error(); function callback(cb) { cb(error); } - var boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); + const results = []; boundCallback() - .subscribe(function () { + .subscribe(() => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); @@ -170,22 +173,22 @@ describe('Observable.bindNodeCallback', function () { expect(results).toEqual([error]); }); - it('should error if selector throws', function () { + it('should error if selector throws', () => { function callback(datum, cb) { cb(null, datum); } function selector() { throw new Error('what? a selector? I don\'t think so'); } - var boundCallback = Observable.bindNodeCallback(callback, selector, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, selector, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: any) => { throw 'should not next'; - }, function (err) { + }, (err: any) => { results.push(err); - }, function () { + }, () => { throw 'should not complete'; }); @@ -194,20 +197,20 @@ describe('Observable.bindNodeCallback', function () { expect(results).toEqual([new Error('what? a selector? I don\'t think so')]); }); - it('should use a selector', function () { + it('should use a selector', () => { function callback(datum, cb) { cb(null, datum); } function selector(x) { return x + '!!!'; } - var boundCallback = Observable.bindNodeCallback(callback, selector, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, selector, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: string) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -217,17 +220,17 @@ describe('Observable.bindNodeCallback', function () { }); }); - it('should pass multiple inner arguments as an array', function () { + it('should pass multiple inner arguments as an array', () => { function callback(datum, cb) { cb(null, datum, 1, 2, 3); } - var boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -236,7 +239,7 @@ describe('Observable.bindNodeCallback', function () { expect(results).toEqual([[42, 1, 2, 3], 'done']); }); - it('should pass multiple inner arguments to the selector if there is one', function () { + it('should pass multiple inner arguments to the selector if there is one', () => { function callback(datum, cb) { cb(null, datum, 1, 2, 3); } @@ -244,13 +247,13 @@ describe('Observable.bindNodeCallback', function () { expect([a, b, c, d]).toEqual([42, 1, 2, 3]); return a + b + c + d; } - var boundCallback = Observable.bindNodeCallback(callback, selector, rxTestScheduler); - var results = []; + const boundCallback = Observable.bindNodeCallback(callback, selector, rxTestScheduler); + const results = []; boundCallback(42) - .subscribe(function (x) { + .subscribe((x: number) => { results.push(x); - }, null, function () { + }, null, () => { results.push('done'); }); @@ -259,27 +262,27 @@ describe('Observable.bindNodeCallback', function () { expect(results).toEqual([48, 'done']); }); - it('should cache value for next subscription and not call callbackFunc again', function () { - var calls = 0; + it('should cache value for next subscription and not call callbackFunc again', () => { + let calls = 0; function callback(datum, cb) { calls++; cb(null, datum); } - var boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); - var results1 = []; - var results2 = []; + const boundCallback = Observable.bindNodeCallback(callback, null, rxTestScheduler); + const results1 = []; + const results2 = []; - var source = boundCallback(42); + const source = boundCallback(42); - source.subscribe(function (x) { + source.subscribe((x: number) => { results1.push(x); - }, null, function () { + }, null, () => { results1.push('done'); }); - source.subscribe(function (x) { + source.subscribe((x: number) => { results2.push(x); - }, null, function () { + }, null, () => { results2.push('done'); }); diff --git a/spec/observables/combineLatest-spec.js b/spec/observables/combineLatest-spec.js deleted file mode 100644 index 381c0cfe78..0000000000 --- a/spec/observables/combineLatest-spec.js +++ /dev/null @@ -1,472 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.combineLatest', function () { - it('should combineLatest the provided observables', function () { - var firstSource = hot('----a----b----c----|'); - var secondSource = hot('--d--e--f--g--|'); - var expected = '----uv--wx-y--z----|'; - - var combined = Observable.combineLatest(firstSource, secondSource, function (a, b) { - return '' + a + b; - }); - - expectObservable(combined).toBe(expected, {u: 'ad', v: 'ae', w: 'af', x: 'bf', y: 'bg', z: 'cg'}); - }); - - it('should combine an immediately-scheduled source with an immediately-scheduled second', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [[1, 4], [2, 4], [2, 5], [3, 5], [3, 6], [3, 7], [3, 8]]; - var i = 0; - Observable.combineLatest(a, b, queueScheduler).subscribe(function (vals) { - expect(vals).toDeepEqual(r[i++]); - }, null, function () { - expect(i).toEqual(r.length); - done(); - }); - }); - - it('should accept array of observables', function () { - var firstSource = hot('----a----b----c----|'); - var secondSource = hot('--d--e--f--g--|'); - var expected = '----uv--wx-y--z----|'; - - var combined = Observable.combineLatest([firstSource, secondSource], function (a, b) { - return '' + a + b; - }); - - expectObservable(combined).toBe(expected, {u: 'ad', v: 'ae', w: 'af', x: 'bf', y: 'bg', z: 'cg'}); - }); - - it('should work with two nevers', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var e2 = cold( '-'); - var e2subs = '^'; - var expected = '-'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and empty', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var e2 = cold( '|'); - var e2subs = '(^!)'; - var expected = '-'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and never', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var e2 = cold( '-'); - var e2subs = '^'; - var expected = '-'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - var expected = '|'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-empty and hot-single', function () { - var values = { - a: 1, - b: 2, - c: 3, - r: 1 + 3 //a + c - }; - var e1 = hot('-a-^-|', values); - var e1subs = '^ !'; - var e2 = hot('-b-^-c-|', values); - var e2subs = '^ !'; - var expected = '----|'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-single and hot-empty', function () { - var values = { - a: 1, b: 2, c: 3 - }; - var e1 = hot('-a-^-|', values); - var e1subs = '^ !'; - var e2 = hot('-b-^-c-|', values); - var e2subs = '^ !'; - var expected = '----|'; - - var result = Observable.combineLatest(e2, e1, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-single and never', function () { - var values = { - a: 1 - }; - var e1 = hot('-a-^-|', values); - var e1subs = '^ !'; - var e2 = hot('------', values); //never - var e2subs = '^ '; - var expected = '-'; //never - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and hot-single', function () { - var values = { - a: 1, b: 2 - }; - var e1 = hot('--------', values); //never - var e1subs = '^ '; - var e2 = hot('-a-^-b-|', values); - var e2subs = '^ !'; - var expected = '-----'; //never - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot and hot', function () { - var e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); - var e1subs = '^ !'; - var e2 = hot('---e-^---f--g--|', { e: 'e', f: 'f', g: 'g' }); - var e2subs = '^ !'; - var expected = '----x-yz--|'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'bf', y: 'cf', z: 'cg' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and error', function () { - var e1 = hot('----------|'); //empty - var e1subs = '^ !'; - var e2 = hot('------#', null, 'shazbot!'); //error - var e2subs = '^ !'; - var expected = '------#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'shazbot!'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with error and empty', function () { - var e1 = hot('--^---#', null, 'too bad, honk'); //error - var e1subs = '^ !'; - var e2 = hot('--^--------|'); //empty - var e2subs = '^ !'; - var expected = '----#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'too bad, honk'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot and throw', function () { - var e1 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); - var e1subs = '^ !'; - var e2 = hot('---^-#', null, 'bazinga'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and hot', function () { - var e1 = hot('---^-#', null, 'bazinga'); - var e1subs = '^ !'; - var e2 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and throw', function () { - var e1 = hot('---^----#', null, 'jenga'); - var e1subs = '^ !'; - var e2 = hot('---^-#', null, 'bazinga'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with error and throw', function () { - var e1 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^-#', null, 'flurp'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'flurp'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and error', function () { - var e1 = hot('---^-#', null, 'flurp'); - var e1subs = '^ !'; - var e2 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'flurp'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and throw', function () { - var e1 = hot('---^-----------'); - var e1subs = '^ !'; - var e2 = hot('---^-----#', null, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '------#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and never', function () { - var e1 = hot('---^----#', null, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^-----------'); - var e2subs = '^ !'; - var expected = '-----#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with some and throw', function () { - var e1 = hot('---^----a---b--|', { a: 1, b: 2 }); - var e1subs = '^ !'; - var e2 = hot('---^--#', null, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and some', function () { - var e1 = hot('---^--#', null, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^----a---b--|', { a: 1, b: 2 }); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle throw after complete left', function () { - var left = hot('--a--^--b---|', { a: 1, b: 2 }); - var leftSubs = '^ !'; - var right = hot('-----^--------#', null, 'bad things'); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = Observable.combineLatest(left, right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bad things'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle throw after complete right', function () { - var left = hot('-----^--------#', null, 'bad things'); - var leftSubs = '^ !'; - var right = hot('--a--^--b---|', { a: 1, b: 2 }); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = Observable.combineLatest(left, right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bad things'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle interleaved with tail', function () { - var e1 = hot('-a--^--b---c---|', { a: 'a', b: 'b', c: 'c' }); - var e1subs = '^ !'; - var e2 = hot('--d-^----e---f--|', { d: 'd', e: 'e', f: 'f'}); - var e2subs = '^ !'; - var expected = '-----x-y-z--|'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'be', y: 'ce', z: 'cf' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle two consecutive hot observables', function () { - var e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); - var e1subs = '^ !'; - var e2 = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); - var e2subs = '^ !'; - var expected = '-----------x--y--z--|'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle two consecutive hot observables with error left', function () { - var left = hot('--a--^--b--c--#', { a: 'a', b: 'b', c: 'c' }, 'jenga'); - var leftSubs = '^ !'; - var right = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = Observable.combineLatest(left, right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'jenga'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle two consecutive hot observables with error right', function () { - var left = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); - var leftSubs = '^ !'; - var right = hot('-----^----------d--e--f--#', { d: 'd', e: 'e', f: 'f' }, 'dun dun dun'); - var rightSubs = '^ !'; - var expected = '-----------x--y--z--#'; - - var result = Observable.combineLatest(left, right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }, 'dun dun dun'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle selector throwing', function () { - var e1 = hot('--a--^--b--|', { a: 1, b: 2}); - var e1subs = '^ !'; - var e2 = hot('--c--^--d--|', { c: 3, d: 4}); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.combineLatest(e1, e2, function (x, y) { throw 'ha ha ' + x + ', ' + y; }); - - expectObservable(result).toBe(expected, null, 'ha ha 2, 4'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '----x-yz-- '; - var unsub = ' ! '; - var values = { x: 'bf', y: 'cf', z: 'cg' }; - - var result = Observable.combineLatest(e1, e2, function (x, y) { return x + y; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '----x-yz-- '; - var unsub = ' ! '; - var values = { x: 'bf', y: 'cf', z: 'cg' }; - - var result = Observable.combineLatest( - e1.mergeMap(function (x) { return Observable.of(x); }), - e2.mergeMap(function (x) { return Observable.of(x); }), - function (x, y) { return x + y; } - ).mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/observables/combineLatest-spec.ts b/spec/observables/combineLatest-spec.ts new file mode 100644 index 0000000000..7499f3515f --- /dev/null +++ b/spec/observables/combineLatest-spec.ts @@ -0,0 +1,473 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.combineLatest', () => { + it('should combineLatest the provided observables', () => { + const firstSource = hot('----a----b----c----|'); + const secondSource = hot('--d--e--f--g--|'); + const expected = '----uv--wx-y--z----|'; + + const combined = Observable.combineLatest(firstSource, secondSource, + (a: any, b: any) => '' + a + b); + + expectObservable(combined).toBe(expected, {u: 'ad', v: 'ae', w: 'af', x: 'bf', y: 'bg', z: 'cg'}); + }); + + it('should combine an immediately-scheduled source with an immediately-scheduled second', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [[1, 4], [2, 4], [2, 5], [3, 5], [3, 6], [3, 7], [3, 8]]; + + //type definition need to be updated + Observable.combineLatest(a, b, queueScheduler).subscribe((vals: any) => { + (expect(vals)).toDeepEqual(r.shift()); + }, done.fail, () => { + expect(r.length).toBe(0); + done(); + }); + }); + + it('should accept array of observables', () => { + const firstSource = hot('----a----b----c----|'); + const secondSource = hot('--d--e--f--g--|'); + const expected = '----uv--wx-y--z----|'; + + const combined = Observable.combineLatest([firstSource, secondSource], + (a: any, b: any) => '' + a + b); + + expectObservable(combined).toBe(expected, {u: 'ad', v: 'ae', w: 'af', x: 'bf', y: 'bg', z: 'cg'}); + }); + + it('should work with two nevers', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const e2 = cold( '-'); + const e2subs = '^'; + const expected = '-'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and empty', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const e2 = cold( '|'); + const e2subs = '(^!)'; + const expected = '-'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and never', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const e2 = cold( '-'); + const e2subs = '^'; + const expected = '-'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + const expected = '|'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-empty and hot-single', () => { + const values = { + a: 1, + b: 2, + c: 3, + r: 1 + 3 //a + c + }; + const e1 = hot('-a-^-|', values); + const e1subs = '^ !'; + const e2 = hot('-b-^-c-|', values); + const e2subs = '^ !'; + const expected = '----|'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-single and hot-empty', () => { + const values = { + a: 1, b: 2, c: 3 + }; + const e1 = hot('-a-^-|', values); + const e1subs = '^ !'; + const e2 = hot('-b-^-c-|', values); + const e2subs = '^ !'; + const expected = '----|'; + + const result = Observable.combineLatest(e2, e1, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-single and never', () => { + const values = { + a: 1 + }; + const e1 = hot('-a-^-|', values); + const e1subs = '^ !'; + const e2 = hot('------', values); //never + const e2subs = '^ '; + const expected = '-'; //never + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and hot-single', () => { + const values = { + a: 1, b: 2 + }; + const e1 = hot('--------', values); //never + const e1subs = '^ '; + const e2 = hot('-a-^-b-|', values); + const e2subs = '^ !'; + const expected = '-----'; //never + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot and hot', () => { + const e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); + const e1subs = '^ !'; + const e2 = hot('---e-^---f--g--|', { e: 'e', f: 'f', g: 'g' }); + const e2subs = '^ !'; + const expected = '----x-yz--|'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'bf', y: 'cf', z: 'cg' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and error', () => { + const e1 = hot('----------|'); //empty + const e1subs = '^ !'; + const e2 = hot('------#', null, 'shazbot!'); //error + const e2subs = '^ !'; + const expected = '------#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'shazbot!'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with error and empty', () => { + const e1 = hot('--^---#', null, 'too bad, honk'); //error + const e1subs = '^ !'; + const e2 = hot('--^--------|'); //empty + const e2subs = '^ !'; + const expected = '----#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'too bad, honk'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot and throw', () => { + const e1 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); + const e1subs = '^ !'; + const e2 = hot('---^-#', null, 'bazinga'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and hot', () => { + const e1 = hot('---^-#', null, 'bazinga'); + const e1subs = '^ !'; + const e2 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and throw', () => { + const e1 = hot('---^----#', null, 'jenga'); + const e1subs = '^ !'; + const e2 = hot('---^-#', null, 'bazinga'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with error and throw', () => { + const e1 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^-#', null, 'flurp'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'flurp'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and error', () => { + const e1 = hot('---^-#', null, 'flurp'); + const e1subs = '^ !'; + const e2 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'flurp'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and throw', () => { + const e1 = hot('---^-----------'); + const e1subs = '^ !'; + const e2 = hot('---^-----#', null, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '------#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and never', () => { + const e1 = hot('---^----#', null, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^-----------'); + const e2subs = '^ !'; + const expected = '-----#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with some and throw', () => { + const e1 = hot('---^----a---b--|', { a: 1, b: 2 }); + const e1subs = '^ !'; + const e2 = hot('---^--#', null, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and some', () => { + const e1 = hot('---^--#', null, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^----a---b--|', { a: 1, b: 2 }); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle throw after complete left', () => { + const left = hot('--a--^--b---|', { a: 1, b: 2 }); + const leftSubs = '^ !'; + const right = hot('-----^--------#', null, 'bad things'); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = Observable.combineLatest(left, right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bad things'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle throw after complete right', () => { + const left = hot('-----^--------#', null, 'bad things'); + const leftSubs = '^ !'; + const right = hot('--a--^--b---|', { a: 1, b: 2 }); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = Observable.combineLatest(left, right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bad things'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle interleaved with tail', () => { + const e1 = hot('-a--^--b---c---|', { a: 'a', b: 'b', c: 'c' }); + const e1subs = '^ !'; + const e2 = hot('--d-^----e---f--|', { d: 'd', e: 'e', f: 'f'}); + const e2subs = '^ !'; + const expected = '-----x-y-z--|'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'be', y: 'ce', z: 'cf' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle two consecutive hot observables', () => { + const e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); + const e1subs = '^ !'; + const e2 = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); + const e2subs = '^ !'; + const expected = '-----------x--y--z--|'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle two consecutive hot observables with error left', () => { + const left = hot('--a--^--b--c--#', { a: 'a', b: 'b', c: 'c' }, 'jenga'); + const leftSubs = '^ !'; + const right = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = Observable.combineLatest(left, right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'jenga'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle two consecutive hot observables with error right', () => { + const left = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); + const leftSubs = '^ !'; + const right = hot('-----^----------d--e--f--#', { d: 'd', e: 'e', f: 'f' }, 'dun dun dun'); + const rightSubs = '^ !'; + const expected = '-----------x--y--z--#'; + + const result = Observable.combineLatest(left, right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }, 'dun dun dun'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle selector throwing', () => { + const e1 = hot('--a--^--b--|', { a: 1, b: 2}); + const e1subs = '^ !'; + const e2 = hot('--c--^--d--|', { c: 3, d: 4}); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => { throw 'ha ha ' + x + ', ' + y; }); + + expectObservable(result).toBe(expected, null, 'ha ha 2, 4'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '----x-yz-- '; + const unsub = ' ! '; + const values = { x: 'bf', y: 'cf', z: 'cg' }; + + const result = Observable.combineLatest(e1, e2, (x: any, y: any) => x + y); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '----x-yz-- '; + const unsub = ' ! '; + const values = { x: 'bf', y: 'cf', z: 'cg' }; + + const result = Observable.combineLatest( + e1.mergeMap((x: string) => Observable.of(x)), + e2.mergeMap((x: string) => Observable.of(x)), + (x: any, y: any) => x + y + ).mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); \ No newline at end of file diff --git a/spec/observables/concat-spec.js b/spec/observables/concat-spec.js deleted file mode 100644 index ddd908a641..0000000000 --- a/spec/observables/concat-spec.js +++ /dev/null @@ -1,343 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.concat', function () { - it('should emit elements from multiple sources', function () { - var e1 = cold('-a-b-c-|'); - var e1subs = '^ !'; - var e2 = cold('-0-1-|'); - var e2subs = ' ^ !'; - var e3 = cold('-w-x-y-z-|'); - var e3subs = ' ^ !'; - var expected = '-a-b-c--0-1--w-x-y-z-|'; - - expectObservable(Observable.concat(e1, e2, e3)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should concat the same cold observable multiple times', function () { - var inner = cold('--i-j-k-l-| '); - var innersubs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '--i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; - - var result = Observable.concat(inner, inner, inner, inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concat the same cold observable multiple times, ' + - 'but the result is unsubscribed early', function () { - var inner = cold('--i-j-k-l-| '); - var unsub = ' !'; - var innersubs = ['^ ! ', - ' ^ !']; - var expected = '--i-j-k-l---i-j-'; - - var result = Observable.concat(inner, inner, inner, inner); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var inner = cold('--i-j-k-l-| '); - var innersubs = ['^ ! ', - ' ^ !']; - var expected = '--i-j-k-l---i-j-'; - var unsub = ' !'; - - var innerWrapped = inner.mergeMap(function (x) { return Observable.of(x); }); - var result = Observable - .concat(innerWrapped, innerWrapped, innerWrapped, innerWrapped) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should complete without emit if both sources are empty', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '----|'); - var e2subs = ' ^ !'; - var expected = '------|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if first source does not completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('--|'); - var e2subs = []; - var expected = '-'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if second source does not completes', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold('---'); - var e2subs = ' ^'; - var expected = '---'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if both sources do not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('-'); - var e2subs = []; - var expected = '-'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when first source is empty, second source raises error', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '----#'); - var e2subs = ' ^ !'; - var expected = '------#'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when first source raises error, second source is empty', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('----|'); - var e2subs = []; - var expected = '---#'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise first error when both source raise error', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('------#'); - var e2subs = []; - var expected = '---#'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat if first source emits once, second source is empty', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '--------|'); - var e2subs = ' ^ !'; - var expected = '--a----------|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat if first source is empty, second source emits once', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '--a--|'); - var e2subs = ' ^ !'; - var expected = '----a--|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit element from first source, and should not complete if second ' + - 'source does not completes', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '-'); - var e2subs = ' ^'; - var expected = '--a---'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if first source does not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('--a--|'); - var e2subs = []; - var expected = '-'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit elements from each source when source emit once', function () { - var e1 = cold('---a|'); - var e1subs = '^ !'; - var e2 = cold( '-----b--|'); - var e2subs = ' ^ !'; - var expected = '---a-----b--|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe to inner source if outer is unsubscribed early', function () { - var e1 = cold('---a-a--a| '); - var e1subs = '^ ! '; - var e2 = cold( '-----b-b--b-|'); - var e2subs = ' ^ ! '; - var unsub = ' ! '; - var expected = '---a-a--a-----b-b '; - - expectObservable(Observable.concat(e1, e2), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error from first source and does not emit from second source', function () { - var e1 = cold('--#'); - var e1subs = '^ !'; - var e2 = cold('----a--|'); - var e2subs = []; - var expected = '--#'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit element from first source then raise error from second source', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '-------#'); - var e2subs = ' ^ !'; - var expected = '--a---------#'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit all elements from both hot observable sources if first source ' + - 'completes before second source starts emit', function () { - var e1 = hot('--a--b-|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--x--y--|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit elements from second source regardless of completion time ' + - 'when second source is cold observable', function () { - var e1 = hot('--a--b--c---|'); - var e1subs = '^ !'; - var e2 = cold('-x-y-z-|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c----x-y-z-|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not emit collapsing element from second source', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--z--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c--y--z--|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should return empty if concatenating an empty source', function () { - var e1 = cold('|'); - var e1subs = ['(^!)', '(^!)']; - var expected = '|'; - - var result = Observable.concat(e1, e1); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error immediately if given a just-throw source', function () { - var e1 = cold( '#'); - var e1subs = '(^!)'; - var expected = '#'; - - var result = Observable.concat(e1, e1); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit elements from second source regardless of completion time ' + - 'when second source is cold observable', function () { - var e1 = hot('--a--b--c---|'); - var e1subs = '^ !'; - var e2 = cold('-x-y-z-|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c----x-y-z-|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not emit collapsing element from second source', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--z--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c--y--z--|'; - - expectObservable(Observable.concat(e1, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat an immediately-scheduled source with an immediately-scheduled second', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [1, 2, 3, 4, 5, 6, 7, 8]; - var i = 0; - - Observable.concat(a, b, queueScheduler).subscribe(function (vals) { - expect(vals).toBe(r[i++]); - }, null, done); - }); -}); \ No newline at end of file diff --git a/spec/observables/concat-spec.ts b/spec/observables/concat-spec.ts new file mode 100644 index 0000000000..85a3eb8aab --- /dev/null +++ b/spec/observables/concat-spec.ts @@ -0,0 +1,345 @@ +/* globals describe, it, expect, expectObservable, expectSubscriptions, cold */ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.concat', () => { + it('should emit elements from multiple sources', () => { + const e1 = cold('-a-b-c-|'); + const e1subs = '^ !'; + const e2 = cold('-0-1-|'); + const e2subs = ' ^ !'; + const e3 = cold('-w-x-y-z-|'); + const e3subs = ' ^ !'; + const expected = '-a-b-c--0-1--w-x-y-z-|'; + + expectObservable(Observable.concat(e1, e2, e3)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should concat the same cold observable multiple times', () => { + const inner = cold('--i-j-k-l-| '); + const innersubs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '--i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; + + const result = Observable.concat(inner, inner, inner, inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concat the same cold observable multiple times, ' + + 'but the result is unsubscribed early', () => { + const inner = cold('--i-j-k-l-| '); + const unsub = ' !'; + const innersubs = ['^ ! ', + ' ^ !']; + const expected = '--i-j-k-l---i-j-'; + + const result = Observable.concat(inner, inner, inner, inner); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const inner = cold('--i-j-k-l-| '); + const innersubs = ['^ ! ', + ' ^ !']; + const expected = '--i-j-k-l---i-j-'; + const unsub = ' !'; + + const innerWrapped = inner.mergeMap((x: string) => Observable.of(x)); + const result = Observable + .concat(innerWrapped, innerWrapped, innerWrapped, innerWrapped) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should complete without emit if both sources are empty', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '----|'); + const e2subs = ' ^ !'; + const expected = '------|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if first source does not completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('--|'); + const e2subs = []; + const expected = '-'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if second source does not completes', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold('---'); + const e2subs = ' ^'; + const expected = '---'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if both sources do not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('-'); + const e2subs = []; + const expected = '-'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when first source is empty, second source raises error', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '----#'); + const e2subs = ' ^ !'; + const expected = '------#'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when first source raises error, second source is empty', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('----|'); + const e2subs = []; + const expected = '---#'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise first error when both source raise error', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('------#'); + const e2subs = []; + const expected = '---#'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat if first source emits once, second source is empty', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '--------|'); + const e2subs = ' ^ !'; + const expected = '--a----------|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat if first source is empty, second source emits once', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '--a--|'); + const e2subs = ' ^ !'; + const expected = '----a--|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit element from first source, and should not complete if second ' + + 'source does not completes', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '-'); + const e2subs = ' ^'; + const expected = '--a---'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if first source does not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('--a--|'); + const e2subs = []; + const expected = '-'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit elements from each source when source emit once', () => { + const e1 = cold('---a|'); + const e1subs = '^ !'; + const e2 = cold( '-----b--|'); + const e2subs = ' ^ !'; + const expected = '---a-----b--|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should unsubscribe to inner source if outer is unsubscribed early', () => { + const e1 = cold('---a-a--a| '); + const e1subs = '^ ! '; + const e2 = cold( '-----b-b--b-|'); + const e2subs = ' ^ ! '; + const unsub = ' ! '; + const expected = '---a-a--a-----b-b '; + + expectObservable(Observable.concat(e1, e2), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error from first source and does not emit from second source', () => { + const e1 = cold('--#'); + const e1subs = '^ !'; + const e2 = cold('----a--|'); + const e2subs = []; + const expected = '--#'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit element from first source then raise error from second source', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '-------#'); + const e2subs = ' ^ !'; + const expected = '--a---------#'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit all elements from both hot observable sources if first source ' + + 'completes before second source starts emit', () => { + const e1 = hot('--a--b-|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--x--y--|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit elements from second source regardless of completion time ' + + 'when second source is cold observable', () => { + const e1 = hot('--a--b--c---|'); + const e1subs = '^ !'; + const e2 = cold('-x-y-z-|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c----x-y-z-|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not emit collapsing element from second source', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--z--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c--y--z--|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should return empty if concatenating an empty source', () => { + const e1 = cold('|'); + const e1subs = ['(^!)', '(^!)']; + const expected = '|'; + + const result = Observable.concat(e1, e1); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error immediately if given a just-throw source', () => { + const e1 = cold( '#'); + const e1subs = '(^!)'; + const expected = '#'; + + const result = Observable.concat(e1, e1); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit elements from second source regardless of completion time ' + + 'when second source is cold observable', () => { + const e1 = hot('--a--b--c---|'); + const e1subs = '^ !'; + const e2 = cold('-x-y-z-|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c----x-y-z-|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not emit collapsing element from second source', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--z--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c--y--z--|'; + + expectObservable(Observable.concat(e1, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat an immediately-scheduled source with an immediately-scheduled second', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [1, 2, 3, 4, 5, 6, 7, 8]; + + Observable.concat(a, b, queueScheduler).subscribe((vals: number) => { + expect(vals).toBe(r.shift()); + }, null, done); + }); +}); \ No newline at end of file diff --git a/spec/observables/defer-spec.js b/spec/observables/defer-spec.js deleted file mode 100644 index ccd886bac1..0000000000 --- a/spec/observables/defer-spec.js +++ /dev/null @@ -1,82 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.defer', function () { - it('should create an observable from the provided observbale factory', function () { - var source = hot('--a--b--c--|'); - var sourceSubs = '^ !'; - var expected = '--a--b--c--|'; - - var e1 = Observable.defer(function () { - return source; - }); - - expectObservable(e1).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should create an observable from completed', function () { - var source = hot('|'); - var sourceSubs = '(^!)'; - var expected = '|'; - - var e1 = Observable.defer(function () { - return source; - }); - - expectObservable(e1).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should create an observable from error', function () { - var source = hot('#'); - var sourceSubs = '(^!)'; - var expected = '#'; - - var e1 = Observable.defer(function () { - return source; - }); - - expectObservable(e1).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should create an observable when factory throws', function () { - var e1 = Observable.defer(function () { - throw 'error'; - }); - var expected = '#'; - - expectObservable(e1).toBe(expected); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--|'); - var sourceSubs = '^ ! '; - var expected = '--a--b- '; - var unsub = ' ! '; - - var e1 = Observable.defer(function () { - return source; - }); - - expectObservable(e1, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--a--b--c--|'); - var sourceSubs = '^ ! '; - var expected = '--a--b- '; - var unsub = ' ! '; - - var e1 = Observable.defer(function () { - return source.mergeMap(function (x) { return Observable.of(x); }); - }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(e1, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); -}); diff --git a/spec/observables/defer-spec.ts b/spec/observables/defer-spec.ts new file mode 100644 index 0000000000..0cf953640e --- /dev/null +++ b/spec/observables/defer-spec.ts @@ -0,0 +1,75 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.defer', () => { + it('should create an observable from the provided observbale factory', () => { + const source = hot('--a--b--c--|'); + const sourceSubs = '^ !'; + const expected = '--a--b--c--|'; + + const e1 = Observable.defer(() => source); + + expectObservable(e1).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should create an observable from completed', () => { + const source = hot('|'); + const sourceSubs = '(^!)'; + const expected = '|'; + + const e1 = Observable.defer(() => source); + + expectObservable(e1).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should create an observable from error', () => { + const source = hot('#'); + const sourceSubs = '(^!)'; + const expected = '#'; + + const e1 = Observable.defer(() => source); + + expectObservable(e1).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should create an observable when factory throws', () => { + //type definition need to be updated + const e1 = Observable.defer((() => { + throw 'error'; + })); + const expected = '#'; + + expectObservable(e1).toBe(expected); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--|'); + const sourceSubs = '^ ! '; + const expected = '--a--b- '; + const unsub = ' ! '; + + const e1 = Observable.defer(() => source); + + expectObservable(e1, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--a--b--c--|'); + const sourceSubs = '^ ! '; + const expected = '--a--b- '; + const unsub = ' ! '; + + const e1 = Observable.defer(() => source.mergeMap((x: string) => Observable.of(x))) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(e1, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); +}); diff --git a/spec/observables/dom/ajax-spec.js b/spec/observables/dom/ajax-spec.js deleted file mode 100644 index c3fda76e9c..0000000000 --- a/spec/observables/dom/ajax-spec.js +++ /dev/null @@ -1,356 +0,0 @@ -/* globals describe, it, expect, sinon, rxTestScheduler */ -var Rx = require('../../../dist/cjs/Rx.DOM'); -var Observable = Rx.Observable; - -function noop() { - // nope. -} - -describe('Observable.ajax', function () { - beforeEach(function () { - setupMockXHR(); - }); - - afterEach(function () { - teardownMockXHR(); - }); - - it('should set headers', function () { - Rx.Observable.ajax({ - url: '/talk-to-me-goose', - headers: { - 'Content-Type': 'kenny/loggins', - 'Fly-Into-The': 'Dangah Zone!', - 'Take-A-Ride-Into-The': 'Danger ZoooOoone!' - } - }) - .subscribe(); - - var request = XMLHttpRequest.mostRecent(); - - expect(request.url).toBe('/talk-to-me-goose'); - expect(request.requestHeaders).toEqual({ - 'Content-Type': 'kenny/loggins', - 'Fly-Into-The': 'Dangah Zone!', - 'Take-A-Ride-Into-The': 'Danger ZoooOoone!', - 'X-Requested-With': 'XMLHttpRequest' - }); - }); - - it('should have an optional resultSelector', function () { - var expected = 'avast ye swabs!'; - var result; - var complete = false; - - Rx.Observable - .ajax({ - url: '/flibbertyJibbet', - responseType: 'text', - resultSelector: function (res) { - return res.response; - } - }) - .subscribe(function (x) { - result = x; - }, null, function () { - complete = true; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - - XMLHttpRequest.mostRecent().respondWith({ - 'status': 200, - 'contentType': 'application/json', - 'responseText': expected - }); - - expect(result).toBe(expected); - expect(complete).toBe(true); - }); - - it('should have error when resultSelector errors', function () { - var expected = 'avast ye swabs!'; - var error; - - Rx.Observable - .ajax({ - url: '/flibbertyJibbet', - responseType: 'text', - resultSelector: function (res) { - throw new Error('ha! ha! fooled you!'); - } - }) - .subscribe(function (x) { - throw 'should not next'; - }, function (err) { - error = err; - }, function () { - throw 'should not complete'; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - - XMLHttpRequest.mostRecent().respondWith({ - 'status': 200, - 'contentType': 'application/json', - 'responseText': expected - }); - - expect(error).toEqual(new Error('ha! ha! fooled you!')); - }); - - it('should error if createXHR throws', function () { - var error; - - Rx.Observable - .ajax({ - url: '/flibbertyJibbet', - responseType: 'text', - createXHR: function () { - throw new Error('wokka wokka'); - } - }) - .subscribe(function (x) { - throw 'should not next'; - }, function (err) { - error = err; - }, function () { - throw 'should not complete'; - }); - - expect(error).toEqual(new Error('wokka wokka')); - }); - - it('should succeed on 200', function () { - var expected = { foo: 'bar' }; - var result; - var complete = false; - - Rx.Observable - .ajax({ - url: '/flibbertyJibbet', - responseType: 'text', - }) - .subscribe(function (x) { - result = x; - }, null, function () { - complete = true; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - - XMLHttpRequest.mostRecent().respondWith({ - 'status': 200, - 'contentType': 'application/json', - 'responseText': JSON.stringify(expected) - }); - - expect(result.xhr).toBeDefined(); - expect(result.response).toBe(JSON.stringify({ foo: 'bar' })); - expect(complete).toBe(true); - }); - - it('should fail on 404', function () { - var error; - - Rx.Observable - .ajax({ - url: '/flibbertyJibbet', - normalizeError: function (e, xhr, type) { - return xhr.response || xhr.responseText; - }, - responseType: 'text' - }) - .subscribe(function (x) { - throw 'should not next'; - }, function (x) { - error = x; - }, function () { - throw 'should not complete'; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - - XMLHttpRequest.mostRecent().respondWith({ - 'status': 404, - 'contentType': 'text/plain', - 'responseText': 'Wee! I am text!' - }); - - expect(error instanceof Rx.AjaxError).toBe(true); - expect(error.message).toBe('ajax error 404'); - expect(error.status).toBe(404); - }); - - it('should fail on 404', function () { - var error; - - Rx.Observable - .ajax({ - url: '/flibbertyJibbet', - normalizeError: function (e, xhr, type) { - return xhr.response || xhr.responseText; - }, - responseType: 'text' - }) - .subscribe(function (x) { - throw 'should not next'; - }, function (x) { - error = x; - }, function () { - throw 'should not complete'; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - - XMLHttpRequest.mostRecent().respondWith({ - 'status': 300, - 'contentType': 'text/plain', - 'responseText': 'Wee! I am text!' - }); - - expect(error instanceof Rx.AjaxError).toBe(true); - expect(error.message).toBe('ajax error 300'); - expect(error.status).toBe(300); - }); - - it('should succeed no settings', function () { - var expected = JSON.stringify({ foo: 'bar' }); - - Rx.Observable - .ajax('/flibbertyJibbet') - .subscribe(function (x) { - expect(x.status).toBe(200); - expect(x.xhr.method).toBe('GET'); - expect(x.xhr.responseText).toBe(expected); - }, function () { - throw 'should not have been called'; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - XMLHttpRequest.mostRecent().respondWith({ - 'status': 200, - 'contentType': 'text/plain', - 'responseText': expected - }); - }); - - it('should fail no settings', function () { - var expected = JSON.stringify({ foo: 'bar' }); - - Rx.Observable - .ajax('/flibbertyJibbet') - .subscribe(function () { - throw 'should not have been called'; - }, function (x) { - expect(x.status).toBe(500); - expect(x.xhr.method).toBe('GET'); - expect(x.xhr.responseText).toBe(expected); - }, function () { - throw 'should not have been called'; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - XMLHttpRequest.mostRecent().respondWith({ - 'status': 500, - 'contentType': 'text/plain', - 'responseText': expected - }); - }); - - describe('ajax.get', function () { - it('should succeed on 200', function () { - var expected = { foo: 'bar' }; - var result; - var complete = false; - - Rx.Observable - .ajax.get('/flibbertyJibbet') - .subscribe(function (x) { - result = x; - }, null, function () { - complete = true; - }); - - var request = XMLHttpRequest.mostRecent(); - - expect(request.url).toBe('/flibbertyJibbet'); - - request.respondWith({ - 'status': 200, - 'contentType': 'application/json', - 'responseText': JSON.stringify(expected) - }); - - expect(result).toEqual(expected); - expect(complete).toBe(true); - }); - - it('should succeed on 200 with a resultSelector', function () { - var expected = { larf: 'hahahahaha' }; - var result; - var innerResult; - var complete = false; - - Rx.Observable - .ajax.get('/flibbertyJibbet', function (x) { - innerResult = x; - return x.response.larf.toUpperCase(); - }) - .subscribe(function (x) { - result = x; - }, null , function () { - complete = true; - }); - - expect(XMLHttpRequest.mostRecent().url).toBe('/flibbertyJibbet'); - - XMLHttpRequest.mostRecent().respondWith({ - 'status': 200, - 'contentType': 'application/json', - 'responseText': JSON.stringify(expected) - }); - - expect(innerResult.xhr).toBeDefined(); - expect(innerResult.response).toEqual({ larf: 'hahahahaha' }); - expect(result).toBe('HAHAHAHAHA'); - expect(complete).toBe(true); - }); - }); - - describe('ajax.post', function () { - it('should succeed on 200', function () { - var expected = { foo: 'bar', hi: 'there you' }; - var result; - var complete = false; - - Rx.Observable - .ajax.post('/flibbertyJibbet', expected) - .subscribe(function (x) { - result = x; - }, null , function () { - complete = true; - }); - - var request = XMLHttpRequest.mostRecent(); - - expect(request.method).toBe('POST'); - expect(request.url).toBe('/flibbertyJibbet'); - expect(request.requestHeaders).toEqual({ - 'X-Requested-With': 'XMLHttpRequest', - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' - }); - - request.respondWith({ - 'status': 200, - 'contentType': 'application/json', - 'responseText': JSON.stringify(expected) - }); - - expect(request.data).toEqual('foo=bar&hi=there%20you'); - expect(result.response).toEqual(expected); - expect(complete).toBe(true); - }); - }); -}); - diff --git a/spec/observables/dom/ajax-spec.ts b/spec/observables/dom/ajax-spec.ts new file mode 100644 index 0000000000..9133c606cc --- /dev/null +++ b/spec/observables/dom/ajax-spec.ts @@ -0,0 +1,362 @@ +import * as Rx from '../../../dist/cjs/Rx.DOM'; +import {root} from '../../../dist/cjs/util/root'; +import {MockXMLHttpRequest} from '../../helpers/ajax-helper'; +import {it} from '../../helpers/test-helper'; + +declare const global: any; +//declare const XMLHttpRequest: MockXMLHttpRequest; + +describe('Observable.ajax', () => { + let gXHR: XMLHttpRequest; + let rXHR: XMLHttpRequest; + + beforeEach(() => { + gXHR = global.XMLHttpRequest; + rXHR = root.XMLHttpRequest; + global.XMLHttpRequest = MockXMLHttpRequest; + root.XMLHttpRequest = MockXMLHttpRequest; + }); + + afterEach(() => { + MockXMLHttpRequest.clearRequest(); + + global.XMLHttpRequest = gXHR; + root.XMLHttpRequest = rXHR; + }); + + it('should set headers', () => { + const obj = { + url: '/talk-to-me-goose', + headers: { + 'Content-Type': 'kenny/loggins', + 'Fly-Into-The': 'Dangah Zone!', + 'Take-A-Ride-Into-The': 'Danger ZoooOoone!' + } + }; + + (Rx.Observable.ajax)(obj).subscribe(); + + const request = MockXMLHttpRequest.mostRecent; + + expect(request.url).toBe('/talk-to-me-goose'); + expect(request.requestHeaders).toEqual({ + 'Content-Type': 'kenny/loggins', + 'Fly-Into-The': 'Dangah Zone!', + 'Take-A-Ride-Into-The': 'Danger ZoooOoone!', + 'X-Requested-With': 'XMLHttpRequest' + }); + }); + + it('should have an optional resultSelector', () => { + const expected = 'avast ye swabs!'; + let result; + let complete = false; + + const obj = { + url: '/flibbertyJibbet', + responseType: 'text', + resultSelector: (res: any) => res.response + }; + + (Rx.Observable.ajax)(obj) + .subscribe((x: any) => { + result = x; + }, null, () => { + complete = true; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 200, + 'contentType': 'application/json', + 'responseText': expected + }); + + expect(result).toBe(expected); + expect(complete).toBe(true); + }); + + it('should have error when resultSelector errors', () => { + const expected = 'avast ye swabs!'; + let error; + const obj = { + url: '/flibbertyJibbet', + responseType: 'text', + resultSelector: (res: any) => { + throw new Error('ha! ha! fooled you!'); + } + }; + + (Rx.Observable.ajax)(obj) + .subscribe((x: any) => { + throw 'should not next'; + }, (err: any) => { + error = err; + }, () => { + throw 'should not complete'; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 200, + 'contentType': 'application/json', + 'responseText': expected + }); + + expect(error).toEqual(new Error('ha! ha! fooled you!')); + }); + + it('should error if createXHR throws', () => { + let error; + const obj = { + url: '/flibbertyJibbet', + responseType: 'text', + createXHR: () => { + throw new Error('wokka wokka'); + } + }; + + (Rx.Observable.ajax)(obj) + .subscribe((x: any) => { + throw 'should not next'; + }, (err: any) => { + error = err; + }, () => { + throw 'should not complete'; + }); + + expect(error).toEqual(new Error('wokka wokka')); + }); + + it('should succeed on 200', () => { + const expected = { foo: 'bar' }; + let result; + let complete = false; + const obj = { + url: '/flibbertyJibbet', + responseType: 'text', + }; + + (Rx.Observable.ajax)(obj) + .subscribe((x: any) => { + result = x; + }, null, () => { + complete = true; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 200, + 'contentType': 'application/json', + 'responseText': JSON.stringify(expected) + }); + + expect(result.xhr).toBeDefined(); + expect(result.response).toBe(JSON.stringify({ foo: 'bar' })); + expect(complete).toBe(true); + }); + + it('should fail on 404', () => { + let error; + const obj = { + url: '/flibbertyJibbet', + normalizeError: (e: any, xhr: any, type: any) => { + return xhr.response || xhr.responseText; + }, + responseType: 'text' + }; + + (Rx.Observable.ajax)(obj) + .subscribe((x: any) => { + throw 'should not next'; + }, (err: any) => { + error = err; + }, () => { + throw 'should not complete'; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 404, + 'contentType': 'text/plain', + 'responseText': 'Wee! I am text!' + }); + + expect(error instanceof Rx.AjaxError).toBe(true); + expect(error.message).toBe('ajax error 404'); + expect(error.status).toBe(404); + }); + + it('should fail on 404', () => { + let error; + const obj = { + url: '/flibbertyJibbet', + normalizeError: (e: any, xhr: any, type: any) => { + return xhr.response || xhr.responseText; + }, + responseType: 'text' + }; + + (Rx.Observable.ajax)(obj).subscribe((x: any) => { + throw 'should not next'; + }, (err: any) => { + error = err; + }, () => { + throw 'should not complete'; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 300, + 'contentType': 'text/plain', + 'responseText': 'Wee! I am text!' + }); + + expect(error instanceof Rx.AjaxError).toBe(true); + expect(error.message).toBe('ajax error 300'); + expect(error.status).toBe(300); + }); + + it('should succeed no settings', () => { + const expected = JSON.stringify({ foo: 'bar' }); + //Type definition need to be updated + (Rx.Observable.ajax)('/flibbertyJibbet') + .subscribe((x: any) => { + expect(x.status).toBe(200); + expect(x.xhr.method).toBe('GET'); + expect(x.xhr.responseText).toBe(expected); + }, () => { + throw 'should not have been called'; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 200, + 'contentType': 'text/plain', + 'responseText': expected + }); + }); + + it('should fail no settings', () => { + const expected = JSON.stringify({ foo: 'bar' }); + + (Rx.Observable.ajax)('/flibbertyJibbet') + .subscribe(() => { + throw 'should not have been called'; + }, (x: any) => { + expect(x.status).toBe(500); + expect(x.xhr.method).toBe('GET'); + expect(x.xhr.responseText).toBe(expected); + }, () => { + throw 'should not have been called'; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 500, + 'contentType': 'text/plain', + 'responseText': expected + }); + }); + + describe('ajax.get', () => { + it('should succeed on 200', () => { + const expected = { foo: 'bar' }; + let result; + let complete = false; + + Rx.Observable + .ajax.get('/flibbertyJibbet') + .subscribe((x: any) => { + result = x; + }, null, () => { + complete = true; + }); + + const request = MockXMLHttpRequest.mostRecent; + + expect(request.url).toBe('/flibbertyJibbet'); + + request.respondWith({ + 'status': 200, + 'contentType': 'application/json', + 'responseText': JSON.stringify(expected) + }); + + expect(result).toEqual(expected); + expect(complete).toBe(true); + }); + + it('should succeed on 200 with a resultSelector', () => { + const expected = { larf: 'hahahahaha' }; + let result; + let innerResult; + let complete = false; + + Rx.Observable + .ajax.get('/flibbertyJibbet', (x: any) => { + innerResult = x; + return x.response.larf.toUpperCase(); + }) + .subscribe((x: any) => { + result = x; + }, null , () => { + complete = true; + }); + + expect(MockXMLHttpRequest.mostRecent.url).toBe('/flibbertyJibbet'); + + MockXMLHttpRequest.mostRecent.respondWith({ + 'status': 200, + 'contentType': 'application/json', + 'responseText': JSON.stringify(expected) + }); + + expect(innerResult.xhr).toBeDefined(); + expect(innerResult.response).toEqual({ larf: 'hahahahaha' }); + expect(result).toBe('HAHAHAHAHA'); + expect(complete).toBe(true); + }); + }); + + describe('ajax.post', () => { + it('should succeed on 200', () => { + const expected = { foo: 'bar', hi: 'there you' }; + let result; + let complete = false; + + Rx.Observable + .ajax.post('/flibbertyJibbet', expected) + .subscribe((x: any) => { + result = x; + }, null , () => { + complete = true; + }); + + const request = MockXMLHttpRequest.mostRecent; + + expect(request.method).toBe('POST'); + expect(request.url).toBe('/flibbertyJibbet'); + expect(request.requestHeaders).toEqual({ + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }); + + request.respondWith({ + 'status': 200, + 'contentType': 'application/json', + 'responseText': JSON.stringify(expected) + }); + + expect(request.data).toEqual('foo=bar&hi=there%20you'); + expect(result.response).toEqual(expected); + expect(complete).toBe(true); + }); + }); +}); + diff --git a/spec/observables/dom/webSocket-spec.js b/spec/observables/dom/webSocket-spec.js deleted file mode 100644 index 994ddacce8..0000000000 --- a/spec/observables/dom/webSocket-spec.js +++ /dev/null @@ -1,445 +0,0 @@ -/* globals describe, it, expect, rxTestScheduler */ -var Rx = require('../../../dist/cjs/Rx.DOM'); -var Observable = Rx.Observable; - -var __ws; -var sockets = []; - -function MockWebSocket(url, protocol) { - sockets.push(this); - this.url = url; - this.protocol = protocol; - this.sent = []; - this.handlers = {}; - this.readyState = 0; -} - -MockWebSocket.lastSocket = function () { - return sockets.length > 0 ? sockets[sockets.length - 1] : undefined; -}; - -MockWebSocket.prototype = { - send: function (data) { - this.sent.push(data); - }, - - lastMessageSent: function () { - var sent = this.sent; - return sent.length > 0 ? sent[sent.length - 1] : undefined; - }, - - triggerClose: function (e) { - this.readyState = 3; - this.trigger('close', e); - }, - - triggerError: function (err) { - this.readyState = 3; - this.trigger('error', err); - }, - - triggerMessage: function (data) { - var messageEvent = { - data: data, - origin: 'mockorigin', - ports: undefined, - source: __root__, - }; - - this.trigger('message', messageEvent); - }, - - open: function () { - this.readyState = 1; - this.trigger('open', {}); - }, - - close: function (code, reason) { - if (this.readyState < 2) { - this.readyState = 2; - this.closeCode = code; - this.closeReason = reason; - this.triggerClose({ wasClean: true }); - } - }, - - addEventListener: function (name, handler) { - var lookup = this.handlers[name] = this.handlers[name] || []; - lookup.push(handler); - }, - - removeEventListener: function (name, handler) { - var lookup = this.handlers[name]; - if (lookup) { - for (var i = lookup.length - 1; i--;) { - if (lookup[i] === handler) { - lookup.splice(i, 1); - } - } - } - }, - - trigger: function (name, e) { - if (this['on' + name]) { - this['on' + name](e); - } - - var lookup = this.handlers[name]; - if (lookup) { - for (var i = 0; i < lookup.length; i++) { - lookup[i](e); - } - } - } -}; - -function setupMockWebSocket() { - sockets = []; - __ws = __root__.WebSocket; - __root__.WebSocket = MockWebSocket; -} - -function teardownMockWebSocket() { - __root__.WebSocket = __ws; - sockets = null; -} - -describe('Observable.webSocket', function () { - beforeEach(function () { - setupMockWebSocket(); - }); - - afterEach(function () { - teardownMockWebSocket(); - }); - - it('should send and receive messages', function () { - var messageReceived = false; - var subject = Observable.webSocket('ws://mysocket'); - - subject.next('ping'); - - subject.subscribe(function (x) { - expect(x).toBe('pong'); - messageReceived = true; - }); - - var socket = MockWebSocket.lastSocket(); - expect(socket.url).toBe('ws://mysocket'); - - socket.open(); - expect(socket.lastMessageSent()).toBe('ping'); - - socket.triggerMessage(JSON.stringify('pong')); - expect(messageReceived).toBe(true); - }); - - it('receive multiple messages', function () { - var expected = ['what', 'do', 'you', 'do', 'with', 'a', 'drunken', 'sailor?']; - var results = []; - var subject = Observable.webSocket('ws://mysocket'); - - subject.subscribe(function (x) { - results.push(x); - }); - - var socket = MockWebSocket.lastSocket(); - - socket.open(); - - expected.forEach(function (x) { - socket.triggerMessage(JSON.stringify(x)); - }); - - expect(results).toEqual(expected); - }); - - it('should queue messages prior to subscription', function () { - var expected = ['make', 'him', 'walk', 'the', 'plank']; - var subject = Observable.webSocket('ws://mysocket'); - - expected.forEach(function (x) { - subject.next(x); - }); - - var socket = MockWebSocket.lastSocket(); - expect(socket).not.toBeDefined(); - - subject.subscribe(); - - socket = MockWebSocket.lastSocket(); - expect(socket.sent.length).toBe(0); - - socket.open(); - expect(socket.sent.length).toBe(expected.length); - }); - - it('should send messages immediately if already open', function () { - var subject = Observable.webSocket('ws://mysocket'); - subject.subscribe(); - var socket = MockWebSocket.lastSocket(); - socket.open(); - - subject.next('avast!'); - expect(socket.lastMessageSent()).toBe('avast!'); - subject.next('ye swab!'); - expect(socket.lastMessageSent()).toBe('ye swab!'); - }); - - it('should close the socket when completed', function () { - var subject = Observable.webSocket('ws://mysocket'); - subject.subscribe(); - var socket = MockWebSocket.lastSocket(); - socket.open(); - - expect(socket.readyState).toBe(1); // open - - spyOn(socket, 'close').and.callThrough(); - expect(socket.close).not.toHaveBeenCalled(); - - subject.complete(); - expect(socket.close).toHaveBeenCalled(); - expect(socket.readyState).toBe(3); // closed - }); - - it('should close the socket with a code and a reason when errored', function () { - var subject = Observable.webSocket('ws://mysocket'); - subject.subscribe(); - var socket = MockWebSocket.lastSocket(); - socket.open(); - - spyOn(socket, 'close').and.callThrough(); - expect(socket.close).not.toHaveBeenCalled(); - - subject.error({ code: 1337, reason: 'Too bad, so sad :('}); - expect(socket.close).toHaveBeenCalledWith(1337, 'Too bad, so sad :('); - }); - - it('should allow resubscription after closure via complete', function () { - var subject = Observable.webSocket('ws://mysocket'); - subject.subscribe(); - var socket1 = MockWebSocket.lastSocket(); - socket1.open(); - subject.complete(); - - subject.next('a mariner yer not. yarrr.'); - subject.subscribe(); - var socket2 = MockWebSocket.lastSocket(); - socket2.open(); - - expect(socket2).not.toBe(socket1); - expect(socket2.lastMessageSent()).toBe('a mariner yer not. yarrr.'); - }); - - it('should allow resubscription after closure via error', function () { - var subject = Observable.webSocket('ws://mysocket'); - subject.subscribe(); - var socket1 = MockWebSocket.lastSocket(); - socket1.open(); - subject.error({ code: 1337 }); - - subject.next('yo-ho! yo-ho!'); - subject.subscribe(); - var socket2 = MockWebSocket.lastSocket(); - socket2.open(); - - expect(socket2).not.toBe(socket1); - expect(socket2.lastMessageSent()).toBe('yo-ho! yo-ho!'); - }); - - it('should have a default resultSelector that parses message data as JSON', function () { - var result; - var expected = { mork: 'shazbot!' }; - var subject = Observable.webSocket('ws://mysocket'); - - subject.subscribe(function (x) { - result = x; - }); - - var socket = MockWebSocket.lastSocket(); - socket.open(); - socket.triggerMessage(JSON.stringify(expected)); - - expect(result).toEqual(expected); - }); - - describe('with a config object', function () { - it('should send and receive messages', function () { - var messageReceived = false; - var subject = Observable.webSocket({ url: 'ws://mysocket' }); - - subject.next('ping'); - - subject.subscribe(function (x) { - expect(x).toBe('pong'); - messageReceived = true; - }); - - var socket = MockWebSocket.lastSocket(); - expect(socket.url).toBe('ws://mysocket'); - - socket.open(); - expect(socket.lastMessageSent()).toBe('ping'); - - socket.triggerMessage(JSON.stringify('pong')); - expect(messageReceived).toBe(true); - }); - - it('should take a protocol and set it properly on the web socket', function () { - var subject = Observable.webSocket({ - url: 'ws://mysocket', - protocol: 'someprotocol' - }); - - subject.subscribe(); - - var socket = MockWebSocket.lastSocket(); - expect(socket.protocol).toBe('someprotocol'); - }); - - it('should take a resultSelector', function () { - var results = []; - - var subject = Observable.webSocket({ - url: 'ws://mysocket', - resultSelector: function (e) { - return e.data + '!'; - } - }); - - subject.subscribe(function (x) { - results.push(x); - }); - - var socket = MockWebSocket.lastSocket(); - socket.open(); - ['ahoy', 'yarr', 'shove off'].forEach(function (x) { - socket.triggerMessage(x); - }); - - expect(results).toEqual(['ahoy!', 'yarr!', 'shove off!']); - }); - - it('if the resultSelector fails it should go down the error path', function () { - var subject = Observable.webSocket({ - url: 'ws://mysocket', - resultSelector: function (e) { - throw new Error('I am a bad error'); - } - }); - - subject.subscribe(function (x) { - expect(x).toBe('this should not happen'); - }, function (err) { - expect(err).toEqual(new Error('I am a bad error')); - }); - - var socket = MockWebSocket.lastSocket(); - socket.open(); - socket.triggerMessage('weee!'); - }); - - it('should accept a closingObserver', function () { - var calls = 0; - var subject = Observable.webSocket({ - url: 'ws://mysocket', - closingObserver: { - next: function (x) { - calls++; - expect(x).toBe(undefined); - } - } - }); - - subject.subscribe(); - var socket = MockWebSocket.lastSocket(); - socket.open(); - - expect(calls).toBe(0); - - subject.complete(); - expect(calls).toBe(1); - - subject.subscribe(); - socket = MockWebSocket.lastSocket(); - socket.open(); - - subject.error({ code: 1337 }); - expect(calls).toBe(2); - }); - - it('should accept a closeObserver', function () { - var expected = [{ wasClean: true }, { wasClean: false }]; - var closes = []; - var subject = Observable.webSocket({ - url: 'ws://mysocket', - closeObserver: { - next: function (e) { - closes.push(e); - } - } - }); - - subject.subscribe(); - var socket = MockWebSocket.lastSocket(); - socket.open(); - - expect(closes.length).toBe(0); - - socket.triggerClose(expected[0]); - expect(closes.length).toBe(1); - - subject.subscribe(null, function (err) { - expect(err).toBe(expected[1]); - }); - - socket = MockWebSocket.lastSocket(); - socket.open(); - - socket.triggerClose(expected[1]); - expect(closes.length).toBe(2); - - expect(closes[0]).toBe(expected[0]); - expect(closes[1]).toBe(expected[1]); - }); - }); - - describe('multiplex', function () { - it('should multiplex over the websocket', function () { - var results = []; - var subject = Observable.webSocket('ws://websocket'); - var source = subject.multiplex(function () { - return { sub: 'foo'}; - }, function () { - return { unsub: 'foo' }; - }, function (value) { - return value.name === 'foo'; - }); - - var sub = source.subscribe(function (x) { - results.push(x.value); - }); - var socket = MockWebSocket.lastSocket(); - socket.open(); - - expect(socket.lastMessageSent()).toEqual({ sub: 'foo' }); - - [1, 2, 3, 4, 5].map(function (x) { - return { - name: x % 3 === 0 ? 'bar' : 'foo', - value: x - }; - }).forEach(function (x) { - socket.triggerMessage(JSON.stringify(x)); - }); - - expect(results).toEqual([1, 2, 4, 5]); - - spyOn(socket, 'close').and.callThrough(); - sub.unsubscribe(); - expect(socket.lastMessageSent()).toEqual({ unsub: 'foo' }); - - expect(socket.close).toHaveBeenCalled(); - }); - }); -}); \ No newline at end of file diff --git a/spec/observables/dom/webSocket-spec.ts b/spec/observables/dom/webSocket-spec.ts new file mode 100644 index 0000000000..608c896681 --- /dev/null +++ b/spec/observables/dom/webSocket-spec.ts @@ -0,0 +1,389 @@ +import * as Rx from '../../../dist/cjs/Rx.DOM'; +import {MockWebSocket} from '../../helpers/ajax-helper'; +import {it} from '../../helpers/test-helper'; + +declare const __root__: any; + +const Observable = Rx.Observable; +var __ws: any; + +function setupMockWebSocket() { + MockWebSocket.clearSockets(); + __ws = __root__.WebSocket; + __root__.WebSocket = MockWebSocket; +} + +function teardownMockWebSocket() { + __root__.WebSocket = __ws; + MockWebSocket.clearSockets(); +} + +describe('Observable.webSocket', () => { + beforeEach(() => { + setupMockWebSocket(); + }); + + afterEach(() => { + teardownMockWebSocket(); + }); + + it('should send and receive messages', () => { + let messageReceived = false; + const subject = Observable.webSocket('ws://mysocket'); + + subject.next('ping'); + + subject.subscribe((x: string) => { + expect(x).toBe('pong'); + messageReceived = true; + }); + + const socket = MockWebSocket.lastSocket; + expect(socket.url).toBe('ws://mysocket'); + + socket.open(); + expect(socket.lastMessageSent).toBe('ping'); + + socket.triggerMessage(JSON.stringify('pong')); + expect(messageReceived).toBe(true); + + subject.unsubscribe(); + }); + + it('receive multiple messages', () => { + const expected = ['what', 'do', 'you', 'do', 'with', 'a', 'drunken', 'sailor?']; + const results = []; + const subject = Observable.webSocket('ws://mysocket'); + + subject.subscribe((x: string) => { + results.push(x); + }); + + const socket = MockWebSocket.lastSocket; + + socket.open(); + + expected.forEach((x: string) => { + socket.triggerMessage(JSON.stringify(x)); + }); + + expect(results).toEqual(expected); + + subject.unsubscribe(); + }); + + it('should queue messages prior to subscription', () => { + const expected = ['make', 'him', 'walk', 'the', 'plank']; + const subject = Observable.webSocket('ws://mysocket'); + + expected.forEach((x: string) => { + subject.next(x); + }); + + let socket = MockWebSocket.lastSocket; + expect(socket).not.toBeDefined(); + + subject.subscribe(); + + socket = MockWebSocket.lastSocket; + expect(socket.sent.length).toBe(0); + + socket.open(); + expect(socket.sent.length).toBe(expected.length); + + subject.unsubscribe(); + }); + + it('should send messages immediately if already open', () => { + const subject = Observable.webSocket('ws://mysocket'); + subject.subscribe(); + const socket = MockWebSocket.lastSocket; + socket.open(); + + subject.next('avast!'); + expect(socket.lastMessageSent).toBe('avast!'); + subject.next('ye swab!'); + expect(socket.lastMessageSent).toBe('ye swab!'); + + subject.unsubscribe(); + }); + + it('should close the socket when completed', () => { + const subject = Observable.webSocket('ws://mysocket'); + subject.subscribe(); + const socket = MockWebSocket.lastSocket; + socket.open(); + + expect(socket.readyState).toBe(1); // open + + spyOn(socket, 'close').and.callThrough(); + expect(socket.close).not.toHaveBeenCalled(); + + subject.complete(); + expect(socket.close).toHaveBeenCalled(); + expect(socket.readyState).toBe(3); // closed + + subject.unsubscribe(); + }); + + it('should close the socket with a code and a reason when errored', () => { + const subject = Observable.webSocket('ws://mysocket'); + subject.subscribe(); + const socket = MockWebSocket.lastSocket; + socket.open(); + + spyOn(socket, 'close').and.callThrough(); + expect(socket.close).not.toHaveBeenCalled(); + + subject.error({ code: 1337, reason: 'Too bad, so sad :('}); + expect(socket.close).toHaveBeenCalledWith(1337, 'Too bad, so sad :('); + + subject.unsubscribe(); + }); + + it('should allow resubscription after closure via complete', () => { + const subject = Observable.webSocket('ws://mysocket'); + subject.subscribe(); + const socket1 = MockWebSocket.lastSocket; + socket1.open(); + subject.complete(); + + subject.next('a mariner yer not. yarrr.'); + subject.subscribe(); + const socket2 = MockWebSocket.lastSocket; + socket2.open(); + + expect(socket2).not.toBe(socket1); + expect(socket2.lastMessageSent).toBe('a mariner yer not. yarrr.'); + + subject.unsubscribe(); + }); + + it('should allow resubscription after closure via error', () => { + const subject = Observable.webSocket('ws://mysocket'); + subject.subscribe(); + const socket1 = MockWebSocket.lastSocket; + socket1.open(); + subject.error({ code: 1337 }); + + subject.next('yo-ho! yo-ho!'); + subject.subscribe(); + const socket2 = MockWebSocket.lastSocket; + socket2.open(); + + expect(socket2).not.toBe(socket1); + expect(socket2.lastMessageSent).toBe('yo-ho! yo-ho!'); + + subject.unsubscribe(); + }); + + it('should have a default resultSelector that parses message data as JSON', () => { + let result; + const expected = { mork: 'shazbot!' }; + const subject = Observable.webSocket('ws://mysocket'); + + subject.subscribe((x: any) => { + result = x; + }); + + const socket = MockWebSocket.lastSocket; + socket.open(); + socket.triggerMessage(JSON.stringify(expected)); + + expect(result).toEqual(expected); + + subject.unsubscribe(); + }); + + describe('with a config object', () => { + it('should send and receive messages', () => { + let messageReceived = false; + const subject = Observable.webSocket({ url: 'ws://mysocket' }); + + subject.next('ping'); + + subject.subscribe((x: string) => { + expect(x).toBe('pong'); + messageReceived = true; + }); + + const socket = MockWebSocket.lastSocket; + expect(socket.url).toBe('ws://mysocket'); + + socket.open(); + expect(socket.lastMessageSent).toBe('ping'); + + socket.triggerMessage(JSON.stringify('pong')); + expect(messageReceived).toBe(true); + + subject.unsubscribe(); + }); + + it('should take a protocol and set it properly on the web socket', () => { + const subject = Observable.webSocket({ + url: 'ws://mysocket', + protocol: 'someprotocol' + }); + + subject.subscribe(); + + const socket = MockWebSocket.lastSocket; + expect(socket.protocol).toBe('someprotocol'); + + subject.unsubscribe(); + }); + + it('should take a resultSelector', () => { + const results = []; + + const subject = Observable.webSocket({ + url: 'ws://mysocket', + resultSelector: (e: any) => { + return e.data + '!'; + } + }); + + subject.subscribe((x: any) => { + results.push(x); + }); + + const socket = MockWebSocket.lastSocket; + socket.open(); + ['ahoy', 'yarr', 'shove off'].forEach((x: any) => { + socket.triggerMessage(x); + }); + + expect(results).toEqual(['ahoy!', 'yarr!', 'shove off!']); + + subject.unsubscribe(); + }); + + it('if the resultSelector fails it should go down the error path', () => { + const subject = Observable.webSocket({ + url: 'ws://mysocket', + resultSelector: (e: any) => { + throw new Error('I am a bad error'); + } + }); + + subject.subscribe((x: any) => { + expect(x).toBe('this should not happen'); + }, (err: any) => { + expect(err).toEqual(new Error('I am a bad error')); + }); + + const socket = MockWebSocket.lastSocket; + socket.open(); + socket.triggerMessage('weee!'); + + subject.unsubscribe(); + }); + + it('should accept a closingObserver', () => { + let calls = 0; + const subject = Observable.webSocket({ + url: 'ws://mysocket', + closingObserver: { + next: function (x) { + calls++; + expect(x).toBe(undefined); + } + } + }); + + subject.subscribe(); + let socket = MockWebSocket.lastSocket; + socket.open(); + + expect(calls).toBe(0); + + subject.complete(); + expect(calls).toBe(1); + + subject.subscribe(); + socket = MockWebSocket.lastSocket; + socket.open(); + + subject.error({ code: 1337 }); + expect(calls).toBe(2); + + subject.unsubscribe(); + }); + + it('should accept a closeObserver', () => { + const expected = [{ wasClean: true }, { wasClean: false }]; + const closes = []; + const subject = Observable.webSocket({ + url: 'ws://mysocket', + closeObserver: { + next: function (e) { + closes.push(e); + } + } + }); + + subject.subscribe(); + let socket = MockWebSocket.lastSocket; + socket.open(); + + expect(closes.length).toBe(0); + + socket.triggerClose(expected[0]); + expect(closes.length).toBe(1); + + subject.subscribe(null, function (err) { + expect(err).toBe(expected[1]); + }); + + socket = MockWebSocket.lastSocket; + socket.open(); + + socket.triggerClose(expected[1]); + expect(closes.length).toBe(2); + + expect(closes[0]).toBe(expected[0]); + expect(closes[1]).toBe(expected[1]); + + subject.unsubscribe(); + }); + }); + + describe('multiplex', () => { + it('should multiplex over the websocket', () => { + const results = []; + const subject = Observable.webSocket('ws://websocket'); + const source = subject.multiplex(() => { + return { sub: 'foo'}; + }, () => { + return { unsub: 'foo' }; + }, function (value: any) { + return value.name === 'foo'; + }); + + const sub = source.subscribe(function (x: any) { + results.push(x.value); + }); + const socket = MockWebSocket.lastSocket; + socket.open(); + + expect(socket.lastMessageSent).toEqual({ sub: 'foo' }); + + [1, 2, 3, 4, 5].map((x: number) => { + return { + name: x % 3 === 0 ? 'bar' : 'foo', + value: x + }; + }).forEach((x: any) => { + socket.triggerMessage(JSON.stringify(x)); + }); + + expect(results).toEqual([1, 2, 4, 5]); + + spyOn(socket, 'close').and.callThrough(); + sub.unsubscribe(); + expect(socket.lastMessageSent).toEqual({ unsub: 'foo' }); + + expect(socket.close).toHaveBeenCalled(); + }); + }); +}); \ No newline at end of file diff --git a/spec/observables/forkJoin-spec.js b/spec/observables/forkJoin-spec.ts similarity index 58% rename from spec/observables/forkJoin-spec.js rename to spec/observables/forkJoin-spec.ts index 056cefb334..543bad48e7 100644 --- a/spec/observables/forkJoin-spec.js +++ b/spec/observables/forkJoin-spec.ts @@ -1,263 +1,264 @@ -/* globals describe, it, expect, lowerCaseO, hot, expectObservable */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.forkJoin', function () { - it('should join the last values of the provided observables into an array', function () { - var e1 = Observable.forkJoin( +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature, lowerCaseO} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.forkJoin', () => { + it('should join the last values of the provided observables into an array', () => { + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('(b|)'), hot('--1--2--3--|') ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: ['d', 'b', '3']}); + }); - //Hack - just adding one new test cases in here or either jasmin-is-weird-spec.js, - //one of test breaks under publish-spec.js - var e2 = Observable.forkJoin( + it('should allow emit null or undefined', () => { + const e2 = Observable.forkJoin( hot('--a--b--c--d--|', { d: null }), hot('(b|)'), hot('--1--2--3--|'), hot('-----r--t--u--|', { u: undefined }) ); - var expected2 = '--------------(x|)'; + const expected2 = '--------------(x|)'; expectObservable(e2).toBe(expected2, {x: [null, 'b', '3', undefined]}); }); - it('should join the last values of the provided observables with selector', function () { + it('should join the last values of the provided observables with selector', () => { function selector(x, y, z) { return x + y + z; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('(b|)'), hot('--1--2--3--|'), selector ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: 'db3'}); }); - it('should accept single observable', function () { - var e1 = Observable.forkJoin( + it('should accept single observable', () => { + const e1 = Observable.forkJoin( hot('--a--b--c--d--|') ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: ['d']}); }); - it('should accept array of observable contains single', function () { - var e1 = Observable.forkJoin( + it('should accept array of observable contains single', () => { + const e1 = Observable.forkJoin( [hot('--a--b--c--d--|')] ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: ['d']}); }); - it('should accept single observable with selector', function () { + it('should accept single observable with selector', () => { function selector(x) { return x + x; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), selector ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: 'dd'}); }); - it('should accept array of observable contains single with selector', function () { + it('should accept array of observable contains single with selector', () => { function selector(x) { return x + x; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( [hot('--a--b--c--d--|')], selector ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: 'dd'}); }); - it('should accept lowercase-o observables', function () { - var e1 = Observable.forkJoin( + it('should accept lowercase-o observables', () => { + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('(b|)'), lowerCaseO('1', '2', '3') ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: ['d', 'b', '3']}); }); - it('should accept promise', function (done) { - var e1 = Observable.forkJoin( + it('should accept promise', (done: DoneSignature) => { + const e1 = Observable.forkJoin( Observable.of(1), Promise.resolve(2) ); - e1.subscribe(function (x) { - expect(x).toEqual([1,2]); + e1.subscribe((x: Array) => { + expect(x).toEqual([1, 2]); }, - function (err) { + (err: any) => { done.fail('should not be called'); }, done); }); - it('should accept array of observables', function () { - var e1 = Observable.forkJoin( + it('should accept array of observables', () => { + const e1 = Observable.forkJoin( [hot('--a--b--c--d--|'), hot('(b|)'), hot('--1--2--3--|')] ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: ['d', 'b', '3']}); }); - it('should accept array of observables with selector', function () { + it('should accept array of observables with selector', () => { function selector(x, y, z) { return x + y + z; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( [hot('--a--b--c--d--|'), hot('(b|)'), hot('--1--2--3--|')], selector ); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: 'db3'}); }); - it('should not emit if any of source observable is empty', function () { - var e1 = Observable.forkJoin( + it('should not emit if any of source observable is empty', () => { + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('(b|)'), hot('------------------|') ); - var expected = '------------------|'; + const expected = '------------------|'; expectObservable(e1).toBe(expected); }); - it('should complete early if any of source is empty and completes before than others', function () { - var e1 = Observable.forkJoin( + it('should complete early if any of source is empty and completes before than others', () => { + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('(b|)'), hot('---------|') ); - var expected = '---------|'; + const expected = '---------|'; expectObservable(e1).toBe(expected); }); - it('should complete when all sources are empty', function () { - var e1 = Observable.forkJoin( + it('should complete when all sources are empty', () => { + const e1 = Observable.forkJoin( hot('--------------|'), hot('---------|') ); - var expected = '---------|'; + const expected = '---------|'; expectObservable(e1).toBe(expected); }); - it('should complete if source is not provided', function () { - var e1 = Observable.forkJoin(); - var expected = '|'; + it('should complete if source is not provided', () => { + const e1 = Observable.forkJoin(); + const expected = '|'; expectObservable(e1).toBe(expected); }); - it('should complete if sources list is empty', function () { - var e1 = Observable.forkJoin([]); - var expected = '|'; + it('should complete if sources list is empty', () => { + const e1 = Observable.forkJoin([]); + const expected = '|'; expectObservable(e1).toBe(expected); }); - it('should complete when any of source is empty with selector', function () { + it('should complete when any of source is empty with selector', () => { function selector(x, y) { return x + y; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('---------|'), selector); - var expected = '---------|'; + const expected = '---------|'; expectObservable(e1).toBe(expected); }); - it('should emit results by resultselector', function () { + it('should emit results by resultselector', () => { function selector(x, y) { return x + y; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( hot('--a--b--c--d--|'), hot('---2-----|'), selector); - var expected = '--------------(x|)'; + const expected = '--------------(x|)'; expectObservable(e1).toBe(expected, {x: 'd2'}); }); - it('should raise error when any of source raises error with empty observable', function () { - var e1 = Observable.forkJoin( + it('should raise error when any of source raises error with empty observable', () => { + const e1 = Observable.forkJoin( hot('------#'), hot('---------|')); - var expected = '------#'; + const expected = '------#'; expectObservable(e1).toBe(expected); }); - it('should raise error when any of source raises error with selector with empty observable', function () { + it('should raise error when any of source raises error with selector with empty observable', () => { function selector(x, y) { return x + y; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( hot('------#'), hot('---------|'), selector); - var expected = '------#'; + const expected = '------#'; expectObservable(e1).toBe(expected); }); - it('should raise error when source raises error', function () { - var e1 = Observable.forkJoin( + it('should raise error when source raises error', () => { + const e1 = Observable.forkJoin( hot('------#'), hot('---a-----|')); - var expected = '------#'; + const expected = '------#'; expectObservable(e1).toBe(expected); }); - it('should raise error when source raises error with selector', function () { + it('should raise error when source raises error with selector', () => { function selector(x, y) { return x + y; } - var e1 = Observable.forkJoin( + const e1 = Observable.forkJoin( hot('------#'), hot('-------b-|'), selector); - var expected = '------#'; + const expected = '------#'; expectObservable(e1).toBe(expected); }); diff --git a/spec/observables/from-promise-spec.js b/spec/observables/from-promise-spec.js deleted file mode 100644 index ed9d32be33..0000000000 --- a/spec/observables/from-promise-spec.js +++ /dev/null @@ -1,158 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.fromPromise', function () { - it('should emit one value from a resolved promise', function (done) { - var promise = Promise.resolve(42); - Observable.fromPromise(promise) - .subscribe( - function (x) { expect(x).toBe(42); }, - done.fail, - done); - }); - - it('should raise error from a rejected promise', function (done) { - var promise = Promise.reject('bad'); - Observable.fromPromise(promise) - .subscribe(done.fail, - function (e) { - expect(e).toBe('bad'); - done(); - }, - done.fail); - }); - - it('should share the underlying promise with multiple subscribers', function (done) { - var promise = Promise.resolve(42); - var observable = Observable.fromPromise(promise); - - observable - .subscribe( - function (x) { expect(x).toBe(42); }, - done.fail, - null); - setTimeout(function () { - observable - .subscribe( - function (x) { expect(x).toBe(42); }, - done.fail, - done); - }); - }); - - it('should accept already-resolved Promise', function (done) { - var promise = Promise.resolve(42); - promise.then(function (x) { - expect(x).toBe(42); - Observable.fromPromise(promise) - .subscribe( - function (y) { expect(y).toBe(42); }, - done.fail, - done); - }, done.fail); - }); - - it('should emit a value from a resolved promise on a separate scheduler', function (done) { - var promise = Promise.resolve(42); - Observable.fromPromise(promise, Rx.Scheduler.nextTick) - .subscribe( - function (x) { expect(x).toBe(42); }, - done.fail, - done); - }); - - it('should raise error from a rejected promise on a separate scheduler', function (done) { - var promise = Promise.reject('bad'); - Observable.fromPromise(promise, Rx.Scheduler.nextTick) - .subscribe( - done.fail, - function (e) { - expect(e).toBe('bad'); - done(); - }, - done.fail); - }); - - it('should share the underlying promise with multiple subscribers on a separate scheduler', function (done) { - var promise = Promise.resolve(42); - var observable = Observable.fromPromise(promise, Rx.Scheduler.nextTick); - - observable - .subscribe( - function (x) { expect(x).toBe(42); }, - done.fail, - null); - setTimeout(function () { - observable - .subscribe( - function (x) { expect(x).toBe(42); }, - done.fail, - done); - }); - }); - - it('should not emit, throw or complete if immediately unsubscribed', function (done) { - var nextSpy = jasmine.createSpy('next'); - var throwSpy = jasmine.createSpy('throw'); - var completeSpy = jasmine.createSpy('complete'); - var promise = Promise.resolve(42); - var subscription = Observable.fromPromise(promise) - .subscribe(nextSpy, throwSpy, completeSpy); - subscription.unsubscribe(); - - setTimeout(function () { - expect(nextSpy).not.toHaveBeenCalled(); - expect(throwSpy).not.toHaveBeenCalled(); - expect(completeSpy).not.toHaveBeenCalled(); - done(); - }); - }); - - if (typeof process === 'object' && Object.prototype.toString.call(process) === '[object process]') { - it('should globally throw unhandled errors on process', function (done) { - var invoked = false; - process.on('uncaughtException', function (reason, p) { - if (invoked) { - return; - } - invoked = true; - expect(reason).toBe('fail'); - done(); - }); - - Observable.fromPromise(Promise.reject('bad')) - .subscribe( - done.fail, - function (e) { - expect(e).toBe('bad'); - throw 'fail'; - }, - done.fail); - }); - } else if (typeof window === 'object' && Object.prototype.toString.call(window) === '[object global]') { - it('should globally throw unhandled errors on window', function (done) { - var invoked = false; - function onException(e) { - if (invoked) { - return; - } - invoked = true; - expect(e).toBe('Uncaught fail'); - done(); - } - - window.onerror = onException; - - Observable.fromPromise(Promise.reject('bad')) - .subscribe( - done.fail, - function (e) { - expect(e).toBe('bad'); - throw 'fail'; - }, - done.fail); - }); - } -}); \ No newline at end of file diff --git a/spec/observables/from-promise-spec.ts b/spec/observables/from-promise-spec.ts new file mode 100644 index 0000000000..e5eba23e4f --- /dev/null +++ b/spec/observables/from-promise-spec.ts @@ -0,0 +1,161 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const process: any; +const Observable = Rx.Observable; + +describe('Observable.fromPromise', () => { + it('should emit one value from a resolved promise', (done: DoneSignature) => { + const promise = Promise.resolve(42); + Observable.fromPromise(promise) + .subscribe( + (x: number) => { expect(x).toBe(42); }, + done.fail, + done); + }); + + it('should raise error from a rejected promise', (done: DoneSignature) => { + const promise = Promise.reject('bad'); + Observable.fromPromise(promise) + .subscribe((x: any) => { + done.fail('should not be called'); + }, + (e: any) => { + expect(e).toBe('bad'); + done(); + }, + done.fail); + }); + + it('should share the underlying promise with multiple subscribers', (done: DoneSignature) => { + const promise = Promise.resolve(42); + const observable = Observable.fromPromise(promise); + + observable + .subscribe( + (x: number) => { expect(x).toBe(42); }, + done.fail, + null); + setTimeout(() => { + observable + .subscribe( + (x: number) => { expect(x).toBe(42); }, + done.fail, + done); + }); + }); + + it('should accept already-resolved Promise', (done: DoneSignature) => { + const promise = Promise.resolve(42); + promise.then((x: number) => { + expect(x).toBe(42); + Observable.fromPromise(promise) + .subscribe( + (y: number) => { expect(y).toBe(42); }, + done.fail, + done); + }, done.fail); + }); + + it('should emit a value from a resolved promise on a separate scheduler', (done: DoneSignature) => { + const promise = Promise.resolve(42); + Observable.fromPromise(promise, Rx.Scheduler.asap) + .subscribe( + (x: number) => { expect(x).toBe(42); }, + done.fail, + done); + }); + + it('should raise error from a rejected promise on a separate scheduler', (done: DoneSignature) => { + const promise = Promise.reject('bad'); + Observable.fromPromise(promise, Rx.Scheduler.asap) + .subscribe( + (x: any) => { done.fail('should not be called'); }, + (e: any) => { + expect(e).toBe('bad'); + done(); + }, + done.fail); + }); + + it('should share the underlying promise with multiple subscribers on a separate scheduler', (done: DoneSignature) => { + const promise = Promise.resolve(42); + const observable = Observable.fromPromise(promise, Rx.Scheduler.asap); + + observable + .subscribe( + (x: number) => { expect(x).toBe(42); }, + done.fail, + null); + setTimeout(() => { + observable + .subscribe( + (x: number) => { expect(x).toBe(42); }, + done.fail, + done); + }); + }); + + it('should not emit, throw or complete if immediately unsubscribed', (done: DoneSignature) => { + const nextSpy = jasmine.createSpy('next'); + const throwSpy = jasmine.createSpy('throw'); + const completeSpy = jasmine.createSpy('complete'); + const promise = Promise.resolve(42); + const subscription = Observable.fromPromise(promise) + .subscribe(nextSpy, throwSpy, completeSpy); + subscription.unsubscribe(); + + setTimeout(() => { + expect(nextSpy).not.toHaveBeenCalled(); + expect(throwSpy).not.toHaveBeenCalled(); + expect(completeSpy).not.toHaveBeenCalled(); + done(); + }); + }); + + if (typeof process === 'object' && Object.prototype.toString.call(process) === '[object process]') { + it('should globally throw unhandled errors on process', (done: DoneSignature) => { + let invoked = false; + process.on('uncaughtException', function (reason, p) { + if (invoked) { + return; + } + invoked = true; + expect(reason).toBe('fail'); + done(); + }); + + Observable.fromPromise(Promise.reject('bad')) + .subscribe( + (x: any) => { done.fail('should not be called'); }, + (e: any) => { + expect(e).toBe('bad'); + throw 'fail'; + }, + done.fail); + }); + } else if (typeof window === 'object' && Object.prototype.toString.call(window) === '[object global]') { + it('should globally throw unhandled errors on window', (done: DoneSignature) => { + let invoked = false; + function onException(e) { + if (invoked) { + return; + } + invoked = true; + expect(e).toBe('Uncaught fail'); + done(); + } + + window.onerror = onException; + + Observable.fromPromise(Promise.reject('bad')) + .subscribe( + (x: any) => { done.fail('should not be called'); }, + (e: any) => { + expect(e).toBe('bad'); + throw 'fail'; + }, + done.fail); + }); + } +}); \ No newline at end of file diff --git a/spec/observables/from-spec.js b/spec/observables/from-spec.js deleted file mode 100644 index 8cb63c940d..0000000000 --- a/spec/observables/from-spec.js +++ /dev/null @@ -1,168 +0,0 @@ -/* globals describe, it, expect, Symbol, expectObservable, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Promise = require('promise'); -var Observable = Rx.Observable; -var $$iterator = require('../../dist/cjs/util/SymbolShim').SymbolShim.iterator; - -describe('Observable.from', function () { - it('should enumerate an Array', function (done) { - var expected = [1, 2, 3]; - var i = 0; - Observable.from(expected).subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }, 300); - - it('should handle an ArrayLike', function (done) { - var arrayLike = { - length: 3, - 0: 1, - 1: 2, - 2: 3 - }; - var expected = [1, 2, 3]; - var i = 0; - Observable.from(arrayLike).subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }, 300); - - it('should handle an ArrayLike from arguments', function (done) { - function makeArrayLike() { - var expected = [1, 2, 3]; - var i = 0; - - Observable.from(arguments).subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - } - - makeArrayLike(1, 2, 3); - }, 300); - - it('should handle an ArrayLike with a mapFn', function (done) { - var arrayLike = { - length: 3, - 0: 1, - 1: 2, - 2: 3 - }; - var expected = [1, 1, 1]; - var i = 0; - var mapFn = function (v, k) { - return v - k; - }; - Observable.from(arrayLike, mapFn).subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }, 300); - - it('should handle an ArrayLike with a thisArg', function (done) { - var arrayLike = { - length: 3, - 0: 1, - 1: 2, - 2: 3 - }; - var expected = [123, 123, 123]; - var i = 0; - var mapFn = function (x, y) { - return this.thing; - }; - Observable.from(arrayLike, mapFn, {thing: 123}).subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }); - - it('should handle a promise', function (done) { - var promise = Promise.resolve('pinky swear'); - - Observable.from(promise).subscribe(function (x) { - expect(x).toBe('pinky swear'); - }, null, done); - }); - - it('should handle an "observableque" object', function (done) { - var observablesque = {}; - - observablesque[Symbol.observable] = function () { - return { - subscribe: function (observer) { - observer.next('test'); - observer.complete(); - } - }; - }; - - Observable.from(observablesque).subscribe(function (x) { - expect(x).toBe('test'); - }, null, done); - }); - - it('should accept scheduler for observableque object', function () { - var observablesque = {}; - - observablesque[Symbol.observable] = function () { - return { - subscribe: function (observer) { - observer.next('x'); - observer.complete(); - } - }; - }; - - var e1 = Observable.from(observablesque, rxTestScheduler); - var expected = '(x|)'; - - expectObservable(e1).toBe(expected); - }); - - it('should handle a string', function (done) { - var expected = ['a', 'b', 'c']; - Observable.from('abc').subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, done); - }); - - it('should handle any iterable thing', function (done) { - var iterable = {}; - var iteratorResults = [ - { value: 'one', done: false }, - { value: 'two', done: false }, - { done: true } - ]; - var expected = ['one', 'two']; - - expect($$iterator).toBe(Symbol.iterator); - - iterable[Symbol.iterator] = function () { - return { - next: function () { - return iteratorResults.shift(); - } - }; - }; - - Observable.from(iterable).subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, done); - }); - - it('should throw for non observable object', function () { - var r = function () { - Observable.from({}).subscribe(); - }; - - expect(r).toThrow(); - }); - - it('should handle object has observable symbol', function (done) { - var value = 'x'; - - Observable.from(Observable.of(value)).subscribe(function (x) { - expect(x).toBe(value); - }, function (err) { - done.fail('should not be called'); - }, done); - }); -}); diff --git a/spec/observables/from-spec.ts b/spec/observables/from-spec.ts new file mode 100644 index 0000000000..7c2001de90 --- /dev/null +++ b/spec/observables/from-spec.ts @@ -0,0 +1,170 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {SymbolShim} from '../../dist/cjs/util/SymbolShim'; +import {expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const Symbol: any; +declare const rxTestScheduler: Rx.TestScheduler; +const $$iterator = SymbolShim.iterator; +const Observable = Rx.Observable; + +describe('Observable.from', () => { + it('should enumerate an Array', (done: DoneSignature) => { + const expected = [1, 2, 3]; + let i = 0; + + Observable.from(expected).subscribe((x: number) => { + expect(x).toBe(expected[i++]); + }, done.fail, done); + }, 300); + + it('should handle an ArrayLike', (done: DoneSignature) => { + const arrayLike = { + length: 3, + 0: 1, + 1: 2, + 2: 3 + }; + const expected = [1, 2, 3]; + + Observable.from(arrayLike).subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, done.fail, done); + }, 300); + + it('should handle an ArrayLike from arguments', (done: DoneSignature) => { + function makeArrayLike(...args) { + const expected = [1, 2, 3]; + + Observable.from(arguments).subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, done.fail, done); + } + + makeArrayLike(1, 2, 3); + }, 300); + + it('should handle an ArrayLike with a mapFn', (done: DoneSignature) => { + const arrayLike = { + length: 3, + 0: 1, + 1: 2, + 2: 3 + }; + const expected = [1, 1, 1]; + const mapFn = (v, k) => v - k; + + Observable.from(arrayLike, mapFn).subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, done.fail, done); + }, 300); + + it('should handle an ArrayLike with a thisArg', (done: DoneSignature) => { + const arrayLike = { + length: 3, + 0: 1, + 1: 2, + 2: 3 + }; + const expected = [123, 123, 123]; + const mapFn = function (x, y) { + return this.thing; + }; + + Observable.from(arrayLike, mapFn, {thing: 123}).subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, done.fail, done); + }); + + it('should handle a promise', (done: DoneSignature) => { + const promise = Promise.resolve('pinky swear'); + + Observable.from(promise).subscribe((x: string) => { + expect(x).toBe('pinky swear'); + }, done.fail, done); + }); + + it('should handle an "observableque" object', (done: DoneSignature) => { + const observablesque = {}; + + observablesque[Symbol.observable] = () => { + return { + subscribe: (observer: Rx.Observer) => { + observer.next('test'); + observer.complete(); + } + }; + }; + + Observable.from(observablesque).subscribe((x: string) => { + expect(x).toBe('test'); + }, done.fail, done); + }); + + it('should accept scheduler for observableque object', () => { + const observablesque = {}; + + observablesque[Symbol.observable] = () => { + return { + subscribe: (observer: Rx.Observer) => { + observer.next('x'); + observer.complete(); + } + }; + }; + + const e1 = Observable.from(observablesque, rxTestScheduler); + const expected = '(x|)'; + + expectObservable(e1).toBe(expected); + }); + + it('should handle a string', (done: DoneSignature) => { + const expected = ['a', 'b', 'c']; + Observable.from('abc').subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, done.fail, done); + }); + + it('should handle any iterable thing', (done: DoneSignature) => { + const iterable = {}; + const iteratorResults = [ + { value: 'one', done: false }, + { value: 'two', done: false }, + { done: true } + ]; + const expected = ['one', 'two']; + + expect($$iterator).toBe(Symbol.iterator); + + iterable[Symbol.iterator] = () => { + return { + next: () => { + return iteratorResults.shift(); + } + }; + }; + + Observable.from(iterable).subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, done.fail, done); + }); + + it('should throw for non observable object', () => { + const r = () => { + Observable.from({}).subscribe(); + }; + + expect(r).toThrow(); + }); + + it('should handle object has observable symbol', (done: DoneSignature) => { + const value = 'x'; + + Observable.from(Observable.of(value)).subscribe((x: string) => { + expect(x).toBe(value); + }, (err: any) => { + done.fail('should not be called'); + }, done); + }); +}); diff --git a/spec/observables/fromEvent-spec.js b/spec/observables/fromEvent-spec.ts similarity index 52% rename from spec/observables/fromEvent-spec.js rename to spec/observables/fromEvent-spec.ts index a1c961af5e..a233740bea 100644 --- a/spec/observables/fromEvent-spec.js +++ b/spec/observables/fromEvent-spec.ts @@ -1,26 +1,30 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.fromEvent', function () { - it('should setup an event observable on objects with "on" and "off" ', function () { - var onEventName; - var onHandler; - var offEventName; - var offHandler; - var obj = { - on: function (a, b) { +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.fromEvent', () => { + it('should setup an event observable on objects with "on" and "off" ', () => { + let onEventName; + let onHandler; + let offEventName; + let offHandler; + + const obj = { + on: (a: string, b: Function) => { onEventName = a; onHandler = b; }, - off: function (a, b) { + off: (a: string, b: Function) => { offEventName = a; offHandler = b; } }; - var subscription = Observable.fromEvent(obj, 'click') - .subscribe(function () { }); + const subscription = Observable.fromEvent(obj, 'click') + .subscribe(() => { + //noop + }); subscription.unsubscribe(); @@ -30,24 +34,27 @@ describe('Observable.fromEvent', function () { expect(offHandler).toBe(onHandler); }); - it('should setup an event observable on objects with "addEventListener" and "removeEventListener" ', function () { - var onEventName; - var onHandler; - var offEventName; - var offHandler; - var obj = { - addEventListener: function (a, b) { + it('should setup an event observable on objects with "addEventListener" and "removeEventListener" ', () => { + let onEventName; + let onHandler; + let offEventName; + let offHandler; + + const obj = { + addEventListener: (a: string, b: EventListenerOrEventListenerObject, useCapture?: boolean) => { onEventName = a; onHandler = b; }, - removeEventListener: function (a, b) { + removeEventListener: (a: string, b: EventListenerOrEventListenerObject, useCapture?: boolean) => { offEventName = a; offHandler = b; } }; - var subscription = Observable.fromEvent(obj, 'click') - .subscribe(function () { }); + const subscription = Observable.fromEvent(obj, 'click') + .subscribe(() => { + //noop + }); subscription.unsubscribe(); @@ -57,24 +64,27 @@ describe('Observable.fromEvent', function () { expect(offHandler).toBe(onHandler); }); - it('should setup an event observable on objects with "addListener" and "removeListener" ', function () { - var onEventName; - var onHandler; - var offEventName; - var offHandler; - var obj = { - addListener: function (a, b) { + it('should setup an event observable on objects with "addListener" and "removeListener" ', () => { + let onEventName; + let onHandler; + let offEventName; + let offHandler; + + const obj = { + addListener: (a: string, b: Function) => { onEventName = a; onHandler = b; }, - removeListener: function (a, b) { + removeListener: (a: string, b: Function) => { offEventName = a; offHandler = b; } }; - var subscription = Observable.fromEvent(obj, 'click') - .subscribe(function () { }); + const subscription = Observable.fromEvent(obj, 'click') + .subscribe(() => { + //noop + }); subscription.unsubscribe(); @@ -84,33 +94,35 @@ describe('Observable.fromEvent', function () { expect(offHandler).toBe(onHandler); }); - it('should pass through events that occur', function (done) { - var send; - var obj = { - on: function (name, handler) { + it('should pass through events that occur', (done: DoneSignature) => { + let send; + const obj = { + on: (name: string, handler: Function) => { send = handler; }, - off: function () { + off: () => { + //noop } }; Observable.fromEvent(obj, 'click').take(1) - .subscribe(function (e) { + .subscribe((e: any) => { expect(e).toBe('test'); - }, function (err) { + }, (err: any) => { done.fail('should not be called'); }, done); send('test'); }); - it('should pass through events that occur and use the selector if provided', function (done) { - var send; - var obj = { - on: function (name, handler) { + it('should pass through events that occur and use the selector if provided', (done: DoneSignature) => { + let send; + const obj = { + on: (name: string, handler: Function) => { send = handler; }, - off: function () { + off: () => { + //noop } }; @@ -119,45 +131,48 @@ describe('Observable.fromEvent', function () { } Observable.fromEvent(obj, 'click', selector).take(1) - .subscribe(function (e) { + .subscribe((e: any) => { expect(e).toBe('test!'); - }, function (err) { + }, (err: any) => { done.fail('should not be called'); }, done); send('test'); }); - it('should not fail if no event arguments are passed and the selector does not return', function (done) { - var send; - var obj = { - on: function (name, handler) { + it('should not fail if no event arguments are passed and the selector does not return', (done: DoneSignature) => { + let send; + const obj = { + on: (name: string, handler: Function) => { send = handler; }, - off: function () { + off: () => { + //noop } }; function selector() { + //noop } Observable.fromEvent(obj, 'click', selector).take(1) - .subscribe(function (e) { + .subscribe((e: any) => { expect(e).toBeUndefined(); - }, function (err) { + }, (err: any) => { done.fail('should not be called'); }, done); send(); }); - it('should return a value from the selector if no event arguments are passed', function (done) { - var send; - var obj = { - on: function (name, handler) { + it('should return a value from the selector if no event arguments are passed', (done: DoneSignature) => { + let send; + const obj = { + on: (name: string, handler: Function) => { send = handler; }, - off: function () { + off: () => { + //noop } }; @@ -166,22 +181,23 @@ describe('Observable.fromEvent', function () { } Observable.fromEvent(obj, 'click', selector).take(1) - .subscribe(function (e) { + .subscribe((e: any) => { expect(e).toBe('no arguments'); - }, function (err) { + }, (err: any) => { done.fail('should not be called'); }, done); send(); }); - it('should pass multiple arguments to selector from event emitter', function (done) { - var send; - var obj = { - on: function (name, handler) { + it('should pass multiple arguments to selector from event emitter', (done: DoneSignature) => { + let send; + const obj = { + on: (name: string, handler: Function) => { send = handler; }, - off: function () { + off: () => { + //noop } }; @@ -190,9 +206,9 @@ describe('Observable.fromEvent', function () { } Observable.fromEvent(obj, 'click', selector).take(1) - .subscribe(function (e) { - expect(e).toEqual([1,2,3]); - }, function (err) { + .subscribe((e: any) => { + expect(e).toEqual([1, 2, 3]); + }, (err: any) => { done.fail('should not be called'); }, done); diff --git a/spec/observables/fromEventPattern-spec.js b/spec/observables/fromEventPattern-spec.js deleted file mode 100644 index 50d1bcb9bc..0000000000 --- a/spec/observables/fromEventPattern-spec.js +++ /dev/null @@ -1,104 +0,0 @@ -/* globals describe, it, expect, jasmine */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.fromEventPattern', function () { - it('should call addHandler on subscription', function () { - var addHandlerCalledWith; - var addHandler = function (h) { - addHandlerCalledWith = h; - }; - - var removeHandler = function () { }; - - Observable.fromEventPattern(addHandler, removeHandler) - .subscribe(function () { }); - - expect(typeof addHandlerCalledWith).toBe('function'); - }); - - it('should call removeHandler on unsubscription', function () { - var removeHandlerCalledWith; - var addHandler = function () { }; - var removeHandler = function (h) { - removeHandlerCalledWith = h; - }; - - var subscription = Observable.fromEventPattern(addHandler, removeHandler) - .subscribe(function () { }); - - subscription.unsubscribe(); - - expect(typeof removeHandlerCalledWith).toBe('function'); - }); - - it('should send errors in addHandler down the error path', function () { - Observable.fromEventPattern(function (handler) { - throw 'bad'; - }, function () { }) - .subscribe(function () { }, - function (err) { - expect(err).toBe('bad'); - }); - }); - - it('should accept a selector that maps outgoing values', function (done) { - var target; - var trigger = function () { - if (target) { - target.apply(null, arguments); - } - }; - - var addHandler = function (handler) { - target = handler; - }; - var removeHandler = function (handler) { - target = null; - }; - var selector = function (a, b) { - return a + b + '!'; - }; - - Observable.fromEventPattern(addHandler, removeHandler, selector).take(1) - .subscribe(function (x) { - expect(x).toBe('testme!'); - }, function (e) { - done.fail('should not be called'); - }, done); - - trigger('test', 'me'); - }); - - it('should send errors in the selector down the error path', function (done) { - var target; - var trigger = function (value) { - if (target) { - target(value); - } - }; - - var addHandler = function (handler) { - target = handler; - }; - var removeHandler = function (handler) { - target = null; - }; - var selector = function (x) { - throw 'bad'; - }; - - Observable.fromEventPattern(addHandler, removeHandler, selector) - .subscribe(function (x) { - done.fail('should not be called'); - }, function (err) { - expect(err).toBe('bad'); - done(); - }, function () { - done.fail('should not be called'); - }); - - trigger('test'); - }); -}); \ No newline at end of file diff --git a/spec/observables/fromEventPattern-spec.ts b/spec/observables/fromEventPattern-spec.ts new file mode 100644 index 0000000000..da0488dcd0 --- /dev/null +++ b/spec/observables/fromEventPattern-spec.ts @@ -0,0 +1,115 @@ +/* globals describe, it, expect, jasmine */ +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.fromEventPattern', () => { + it('should call addHandler on subscription', () => { + let addHandlerCalledWith; + const addHandler = (h: any) => { + addHandlerCalledWith = h; + }; + + const removeHandler = () => { + //noop + }; + + Observable.fromEventPattern(addHandler, removeHandler) + .subscribe(() => { + //noop + }); + + expect(typeof addHandlerCalledWith).toBe('function'); + }); + + it('should call removeHandler on unsubscription', () => { + let removeHandlerCalledWith; + const addHandler = () => { + //noop + }; + const removeHandler = (h: any) => { + removeHandlerCalledWith = h; + }; + + const subscription = Observable.fromEventPattern(addHandler, removeHandler) + .subscribe(() => { + //noop + }); + + subscription.unsubscribe(); + + expect(typeof removeHandlerCalledWith).toBe('function'); + }); + + it('should send errors in addHandler down the error path', () => { + Observable.fromEventPattern((h: any) => { + throw 'bad'; + }, () => { + //noop + }).subscribe(() => { + //noop + }, (err: any) => { + expect(err).toBe('bad'); + }); + }); + + it('should accept a selector that maps outgoing values', (done: DoneSignature) => { + let target; + const trigger = function (...args) { + if (target) { + target.apply(null, arguments); + } + }; + + const addHandler = (handler: any) => { + target = handler; + }; + const removeHandler = (handler: any) => { + target = null; + }; + const selector = (a: any, b: any) => { + return a + b + '!'; + }; + + Observable.fromEventPattern(addHandler, removeHandler, selector).take(1) + .subscribe((x: any) => { + expect(x).toBe('testme!'); + }, (err: any) => { + done.fail('should not be called'); + }, done); + + trigger('test', 'me'); + }); + + it('should send errors in the selector down the error path', (done: DoneSignature) => { + let target; + const trigger = (value: any) => { + if (target) { + target(value); + } + }; + + const addHandler = (handler: any) => { + target = handler; + }; + const removeHandler = (handler: any) => { + target = null; + }; + const selector = (x: any) => { + throw 'bad'; + }; + + Observable.fromEventPattern(addHandler, removeHandler, selector) + .subscribe((x: any) => { + done.fail('should not be called'); + }, (err: any) => { + expect(err).toBe('bad'); + done(); + }, () => { + done.fail('should not be called'); + }); + + trigger('test'); + }); +}); \ No newline at end of file diff --git a/spec/observables/interval-spec.js b/spec/observables/interval-spec.js deleted file mode 100644 index 89feaae4ba..0000000000 --- a/spec/observables/interval-spec.js +++ /dev/null @@ -1,49 +0,0 @@ -/* globals describe, it, expect, spyOn */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Observer = Rx.Observer; - -describe('Observable.interval', function () { - it('should set up an interval', function () { - var expected = '----------0---------1---------2---------3---------4---------5---------6-----'; - expectObservable(Observable.interval(100, rxTestScheduler)).toBe(expected, [0,1,2,3,4,5,6]); - }); - - it('should specify default scheduler if incorrect scheduler specified', function () { - var scheduler = Observable.interval(10, jasmine.createSpy('dummy')).scheduler; - - expect(scheduler).toBe(Rx.Scheduler.asap); - }); - - it('should emit when relative interval set to zero', function () { - var e1 = Observable.interval(0, rxTestScheduler).take(7); - var expected = '(0123456|)'; - - expectObservable(e1).toBe(expected, [0,1,2,3,4,5,6]); - }); - - it('should consider negative interval as zero', function () { - var e1 = Observable.interval(-1, rxTestScheduler).take(7); - var expected = '(0123456|)'; - - expectObservable(e1).toBe(expected, [0,1,2,3,4,5,6]); - }); - - it('should emit values until unsubscribed', function (done) { - var values = []; - var expected = [0,1,2,3,4,5,6]; - var e1 = Observable.interval(5); - var subscription = e1.subscribe(function (x) { - values.push(x); - if (x === 6) { - subscription.unsubscribe(); - expect(values).toEqual(expected); - done(); - } - }, function (x) { - done.fail('should not be called'); - }, function (x) { - done.fail('should not be called'); - }); - }); -}); diff --git a/spec/observables/interval-spec.ts b/spec/observables/interval-spec.ts new file mode 100644 index 0000000000..93089ee20d --- /dev/null +++ b/spec/observables/interval-spec.ts @@ -0,0 +1,52 @@ +/* globals describe, it, expect, spyOn */ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.interval', () => { + it('should set up an interval', () => { + const expected = '----------0---------1---------2---------3---------4---------5---------6-----'; + expectObservable(Observable.interval(100, rxTestScheduler)).toBe(expected, [0, 1, 2, 3, 4, 5, 6]); + }); + + it('should specify default scheduler if incorrect scheduler specified', () => { + const scheduler = (Observable.interval(10, jasmine.createSpy('dummy'))).scheduler; + + expect(scheduler).toBe(Rx.Scheduler.asap); + }); + + it('should emit when relative interval set to zero', () => { + const e1 = Observable.interval(0, rxTestScheduler).take(7); + const expected = '(0123456|)'; + + expectObservable(e1).toBe(expected, [0, 1, 2, 3, 4, 5, 6]); + }); + + it('should consider negative interval as zero', () => { + const e1 = Observable.interval(-1, rxTestScheduler).take(7); + const expected = '(0123456|)'; + + expectObservable(e1).toBe(expected, [0, 1, 2, 3, 4, 5, 6]); + }); + + it('should emit values until unsubscribed', (done: DoneSignature) => { + const values = []; + const expected = [0, 1, 2, 3, 4, 5, 6]; + const e1 = Observable.interval(5); + const subscription = e1.subscribe((x: number) => { + values.push(x); + if (x === 6) { + subscription.unsubscribe(); + expect(values).toEqual(expected); + done(); + } + }, (err: any) => { + done.fail('should not be called'); + }, () => { + done.fail('should not be called'); + }); + }); +}); diff --git a/spec/observables/jasmine-is-weird-spec.js b/spec/observables/jasmine-is-weird-spec.js deleted file mode 100644 index dec130e968..0000000000 --- a/spec/observables/jasmine-is-weird-spec.js +++ /dev/null @@ -1,38 +0,0 @@ -/* globals describe, it, expect, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -/** - * I'm starting this file to collect tests that when put in other files break jasmine for - * no apparent reason. It seems like maybe we should move off of jasmine, but moving >1700 tests - * sounds really gross, so I don't want to do that... - */ -describe('jasmine is weird', function () { - describe('bindCallback', function () { - // HACK: If you move this test under the bindCallback-spec.js file, it will arbitrarily - // break one bufferWhen-spec.js test. - it('should not even call the callbackFn if immediately unsubscribed', function () { - var calls = 0; - function callback(datum, cb) { - calls++; - cb(datum); - } - var boundCallback = Observable.bindCallback(callback, null, rxTestScheduler); - var results1 = []; - - var source = boundCallback(42); - - var subscription = source.subscribe(function (x) { - results1.push(x); - }, null, function () { - results1.push('done'); - }); - - subscription.unsubscribe(); - - rxTestScheduler.flush(); - - expect(calls).toBe(0); - }); - }); -}); \ No newline at end of file diff --git a/spec/observables/merge-spec.js b/spec/observables/merge-spec.js deleted file mode 100644 index 35b6d78fb3..0000000000 --- a/spec/observables/merge-spec.js +++ /dev/null @@ -1,231 +0,0 @@ -/* globals expect, it, describe, hot, cold, expectObservable */ - -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.merge(...observables)', function () { - it('should merge cold and cold', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a--x--b--y--c--z----|'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should return itself when try to merge single observable', function () { - var e1 = Observable.of('a'); - var result = Observable.merge(e1); - - expect(e1).toBe(result); - }); - - it('should merge hot and hot', function () { - var e1 = hot('---a---^-b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('-----x-^----y-----z----|'); - var e2subs = '^ !'; - var expected = '--b--y--c--z----|'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and cold', function () { - var e1 = hot('---a-^---b-----c----|'); - var e1subs = '^ !'; - var e2 = cold( '--x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '--x-b---y-c---z----|'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge parallel emissions', function () { - var e1 = hot('---a----b----c----|'); - var e1subs = '^ !'; - var e2 = hot('---x----y----z----|'); - var e2subs = '^ !'; - var expected = '---(ax)-(by)-(cz)-|'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge empty and empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe('|'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge three empties', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - var e3 = cold('|'); - var e3subs = '(^!)'; - - var result = Observable.merge(e1, e2, e3); - - expectObservable(result).toBe('|'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should merge never and empty', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('|'); - var e2subs = '(^!)'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe('-'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge never and never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('-'); - var e2subs = '^'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe('-'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge empty and throw', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('#'); - var e2subs = '(^!)'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe('#'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and throw', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '(^!)'; - var e2 = cold('#'); - var e2subs = '(^!)'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe('#'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge never and throw', function () { - var e1 = cold('-'); - var e1subs = '(^!)'; - var e2 = cold('#'); - var e2subs = '(^!)'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe('#'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge empty and eventual error', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = hot('-------#'); - var e2subs = '^------!'; - var expected = '-------#'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and error', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ ! '; - var e2 = hot('-------# '); - var e2subs = '^ ! '; - var expected = '--a--b-# '; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge never and error', function () { - var e1 = hot( '-'); - var e1subs = '^ !'; - var e2 = hot('-------#'); - var e2subs = '^ !'; - var expected = '-------#'; - - var result = Observable.merge(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); - -describe('Observable.merge(...observables, Scheduler, number)', function () { - it('should handle concurrency limits', function () { - var e1 = cold('---a---b---c---|'); - var e2 = cold('-d---e---f--|'); - var e3 = cold( '---x---y---z---|'); - var expected = '-d-a-e-b-f-c---x---y---z---|'; - expectObservable(Observable.merge(e1, e2, e3, 2)).toBe(expected); - }); - - it('should handle scheduler', function () { - var e1 = Observable.of('a'); - var e2 = Observable.of('b').delay(20, rxTestScheduler); - var expected = 'a-(b|)'; - - expectObservable(Observable.merge(e1, e2, rxTestScheduler)).toBe(expected); - }); - - it('should handle scheduler with concurrency limits', function () { - var e1 = cold('---a---b---c---|'); - var e2 = cold('-d---e---f--|'); - var e3 = cold( '---x---y---z---|'); - var expected = '-d-a-e-b-f-c---x---y---z---|'; - expectObservable(Observable.merge(e1, e2, e3, 2, rxTestScheduler)).toBe(expected); - }); -}); diff --git a/spec/observables/merge-spec.ts b/spec/observables/merge-spec.ts new file mode 100644 index 0000000000..05c9f925f6 --- /dev/null +++ b/spec/observables/merge-spec.ts @@ -0,0 +1,233 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.merge(...observables)', () => { + it('should merge cold and cold', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a--x--b--y--c--z----|'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should return itself when try to merge single observable', () => { + const e1 = Observable.of('a'); + const result = Observable.merge(e1); + + expect(e1).toBe(result); + }); + + it('should merge hot and hot', () => { + const e1 = hot('---a---^-b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('-----x-^----y-----z----|'); + const e2subs = '^ !'; + const expected = '--b--y--c--z----|'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and cold', () => { + const e1 = hot('---a-^---b-----c----|'); + const e1subs = '^ !'; + const e2 = cold( '--x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '--x-b---y-c---z----|'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge parallel emissions', () => { + const e1 = hot('---a----b----c----|'); + const e1subs = '^ !'; + const e2 = hot('---x----y----z----|'); + const e2subs = '^ !'; + const expected = '---(ax)-(by)-(cz)-|'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge empty and empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe('|'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge three empties', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + const e3 = cold('|'); + const e3subs = '(^!)'; + + const result = Observable.merge(e1, e2, e3); + + expectObservable(result).toBe('|'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should merge never and empty', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('|'); + const e2subs = '(^!)'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe('-'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge never and never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('-'); + const e2subs = '^'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe('-'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge empty and throw', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('#'); + const e2subs = '(^!)'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe('#'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and throw', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '(^!)'; + const e2 = cold('#'); + const e2subs = '(^!)'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe('#'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge never and throw', () => { + const e1 = cold('-'); + const e1subs = '(^!)'; + const e2 = cold('#'); + const e2subs = '(^!)'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe('#'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge empty and eventual error', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = hot('-------#'); + const e2subs = '^------!'; + const expected = '-------#'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and error', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ ! '; + const e2 = hot('-------# '); + const e2subs = '^ ! '; + const expected = '--a--b-# '; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge never and error', () => { + const e1 = hot( '-'); + const e1subs = '^ !'; + const e2 = hot('-------#'); + const e2subs = '^ !'; + const expected = '-------#'; + + const result = Observable.merge(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); + +describe('Observable.merge(...observables, Scheduler, number)', () => { + it('should handle concurrency limits', () => { + const e1 = cold('---a---b---c---|'); + const e2 = cold('-d---e---f--|'); + const e3 = cold( '---x---y---z---|'); + const expected = '-d-a-e-b-f-c---x---y---z---|'; + expectObservable(Observable.merge(e1, e2, e3, 2)).toBe(expected); + }); + + it('should handle scheduler', () => { + const e1 = Observable.of('a'); + const e2 = Observable.of('b').delay(20, rxTestScheduler); + const expected = 'a-(b|)'; + + expectObservable(Observable.merge(e1, e2, rxTestScheduler)).toBe(expected); + }); + + it('should handle scheduler with concurrency limits', () => { + const e1 = cold('---a---b---c---|'); + const e2 = cold('-d---e---f--|'); + const e3 = cold( '---x---y---z---|'); + const expected = '-d-a-e-b-f-c---x---y---z---|'; + expectObservable(Observable.merge(e1, e2, e3, 2, rxTestScheduler)).toBe(expected); + }); +}); diff --git a/spec/observables/of-spec.js b/spec/observables/of-spec.js deleted file mode 100644 index 0d00d76491..0000000000 --- a/spec/observables/of-spec.js +++ /dev/null @@ -1,79 +0,0 @@ -/* globals describe, it, expect, expectObservable, rxTestScheduler */ -var ArrayObservable = require('../../dist/cjs/observable/ArrayObservable').ArrayObservable; -var ScalarObservable = require('../../dist/cjs/observable/ScalarObservable').ScalarObservable; -var EmptyObservable = require('../../dist/cjs/observable/EmptyObservable').EmptyObservable; -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.of', function () { - it('should create an observable from the provided values', function (done) { - var x = { foo: 'bar' }; - var expected = [1, 'a', x]; - var i = 0; - Observable.of(1, 'a', x) - .subscribe(function (y) { - expect(y).toBe(expected[i++]); - }, - null, - function () { - done(); - }); - }); - - it('should return a scalar observable if only passed one value', function () { - var obs = Observable.of('one'); - expect(obs instanceof ScalarObservable).toBe(true); - }); - - it('should return a scalar observable if only passed one value and a scheduler', function () { - var obs = Observable.of('one', Rx.Scheduler.queue); - expect(obs instanceof ScalarObservable).toBe(true); - }); - - it('should return an array observable if passed many values', function () { - var obs = Observable.of('one', 'two', 'three'); - expect(obs instanceof ArrayObservable).toBe(true); - }); - - it('should return an empty observable if passed no values', function () { - var obs = Observable.of(); - expect(obs instanceof EmptyObservable).toBe(true); - }); - - it('should return an empty observable if passed only a scheduler', function () { - var obs = Observable.of(Rx.Scheduler.queue); - expect(obs instanceof EmptyObservable).toBe(true); - }); - - it('should emit one value', function (done) { - var calls = 0; - Observable.of(42).subscribe(function (x) { - expect(++calls).toBe(1); - expect(x).toBe(42); - }, function (x) { - done.fail('should not be called'); - }, done); - }); - - it('should handle an Observable as the only value', function () { - var source = Observable.of( - Observable.of('a', 'b', 'c', rxTestScheduler), - rxTestScheduler - ); - expect(source instanceof ScalarObservable).toBe(true); - var result = source.concatAll(); - expectObservable(result).toBe('(abc|)'); - }); - - it('should handle many Observable as the given values', function () { - var source = Observable.of( - Observable.of('a', 'b', 'c', rxTestScheduler), - Observable.of('d', 'e', 'f', rxTestScheduler), - rxTestScheduler - ); - expect(source instanceof ArrayObservable).toBe(true); - - var result = source.concatAll(); - expectObservable(result).toBe('(abcdef|)'); - }); -}); \ No newline at end of file diff --git a/spec/observables/of-spec.ts b/spec/observables/of-spec.ts new file mode 100644 index 0000000000..ce6aa600c1 --- /dev/null +++ b/spec/observables/of-spec.ts @@ -0,0 +1,82 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {ArrayObservable} from '../../dist/cjs/observable/ArrayObservable'; +import {ScalarObservable} from '../../dist/cjs/observable/ScalarObservable'; +import {EmptyObservable} from '../../dist/cjs/observable/EmptyObservable'; +import {expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.of', () => { + it('should create an observable from the provided values', (done: DoneSignature) => { + const x = { foo: 'bar' }; + const expected = [1, 'a', x]; + let i = 0; + + Observable.of(1, 'a', x) + .subscribe((y: any) => { + expect(y).toBe(expected[i++]); + }, + done.fail, + done); + }); + + it('should return a scalar observable if only passed one value', () => { + const obs = Observable.of('one'); + expect(obs instanceof ScalarObservable).toBe(true); + }); + + it('should return a scalar observable if only passed one value and a scheduler', () => { + const obs = Observable.of('one', Rx.Scheduler.queue); + expect(obs instanceof ScalarObservable).toBe(true); + }); + + it('should return an array observable if passed many values', () => { + const obs = Observable.of('one', 'two', 'three'); + expect(obs instanceof ArrayObservable).toBe(true); + }); + + it('should return an empty observable if passed no values', () => { + const obs = Observable.of(); + expect(obs instanceof EmptyObservable).toBe(true); + }); + + it('should return an empty observable if passed only a scheduler', () => { + const obs = Observable.of(Rx.Scheduler.queue); + expect(obs instanceof EmptyObservable).toBe(true); + }); + + it('should emit one value', (done: DoneSignature) => { + let calls = 0; + + Observable.of(42).subscribe((x: number) => { + expect(++calls).toBe(1); + expect(x).toBe(42); + }, (err: any) => { + done.fail('should not be called'); + }, done); + }); + + it('should handle an Observable as the only value', () => { + const source = Observable.of>( + Observable.of('a', 'b', 'c', rxTestScheduler), + rxTestScheduler + ); + expect(source instanceof ScalarObservable).toBe(true); + const result = source.concatAll(); + expectObservable(result).toBe('(abc|)'); + }); + + it('should handle many Observable as the given values', () => { + const source = Observable.of>( + Observable.of('a', 'b', 'c', rxTestScheduler), + Observable.of('d', 'e', 'f', rxTestScheduler), + rxTestScheduler + ); + expect(source instanceof ArrayObservable).toBe(true); + + const result = source.concatAll(); + expectObservable(result).toBe('(abcdef|)'); + }); +}); \ No newline at end of file diff --git a/spec/observables/race-spec.js b/spec/observables/race-spec.js deleted file mode 100644 index 47fd883a69..0000000000 --- a/spec/observables/race-spec.js +++ /dev/null @@ -1,193 +0,0 @@ -/* globals expect, it, describe, hot, cold, expectObservable, expectSubscriptions */ - -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.race(...observables)', function () { - it('should race a single observable', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = Observable.race(e1); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should race cold and cold', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race hot and hot', function () { - var e1 = hot('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race hot and cold', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race 2nd and 1st', function () { - var e1 = cold('------x-----y-----z----|'); - var e1subs = '^ !'; - var e2 = cold('---a-----b-----c----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race emit and complete', function () { - var e1 = cold('-----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '-----|'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b---'; - var unsub = ' !'; - - var result = Observable.race(e1, e2); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '---b--c--- '; - var unsub = ' ! '; - - var result = Observable.race( - e1.mergeMap(function (x) { return Observable.of(x); }), - e2.mergeMap(function (x) { return Observable.of(x); }) - ).mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should never emit when given non emitting sources', function () { - var e1 = cold('---|'); - var e2 = cold('---|'); - var e1subs = '^ !'; - var expected = '---|'; - - var source = Observable.race(e1, e2); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should throw when error occurs mid stream', function () { - var e1 = cold('---a-----#'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----#'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should throw when error occurs before a winner is found', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.race(e1, e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('handle empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - var source = Observable.race(e1); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var source = Observable.race(e1); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - var source = Observable.race(e1); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/observables/race-spec.ts b/spec/observables/race-spec.ts new file mode 100644 index 0000000000..97d19eb0de --- /dev/null +++ b/spec/observables/race-spec.ts @@ -0,0 +1,194 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.race(...observables)', () => { + it('should race a single observable', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = Observable.race(e1); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should race cold and cold', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race hot and hot', () => { + const e1 = hot('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race hot and cold', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race 2nd and 1st', () => { + const e1 = cold('------x-----y-----z----|'); + const e1subs = '^ !'; + const e2 = cold('---a-----b-----c----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race emit and complete', () => { + const e1 = cold('-----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '-----|'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b---'; + const unsub = ' !'; + + const result = Observable.race(e1, e2); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '---b--c--- '; + const unsub = ' ! '; + + const result = Observable.race( + e1.mergeMap((x: string) => Observable.of(x)), + e2.mergeMap((x: string) => Observable.of(x)) + ).mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should never emit when given non emitting sources', () => { + const e1 = cold('---|'); + const e2 = cold('---|'); + const e1subs = '^ !'; + const expected = '---|'; + + const source = Observable.race(e1, e2); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should throw when error occurs mid stream', () => { + const e1 = cold('---a-----#'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----#'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should throw when error occurs before a winner is found', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.race(e1, e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('handle empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + const source = Observable.race(e1); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const source = Observable.race(e1); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + const source = Observable.race(e1); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/observables/range-spec.js b/spec/observables/range-spec.js deleted file mode 100644 index edae152e14..0000000000 --- a/spec/observables/range-spec.js +++ /dev/null @@ -1,82 +0,0 @@ -var Rx = require('../../dist/cjs/Rx'); -var RangeObservable = require('../../dist/cjs/observable/RangeObservable').RangeObservable; -var Observable = Rx.Observable; -var asap = Rx.Scheduler.asap; - -describe('Observable.range', function () { - it('should synchronously create a range of values by default', function () { - var results = []; - Observable.range(12, 4).subscribe(function (x) { - results.push(x); - }); - expect(results).toEqual([12, 13, 14, 15]); - }); - - it('should accept a scheduler', function (done) { - var expected = [12, 13, 14, 15]; - spyOn(asap, 'schedule').and.callThrough(); - - var source = Observable.range(12, 4, asap); - - expect(source.scheduler).toBe(asap); - - source.subscribe(function (x) { - expect(asap.schedule).toHaveBeenCalled(); - var exp = expected.shift(); - expect(x).toBe(exp); - }, function (x) { - done.fail('should not be called'); - }, done); - }); -}); - -describe('RangeObservable', function () { - describe('create', function () { - it('should create a RangeObservable', function () { - var observable = RangeObservable.create(12, 4); - expect(observable instanceof RangeObservable).toBe(true); - }); - - it('should accept a scheduler', function () { - var observable = RangeObservable.create(12, 4, asap); - expect(observable.scheduler).toBe(asap); - }); - }); - - describe('dispatch', function () { - it('should complete if index >= end', function () { - var state = { - subscriber: jasmine.createSpyObj(['next', 'error', 'complete']), - index: 10, - start: 0, - end: 9 - }; - - RangeObservable.dispatch(state); - - expect(state.subscriber.complete).toHaveBeenCalled(); - expect(state.subscriber.next).not.toHaveBeenCalled(); - }); - - it('should next out a nother value and increment the index and start', function () { - var state = { - subscriber: jasmine.createSpyObj(['next', 'error', 'complete']), - index: 1, - start: 5, - end: 9 - }; - - var thisArg = { - schedule: jasmine.createSpy('schedule') - }; - - RangeObservable.dispatch.call(thisArg, state); - - expect(state.subscriber.complete).not.toHaveBeenCalled(); - expect(state.subscriber.next).toHaveBeenCalledWith(5); - expect(state.start).toBe(6); - expect(state.index).toBe(2); - expect(thisArg.schedule).toHaveBeenCalledWith(state); - }); - }); -}); \ No newline at end of file diff --git a/spec/observables/range-spec.ts b/spec/observables/range-spec.ts new file mode 100644 index 0000000000..37afc47815 --- /dev/null +++ b/spec/observables/range-spec.ts @@ -0,0 +1,86 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {RangeObservable} from '../../dist/cjs/observable/RangeObservable'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const asap = Rx.Scheduler.asap; + +describe('Observable.range', () => { + it('should synchronously create a range of values by default', () => { + const results = []; + Observable.range(12, 4).subscribe(function (x) { + results.push(x); + }); + expect(results).toEqual([12, 13, 14, 15]); + }); + + it('should accept a scheduler', (done: DoneSignature) => { + const expected = [12, 13, 14, 15]; + spyOn(asap, 'schedule').and.callThrough(); + + const source = Observable.range(12, 4, asap); + + expect((source).scheduler).toBe(asap); + + source.subscribe(function (x) { + expect(asap.schedule).toHaveBeenCalled(); + const exp = expected.shift(); + expect(x).toBe(exp); + }, function (x) { + done.fail('should not be called'); + }, done); + }); +}); + +describe('RangeObservable', () => { + describe('create', () => { + it('should create a RangeObservable', () => { + const observable = RangeObservable.create(12, 4); + expect(observable instanceof RangeObservable).toBe(true); + }); + + it('should accept a scheduler', () => { + const observable = RangeObservable.create(12, 4, asap); + expect((observable).scheduler).toBe(asap); + }); + }); + + describe('dispatch', () => { + it('should complete if index >= end', () => { + const obj: Rx.Subscriber = jasmine.createSpyObj('subscriber', ['next', 'error', 'complete']); + const state = { + subscriber: obj, + index: 10, + start: 0, + end: 9 + }; + + RangeObservable.dispatch(state); + + expect(state.subscriber.complete).toHaveBeenCalled(); + expect(state.subscriber.next).not.toHaveBeenCalled(); + }); + + it('should next out another value and increment the index and start', () => { + const obj: Rx.Subscriber = jasmine.createSpyObj('subscriber', ['next', 'error', 'complete']); + const state = { + subscriber: obj, + index: 1, + start: 5, + end: 9 + }; + + const thisArg = { + schedule: jasmine.createSpy('schedule') + }; + + RangeObservable.dispatch.call(thisArg, state); + + expect(state.subscriber.complete).not.toHaveBeenCalled(); + expect(state.subscriber.next).toHaveBeenCalledWith(5); + expect(state.start).toBe(6); + expect(state.index).toBe(2); + expect(thisArg.schedule).toHaveBeenCalledWith(state); + }); + }); +}); \ No newline at end of file diff --git a/spec/observables/throw-spec.js b/spec/observables/throw-spec.js deleted file mode 100644 index 7132ebd5a4..0000000000 --- a/spec/observables/throw-spec.js +++ /dev/null @@ -1,16 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.throw', function () { - it('should emit one value', function (done) { - var calls = 0; - Observable.throw('bad').subscribe(function () { - throw 'should not be called'; - }, function (err) { - expect(++calls).toBe(1); - expect(err).toBe('bad'); - done(); - }); - }); -}); \ No newline at end of file diff --git a/spec/observables/throw-spec.ts b/spec/observables/throw-spec.ts new file mode 100644 index 0000000000..1f83382d58 --- /dev/null +++ b/spec/observables/throw-spec.ts @@ -0,0 +1,17 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.throw', () => { + it('should emit one value', (done: DoneSignature) => { + let calls = 0; + Observable.throw('bad').subscribe(() => { + done.fail('should not be called'); + }, (err: any) => { + expect(++calls).toBe(1); + expect(err).toBe('bad'); + done(); + }); + }); +}); \ No newline at end of file diff --git a/spec/observables/timer-spec.js b/spec/observables/timer-spec.js deleted file mode 100644 index 3d7dcf08ed..0000000000 --- a/spec/observables/timer-spec.js +++ /dev/null @@ -1,73 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Observer = Rx.Observer; - -describe('Observable.timer', function () { - it('should schedule a value of 0 then complete', function () { - var dueTime = time('-----|'); - var expected = '-----(x|)'; - - var source = Observable.timer(dueTime, undefined, rxTestScheduler); - expectObservable(source).toBe(expected, {x: 0}); - }); - - it('should emit a single value immediately', function () { - var dueTime = time('|'); - var expected = '(x|)'; - - var source = Observable.timer(dueTime, rxTestScheduler); - expectObservable(source).toBe(expected, {x: 0}); - }); - - it('should start after delay and periodically emit values', function () { - var dueTime = time('----|'); - var period = time( '--|'); - var expected = '----a-b-c-d-(e|)'; - - var source = Observable.timer(dueTime, period, rxTestScheduler).take(5); - var values = { a: 0, b: 1, c: 2, d: 3, e: 4}; - expectObservable(source).toBe(expected, values); - }); - - it('should start immediately and periodically emit values', function () { - var dueTime = time('|'); - var period = time('---|'); - var expected = 'a--b--c--d--(e|)'; - - var source = Observable.timer(dueTime, period, rxTestScheduler).take(5); - var values = { a: 0, b: 1, c: 2, d: 3, e: 4}; - expectObservable(source).toBe(expected, values); - }); - - it('should stop emiting values when subscription is done', function () { - var dueTime = time('|'); - var period = time('---|'); - var expected = 'a--b--c--d--e'; - var unsub = '^ !'; - - var source = Observable.timer(dueTime, period, rxTestScheduler); - var values = { a: 0, b: 1, c: 2, d: 3, e: 4}; - expectObservable(source, unsub).toBe(expected, values); - }); - - it('should schedule a value at a specified Date', function () { - var offset = time('----|'); - var expected = '----(a|)'; - - var dueTime = new Date(rxTestScheduler.now() + offset); - var source = Observable.timer(dueTime, null, rxTestScheduler); - expectObservable(source).toBe(expected, {a: 0}); - }); - - it('should start after delay and periodically emit values', function () { - var offset = time('----|'); - var period = time( '--|'); - var expected = '----a-b-c-d-(e|)'; - - var dueTime = new Date(rxTestScheduler.now() + offset); - var source = Observable.timer(dueTime, period, rxTestScheduler).take(5); - var values = { a: 0, b: 1, c: 2, d: 3, e: 4}; - expectObservable(source).toBe(expected, values); - }); -}); diff --git a/spec/observables/timer-spec.ts b/spec/observables/timer-spec.ts new file mode 100644 index 0000000000..2080c1f8b1 --- /dev/null +++ b/spec/observables/timer-spec.ts @@ -0,0 +1,76 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {time, expectObservable} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; + +const Observable = Rx.Observable; + +describe('Observable.timer', () => { + it('should schedule a value of 0 then complete', () => { + const dueTime = time('-----|'); + const expected = '-----(x|)'; + + const source = Observable.timer(dueTime, undefined, rxTestScheduler); + expectObservable(source).toBe(expected, {x: 0}); + }); + + it('should emit a single value immediately', () => { + const dueTime = time('|'); + const expected = '(x|)'; + + const source = Observable.timer(dueTime, rxTestScheduler); + expectObservable(source).toBe(expected, {x: 0}); + }); + + it('should start after delay and periodically emit values', () => { + const dueTime = time('----|'); + const period = time( '--|'); + const expected = '----a-b-c-d-(e|)'; + + const source = Observable.timer(dueTime, period, rxTestScheduler).take(5); + const values = { a: 0, b: 1, c: 2, d: 3, e: 4}; + expectObservable(source).toBe(expected, values); + }); + + it('should start immediately and periodically emit values', () => { + const dueTime = time('|'); + const period = time('---|'); + const expected = 'a--b--c--d--(e|)'; + + const source = Observable.timer(dueTime, period, rxTestScheduler).take(5); + const values = { a: 0, b: 1, c: 2, d: 3, e: 4}; + expectObservable(source).toBe(expected, values); + }); + + it('should stop emiting values when subscription is done', () => { + const dueTime = time('|'); + const period = time('---|'); + const expected = 'a--b--c--d--e'; + const unsub = '^ !'; + + const source = Observable.timer(dueTime, period, rxTestScheduler); + const values = { a: 0, b: 1, c: 2, d: 3, e: 4}; + expectObservable(source, unsub).toBe(expected, values); + }); + + it('should schedule a value at a specified Date', () => { + const offset = time('----|'); + const expected = '----(a|)'; + + const dueTime = new Date(rxTestScheduler.now() + offset); + const source = Observable.timer(dueTime, null, rxTestScheduler); + expectObservable(source).toBe(expected, {a: 0}); + }); + + it('should start after delay and periodically emit values', () => { + const offset = time('----|'); + const period = time( '--|'); + const expected = '----a-b-c-d-(e|)'; + + const dueTime = new Date(rxTestScheduler.now() + offset); + const source = Observable.timer(dueTime, period, rxTestScheduler).take(5); + const values = { a: 0, b: 1, c: 2, d: 3, e: 4}; + expectObservable(source).toBe(expected, values); + }); +}); diff --git a/spec/observables/zip-spec.js b/spec/observables/zip-spec.js deleted file mode 100644 index ec3cf4b30a..0000000000 --- a/spec/observables/zip-spec.js +++ /dev/null @@ -1,574 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold, Symbol */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.zip', function () { - it('should combine a source with a second', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - - expectObservable(Observable.zip(a, b)) - .toBe(expected, { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should zip the provided observables', function (done) { - var expected = ['a1', 'b2', 'c3']; - var i = 0; - - Observable.zip( - Observable.fromArray(['a','b','c']), - Observable.fromArray([1,2,3]), - function (a, b) { - return a + b; - } - ) - .subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }); - - it('should end once one observable completes and its buffer is empty', function () { - var e1 = hot('---a--b--c--| '); - var e1subs = '^ ! '; - var e2 = hot('------d----e----f--------| '); - var e2subs = '^ ! '; - var e3 = hot('--------h----i----j---------'); // doesn't complete - var e3subs = '^ ! '; - var expected = '--------x----y----(z|) '; // e1 complete and buffer empty - var values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] - }; - - expectObservable(Observable.zip(e1,e2,e3)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should end once one observable nexts and zips value from completed other ' + - 'observable whose buffer is empty', function () { - var e1 = hot('---a--b--c--| '); - var e1subs = '^ ! '; - var e2 = hot('------d----e----f| '); - var e2subs = '^ ! '; - var e3 = hot('--------h----i----j-------'); // doesn't complete - var e3subs = '^ ! '; - var expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete - var values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] - }; - - expectObservable(Observable.zip(e1,e2,e3)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - describe('with iterables', function () { - it('should zip them with values', function () { - var myIterator = { - count: 0, - next: function () { - return { value: this.count++, done: false }; - } - }; - myIterator[Symbol.iterator] = function () { return this; }; - - var e1 = hot('---a---b---c---d---|'); - var e1subs = '^ !'; - var expected = '---w---x---y---z---|'; - - var values = { - w: ['a', 0], - x: ['b', 1], - y: ['c', 2], - z: ['d', 3] - }; - - expectObservable(Observable.zip(e1, myIterator)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should only call `next` as needed', function () { - var nextCalled = 0; - var myIterator = { - count: 0, - next: function () { - nextCalled++; - return { value: this.count++, done: false }; - } - }; - myIterator[Symbol.iterator] = function () { return this; }; - - Observable.zip(Observable.of(1,2,3), myIterator) - .subscribe(); - - // since zip will call `next()` in advance, total calls when - // zipped with 3 other values should be 4. - expect(nextCalled).toBe(4); - }); - - it('should work with never observable and empty iterable', function () { - var a = cold( '-'); - var asubs = '^'; - var b = []; - var expected = '-'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with empty observable and empty iterable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var b = []; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with empty observable and non-empty iterable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var b = [1]; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and empty iterable', function () { - var a = hot('---^----a--|'); - var asubs = '^ !'; - var b = []; - var expected = '--------|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with never observable and non-empty iterable', function () { - var a = cold('-'); - var asubs = '^'; - var b = [1]; - var expected = '-'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and non-empty iterable', function () { - var a = hot('---^----1--|'); - var asubs = '^ ! '; - var b = [2]; - var expected = '-----(x|)'; - - expectObservable(Observable.zip(a,b)).toBe(expected, { x: ['1', 2] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and empty iterable', function () { - var a = hot('---^----#'); - var asubs = '^ !'; - var b = []; - var expected = '-----#'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with observable which raises error and non-empty iterable', function () { - var a = hot('---^----#'); - var asubs = '^ !'; - var b = [1]; - var expected = '-----#'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty many observable and non-empty many iterable', function () { - var a = hot('---^--1--2--3--|'); - var asubs = '^ ! '; - var b = [4, 5, 6]; - var expected = '---x--y--(z|)'; - - expectObservable(Observable.zip(a,b)).toBe(expected, - { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and non-empty iterable selector that throws', function () { - var a = hot('---^--1--2--3--|'); - var asubs = '^ !'; - var b = [4, 5, 6]; - var expected = '---x--#'; - - var selector = function (x, y) { - if (y === 5) { - throw new Error('too bad'); - } else { - return x + y; - }}; - expectObservable(Observable.zip(a,b,selector)).toBe(expected, - { x: '14' }, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - }); - - it('should combine two observables and selector', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - - expectObservable(Observable.zip(a,b, function (e1,e2) { return e1 + e2; })) - .toBe(expected, { x: '14', y: '25', z: '36' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - expectObservable(Observable.zip(a,b,c)).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric selector', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - var observable = Observable.zip(a,b,c, - function (r0, r1, r2) { return [r0, r1, r2]; }); - expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric array selector', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - var observable = Observable.zip(a,b,c, - function (r0, r1, r2) { return [r0, r1, r2]; }); - expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data asymmetric 1', function () { - var a = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--4--6--8--0--| '); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e--| '; - - expectObservable(Observable.zip(a,b, function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data asymmetric 2', function () { - var a = hot('---1-^--2--4--6--8--0--| '); - var asubs = '^ ! '; - var b = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e--| '; - - expectObservable(Observable.zip(a,b, function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data symmetric', function () { - var a = hot('---1-^-1-3-5-7-9------| '); - var asubs = '^ ! '; - var b = hot('---1-^--2--4--6--8--0--|'); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e-| '; - - expectObservable(Observable.zip(a,b, function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with selector throws', function () { - var a = hot('---1-^-2---4----| '); - var asubs = '^ ! '; - var b = hot('---1-^--3----5----|'); - var bsubs = '^ ! '; - var expected = '---x----# '; - - var selector = function (x, y) { - if (y === '5') { - throw new Error('too bad'); - } else { - return x + y; - }}; - var observable = Observable.zip(a,b,selector); - expectObservable(observable).toBe(expected, - { x: '23' }, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with right completes first', function () { - var a = hot('---1-^-2-----|'); - var asubs = '^ !'; - var b = hot('---1-^--3--|'); - var bsubs = '^ !'; - var expected = '---x--|'; - - expectObservable(Observable.zip(a,b)).toBe(expected, { x: ['2', '3'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two nevers', function () { - var a = cold( '-'); - var asubs = '^'; - var b = cold( '-'); - var bsubs = '^'; - var expected = '-'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and empty', function () { - var a = cold( '-'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and never', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = cold( '-'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and empty', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and non-empty', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = hot( '---1--|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with non-empty and empty', function () { - var a = hot( '---1--|'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and non-empty', function () { - var a = cold( '-'); - var asubs = '^'; - var b = hot( '---1--|'); - var bsubs = '^ !'; - var expected = '-'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with non-empty and never', function () { - var a = hot( '---1--|'); - var asubs = '^ !'; - var b = cold( '-'); - var bsubs = '^'; - var expected = '-'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and error', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = hot( '------#', null, 'too bad'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and empty', function () { - var a = hot( '------#', null, 'too bad'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error', function () { - var a = hot('----------|'); - var asubs = '^ ! '; - var b = hot('------# '); - var bsubs = '^ ! '; - var expected = '------# '; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and error', function () { - var a = cold( '-'); - var asubs = '^ !'; - var b = hot('------#'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and never', function () { - var a = hot('------#'); - var asubs = '^ !'; - var b = cold( '-'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and error', function () { - var a = hot('------#', null, 'too bad'); - var asubs = '^ !'; - var b = hot('----------#', null, 'too bad 2'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(Observable.zip(a,b)).toBe(expected, null, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two sources that eventually raise errors', function () { - var a = hot('--w-----#----', { w: 1 }, 'too bad'); - var asubs = '^ !'; - var b = hot('-----z-----#-', { z: 2 }, 'too bad 2'); - var bsubs = '^ !'; - var expected = '-----x--#'; - - expectObservable(Observable.zip(a,b)).toBe(expected, { x: [1, 2] }, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two sources that eventually raise errors (swapped)', function () { - var a = hot('-----z-----#-', { z: 2 }, 'too bad 2'); - var asubs = '^ !'; - var b = hot('--w-----#----', { w: 1 }, 'too bad'); - var bsubs = '^ !'; - var expected = '-----x--#'; - - expectObservable(Observable.zip(a,b)).toBe(expected, { x: [2, 1] }, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and some', function () { - var a = cold( '#'); - var asubs = '(^!)'; - var b = hot( '--1--2--3--'); - var bsubs = '(^!)'; - var expected = '#'; - - expectObservable(Observable.zip(a,b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should combine an immediately-scheduled source with an immediately-scheduled second', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [[1, 4], [2, 5], [3, 6]]; - var i = 0; - - Observable.zip(a,b).subscribe(function (vals) { - expect(vals).toDeepEqual(r[i++]); - }, null, done); - }); -}); \ No newline at end of file diff --git a/spec/observables/zip-spec.ts b/spec/observables/zip-spec.ts new file mode 100644 index 0000000000..b1600a6e10 --- /dev/null +++ b/spec/observables/zip-spec.ts @@ -0,0 +1,577 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const Symbol: any; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.zip', () => { + it('should combine a source with a second', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + + expectObservable(Observable.zip(a, b)) + .toBe(expected, { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should zip the provided observables', (done: DoneSignature) => { + const expected = ['a1', 'b2', 'c3']; + let i = 0; + + Observable.zip( + Observable.fromArray(['a', 'b', 'c']), + Observable.fromArray([1, 2, 3]), (a: string, b: number) => a + b) + .subscribe((x: string) => { + expect(x).toBe(expected[i++]); + }, null, done); + }); + + it('should end once one observable completes and its buffer is empty', () => { + const e1 = hot('---a--b--c--| '); + const e1subs = '^ ! '; + const e2 = hot('------d----e----f--------| '); + const e2subs = '^ ! '; + const e3 = hot('--------h----i----j---------'); // doesn't complete + const e3subs = '^ ! '; + const expected = '--------x----y----(z|) '; // e1 complete and buffer empty + const values = { + x: ['a', 'd', 'h'], + y: ['b', 'e', 'i'], + z: ['c', 'f', 'j'] + }; + + expectObservable(Observable.zip(e1, e2, e3)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should end once one observable nexts and zips value from completed other ' + + 'observable whose buffer is empty', () => { + const e1 = hot('---a--b--c--| '); + const e1subs = '^ ! '; + const e2 = hot('------d----e----f| '); + const e2subs = '^ ! '; + const e3 = hot('--------h----i----j-------'); // doesn't complete + const e3subs = '^ ! '; + const expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete + const values = { + x: ['a', 'd', 'h'], + y: ['b', 'e', 'i'], + z: ['c', 'f', 'j'] + }; + + expectObservable(Observable.zip(e1, e2, e3)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + describe('with iterables', () => { + it('should zip them with values', () => { + const myIterator = { + count: 0, + next: function () { + return { value: this.count++, done: false }; + } + }; + + myIterator[Symbol.iterator] = function () { return this; }; + + const e1 = hot('---a---b---c---d---|'); + const e1subs = '^ !'; + const expected = '---w---x---y---z---|'; + + const values = { + w: ['a', 0], + x: ['b', 1], + y: ['c', 2], + z: ['d', 3] + }; + + expectObservable(Observable.zip(e1, myIterator)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should only call `next` as needed', () => { + let nextCalled = 0; + const myIterator = { + count: 0, + next: () => { + nextCalled++; + return { value: this.count++, done: false }; + } + }; + myIterator[Symbol.iterator] = function() { + return this; + }; + + Observable.zip(Observable.of(1, 2, 3), myIterator) + .subscribe(); + + // since zip will call `next()` in advance, total calls when + // zipped with 3 other values should be 4. + expect(nextCalled).toBe(4); + }); + + it('should work with never observable and empty iterable', () => { + const a = cold( '-'); + const asubs = '^'; + const b = []; + const expected = '-'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with empty observable and empty iterable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const b = []; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with empty observable and non-empty iterable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const b = [1]; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and empty iterable', () => { + const a = hot('---^----a--|'); + const asubs = '^ !'; + const b = []; + const expected = '--------|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with never observable and non-empty iterable', () => { + const a = cold('-'); + const asubs = '^'; + const b = [1]; + const expected = '-'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and non-empty iterable', () => { + const a = hot('---^----1--|'); + const asubs = '^ ! '; + const b = [2]; + const expected = '-----(x|)'; + + expectObservable(Observable.zip(a, b)).toBe(expected, { x: ['1', 2] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and empty iterable', () => { + const a = hot('---^----#'); + const asubs = '^ !'; + const b = []; + const expected = '-----#'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with observable which raises error and non-empty iterable', () => { + const a = hot('---^----#'); + const asubs = '^ !'; + const b = [1]; + const expected = '-----#'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty many observable and non-empty many iterable', () => { + const a = hot('---^--1--2--3--|'); + const asubs = '^ ! '; + const b = [4, 5, 6]; + const expected = '---x--y--(z|)'; + + expectObservable(Observable.zip(a, b)).toBe(expected, + { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and non-empty iterable selector that throws', () => { + const a = hot('---^--1--2--3--|'); + const asubs = '^ !'; + const b = [4, 5, 6]; + const expected = '---x--#'; + + const selector = (x: string, y: number) => { + if (y === 5) { + throw new Error('too bad'); + } else { + return x + y; + }}; + expectObservable(Observable.zip(a, b, selector)).toBe(expected, + { x: '14' }, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + }); + + it('should combine two observables and selector', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + + expectObservable(Observable.zip(a, b, (e1: string, e2: string) => e1 + e2)) + .toBe(expected, { x: '14', y: '25', z: '36' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + expectObservable(Observable.zip(a, b, c)).toBe(expected, + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric selector', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + const observable = Observable.zip(a, b, c, + (r0: string, r1: string, r2: string) => [r0, r1, r2]); + expectObservable(observable).toBe(expected, + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric array selector', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + const observable = Observable.zip(a, b, c, + (r0: string, r1: string, r2: string) => [r0, r1, r2]); + expectObservable(observable).toBe(expected, + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data asymmetric 1', () => { + const a = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--4--6--8--0--| '); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e--| '; + + expectObservable(Observable.zip(a, b, (r1: string, r2: string) => r1 + r2)) + .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data asymmetric 2', () => { + const a = hot('---1-^--2--4--6--8--0--| '); + const asubs = '^ ! '; + const b = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e--| '; + + expectObservable(Observable.zip(a, b, (r1: string, r2: string) => r1 + r2)) + .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data symmetric', () => { + const a = hot('---1-^-1-3-5-7-9------| '); + const asubs = '^ ! '; + const b = hot('---1-^--2--4--6--8--0--|'); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e-| '; + + expectObservable(Observable.zip(a, b, (r1: string, r2: string) => r1 + r2)) + .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with selector throws', () => { + const a = hot('---1-^-2---4----| '); + const asubs = '^ ! '; + const b = hot('---1-^--3----5----|'); + const bsubs = '^ ! '; + const expected = '---x----# '; + + const selector = (x: string, y: string) => { + if (y === '5') { + throw new Error('too bad'); + } else { + return x + y; + }}; + const observable = Observable.zip(a, b, selector); + expectObservable(observable).toBe(expected, + { x: '23' }, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with right completes first', () => { + const a = hot('---1-^-2-----|'); + const asubs = '^ !'; + const b = hot('---1-^--3--|'); + const bsubs = '^ !'; + const expected = '---x--|'; + + expectObservable(Observable.zip(a, b)).toBe(expected, { x: ['2', '3'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two nevers', () => { + const a = cold( '-'); + const asubs = '^'; + const b = cold( '-'); + const bsubs = '^'; + const expected = '-'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and empty', () => { + const a = cold( '-'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and never', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = cold( '-'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and empty', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and non-empty', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = hot( '---1--|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with non-empty and empty', () => { + const a = hot( '---1--|'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and non-empty', () => { + const a = cold( '-'); + const asubs = '^'; + const b = hot( '---1--|'); + const bsubs = '^ !'; + const expected = '-'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with non-empty and never', () => { + const a = hot( '---1--|'); + const asubs = '^ !'; + const b = cold( '-'); + const bsubs = '^'; + const expected = '-'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and error', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = hot( '------#', null, 'too bad'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and empty', () => { + const a = hot( '------#', null, 'too bad'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error', () => { + const a = hot('----------|'); + const asubs = '^ ! '; + const b = hot('------# '); + const bsubs = '^ ! '; + const expected = '------# '; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and error', () => { + const a = cold( '-'); + const asubs = '^ !'; + const b = hot('------#'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and never', () => { + const a = hot('------#'); + const asubs = '^ !'; + const b = cold( '-'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and error', () => { + const a = hot('------#', null, 'too bad'); + const asubs = '^ !'; + const b = hot('----------#', null, 'too bad 2'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(Observable.zip(a, b)).toBe(expected, null, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two sources that eventually raise errors', () => { + const a = hot('--w-----#----', { w: 1 }, 'too bad'); + const asubs = '^ !'; + const b = hot('-----z-----#-', { z: 2 }, 'too bad 2'); + const bsubs = '^ !'; + const expected = '-----x--#'; + + expectObservable(Observable.zip(a,b)).toBe(expected, { x: [1, 2] }, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two sources that eventually raise errors (swapped)', () => { + const a = hot('-----z-----#-', { z: 2 }, 'too bad 2'); + const asubs = '^ !'; + const b = hot('--w-----#----', { w: 1 }, 'too bad'); + const bsubs = '^ !'; + const expected = '-----x--#'; + + expectObservable(Observable.zip(a, b)).toBe(expected, { x: [2, 1] }, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and some', () => { + const a = cold( '#'); + const asubs = '(^!)'; + const b = hot( '--1--2--3--'); + const bsubs = '(^!)'; + const expected = '#'; + + expectObservable(Observable.zip(a, b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should combine an immediately-scheduled source with an immediately-scheduled second', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [[1, 4], [2, 5], [3, 6]]; + let i = 0; + + Observable.zip(a, b).subscribe((vals:Array) => { + (expect(vals)).toDeepEqual(r[i++]); + }, null, done); + }); +}); \ No newline at end of file diff --git a/spec/operators/buffer-spec.js b/spec/operators/buffer-spec.js deleted file mode 100644 index dcb8f68004..0000000000 --- a/spec/operators/buffer-spec.js +++ /dev/null @@ -1,220 +0,0 @@ -/* globals describe, it, expect, hot, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.buffer()', function () { - it.asDiagram('buffer')('should emit buffers that close and reopen', function () { - var a = hot('-a-b-c-d-e-f-g-h-i-|'); - var b = hot('-----B-----B-----B-|'); - var expected = '-----x-----y-----z-|'; - var expectedValues = { - x: ['a','b','c'], - y: ['d','e','f'], - z: ['g','h','i'] - }; - expectObservable(a.buffer(b)).toBe(expected, expectedValues); - }); - - it('should work with empty and empty selector', function () { - var a = Observable.empty(); - var b = Observable.empty(); - var expected = '|'; - expectObservable(a.buffer(b)).toBe(expected); - }); - - it('should work with empty and non-empty selector', function () { - var a = Observable.empty(); - var b = hot('-----a-----'); - var expected = '|'; - expectObservable(a.buffer(b)).toBe(expected); - }); - - it('should work with non-empty and empty selector', function () { - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var b = Observable.empty(); - var expected = '|'; - expectObservable(a.buffer(b)).toBe(expected); - }); - - it('should work with never and never selector', function () { - var a = Observable.never(); - var b = Observable.never(); - var expected = '-'; - expectObservable(a.buffer(b)).toBe(expected); - }); - - it('should work with never and empty selector', function () { - var a = Observable.never(); - var b = Observable.empty(); - var expected = '|'; - expectObservable(a.buffer(b)).toBe(expected); - }); - - it('should work with empty and never selector', function () { - var a = Observable.empty(); - var b = Observable.never(); - var expected = '|'; - expectObservable(a.buffer(b)).toBe(expected); - }); - - it('should work with non-empty and throw selector', function () { - var a = hot('---^--a--'); - var b = Observable.throw(new Error('too bad')); - var expected = '#'; - expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); - }); - - it('should work with throw and non-empty selector', function () { - var a = Observable.throw(new Error('too bad')); - var b = hot('---^--a--'); - var expected = '#'; - expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); - }); - - it('should work with error', function () { - var a = hot('---^-------#', null, new Error('too bad')); - var b = hot('---^--------'); - var expected = '--------#'; - expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); - }); - - it('should work with error and non-empty selector', function () { - var a = hot('---^-------#', null, new Error('too bad')); - var b = hot('---^---a----'); - var expected = '----a---#'; - expectObservable(a.buffer(b)).toBe(expected, { a: [] }, new Error('too bad')); - }); - - it('should work with selector', function () { - // Buffer Boundaries Simple (RxJS 4) - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var b = hot('--------^--a-------b---cd---------e---f---|'); - var expected = '---a-------b---cd---------e---f-|'; - var expectedValues = { - a: ['3'], - b: ['4', '5'], - c: ['6'], - d: [], - e: ['7', '8', '9'], - f: ['0'] - }; - expectObservable(a.buffer(b)).toBe(expected, expectedValues); - }); - - it('should work with selector completed', function () { - // Buffer Boundaries onCompletedBoundaries (RxJS 4) - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var subs = '^ ! '; - var b = hot('--------^--a-------b---cd| '); - var expected = '---a-------b---cd| '; - var expectedValues = { - a: ['3'], - b: ['4', '5'], - c: ['6'], - d: [] - }; - expectObservable(a.buffer(b)).toBe(expected, expectedValues); - expectSubscriptions(a.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing the result Observable early', function () { - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var unsub = ' ! '; - var subs = '^ ! '; - var b = hot('--------^--a-------b---cd| '); - var expected = '---a-------b--- '; - var expectedValues = { - a: ['3'], - b: ['4', '5'] - }; - expectObservable(a.buffer(b), unsub).toBe(expected, expectedValues); - expectSubscriptions(a.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var subs = '^ ! '; - var b = hot('--------^--a-------b---cd| '); - var expected = '---a-------b--- '; - var unsub = ' ! '; - var expectedValues = { - a: ['3'], - b: ['4', '5'] - }; - - var result = a - .mergeMap(function (x) { return Observable.of(x); }) - .buffer(b) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, expectedValues); - expectSubscriptions(a.subscriptions).toBe(subs); - }); - - it('should work with non-empty and selector error', function () { - // Buffer Boundaries onErrorSource (RxJS 4) - var a = hot('--1--2--^--3-----#', {'3': 3}, new Error('too bad')); - var subs = '^ !'; - var b = hot('--------^--a--b---'); - var expected = '---a--b--#'; - var expectedValues = { - a: [3], - b: [] - }; - expectObservable(a.buffer(b)).toBe(expected, expectedValues, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(subs); - }); - - it('should work with non-empty and empty selector error', function () { - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var b = hot('--------^----------------#', null, new Error('too bad')); - var expected = '-----------------#'; - expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); - }); - - it('should work with non-empty and selector error', function () { - // Buffer Boundaries onErrorBoundaries (RxJS 4) - var obj = { a: true, b: true, c: true }; - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var subs = '^ !'; - var b = hot('--------^--a-------b---c-#', obj, new Error('too bad')); - var expected = '---a-------b---c-#'; - var expectedValues = { - a: ['3'], - b: ['4', '5'], - c: ['6'] - }; - expectObservable(a.buffer(b)).toBe(expected, expectedValues, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(subs); - }); - - it('should unsubscribe notifier when source unsubscribed', function () { - var a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); - var unsub = ' ! '; - var subs = '^ ! '; - var b = hot('--------^--a-------b---cd| '); - var bsubs = '^ ! '; - var expected = '---a-------b--- '; - var expectedValues = { - a: ['3'], - b: ['4', '5'] - }; - - expectObservable(a.buffer(b), unsub).toBe(expected, expectedValues); - expectSubscriptions(a.subscriptions).toBe(subs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should unsubscribe notifier when source unsubscribed', function () { - var a = hot('-a-b-c-d-e-f-g-h-i-|'); - var b = hot('-----1-----2-----3-|'); - var bsubs = '^ !'; - var expected = '-----(x|)'; - var expectedValues = { - x: ['a','b','c'], - }; - - expectObservable(a.buffer(b).take(1)).toBe(expected, expectedValues); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); -}); diff --git a/spec/operators/buffer-spec.ts b/spec/operators/buffer-spec.ts new file mode 100644 index 0000000000..372dcb4377 --- /dev/null +++ b/spec/operators/buffer-spec.ts @@ -0,0 +1,222 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.buffer()', () => { + asDiagram('buffer')('should emit buffers that close and reopen', () => { + const a = hot('-a-b-c-d-e-f-g-h-i-|'); + const b = hot('-----B-----B-----B-|'); + const expected = '-----x-----y-----z-|'; + const expectedValues = { + x: ['a','b','c'], + y: ['d','e','f'], + z: ['g','h','i'] + }; + expectObservable(a.buffer(b)).toBe(expected, expectedValues); + }); + + it('should work with empty and empty selector', () => { + const a = Observable.empty(); + const b = Observable.empty(); + const expected = '|'; + expectObservable(a.buffer(b)).toBe(expected); + }); + + it('should work with empty and non-empty selector', () => { + const a = Observable.empty(); + const b = hot('-----a-----'); + const expected = '|'; + expectObservable(a.buffer(b)).toBe(expected); + }); + + it('should work with non-empty and empty selector', () => { + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const b = Observable.empty(); + const expected = '|'; + expectObservable(a.buffer(b)).toBe(expected); + }); + + it('should work with never and never selector', () => { + const a = Observable.never(); + const b = Observable.never(); + const expected = '-'; + expectObservable(a.buffer(b)).toBe(expected); + }); + + it('should work with never and empty selector', () => { + const a = Observable.never(); + const b = Observable.empty(); + const expected = '|'; + expectObservable(a.buffer(b)).toBe(expected); + }); + + it('should work with empty and never selector', () => { + const a = Observable.empty(); + const b = Observable.never(); + const expected = '|'; + expectObservable(a.buffer(b)).toBe(expected); + }); + + it('should work with non-empty and throw selector', () => { + const a = hot('---^--a--'); + const b = Observable.throw(new Error('too bad')); + const expected = '#'; + expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); + }); + + it('should work with throw and non-empty selector', () => { + const a = Observable.throw(new Error('too bad')); + const b = hot('---^--a--'); + const expected = '#'; + expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); + }); + + it('should work with error', () => { + const a = hot('---^-------#', null, new Error('too bad')); + const b = hot('---^--------'); + const expected = '--------#'; + expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); + }); + + it('should work with error and non-empty selector', () => { + const a = hot('---^-------#', null, new Error('too bad')); + const b = hot('---^---a----'); + const expected = '----a---#'; + expectObservable(a.buffer(b)).toBe(expected, { a: [] }, new Error('too bad')); + }); + + it('should work with selector', () => { + // Buffer Boundaries Simple (RxJS 4) + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const b = hot('--------^--a-------b---cd---------e---f---|'); + const expected = '---a-------b---cd---------e---f-|'; + const expectedValues = { + a: ['3'], + b: ['4', '5'], + c: ['6'], + d: [], + e: ['7', '8', '9'], + f: ['0'] + }; + expectObservable(a.buffer(b)).toBe(expected, expectedValues); + }); + + it('should work with selector completed', () => { + // Buffer Boundaries onCompletedBoundaries (RxJS 4) + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const subs = '^ ! '; + const b = hot('--------^--a-------b---cd| '); + const expected = '---a-------b---cd| '; + const expectedValues = { + a: ['3'], + b: ['4', '5'], + c: ['6'], + d: [] + }; + expectObservable(a.buffer(b)).toBe(expected, expectedValues); + expectSubscriptions(a.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing the result Observable early', () => { + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const unsub = ' ! '; + const subs = '^ ! '; + const b = hot('--------^--a-------b---cd| '); + const expected = '---a-------b--- '; + const expectedValues = { + a: ['3'], + b: ['4', '5'] + }; + expectObservable(a.buffer(b), unsub).toBe(expected, expectedValues); + expectSubscriptions(a.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const subs = '^ ! '; + const b = hot('--------^--a-------b---cd| '); + const expected = '---a-------b--- '; + const unsub = ' ! '; + const expectedValues = { + a: ['3'], + b: ['4', '5'] + }; + + const result = a + .mergeMap((x: any) => Observable.of(x)) + .buffer(b) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, expectedValues); + expectSubscriptions(a.subscriptions).toBe(subs); + }); + + it('should work with non-empty and selector error', () => { + // Buffer Boundaries onErrorSource (RxJS 4) + const a = hot('--1--2--^--3-----#', {'3': 3}, new Error('too bad')); + const subs = '^ !'; + const b = hot('--------^--a--b---'); + const expected = '---a--b--#'; + const expectedValues = { + a: [3], + b: [] + }; + expectObservable(a.buffer(b)).toBe(expected, expectedValues, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(subs); + }); + + it('should work with non-empty and empty selector error', () => { + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const b = hot('--------^----------------#', null, new Error('too bad')); + const expected = '-----------------#'; + expectObservable(a.buffer(b)).toBe(expected, null, new Error('too bad')); + }); + + it('should work with non-empty and selector error', () => { + // Buffer Boundaries onErrorBoundaries (RxJS 4) + const obj = { a: true, b: true, c: true }; + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const subs = '^ !'; + const b = hot('--------^--a-------b---c-#', obj, new Error('too bad')); + const expected = '---a-------b---c-#'; + const expectedValues = { + a: ['3'], + b: ['4', '5'], + c: ['6'] + }; + expectObservable(a.buffer(b)).toBe(expected, expectedValues, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(subs); + }); + + it('should unsubscribe notifier when source unsubscribed', () => { + const a = hot('--1--2--^--3--4--5---6----7--8--9---0---|'); + const unsub = ' ! '; + const subs = '^ ! '; + const b = hot('--------^--a-------b---cd| '); + const bsubs = '^ ! '; + const expected = '---a-------b--- '; + const expectedValues = { + a: ['3'], + b: ['4', '5'] + }; + + expectObservable(a.buffer(b), unsub).toBe(expected, expectedValues); + expectSubscriptions(a.subscriptions).toBe(subs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should unsubscribe notifier when source unsubscribed', () => { + const a = hot('-a-b-c-d-e-f-g-h-i-|'); + const b = hot('-----1-----2-----3-|'); + const bsubs = '^ !'; + const expected = '-----(x|)'; + const expectedValues = { + x: ['a','b','c'], + }; + + expectObservable(a.buffer(b).take(1)).toBe(expected, expectedValues); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); +}); diff --git a/spec/operators/bufferCount-spec.js b/spec/operators/bufferCount-spec.js deleted file mode 100644 index bfbf809ac8..0000000000 --- a/spec/operators/bufferCount-spec.js +++ /dev/null @@ -1,118 +0,0 @@ -/* globals describe, it, expect, hot, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.bufferCount', function () { - it.asDiagram('bufferCount(3,2)')('should emit buffers at intervals', function () { - var values = { - v: ['a', 'b', 'c'], - w: ['c', 'd', 'e'], - x: ['e', 'f', 'g'], - y: ['g', 'h', 'i'], - z: ['i'] - }; - var e1 = hot('--a--b--c--d--e--f--g--h--i--|'); - var expected = '--------v-----w-----x-----y--(z|)'; - - expectObservable(e1.bufferCount(3, 2)).toBe(expected, values); - }); - - it('should emit buffers at buffersize of intervals if not specified', function () { - var values = { - x: ['a', 'b'], - y: ['c', 'd'], - z: ['e', 'f'] - }; - var e1 = hot('--a--b--c--d--e--f--|'); - var expected = '-----x-----y-----z--|'; - - expectObservable(e1.bufferCount(2)).toBe(expected, values); - }); - - it('should emit partial buffers if source completes before reaching specified buffer count', function () { - var e1 = hot('--a--b--c--d--|'); - var expected = '--------------(x|)'; - - expectObservable(e1.bufferCount(5)).toBe(expected, {x: ['a', 'b', 'c', 'd']}); - }); - - it('should emit full buffer then last partial buffer if source completes', function () { - var e1 = hot('--a^-b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '--------y-----(z|)'; - - expectObservable(e1.bufferCount(3)).toBe(expected, {y: ['b', 'c', 'd'], z: ['e']}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit buffers at intervals, but stop when result is unsubscribed early', function () { - var values = { - v: ['a', 'b', 'c'], - w: ['c', 'd', 'e'] - }; - var e1 = hot('--a--b--c--d--e--f--g--h--i--|'); - var unsub = ' ! '; - var subs = '^ ! '; - var expected = '--------v-----w---- '; - - expectObservable(e1.bufferCount(3, 2), unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var values = { - v: ['a', 'b', 'c'], - w: ['c', 'd', 'e'] - }; - var e1 = hot('--a--b--c--d--e--f--g--h--i--|'); - var subs = '^ ! '; - var expected = '--------v-----w---- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .bufferCount(3, 2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error if source raise error before reaching specified buffer count', function () { - var e1 = hot('--a--b--c--d--#'); - var e1subs = '^ !'; - var expected = '--------------#'; - - expectObservable(e1.bufferCount(5)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit buffers with specified skip count when skip count is less than window count', function () { - var values = { - v: ['a', 'b', 'c'], - w: ['b', 'c', 'd'], - x: ['c', 'd', 'e'], - y: ['d', 'e'], - z: ['e'] - }; - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '--------v--w--x--(yz|)'; - - expectObservable(e1.bufferCount(3, 1)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit buffers with specified skip count when skip count is more than window count', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '-----y--------z--|'; - var values = { - y: ['a', 'b'], - z: ['d', 'e'] - }; - - expectObservable(e1.bufferCount(2, 3)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/bufferCount-spec.ts b/spec/operators/bufferCount-spec.ts new file mode 100644 index 0000000000..ecc149088f --- /dev/null +++ b/spec/operators/bufferCount-spec.ts @@ -0,0 +1,120 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.bufferCount', () => { + asDiagram('bufferCount(3,2)')('should emit buffers at intervals', () => { + const values = { + v: ['a', 'b', 'c'], + w: ['c', 'd', 'e'], + x: ['e', 'f', 'g'], + y: ['g', 'h', 'i'], + z: ['i'] + }; + const e1 = hot('--a--b--c--d--e--f--g--h--i--|'); + const expected = '--------v-----w-----x-----y--(z|)'; + + expectObservable(e1.bufferCount(3, 2)).toBe(expected, values); + }); + + it('should emit buffers at buffersize of intervals if not specified', () => { + const values = { + x: ['a', 'b'], + y: ['c', 'd'], + z: ['e', 'f'] + }; + const e1 = hot('--a--b--c--d--e--f--|'); + const expected = '-----x-----y-----z--|'; + + expectObservable(e1.bufferCount(2)).toBe(expected, values); + }); + + it('should emit partial buffers if source completes before reaching specified buffer count', () => { + const e1 = hot('--a--b--c--d--|'); + const expected = '--------------(x|)'; + + expectObservable(e1.bufferCount(5)).toBe(expected, {x: ['a', 'b', 'c', 'd']}); + }); + + it('should emit full buffer then last partial buffer if source completes', () => { + const e1 = hot('--a^-b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '--------y-----(z|)'; + + expectObservable(e1.bufferCount(3)).toBe(expected, {y: ['b', 'c', 'd'], z: ['e']}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit buffers at intervals, but stop when result is unsubscribed early', () => { + const values = { + v: ['a', 'b', 'c'], + w: ['c', 'd', 'e'] + }; + const e1 = hot('--a--b--c--d--e--f--g--h--i--|'); + const unsub = ' ! '; + const subs = '^ ! '; + const expected = '--------v-----w---- '; + + expectObservable(e1.bufferCount(3, 2), unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const values = { + v: ['a', 'b', 'c'], + w: ['c', 'd', 'e'] + }; + const e1 = hot('--a--b--c--d--e--f--g--h--i--|'); + const subs = '^ ! '; + const expected = '--------v-----w---- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .bufferCount(3, 2) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error if source raise error before reaching specified buffer count', () => { + const e1 = hot('--a--b--c--d--#'); + const e1subs = '^ !'; + const expected = '--------------#'; + + expectObservable(e1.bufferCount(5)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit buffers with specified skip count when skip count is less than window count', () => { + const values = { + v: ['a', 'b', 'c'], + w: ['b', 'c', 'd'], + x: ['c', 'd', 'e'], + y: ['d', 'e'], + z: ['e'] + }; + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '--------v--w--x--(yz|)'; + + expectObservable(e1.bufferCount(3, 1)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit buffers with specified skip count when skip count is more than window count', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '-----y--------z--|'; + const values = { + y: ['a', 'b'], + z: ['d', 'e'] + }; + + expectObservable(e1.bufferCount(2, 3)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/bufferTime-spec.js b/spec/operators/bufferTime-spec.js deleted file mode 100644 index ed63186927..0000000000 --- a/spec/operators/bufferTime-spec.js +++ /dev/null @@ -1,227 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler, time */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.bufferTime', function () { - it.asDiagram('bufferTime(100)')('should emit buffers at intervals', function () { - var e1 = hot('---a---b---c---d---e---f---g-----|'); - var subs = '^ !'; - var t = time( '----------|'); - var expected = '----------w---------x---------y--(z|)'; - var values = { - w: ['a','b'], - x: ['c','d','e'], - y: ['f', 'g'], - z: [] - }; - - var result = e1.bufferTime(t, null, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should emit buffers at intervals test 2', function () { - var e1 = hot('---------a---------b---------c---------d---------e---------g--------|'); - var t = time( '--------------------------------|'); - var expected = '--------------------------------x-------------------------------y---(z|)'; - var values = { - x: ['a','b','c'], - y: ['d', 'e', 'g'], - z: [] - }; - - var result = e1.bufferTime(t, null, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - }); - - it('should emit buffers that have been created at intervals and close after the specified delay', function () { - var e1 = hot('---a---b---c----d----e----f----g----h----i----(k|)'); - // --------------------*--------------------*---- start interval - // ---------------------| timespans - // ---------------------| - // -----| - var t = time( '---------------------|'); - var interval = time( '--------------------|'); - var expected = '---------------------x-------------------y----(z|)'; - var values = { - x: ['a', 'b', 'c', 'd', 'e'], - y: ['e', 'f', 'g', 'h', 'i'], - z: ['i', 'k'] - }; - - var result = e1.bufferTime(t, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - }); - - it('should emit buffers with timeSpan 100 and creationInterval 70', function () { - var e1 = hot('--1--^2--3---4---5--6--7---8----9------------|'); - // -------*------*------*------*------*----- creation interval - // ----------| timespans - // ----------| - // ----------| - // ----------| - // ----------| - // ----------| - var e1subs = '^ !'; - var t = time( '----------|'); - var interval = time( '-------|'); - var expected = '----------a------b------c------d------e-(f|)'; - var values = { - a: ['2', '3', '4'], - b: ['4', '5', '6'], - c: ['6', '7', '8'], - d: ['8', '9'], - e: [], - f: [] - }; - - var result = e1.bufferTime(t, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit buffers but handle source ending with an error', function () { - var e1 = hot('--1--^2--3---4---5--6--7---8----9------------#'); - // -------*------*------*------*------*----- creation interval - // ----------| timespans - // ----------| - // ----------| - // ----------| - // ----------| - // ----------| - var t = time( '----------|'); - var interval = time( '-------|'); - var expected = '----------a------b------c------d------e-#'; - var values = { - a: ['2', '3', '4'], - b: ['4', '5', '6'], - c: ['6', '7', '8'], - d: ['8', '9'], - e: [] - }; - - var result = e1.bufferTime(t, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - }); - - it('should emit buffers and allow result to unsubscribed early', function () { - var e1 = hot('--1--^2--3---4---5--6--7---8----9------------|'); - var unsub = ' ! '; - var subs = '^ ! '; - // -------*------*------*------*------*----- creation interval - // ----------| timespans - // ----------| - // ----------| - var t = time( '----------|'); - var interval = time( '-------|'); - var expected = '----------a------ '; - var values = { - a: ['2', '3', '4'] - }; - - var result = e1.bufferTime(t, interval, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--1--^2--3---4---5--6--7---8----9------------|'); - var subs = '^ ! '; - // -------*------*------*------*------*----- creation interval - // ----------| timespans - // ----------| - // ----------| - var t = time( '----------|'); - var interval = time( '-------|'); - var expected = '----------a------ '; - var unsub = ' ! '; - var values = { - a: ['2', '3', '4'] - }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .bufferTime(t, interval, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle empty', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var expected = '(b|)'; - var values = { b: [] }; - var t = time('----------|'); - - var result = e1.bufferTime(t, null, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle never', function () { - var e1 = cold('-'); - var unsub = ' !'; - var t = time( '----------|'); - var expected = '----------a---------a---------a---------a----'; - - var result = e1.bufferTime(t, null, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected, { a: [] }); - }); - - it('should handle throw', function () { - var e1 = Observable.throw(new Error('haha')); - var expected = '#'; - var t = time('----------|'); - - var result = e1.bufferTime(t, null, rxTestScheduler); - - expectObservable(result).toBe(expected, undefined, new Error('haha')); - }); - - it('should handle errors', function () { - var e1 = hot('---a---b---c---#'); - var e1subs = '^ !'; - var t = time( '----------|'); - var expected = '----------w----#'; - var values = { - w: ['a','b'] - }; - - var result = e1.bufferTime(t, null, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit buffers that have been created at intervals and close after ' + - 'the specified delay with errors', function () { - var e1 = hot('---a---b---c----d----e----f----g----h----i--#'); - // --------------------*--------------------*---- start interval - // ---------------------| timespans - // ---------------------| - // -----| - var e1subs = '^ !'; - var t = time( '---------------------|'); - var interval = time( '--------------------|'); - var expected = '---------------------x-------------------y--#'; - var values = { - x: ['a', 'b', 'c', 'd', 'e'], - y: ['e', 'f', 'g', 'h', 'i'] - }; - - var result = e1.bufferTime(t, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/bufferTime-spec.ts b/spec/operators/bufferTime-spec.ts new file mode 100644 index 0000000000..5fe1964de7 --- /dev/null +++ b/spec/operators/bufferTime-spec.ts @@ -0,0 +1,230 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.bufferTime', () => { + asDiagram('bufferTime(100)')('should emit buffers at intervals', () => { + const e1 = hot('---a---b---c---d---e---f---g-----|'); + const subs = '^ !'; + const t = time( '----------|'); + const expected = '----------w---------x---------y--(z|)'; + const values = { + w: ['a','b'], + x: ['c','d','e'], + y: ['f', 'g'], + z: [] + }; + + const result = e1.bufferTime(t, null, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should emit buffers at intervals test 2', () => { + const e1 = hot('---------a---------b---------c---------d---------e---------g--------|'); + const t = time( '--------------------------------|'); + const expected = '--------------------------------x-------------------------------y---(z|)'; + const values = { + x: ['a','b','c'], + y: ['d', 'e', 'g'], + z: [] + }; + + const result = e1.bufferTime(t, null, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + }); + + it('should emit buffers that have been created at intervals and close after the specified delay', () => { + const e1 = hot('---a---b---c----d----e----f----g----h----i----(k|)'); + // --------------------*--------------------*---- start interval + // ---------------------| timespans + // ---------------------| + // -----| + const t = time( '---------------------|'); + const interval = time( '--------------------|'); + const expected = '---------------------x-------------------y----(z|)'; + const values = { + x: ['a', 'b', 'c', 'd', 'e'], + y: ['e', 'f', 'g', 'h', 'i'], + z: ['i', 'k'] + }; + + const result = e1.bufferTime(t, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + }); + + it('should emit buffers with timeSpan 100 and creationInterval 70', () => { + const e1 = hot('--1--^2--3---4---5--6--7---8----9------------|'); + // -------*------*------*------*------*----- creation interval + // ----------| timespans + // ----------| + // ----------| + // ----------| + // ----------| + // ----------| + const e1subs = '^ !'; + const t = time( '----------|'); + const interval = time( '-------|'); + const expected = '----------a------b------c------d------e-(f|)'; + const values = { + a: ['2', '3', '4'], + b: ['4', '5', '6'], + c: ['6', '7', '8'], + d: ['8', '9'], + e: [], + f: [] + }; + + const result = e1.bufferTime(t, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit buffers but handle source ending with an error', () => { + const e1 = hot('--1--^2--3---4---5--6--7---8----9------------#'); + // -------*------*------*------*------*----- creation interval + // ----------| timespans + // ----------| + // ----------| + // ----------| + // ----------| + // ----------| + const t = time( '----------|'); + const interval = time( '-------|'); + const expected = '----------a------b------c------d------e-#'; + const values = { + a: ['2', '3', '4'], + b: ['4', '5', '6'], + c: ['6', '7', '8'], + d: ['8', '9'], + e: [] + }; + + const result = e1.bufferTime(t, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + }); + + it('should emit buffers and allow result to unsubscribed early', () => { + const e1 = hot('--1--^2--3---4---5--6--7---8----9------------|'); + const unsub = ' ! '; + const subs = '^ ! '; + // -------*------*------*------*------*----- creation interval + // ----------| timespans + // ----------| + // ----------| + const t = time( '----------|'); + const interval = time( '-------|'); + const expected = '----------a------ '; + const values = { + a: ['2', '3', '4'] + }; + + const result = e1.bufferTime(t, interval, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--1--^2--3---4---5--6--7---8----9------------|'); + const subs = '^ ! '; + // -------*------*------*------*------*----- creation interval + // ----------| timespans + // ----------| + // ----------| + const t = time( '----------|'); + const interval = time( '-------|'); + const expected = '----------a------ '; + const unsub = ' ! '; + const values = { + a: ['2', '3', '4'] + }; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .bufferTime(t, interval, rxTestScheduler) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle empty', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const expected = '(b|)'; + const values = { b: [] }; + const t = time('----------|'); + + const result = e1.bufferTime(t, null, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle never', () => { + const e1 = cold('-'); + const unsub = ' !'; + const t = time( '----------|'); + const expected = '----------a---------a---------a---------a----'; + + const result = e1.bufferTime(t, null, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected, { a: [] }); + }); + + it('should handle throw', () => { + const e1 = Observable.throw(new Error('haha')); + const expected = '#'; + const t = time('----------|'); + + const result = e1.bufferTime(t, null, rxTestScheduler); + + expectObservable(result).toBe(expected, undefined, new Error('haha')); + }); + + it('should handle errors', () => { + const e1 = hot('---a---b---c---#'); + const e1subs = '^ !'; + const t = time( '----------|'); + const expected = '----------w----#'; + const values = { + w: ['a','b'] + }; + + const result = e1.bufferTime(t, null, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit buffers that have been created at intervals and close after ' + + 'the specified delay with errors', () => { + const e1 = hot('---a---b---c----d----e----f----g----h----i--#'); + // --------------------*--------------------*---- start interval + // ---------------------| timespans + // ---------------------| + // -----| + const e1subs = '^ !'; + const t = time( '---------------------|'); + const interval = time( '--------------------|'); + const expected = '---------------------x-------------------y--#'; + const values = { + x: ['a', 'b', 'c', 'd', 'e'], + y: ['e', 'f', 'g', 'h', 'i'] + }; + + const result = e1.bufferTime(t, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/bufferToggle-spec.js b/spec/operators/bufferToggle-spec.js deleted file mode 100644 index 48c0096205..0000000000 --- a/spec/operators/bufferToggle-spec.js +++ /dev/null @@ -1,342 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.bufferToggle', function () { - it.asDiagram('bufferToggle')('should emit buffers using hot openings and hot closings', function () { - var e1 = hot('---a---b---c---d---e---f---g---|'); - var e2 = hot('--o------------------o---------|'); - var e3 = hot('---------c---------------c-----|'); - var expected = '---------x---------------y-----|'; - var values = { - x: ['a','b'], - y: ['f'], - }; - - var result = e1.bufferToggle(e2, function (x) { return e3; }); - - expectObservable(result).toBe(expected, values); - }); - - it('should emit buffers that are opened by an observable from the first argument ' + - 'and closed by an observable returned by the function in the second argument', - function () { - var e1 = hot('-----a----b----c----d----e----f----g----h----i----|'); - var e2 = cold('-------------x-------------y--------------z-------|'); - var e3 = cold('---------------(j|)'); - // ---------------(j|) - // ---------------(j|) - var expected = '----------------------------q-------------r-------(s|)'; - - var values = { - q: ['c','d','e'], - r: ['f','g','h'], - s: ['i'] - }; - var innerVals = ['x', 'y', 'z']; - - expectObservable(e1.bufferToggle(e2, function (x) { - expect(x).toBe(innerVals.shift()); - return e3; - })).toBe(expected, values); - }); - - it('should emit buffers using varying cold closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e2 = cold('--x-----------y--------z---| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var closeSubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-----------------ij----------------(k|) '; - var values = { - i: ['b','c','d','e'], - j: ['e'], - k: ['g','h'] - }; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); - }); - - it('should emit buffers using varying hot closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e2 = cold('--x-----------y--------z---| '); - var subs = '^ ! '; - var closings = [ - {obs: hot( '-1--^----------------s-| '), // eslint-disable-line key-spacing - sub: ' ^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '-----3----4-------(s|) '), // eslint-disable-line key-spacing - sub: ' ^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '-------3----4-------5----------------s|'), // eslint-disable-line key-spacing - sub: ' ^ ! '}]; // eslint-disable-line key-spacing - var expected = '-----------------ij----------------(k|)'; - var values = { - i: ['b','c','d','e'], - j: ['e'], - k: ['g','h'] - }; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++].obs; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - for (var j = 0; j < closings.length; j++) { - expectSubscriptions(closings[j].obs.subscriptions).toBe(closings[j].sub); - } - }); - - it('should emit buffers using varying empty delayed closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e2 = cold('--x-----------y--------z---| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------| '), - cold( '----| '), - cold( '---------------|')]; - var expected = '-----------------ij----------------(k|)'; - var values = { - i: ['b','c','d','e'], - j: ['e'], - k: ['g','h'] - }; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should emit buffers using varying cold closings, outer unsubscribed early', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var closings = [ - cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var csub0 = ' ^ ! '; - var expected = '----------- '; - var unsub = ' ! '; - var values = { - i: ['b','c','d','e'] - }; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++]; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(csub0); - expectSubscriptions(closings[1].subscriptions).toBe([]); - expectSubscriptions(closings[2].subscriptions).toBe([]); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var closings = [ - cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var expected = '-----------------i- '; - var unsub = ' ! '; - var values = { - i: ['b','c','d','e'] - }; - - var i = 0; - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .bufferToggle(e2, function () { return closings[i++]; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should propagate error thrown from closingSelector', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e2 = cold('--x-----------y--------z---| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var closeSubs0 = ' ^ ! '; - var expected = '--------------# '; - - var i = 0; - var result = e1.bufferToggle(e2, function () { - if (i === 1) { - throw 'error'; - } - return closings[i++]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs0); - expectSubscriptions(closings[1].subscriptions).toBe([]); - expectSubscriptions(closings[2].subscriptions).toBe([]); - }); - - it('should propagate error emitted from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e2 = cold('--x-----------y--------z---| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '# ')]; - var closeSubs = [' ^ ! ', - ' (^!) ']; - var expected = '--------------# '; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should propagate error emitted late from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e2 = cold('--x-----------y--------z---| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '-----# ')]; - var closeSubs = [' ^ ! ', - ' ^ ! ']; - var expected = '-----------------i-# '; - var values = { - i: ['b','c','d','e'] - }; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should handle errors', function () { - var e1 = hot('--a--^---b---c---d---e--# '); - var e2 = cold('--x-----------y--------z---|'); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '-------s| ')]; - var closeSubs = [' ^ ! ', - ' ^ ! ']; - var expected = '-----------------i-# '; - var values = { - i: ['b','c','d','e'] - }; - - var i = 0; - var result = e1.bufferToggle(e2, function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should handle empty source', function () { - var e1 = cold('|'); - var e2 = cold('--o-----|'); - var e3 = cold( '-----c--|'); - var expected = '|'; - var values = { x: [] }; - - var result = e1.bufferToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected, values); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e2 = cold('--o-----|'); - var e3 = cold( '-----c--|'); - var expected = '#'; - var values = { x: [] }; - - var result = e1.bufferToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected, values); - }); - - it('should handle never', function () { - var e1 = hot('-'); - var e2 = cold('--o-----o------o-----o---o-----|'); - var e3 = cold( '--c-|'); - var unsub = ' !'; - var subs = '^ !'; - var expected = '----x-----x------x-----x---x-----------------'; - var values = { x: [] }; - - var result = e1.bufferToggle(e2, function () { return e3; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a never opening Observable', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e2 = cold( '-'); - var e3 = cold( '--c-|'); - var expected = '-----------------------------------|'; - - var result = e1.bufferToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected); - }); - - it('should handle a never closing Observable', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e2 = cold( '---o---------------o-----------|'); - var e3 = cold('-'); - var expected = '-----------------------------------(xy|)'; - var values = { - x: ['b', 'c', 'd', 'e', 'f', 'g', 'h'], - y: ['f', 'g', 'h'] - }; - - var result = e1.bufferToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected, values); - }); - - it('should handle opening Observable that just throws', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '(^!)'; - var e2 = cold( '#'); - var e2subs = '(^!)'; - var e3 = cold( '--c-|'); - var expected = '#'; - - var result = e1.bufferToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/bufferToggle-spec.ts b/spec/operators/bufferToggle-spec.ts new file mode 100644 index 0000000000..5a5b7fab88 --- /dev/null +++ b/spec/operators/bufferToggle-spec.ts @@ -0,0 +1,344 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.bufferToggle', () => { + asDiagram('bufferToggle')('should emit buffers using hot openings and hot closings', () => { + const e1 = hot('---a---b---c---d---e---f---g---|'); + const e2 = hot('--o------------------o---------|'); + const e3 = hot('---------c---------------c-----|'); + const expected = '---------x---------------y-----|'; + const values = { + x: ['a','b'], + y: ['f'], + }; + + const result = e1.bufferToggle(e2, (x: any) => e3); + + expectObservable(result).toBe(expected, values); + }); + + it('should emit buffers that are opened by an observable from the first argument ' + + 'and closed by an observable returned by the function in the second argument', + () => { + const e1 = hot('-----a----b----c----d----e----f----g----h----i----|'); + const e2 = cold('-------------x-------------y--------------z-------|'); + const e3 = cold('---------------(j|)'); + // ---------------(j|) + // ---------------(j|) + const expected = '----------------------------q-------------r-------(s|)'; + + const values = { + q: ['c','d','e'], + r: ['f','g','h'], + s: ['i'] + }; + const innerVals = ['x', 'y', 'z']; + + expectObservable(e1.bufferToggle(e2, (x: string) => { + expect(x).toBe(innerVals.shift()); + return e3; + })).toBe(expected, values); + }); + + it('should emit buffers using constying cold closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e2 = cold('--x-----------y--------z---| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const closeSubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-----------------ij----------------(k|) '; + const values = { + i: ['b','c','d','e'], + j: ['e'], + k: ['g','h'] + }; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); + }); + + it('should emit buffers using constying hot closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e2 = cold('--x-----------y--------z---| '); + const subs = '^ ! '; + const closings = [ + {obs: hot( '-1--^----------------s-| '), // eslint-disable-line key-spacing + sub: ' ^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '-----3----4-------(s|) '), // eslint-disable-line key-spacing + sub: ' ^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '-------3----4-------5----------------s|'), // eslint-disable-line key-spacing + sub: ' ^ ! '}]; // eslint-disable-line key-spacing + const expected = '-----------------ij----------------(k|)'; + const values = { + i: ['b','c','d','e'], + j: ['e'], + k: ['g','h'] + }; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++].obs); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + for (let j = 0; j < closings.length; j++) { + expectSubscriptions(closings[j].obs.subscriptions).toBe(closings[j].sub); + } + }); + + it('should emit buffers using constying empty delayed closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e2 = cold('--x-----------y--------z---| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------| '), + cold( '----| '), + cold( '---------------|')]; + const expected = '-----------------ij----------------(k|)'; + const values = { + i: ['b','c','d','e'], + j: ['e'], + k: ['g','h'] + }; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should emit buffers using constying cold closings, outer unsubscribed early', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const closings = [ + cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const csub0 = ' ^ ! '; + const expected = '----------- '; + const unsub = ' ! '; + const values = { + i: ['b','c','d','e'] + }; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++]); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(csub0); + expectSubscriptions(closings[1].subscriptions).toBe([]); + expectSubscriptions(closings[2].subscriptions).toBe([]); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const closings = [ + cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const expected = '-----------------i- '; + const unsub = ' ! '; + const values = { + i: ['b','c','d','e'] + }; + + let i = 0; + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .bufferToggle(e2, () => closings[i++]) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should propagate error thrown from closingSelector', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e2 = cold('--x-----------y--------z---| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const closeSubs0 = ' ^ ! '; + const expected = '--------------# '; + + let i = 0; + const result = e1.bufferToggle(e2, () => { + if (i === 1) { + throw 'error'; + } + return closings[i++]; + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs0); + expectSubscriptions(closings[1].subscriptions).toBe([]); + expectSubscriptions(closings[2].subscriptions).toBe([]); + }); + + it('should propagate error emitted from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e2 = cold('--x-----------y--------z---| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '# ')]; + const closeSubs = [' ^ ! ', + ' (^!) ']; + const expected = '--------------# '; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should propagate error emitted late from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e2 = cold('--x-----------y--------z---| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '-----# ')]; + const closeSubs = [' ^ ! ', + ' ^ ! ']; + const expected = '-----------------i-# '; + const values = { + i: ['b','c','d','e'] + }; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should handle errors', () => { + const e1 = hot('--a--^---b---c---d---e--# '); + const e2 = cold('--x-----------y--------z---|'); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '-------s| ')]; + const closeSubs = [' ^ ! ', + ' ^ ! ']; + const expected = '-----------------i-# '; + const values = { + i: ['b','c','d','e'] + }; + + let i = 0; + const result = e1.bufferToggle(e2, () => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should handle empty source', () => { + const e1 = cold('|'); + const e2 = cold('--o-----|'); + const e3 = cold( '-----c--|'); + const expected = '|'; + const values = { x: [] }; + + const result = e1.bufferToggle(e2, () => e3); + + expectObservable(result).toBe(expected, values); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e2 = cold('--o-----|'); + const e3 = cold( '-----c--|'); + const expected = '#'; + const values = { x: [] }; + + const result = e1.bufferToggle(e2, () => e3); + + expectObservable(result).toBe(expected, values); + }); + + it('should handle never', () => { + const e1 = hot('-'); + const e2 = cold('--o-----o------o-----o---o-----|'); + const e3 = cold( '--c-|'); + const unsub = ' !'; + const subs = '^ !'; + const expected = '----x-----x------x-----x---x-----------------'; + const values = { x: [] }; + + const result = e1.bufferToggle(e2, () => e3); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a never opening Observable', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e2 = cold( '-'); + const e3 = cold( '--c-|'); + const expected = '-----------------------------------|'; + + const result = e1.bufferToggle(e2, () => e3); + + expectObservable(result).toBe(expected); + }); + + it('should handle a never closing Observable', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e2 = cold( '---o---------------o-----------|'); + const e3 = cold('-'); + const expected = '-----------------------------------(xy|)'; + const values = { + x: ['b', 'c', 'd', 'e', 'f', 'g', 'h'], + y: ['f', 'g', 'h'] + }; + + const result = e1.bufferToggle(e2, () => e3); + + expectObservable(result).toBe(expected, values); + }); + + it('should handle opening Observable that just throws', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '(^!)'; + const e2 = cold( '#'); + const e2subs = '(^!)'; + const e3 = cold( '--c-|'); + const expected = '#'; + + const result = e1.bufferToggle(e2, () => e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/bufferWhen-spec.js b/spec/operators/bufferWhen-spec.js deleted file mode 100644 index 1b600afc6f..0000000000 --- a/spec/operators/bufferWhen-spec.js +++ /dev/null @@ -1,350 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.bufferWhen', function () { - it.asDiagram('bufferWhen')('should emit buffers that close and reopen', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---------|'); - var e2 = cold( '--------------(s|)'); - // --------------(s|) - var expected = '--------------x-------------y-----(z|)'; - var values = { - x: ['b','c','d'], - y: ['e','f','g'], - z: [] - }; - - expectObservable(e1.bufferWhen(function () { return e2; })).toBe(expected, values); - }); - - it('should emit buffers using varying cold closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '----------(s|) '), - cold( '-------------(s|)')]; - var expected = '---------------x---------y---------(z|) '; - var values = { - x: ['b','c','d'], - y: ['e','f','g'], - z: ['h'] - }; - - var i = 0; - var result = e1.bufferWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should emit buffers using varying hot closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var closings = [ - {obs: hot( '-1--^--------------s---| '), // eslint-disable-line key-spacing - sub: '^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '--1-^----3--------4----------s-| '), // eslint-disable-line key-spacing - sub: ' ^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '1-2-^------3----4-------5--6-----------s--|'), // eslint-disable-line key-spacing - sub: ' ^ ! '}]; // eslint-disable-line key-spacing - var expected = '---------------x---------y---------(z|)'; - var values = { - x: ['b','c','d'], - y: ['e','f','g'], - z: ['h'] - }; - - var i = 0; - var result = e1.bufferWhen(function () { return closings[i++].obs; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - for (var j = 0; j < closings.length; j++) { - expectSubscriptions(closings[j].obs.subscriptions).toBe(closings[j].sub); - } - }); - - it('should emit buffers using varying empty delayed closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------| '), - cold( '----------| '), - cold( '-------------|')]; - var closeSubs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '---------------x---------y---------(z|)'; - var values = { - x: ['b','c','d'], - y: ['e','f','g'], - z: ['h'] - }; - - var i = 0; - var result = e1.bufferWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); - }); - - it('should emit buffers using varying cold closings, outer unsubscribed early', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var unsub = ' ! '; - var subs = '^ ! '; - var closings = [ - cold( '---------------(s|) '), - cold( '----------(s|) '), - cold( '-------------(s|)')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = '---------------x--- '; - var values = { - x: ['b','c','d'] - }; - - var i = 0; - var result = e1.bufferWhen(function () { return closings[i++]; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(closings[2].subscriptions).toBe([]); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------(s|) '), - cold( '----------(s|) '), - cold( '-------------(s|)')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = '---------------x--- '; - var unsub = ' ! '; - var values = { - x: ['b','c','d'] - }; - - var i = 0; - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .bufferWhen(function () { return closings[i++]; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(closings[2].subscriptions).toBe([]); - }); - - it('should propagate error thrown from closingSelector', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '----------(s|) '), - cold( '-------------(s|)')]; - var closeSubs0 = '^ ! '; - var expected = '---------------(x#) '; - var values = { x: ['b','c','d'] }; - - var i = 0; - var result = e1.bufferWhen(function () { - if (i === 1) { - throw 'error'; - } - return closings[i++]; - }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs0); - }); - - it('should propagate error emitted from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '# ')]; - var closeSubs = ['^ ! ', - ' (^!) ']; - var expected = '---------------(x#) '; - var values = { x: ['b','c','d'] }; - - var i = 0; - var result = e1.bufferWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should propagate error emitted late from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var subs = '^ ! '; - var closings = [ - cold( '---------------s--| '), - cold( '------# ')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = '---------------x-----# '; - var values = { x: ['b','c','d'] }; - - var i = 0; - var result = e1.bufferWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should handle errors', function () { - var e1 = hot('--a--^---b---c---d---e---f---#'); - var e2 = cold( '---------------(s|)'); - // ---------------(s|) - var e2subs = ['^ ! ', - ' ^ !']; - var expected = '---------------x--------#'; - var values = { - x: ['b','c','d'] - }; - - var result = e1.bufferWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle empty', function () { - var e1 = cold('|'); - var e2 = cold('--------(s|)'); - var e1subs = '(^!)'; - var expected = '(x|)'; - var values = { - x: [] - }; - - var result = e1.bufferWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e2 = cold('--------(s|)'); - var e1subs = '(^!)'; - var expected = '#'; - var values = { - x: [] - }; - - var result = e1.bufferWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle never', function () { - var e1 = hot('-'); - var unsub = ' !'; - var e1subs = '^ !'; - var e2 = cold( '--------(s|) '); - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '--------x-------x-------x-------x-------x----'; - var values = { - x: [] - }; - - var source = e1.bufferWhen(function () { return e2; }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle an inner never', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e2 = cold('-'); - var expected = '-----------------------------------(x|)'; - var values = { - x: ['b','c','d','e','f','g','h'] - }; - - expectObservable(e1.bufferWhen(function () { return e2; })).toBe(expected, values); - }); - - // bufferWhen is not supposed to handle a factory that returns always empty - // closing Observables, because doing such would constantly recreate a new - // buffer in a synchronous infinite loop until the stack overflows. This also - // happens with buffer in RxJS 4. - it('should NOT handle hot inner empty', function (done) { - var source = Observable.of(1, 2, 3, 4, 5, 6, 7, 8, 9); - var closing = Observable.empty(); - var TOO_MANY_INVOCATIONS = 30; - - source - .bufferWhen(function () { return closing; }) - .takeWhile(function (val, index) { - return index < TOO_MANY_INVOCATIONS; - }) - .subscribe(function (val) { - expect(Array.isArray(val)).toBe(true); - expect(val.length).toBe(0); - }, function (err) { - done.fail('should not be called'); - }, done); - }); - - it('should handle inner throw', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '(^!)'; - var e2 = cold( '#'); - var e2subs = '(^!)'; - var expected = '#'; - var values = { - x: ['b','c','d','e','f','g','h'] - }; - - var result = e1.bufferWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle disposing of source', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var subs = '^ !'; - var unsub = ' !'; - var e2 = cold( '---------------(s|)'); - // ---------------(s|) - var expected = '---------------x-----'; - var values = { - x: ['b','c','d'], - y: ['e','f','g','h'], - z: [] - }; - - var source = e1.bufferWhen(function () { return e2; }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/bufferWhen-spec.ts b/spec/operators/bufferWhen-spec.ts new file mode 100644 index 0000000000..8d93c92f17 --- /dev/null +++ b/spec/operators/bufferWhen-spec.ts @@ -0,0 +1,350 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.bufferWhen', () => { + asDiagram('bufferWhen')('should emit buffers that close and reopen', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---------|'); + const e2 = cold( '--------------(s|)'); + // --------------(s|) + const expected = '--------------x-------------y-----(z|)'; + const values = { + x: ['b','c','d'], + y: ['e','f','g'], + z: [] + }; + + expectObservable(e1.bufferWhen(() => e2)).toBe(expected, values); + }); + + it('should emit buffers using constying cold closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '----------(s|) '), + cold( '-------------(s|)')]; + const expected = '---------------x---------y---------(z|) '; + const values = { + x: ['b','c','d'], + y: ['e','f','g'], + z: ['h'] + }; + + let i = 0; + const result = e1.bufferWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should emit buffers using constying hot closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const closings = [ + {obs: hot( '-1--^--------------s---| '), // eslint-disable-line key-spacing + sub: '^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '--1-^----3--------4----------s-| '), // eslint-disable-line key-spacing + sub: ' ^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '1-2-^------3----4-------5--6-----------s--|'), // eslint-disable-line key-spacing + sub: ' ^ ! '}]; // eslint-disable-line key-spacing + const expected = '---------------x---------y---------(z|)'; + const values = { + x: ['b','c','d'], + y: ['e','f','g'], + z: ['h'] + }; + + let i = 0; + const result = e1.bufferWhen(() => closings[i++].obs); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + for (let j = 0; j < closings.length; j++) { + expectSubscriptions(closings[j].obs.subscriptions).toBe(closings[j].sub); + } + }); + + it('should emit buffers using constying empty delayed closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------| '), + cold( '----------| '), + cold( '-------------|')]; + const closeSubs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '---------------x---------y---------(z|)'; + const values = { + x: ['b','c','d'], + y: ['e','f','g'], + z: ['h'] + }; + + let i = 0; + const result = e1.bufferWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); + }); + + it('should emit buffers using constying cold closings, outer unsubscribed early', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const unsub = ' ! '; + const subs = '^ ! '; + const closings = [ + cold( '---------------(s|) '), + cold( '----------(s|) '), + cold( '-------------(s|)')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = '---------------x--- '; + const values = { + x: ['b','c','d'] + }; + + let i = 0; + const result = e1.bufferWhen(() => closings[i++]); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(closings[2].subscriptions).toBe([]); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------(s|) '), + cold( '----------(s|) '), + cold( '-------------(s|)')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = '---------------x--- '; + const unsub = ' ! '; + const values = { + x: ['b','c','d'] + }; + + let i = 0; + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .bufferWhen(() => closings[i++]) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(closings[2].subscriptions).toBe([]); + }); + + it('should propagate error thrown from closingSelector', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '----------(s|) '), + cold( '-------------(s|)')]; + const closeSubs0 = '^ ! '; + const expected = '---------------(x#) '; + const values = { x: ['b','c','d'] }; + + let i = 0; + const result = e1.bufferWhen(() => { + if (i === 1) { + throw 'error'; + } + return closings[i++]; + }); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs0); + }); + + it('should propagate error emitted from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '# ')]; + const closeSubs = ['^ ! ', + ' (^!) ']; + const expected = '---------------(x#) '; + const values = { x: ['b','c','d'] }; + + let i = 0; + const result = e1.bufferWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should propagate error emitted late from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const subs = '^ ! '; + const closings = [ + cold( '---------------s--| '), + cold( '------# ')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = '---------------x-----# '; + const values = { x: ['b','c','d'] }; + + let i = 0; + const result = e1.bufferWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should handle errors', () => { + const e1 = hot('--a--^---b---c---d---e---f---#'); + const e2 = cold( '---------------(s|)'); + // ---------------(s|) + const e2subs = ['^ ! ', + ' ^ !']; + const expected = '---------------x--------#'; + const values = { + x: ['b','c','d'] + }; + + const result = e1.bufferWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle empty', () => { + const e1 = cold('|'); + const e2 = cold('--------(s|)'); + const e1subs = '(^!)'; + const expected = '(x|)'; + const values = { + x: [] + }; + + const result = e1.bufferWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e2 = cold('--------(s|)'); + const e1subs = '(^!)'; + const expected = '#'; + const values = { + x: [] + }; + + const result = e1.bufferWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle never', () => { + const e1 = hot('-'); + const unsub = ' !'; + const e1subs = '^ !'; + const e2 = cold( '--------(s|) '); + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '--------x-------x-------x-------x-------x----'; + const values = { + x: [] + }; + + const source = e1.bufferWhen(() => e2); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle an inner never', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e2 = cold('-'); + const expected = '-----------------------------------(x|)'; + const values = { + x: ['b','c','d','e','f','g','h'] + }; + + expectObservable(e1.bufferWhen(() => e2)).toBe(expected, values); + }); + + // bufferWhen is not supposed to handle a factory that returns always empty + // closing Observables, because doing such would constantly recreate a new + // buffer in a synchronous infinite loop until the stack overflows. This also + // happens with buffer in RxJS 4. + it('should NOT handle hot inner empty', (done: DoneSignature) => { + const source = Observable.of(1, 2, 3, 4, 5, 6, 7, 8, 9); + const closing = Observable.empty(); + const TOO_MANY_INVOCATIONS = 30; + + source + .bufferWhen(() => closing) + .takeWhile((val: any, index: number) => index < TOO_MANY_INVOCATIONS) + .subscribe((val: any) => { + expect(Array.isArray(val)).toBe(true); + expect(val.length).toBe(0); + }, (err: any) => { + done.fail('should not be called'); + }, done); + }); + + it('should handle inner throw', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '(^!)'; + const e2 = cold( '#'); + const e2subs = '(^!)'; + const expected = '#'; + const values = { + x: ['b','c','d','e','f','g','h'] + }; + + const result = e1.bufferWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle disposing of source', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const subs = '^ !'; + const unsub = ' !'; + const e2 = cold( '---------------(s|)'); + // ---------------(s|) + const expected = '---------------x-----'; + const values = { + x: ['b','c','d'], + y: ['e','f','g','h'], + z: [] + }; + + const source = e1.bufferWhen(() => e2); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/cache-spec.js b/spec/operators/cache-spec.js deleted file mode 100644 index d464ee9f64..0000000000 --- a/spec/operators/cache-spec.js +++ /dev/null @@ -1,182 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot, rxTestScheduler, time */ -var Rx = require('../../dist/cjs/Rx'); - -var asap = Rx.Scheduler.asap; -var Observable = Rx.Observable; - -describe('Observable.prototype.cache', function () { - it('should replay values upon subscription', function () { - var s1 = hot('---^---a---b---c---| ').cache(); - var expected1 = '----a---b---c---| '; - var expected2 = ' (abc|)'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should replay values and error', function () { - var s1 = hot('---^---a---b---c---# ').cache(); - var expected1 = '----a---b---c---# '; - var expected2 = ' (abc#)'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should replay values and and share', function () { - var s1 = hot('---^---a---b---c------------d--e--f-|').cache(); - var expected1 = '----a---b---c------------d--e--f-|'; - var expected2 = ' (abc)----d--e--f-|'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should have a bufferCount that limits the replay test 1', function () { - var s1 = hot('---^---a---b---c------------d--e--f-|').cache(1); - var expected1 = '----a---b---c------------d--e--f-|'; - var expected2 = ' c--------d--e--f-|'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should have a bufferCount that limits the replay test 2', function () { - var s1 = hot('---^---a---b---c------------d--e--f-|').cache(2); - var expected1 = '----a---b---c------------d--e--f-|'; - var expected2 = ' (bc)-----d--e--f-|'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should accept a windowTime that limits the replay', function () { - var w = time( '----------|'); - var s1 = hot('---^---a---b---c------------d--e--f-|').cache(Number.POSITIVE_INFINITY, w, rxTestScheduler); - var expected1 = '----a---b---c------------d--e--f-|'; - var expected2 = ' (bc)-----d--e--f-|'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should handle empty', function () { - var s1 = cold('|').cache(); - var expected1 = '|'; - var expected2 = ' |'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should handle throw', function () { - var s1 = cold('#').cache(); - var expected1 = '#'; - var expected2 = ' #'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should handle never', function () { - var s1 = cold('-').cache(); - var expected1 = '-'; - var expected2 = ' -'; - var t = time( '----------------|'); - - expectObservable(s1).toBe(expected1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected2); - }, t); - }); - - it('should multicast a completion', function () { - var s1 = hot('--a--^--b------c-----d------e-|').cache(); - var t1 = time( '| '); - var e1 = '---b------c-----d------e-|'; - var t2 = time( '----------| '); - var e2 = ' (bc)--d------e-|'; - var t3 = time( '----------------| '); - var e3 = ' (bcd)--e-|'; - - var expected = [e1, e2, e3]; - - [t1, t2, t3].forEach(function (t, i) { - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected[i]); - }, t); - }); - }); - - it('should multicast an error', function () { - var s1 = hot('--a--^--b------c-----d------e-#').cache(); - var t1 = time( '| '); - var e1 = '---b------c-----d------e-#'; - var t2 = time( '----------| '); - var e2 = ' (bc)--d------e-#'; - var t3 = time( '----------------| '); - var e3 = ' (bcd)--e-#'; - - var expected = [e1, e2, e3]; - - [t1, t2, t3].forEach(function (t, i) { - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(expected[i]); - }, t); - }); - }); - - it('should limit replay by both count and a window time, test 2', function () { - var w = time( '-----------|'); - var s1 = hot('--a--^---b---c----d----e------f--g--h--i-------|').cache(4, w, rxTestScheduler); - var e1 = '----b---c----d----e------f--g--h--i-------|'; - var t1 = time( '--------------------|'); - // -----------| - var e2 = ' (de)-f--g--h--i-------|'; // time wins - var t2 = time( '-----------------------------------|'); - var e3 = ' (fghi)-|'; // count wins - // -----------| - - expectObservable(s1).toBe(e1); - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(e2); - }, t1); - - rxTestScheduler.schedule(function () { - expectObservable(s1).toBe(e3); - }, t2); - }); -}); \ No newline at end of file diff --git a/spec/operators/cache-spec.ts b/spec/operators/cache-spec.ts new file mode 100644 index 0000000000..8ad316e014 --- /dev/null +++ b/spec/operators/cache-spec.ts @@ -0,0 +1,184 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; +const asap = Rx.Scheduler.asap; + +describe('Observable.prototype.cache', () => { + it('should replay values upon subscription', () => { + const s1 = hot('---^---a---b---c---| ').cache(); + const expected1 = '----a---b---c---| '; + const expected2 = ' (abc|)'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should replay values and error', () => { + const s1 = hot('---^---a---b---c---# ').cache(); + const expected1 = '----a---b---c---# '; + const expected2 = ' (abc#)'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should replay values and and share', () => { + const s1 = hot('---^---a---b---c------------d--e--f-|').cache(); + const expected1 = '----a---b---c------------d--e--f-|'; + const expected2 = ' (abc)----d--e--f-|'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should have a bufferCount that limits the replay test 1', () => { + const s1 = hot('---^---a---b---c------------d--e--f-|').cache(1); + const expected1 = '----a---b---c------------d--e--f-|'; + const expected2 = ' c--------d--e--f-|'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should have a bufferCount that limits the replay test 2', () => { + const s1 = hot('---^---a---b---c------------d--e--f-|').cache(2); + const expected1 = '----a---b---c------------d--e--f-|'; + const expected2 = ' (bc)-----d--e--f-|'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should accept a windowTime that limits the replay', () => { + const w = time( '----------|'); + const s1 = hot('---^---a---b---c------------d--e--f-|').cache(Number.POSITIVE_INFINITY, w, rxTestScheduler); + const expected1 = '----a---b---c------------d--e--f-|'; + const expected2 = ' (bc)-----d--e--f-|'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should handle empty', () => { + const s1 = cold('|').cache(); + const expected1 = '|'; + const expected2 = ' |'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should handle throw', () => { + const s1 = cold('#').cache(); + const expected1 = '#'; + const expected2 = ' #'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should handle never', () => { + const s1 = cold('-').cache(); + const expected1 = '-'; + const expected2 = ' -'; + const t = time( '----------------|'); + + expectObservable(s1).toBe(expected1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected2); + }, t); + }); + + it('should multicast a completion', () => { + const s1 = hot('--a--^--b------c-----d------e-|').cache(); + const t1 = time( '| '); + const e1 = '---b------c-----d------e-|'; + const t2 = time( '----------| '); + const e2 = ' (bc)--d------e-|'; + const t3 = time( '----------------| '); + const e3 = ' (bcd)--e-|'; + + const expected = [e1, e2, e3]; + + [t1, t2, t3].forEach((t: any, i: number) => { + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected[i]); + }, t); + }); + }); + + it('should multicast an error', () => { + const s1 = hot('--a--^--b------c-----d------e-#').cache(); + const t1 = time( '| '); + const e1 = '---b------c-----d------e-#'; + const t2 = time( '----------| '); + const e2 = ' (bc)--d------e-#'; + const t3 = time( '----------------| '); + const e3 = ' (bcd)--e-#'; + + const expected = [e1, e2, e3]; + + [t1, t2, t3].forEach((t: any, i: number) => { + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(expected[i]); + }, t); + }); + }); + + it('should limit replay by both count and a window time, test 2', () => { + const w = time( '-----------|'); + const s1 = hot('--a--^---b---c----d----e------f--g--h--i-------|').cache(4, w, rxTestScheduler); + const e1 = '----b---c----d----e------f--g--h--i-------|'; + const t1 = time( '--------------------|'); + // -----------| + const e2 = ' (de)-f--g--h--i-------|'; // time wins + const t2 = time( '-----------------------------------|'); + const e3 = ' (fghi)-|'; // count wins + // -----------| + + expectObservable(s1).toBe(e1); + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(e2); + }, t1); + + rxTestScheduler.schedule(() => { + expectObservable(s1).toBe(e3); + }, t2); + }); +}); \ No newline at end of file diff --git a/spec/operators/catch-spec.js b/spec/operators/catch-spec.js deleted file mode 100644 index a7d819a572..0000000000 --- a/spec/operators/catch-spec.js +++ /dev/null @@ -1,228 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.catch()', function () { - it.asDiagram('catch')('should catch error and replace with a cold Observable', function () { - var e1 = hot('--a--b--# '); - var e2 = cold('-1-2-3-| '); - var expected = '--a--b---1-2-3-|)'; - - var result = e1.catch(function (err) { return e2; }); - - expectObservable(result).toBe(expected); - }); - - it('should catch error and replace it with Observable.of()', function () { - var e1 = hot('--a--b--c--------|'); - var subs = '^ !'; - var expected = '--a--b--(XYZ|)'; - - var result = e1 - .map(function (n) { - if (n === 'c') { - throw 'bad'; - } - return n; - }) - .catch(function (err) { - return Observable.of('X', 'Y', 'Z'); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should catch error and replace it with a cold Observable', function () { - var e1 = hot('--a--b--# '); - var e1subs = '^ ! '; - var e2 = cold( '1-2-3-4-5-|'); - var e2subs = ' ^ !'; - var expected = '--a--b--1-2-3-4-5-|'; - - var result = e1.catch(function (err) { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--1-2-3-4-5-6---#'); - var e1subs = '^ ! '; - var expected = '--1-2-3- '; - var unsub = ' ! '; - - var result = e1.catch(function () { - return Observable.of('X', 'Y', 'Z'); - }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('--1-2-3-4-5-6---#'); - var e1subs = '^ ! '; - var expected = '--1-2-3- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .catch(function () { - return Observable.of('X', 'Y', 'Z'); - }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should catch error and replace it with a hot Observable', function () { - var e1 = hot('--a--b--# '); - var e1subs = '^ ! '; - var e2 = hot('1-2-3-4-5-6-7-8-9-|'); - var e2subs = ' ^ !'; - var expected = '--a--b--5-6-7-8-9-|'; - - var result = e1.catch(function (err) { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should catch and allow the cold observable to be repeated with the third ' + - '(caught) argument', function () { - var e1 = cold('--a--b--c--------| '); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '--a--b----a--b----a--b--#'; - - var retries = 0; - var result = e1 - .map(function (n) { - if (n === 'c') { - throw 'bad'; - } - return n; - }) - .catch(function (err, caught) { - if (retries++ === 2) { - throw 'done'; - } - return caught; - }); - - expectObservable(result).toBe(expected, undefined, 'done'); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should catch and allow the hot observable to proceed with the third ' + - '(caught) argument', function () { - var e1 = hot('--a--b--c----d---|'); - var subs = ['^ ! ', - ' ^ !']; - var expected = '--a--b-------d---|'; - - var retries = 0; - var result = e1 - .map(function (n) { - if (n === 'c') { - throw 'bad'; - } - return n; - }) - .catch(function (err, caught) { - if (retries++ === 2) { - throw 'done'; - } - return caught; - }); - - expectObservable(result).toBe(expected, undefined, 'done'); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should catch and replace a Observable.throw() as the source', function () { - var e1 = cold('#'); - var subs = '(^!)'; - var expected = '(abc|)'; - - var result = e1.catch(function (err) { - return Observable.of('a', 'b', 'c'); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should mirror the source if it does not raise errors', function () { - var e1 = cold('--a--b--c--|'); - var subs = '^ !'; - var expected = '--a--b--c--|'; - - var result = e1.catch(function (err) { - return Observable.of('x', 'y', 'z'); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should complete if you return Observable.empty()', function () { - var e1 = hot('--a--b--#'); - var e1subs = '^ !'; - var e2 = cold( '|'); - var e2subs = ' (^!)'; - var expected = '--a--b--|'; - - var result = e1.catch(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error if you return Observable.throw()', function () { - var e1 = hot('--a--b--#'); - var e1subs = '^ !'; - var e2 = cold( '#'); - var e2subs = ' (^!)'; - var expected = '--a--b--#'; - - var result = e1.catch(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should never terminate if you return Observable.never()', function () { - var e1 = hot('--a--b--#'); - var e1subs = '^ !'; - var e2 = cold( '-'); - var e2subs = ' ^'; - var expected = '--a--b---'; - - var result = e1.catch(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should pass the error as the first argument', function (done) { - Observable.throw('bad') - .catch(function (err) { - expect(err).toBe('bad'); - return Observable.empty(); - }) - .subscribe(function () { }, - function (err) { - done.fail('should not be called'); - }, - done); - }); -}); diff --git a/spec/operators/catch-spec.ts b/spec/operators/catch-spec.ts new file mode 100644 index 0000000000..4a31278737 --- /dev/null +++ b/spec/operators/catch-spec.ts @@ -0,0 +1,227 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram, DoneSignature} from '../helpers/test-helper'; + +declare const rxTestSchdeuler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.catch()', () => { + asDiagram('catch')('should catch error and replace with a cold Observable', () => { + const e1 = hot('--a--b--# '); + const e2 = cold('-1-2-3-| '); + const expected = '--a--b---1-2-3-|)'; + + const result = e1.catch((err: any) => e2); + + expectObservable(result).toBe(expected); + }); + + it('should catch error and replace it with Observable.of()', () => { + const e1 = hot('--a--b--c--------|'); + const subs = '^ !'; + const expected = '--a--b--(XYZ|)'; + + const result = e1 + .map((n: string) => { + if (n === 'c') { + throw 'bad'; + } + return n; + }) + .catch((err: any) => { + return Observable.of('X', 'Y', 'Z'); + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should catch error and replace it with a cold Observable', () => { + const e1 = hot('--a--b--# '); + const e1subs = '^ ! '; + const e2 = cold( '1-2-3-4-5-|'); + const e2subs = ' ^ !'; + const expected = '--a--b--1-2-3-4-5-|'; + + const result = e1.catch((err: any) => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--1-2-3-4-5-6---#'); + const e1subs = '^ ! '; + const expected = '--1-2-3- '; + const unsub = ' ! '; + + const result = e1.catch(() => { + return Observable.of('X', 'Y', 'Z'); + }); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('--1-2-3-4-5-6---#'); + const e1subs = '^ ! '; + const expected = '--1-2-3- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .catch(() => { + return Observable.of('X', 'Y', 'Z'); + }) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should catch error and replace it with a hot Observable', () => { + const e1 = hot('--a--b--# '); + const e1subs = '^ ! '; + const e2 = hot('1-2-3-4-5-6-7-8-9-|'); + const e2subs = ' ^ !'; + const expected = '--a--b--5-6-7-8-9-|'; + + const result = e1.catch((err: any) => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should catch and allow the cold observable to be repeated with the third ' + + '(caught) argument', () => { + const e1 = cold('--a--b--c--------| '); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '--a--b----a--b----a--b--#'; + + let retries = 0; + const result = e1 + .map((n: any) => { + if (n === 'c') { + throw 'bad'; + } + return n; + }) + .catch((err: any, caught: any) => { + if (retries++ === 2) { + throw 'done'; + } + return caught; + }); + + expectObservable(result).toBe(expected, undefined, 'done'); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should catch and allow the hot observable to proceed with the third ' + + '(caught) argument', () => { + const e1 = hot('--a--b--c----d---|'); + const subs = ['^ ! ', + ' ^ !']; + const expected = '--a--b-------d---|'; + + let retries = 0; + const result = e1 + .map((n: any) => { + if (n === 'c') { + throw 'bad'; + } + return n; + }) + .catch((err: any, caught: any) => { + if (retries++ === 2) { + throw 'done'; + } + return caught; + }); + + expectObservable(result).toBe(expected, undefined, 'done'); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should catch and replace a Observable.throw() as the source', () => { + const e1 = cold('#'); + const subs = '(^!)'; + const expected = '(abc|)'; + + const result = e1.catch((err: any) => Observable.of('a', 'b', 'c')); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should mirror the source if it does not raise errors', () => { + const e1 = cold('--a--b--c--|'); + const subs = '^ !'; + const expected = '--a--b--c--|'; + + const result = e1.catch((err: any) => Observable.of('x', 'y', 'z')); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should complete if you return Observable.empty()', () => { + const e1 = hot('--a--b--#'); + const e1subs = '^ !'; + const e2 = cold( '|'); + const e2subs = ' (^!)'; + const expected = '--a--b--|'; + + const result = e1.catch(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error if you return Observable.throw()', () => { + const e1 = hot('--a--b--#'); + const e1subs = '^ !'; + const e2 = cold( '#'); + const e2subs = ' (^!)'; + const expected = '--a--b--#'; + + const result = e1.catch(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should never terminate if you return Observable.never()', () => { + const e1 = hot('--a--b--#'); + const e1subs = '^ !'; + const e2 = cold( '-'); + const e2subs = ' ^'; + const expected = '--a--b---'; + + const result = e1.catch(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should pass the error as the first argument', (done: DoneSignature) => { + Observable.throw('bad') + .catch((err: any) => { + expect(err).toBe('bad'); + return Observable.empty(); + }) + .subscribe(() => { }, + (err: any) => { + done.fail('should not be called'); + }, + done); + }); +}); diff --git a/spec/operators/combineAll-spec.js b/spec/operators/combineAll-spec.js deleted file mode 100644 index c2b719085c..0000000000 --- a/spec/operators/combineAll-spec.js +++ /dev/null @@ -1,472 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.combineAll()', function () { - it.asDiagram('combineAll')('should combine events from two observables', function () { - var x = cold( '-a-----b---|'); - var y = cold( '--1-2-| '); - var outer = hot('-x----y--------| ', { x: x, y: y }); - var expected = '-----------------A-B--C---|'; - - var result = outer.combineAll(function (a, b) { return String(a) + String(b); }); - - expectObservable(result).toBe(expected, { A: 'a1', B: 'a2', C: 'b2' }); - }); - - it('should work with two nevers', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var e2 = cold( '-'); - var e2subs = '^'; - var expected = '-'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and empty', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var e2 = cold( '|'); - var e2subs = '(^!)'; - var expected = '-'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and never', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var e2 = cold( '-'); - var e2subs = '^'; - var expected = '-'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - var expected = '|'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-empty and hot-single', function () { - var e1 = hot('-a-^-|'); - var e1subs = '^ !'; - var e2 = hot('-b-^-c-|'); - var e2subs = '^ !'; - var expected = '----|'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-single and hot-empty', function () { - var e1 = hot('-a-^-|'); - var e1subs = '^ !'; - var e2 = hot('-b-^-c-|'); - var e2subs = '^ !'; - var expected = '----|'; - - var result = Observable.of(e2, e1).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-single and never', function () { - var e1 = hot('-a-^-|'); - var e1subs = '^ !'; - var e2 = hot('------'); //never - var e2subs = '^ '; - var expected = '-'; //never - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and hot-single', function () { - var e1 = hot('--------'); //never - var e1subs = '^ '; - var e2 = hot('-a-^-b-|'); - var e2subs = '^ !'; - var expected = '-----'; //never - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot and hot', function () { - var e1 = hot('--a--^--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('---e-^---f--g--|'); - var e2subs = '^ !'; - var expected = '----x-yz--|'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'bf', y: 'cf', z: 'cg' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '----x-yz-- '; - var unsub = ' ! '; - var values = { x: 'bf', y: 'cf', z: 'cg' }; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '----x-yz-- '; - var unsub = ' ! '; - var values = { x: 'bf', y: 'cf', z: 'cg' }; - - var result = Observable.of(e1, e2) - .mergeMap(function (x) { return Observable.of(x); }) - .combineAll(function (x, y) { return x + y; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should combine 3 observables', function () { - var e1 = hot('--a--^--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('---e-^---f--g--|'); - var e2subs = '^ !'; - var e3 = hot('---h-^----i--j-|'); - var e3subs = '^ !'; - var expected = '-----wxyz-|'; - - var result = Observable.of(e1, e2, e3).combineAll(function (x, y, z) { return x + y + z; }); - - expectObservable(result).toBe(expected, { w: 'bfi', x: 'cfi', y: 'cgi', z: 'cgj' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should work with empty and error', function () { - var e1 = hot('----------|'); //empty - var e1subs = '^ !'; - var e2 = hot('------#', undefined, 'shazbot!'); //error - var e2subs = '^ !'; - var expected = '------#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'shazbot!'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with error and empty', function () { - var e1 = hot('--^---#', undefined, 'too bad, honk'); //error - var e1subs = '^ !'; - var e2 = hot('--^--------|'); //empty - var e2subs = '^ !'; - var expected = '----#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'too bad, honk'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot and throw', function () { - var e1 = hot('-a-^--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('---^-#', undefined, 'bazinga'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and hot', function () { - var e1 = hot('---^-#', undefined, 'bazinga'); - var e1subs = '^ !'; - var e2 = hot('-a-^--b--c--|'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and throw', function () { - var e1 = hot('---^----#', undefined, 'jenga'); - var e1subs = '^ !'; - var e2 = hot('---^-#', undefined, 'bazinga'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with error and throw', function () { - var e1 = hot('-a-^--b--#', undefined, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^-#', undefined, 'flurp'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'flurp'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and error', function () { - var e1 = hot('---^-#', undefined, 'flurp'); - var e1subs = '^ !'; - var e2 = hot('-a-^--b--#', undefined, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'flurp'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and throw', function () { - var e1 = hot('---^-----------'); - var e1subs = '^ !'; - var e2 = hot('---^-----#', undefined, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '------#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and never', function () { - var e1 = hot('---^----#', undefined, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^-----------'); - var e2subs = '^ !'; - var expected = '-----#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with some and throw', function () { - var e1 = hot('---^----a---b--|'); - var e1subs = '^ !'; - var e2 = hot('---^--#', undefined, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and some', function () { - var e1 = hot('---^--#', undefined, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^----a---b--|'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle throw after complete left', function () { - var left = hot('--a--^--b---|'); - var leftSubs = '^ !'; - var right = hot('-----^--------#', undefined, 'bad things'); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = Observable.of(left, right).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bad things'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle throw after complete right', function () { - var left = hot('-----^--------#', undefined, 'bad things'); - var leftSubs = '^ !'; - var right = hot('--a--^--b---|'); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = Observable.of(left, right).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bad things'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle interleaved with tail', function () { - var e1 = hot('-a--^--b---c---|'); - var e1subs = '^ !'; - var e2 = hot('--d-^----e---f--|'); - var e2subs = '^ !'; - var expected = '-----x-y-z--|'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'be', y: 'ce', z: 'cf' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle two consecutive hot observables', function () { - var e1 = hot('--a--^--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('-----^----------d--e--f--|'); - var e2subs = '^ !'; - var expected = '-----------x--y--z--|'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle two consecutive hot observables with error left', function () { - var left = hot('--a--^--b--c--#', undefined, 'jenga'); - var leftSubs = '^ !'; - var right = hot('-----^----------d--e--f--|'); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = Observable.of(left, right).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'jenga'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle two consecutive hot observables with error right', function () { - var left = hot('--a--^--b--c--|'); - var leftSubs = '^ !'; - var right = hot('-----^----------d--e--f--#', undefined, 'dun dun dun'); - var rightSubs = '^ !'; - var expected = '-----------x--y--z--#'; - - var result = Observable.of(left, right).combineAll(function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }, 'dun dun dun'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle selector throwing', function () { - var e1 = hot('--a--^--b--|'); - var e1subs = '^ !'; - var e2 = hot('--c--^--d--|'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = Observable.of(e1, e2).combineAll(function (x, y) { throw 'ha ha ' + x + ', ' + y; }); - - expectObservable(result).toBe(expected, null, 'ha ha b, d'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should combine two observables', function (done) { - var a = Observable.of(1, 2, 3); - var b = Observable.of(4, 5, 6, 7, 8); - var expected = [[3, 4], [3, 5], [3, 6], [3, 7], [3, 8]]; - Observable.of(a, b).combineAll().subscribe(function (vals) { - expect(vals).toEqual(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - done(); - }); - }); - - it('should combine two immediately-scheduled observables', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [[1, 4], [2, 4], [2, 5], [3, 5], [3, 6], [3, 7], [3, 8]]; - var i = 0; - Observable.of(a, b, queueScheduler).combineAll().subscribe(function (vals) { - expect(vals).toDeepEqual(r[i++]); - }, null, function () { - expect(i).toEqual(r.length); - done(); - }); - }); -}); \ No newline at end of file diff --git a/spec/operators/combineAll-spec.ts b/spec/operators/combineAll-spec.ts new file mode 100644 index 0000000000..d3cce70b4f --- /dev/null +++ b/spec/operators/combineAll-spec.ts @@ -0,0 +1,475 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.combineAll()', () => { + asDiagram('combineAll')('should combine events from two observables', () => { + const x = cold( '-a-----b---|'); + const y = cold( '--1-2-| '); + const outer = hot('-x----y--------| ', { x: x, y: y }); + const expected = '-----------------A-B--C---|'; + + const result = outer.combineAll((a: any, b: any) => String(a) + String(b)); + + expectObservable(result).toBe(expected, { A: 'a1', B: 'a2', C: 'b2' }); + }); + + it('should work with two nevers', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const e2 = cold( '-'); + const e2subs = '^'; + const expected = '-'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and empty', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const e2 = cold( '|'); + const e2subs = '(^!)'; + const expected = '-'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and never', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const e2 = cold( '-'); + const e2subs = '^'; + const expected = '-'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + const expected = '|'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-empty and hot-single', () => { + const e1 = hot('-a-^-|'); + const e1subs = '^ !'; + const e2 = hot('-b-^-c-|'); + const e2subs = '^ !'; + const expected = '----|'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-single and hot-empty', () => { + const e1 = hot('-a-^-|'); + const e1subs = '^ !'; + const e2 = hot('-b-^-c-|'); + const e2subs = '^ !'; + const expected = '----|'; + + const result = Observable.of(e2, e1).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-single and never', () => { + const e1 = hot('-a-^-|'); + const e1subs = '^ !'; + const e2 = hot('------'); //never + const e2subs = '^ '; + const expected = '-'; //never + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and hot-single', () => { + const e1 = hot('--------'); //never + const e1subs = '^ '; + const e2 = hot('-a-^-b-|'); + const e2subs = '^ !'; + const expected = '-----'; //never + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot and hot', () => { + const e1 = hot('--a--^--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('---e-^---f--g--|'); + const e2subs = '^ !'; + const expected = '----x-yz--|'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'bf', y: 'cf', z: 'cg' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '----x-yz-- '; + const unsub = ' ! '; + const values = { x: 'bf', y: 'cf', z: 'cg' }; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '----x-yz-- '; + const unsub = ' ! '; + const values = { x: 'bf', y: 'cf', z: 'cg' }; + + const result = Observable.of(e1, e2) + .mergeMap((x: any) => Observable.of(x)) + .combineAll((x: any, y: any) => x + y) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should combine 3 observables', () => { + const e1 = hot('--a--^--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('---e-^---f--g--|'); + const e2subs = '^ !'; + const e3 = hot('---h-^----i--j-|'); + const e3subs = '^ !'; + const expected = '-----wxyz-|'; + + const result = Observable.of(e1, e2, e3).combineAll(((x: string, y: string, z: string) => x + y + z)); + + expectObservable(result).toBe(expected, { w: 'bfi', x: 'cfi', y: 'cgi', z: 'cgj' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should work with empty and error', () => { + const e1 = hot('----------|'); //empty + const e1subs = '^ !'; + const e2 = hot('------#', undefined, 'shazbot!'); //error + const e2subs = '^ !'; + const expected = '------#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'shazbot!'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with error and empty', () => { + const e1 = hot('--^---#', undefined, 'too bad, honk'); //error + const e1subs = '^ !'; + const e2 = hot('--^--------|'); //empty + const e2subs = '^ !'; + const expected = '----#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'too bad, honk'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot and throw', () => { + const e1 = hot('-a-^--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('---^-#', undefined, 'bazinga'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and hot', () => { + const e1 = hot('---^-#', undefined, 'bazinga'); + const e1subs = '^ !'; + const e2 = hot('-a-^--b--c--|'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and throw', () => { + const e1 = hot('---^----#', undefined, 'jenga'); + const e1subs = '^ !'; + const e2 = hot('---^-#', undefined, 'bazinga'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with error and throw', () => { + const e1 = hot('-a-^--b--#', undefined, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^-#', undefined, 'flurp'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'flurp'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and error', () => { + const e1 = hot('---^-#', undefined, 'flurp'); + const e1subs = '^ !'; + const e2 = hot('-a-^--b--#', undefined, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'flurp'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and throw', () => { + const e1 = hot('---^-----------'); + const e1subs = '^ !'; + const e2 = hot('---^-----#', undefined, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '------#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and never', () => { + const e1 = hot('---^----#', undefined, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^-----------'); + const e2subs = '^ !'; + const expected = '-----#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with some and throw', () => { + const e1 = hot('---^----a---b--|'); + const e1subs = '^ !'; + const e2 = hot('---^--#', undefined, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and some', () => { + const e1 = hot('---^--#', undefined, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^----a---b--|'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle throw after complete left', () => { + const left = hot('--a--^--b---|'); + const leftSubs = '^ !'; + const right = hot('-----^--------#', undefined, 'bad things'); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = Observable.of(left, right).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bad things'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle throw after complete right', () => { + const left = hot('-----^--------#', undefined, 'bad things'); + const leftSubs = '^ !'; + const right = hot('--a--^--b---|'); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = Observable.of(left, right).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bad things'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle interleaved with tail', () => { + const e1 = hot('-a--^--b---c---|'); + const e1subs = '^ !'; + const e2 = hot('--d-^----e---f--|'); + const e2subs = '^ !'; + const expected = '-----x-y-z--|'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'be', y: 'ce', z: 'cf' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle two consecutive hot observables', () => { + const e1 = hot('--a--^--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('-----^----------d--e--f--|'); + const e2subs = '^ !'; + const expected = '-----------x--y--z--|'; + + const result = Observable.of(e1, e2).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle two consecutive hot observables with error left', () => { + const left = hot('--a--^--b--c--#', undefined, 'jenga'); + const leftSubs = '^ !'; + const right = hot('-----^----------d--e--f--|'); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = Observable.of(left, right).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'jenga'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle two consecutive hot observables with error right', () => { + const left = hot('--a--^--b--c--|'); + const leftSubs = '^ !'; + const right = hot('-----^----------d--e--f--#', undefined, 'dun dun dun'); + const rightSubs = '^ !'; + const expected = '-----------x--y--z--#'; + + const result = Observable.of(left, right).combineAll((x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }, 'dun dun dun'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle selector throwing', () => { + const e1 = hot('--a--^--b--|'); + const e1subs = '^ !'; + const e2 = hot('--c--^--d--|'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = Observable.of(e1, e2).combineAll(((x: string, y: string) => { throw 'ha ha ' + x + ', ' + y; })); + + expectObservable(result).toBe(expected, null, 'ha ha b, d'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should combine two observables', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3); + const b = Observable.of(4, 5, 6, 7, 8); + const expected = [[3, 4], [3, 5], [3, 6], [3, 7], [3, 8]]; + Observable.of(a, b).combineAll().subscribe((vals: any) => { + expect(vals).toEqual(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + done(); + }); + }); + + it('should combine two immediately-scheduled observables', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [[1, 4], [2, 4], [2, 5], [3, 5], [3, 6], [3, 7], [3, 8]]; + + Observable.of>(a, b, queueScheduler).combineAll() + .subscribe((vals: any) => { + (expect(vals)).toDeepEqual(r.shift()); + }, null, () => { + expect(r.length).toEqual(0); + done(); + }); + }); +}); \ No newline at end of file diff --git a/spec/operators/combineLatest-spec.js b/spec/operators/combineLatest-spec.js deleted file mode 100644 index 7ec776d31e..0000000000 --- a/spec/operators/combineLatest-spec.js +++ /dev/null @@ -1,463 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.combineLatest', function () { - it.asDiagram('combineLatest')('should combine events from two cold observables', function () { - var e1 = hot('-a--b-----c-d-e-|'); - var e2 = hot('--1--2-3-4---| '); - var expected = '--A-BC-D-EF-G-H-|'; - - var result = e1.combineLatest(e2, function (a, b) { return String(a) + String(b); }); - - expectObservable(result).toBe(expected, { - A: 'a1', B: 'b1', C: 'b2', D: 'b3', E: 'b4', F: 'c4', G: 'd4', H: 'e4' - }); - }); - - it('should work with two nevers', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var e2 = cold( '-'); - var e2subs = '^'; - var expected = '-'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and empty', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var e2 = cold( '|'); - var e2subs = '(^!)'; - var expected = '-'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and never', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var e2 = cold( '-'); - var e2subs = '^'; - var expected = '-'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with empty and empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - var expected = '|'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-empty and hot-single', function () { - var values = { - a: 1, - b: 2, - c: 3, - r: 1 + 3 //a + c - }; - var e1 = hot('-a-^-|', values); - var e1subs = '^ !'; - var e2 = hot('-b-^-c-|', values); - var e2subs = '^ !'; - var expected = '----|'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-single and hot-empty', function () { - var values = { - a: 1, b: 2, c: 3 - }; - var e1 = hot('-a-^-|', values); - var e1subs = '^ !'; - var e2 = hot('-b-^-c-|', values); - var e2subs = '^ !'; - var expected = '----|'; - - var result = e2.combineLatest(e1, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot-single and never', function () { - var values = { - a: 1 - }; - var e1 = hot('-a-^-|', values); - var e1subs = '^ !'; - var e2 = hot('------', values); //never - var e2subs = '^ '; - var expected = '-'; //never - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and hot-single', function () { - var values = { - a: 1, b: 2 - }; - var e1 = hot('--------', values); //never - var e1subs = '^ '; - var e2 = hot('-a-^-b-|', values); - var e2subs = '^ !'; - var expected = '-----'; //never - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot and hot', function () { - var e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); - var e1subs = '^ !'; - var e2 = hot('---e-^---f--g--|', { e: 'e', f: 'f', g: 'g' }); - var e2subs = '^ !'; - var expected = '----x-yz--|'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'bf', y: 'cf', z: 'cg' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should accept array of observables', function () { - var e1 = hot('--a--^--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('---e-^---f--g--|'); - var e2subs = '^ !'; - var e3 = hot('---h-^----i--j-|'); - var e3subs = '^ !'; - var expected = '-----wxyz-|'; - - var result = e1.combineLatest([e2, e3], function (x, y, z) { return x + y + z; }); - - expectObservable(result).toBe(expected, { w: 'bfi', x: 'cfi', y: 'cgi', z: 'cgj' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should work with empty and error', function () { - var e1 = hot('----------|'); //empty - var e1subs = '^ !'; - var e2 = hot('------#', null, 'shazbot!'); //error - var e2subs = '^ !'; - var expected = '------#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'shazbot!'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with error and empty', function () { - var e1 = hot('--^---#', null, 'too bad, honk'); //error - var e1subs = '^ !'; - var e2 = hot('--^--------|'); //empty - var e2subs = '^ !'; - var expected = '----#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'too bad, honk'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with hot and throw', function () { - var e1 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); - var e1subs = '^ !'; - var e2 = hot('---^-#', null, 'bazinga'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and hot', function () { - var e1 = hot('---^-#', null, 'bazinga'); - var e1subs = '^ !'; - var e2 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); - var e2subs = '^ !'; - var expected = '--#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and throw', function () { - var e1 = hot('---^----#', null, 'jenga'); - var e1subs = '^ !'; - var e2 = hot('---^-#', null, 'bazinga'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bazinga'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with error and throw', function () { - var e1 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^-#', null, 'flurp'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'flurp'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and error', function () { - var e1 = hot('---^-#', null, 'flurp'); - var e1subs = '^ !'; - var e2 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '--#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'flurp'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with never and throw', function () { - var e1 = hot('---^-----------'); - var e1subs = '^ !'; - var e2 = hot('---^-----#', null, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '------#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and never', function () { - var e1 = hot('---^----#', null, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^-----------'); - var e2subs = '^ !'; - var expected = '-----#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with some and throw', function () { - var e1 = hot('---^----a---b--|', { a: 1, b: 2 }); - var e1subs = '^ !'; - var e2 = hot('---^--#', null, 'wokka wokka'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should work with throw and some', function () { - var e1 = hot('---^--#', null, 'wokka wokka'); - var e1subs = '^ !'; - var e2 = hot('---^----a---b--|', { a: 1, b: 2 }); - var e2subs = '^ !'; - var expected = '---#'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle throw after complete left', function () { - var left = hot('--a--^--b---|', { a: 1, b: 2 }); - var leftSubs = '^ !'; - var right = hot('-----^--------#', null, 'bad things'); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = left.combineLatest(right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bad things'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle throw after complete right', function () { - var left = hot('-----^--------#', null, 'bad things'); - var leftSubs = '^ !'; - var right = hot('--a--^--b---|', { a: 1, b: 2 }); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = left.combineLatest(right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'bad things'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle interleaved with tail', function () { - var e1 = hot('-a--^--b---c---|', { a: 'a', b: 'b', c: 'c' }); - var e1subs = '^ !'; - var e2 = hot('--d-^----e---f--|', { d: 'd', e: 'e', f: 'f'}); - var e2subs = '^ !'; - var expected = '-----x-y-z--|'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'be', y: 'ce', z: 'cf' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle two consecutive hot observables', function () { - var e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); - var e1subs = '^ !'; - var e2 = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); - var e2subs = '^ !'; - var expected = '-----------x--y--z--|'; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle two consecutive hot observables with error left', function () { - var left = hot('--a--^--b--c--#', { a: 'a', b: 'b', c: 'c' }, 'jenga'); - var leftSubs = '^ !'; - var right = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); - var rightSubs = '^ !'; - var expected = '---------#'; - - var result = left.combineLatest(right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, null, 'jenga'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle two consecutive hot observables with error right', function () { - var left = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); - var leftSubs = '^ !'; - var right = hot('-----^----------d--e--f--#', { d: 'd', e: 'e', f: 'f' }, 'dun dun dun'); - var rightSubs = '^ !'; - var expected = '-----------x--y--z--#'; - - var result = left.combineLatest(right, function (x, y) { return x + y; }); - - expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }, 'dun dun dun'); - expectSubscriptions(left.subscriptions).toBe(leftSubs); - expectSubscriptions(right.subscriptions).toBe(rightSubs); - }); - - it('should handle selector throwing', function () { - var e1 = hot('--a--^--b--|', { a: 1, b: 2}); - var e1subs = '^ !'; - var e2 = hot('--c--^--d--|', { c: 3, d: 4}); - var e2subs = '^ !'; - var expected = '---#'; - - var result = e1.combineLatest(e2, function (x, y) { throw 'ha ha ' + x + ', ' + y; }); - - expectObservable(result).toBe(expected, null, 'ha ha 2, 4'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '----x-yz-- '; - var unsub = ' ! '; - var values = { x: 'bf', y: 'cf', z: 'cg' }; - - var result = e1.combineLatest(e2, function (x, y) { return x + y; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '----x-yz-- '; - var unsub = ' ! '; - var values = { x: 'bf', y: 'cf', z: 'cg' }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .combineLatest(e2, function (x, y) { return x + y; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); diff --git a/spec/operators/combineLatest-spec.ts b/spec/operators/combineLatest-spec.ts new file mode 100644 index 0000000000..214a0f4874 --- /dev/null +++ b/spec/operators/combineLatest-spec.ts @@ -0,0 +1,465 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.combineLatest', () => { + asDiagram('combineLatest')('should combine events from two cold observables', () => { + const e1 = hot('-a--b-----c-d-e-|'); + const e2 = hot('--1--2-3-4---| '); + const expected = '--A-BC-D-EF-G-H-|'; + + const result = e1.combineLatest(e2, (a: any, b: any) => String(a) + String(b)); + + expectObservable(result).toBe(expected, { + A: 'a1', B: 'b1', C: 'b2', D: 'b3', E: 'b4', F: 'c4', G: 'd4', H: 'e4' + }); + }); + + it('should work with two nevers', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const e2 = cold( '-'); + const e2subs = '^'; + const expected = '-'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and empty', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const e2 = cold( '|'); + const e2subs = '(^!)'; + const expected = '-'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and never', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const e2 = cold( '-'); + const e2subs = '^'; + const expected = '-'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with empty and empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + const expected = '|'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-empty and hot-single', () => { + const values = { + a: 1, + b: 2, + c: 3, + r: 1 + 3 //a + c + }; + const e1 = hot('-a-^-|', values); + const e1subs = '^ !'; + const e2 = hot('-b-^-c-|', values); + const e2subs = '^ !'; + const expected = '----|'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-single and hot-empty', () => { + const values = { + a: 1, b: 2, c: 3 + }; + const e1 = hot('-a-^-|', values); + const e1subs = '^ !'; + const e2 = hot('-b-^-c-|', values); + const e2subs = '^ !'; + const expected = '----|'; + + const result = e2.combineLatest(e1, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot-single and never', () => { + const values = { + a: 1 + }; + const e1 = hot('-a-^-|', values); + const e1subs = '^ !'; + const e2 = hot('------', values); //never + const e2subs = '^ '; + const expected = '-'; //never + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and hot-single', () => { + const values = { + a: 1, b: 2 + }; + const e1 = hot('--------', values); //never + const e1subs = '^ '; + const e2 = hot('-a-^-b-|', values); + const e2subs = '^ !'; + const expected = '-----'; //never + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot and hot', () => { + const e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); + const e1subs = '^ !'; + const e2 = hot('---e-^---f--g--|', { e: 'e', f: 'f', g: 'g' }); + const e2subs = '^ !'; + const expected = '----x-yz--|'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'bf', y: 'cf', z: 'cg' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should accept array of observables', () => { + const e1 = hot('--a--^--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('---e-^---f--g--|'); + const e2subs = '^ !'; + const e3 = hot('---h-^----i--j-|'); + const e3subs = '^ !'; + const expected = '-----wxyz-|'; + + const result = e1.combineLatest([e2, e3], (x: string, y: string, z: string) => x + y + z); + + expectObservable(result).toBe(expected, { w: 'bfi', x: 'cfi', y: 'cgi', z: 'cgj' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should work with empty and error', () => { + const e1 = hot('----------|'); //empty + const e1subs = '^ !'; + const e2 = hot('------#', null, 'shazbot!'); //error + const e2subs = '^ !'; + const expected = '------#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'shazbot!'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with error and empty', () => { + const e1 = hot('--^---#', null, 'too bad, honk'); //error + const e1subs = '^ !'; + const e2 = hot('--^--------|'); //empty + const e2subs = '^ !'; + const expected = '----#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'too bad, honk'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with hot and throw', () => { + const e1 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); + const e1subs = '^ !'; + const e2 = hot('---^-#', null, 'bazinga'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and hot', () => { + const e1 = hot('---^-#', null, 'bazinga'); + const e1subs = '^ !'; + const e2 = hot('-a-^--b--c--|', { a: 1, b: 2, c: 3}); + const e2subs = '^ !'; + const expected = '--#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and throw', () => { + const e1 = hot('---^----#', null, 'jenga'); + const e1subs = '^ !'; + const e2 = hot('---^-#', null, 'bazinga'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bazinga'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with error and throw', () => { + const e1 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^-#', null, 'flurp'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'flurp'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and error', () => { + const e1 = hot('---^-#', null, 'flurp'); + const e1subs = '^ !'; + const e2 = hot('-a-^--b--#', { a: 1, b: 2 }, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '--#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'flurp'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with never and throw', () => { + const e1 = hot('---^-----------'); + const e1subs = '^ !'; + const e2 = hot('---^-----#', null, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '------#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and never', () => { + const e1 = hot('---^----#', null, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^-----------'); + const e2subs = '^ !'; + const expected = '-----#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with some and throw', () => { + const e1 = hot('---^----a---b--|', { a: 1, b: 2 }); + const e1subs = '^ !'; + const e2 = hot('---^--#', null, 'wokka wokka'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should work with throw and some', () => { + const e1 = hot('---^--#', null, 'wokka wokka'); + const e1subs = '^ !'; + const e2 = hot('---^----a---b--|', { a: 1, b: 2 }); + const e2subs = '^ !'; + const expected = '---#'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { a: 1, b: 2}, 'wokka wokka'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle throw after complete left', () => { + const left = hot('--a--^--b---|', { a: 1, b: 2 }); + const leftSubs = '^ !'; + const right = hot('-----^--------#', null, 'bad things'); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = left.combineLatest(right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bad things'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle throw after complete right', () => { + const left = hot('-----^--------#', null, 'bad things'); + const leftSubs = '^ !'; + const right = hot('--a--^--b---|', { a: 1, b: 2 }); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = left.combineLatest(right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'bad things'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle interleaved with tail', () => { + const e1 = hot('-a--^--b---c---|', { a: 'a', b: 'b', c: 'c' }); + const e1subs = '^ !'; + const e2 = hot('--d-^----e---f--|', { d: 'd', e: 'e', f: 'f'}); + const e2subs = '^ !'; + const expected = '-----x-y-z--|'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'be', y: 'ce', z: 'cf' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle two consecutive hot observables', () => { + const e1 = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); + const e1subs = '^ !'; + const e2 = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); + const e2subs = '^ !'; + const expected = '-----------x--y--z--|'; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle two consecutive hot observables with error left', () => { + const left = hot('--a--^--b--c--#', { a: 'a', b: 'b', c: 'c' }, 'jenga'); + const leftSubs = '^ !'; + const right = hot('-----^----------d--e--f--|', { d: 'd', e: 'e', f: 'f' }); + const rightSubs = '^ !'; + const expected = '---------#'; + + const result = left.combineLatest(right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, null, 'jenga'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle two consecutive hot observables with error right', () => { + const left = hot('--a--^--b--c--|', { a: 'a', b: 'b', c: 'c' }); + const leftSubs = '^ !'; + const right = hot('-----^----------d--e--f--#', { d: 'd', e: 'e', f: 'f' }, 'dun dun dun'); + const rightSubs = '^ !'; + const expected = '-----------x--y--z--#'; + + const result = left.combineLatest(right, (x: any, y: any) => x + y); + + expectObservable(result).toBe(expected, { x: 'cd', y: 'ce', z: 'cf' }, 'dun dun dun'); + expectSubscriptions(left.subscriptions).toBe(leftSubs); + expectSubscriptions(right.subscriptions).toBe(rightSubs); + }); + + it('should handle selector throwing', () => { + const e1 = hot('--a--^--b--|', { a: 1, b: 2}); + const e1subs = '^ !'; + const e2 = hot('--c--^--d--|', { c: 3, d: 4}); + const e2subs = '^ !'; + const expected = '---#'; + + const result = e1.combineLatest(e2, (x: number, y: number) => { throw 'ha ha ' + x + ', ' + y; }); + + expectObservable(result).toBe(expected, null, 'ha ha 2, 4'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '----x-yz-- '; + const unsub = ' ! '; + const values = { x: 'bf', y: 'cf', z: 'cg' }; + + const result = e1.combineLatest(e2, (x: any, y: any) => x + y); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '----x-yz-- '; + const unsub = ' ! '; + const values = { x: 'bf', y: 'cf', z: 'cg' }; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .combineLatest(e2, (x: any, y: any) => x + y) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); diff --git a/spec/operators/concat-spec.js b/spec/operators/concat-spec.js deleted file mode 100644 index 36717484ab..0000000000 --- a/spec/operators/concat-spec.js +++ /dev/null @@ -1,309 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.concat()', function () { - it.asDiagram('concat')('should concatenate two cold observables', function () { - var e1 = cold('--a--b-|'); - var e2 = cold( '--x---y--|'); - var expected = '--a--b---x---y--|'; - - expectObservable(e1.concat(e2, rxTestScheduler)).toBe(expected); - }); - - it('should work properly with scalar observables', function (done) { - var results = []; - - var s1 = Observable - .create(function (observer) { - setTimeout(function () { - observer.next(1); - observer.complete(); - }); - }) - .concat(Observable.of(2)); - - s1.subscribe( - function (x) { - results.push('Next: ' + x); - }, - done.fail, - function (x) { - results.push('Completed'); - expect(results).toEqual(['Next: 1', 'Next: 2', 'Completed']); - done(); - } - ); - }); - - it('should complete without emit if both sources are empty', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '----|'); - var e2subs = ' ^ !'; - var expected = '------|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if first source does not completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('--|'); - var e2subs = []; - var expected = '-'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if second source does not completes', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold('---'); - var e2subs = ' ^'; - var expected = '---'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if both sources do not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('-'); - var e2subs = []; - var expected = '-'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when first source is empty, second source raises error', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '----#'); - var e2subs = ' ^ !'; - var expected = '------#'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when first source raises error, second source is empty', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('----|'); - var e2subs = []; - var expected = '---#'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise first error when both source raise error', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('------#'); - var e2subs = []; - var expected = '---#'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat if first source emits once, second source is empty', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '--------|'); - var e2subs = ' ^ !'; - var expected = '--a----------|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat if first source is empty, second source emits once', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '--a--|'); - var e2subs = ' ^ !'; - var expected = '----a--|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit element from first source, and should not complete if second ' + - 'source does not completes', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '-'); - var e2subs = ' ^'; - var expected = '--a---'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if first source does not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('--a--|'); - var e2subs = []; - var expected = '-'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit elements from each source when source emit once', function () { - var e1 = cold('---a|'); - var e1subs = '^ !'; - var e2 = cold( '-----b--|'); - var e2subs = ' ^ !'; - var expected = '---a-----b--|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe to inner source if outer is unsubscribed early', function () { - var e1 = cold('---a-a--a| '); - var e1subs = '^ ! '; - var e2 = cold( '-----b-b--b-|'); - var e2subs = ' ^ ! '; - var unsub = ' ! '; - var expected = '---a-a--a-----b-b '; - - expectObservable(e1.concat(e2), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = cold('---a-a--a| '); - var e1subs = '^ ! '; - var e2 = cold( '-----b-b--b-|'); - var e2subs = ' ^ ! '; - var expected = '---a-a--a-----b-b- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .concat(e2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error from first source and does not emit from second source', function () { - var e1 = cold('--#'); - var e1subs = '^ !'; - var e2 = cold('----a--|'); - var e2subs = []; - var expected = '--#'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit element from first source then raise error from second source', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '-------#'); - var e2subs = ' ^ !'; - var expected = '--a---------#'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit all elements from both hot observable sources if first source ' + - 'completes before second source starts emit', function () { - var e1 = hot('--a--b-|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--x--y--|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit elements from second source regardless of completion time ' + - 'when second source is cold observable', function () { - var e1 = hot('--a--b--c---|'); - var e1subs = '^ !'; - var e2 = cold('-x-y-z-|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c----x-y-z-|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not emit collapsing element from second source', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--z--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c--y--z--|'; - - expectObservable(e1.concat(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should accept scheduler with multiple observables', function () { - var e1 = cold('---a|'); - var e1subs = '^ !'; - var e2 = cold( '---b--|'); - var e2subs = ' ^ !'; - var e3 = cold( '---c--|'); - var e3subs = ' ^ !'; - var expected = '---a---b-----c--|'; - - expectObservable(e1.concat(e2, e3, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should accept scheduler without observable parameters', function () { - var e1 = cold('---a-|'); - var e1subs = '^ !'; - var expected = '---a-|'; - - expectObservable(e1.concat(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit self without parameters', function () { - var e1 = cold('---a-|'); - var e1subs = '^ !'; - var expected = '---a-|'; - - expectObservable(e1.concat()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/concat-spec.ts b/spec/operators/concat-spec.ts new file mode 100644 index 0000000000..565d6a4232 --- /dev/null +++ b/spec/operators/concat-spec.ts @@ -0,0 +1,311 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.concat()', () => { + asDiagram('concat')('should concatenate two cold observables', () => { + const e1 = cold('--a--b-|'); + const e2 = cold( '--x---y--|'); + const expected = '--a--b---x---y--|'; + + expectObservable(e1.concat(e2, rxTestScheduler)).toBe(expected); + }); + + it('should work properly with scalar observables', (done: DoneSignature) => { + const results = []; + + const s1 = Observable + .create((observer: Rx.Observer) => { + setTimeout(() => { + observer.next(1); + observer.complete(); + }); + }) + .concat(Observable.of(2)); + + s1.subscribe((x: number) => { + results.push('Next: ' + x); + }, + done.fail, + () => { + results.push('Completed'); + expect(results).toEqual(['Next: 1', 'Next: 2', 'Completed']); + done(); + } + ); + }); + + it('should complete without emit if both sources are empty', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '----|'); + const e2subs = ' ^ !'; + const expected = '------|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if first source does not completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('--|'); + const e2subs = []; + const expected = '-'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if second source does not completes', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold('---'); + const e2subs = ' ^'; + const expected = '---'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if both sources do not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('-'); + const e2subs = []; + const expected = '-'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when first source is empty, second source raises error', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '----#'); + const e2subs = ' ^ !'; + const expected = '------#'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when first source raises error, second source is empty', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('----|'); + const e2subs = []; + const expected = '---#'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise first error when both source raise error', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('------#'); + const e2subs = []; + const expected = '---#'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat if first source emits once, second source is empty', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '--------|'); + const e2subs = ' ^ !'; + const expected = '--a----------|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat if first source is empty, second source emits once', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '--a--|'); + const e2subs = ' ^ !'; + const expected = '----a--|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit element from first source, and should not complete if second ' + + 'source does not completes', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '-'); + const e2subs = ' ^'; + const expected = '--a---'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if first source does not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('--a--|'); + const e2subs = []; + const expected = '-'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit elements from each source when source emit once', () => { + const e1 = cold('---a|'); + const e1subs = '^ !'; + const e2 = cold( '-----b--|'); + const e2subs = ' ^ !'; + const expected = '---a-----b--|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should unsubscribe to inner source if outer is unsubscribed early', () => { + const e1 = cold('---a-a--a| '); + const e1subs = '^ ! '; + const e2 = cold( '-----b-b--b-|'); + const e2subs = ' ^ ! '; + const unsub = ' ! '; + const expected = '---a-a--a-----b-b '; + + expectObservable(e1.concat(e2), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = cold('---a-a--a| '); + const e1subs = '^ ! '; + const e2 = cold( '-----b-b--b-|'); + const e2subs = ' ^ ! '; + const expected = '---a-a--a-----b-b- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .concat(e2) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error from first source and does not emit from second source', () => { + const e1 = cold('--#'); + const e1subs = '^ !'; + const e2 = cold('----a--|'); + const e2subs = []; + const expected = '--#'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit element from first source then raise error from second source', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '-------#'); + const e2subs = ' ^ !'; + const expected = '--a---------#'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit all elements from both hot observable sources if first source ' + + 'completes before second source starts emit', () => { + const e1 = hot('--a--b-|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--x--y--|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit elements from second source regardless of completion time ' + + 'when second source is cold observable', () => { + const e1 = hot('--a--b--c---|'); + const e1subs = '^ !'; + const e2 = cold('-x-y-z-|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c----x-y-z-|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not emit collapsing element from second source', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--z--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c--y--z--|'; + + expectObservable(e1.concat(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should accept scheduler with multiple observables', () => { + const e1 = cold('---a|'); + const e1subs = '^ !'; + const e2 = cold( '---b--|'); + const e2subs = ' ^ !'; + const e3 = cold( '---c--|'); + const e3subs = ' ^ !'; + const expected = '---a---b-----c--|'; + + expectObservable(e1.concat(e2, e3, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should accept scheduler without observable parameters', () => { + const e1 = cold('---a-|'); + const e1subs = '^ !'; + const expected = '---a-|'; + + expectObservable(e1.concat(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit self without parameters', () => { + const e1 = cold('---a-|'); + const e1subs = '^ !'; + const expected = '---a-|'; + + expectObservable(e1.concat()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/concatAll-spec.js b/spec/operators/concatAll-spec.js deleted file mode 100644 index 18d1e3cac2..0000000000 --- a/spec/operators/concatAll-spec.js +++ /dev/null @@ -1,426 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.concatAll()', function () { - it.asDiagram('concatAll')('should concat an observable of observables', function () { - var x = cold( '----a------b------| '); - var y = cold( '---c-d---| '); - var z = cold( '---e--f-|'); - var outer = hot('-x---y----z------| ', { x: x, y: y, z: z }); - var expected = '-----a------b---------c-d------e--f-|'; - - var result = outer.concatAll(); - - expectObservable(result).toBe(expected); - }); - - it('should concat sources from promise', function (done) { - var sources = Rx.Observable.fromArray([ - new Promise(function (res) { res(0); }), - new Promise(function (res) { res(1); }), - new Promise(function (res) { res(2); }), - new Promise(function (res) { res(3); }), - ]); - - var res = []; - sources.concatAll().subscribe( - function (x) { res.push(x); }, - function (err) { done.fail('should not be called.'); }, - function () { - expect(res).toEqual([0,1,2,3]); - done(); - }); - }, 2000); - - it('should concat and raise error from promise', function (done) { - var sources = Rx.Observable.fromArray([ - new Promise(function (res) { res(0); }), - new Promise(function (res, rej) { rej(1); }), - new Promise(function (res) { res(2); }), - new Promise(function (res) { res(3); }), - ]); - - var res = []; - sources.concatAll().subscribe( - function (x) { res.push(x); }, - function (err) { - expect(res.length).toBe(1); - expect(err).toBe(1); - done(); - }, - function () { done.fail('should not be called.'); }); - }, 2000); - - it('should concat all observables in an observable', function () { - var e1 = Rx.Observable.fromArray([ - Rx.Observable.of('a'), - Rx.Observable.of('b'), - Rx.Observable.of('c') - ]); - var expected = '(abc|)'; - - expectObservable(e1.concatAll()).toBe(expected); - }); - - it('should throw if any child observable throws', function () { - var e1 = Rx.Observable.fromArray([ - Rx.Observable.of('a'), - Rx.Observable.throw('error'), - Rx.Observable.of('c') - ]); - var expected = '(a#)'; - - expectObservable(e1.concatAll()).toBe(expected); - }); - - it('should concat merging a hot observable of non-overlapped observables', function () { - var values = { - x: cold( 'a-b---------|'), - y: cold( 'c-d-e-f-|'), - z: cold( 'g-h-i-j-k-|') - }; - - var e1 = hot('--x---------y--------z--------|', values); - var expected = '--a-b---------c-d-e-f-g-h-i-j-k-|'; - - expectObservable(e1.concatAll()).toBe(expected); - }); - - it('should raise error if inner observable raises error', function () { - var values = { - x: cold( 'a-b---------|'), - y: cold( 'c-d-e-f-#'), - z: cold( 'g-h-i-j-k-|') - }; - var e1 = hot('--x---------y--------z--------|', values); - var expected = '--a-b---------c-d-e-f-#'; - - expectObservable(e1.concatAll()).toBe(expected); - }); - - it('should raise error if outer observable raises error', function () { - var values = { - y: cold( 'a-b---------|'), - z: cold( 'c-d-e-f-|'), - }; - var e1 = hot('--y---------z---# ', values); - var expected = '--a-b---------c-#'; - - expectObservable(e1.concatAll()).toBe(expected); - }); - - it('should complete without emit if both sources are empty', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '----|'); - var e2subs = ' ^ !'; - var expected = '------|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if first source does not completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('--|'); - var e2subs = []; - var expected = '-'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if second source does not completes', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold('---'); - var e2subs = ' ^'; - var expected = '---'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if both sources do not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('-'); - var e2subs = []; - var expected = '-'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when first source is empty, second source raises error', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '----#'); - var e2subs = ' ^ !'; - var expected = '------#'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when first source raises error, second source is empty', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('----|'); - var e2subs = []; - var expected = '---#'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise first error when both source raise error', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('------#'); - var e2subs = []; - var expected = '---#'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat if first source emits once, second source is empty', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '--------|'); - var e2subs = ' ^ !'; - var expected = '--a----------|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should concat if first source is empty, second source emits once', function () { - var e1 = cold('--|'); - var e1subs = '^ !'; - var e2 = cold( '--a--|'); - var e2subs = ' ^ !'; - var expected = '----a--|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit element from first source, and should not complete if second ' + - 'source does not completes', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '-'); - var e2subs = ' ^'; - var expected = '--a---'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete if first source does not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('--a--|'); - var e2subs = []; - var expected = '-'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit elements from each source when source emit once', function () { - var e1 = cold('---a|'); - var e1subs = '^ !'; - var e2 = cold( '-----b--|'); - var e2subs = ' ^ !'; - var expected = '---a-----b--|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe to inner source if outer is unsubscribed early', function () { - var e1 = cold('---a-a--a| '); - var e1subs = '^ ! '; - var e2 = cold( '-----b-b--b-|'); - var e2subs = ' ^ ! '; - var unsub = ' ! '; - var expected = '---a-a--a-----b-b '; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = cold('---a-a--a| '); - var e1subs = '^ ! '; - var e2 = cold( '-----b-b--b-|'); - var e2subs = ' ^ ! '; - var expected = '---a-a--a-----b-b- '; - var unsub = ' ! '; - - var result = Observable.of(e1, e2) - .mergeMap(function (x) { return Observable.of(x); }) - .concatAll() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error from first source and does not emit from second source', function () { - var e1 = cold('--#'); - var e1subs = '^ !'; - var e2 = cold('----a--|'); - var e2subs = []; - var expected = '--#'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit element from first source then raise error from second source', function () { - var e1 = cold('--a--|'); - var e1subs = '^ !'; - var e2 = cold( '-------#'); - var e2subs = ' ^ !'; - var expected = '--a---------#'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit all elements from both hot observable sources if first source ' + - 'completes before second source starts emit', function () { - var e1 = hot('--a--b-|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--x--y--|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit elements from second source regardless of completion time ' + - 'when second source is cold observable', function () { - var e1 = hot('--a--b--c---|'); - var e1subs = '^ !'; - var e2 = cold('-x-y-z-|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c----x-y-z-|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not emit collapsing element from second source', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var e2 = hot('--------x--y--z--|'); - var e2subs = ' ^ !'; - var expected = '--a--b--c--y--z--|'; - - var result = Observable.of(e1, e2).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should be able to work on a different scheduler', function () { - var e1 = cold('---a|'); - var e1subs = '^ !'; - var e2 = cold( '---b--|'); - var e2subs = ' ^ !'; - var e3 = cold( '---c--|'); - var e3subs = ' ^ !'; - var expected = '---a---b-----c--|'; - - var result = Observable.of(e1, e2, e3, rxTestScheduler).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should concatAll a nested observable with a single inner observable', function () { - var e1 = cold('---a-|'); - var e1subs = '^ !'; - var expected = '---a-|'; - - var result = Observable.of(e1).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatAll a nested observable with a single inner observable, and a scheduler', function () { - var e1 = cold('---a-|'); - var e1subs = '^ !'; - var expected = '---a-|'; - - var result = Observable.of(e1, rxTestScheduler).concatAll(); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/concatAll-spec.ts b/spec/operators/concatAll-spec.ts new file mode 100644 index 0000000000..2e49c16b5e --- /dev/null +++ b/spec/operators/concatAll-spec.ts @@ -0,0 +1,428 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.concatAll()', () => { + asDiagram('concatAll')('should concat an observable of observables', () => { + const x = cold( '----a------b------| '); + const y = cold( '---c-d---| '); + const z = cold( '---e--f-|'); + const outer = hot('-x---y----z------| ', { x: x, y: y, z: z }); + const expected = '-----a------b---------c-d------e--f-|'; + + const result = outer.concatAll(); + + expectObservable(result).toBe(expected); + }); + + it('should concat sources from promise', (done: DoneSignature) => { + const sources = Rx.Observable.fromArray([ + new Promise((res: any) => { res(0); }), + new Promise((res: any) => { res(1); }), + new Promise((res: any) => { res(2); }), + new Promise((res: any) => { res(3); }), + ]).take(10); + + const res = []; + (sources.concatAll()).subscribe( + (x: number) => { res.push(x); }, + (err: any) => { done.fail('should not be called.'); }, + () => { + expect(res).toEqual([0,1,2,3]); + done(); + }); + }, 2000); + + it('should concat and raise error from promise', (done: DoneSignature) => { + const sources = Rx.Observable.fromArray([ + new Promise((res: any) => { res(0); }), + new Promise((res: any, rej: any) => { rej(1); }), + new Promise((res: any) => { res(2); }), + new Promise((res: any) => { res(3); }), + ]).take(10); + + const res = []; + (sources.concatAll()).subscribe( + (x: number) => { res.push(x); }, + (err: any) => { + expect(res.length).toBe(1); + expect(err).toBe(1); + done(); + }, + () => { done.fail('should not be called.'); }); + }, 2000); + + it('should concat all observables in an observable', () => { + const e1 = Rx.Observable.fromArray([ + Rx.Observable.of('a'), + Rx.Observable.of('b'), + Rx.Observable.of('c') + ]).take(10); + const expected = '(abc|)'; + + expectObservable(e1.concatAll()).toBe(expected); + }); + + it('should throw if any child observable throws', () => { + const e1 = Rx.Observable.fromArray([ + Rx.Observable.of('a'), + Rx.Observable.throw('error'), + Rx.Observable.of('c') + ]).take(10); + const expected = '(a#)'; + + expectObservable(e1.concatAll()).toBe(expected); + }); + + it('should concat merging a hot observable of non-overlapped observables', () => { + const values = { + x: cold( 'a-b---------|'), + y: cold( 'c-d-e-f-|'), + z: cold( 'g-h-i-j-k-|') + }; + + const e1 = hot('--x---------y--------z--------|', values); + const expected = '--a-b---------c-d-e-f-g-h-i-j-k-|'; + + expectObservable(e1.concatAll()).toBe(expected); + }); + + it('should raise error if inner observable raises error', () => { + const values = { + x: cold( 'a-b---------|'), + y: cold( 'c-d-e-f-#'), + z: cold( 'g-h-i-j-k-|') + }; + const e1 = hot('--x---------y--------z--------|', values); + const expected = '--a-b---------c-d-e-f-#'; + + expectObservable(e1.concatAll()).toBe(expected); + }); + + it('should raise error if outer observable raises error', () => { + const values = { + y: cold( 'a-b---------|'), + z: cold( 'c-d-e-f-|'), + }; + const e1 = hot('--y---------z---# ', values); + const expected = '--a-b---------c-#'; + + expectObservable(e1.concatAll()).toBe(expected); + }); + + it('should complete without emit if both sources are empty', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '----|'); + const e2subs = ' ^ !'; + const expected = '------|'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if first source does not completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('--|'); + const e2subs = []; + const expected = '-'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if second source does not completes', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold('---'); + const e2subs = ' ^'; + const expected = '---'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if both sources do not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('-'); + const e2subs = []; + const expected = '-'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when first source is empty, second source raises error', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '----#'); + const e2subs = ' ^ !'; + const expected = '------#'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when first source raises error, second source is empty', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('----|'); + const e2subs = []; + const expected = '---#'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise first error when both source raise error', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('------#'); + const e2subs = []; + const expected = '---#'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat if first source emits once, second source is empty', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '--------|'); + const e2subs = ' ^ !'; + const expected = '--a----------|'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should concat if first source is empty, second source emits once', () => { + const e1 = cold('--|'); + const e1subs = '^ !'; + const e2 = cold( '--a--|'); + const e2subs = ' ^ !'; + const expected = '----a--|'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit element from first source, and should not complete if second ' + + 'source does not completes', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '-'); + const e2subs = ' ^'; + const expected = '--a---'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete if first source does not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('--a--|'); + const e2subs = []; + const expected = '-'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit elements from each source when source emit once', () => { + const e1 = cold('---a|'); + const e1subs = '^ !'; + const e2 = cold( '-----b--|'); + const e2subs = ' ^ !'; + const expected = '---a-----b--|'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should unsubscribe to inner source if outer is unsubscribed early', () => { + const e1 = cold('---a-a--a| '); + const e1subs = '^ ! '; + const e2 = cold( '-----b-b--b-|'); + const e2subs = ' ^ ! '; + const unsub = ' ! '; + const expected = '---a-a--a-----b-b '; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = cold('---a-a--a| '); + const e1subs = '^ ! '; + const e2 = cold( '-----b-b--b-|'); + const e2subs = ' ^ ! '; + const expected = '---a-a--a-----b-b- '; + const unsub = ' ! '; + + const result = Observable.of(e1, e2) + .mergeMap((x: any) => Observable.of(x)) + .concatAll() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error from first source and does not emit from second source', () => { + const e1 = cold('--#'); + const e1subs = '^ !'; + const e2 = cold('----a--|'); + const e2subs = []; + const expected = '--#'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit element from first source then raise error from second source', () => { + const e1 = cold('--a--|'); + const e1subs = '^ !'; + const e2 = cold( '-------#'); + const e2subs = ' ^ !'; + const expected = '--a---------#'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit all elements from both hot observable sources if first source ' + + 'completes before second source starts emit', () => { + const e1 = hot('--a--b-|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--x--y--|'; + + const result = Observable.of(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit elements from second source regardless of completion time ' + + 'when second source is cold observable', () => { + const e1 = hot('--a--b--c---|'); + const e1subs = '^ !'; + const e2 = cold('-x-y-z-|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c----x-y-z-|'; + + const result = Observable.of>(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not emit collapsing element from second source', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const e2 = hot('--------x--y--z--|'); + const e2subs = ' ^ !'; + const expected = '--a--b--c--y--z--|'; + + const result = Observable.of>(e1, e2).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should be able to work on a different scheduler', () => { + const e1 = cold('---a|'); + const e1subs = '^ !'; + const e2 = cold( '---b--|'); + const e2subs = ' ^ !'; + const e3 = cold( '---c--|'); + const e3subs = ' ^ !'; + const expected = '---a---b-----c--|'; + + const result = Observable.of>(e1, e2, e3, rxTestScheduler).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should concatAll a nested observable with a single inner observable', () => { + const e1 = cold('---a-|'); + const e1subs = '^ !'; + const expected = '---a-|'; + + const result = Observable.of(e1).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatAll a nested observable with a single inner observable, and a scheduler', () => { + const e1 = cold('---a-|'); + const e1subs = '^ !'; + const expected = '---a-|'; + + const result = Observable.of>(e1, rxTestScheduler).concatAll(); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/concatMap-spec.js b/spec/operators/concatMap-spec.js deleted file mode 100644 index 5a4ac8762b..0000000000 --- a/spec/operators/concatMap-spec.js +++ /dev/null @@ -1,787 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.concatMap()', function () { - it('should concatenate many regular interval inners', function () { - var a = cold('--a-a-a-(a|) '); - var asubs = '^ ! '; - var b = cold( '----b--b--(b|) '); - var bsubs = ' ^ ! '; - var c = cold( '-c-c-(c|) '); - var csubs = ' ^ ! '; - var d = cold( '------(d|)'); - var dsubs = ' ^ ! '; - var e1 = hot('a---b--------------------c-d----| '); - var e1subs = '^ ! '; - var expected = '--a-a-a-a---b--b--b-------c-c-c-----(d|)'; - - var observableLookup = { a: a, b: b, c: c, d: d }; - var source = e1.concatMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer values to many inner values', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---| '); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an empty source', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var inner = cold('-1-2-3|'); - var innersubs = []; - var expected = '|'; - - var result = e1.concatMap(function () { return inner; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a never source', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var inner = cold('-1-2-3|'); - var innersubs = []; - var expected = '-'; - - var result = e1.concatMap(function () { return inner; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error immediately if given a just-throw source', function () { - var e1 = cold( '#'); - var e1subs = '(^!)'; - var inner = cold('-1-2-3|'); - var innersubs = []; - var expected = '#'; - - var result = e1.concatMap(function () { return inner; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return a silenced version of the source if the mapped inner is empty', function () { - var e1 = cold( '--a-b--c-| '); - var e1subs = '^ ! '; - var inner = cold('|'); - var innersubs = [' (^!) ', - ' (^!) ', - ' (^!)']; - var expected = '---------| '; - - var result = e1.concatMap(function () { return inner; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return a never if the mapped inner is never', function () { - var e1 = cold( '--a-b--c-|'); - var e1subs = '^ '; - var inner = cold('-'); - var innersubs = ' ^ '; - var expected = '----------'; - - var result = e1.concatMap(function () { return inner; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should propagate errors if the mapped inner is a just-throw Observable', function () { - var e1 = cold( '--a-b--c-|'); - var e1subs = '^ ! '; - var inner = cold('#'); - var innersubs = ' (^!) '; - var expected = '--# '; - - var result = e1.concatMap(function () { return inner; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to many inner, complete late', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d----------------------------------|'); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l--------|'; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to many inner, outer never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d-----------------------------------'); - var e1subs = '^ '; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l---------'; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to many inner, inner never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---|'); - var e1subs = '^ '; - var inner = cold('--i-j-k-l- ', values); - var innersubs = ' ^ '; - var expected = '---i-j-k-l--------'; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to many inner, and inner throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---|'); - var e1subs = '^ ! '; - var inner = cold('--i-j-k-l-# ', values); - var innersubs = ' ^ ! '; - var expected = '---i-j-k-l-# '; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to many inner, and outer throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---#'); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ !']; - var expected = '---i-j-k-l---i-j-#'; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to many inner, both inner and outer throw', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---#'); - var e1subs = '^ ! '; - var inner = cold('--i-j-k-l-# ', values); - var innersubs = ' ^ ! '; - var expected = '---i-j-k-l-# '; - - var result = e1.concatMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, where all inners are finite', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = ' ^ ! '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = ' ^ ! '; - var f = cold( '--| '); - var fsubs = ' ^ ! '; - var g = cold( '---1-2|'); - var gsubs = ' ^ !'; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); - var e1subs = '^ !'; - var expected = '---2--3--4--5----6-----2--3-1------2--3-4-5--------1-2|'; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { return observableLookup[value]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, all inners finite except one', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3- '); - var dsubs = ' ^ '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = []; - var f = cold( '--| '); - var fsubs = []; - var g = cold( '---1-2|'); - var gsubs = []; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); - var e1subs = '^ '; - var expected = '---2--3--4--5----6-----2--3----------------------------'; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { return observableLookup[value]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, inners finite, outer does not complete', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = ' ^ ! '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = ' ^ ! '; - var f = cold( '--| '); - var fsubs = ' ^ ! '; - var g = cold( '---1-2|'); - var gsubs = ' ^ !'; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g--- '); - var e1subs = '^ '; - var expected = '---2--3--4--5----6-----2--3-1------2--3-4-5--------1-2-'; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { return observableLookup[value]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, all inners finite, and outer throws', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = ' ^ ! '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = ' ^ ! '; - var f = cold( '--| '); - var fsubs = []; - var g = cold( '---1-2|'); - var gsubs = []; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g# '); - var e1subs = '^ ! '; - var expected = '---2--3--4--5----6-----2--3-1------2--3# '; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { return observableLookup[value]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, all inners complete except one throws', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-# '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = []; - var e = cold( '-1------2--3-4-5---| '); - var esubs = []; - var f = cold( '--| '); - var fsubs = []; - var g = cold( '---1-2|'); - var gsubs = []; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); - var e1subs = '^ ! '; - var expected = '---2--3--4--5----6-# '; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { return observableLookup[value]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, all inners finite, outer is unsubscribed early', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = ' ^ ! '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = ' ^ ! '; - var f = cold( '--| '); - var fsubs = []; - var g = cold( '---1-2|'); - var gsubs = []; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); - var e1subs = '^ ! '; - var unsub = ' ! '; - var expected = '---2--3--4--5----6-----2--3-1-- '; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { return observableLookup[value]; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = ' ^ ! '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = ' ^ ! '; - var f = cold( '--| '); - var fsubs = []; - var g = cold( '---1-2|'); - var gsubs = []; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); - var e1subs = '^ ! '; - var unsub = ' ! '; - var expected = '---2--3--4--5----6-----2--3-1-- '; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .concatMap(function (value) { return observableLookup[value]; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many complex, all inners finite, project throws', function () { - var a = cold( '-# '); - var asubs = []; - var b = cold( '-# '); - var bsubs = []; - var c = cold( '-2--3--4--5----6-| '); - var csubs = ' ^ ! '; - var d = cold( '----2--3| '); - var dsubs = ' ^ ! '; - var e = cold( '-1------2--3-4-5---| '); - var esubs = []; - var f = cold( '--| '); - var fsubs = []; - var g = cold( '---1-2|'); - var gsubs = []; - var e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); - var e1subs = '^ ! '; - var expected = '---2--3--4--5----6-----2--3# '; - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.concatMap(function (value) { - if (value === 'e') { throw 'error'; } - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - expectSubscriptions(c.subscriptions).toBe(csubs); - expectSubscriptions(d.subscriptions).toBe(dsubs); - expectSubscriptions(e.subscriptions).toBe(esubs); - expectSubscriptions(f.subscriptions).toBe(fsubs); - expectSubscriptions(g.subscriptions).toBe(gsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - function arrayRepeat(value, times) { - var results = []; - for (var i = 0; i < times; i++) { - results.push(value); - } - return results; - } - - it('should concatMap many outer to an array for each value', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(22)--(4444)---(333)----(22)----|'; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, using resultSelector', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(44)--(8888)---(666)----(44)----|'; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }, function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, and outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var e1subs = '^ !'; - var expected = '(22)--(4444)---(333)----(22)----#'; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, resultSelector, outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var e1subs = '^ !'; - var expected = '(44)--(8888)---(666)----(44)----#'; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }, function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, outer unsubscribed early', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var unsub = ' ! '; - var expected = '(22)--(4444)-- '; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, resultSelector, outer unsubscribed', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var unsub = ' ! '; - var expected = '(44)--(8888)-- '; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }, function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, project throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var expected = '(22)--(4444)---# '; - - var invoked = 0; - var result = e1.concatMap(function (value) { - invoked++; - if (invoked === 3) { - throw 'error'; - } - return arrayRepeat(value, value); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, resultSelector throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var expected = '(44)--(8888)---# '; - - var result = e1.concatMap(function (value) { - return arrayRepeat(value, value); - }, function (inner, outer) { - if (outer === '3') { - throw 'error'; - } - return String(parseInt(outer) + parseInt(inner)); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should concatMap many outer to inner arrays, resultSelector, project throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var expected = '(44)--(8888)---# '; - - var invoked = 0; - var result = e1.concatMap(function (value) { - invoked++; - if (invoked === 3) { - throw 'error'; - } - return arrayRepeat(value, value); - }, function (inner, outer) { - return String(parseInt(outer) + parseInt(inner)); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should map values to constant resolved promises and concatenate', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value) { - return Observable.from(Promise.resolve(42)); - }; - - var results = []; - source.concatMap(project).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([42,42,42,42]); - done(); - }); - }); - - it('should map values to constant rejected promises and concatenate', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value) { - return Observable.from(Promise.reject(42)); - }; - - source.concatMap(project).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual(42); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should map values to resolved promises and concatenate', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value, index) { - return Observable.from(Promise.resolve(value + index)); - }; - - var results = []; - source.concatMap(project).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([4,4,4,4]); - done(); - }); - }); - - it('should map values to rejected promises and concatenate', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value, index) { - return Observable.from(Promise.reject('' + value + '-' + index)); - }; - - source.concatMap(project).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual('4-0'); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should concatMap values to resolved promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var resultSelectorCalledWith = []; - var project = function (value, index) { - return Observable.from(Promise.resolve([value, index])); - }; - var resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { - resultSelectorCalledWith.push([].slice.call(arguments)); - return 8; - }; - - var results = []; - var expectedCalls = [ - [4, [4,0], 0, 0], - [3, [3,1], 1, 0], - [2, [2,2], 2, 0], - [1, [1,3], 3, 0] - ]; - source.concatMap(project, resultSelector).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([8,8,8,8]); - expect(resultSelectorCalledWith).toDeepEqual(expectedCalls); - done(); - }); - }); - - it('should concatMap values to rejected promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value, index) { - return Observable.from(Promise.reject('' + value + '-' + index)); - }; - var resultSelector = function () { - throw 'this should not be called'; - }; - - source.concatMap(project, resultSelector).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual('4-0'); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); -}); \ No newline at end of file diff --git a/spec/operators/concatMap-spec.ts b/spec/operators/concatMap-spec.ts new file mode 100644 index 0000000000..80e4178e38 --- /dev/null +++ b/spec/operators/concatMap-spec.ts @@ -0,0 +1,748 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.concatMap()', () => { + it('should concatenate many regular interval inners', () => { + const a = cold('--a-a-a-(a|) '); + const asubs = '^ ! '; + const b = cold( '----b--b--(b|) '); + const bsubs = ' ^ ! '; + const c = cold( '-c-c-(c|) '); + const csubs = ' ^ ! '; + const d = cold( '------(d|)'); + const dsubs = ' ^ ! '; + const e1 = hot('a---b--------------------c-d----| '); + const e1subs = '^ ! '; + const expected = '--a-a-a-a---b--b--b-------c-c-c-----(d|)'; + + const observableLookup = { a: a, b: b, c: c, d: d }; + const source = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(source).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer values to many inner values', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---| '); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; + + const result = e1.concatMap((value: any) =>inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an empty source', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const inner = cold('-1-2-3|'); + const innersubs = []; + const expected = '|'; + + const result = e1.concatMap(() => inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a never source', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const inner = cold('-1-2-3|'); + const innersubs = []; + const expected = '-'; + + const result = e1.concatMap(() => { return inner; }); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error immediately if given a just-throw source', () => { + const e1 = cold( '#'); + const e1subs = '(^!)'; + const inner = cold('-1-2-3|'); + const innersubs = []; + const expected = '#'; + + const result = e1.concatMap(() => { return inner; }); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return a silenced version of the source if the mapped inner is empty', () => { + const e1 = cold( '--a-b--c-| '); + const e1subs = '^ ! '; + const inner = cold('|'); + const innersubs = [' (^!) ', + ' (^!) ', + ' (^!)']; + const expected = '---------| '; + + const result = e1.concatMap(() => { return inner; }); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return a never if the mapped inner is never', () => { + const e1 = cold( '--a-b--c-|'); + const e1subs = '^ '; + const inner = cold('-'); + const innersubs = ' ^ '; + const expected = '----------'; + + const result = e1.concatMap(() => { return inner; }); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should propagate errors if the mapped inner is a just-throw Observable', () => { + const e1 = cold( '--a-b--c-|'); + const e1subs = '^ ! '; + const inner = cold('#'); + const innersubs = ' (^!) '; + const expected = '--# '; + + const result = e1.concatMap(() => { return inner; }); + + expectObservable(result).toBe(expected); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to many inner, complete late', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d----------------------------------|'); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l--------|'; + + const result = e1.concatMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to many inner, outer never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d-----------------------------------'); + const e1subs = '^ '; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l---------'; + + const result = e1.concatMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to many inner, inner never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---|'); + const e1subs = '^ '; + const inner = cold('--i-j-k-l- ', values); + const innersubs = ' ^ '; + const expected = '---i-j-k-l--------'; + + const result = e1.concatMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to many inner, and inner throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---|'); + const e1subs = '^ ! '; + const inner = cold('--i-j-k-l-# ', values); + const innersubs = ' ^ ! '; + const expected = '---i-j-k-l-# '; + + const result = e1.concatMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to many inner, and outer throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---#'); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ !']; + const expected = '---i-j-k-l---i-j-#'; + + const result = e1.concatMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to many inner, both inner and outer throw', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---#'); + const e1subs = '^ ! '; + const inner = cold('--i-j-k-l-# ', values); + const innersubs = ' ^ ! '; + const expected = '---i-j-k-l-# '; + + const result = e1.concatMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, where all inners are finite', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = ' ^ ! '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = ' ^ ! '; + const f = cold( '--| '); + const fsubs = ' ^ ! '; + const g = cold( '---1-2|'); + const gsubs = ' ^ !'; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); + const e1subs = '^ !'; + const expected = '---2--3--4--5----6-----2--3-1------2--3-4-5--------1-2|'; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, all inners finite except one', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3- '); + const dsubs = ' ^ '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = []; + const f = cold( '--| '); + const fsubs = []; + const g = cold( '---1-2|'); + const gsubs = []; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); + const e1subs = '^ '; + const expected = '---2--3--4--5----6-----2--3----------------------------'; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, inners finite, outer does not complete', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = ' ^ ! '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = ' ^ ! '; + const f = cold( '--| '); + const fsubs = ' ^ ! '; + const g = cold( '---1-2|'); + const gsubs = ' ^ !'; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g--- '); + const e1subs = '^ '; + const expected = '---2--3--4--5----6-----2--3-1------2--3-4-5--------1-2-'; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, all inners finite, and outer throws', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = ' ^ ! '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = ' ^ ! '; + const f = cold( '--| '); + const fsubs = []; + const g = cold( '---1-2|'); + const gsubs = []; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g# '); + const e1subs = '^ ! '; + const expected = '---2--3--4--5----6-----2--3-1------2--3# '; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, all inners complete except one throws', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-# '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = []; + const e = cold( '-1------2--3-4-5---| '); + const esubs = []; + const f = cold( '--| '); + const fsubs = []; + const g = cold( '---1-2|'); + const gsubs = []; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); + const e1subs = '^ ! '; + const expected = '---2--3--4--5----6-# '; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, all inners finite, outer is unsubscribed early', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = ' ^ ! '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = ' ^ ! '; + const f = cold( '--| '); + const fsubs = []; + const g = cold( '---1-2|'); + const gsubs = []; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); + const e1subs = '^ ! '; + const unsub = ' ! '; + const expected = '---2--3--4--5----6-----2--3-1-- '; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: any) => observableLookup[value]); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = ' ^ ! '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = ' ^ ! '; + const f = cold( '--| '); + const fsubs = []; + const g = cold( '---1-2|'); + const gsubs = []; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); + const e1subs = '^ ! '; + const unsub = ' ! '; + const expected = '---2--3--4--5----6-----2--3-1-- '; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .concatMap((value: any) => observableLookup[value]) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many complex, all inners finite, project throws', () => { + const a = cold( '-# '); + const asubs = []; + const b = cold( '-# '); + const bsubs = []; + const c = cold( '-2--3--4--5----6-| '); + const csubs = ' ^ ! '; + const d = cold( '----2--3| '); + const dsubs = ' ^ ! '; + const e = cold( '-1------2--3-4-5---| '); + const esubs = []; + const f = cold( '--| '); + const fsubs = []; + const g = cold( '---1-2|'); + const gsubs = []; + const e1 = hot('-a-b--^-c-----d------e----------------f-----g| '); + const e1subs = '^ ! '; + const expected = '---2--3--4--5----6-----2--3# '; + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.concatMap((value: string) => { + if (value === 'e') { throw 'error'; } + return observableLookup[value]; + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + expectSubscriptions(c.subscriptions).toBe(csubs); + expectSubscriptions(d.subscriptions).toBe(dsubs); + expectSubscriptions(e.subscriptions).toBe(esubs); + expectSubscriptions(f.subscriptions).toBe(fsubs); + expectSubscriptions(g.subscriptions).toBe(gsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + function arrayRepeat(value, times) { + let results = []; + for (let i = 0; i < times; i++) { + results.push(value); + } + return results; + } + + it('should concatMap many outer to an array for each value', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(22)--(4444)---(333)----(22)----|'; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value))); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, using resultSelector', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(44)--(8888)---(666)----(44)----|'; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value)), + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, and outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const e1subs = '^ !'; + const expected = '(22)--(4444)---(333)----(22)----#'; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value))); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, resultSelector, outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const e1subs = '^ !'; + const expected = '(44)--(8888)---(666)----(44)----#'; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value)), + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, outer unsubscribed early', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const unsub = ' ! '; + const expected = '(22)--(4444)-- '; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value))); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, resultSelector, outer unsubscribed', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const unsub = ' ! '; + const expected = '(44)--(8888)-- '; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value)), + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, project throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const expected = '(22)--(4444)---# '; + + let invoked = 0; + const result = e1.concatMap(((value: any) => { + invoked++; + if (invoked === 3) { + throw 'error'; + } + return arrayRepeat(value, value); + })); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, resultSelector throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const expected = '(44)--(8888)---# '; + + const result = e1.concatMap(((value: any) => arrayRepeat(value, value)), + (inner: any, outer: any) => { + if (outer === '3') { + throw 'error'; + } + return String(parseInt(outer) + parseInt(inner)); + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should concatMap many outer to inner arrays, resultSelector, project throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const expected = '(44)--(8888)---# '; + + let invoked = 0; + const result = e1.concatMap(((value: any) => { + invoked++; + if (invoked === 3) { + throw 'error'; + } + return arrayRepeat(value, value); + }), (inner: string, outer: string) => { + return String(parseInt(outer) + parseInt(inner)); + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should map values to constant resolved promises and concatenate', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = (value: any) => Observable.from(Promise.resolve(42)); + + const results = []; + source.concatMap(project).subscribe( + (x: any) => { + results.push(x); + }, (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, () => { + expect(results).toEqual([42,42,42,42]); + done(); + }); + }); + + it('should map values to constant rejected promises and concatenate', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = (value: any) => Observable.from(Promise.reject(42)); + + source.concatMap(project).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, (err: any) => { + expect(err).toEqual(42); + done(); + }, () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should map values to resolved promises and concatenate', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = (value: number, index: number) => Observable.from(Promise.resolve(value + index)); + + const results = []; + source.concatMap(project).subscribe( + (x: any) => { + results.push(x); + }, (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, () => { + expect(results).toEqual([4,4,4,4]); + done(); + }); + }); + + it('should map values to rejected promises and concatenate', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = (value: number, index: number) => Observable.from(Promise.reject('' + value + '-' + index)); + + source.concatMap(project).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, (err: any) => { + expect(err).toEqual('4-0'); + done(); + }, () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should concatMap values to resolved promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const resultSelectorCalledWith = []; + const project = (value: number, index: number) => Observable.from((Promise.resolve([value, index]))); + + const resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { + resultSelectorCalledWith.push([].slice.call(arguments)); + return 8; + }; + + const results = []; + const expectedCalls = [ + [4, [4,0], 0, 0], + [3, [3,1], 1, 0], + [2, [2,2], 2, 0], + [1, [1,3], 3, 0] + ]; + source.concatMap(project, resultSelector).subscribe( + (x: any) => { + results.push(x); + }, (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, () => { + expect(results).toEqual([8,8,8,8]); + (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); + done(); + }); + }); + + it('should concatMap values to rejected promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = (value: number, index: number) => Observable.from(Promise.reject('' + value + '-' + index)); + + const resultSelector = () => { + throw 'this should not be called'; + }; + + source.concatMap(project, resultSelector).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, (err: any) => { + expect(err).toEqual('4-0'); + done(); + }, () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); +}); \ No newline at end of file diff --git a/spec/operators/concatMapTo-spec.js b/spec/operators/concatMapTo-spec.js deleted file mode 100644 index 65a215f905..0000000000 --- a/spec/operators/concatMapTo-spec.js +++ /dev/null @@ -1,386 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.concatMapTo()', function () { - it('should concatMapTo many outer values to many inner values', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---| '); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should handle an empty source', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var inner = cold('-1-2-3|'); - var innersubs = []; - var expected = '|'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should handle a never source', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var inner = cold('-1-2-3|'); - var innersubs = []; - var expected = '-'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should error immediately if given a just-throw source', function () { - var e1 = cold( '#'); - var e1subs = '(^!)'; - var inner = cold('-1-2-3|'); - var innersubs = []; - var expected = '#'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should return a silenced version of the source if the mapped inner is empty', function () { - var e1 = cold('--a-b--c-|'); - var e1subs = '^ !'; - var inner = cold('|'); - var innersubs = [' (^!) ', - ' (^!) ', - ' (^!)']; - var expected = '---------|'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should return a never if the mapped inner is never', function () { - var e1 = cold('--a-b--c-|'); - var e1subs = '^ '; - var inner = cold('-'); - var innersubs = ' ^ '; - var expected = '----------'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should propagate errors if the mapped inner is a just-throw Observable', function () { - var e1 = cold('--a-b--c-|'); - var e1subs = '^ ! '; - var inner = cold('#'); - var innersubs = ' (^!) '; - var expected = '--#'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to many inner, complete late', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d----------------------------------|'); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l--------|'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to many inner, outer never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d-----------------------------------'); - var e1subs = '^ '; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l---------'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---| '); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ !']; - var expected = '---i-j-k-l---i-j-k-'; - var unsub = ' !'; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .concatMapTo(inner) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to many inner, inner never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---|'); - var e1subs = '^ '; - var inner = cold('--i-j-k-l- ', values); - var innersubs = ' ^ '; - var expected = '---i-j-k-l--------'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to many inner, and inner throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---|'); - var e1subs = '^ ! '; - var inner = cold('--i-j-k-l-# ', values); - var innersubs = ' ^ ! '; - var expected = '---i-j-k-l-# '; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to many inner, and outer throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---#'); - var e1subs = '^ !'; - var inner = cold('--i-j-k-l-| ', values); - var innersubs = [' ^ ! ', - ' ^ !']; - var expected = '---i-j-k-l---i-j-#'; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to many inner, both inner and outer throw', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a---b---c---d---#'); - var e1subs = '^ ! '; - var inner = cold('--i-j-k-l-# ', values); - var innersubs = ' ^ ! '; - var expected = '---i-j-k-l-# '; - - var result = e1.concatMapTo(inner); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - }); - - it('should concatMapTo many outer to an array', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var expected = '(0123)(0123)---(0123)---(0123)--|'; - - var result = e1.concatMapTo(['0', '1', '2', '3']); - - expectObservable(result).toBe(expected); - }); - - it('should concatMapTo many outer to inner arrays, using resultSelector', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var expected = '(2345)(4567)---(3456)---(2345)--|'; - - var result = e1.concatMapTo(['0', '1', '2', '3'], function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result).toBe(expected); - }); - - it('should concatMapTo many outer to inner arrays, and outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var expected = '(0123)(0123)---(0123)---(0123)--#'; - - var result = e1.concatMapTo(['0', '1', '2', '3']); - - expectObservable(result).toBe(expected); - }); - - it('should concatMapTo many outer to inner arrays, resultSelector, outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var expected = '(2345)(4567)---(3456)---(2345)--#'; - - var result = e1.concatMapTo(['0', '1', '2', '3'], function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result).toBe(expected); - }); - - it('should mergeMap many outer to inner arrays, outer unsubscribed early', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var unsub = ' !'; - var expected = '(0123)(0123)--'; - - var result = e1.concatMapTo(['0', '1', '2', '3']); - - expectObservable(result, unsub).toBe(expected); - }); - - it('should concatMapTo many outer to inner arrays, resultSelector, outer unsubscribed', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var unsub = ' !'; - var expected = '(2345)(4567)--'; - - var result = e1.concatMapTo(['0', '1', '2', '3'], function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result, unsub).toBe(expected); - }); - - it('should concatMapTo many outer to inner arrays, resultSelector throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var expected = '(2345)(4567)---#'; - - var result = e1.concatMapTo(['0', '1', '2', '3'], function (x, y) { - if (x === '3') { - throw 'error'; - } - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(result).toBe(expected); - }); - - it('should map values to constant resolved promises and concatenate', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - - var results = []; - source.concatMapTo(Observable.from(Promise.resolve(42))).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([42,42,42,42]); - done(); - }); - }); - - it('should map values to constant rejected promises and concatenate', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - - source.concatMapTo(Observable.from(Promise.reject(42))).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual(42); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should concatMapTo values to resolved promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var resultSelectorCalledWith = []; - var inner = Observable.from(Promise.resolve(42)); - var resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { - resultSelectorCalledWith.push([].slice.call(arguments)); - return 8; - }; - - var results = []; - var expectedCalls = [ - [4, 42, 0, 0], - [3, 42, 1, 0], - [2, 42, 2, 0], - [1, 42, 3, 0] - ]; - source.concatMapTo(inner, resultSelector).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([8,8,8,8]); - expect(resultSelectorCalledWith).toDeepEqual(expectedCalls); - done(); - }); - }); - - it('should concatMapTo values to rejected promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var inner = Observable.from(Promise.reject(42)); - var resultSelector = function () { - throw 'this should not be called'; - }; - - source.concatMapTo(inner, resultSelector).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual(42); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); -}); \ No newline at end of file diff --git a/spec/operators/concatMapTo-spec.ts b/spec/operators/concatMapTo-spec.ts new file mode 100644 index 0000000000..2016b7ee52 --- /dev/null +++ b/spec/operators/concatMapTo-spec.ts @@ -0,0 +1,384 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.concatMapTo()', () => { + it('should concatMapTo many outer values to many inner values', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---| '); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should handle an empty source', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const inner = cold('-1-2-3|'); + const innersubs = []; + const expected = '|'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should handle a never source', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const inner = cold('-1-2-3|'); + const innersubs = []; + const expected = '-'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should error immediately if given a just-throw source', () => { + const e1 = cold( '#'); + const e1subs = '(^!)'; + const inner = cold('-1-2-3|'); + const innersubs = []; + const expected = '#'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should return a silenced version of the source if the mapped inner is empty', () => { + const e1 = cold('--a-b--c-|'); + const e1subs = '^ !'; + const inner = cold('|'); + const innersubs = [' (^!) ', + ' (^!) ', + ' (^!)']; + const expected = '---------|'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should return a never if the mapped inner is never', () => { + const e1 = cold('--a-b--c-|'); + const e1subs = '^ '; + const inner = cold('-'); + const innersubs = ' ^ '; + const expected = '----------'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should propagate errors if the mapped inner is a just-throw Observable', () => { + const e1 = cold('--a-b--c-|'); + const e1subs = '^ ! '; + const inner = cold('#'); + const innersubs = ' (^!) '; + const expected = '--#'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to many inner, complete late', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d----------------------------------|'); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l--------|'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to many inner, outer never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d-----------------------------------'); + const e1subs = '^ '; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l---------'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---| '); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ !']; + const expected = '---i-j-k-l---i-j-k-'; + const unsub = ' !'; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .concatMapTo(inner) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to many inner, inner never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---|'); + const e1subs = '^ '; + const inner = cold('--i-j-k-l- ', values); + const innersubs = ' ^ '; + const expected = '---i-j-k-l--------'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to many inner, and inner throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---|'); + const e1subs = '^ ! '; + const inner = cold('--i-j-k-l-# ', values); + const innersubs = ' ^ ! '; + const expected = '---i-j-k-l-# '; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to many inner, and outer throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---#'); + const e1subs = '^ !'; + const inner = cold('--i-j-k-l-| ', values); + const innersubs = [' ^ ! ', + ' ^ !']; + const expected = '---i-j-k-l---i-j-#'; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to many inner, both inner and outer throw', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a---b---c---d---#'); + const e1subs = '^ ! '; + const inner = cold('--i-j-k-l-# ', values); + const innersubs = ' ^ ! '; + const expected = '---i-j-k-l-# '; + + const result = e1.concatMapTo(inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + }); + + it('should concatMapTo many outer to an array', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const expected = '(0123)(0123)---(0123)---(0123)--|'; + + const result = e1.concatMapTo(['0', '1', '2', '3']); + + expectObservable(result).toBe(expected); + }); + + it('should concatMapTo many outer to inner arrays, using resultSelector', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const expected = '(2345)(4567)---(3456)---(2345)--|'; + + const result = e1.concatMapTo(['0', '1', '2', '3'], + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(result).toBe(expected); + }); + + it('should concatMapTo many outer to inner arrays, and outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const expected = '(0123)(0123)---(0123)---(0123)--#'; + + const result = e1.concatMapTo(['0', '1', '2', '3']); + + expectObservable(result).toBe(expected); + }); + + it('should concatMapTo many outer to inner arrays, resultSelector, outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const expected = '(2345)(4567)---(3456)---(2345)--#'; + + const result = e1.concatMapTo(['0', '1', '2', '3'], + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(result).toBe(expected); + }); + + it('should mergeMap many outer to inner arrays, outer unsubscribed early', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const unsub = ' !'; + const expected = '(0123)(0123)--'; + + const result = e1.concatMapTo(['0', '1', '2', '3']); + + expectObservable(result, unsub).toBe(expected); + }); + + it('should concatMapTo many outer to inner arrays, resultSelector, outer unsubscribed', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const unsub = ' !'; + const expected = '(2345)(4567)--'; + + const result = e1.concatMapTo(['0', '1', '2', '3'], + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(result, unsub).toBe(expected); + }); + + it('should concatMapTo many outer to inner arrays, resultSelector throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const expected = '(2345)(4567)---#'; + + const result = e1.concatMapTo(['0', '1', '2', '3'], (x: string, y: string) => { + if (x === '3') { + throw 'error'; + } + return String(parseInt(x) + parseInt(y)); + }); + + expectObservable(result).toBe(expected); + }); + + it('should map values to constant resolved promises and concatenate', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + + const results = []; + source.concatMapTo(Observable.from(Promise.resolve(42))).subscribe( + (x: any) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([42,42,42,42]); + done(); + }); + }); + + it('should map values to constant rejected promises and concatenate', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + + source.concatMapTo(Observable.from(Promise.reject(42))).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual(42); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should concatMapTo values to resolved promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const resultSelectorCalledWith = []; + const inner = Observable.from(Promise.resolve(42)); + const resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { + resultSelectorCalledWith.push([].slice.call(arguments)); + return 8; + }; + + const results = []; + const expectedCalls = [ + [4, 42, 0, 0], + [3, 42, 1, 0], + [2, 42, 2, 0], + [1, 42, 3, 0] + ]; + source.concatMapTo(inner, resultSelector).subscribe( + (x: any) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([8,8,8,8]); + (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); + done(); + }); + }); + + it('should concatMapTo values to rejected promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const inner = Observable.from(Promise.reject(42)); + const resultSelector = () => { + throw 'this should not be called'; + }; + + source.concatMapTo(inner, resultSelector).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual(42); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); +}); \ No newline at end of file diff --git a/spec/operators/count-spec.js b/spec/operators/count-spec.js deleted file mode 100644 index 65e330e0b1..0000000000 --- a/spec/operators/count-spec.js +++ /dev/null @@ -1,266 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('count', function () { - it.asDiagram('count')('should count the values of an observable', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.count()).toBe(expected, {x: 3}); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should be never when source is never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.count()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be zero when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(w|)'; - - expectObservable(e1.count()).toBe(expected, { w: 0 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be never when source doesn\'t complete', function () { - var e1 = hot('--x--^--y--'); - var e1subs = '^ '; - var expected = '------'; - - expectObservable(e1.count()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be zero when source doesn\'t have values', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----(w|)'; - - expectObservable(e1.count()).toBe(expected, { w: 0 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should count the unique value of an observable', function () { - var e1 = hot('-x-^--y--|'); - var e1subs = '^ !'; - var expected = '------(w|)'; - - expectObservable(e1.count()).toBe(expected, { w: 1 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should count the values of an ongoing hot observable', function () { - var source = hot('--a-^-b--c--d--|'); - var subs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.count()).toBe(expected, {x: 3}); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should count a range() source observable', function (done) { - Rx.Observable.range(1, 10).count().subscribe( - function (value) { - expect(value).toEqual(10); - }, - done.fail, - done - ); - }); - - it('should count a range().skip(1) source observable', function (done) { - Rx.Observable.range(1, 10).skip(1).count().subscribe( - function (value) { - expect(value).toEqual(9); - }, - done.fail, - done - ); - }); - - it('should count a range().take(1) source observable', function (done) { - Rx.Observable.range(1, 10).take(1).count().subscribe( - function (value) { - expect(value).toEqual(1); - }, - done.fail, - done - ); - }); - - it('should work with error', function () { - var e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); - var e1subs = '^ !'; - var expected = '---------#'; - - expectObservable(e1.count()).toBe(expected, null, 'too bad'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.count()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-true predicate on an empty hot observable', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----(w|)'; - var predicate = function () { - return true; - }; - - expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-false predicate on an empty hot observable', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----(w|)'; - var predicate = function () { - return false; - }; - - expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-true predicate on a simple hot observable', function () { - var e1 = hot('-x-^-a-|'); - var e1subs = '^ !'; - var expected = '----(w|)'; - var predicate = function () { - return true; - }; - - expectObservable(e1.count(predicate)).toBe(expected, { w: 1 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-false predicate on a simple hot observable', function () { - var e1 = hot('-x-^-a-|'); - var e1subs = '^ !'; - var expected = '----(w|)'; - var predicate = function () { - return false; - }; - - expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('-1-^-2--3--4-|'); - var e1subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = e1.count(function (value) { return parseInt(value) < 10; }); - - expectObservable(result, unsub).toBe(expected, { w: 3 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-1-^-2--3--4-|'); - var e1subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .count(function (value) { return parseInt(value) < 10; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, { w: 3 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a match-all predicate on observable with many values', function () { - var e1 = hot('-1-^-2--3--4-|'); - var e1subs = '^ !'; - var expected = '----------(w|)'; - var predicate = function (value) { - return parseInt(value) < 10; - }; - - expectObservable(e1.count(predicate)).toBe(expected, { w: 3 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a match-none predicate on observable with many values', function () { - var e1 = hot('-1-^-2--3--4-|'); - var e1subs = '^ !'; - var expected = '----------(w|)'; - var predicate = function (value) { - return parseInt(value) > 10; - }; - - expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-true predicate on observable that throws', function () { - var e1 = hot('-1-^---#'); - var e1subs = '^ !'; - var expected = '----#'; - var predicate = function () { - return true; - }; - - expectObservable(e1.count(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-false predicate on observable that throws', function () { - var e1 = hot('-1-^---#'); - var e1subs = '^ !'; - var expected = '----#'; - var predicate = function () { - return false; - }; - - expectObservable(e1.count(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an always-true predicate on a hot never-observable', function () { - var e1 = hot('-x-^----'); - var e1subs = '^ '; - var expected = '-----'; - var predicate = function () { - return true; - }; - - expectObservable(e1.count(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate that throws, on observable with many values', function () { - var e1 = hot('-1-^-2--3--|'); - var e1subs = '^ ! '; - var expected = '-----# '; - var predicate = function (value) { - if (value === '3') { - throw 'error'; - } - return true; - }; - - expectObservable(e1.count(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/count-spec.ts b/spec/operators/count-spec.ts new file mode 100644 index 0000000000..033221f46e --- /dev/null +++ b/spec/operators/count-spec.ts @@ -0,0 +1,258 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('count', () => { + asDiagram('count')('should count the values of an observable', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable(source.count()).toBe(expected, {x: 3}); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should be never when source is never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.count()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be zero when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(w|)'; + + expectObservable(e1.count()).toBe(expected, { w: 0 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be never when source doesn\'t complete', () => { + const e1 = hot('--x--^--y--'); + const e1subs = '^ '; + const expected = '------'; + + expectObservable(e1.count()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be zero when source doesn\'t have values', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----(w|)'; + + expectObservable(e1.count()).toBe(expected, { w: 0 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should count the unique value of an observable', () => { + const e1 = hot('-x-^--y--|'); + const e1subs = '^ !'; + const expected = '------(w|)'; + + expectObservable(e1.count()).toBe(expected, { w: 1 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should count the values of an ongoing hot observable', () => { + const source = hot('--a-^-b--c--d--|'); + const subs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable(source.count()).toBe(expected, {x: 3}); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should count a range() source observable', (done: DoneSignature) => { + Rx.Observable.range(1, 10).count().subscribe( + (value: number) => { + expect(value).toEqual(10); + }, + done.fail, + done + ); + }); + + it('should count a range().skip(1) source observable', (done: DoneSignature) => { + Rx.Observable.range(1, 10).skip(1).count().subscribe( + (value: number) => { + expect(value).toEqual(9); + }, + done.fail, + done + ); + }); + + it('should count a range().take(1) source observable', (done: DoneSignature) => { + Rx.Observable.range(1, 10).take(1).count().subscribe( + (value: number) => { + expect(value).toEqual(1); + }, + done.fail, + done + ); + }); + + it('should work with error', () => { + const e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); + const e1subs = '^ !'; + const expected = '---------#'; + + expectObservable(e1.count()).toBe(expected, null, 'too bad'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.count()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-true predicate on an empty hot observable', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----(w|)'; + const predicate = () => { + return true; + }; + + expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-false predicate on an empty hot observable', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----(w|)'; + const predicate = () => { + return false; + }; + + expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-true predicate on a simple hot observable', () => { + const e1 = hot('-x-^-a-|'); + const e1subs = '^ !'; + const expected = '----(w|)'; + const predicate = () => { + return true; + }; + + expectObservable(e1.count(predicate)).toBe(expected, { w: 1 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-false predicate on a simple hot observable', () => { + const e1 = hot('-x-^-a-|'); + const e1subs = '^ !'; + const expected = '----(w|)'; + const predicate = () => { + return false; + }; + + expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('-1-^-2--3--4-|'); + const e1subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = e1.count((value: string) => parseInt(value) < 10); + + expectObservable(result, unsub).toBe(expected, { w: 3 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-1-^-2--3--4-|'); + const e1subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .count((value: string) => parseInt(value) < 10) + .mergeMap((x: number) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, { w: 3 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a match-all predicate on observable with many values', () => { + const e1 = hot('-1-^-2--3--4-|'); + const e1subs = '^ !'; + const expected = '----------(w|)'; + const predicate = (value: string) => parseInt(value) < 10; + + expectObservable(e1.count(predicate)).toBe(expected, { w: 3 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a match-none predicate on observable with many values', () => { + const e1 = hot('-1-^-2--3--4-|'); + const e1subs = '^ !'; + const expected = '----------(w|)'; + const predicate = (value: string) => parseInt(value) > 10; + + expectObservable(e1.count(predicate)).toBe(expected, { w: 0 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-true predicate on observable that throws', () => { + const e1 = hot('-1-^---#'); + const e1subs = '^ !'; + const expected = '----#'; + const predicate = () => true; + + expectObservable(e1.count(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-false predicate on observable that throws', () => { + const e1 = hot('-1-^---#'); + const e1subs = '^ !'; + const expected = '----#'; + const predicate = () => false; + + expectObservable(e1.count(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an always-true predicate on a hot never-observable', () => { + const e1 = hot('-x-^----'); + const e1subs = '^ '; + const expected = '-----'; + const predicate = () => true; + + expectObservable(e1.count(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate that throws, on observable with many values', () => { + const e1 = hot('-1-^-2--3--|'); + const e1subs = '^ ! '; + const expected = '-----# '; + const predicate = (value: string) => { + if (value === '3') { + throw 'error'; + } + return true; + }; + + expectObservable(e1.count(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/debounce-spec.js b/spec/operators/debounce-spec.ts similarity index 50% rename from spec/operators/debounce-spec.js rename to spec/operators/debounce-spec.ts index c912cfa250..e841dddf48 100644 --- a/spec/operators/debounce-spec.js +++ b/spec/operators/debounce-spec.ts @@ -1,270 +1,270 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; -describe('Observable.prototype.debounce()', function () { +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.debounce()', () => { function getTimerSelector(x) { - return function () { - return Observable.timer(x, rxTestScheduler); - }; + return () => Observable.timer(x, rxTestScheduler); } - it.asDiagram('debounce')('should debounce values by a specified cold Observable', function () { - var e1 = hot('-a--bc--d---|'); - var e2 = cold('--| '); - var expected = '---a---c--d-|'; + asDiagram('debounce')('should debounce values by a specified cold Observable', () => { + const e1 = hot('-a--bc--d---|'); + const e2 = cold('--| '); + const expected = '---a---c--d-|'; - var result = e1.debounce(function () { return e2; }); + const result = e1.debounce(() => e2); expectObservable(result).toBe(expected); }); - it('should delay all element by selector observable', function () { - var e1 = hot('--a--b--c--d---------|'); - var e1subs = '^ !'; - var expected = '----a--b--c--d-------|'; + it('should delay all element by selector observable', () => { + const e1 = hot('--a--b--c--d---------|'); + const e1subs = '^ !'; + const expected = '----a--b--c--d-------|'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should debounce by selector observable', function () { - var e1 = hot('--a--bc--d----|'); - var e1subs = '^ !'; - var expected = '----a---c--d--|'; + it('should debounce by selector observable', () => { + const e1 = hot('--a--bc--d----|'); + const e1subs = '^ !'; + const expected = '----a---c--d--|'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should complete when source does not emit', function () { - var e1 = hot('-----|'); - var e1subs = '^ !'; - var expected = '-----|'; + it('should complete when source does not emit', () => { + const e1 = hot('-----|'); + const e1subs = '^ !'; + const expected = '-----|'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should complete when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; + it('should complete when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should raise error when source does not emit and raises error', function () { - var e1 = hot('-----#'); - var e1subs = '^ !'; - var expected = '-----#'; + it('should raise error when source does not emit and raises error', () => { + const e1 = hot('-----#'); + const e1subs = '^ !'; + const expected = '-----#'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should raise error when source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; + it('should raise error when source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--bc--d----|'); - var e1subs = '^ ! '; - var expected = '----a--- '; - var unsub = ' ! '; + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--bc--d----|'); + const e1subs = '^ ! '; + const expected = '----a--- '; + const unsub = ' ! '; - var result = e1.debounce(getTimerSelector(20)); + const result = e1.debounce(getTimerSelector(20)); expectObservable(result, unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--bc--d----|'); - var e1subs = '^ ! '; - var expected = '----a--- '; - var unsub = ' ! '; + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--bc--d----|'); + const e1subs = '^ ! '; + const expected = '----a--- '; + const unsub = ' ! '; - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) + const result = e1 + .mergeMap((x: any) => Observable.of(x)) .debounce(getTimerSelector(20)) - .mergeMap(function (x) { return Observable.of(x); }); + .mergeMap((x: any) => Observable.of(x)); expectObservable(result, unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should debounce and does not complete when source does not completes', function () { - var e1 = hot('--a--bc--d---'); - var e1subs = '^ '; - var expected = '----a---c--d-'; + it('should debounce and does not complete when source does not completes', () => { + const e1 = hot('--a--bc--d---'); + const e1subs = '^ '; + const expected = '----a---c--d-'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should not completes when source does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; + it('should not completes when source does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should not completes when source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; + it('should not completes when source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should delay all element until source raises error', function () { - var e1 = hot('--a--b--c--d---------#'); - var e1subs = '^ !'; - var expected = '----a--b--c--d-------#'; + it('should delay all element until source raises error', () => { + const e1 = hot('--a--b--c--d---------#'); + const e1subs = '^ !'; + const expected = '----a--b--c--d-------#'; expectObservable(e1.debounce(getTimerSelector(20))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should debounce all elements while source emits by selector observable', function () { - var e1 = hot('---a---b---c---d---e|'); - var e1subs = '^ !'; - var expected = '--------------------(e|)'; + it('should debounce all elements while source emits by selector observable', () => { + const e1 = hot('---a---b---c---d---e|'); + const e1subs = '^ !'; + const expected = '--------------------(e|)'; expectObservable(e1.debounce(getTimerSelector(40))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should debounce all element while source emits by selector observable until raises error', function () { - var e1 = hot('--a--b--c--d-#'); - var e1subs = '^ !'; - var expected = '-------------#'; + it('should debounce all element while source emits by selector observable until raises error', () => { + const e1 = hot('--a--b--c--d-#'); + const e1subs = '^ !'; + const expected = '-------------#'; expectObservable(e1.debounce(getTimerSelector(50))).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should delay element by same selector observable emits multiple', function () { - var e1 = hot('----a--b--c----d----e-------|'); - var e1subs = '^ !'; - var expected = '------a--b--c----d----e-----|'; - var selector = cold('--x-y-'); - var selectorSubs = + it('should delay element by same selector observable emits multiple', () => { + const e1 = hot('----a--b--c----d----e-------|'); + const e1subs = '^ !'; + const expected = '------a--b--c----d----e-----|'; + const selector = cold('--x-y-'); + const selectorSubs = [' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ']; - expectObservable(e1.debounce(function () { return selector; })).toBe(expected); + expectObservable(e1.debounce(() => selector)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); expectSubscriptions(selector.subscriptions).toBe(selectorSubs); }); - it('should debounce by selector observable emits multiple', function () { - var e1 = hot('----a--b--c----d----e-------|'); - var e1subs = '^ !'; - var expected = '------a-----c---------e-----|'; - var selector = [cold('--x-y-'), + it('should debounce by selector observable emits multiple', () => { + const e1 = hot('----a--b--c----d----e-------|'); + const e1subs = '^ !'; + const expected = '------a-----c---------e-----|'; + const selector = [cold('--x-y-'), cold( '----x-y-'), cold( '--x-y-'), cold( '------x-y-'), cold( '--x-y-')]; - var selectorSubs = + const selectorSubs = [' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ']; - expectObservable(e1.debounce(function () { return selector.shift(); })).toBe(expected); + expectObservable(e1.debounce(() => selector.shift())).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should debounce by selector observable until source completes', function () { - var e1 = hot('----a--b--c----d----e|'); - var e1subs = '^ !'; - var expected = '------a-----c--------(e|)'; - var selector = [cold('--x-y-'), + it('should debounce by selector observable until source completes', () => { + const e1 = hot('----a--b--c----d----e|'); + const e1subs = '^ !'; + const expected = '------a-----c--------(e|)'; + const selector = [cold('--x-y-'), cold( '----x-y-'), cold( '--x-y-'), cold( '------x-y-'), cold( '--x-y-')]; - var selectorSubs = + const selectorSubs = [' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^!']; - expectObservable(e1.debounce(function () { return selector.shift(); })).toBe(expected); + expectObservable(e1.debounce(() => selector.shift())).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should raise error when selector observable raises error', function () { - var e1 = hot('--------a--------b--------c---------|'); - var e1subs = '^ !'; - var expected = '---------a---------b---------#'; - var selector = [cold( '-x-y-'), + it('should raise error when selector observable raises error', () => { + const e1 = hot('--------a--------b--------c---------|'); + const e1subs = '^ !'; + const expected = '---------a---------b---------#'; + const selector = [cold( '-x-y-'), cold( '--x-y-'), cold( '---#')]; - var selectorSubs = + const selectorSubs = [' ^! ', ' ^ ! ', ' ^ !']; - expectObservable(e1.debounce(function () { return selector.shift(); })).toBe(expected); + expectObservable(e1.debounce(() => selector.shift())).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should raise error when source raises error with selector observable', function () { - var e1 = hot('--------a--------b--------c---------d#'); - var e1subs = '^ !'; - var expected = '---------a---------b---------c-------#'; - var selector = [cold( '-x-y-'), + it('should raise error when source raises error with selector observable', () => { + const e1 = hot('--------a--------b--------c---------d#'); + const e1subs = '^ !'; + const expected = '---------a---------b---------c-------#'; + const selector = [cold( '-x-y-'), cold( '--x-y-'), cold( '---x-y-'), cold( '----x-y-')]; - var selectorSubs = + const selectorSubs = [' ^! ', ' ^ ! ', ' ^ ! ', ' ^!']; - expectObservable(e1.debounce(function () { return selector.shift(); })).toBe(expected); + expectObservable(e1.debounce(() => selector.shift())).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should raise error when selector function throws', function () { - var e1 = hot('--------a--------b--------c---------|'); - var e1subs = '^ !'; - var expected = '---------a---------b------#'; - var selector = [cold( '-x-y-'), + it('should raise error when selector function throws', () => { + const e1 = hot('--------a--------b--------c---------|'); + const e1subs = '^ !'; + const expected = '---------a---------b------#'; + const selector = [cold( '-x-y-'), cold( '--x-y-')]; - var selectorSubs = + const selectorSubs = [' ^! ', ' ^ ! ']; @@ -278,118 +278,115 @@ describe('Observable.prototype.debounce()', function () { expectObservable(e1.debounce(selectorFunction)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should mirror the source when given an empty selector Observable', function () { - var e1 = hot('--------a-x-yz---bxy---z--c--x--y--z|'); - var e1subs = '^ !'; - var expected = '--------a-x-yz---bxy---z--c--x--y--z|'; + it('should mirror the source when given an empty selector Observable', () => { + const e1 = hot('--------a-x-yz---bxy---z--c--x--y--z|'); + const e1subs = '^ !'; + const expected = '--------a-x-yz---bxy---z--c--x--y--z|'; - function selectorFunction(x) { return Observable.empty(); } + function selectorFunction(x) { return Observable.empty(); } expectObservable(e1.debounce(selectorFunction)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should ignore all values except last, when given a never selector Observable', function () { - var e1 = hot('--------a-x-yz---bxy---z--c--x--y--z|'); - var e1subs = '^ !'; - var expected = '------------------------------------(z|)'; + it('should ignore all values except last, when given a never selector Observable', () => { + const e1 = hot('--------a-x-yz---bxy---z--c--x--y--z|'); + const e1subs = '^ !'; + const expected = '------------------------------------(z|)'; - function selectorFunction(x) { return Observable.never(); } + function selectorFunction(x) { return Observable.never(); } expectObservable(e1.debounce(selectorFunction)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should delay element by selector observable completes when it does not emits', function () { - var e1 = hot('--------a--------b--------c---------|'); - var e1subs = '^ !'; - var expected = '---------a---------b---------c------|'; - var selector = [cold( '-|'), + it('should delay element by selector observable completes when it does not emits', () => { + const e1 = hot('--------a--------b--------c---------|'); + const e1subs = '^ !'; + const expected = '---------a---------b---------c------|'; + const selector = [cold( '-|'), cold( '--|'), cold( '---|')]; - var selectorSubs = + const selectorSubs = [' ^! ', ' ^ ! ', ' ^ ! ']; - expectObservable(e1.debounce(function () { return selector.shift(); })).toBe(expected); + expectObservable(e1.debounce(() => selector.shift())).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should debounce by selector observable completes when it does not emits', function () { - var e1 = hot('----a--b-c---------de-------------|'); - var e1subs = '^ !'; - var expected = '-----a------c------------e--------|'; - var selector = [cold('-|'), + it('should debounce by selector observable completes when it does not emits', () => { + const e1 = hot('----a--b-c---------de-------------|'); + const e1subs = '^ !'; + const expected = '-----a------c------------e--------|'; + const selector = [cold('-|'), cold( '--|'), cold( '---|'), cold( '----|'), cold( '-----|')]; - var selectorSubs = + const selectorSubs = [' ^! ', ' ^ ! ', ' ^ ! ', ' ^! ', ' ^ ! ']; - expectObservable(e1.debounce(function () { return selector.shift(); })).toBe(expected); + expectObservable(e1.debounce(() => selector.shift())).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var i = 0; i < selectorSubs.length; i++) { + for (let i = 0; i < selectorSubs.length; i++) { expectSubscriptions(selector[i].subscriptions).toBe(selectorSubs[i]); } }); - it('should delay by promise resolves', function (done) { - var e1 = Observable.concat(Observable.of(1), + it('should delay by promise resolves', (done: DoneSignature) => { + const e1 = Observable.concat(Observable.of(1), Observable.timer(10).mapTo(2), Observable.timer(10).mapTo(3), Observable.timer(100).mapTo(4) ); - var expected = [1,2,3,4]; + const expected = [1,2,3,4]; - e1.debounce(function () { - return new Promise(function (resolve) { resolve(42); }); - }).subscribe(function (x) { + e1.debounce(() => { + return new Promise((resolve: any) => { resolve(42); }); + }).subscribe((x: number) => { expect(x).toEqual(expected.shift()); }, - function () { throw 'should not be called'; }, - function () { + done.fail, + () => { expect(expected.length).toBe(0); done(); }); }); - it('should raises error when promise rejects', function (done) { - var e1 = Observable.concat(Observable.of(1), + it('should raises error when promise rejects', (done: DoneSignature) => { + const e1 = Observable.concat(Observable.of(1), Observable.timer(10).mapTo(2), Observable.timer(10).mapTo(3), Observable.timer(100).mapTo(4) ); - var expected = [1,2]; - var error = new Error('error'); + const expected = [1,2]; + const error = new Error('error'); - e1.debounce(function (x) { + e1.debounce((x: number) => { if (x === 3) { - return new Promise(function (resolve, reject) {reject(error);}); + return new Promise((resolve: any, reject: any) => {reject(error);}); } else { - return new Promise(function (resolve) {resolve(42);}); + return new Promise((resolve: any) => {resolve(42);}); } - }).subscribe(function (x) { + }).subscribe((x: number) => { expect(x).toEqual(expected.shift()); }, - function (err) { + (err: any) => { expect(err).toBe(error); expect(expected.length).toBe(0); done(); - }, - function () { - throw 'should not be called'; - }); + }, done.fail); }); }); \ No newline at end of file diff --git a/spec/operators/debounceTime-spec.js b/spec/operators/debounceTime-spec.js deleted file mode 100644 index 92778778b0..0000000000 --- a/spec/operators/debounceTime-spec.js +++ /dev/null @@ -1,147 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.debounceTime()', function () { - it.asDiagram('debounceTime(20)')('should debounce values by 20 time units', function () { - var e1 = hot('-a--bc--d---|'); - var expected = '---a---c--d-|'; - - expectObservable(e1.debounceTime(20, rxTestScheduler)).toBe(expected); - }); - - it('should delay all element by the specified time', function () { - var e1 = hot('-a--------b------c----|'); - var e1subs = '^ !'; - var expected = '------a--------b------(c|)'; - - expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should debounce and delay element by the specified time', function () { - var e1 = hot('-a--(bc)-----------d-------|'); - var e1subs = '^ !'; - var expected = '---------c--------------d--|'; - - expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete when source does not emit', function () { - var e1 = hot('-----|'); - var e1subs = '^ !'; - var expected = '-----|'; - - expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when source does not emit and raises error', function () { - var e1 = hot('-----#'); - var e1subs = '^ !'; - var expected = '-----#'; - - expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--bc--d----|'); - var e1subs = '^ ! '; - var expected = '----a--- '; - var unsub = ' ! '; - - var result = e1.debounceTime(20, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--bc--d----|'); - var e1subs = '^ ! '; - var expected = '----a--- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .debounceTime(20, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should debounce and does not complete when source does not completes', function () { - var e1 = hot('-a--(bc)-----------d-------'); - var e1subs = '^ '; - var expected = '---------c--------------d--'; - - expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes when source does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes when source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should delay all element until source raises error', function () { - var e1 = hot('-a--------b------c----#'); - var e1subs = '^ !'; - var expected = '------a--------b------#'; - - expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should debounce all elements while source emits within given time', function () { - var e1 = hot('--a--b--c--d--e--f--g--h-|'); - var e1subs = '^ !'; - var expected = '-------------------------(h|)'; - - expectObservable(e1.debounceTime(40, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should debounce all element while source emits within given time until raises error', function () { - var e1 = hot('--a--b--c--d--e--f--g--h-#'); - var e1subs = '^ !'; - var expected = '-------------------------#'; - - expectObservable(e1.debounceTime(40, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/debounceTime-spec.ts b/spec/operators/debounceTime-spec.ts new file mode 100644 index 0000000000..9b37bea221 --- /dev/null +++ b/spec/operators/debounceTime-spec.ts @@ -0,0 +1,150 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.debounceTime()', () => { + asDiagram('debounceTime(20)')('should debounce values by 20 time units', () => { + const e1 = hot('-a--bc--d---|'); + const expected = '---a---c--d-|'; + + expectObservable(e1.debounceTime(20, rxTestScheduler)).toBe(expected); + }); + + it('should delay all element by the specified time', () => { + const e1 = hot('-a--------b------c----|'); + const e1subs = '^ !'; + const expected = '------a--------b------(c|)'; + + expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should debounce and delay element by the specified time', () => { + const e1 = hot('-a--(bc)-----------d-------|'); + const e1subs = '^ !'; + const expected = '---------c--------------d--|'; + + expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete when source does not emit', () => { + const e1 = hot('-----|'); + const e1subs = '^ !'; + const expected = '-----|'; + + expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when source does not emit and raises error', () => { + const e1 = hot('-----#'); + const e1subs = '^ !'; + const expected = '-----#'; + + expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--bc--d----|'); + const e1subs = '^ ! '; + const expected = '----a--- '; + const unsub = ' ! '; + + const result = e1.debounceTime(20, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--bc--d----|'); + const e1subs = '^ ! '; + const expected = '----a--- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .debounceTime(20, rxTestScheduler) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should debounce and does not complete when source does not completes', () => { + const e1 = hot('-a--(bc)-----------d-------'); + const e1subs = '^ '; + const expected = '---------c--------------d--'; + + expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes when source does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes when source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.debounceTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should delay all element until source raises error', () => { + const e1 = hot('-a--------b------c----#'); + const e1subs = '^ !'; + const expected = '------a--------b------#'; + + expectObservable(e1.debounceTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should debounce all elements while source emits within given time', () => { + const e1 = hot('--a--b--c--d--e--f--g--h-|'); + const e1subs = '^ !'; + const expected = '-------------------------(h|)'; + + expectObservable(e1.debounceTime(40, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should debounce all element while source emits within given time until raises error', () => { + const e1 = hot('--a--b--c--d--e--f--g--h-#'); + const e1subs = '^ !'; + const expected = '-------------------------#'; + + expectObservable(e1.debounceTime(40, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/defaultIfEmpty-spec.js b/spec/operators/defaultIfEmpty-spec.js deleted file mode 100644 index c80c916262..0000000000 --- a/spec/operators/defaultIfEmpty-spec.js +++ /dev/null @@ -1,84 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.defaultIfEmpty()', function () { - it.asDiagram('defaultIfEmpty(42)')('should return the Observable if not empty with a default value', function () { - var e1 = hot('--------|'); - var expected = '--------(x|)'; - - expectObservable(e1.defaultIfEmpty(42)).toBe(expected, { x: 42 }); - }); - - it('should return the argument if Observable is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(x|)'; - - expectObservable(e1.defaultIfEmpty('x')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return null if the Observable is empty and no arguments', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(x|)'; - - expectObservable(e1.defaultIfEmpty()).toBe(expected, { x: null }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return the Observable if not empty with a default value', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ !'; - var expected = '--a--b--|'; - - expectObservable(e1.defaultIfEmpty('x')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return the Observable if not empty with no default value', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ !'; - var expected = '--a--b--|'; - - expectObservable(e1.defaultIfEmpty()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ ! '; - var expected = '--a-- '; - var unsub = ' ! '; - - var result = e1.defaultIfEmpty('x'); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ ! '; - var expected = '--a-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .defaultIfEmpty('x') - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error if the Observable errors', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.defaultIfEmpty('x')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/defaultIfEmpty-spec.ts b/spec/operators/defaultIfEmpty-spec.ts new file mode 100644 index 0000000000..18ad03f8de --- /dev/null +++ b/spec/operators/defaultIfEmpty-spec.ts @@ -0,0 +1,86 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.defaultIfEmpty()', () => { + asDiagram('defaultIfEmpty(42)')('should return the Observable if not empty with a default value', () => { + const e1 = hot('--------|'); + const expected = '--------(x|)'; + + expectObservable(e1.defaultIfEmpty(42)).toBe(expected, { x: 42 }); + }); + + it('should return the argument if Observable is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(x|)'; + + expectObservable(e1.defaultIfEmpty('x')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return null if the Observable is empty and no arguments', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(x|)'; + + expectObservable(e1.defaultIfEmpty()).toBe(expected, { x: null }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return the Observable if not empty with a default value', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ !'; + const expected = '--a--b--|'; + + expectObservable(e1.defaultIfEmpty('x')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return the Observable if not empty with no default value', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ !'; + const expected = '--a--b--|'; + + expectObservable(e1.defaultIfEmpty()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ ! '; + const expected = '--a-- '; + const unsub = ' ! '; + + const result = e1.defaultIfEmpty('x'); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ ! '; + const expected = '--a-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .defaultIfEmpty('x') + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error if the Observable errors', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.defaultIfEmpty('x')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/delay-spec.js b/spec/operators/delay-spec.js deleted file mode 100644 index 2939742c5e..0000000000 --- a/spec/operators/delay-spec.js +++ /dev/null @@ -1,142 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.delay()', function () { - it.asDiagram('delay(20)')('should delay by specified timeframe', function () { - var e1 = hot('---a--b--| '); - var t = time( '--| '); - var expected = '-----a--b--|'; - var subs = '^ !'; - - var result = e1.delay(t, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should delay by absolute time period', function () { - var e1 = hot('--a--b--| '); - var t = time( '---| '); - var expected = '-----a--b--|'; - var subs = '^ !'; - - var absoluteDelay = new Date(rxTestScheduler.now() + t); - var result = e1.delay(absoluteDelay, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should delay by absolute time period after subscription', function () { - var e1 = hot('---^--a--b--| '); - var t = time( '---| '); - var expected = '------a--b--|'; - var subs = '^ !'; - - var absoluteDelay = new Date(rxTestScheduler.now() + t); - var result = e1.delay(absoluteDelay, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source raises error', function () { - var e1 = hot('---a---b---#'); - var t = time( '---| '); - var expected = '------a---b#'; - var subs = '^ !'; - - var result = e1.delay(t, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source raises error', function () { - var e1 = hot('--a--b--#'); - var t = time( '---| '); - var expected = '-----a--#'; - var subs = '^ !'; - - var absoluteDelay = new Date(rxTestScheduler.now() + t); - var result = e1.delay(absoluteDelay, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source raises error after subscription', function () { - var e1 = hot('---^---a---b---#'); - var t = time( '---| '); - var expected = '-------a---b#'; - var e1Sub = '^ !'; - - var absoluteDelay = new Date(rxTestScheduler.now() + t); - var result = e1.delay(absoluteDelay, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1Sub); - }); - - it('should delay when source does not emits', function () { - var e1 = hot('----| '); - var t = time( '---|'); - var expected = '-------|'; - var subs = '^ !'; - - var result = e1.delay(t, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should delay when source is empty', function () { - var e1 = cold('|'); - var t = time('---|'); - var expected = '---|'; - - var result = e1.delay(t, rxTestScheduler); - - expectObservable(result).toBe(expected); - }); - - it('should not complete when source does not completes', function () { - var e1 = hot('---a---b---------'); - var t = time( '---| '); - var expected = '------a---b------'; - var unsub = '----------------!'; - var subs = '^ !'; - - var result = e1.delay(t, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('---a---b----'); - var t = time( '---| '); - var e1subs = '^ ! '; - var expected = '------a-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .delay(t, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete when source never completes', function () { - var e1 = cold('-'); - var t = time('---|'); - var expected = '-'; - - var result = e1.delay(t, rxTestScheduler); - - expectObservable(result).toBe(expected); - }); -}); \ No newline at end of file diff --git a/spec/operators/delay-spec.ts b/spec/operators/delay-spec.ts new file mode 100644 index 0000000000..75c83d3523 --- /dev/null +++ b/spec/operators/delay-spec.ts @@ -0,0 +1,145 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.delay()', () => { + asDiagram('delay(20)')('should delay by specified timeframe', () => { + const e1 = hot('---a--b--| '); + const t = time( '--| '); + const expected = '-----a--b--|'; + const subs = '^ !'; + + const result = e1.delay(t, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should delay by absolute time period', () => { + const e1 = hot('--a--b--| '); + const t = time( '---| '); + const expected = '-----a--b--|'; + const subs = '^ !'; + + const absoluteDelay = new Date(rxTestScheduler.now() + t); + const result = e1.delay(absoluteDelay, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should delay by absolute time period after subscription', () => { + const e1 = hot('---^--a--b--| '); + const t = time( '---| '); + const expected = '------a--b--|'; + const subs = '^ !'; + + const absoluteDelay = new Date(rxTestScheduler.now() + t); + const result = e1.delay(absoluteDelay, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source raises error', () => { + const e1 = hot('---a---b---#'); + const t = time( '---| '); + const expected = '------a---b#'; + const subs = '^ !'; + + const result = e1.delay(t, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source raises error', () => { + const e1 = hot('--a--b--#'); + const t = time( '---| '); + const expected = '-----a--#'; + const subs = '^ !'; + + const absoluteDelay = new Date(rxTestScheduler.now() + t); + const result = e1.delay(absoluteDelay, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source raises error after subscription', () => { + const e1 = hot('---^---a---b---#'); + const t = time( '---| '); + const expected = '-------a---b#'; + const e1Sub = '^ !'; + + const absoluteDelay = new Date(rxTestScheduler.now() + t); + const result = e1.delay(absoluteDelay, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1Sub); + }); + + it('should delay when source does not emits', () => { + const e1 = hot('----| '); + const t = time( '---|'); + const expected = '-------|'; + const subs = '^ !'; + + const result = e1.delay(t, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should delay when source is empty', () => { + const e1 = cold('|'); + const t = time('---|'); + const expected = '---|'; + + const result = e1.delay(t, rxTestScheduler); + + expectObservable(result).toBe(expected); + }); + + it('should not complete when source does not completes', () => { + const e1 = hot('---a---b---------'); + const t = time( '---| '); + const expected = '------a---b------'; + const unsub = '----------------!'; + const subs = '^ !'; + + const result = e1.delay(t, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('---a---b----'); + const t = time( '---| '); + const e1subs = '^ ! '; + const expected = '------a-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .delay(t, rxTestScheduler) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete when source never completes', () => { + const e1 = cold('-'); + const t = time('---|'); + const expected = '-'; + + const result = e1.delay(t, rxTestScheduler); + + expectObservable(result).toBe(expected); + }); +}); \ No newline at end of file diff --git a/spec/operators/delayWhen-spec.js b/spec/operators/delayWhen-spec.js deleted file mode 100644 index 0f317c3738..0000000000 --- a/spec/operators/delayWhen-spec.js +++ /dev/null @@ -1,211 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.delayWhen()', function () { - it.asDiagram('delay(durationSelector)')('should delay by duration selector', function () { - var e1 = hot('---a---b---c--|'); - var expected = '-----a------c----(b|)'; - var subs = '^ !'; - var selector = [cold( '--x--|'), - cold( '----------x-|'), - cold( '-x--|')]; - var selectorSubs = [' ^ ! ', - ' ^ !', - ' ^! ']; - - var idx = 0; - function durationSelector(x) { - return selector[idx++]; - } - - var result = e1.delayWhen(durationSelector); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector[0].subscriptions).toBe(selectorSubs[0]); - expectSubscriptions(selector[1].subscriptions).toBe(selectorSubs[1]); - expectSubscriptions(selector[2].subscriptions).toBe(selectorSubs[2]); - }); - - it('should delay by selector', function () { - var e1 = hot('--a--b--|'); - var expected = '---a--b-|'; - var subs = '^ !'; - var selector = cold( '-x--|'); - var selectorSubs = [' ^! ', - ' ^! ']; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should raise error if source raises error', function () { - var e1 = hot('--a--#'); - var expected = '---a-#'; - var subs = '^ !'; - var selector = cold( '-x--|'); - var selectorSubs = ' ^! '; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should raise error if selector raises error', function () { - var e1 = hot('--a--b--|'); - var expected = '---#'; - var subs = '^ !'; - var selector = cold( '-#'); - var selectorSubs = ' ^! '; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should delay by selector and completes after value emits', function () { - var e1 = hot('--a--b--|'); - var expected = '---------a--(b|)'; - var subs = '^ !'; - var selector = cold('-------x--|'); - var selectorSubs = [' ^ !', - ' ^ !']; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should delay by selector completes if selector does not emits', function () { - var e1 = hot('--a--b--|'); - var expected = '------a--(b|)'; - var subs = '^ !'; - var selector = cold( '----|'); - var selectorSubs = [' ^ !', - ' ^ !']; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should not emit if selector never emits', function () { - var e1 = hot('--a--b--|'); - var expected = '-'; - var subs = '^ '; - var selector = cold( '-'); - var selectorSubs = [' ^ ', - ' ^ ']; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should delay by first value from selector', function () { - var e1 = hot('--a--b--|'); - var expected = '------a--(b|)'; - var subs = '^ !'; - var selector = cold( '----x--y--|'); - var selectorSubs = [' ^ !', - ' ^ !']; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should delay by selector does not completes', function () { - var e1 = hot('--a--b--|'); - var expected = '------a--(b|)'; - var subs = '^ !'; - var selector = cold( '----x-----y---'); - var selectorSubs = [' ^ !', - ' ^ !']; - - var result = e1.delayWhen(function (x) { return selector; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - }); - - it('should raise error if selector throws', function () { - var e1 = hot('--a--b--|'); - var expected = '--#'; - var subs = '^ !'; - - var err = new Error('error'); - var result = e1.delayWhen(function (x) { throw err; }); - - expectObservable(result).toBe(expected, null, err); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should start subscription when subscription delay emits', function () { - var e1 = hot('-----a---b---|'); - var expected = ' -----a---b-|'; - var subs = ' ^ !'; - var selector = cold( '--x--|'); - var selectorSubs = [' ^ !', - ' ^ !']; - var subDelay = cold('--x--|'); - var subDelaySub = '^ !'; - - var result = e1.delayWhen(function (x) { return selector; }, subDelay); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - expectSubscriptions(subDelay.subscriptions).toBe(subDelaySub); - }); - - it('should start subscription when subscription delay completes without emit value', function () { - var e1 = hot('-----a---b---|'); - var expected = ' -----a---b-|'; - var subs = ' ^ !'; - var selector = cold( '--x--|'); - var selectorSubs = [' ^ !', - ' ^ !']; - var subDelay = cold('--|'); - var subDelaySub = '^ !'; - - var result = e1.delayWhen(function (x) { return selector; }, subDelay); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(selector.subscriptions).toBe(selectorSubs); - expectSubscriptions(subDelay.subscriptions).toBe(subDelaySub); - }); - - it('should raise error when subscription delay raises error', function () { - var e1 = hot('-----a---b---|'); - var expected = ' # '; - var selector = cold( '--x--|'); - var subDelay = cold('---#'); - var subDelaySub = '^ !'; - - var result = e1.delayWhen(function (x) { return selector; }, subDelay); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe([]); - expectSubscriptions(selector.subscriptions).toBe([]); - expectSubscriptions(subDelay.subscriptions).toBe(subDelaySub); - }); -}); \ No newline at end of file diff --git a/spec/operators/delayWhen-spec.ts b/spec/operators/delayWhen-spec.ts new file mode 100644 index 0000000000..6cd77adac5 --- /dev/null +++ b/spec/operators/delayWhen-spec.ts @@ -0,0 +1,214 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.delayWhen()', () => { + asDiagram('delay(durationSelector)')('should delay by duration selector', () => { + const e1 = hot('---a---b---c--|'); + const expected = '-----a------c----(b|)'; + const subs = '^ !'; + const selector = [cold( '--x--|'), + cold( '----------x-|'), + cold( '-x--|')]; + const selectorSubs = [' ^ ! ', + ' ^ !', + ' ^! ']; + + let idx = 0; + function durationSelector(x) { + return selector[idx++]; + } + + const result = e1.delayWhen(durationSelector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector[0].subscriptions).toBe(selectorSubs[0]); + expectSubscriptions(selector[1].subscriptions).toBe(selectorSubs[1]); + expectSubscriptions(selector[2].subscriptions).toBe(selectorSubs[2]); + }); + + it('should delay by selector', () => { + const e1 = hot('--a--b--|'); + const expected = '---a--b-|'; + const subs = '^ !'; + const selector = cold( '-x--|'); + const selectorSubs = [' ^! ', + ' ^! ']; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should raise error if source raises error', () => { + const e1 = hot('--a--#'); + const expected = '---a-#'; + const subs = '^ !'; + const selector = cold( '-x--|'); + const selectorSubs = ' ^! '; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should raise error if selector raises error', () => { + const e1 = hot('--a--b--|'); + const expected = '---#'; + const subs = '^ !'; + const selector = cold( '-#'); + const selectorSubs = ' ^! '; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should delay by selector and completes after value emits', () => { + const e1 = hot('--a--b--|'); + const expected = '---------a--(b|)'; + const subs = '^ !'; + const selector = cold('-------x--|'); + const selectorSubs = [' ^ !', + ' ^ !']; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should delay by selector completes if selector does not emits', () => { + const e1 = hot('--a--b--|'); + const expected = '------a--(b|)'; + const subs = '^ !'; + const selector = cold( '----|'); + const selectorSubs = [' ^ !', + ' ^ !']; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should not emit if selector never emits', () => { + const e1 = hot('--a--b--|'); + const expected = '-'; + const subs = '^ '; + const selector = cold( '-'); + const selectorSubs = [' ^ ', + ' ^ ']; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should delay by first value from selector', () => { + const e1 = hot('--a--b--|'); + const expected = '------a--(b|)'; + const subs = '^ !'; + const selector = cold( '----x--y--|'); + const selectorSubs = [' ^ !', + ' ^ !']; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should delay by selector does not completes', () => { + const e1 = hot('--a--b--|'); + const expected = '------a--(b|)'; + const subs = '^ !'; + const selector = cold( '----x-----y---'); + const selectorSubs = [' ^ !', + ' ^ !']; + + const result = e1.delayWhen((x: any) => selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + }); + + it('should raise error if selector throws', () => { + const e1 = hot('--a--b--|'); + const expected = '--#'; + const subs = '^ !'; + + const err = new Error('error'); + const result = e1.delayWhen(((x: any) => { throw err; })); + + expectObservable(result).toBe(expected, null, err); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should start subscription when subscription delay emits', () => { + const e1 = hot('-----a---b---|'); + const expected = ' -----a---b-|'; + const subs = ' ^ !'; + const selector = cold( '--x--|'); + const selectorSubs = [' ^ !', + ' ^ !']; + const subDelay = cold('--x--|'); + const subDelaySub = '^ !'; + + const result = e1.delayWhen((x: any) => selector, subDelay); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + expectSubscriptions(subDelay.subscriptions).toBe(subDelaySub); + }); + + it('should start subscription when subscription delay completes without emit value', () => { + const e1 = hot('-----a---b---|'); + const expected = ' -----a---b-|'; + const subs = ' ^ !'; + const selector = cold( '--x--|'); + const selectorSubs = [' ^ !', + ' ^ !']; + const subDelay = cold('--|'); + const subDelaySub = '^ !'; + + const result = e1.delayWhen((x: any) => selector, subDelay); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(selector.subscriptions).toBe(selectorSubs); + expectSubscriptions(subDelay.subscriptions).toBe(subDelaySub); + }); + + it('should raise error when subscription delay raises error', () => { + const e1 = hot('-----a---b---|'); + const expected = ' # '; + const selector = cold( '--x--|'); + const subDelay = cold('---#'); + const subDelaySub = '^ !'; + + const result = e1.delayWhen((x: any) => selector, subDelay); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe([]); + expectSubscriptions(selector.subscriptions).toBe([]); + expectSubscriptions(subDelay.subscriptions).toBe(subDelaySub); + }); +}); \ No newline at end of file diff --git a/spec/operators/dematerialize-spec.js b/spec/operators/dematerialize-spec.js deleted file mode 100644 index 6b60993752..0000000000 --- a/spec/operators/dematerialize-spec.js +++ /dev/null @@ -1,161 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Notification = Rx.Notification; - -describe('Observable.prototype.dematerialize()', function () { - it.asDiagram('dematerialize')('should dematerialize an Observable', function () { - var values = { - a: '{x}', - b: '{y}', - c: '{z}', - d: '|' - }; - - var e1 = hot('--a--b--c--d-|', values); - var expected = '--x--y--z--|'; - - var result = e1.map(function (x) { - if (x === '|') { - return Notification.createComplete(); - } else { - return Notification.createNext(x.replace('{', '').replace('}', '')); - } - }).dematerialize(); - - expectObservable(result).toBe(expected); - }); - - it('should dematerialize a happy stream', function () { - var values = { - a: Notification.createNext('w'), - b: Notification.createNext('x'), - c: Notification.createNext('y'), - d: Notification.createComplete() - }; - - var e1 = hot('--a--b--c--d--|', values); - var e1subs = '^ !'; - var expected = '--w--x--y--|'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize a sad stream', function () { - var values = { - a: Notification.createNext('w'), - b: Notification.createNext('x'), - c: Notification.createNext('y'), - d: Notification.createError('error') - }; - - var e1 = hot('--a--b--c--d--|', values); - var e1subs = '^ !'; - var expected = '--w--x--y--#'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize stream does not completes', function () { - var e1 = hot('------'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize stream never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize stream does not emit', function () { - var e1 = hot('----|'); - var e1subs = '^ !'; - var expected = '----|'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize empty stream', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize stream throws', function () { - var error = 'error'; - var e1 = hot('(x|)', {x: Notification.createError(error)}); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.dematerialize()).toBe(expected, null, error); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var values = { - a: Notification.createNext('w'), - b: Notification.createNext('x') - }; - - var e1 = hot('--a--b--c--d--|', values); - var e1subs = '^ ! '; - var expected = '--w--x-- '; - var unsub = ' ! '; - - var result = e1.dematerialize(); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var values = { - a: Notification.createNext('w'), - b: Notification.createNext('x') - }; - - var e1 = hot('--a--b--c--d--|', values); - var e1subs = '^ ! '; - var expected = '--w--x-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .dematerialize() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize and completes when stream compltes with complete notification', function () { - var e1 = hot('----(a|)', { a: Notification.createComplete() }); - var e1subs = '^ !'; - var expected = '----|'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should dematerialize and completes when stream emits complete notification', function () { - var e1 = hot('----a--|', { a: Notification.createComplete() }); - var e1subs = '^ !'; - var expected = '----|'; - - expectObservable(e1.dematerialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/dematerialize-spec.ts b/spec/operators/dematerialize-spec.ts new file mode 100644 index 0000000000..fb00aa1625 --- /dev/null +++ b/spec/operators/dematerialize-spec.ts @@ -0,0 +1,163 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Notification = Rx.Notification; + +describe('Observable.prototype.dematerialize()', () => { + asDiagram('dematerialize')('should dematerialize an Observable', () => { + const values = { + a: '{x}', + b: '{y}', + c: '{z}', + d: '|' + }; + + const e1 = hot('--a--b--c--d-|', values); + const expected = '--x--y--z--|'; + + const result = e1.map((x: string) => { + if (x === '|') { + return Notification.createComplete(); + } else { + return Notification.createNext(x.replace('{', '').replace('}', '')); + } + }).dematerialize(); + + expectObservable(result).toBe(expected); + }); + + it('should dematerialize a happy stream', () => { + const values = { + a: Notification.createNext('w'), + b: Notification.createNext('x'), + c: Notification.createNext('y'), + d: Notification.createComplete() + }; + + const e1 = hot('--a--b--c--d--|', values); + const e1subs = '^ !'; + const expected = '--w--x--y--|'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize a sad stream', () => { + const values = { + a: Notification.createNext('w'), + b: Notification.createNext('x'), + c: Notification.createNext('y'), + d: Notification.createError('error') + }; + + const e1 = hot('--a--b--c--d--|', values); + const e1subs = '^ !'; + const expected = '--w--x--y--#'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize stream does not completes', () => { + const e1 = hot('------'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize stream never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize stream does not emit', () => { + const e1 = hot('----|'); + const e1subs = '^ !'; + const expected = '----|'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize empty stream', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize stream throws', () => { + const error = 'error'; + const e1 = hot('(x|)', {x: Notification.createError(error)}); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.dematerialize()).toBe(expected, null, error); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const values = { + a: Notification.createNext('w'), + b: Notification.createNext('x') + }; + + const e1 = hot('--a--b--c--d--|', values); + const e1subs = '^ ! '; + const expected = '--w--x-- '; + const unsub = ' ! '; + + const result = e1.dematerialize(); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const values = { + a: Notification.createNext('w'), + b: Notification.createNext('x') + }; + + const e1 = hot('--a--b--c--d--|', values); + const e1subs = '^ ! '; + const expected = '--w--x-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .dematerialize() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize and completes when stream compltes with complete notification', () => { + const e1 = hot('----(a|)', { a: Notification.createComplete() }); + const e1subs = '^ !'; + const expected = '----|'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should dematerialize and completes when stream emits complete notification', () => { + const e1 = hot('----a--|', { a: Notification.createComplete() }); + const e1subs = '^ !'; + const expected = '----|'; + + expectObservable(e1.dematerialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/distinct-spec.js b/spec/operators/distinct-spec.js deleted file mode 100644 index aecf5772a4..0000000000 --- a/spec/operators/distinct-spec.js +++ /dev/null @@ -1,241 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.distinct()', function () { - it('should distinguish between values', function () { - var e1 = hot('--a--a--a--b--b--a--|'); - var e1subs = '^ !'; - var expected = '--a--------b--------|'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish between values and does not completes', function () { - var e1 = hot('--a--a--a--b--b--a-'); - var e1subs = '^ '; - var expected = '--a--------b-------'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source does not emit', function () { - var e1 = hot('------|'); - var e1subs = '^ !'; - var expected = '------|'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source emits single element only', function () { - var e1 = hot('--a--|'); - var e1subs = '^ !'; - var expected = '--a--|'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source is scalar', function () { - var e1 = Observable.of('a'); - var expected = '(a|)'; - - expectObservable(e1.distinct()).toBe(expected); - }); - - it('should raises error if source raises error', function () { - var e1 = hot('--a--a--#'); - var e1subs = '^ !'; - var expected = '--a-----#'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not omit if source elements are all different', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ !'; - var expected = '--a--b--c--d--e--f--|'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--b--b--d--a--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1.distinct(); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--b--b--d--a--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .distinct() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if source elements are all same', function () { - var e1 = hot('--a--a--a--a--a--a--|'); - var e1subs = '^ !'; - var expected = '--a-----------------|'; - - expectObservable(e1.distinct()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if comparer returns true always regardless of source emits', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ !'; - var expected = '--a-----------------|'; - - expectObservable(e1.distinct(function () { return true; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit all if comparer returns false always regardless of source emits', function () { - var e1 = hot('--a--a--a--a--a--a--|'); - var e1subs = '^ !'; - var expected = '--a--a--a--a--a--a--|'; - - expectObservable(e1.distinct(function () { return false; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish values by selector', function () { - var e1 = hot('--a--b--c--d--e--f--|', {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); - var e1subs = '^ !'; - var expected = '--a-----c-----e-----|'; - var selector = function (x, y) { - return y % 2 === 0; - }; - - expectObservable(e1.distinct(selector)).toBe(expected, {a: 1, c: 3, e: 5}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error when comparer throws', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b--c--# '; - var selector = function (x, y) { - if (y === 'd') { - throw 'error'; - } - return x === y; - }; - - expectObservable(e1.distinct(selector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should support a flushing stream', function () { - var e1 = hot('--a--b--a--b--a--b--|'); - var e1subs = '^ !'; - var e2 = hot('-----------x--------|'); - var e2subs = '^ !'; - var expected = '--a--b--------a--b--|'; - var selector = function (x, y) { - return x === y; - }; - - expectObservable(e1.distinct(selector, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error if flush raises error', function () { - var e1 = hot('--a--b--a--b--a--b--|'); - var e1subs = '^ !'; - var e2 = hot('-----------x-#'); - var e2subs = '^ !'; - var expected = '--a--b-------#'; - var selector = function (x, y) { - return x === y; - }; - - expectObservable(e1.distinct(selector, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe from the flushing stream when the main stream is unsubbed', function () { - var e1 = hot('--a--b--a--b--a--b--|'); - var e1subs = '^ ! '; - var e2 = hot('-----------x--------|'); - var e2subs = '^ ! '; - var unsub = ' ! '; - var expected = '--a--b------'; - var selector = function (x, y) { - return x === y; - }; - - expectObservable(e1.distinct(selector, e2), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow opting in to default comparator with flush', function () { - var e1 = hot('--a--b--a--b--a--b--|'); - var e1subs = '^ !'; - var e2 = hot('-----------x--------|'); - var e2subs = '^ !'; - var expected = '--a--b--------a--b--|'; - - expectObservable(e1.distinct(null, e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/distinct-spec.ts b/spec/operators/distinct-spec.ts new file mode 100644 index 0000000000..1340584306 --- /dev/null +++ b/spec/operators/distinct-spec.ts @@ -0,0 +1,235 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.distinct()', () => { + it('should distinguish between values', () => { + const e1 = hot('--a--a--a--b--b--a--|'); + const e1subs = '^ !'; + const expected = '--a--------b--------|'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish between values and does not completes', () => { + const e1 = hot('--a--a--a--b--b--a-'); + const e1subs = '^ '; + const expected = '--a--------b-------'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source does not emit', () => { + const e1 = hot('------|'); + const e1subs = '^ !'; + const expected = '------|'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source emits single element only', () => { + const e1 = hot('--a--|'); + const e1subs = '^ !'; + const expected = '--a--|'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source is scalar', () => { + const e1 = Observable.of('a'); + const expected = '(a|)'; + + expectObservable((e1).distinct()).toBe(expected); + }); + + it('should raises error if source raises error', () => { + const e1 = hot('--a--a--#'); + const e1subs = '^ !'; + const expected = '--a-----#'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not omit if source elements are all different', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ !'; + const expected = '--a--b--c--d--e--f--|'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--b--b--d--a--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = (e1).distinct(); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--b--b--d--a--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = (e1 + .mergeMap((x: any) => Observable.of(x))) + .distinct() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if source elements are all same', () => { + const e1 = hot('--a--a--a--a--a--a--|'); + const e1subs = '^ !'; + const expected = '--a-----------------|'; + + expectObservable((e1).distinct()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if comparer returns true always regardless of source emits', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ !'; + const expected = '--a-----------------|'; + + expectObservable((e1).distinct(() => true)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit all if comparer returns false always regardless of source emits', () => { + const e1 = hot('--a--a--a--a--a--a--|'); + const e1subs = '^ !'; + const expected = '--a--a--a--a--a--a--|'; + + expectObservable((e1).distinct(() => false)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish values by selector', () => { + const e1 = hot('--a--b--c--d--e--f--|', {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); + const e1subs = '^ !'; + const expected = '--a-----c-----e-----|'; + const selector = (x: number, y: number) => y % 2 === 0; + + expectObservable((e1).distinct(selector)).toBe(expected, {a: 1, c: 3, e: 5}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error when comparer throws', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b--c--# '; + const selector = (x: string, y: string) => { + if (y === 'd') { + throw 'error'; + } + return x === y; + }; + + expectObservable((e1).distinct(selector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should support a flushing stream', () => { + const e1 = hot('--a--b--a--b--a--b--|'); + const e1subs = '^ !'; + const e2 = hot('-----------x--------|'); + const e2subs = '^ !'; + const expected = '--a--b--------a--b--|'; + const selector = (x: string, y: string) => x === y; + + expectObservable((e1).distinct(selector, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error if flush raises error', () => { + const e1 = hot('--a--b--a--b--a--b--|'); + const e1subs = '^ !'; + const e2 = hot('-----------x-#'); + const e2subs = '^ !'; + const expected = '--a--b-------#'; + const selector = (x: string, y: string) => x === y; + + expectObservable((e1).distinct(selector, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should unsubscribe from the flushing stream when the main stream is unsubbed', () => { + const e1 = hot('--a--b--a--b--a--b--|'); + const e1subs = '^ ! '; + const e2 = hot('-----------x--------|'); + const e2subs = '^ ! '; + const unsub = ' ! '; + const expected = '--a--b------'; + const selector = (x: string, y: string) => x === y; + + expectObservable((e1).distinct(selector, e2), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow opting in to default comparator with flush', () => { + const e1 = hot('--a--b--a--b--a--b--|'); + const e1subs = '^ !'; + const e2 = hot('-----------x--------|'); + const e2subs = '^ !'; + const expected = '--a--b--------a--b--|'; + + expectObservable((e1).distinct(null, e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/distinctKey-spec.js b/spec/operators/distinctKey-spec.js deleted file mode 100644 index 603a4781e0..0000000000 --- a/spec/operators/distinctKey-spec.js +++ /dev/null @@ -1,272 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.distinctKey()', function () { - it.asDiagram('distinctKey(\'k\')')('should distinguish between values', function () { - var values = {a: {k: 1}, b: {k: 2}, c: {k: 3}}; - var e1 = hot('-a--b-b----a-c-|', values); - var expected = '-a--b--------c-|'; - - var result = e1.distinctKey('k'); - - expectObservable(result).toBe(expected, values); - }); - - it('should distinguish between values', function () { - var values = {a: {val: 1}, b: {val: 2}}; - var e1 = hot('--a--a--a--b--b--a--|', values); - var e1subs = '^ !'; - var expected = '--a--------b--------|'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish between values and does not completes', function () { - var values = {a: {val: 1}, b: {val: 2}}; - var e1 = hot('--a--a--a--b--b--a-', values); - var e1subs = '^ '; - var expected = '--a--------b-------'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish between values with key', function () { - var values = {a: {val: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {val: 1}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--b--------e--|'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not compare if source does not have element with key', function () { - var values = {a: {valOther: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {valOther: 1}, e: {valOther: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--------------|'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinctKey('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinctKey('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.distinctKey('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source does not emit', function () { - var e1 = hot('------|'); - var e1subs = '^ !'; - var expected = '------|'; - - expectObservable(e1.distinctKey('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source emits single element only', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--|', values); - var e1subs = '^ !'; - var expected = '--a--|'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source is scalar', function () { - var values = {a: {val: 1}}; - var e1 = Observable.of(values.a); - var expected = '(a|)'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - }); - - it('should raises error if source raises error', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--a--#', values); - var e1subs = '^ !'; - var expected = '--a-----#'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.distinctKey('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not omit if source elements are all different', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--b--c--d--e--|'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--b--d--a--e--|', values); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1.distinctKey('val'); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--b--d--a--e--|', values); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .distinctKey('val') - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if source elements are all same', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--a--a--a--a--a--|', values); - var e1subs = '^ !'; - var expected = '--a-----------------|'; - - expectObservable(e1.distinctKey('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if comparer returns true always regardless of source emits', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--------------|'; - - expectObservable(e1.distinctKey('val', function () { return true; })).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit all if comparer returns false always regardless of source emits', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--a--a--a--a--a--|', values); - var e1subs = '^ !'; - var expected = '--a--a--a--a--a--a--|'; - - expectObservable(e1.distinctKey('val', function () { return false; })).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish values by selector', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a-----c-----e--|'; - var selector = function (x, y) { - return y % 2 === 0; - }; - - expectObservable(e1.distinctKey('val', selector)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error when comparer throws', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ ! '; - var expected = '--a--b--c--# '; - var selector = function (x, y) { - if (y === 4) { - throw 'error'; - } - return x === y; - }; - - expectObservable(e1.distinctKey('val', selector)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should support a flushing stream', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--a--b--a--b--|', values); - var e1subs = '^ !'; - var e2 = hot('-----------x--------|'); - var e2subs = '^ !'; - var expected = '--a--b--------a--b--|'; - var selector = function (x, y) { - return x === y; - }; - - expectObservable(e1.distinct(selector, e2)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe from the flushing stream when the main stream is unsubbed', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--a--b--a--b--|', values); - var e1subs = '^ ! '; - var e2 = hot('-----------x--------|'); - var e2subs = '^ ! '; - var unsub = ' ! '; - var expected = '--a--b------'; - var selector = function (x, y) { - return x === y; - }; - - expectObservable(e1.distinct(selector, e2), unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow opting in to default comparator with flush', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--a--b--a--b--|', values); - var e1subs = '^ !'; - var e2 = hot('-----------x--------|'); - var e2subs = '^ !'; - var expected = '--a--b--------a--b--|'; - - expectObservable(e1.distinct(null, e2)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/distinctKey-spec.ts b/spec/operators/distinctKey-spec.ts new file mode 100644 index 0000000000..e03f62da4d --- /dev/null +++ b/spec/operators/distinctKey-spec.ts @@ -0,0 +1,226 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.distinctKey()', () => { + asDiagram('distinctKey(\'k\')')('should distinguish between values', () => { + const values = {a: {k: 1}, b: {k: 2}, c: {k: 3}}; + const e1 = hot('-a--b-b----a-c-|', values); + const expected = '-a--b--------c-|'; + + const result = (e1).distinctKey('k'); + + expectObservable(result).toBe(expected, values); + }); + + it('should distinguish between values', () => { + const values = {a: {val: 1}, b: {val: 2}}; + const e1 = hot('--a--a--a--b--b--a--|', values); + const e1subs = '^ !'; + const expected = '--a--------b--------|'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish between values and does not completes', () => { + const values = {a: {val: 1}, b: {val: 2}}; + const e1 = hot('--a--a--a--b--b--a-', values); + const e1subs = '^ '; + const expected = '--a--------b-------'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish between values with key', () => { + const values = {a: {val: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {val: 1}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--b--------e--|'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not compare if source does not have element with key', () => { + const values = {a: {valOther: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {valOther: 1}, e: {valOther: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--------------|'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).distinctKey('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).distinctKey('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).distinctKey('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source does not emit', () => { + const e1 = hot('------|'); + const e1subs = '^ !'; + const expected = '------|'; + + expectObservable((e1).distinctKey('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source emits single element only', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--|', values); + const e1subs = '^ !'; + const expected = '--a--|'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source is scalar', () => { + const values = {a: {val: 1}}; + const e1 = Observable.of(values.a); + const expected = '(a|)'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + }); + + it('should raises error if source raises error', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--a--#', values); + const e1subs = '^ !'; + const expected = '--a-----#'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).distinctKey('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not omit if source elements are all different', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--b--c--d--e--|'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--b--d--a--e--|', values); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = (e1).distinctKey('val'); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--b--d--a--e--|', values); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = (e1) + .mergeMap((x: any) => Observable.of(x)) + .distinctKey('val') + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if source elements are all same', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--a--a--a--a--a--|', values); + const e1subs = '^ !'; + const expected = '--a-----------------|'; + + expectObservable((e1).distinctKey('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if comparer returns true always regardless of source emits', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--------------|'; + + expectObservable((e1).distinctKey('val', () => true)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit all if comparer returns false always regardless of source emits', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--a--a--a--a--a--|', values); + const e1subs = '^ !'; + const expected = '--a--a--a--a--a--a--|'; + + expectObservable((e1).distinctKey('val', () => false)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish values by selector', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a-----c-----e--|'; + const selector = (x: number, y: number) => y % 2 === 0; + + expectObservable((e1).distinctKey('val', selector)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error when comparer throws', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ ! '; + const expected = '--a--b--c--# '; + const selector = (x: number, y: number) => { + if (y === 4) { + throw 'error'; + } + return x === y; + }; + + expectObservable((e1).distinctKey('val', selector)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/distinctUntilChanged-spec.js b/spec/operators/distinctUntilChanged-spec.js deleted file mode 100644 index a5be2f449b..0000000000 --- a/spec/operators/distinctUntilChanged-spec.js +++ /dev/null @@ -1,220 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.distinctUntilChanged()', function () { - it.asDiagram('distinctUntilChanged')('should distinguish between values', function () { - var e1 = hot('-1--2-2----1-3-|'); - var expected = '-1--2------1-3-|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - }); - - it('should distinguish between values', function () { - var e1 = hot('--a--a--a--b--b--a--|'); - var e1subs = '^ !'; - var expected = '--a--------b-----a--|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish between values and does not completes', function () { - var e1 = hot('--a--a--a--b--b--a-'); - var e1subs = '^ '; - var expected = '--a--------b-----a-'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source does not emit', function () { - var e1 = hot('------|'); - var e1subs = '^ !'; - var expected = '------|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source emits single element only', function () { - var e1 = hot('--a--|'); - var e1subs = '^ !'; - var expected = '--a--|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source is scalar', function () { - var e1 = Observable.of('a'); - var expected = '(a|)'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - }); - - it('should raises error if source raises error', function () { - var e1 = hot('--a--a--#'); - var e1subs = '^ !'; - var expected = '--a-----#'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not omit if source elements are all different', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ !'; - var expected = '--a--b--c--d--e--f--|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--b--b--d--a--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1.distinctUntilChanged(); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--b--b--d--a--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .distinctUntilChanged() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if source elements are all same', function () { - var e1 = hot('--a--a--a--a--a--a--|'); - var e1subs = '^ !'; - var expected = '--a-----------------|'; - - expectObservable(e1.distinctUntilChanged()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if comparator returns true always regardless of source emits', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ !'; - var expected = '--a-----------------|'; - - expectObservable(e1.distinctUntilChanged(function () { return true; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit all if comparator returns false always regardless of source emits', function () { - var e1 = hot('--a--a--a--a--a--a--|'); - var e1subs = '^ !'; - var expected = '--a--a--a--a--a--a--|'; - - expectObservable(e1.distinctUntilChanged(function () { return false; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish values by comparator', function () { - var e1 = hot('--a--b--c--d--e--f--|', {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); - var e1subs = '^ !'; - var expected = '--a-----c-----e-----|'; - var comparator = function (x, y) { - return y % 2 === 0; - }; - - expectObservable(e1.distinctUntilChanged(comparator)).toBe(expected, {a: 1, c: 3, e: 5}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error when comparator throws', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b--c--# '; - var comparator = function (x, y) { - if (y === 'd') { - throw 'error'; - } - return x === y; - }; - - expectObservable(e1.distinctUntilChanged(comparator)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should use the keySelector to pick comparator values', function () { - var e1 = hot('--a--b--c--d--e--f--|', {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); - var e1subs = '^ !'; - var expected = '--a--b-----d-----f--|'; - var comparator = function (x, y) { - return y % 2 === 1; - }; - var keySelector = function (x) { - return x % 2; - }; - - expectObservable(e1.distinctUntilChanged(comparator, keySelector)).toBe(expected, {a: 1, b: 2, d: 4, f: 6}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error when keySelector throws', function () { - var e1 = hot('--a--b--c--d--e--f--|'); - var e1subs = '^ ! '; - var expected = '--a--b--c--# '; - var keySelector = function (x) { - if (x === 'd') { - throw 'error'; - } - return x; - }; - - expectObservable(e1.distinctUntilChanged(null, keySelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/distinctUntilChanged-spec.ts b/spec/operators/distinctUntilChanged-spec.ts new file mode 100644 index 0000000000..e8da22476e --- /dev/null +++ b/spec/operators/distinctUntilChanged-spec.ts @@ -0,0 +1,216 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.distinctUntilChanged()', () => { + asDiagram('distinctUntilChanged')('should distinguish between values', () => { + const e1 = hot('-1--2-2----1-3-|'); + const expected = '-1--2------1-3-|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + }); + + it('should distinguish between values', () => { + const e1 = hot('--a--a--a--b--b--a--|'); + const e1subs = '^ !'; + const expected = '--a--------b-----a--|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish between values and does not completes', () => { + const e1 = hot('--a--a--a--b--b--a-'); + const e1subs = '^ '; + const expected = '--a--------b-----a-'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source does not emit', () => { + const e1 = hot('------|'); + const e1subs = '^ !'; + const expected = '------|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source emits single element only', () => { + const e1 = hot('--a--|'); + const e1subs = '^ !'; + const expected = '--a--|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source is scalar', () => { + const e1 = Observable.of('a'); + const expected = '(a|)'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + }); + + it('should raises error if source raises error', () => { + const e1 = hot('--a--a--#'); + const e1subs = '^ !'; + const expected = '--a-----#'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not omit if source elements are all different', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ !'; + const expected = '--a--b--c--d--e--f--|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--b--b--d--a--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = e1.distinctUntilChanged(); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--b--b--d--a--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: any) => Observable.of(x)) + .distinctUntilChanged() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if source elements are all same', () => { + const e1 = hot('--a--a--a--a--a--a--|'); + const e1subs = '^ !'; + const expected = '--a-----------------|'; + + expectObservable(e1.distinctUntilChanged()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if comparator returns true always regardless of source emits', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ !'; + const expected = '--a-----------------|'; + + expectObservable(e1.distinctUntilChanged(() => { return true; })).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit all if comparator returns false always regardless of source emits', () => { + const e1 = hot('--a--a--a--a--a--a--|'); + const e1subs = '^ !'; + const expected = '--a--a--a--a--a--a--|'; + + expectObservable(e1.distinctUntilChanged(() => { return false; })).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish values by comparator', () => { + const e1 = hot('--a--b--c--d--e--f--|', {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); + const e1subs = '^ !'; + const expected = '--a-----c-----e-----|'; + const comparator = (x: number, y: number) => y % 2 === 0; + + expectObservable(e1.distinctUntilChanged(comparator)).toBe(expected, {a: 1, c: 3, e: 5}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error when comparator throws', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b--c--# '; + const comparator = (x: string, y: string) => { + if (y === 'd') { + throw 'error'; + } + return x === y; + }; + + expectObservable(e1.distinctUntilChanged(comparator)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should use the keySelector to pick comparator values', () => { + const e1 = hot('--a--b--c--d--e--f--|', {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}); + const e1subs = '^ !'; + const expected = '--a--b-----d-----f--|'; + const comparator = (x: number, y: number) => y % 2 === 1; + const keySelector = (x: number) => x % 2; + + expectObservable((e1).distinctUntilChanged(comparator, keySelector)).toBe(expected, {a: 1, b: 2, d: 4, f: 6}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error when keySelector throws', () => { + const e1 = hot('--a--b--c--d--e--f--|'); + const e1subs = '^ ! '; + const expected = '--a--b--c--# '; + const keySelector = (x: string) => { + if (x === 'd') { + throw 'error'; + } + return x; + }; + + expectObservable((e1).distinctUntilChanged(null, keySelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/distinctUntilKeyChanged-spec.js b/spec/operators/distinctUntilKeyChanged-spec.js deleted file mode 100644 index efa69f1054..0000000000 --- a/spec/operators/distinctUntilKeyChanged-spec.js +++ /dev/null @@ -1,226 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.distinctUntilKeyChanged()', function () { - it.asDiagram('distinctUntilKeyChanged(\'k\')')('should distinguish between values', function () { - var values = {a: {k: 1}, b: {k: 2}, c: {k: 3}}; - var e1 = hot('-a--b-b----a-c-|', values); - var expected = '-a--b------a-c-|'; - - var result = e1.distinctUntilKeyChanged('k'); - - expectObservable(result).toBe(expected, values); - }); - - it('should distinguish between values', function () { - var values = {a: {val: 1}, b: {val: 2}}; - var e1 = hot('--a--a--a--b--b--a--|', values); - var e1subs = '^ !'; - var expected = '--a--------b-----a--|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish between values and does not completes', function () { - var values = {a: {val: 1}, b: {val: 2}}; - var e1 = hot('--a--a--a--b--b--a-', values); - var e1subs = '^ '; - var expected = '--a--------b-----a-'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish between values with key', function () { - var values = {a: {val: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {val: 1}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--b-----d--e--|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not compare if source does not have element with key', function () { - var values = {a: {valOther: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {valOther: 1}, e: {valOther: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--------------|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete if source does not emit', function () { - var e1 = hot('------|'); - var e1subs = '^ !'; - var expected = '------|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source emits single element only', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--|', values); - var e1subs = '^ !'; - var expected = '--a--|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit if source is scalar', function () { - var values = {a: {val: 1}}; - var e1 = Observable.of(values.a); - var expected = '(a|)'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - }); - - it('should raises error if source raises error', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--a--#', values); - var e1subs = '^ !'; - var expected = '--a-----#'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not omit if source elements are all different', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--b--c--d--e--|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--b--d--a--e--|', values); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1.distinctUntilKeyChanged('val'); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--b--d--a--e--|', values); - var e1subs = '^ ! '; - var expected = '--a--b----- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .distinctUntilKeyChanged('val') - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if source elements are all same', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--a--a--a--a--a--|', values); - var e1subs = '^ !'; - var expected = '--a-----------------|'; - - expectObservable(e1.distinctUntilKeyChanged('val')).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit once if comparer returns true always regardless of source emits', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a--------------|'; - - expectObservable(e1.distinctUntilKeyChanged('val', function () { return true; })).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit all if comparer returns false always regardless of source emits', function () { - var values = {a: {val: 1}}; - var e1 = hot('--a--a--a--a--a--a--|', values); - var e1subs = '^ !'; - var expected = '--a--a--a--a--a--a--|'; - - expectObservable(e1.distinctUntilKeyChanged('val', function () { return false; })).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should distinguish values by selector', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ !'; - var expected = '--a-----c-----e--|'; - var selector = function (x, y) { - return y % 2 === 0; - }; - - expectObservable(e1.distinctUntilKeyChanged('val', selector)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raises error when comparer throws', function () { - var values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; - var e1 = hot('--a--b--c--d--e--|', values); - var e1subs = '^ ! '; - var expected = '--a--b--c--# '; - var selector = function (x, y) { - if (y === 4) { - throw 'error'; - } - return x === y; - }; - - expectObservable(e1.distinctUntilKeyChanged('val', selector)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/distinctUntilKeyChanged-spec.ts b/spec/operators/distinctUntilKeyChanged-spec.ts new file mode 100644 index 0000000000..442f28d305 --- /dev/null +++ b/spec/operators/distinctUntilKeyChanged-spec.ts @@ -0,0 +1,224 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +describe('Observable.prototype.distinctUntilKeyChanged()', () => { + asDiagram('distinctUntilKeyChanged(\'k\')')('should distinguish between values', () => { + const values = {a: {k: 1}, b: {k: 2}, c: {k: 3}}; + const e1 = hot('-a--b-b----a-c-|', values); + const expected = '-a--b------a-c-|'; + + const result = (e1).distinctUntilKeyChanged('k'); + + expectObservable(result).toBe(expected, values); + }); + + it('should distinguish between values', () => { + const values = {a: {val: 1}, b: {val: 2}}; + const e1 = hot('--a--a--a--b--b--a--|', values); + const e1subs = '^ !'; + const expected = '--a--------b-----a--|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish between values and does not completes', () => { + const values = {a: {val: 1}, b: {val: 2}}; + const e1 = hot('--a--a--a--b--b--a-', values); + const e1subs = '^ '; + const expected = '--a--------b-----a-'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish between values with key', () => { + const values = {a: {val: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {val: 1}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--b-----d--e--|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not compare if source does not have element with key', () => { + const values = {a: {valOther: 1}, b: {valOther: 1}, c: {valOther: 3}, d: {valOther: 1}, e: {valOther: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--------------|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete if source does not emit', () => { + const e1 = hot('------|'); + const e1subs = '^ !'; + const expected = '------|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source emits single element only', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--|', values); + const e1subs = '^ !'; + const expected = '--a--|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit if source is scalar', () => { + const values = {a: {val: 1}}; + const e1 = Rx.Observable.of(values.a); + const expected = '(a|)'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + }); + + it('should raises error if source raises error', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--a--#', values); + const e1subs = '^ !'; + const expected = '--a-----#'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not omit if source elements are all different', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--b--c--d--e--|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--b--d--a--e--|', values); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = (e1).distinctUntilKeyChanged('val'); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--b--d--a--e--|', values); + const e1subs = '^ ! '; + const expected = '--a--b----- '; + const unsub = ' ! '; + + const result = (e1) + .mergeMap((x: any) => Rx.Observable.of(x)) + .distinctUntilKeyChanged('val') + .mergeMap((x: any) => Rx.Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if source elements are all same', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--a--a--a--a--a--|', values); + const e1subs = '^ !'; + const expected = '--a-----------------|'; + + expectObservable((e1).distinctUntilKeyChanged('val')).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit once if comparer returns true always regardless of source emits', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a--------------|'; + + expectObservable((e1).distinctUntilKeyChanged('val', () => true)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit all if comparer returns false always regardless of source emits', () => { + const values = {a: {val: 1}}; + const e1 = hot('--a--a--a--a--a--a--|', values); + const e1subs = '^ !'; + const expected = '--a--a--a--a--a--a--|'; + + expectObservable((e1).distinctUntilKeyChanged('val', () => false)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should distinguish values by selector', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ !'; + const expected = '--a-----c-----e--|'; + const selector = (x: number, y: number) => y % 2 === 0; + + expectObservable((e1).distinctUntilKeyChanged('val', selector)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raises error when comparer throws', () => { + const values = {a: {val: 1}, b: {val: 2}, c: {val: 3}, d: {val: 4}, e: {val: 5}}; + const e1 = hot('--a--b--c--d--e--|', values); + const e1subs = '^ ! '; + const expected = '--a--b--c--# '; + const selector = (x: number, y: number) => { + if (y === 4) { + throw 'error'; + } + return x === y; + }; + + expectObservable((e1).distinctUntilKeyChanged('val', selector)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/do-spec.js b/spec/operators/do-spec.js deleted file mode 100644 index 84e85f6c97..0000000000 --- a/spec/operators/do-spec.js +++ /dev/null @@ -1,212 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Subject = Rx.Subject; -var Observable = Rx.Observable; - -describe('Observable.prototype.do()', function () { - it.asDiagram('do(x => console.log(x))')('should mirror multiple values and complete', function () { - var e1 = cold('--1--2--3--|'); - var e1subs = '^ !'; - var expected = '--1--2--3--|'; - - var result = e1.do(); - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should next with a callback', function () { - var value = null; - Observable.of(42).do(function (x) { - value = x; - }) - .subscribe(); - - expect(value).toBe(42); - }); - - it('should complete with a callback', function () { - var err = null; - Observable.throw('bad').do(null, function (x) { - err = x; - }) - .subscribe(null, function (ex) { - expect(ex).toBe('bad'); - }); - - expect(err).toBe('bad'); - }); - - it('should handle everything with an observer', function () { - var expected = [1,2,3]; - var results = []; - var completeCalled = false; - Observable.of(1,2,3) - .do({ - next: function (x) { - results.push(x); - }, - error: function (err) { - throw 'should not be called'; - }, - complete: function () { - completeCalled = true; - } - }) - .subscribe(); - - expect(completeCalled).toBe(true); - expect(results).toEqual(expected); - }); - - it('should handle everything with a Subject', function () { - var expected = [1,2,3]; - var results = []; - var completeCalled = false; - var subject = new Subject(); - - subject.subscribe({ - next: function (x) { - results.push(x); - }, - error: function (err) { - throw 'should not be called'; - }, - complete: function () { - completeCalled = true; - } - }); - - Observable.of(1,2,3) - .do(subject) - .subscribe(); - - expect(completeCalled).toBe(true); - expect(results).toEqual(expected); - }); - - it('should handle an error with a callback', function () { - var errored = false; - Observable.throw('bad').do(null, function (err) { - expect(err).toBe('bad'); - }) - .subscribe(null, function (err) { - errored = true; - expect(err).toBe('bad'); - }); - - expect(errored).toBe(true); - }); - - it('should handle an error with observer', function () { - var errored = false; - Observable.throw('bad').do({ error: function (err) { - expect(err).toBe('bad'); - } }) - .subscribe(null, function (err) { - errored = true; - expect(err).toBe('bad'); - }); - - expect(errored).toBe(true); - }); - - it('should handle complete with observer', function () { - var completed = false; - - Observable.empty().do({ - complete: function () { - completed = true; - } - }).subscribe(); - - expect(completed).toBe(true); - }); - - it('should handle next with observer', function () { - var value = null; - - Observable.of('hi').do({ - next: function (x) { - value = x; - } - }).subscribe(); - - expect(value).toBe('hi'); - }); - - it('should raise error if next handler raises error', function () { - Observable.of('hi').do({ - next: function (x) { - throw new Error('bad'); - } - }).subscribe(null, function (err) { - expect(err.message).toBe('bad'); - }); - }); - - it('should raise error if error handler raises error', function () { - Observable.throw('ops').do({ - error: function (x) { - throw new Error('bad'); - } - }).subscribe(null, function (err) { - expect(err.message).toBe('bad'); - }); - }); - - it('should raise error if complete handler raises error', function () { - Observable.empty().do({ - complete: function (x) { - throw new Error('bad'); - } - }).subscribe(null, function (err) { - expect(err.message).toBe('bad'); - }); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--1--2--3--#'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '--1--2-- '; - - var result = e1.do(); - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--1--2--3--#'); - var e1subs = '^ ! '; - var expected = '--1--2-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .do() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mirror multiple values and complete', function () { - var e1 = cold('--1--2--3--|'); - var e1subs = '^ !'; - var expected = '--1--2--3--|'; - - var result = e1.do(); - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mirror multiple values and terminate with error', function () { - var e1 = cold('--1--2--3--#'); - var e1subs = '^ !'; - var expected = '--1--2--3--#'; - - var result = e1.do(); - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/do-spec.ts b/spec/operators/do-spec.ts new file mode 100644 index 0000000000..e6d932f676 --- /dev/null +++ b/spec/operators/do-spec.ts @@ -0,0 +1,214 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Subject = Rx.Subject; + +describe('Observable.prototype.do()', () => { + asDiagram('do(x => console.log(x))')('should mirror multiple values and complete', () => { + const e1 = cold('--1--2--3--|'); + const e1subs = '^ !'; + const expected = '--1--2--3--|'; + + const result = (e1).do(); + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should next with a callback', () => { + let value = null; + Observable.of(42).do(function (x) { + value = x; + }) + .subscribe(); + + expect(value).toBe(42); + }); + + it('should complete with a callback', () => { + let err = null; + Observable.throw('bad').do(null, function (x) { + err = x; + }) + .subscribe(null, function (ex) { + expect(ex).toBe('bad'); + }); + + expect(err).toBe('bad'); + }); + + it('should handle everything with an observer', () => { + const expected = [1,2,3]; + const results = []; + let completeCalled = false; + Observable.of(1,2,3) + .do({ + next: (x: number) => { + results.push(x); + }, + error: (err: any) => { + throw 'should not be called'; + }, + complete: () => { + completeCalled = true; + } + }) + .subscribe(); + + expect(completeCalled).toBe(true); + expect(results).toEqual(expected); + }); + + it('should handle everything with a Subject', () => { + const expected = [1,2,3]; + const results = []; + let completeCalled = false; + const subject = new Subject(); + + subject.subscribe({ + next: (x: any) => { + results.push(x); + }, + error: (err: any) => { + throw 'should not be called'; + }, + complete: () => { + completeCalled = true; + } + }); + + Observable.of(1,2,3) + .do(subject) + .subscribe(); + + expect(completeCalled).toBe(true); + expect(results).toEqual(expected); + }); + + it('should handle an error with a callback', () => { + let errored = false; + Observable.throw('bad').do(null, (err: any) => { + expect(err).toBe('bad'); + }) + .subscribe(null, (err: any) => { + errored = true; + expect(err).toBe('bad'); + }); + + expect(errored).toBe(true); + }); + + it('should handle an error with observer', () => { + let errored = false; + Observable.throw('bad').do({ error: function (err) { + expect(err).toBe('bad'); + } }) + .subscribe(null, function (err) { + errored = true; + expect(err).toBe('bad'); + }); + + expect(errored).toBe(true); + }); + + it('should handle complete with observer', () => { + let completed = false; + + Observable.empty().do({ + complete: () => { + completed = true; + } + }).subscribe(); + + expect(completed).toBe(true); + }); + + it('should handle next with observer', () => { + let value = null; + + Observable.of('hi').do({ + next: (x: string) => { + value = x; + } + }).subscribe(); + + expect(value).toBe('hi'); + }); + + it('should raise error if next handler raises error', () => { + Observable.of('hi').do({ + next: (x: string) => { + throw new Error('bad'); + } + }).subscribe(null, (err: any) => { + expect(err.message).toBe('bad'); + }); + }); + + it('should raise error if error handler raises error', () => { + Observable.throw('ops').do({ + error: (x: any) => { + throw new Error('bad'); + } + }).subscribe(null, (err: any) => { + expect(err.message).toBe('bad'); + }); + }); + + it('should raise error if complete handler raises error', () => { + Observable.empty().do({ + complete: () => { + throw new Error('bad'); + } + }).subscribe(null, (err: any) => { + expect(err.message).toBe('bad'); + }); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--1--2--3--#'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '--1--2-- '; + + const result = (e1).do(); + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--1--2--3--#'); + const e1subs = '^ ! '; + const expected = '--1--2-- '; + const unsub = ' ! '; + + const result = (e1) + .mergeMap((x: any) => Observable.of(x)) + .do() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mirror multiple values and complete', () => { + const e1 = cold('--1--2--3--|'); + const e1subs = '^ !'; + const expected = '--1--2--3--|'; + + const result = (e1).do(); + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mirror multiple values and terminate with error', () => { + const e1 = cold('--1--2--3--#'); + const e1subs = '^ !'; + const expected = '--1--2--3--#'; + + const result = (e1).do(); + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/elementAt-spec.js b/spec/operators/elementAt-spec.js deleted file mode 100644 index 8ff94bee67..0000000000 --- a/spec/operators/elementAt-spec.js +++ /dev/null @@ -1,120 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.elementAt', function () { - it.asDiagram('elementAt(2)')('should return last element by zero-based index', function () { - var source = hot('--a--b--c-d---|'); - var subs = '^ ! '; - var expected = '--------(c|) '; - - expectObservable(source.elementAt(2)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return first element by zero-based index', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '--(a|)'; - - expectObservable(source.elementAt(0)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return non-first element by zero-based index', function () { - var source = hot('--a--b--c--d--e--f--|'); - var subs = '^ !'; - var expected = '-----------(d|)'; - - expectObservable(source.elementAt(3)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return last element by zero-based index', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '--------(c|)'; - - expectObservable(source.elementAt(2)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if source is Empty Observable', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(source.elementAt(0)).toBe(expected, undefined, new Rx.ArgumentOutOfRangeError()); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should propagate error if source is Throw Observable', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(source.elementAt(0)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return Never if source is Never Observable', function () { - var source = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.elementAt(0)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source.elementAt(2); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result Observable is unsubscribed', function () { - var source = hot('--a--b--c--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .elementAt(2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should throw if index is smaller than zero', function () { - expect(function () { Observable.range(0,10).elementAt(-1); }) - .toThrow(new Rx.ArgumentOutOfRangeError()); - }); - - it('should raise error if index is out of range but does not have default value', function () { - var source = hot('--a--|'); - var subs = '^ !'; - var expected = '-----#'; - - expectObservable(source.elementAt(3)) - .toBe(expected, null, new Rx.ArgumentOutOfRangeError()); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return default value if index is out of range', function () { - var source = hot('--a--|'); - var subs = '^ !'; - var expected = '-----(x|)'; - var defaultValue = '42'; - - expectObservable(source.elementAt(3, defaultValue)).toBe(expected, { x: defaultValue }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); diff --git a/spec/operators/elementAt-spec.ts b/spec/operators/elementAt-spec.ts new file mode 100644 index 0000000000..ff44e4f564 --- /dev/null +++ b/spec/operators/elementAt-spec.ts @@ -0,0 +1,122 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.elementAt', () => { + asDiagram('elementAt(2)')('should return last element by zero-based index', () => { + const source = hot('--a--b--c-d---|'); + const subs = '^ ! '; + const expected = '--------(c|) '; + + expectObservable((source).elementAt(2)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return first element by zero-based index', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '--(a|)'; + + expectObservable((source).elementAt(0)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return non-first element by zero-based index', () => { + const source = hot('--a--b--c--d--e--f--|'); + const subs = '^ !'; + const expected = '-----------(d|)'; + + expectObservable((source).elementAt(3)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return last element by zero-based index', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '--------(c|)'; + + expectObservable((source).elementAt(2)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if source is Empty Observable', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable((source).elementAt(0)).toBe(expected, undefined, new Rx.ArgumentOutOfRangeError()); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should propagate error if source is Throw Observable', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable((source).elementAt(0)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return Never if source is Never Observable', () => { + const source = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable((source).elementAt(0)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source).elementAt(2); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result Observable is unsubscribed', () => { + const source = hot('--a--b--c--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source) + .mergeMap((x: any) => Observable.of(x)) + .elementAt(2) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should throw if index is smaller than zero', () => { + expect(() => { (Observable.range(0,10)).elementAt(-1); }) + .toThrow(new Rx.ArgumentOutOfRangeError()); + }); + + it('should raise error if index is out of range but does not have default value', () => { + const source = hot('--a--|'); + const subs = '^ !'; + const expected = '-----#'; + + expectObservable((source).elementAt(3)) + .toBe(expected, null, new Rx.ArgumentOutOfRangeError()); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return default value if index is out of range', () => { + const source = hot('--a--|'); + const subs = '^ !'; + const expected = '-----(x|)'; + const defaultValue = '42'; + + expectObservable((source).elementAt(3, defaultValue)).toBe(expected, { x: defaultValue }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); diff --git a/spec/operators/every-spec.js b/spec/operators/every-spec.js deleted file mode 100644 index 162c45f854..0000000000 --- a/spec/operators/every-spec.js +++ /dev/null @@ -1,264 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.every()', function () { - function truePredicate(x) { - return true; - } - - function predicate(x) { - return x % 5 === 0; - } - - it.asDiagram('every(x => x % 5 === 0)')('should return false if only some of element matches with predicate', function () { - var source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15, d: 18, e: 20}); - var sourceSubs = '^ ! '; - var expected = '-----------(F|) '; - - expectObservable(source.every(predicate)).toBe(expected, {F: false}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should accept thisArg with scalar observables', function () { - var thisArg = {}; - var result; - - Observable.of(1).every(function () { - result = this; - }, thisArg).subscribe(); - - expect(result).toBe(thisArg); - }); - - it('should accept thisArg with array observables', function () { - var thisArg = {}; - var result; - - Observable.of(1,2,3,4).every(function () { - result = this; - }, thisArg).subscribe(); - - expect(result).toBe(thisArg); - }); - - it('should accept thisArg with ordinary observables', function () { - var thisArg = {}; - var result; - - Observable.create(function (observer) { - observer.next(1); - observer.complete(); - }) - .every(function () { - result = this; - }, thisArg).subscribe(); - - expect(result).toBe(thisArg); - }); - - it('should emit true if source is empty', function () { - var source = hot('-----|'); - var sourceSubs = '^ !'; - var expected = '-----(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: true}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit false if single source of element does not match with predicate', function () { - var source = hot('--a--|'); - var sourceSubs = '^ !'; - var expected = '--(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: false}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit false if none of element does not match with predicate', function () { - var source = hot('--a--b--c--d--e--|'); - var sourceSubs = '^ !'; - var expected = '--(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: false}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should return false if only some of element matches with predicate', function () { - var source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15}); - var sourceSubs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: false}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15}); - var sourceSubs = '^ ! '; - var expected = '-------- '; - var unsub = ' ! '; - - var result = source.every(predicate); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not break unsubscription chains when result Observable is unsubscribed', function () { - var source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15}); - var sourceSubs = '^ ! '; - var expected = '-------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .every(predicate) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should propagate error if predicate eventually throws', function () { - var source = hot('--a--b--c--d--e--|'); - var sourceSubs = '^ !'; - var expected = '--------#'; - - function faultyPredicate(x) { - if (x === 'c') { - throw 'error'; - } else { - return true; - } - } - - expectObservable(source.every(faultyPredicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit true if single source element match with predicate', function () { - var source = hot('--a--|', {a: 5}); - var sourceSubs = '^ !'; - var expected = '-----(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: true}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit true if Scalar source matches with predicate', function () { - var source = Observable.of(5); - var expected = '(T|)'; - - expectObservable(source.every(predicate)).toBe(expected, {T: true}); - }); - - it('should emit false if Scalar source does not match with predicate', function () { - var source = Observable.of(3); - var expected = '(F|)'; - - expectObservable(source.every(predicate)).toBe(expected, {F: false}); - }); - - it('should propagate error if predicate throws on Scalar source', function () { - var source = Observable.of(3); - var expected = '#'; - - function faultyPredicate(x) { - throw 'error'; - } - - expectObservable(source.every(faultyPredicate)).toBe(expected); - }); - - it('should emit true if Array source matches with predicate', function () { - var source = Observable.of(5, 10, 15, 20); - var expected = '(T|)'; - - expectObservable(source.every(predicate)).toBe(expected, {T: true}); - }); - - it('should emit false if Array source does not match with predicate', function () { - var source = Observable.of(5, 9, 15, 20); - var expected = '(F|)'; - - expectObservable(source.every(predicate)).toBe(expected, {F: false}); - }); - - it('should propagate error if predicate eventually throws on Array source', function () { - var source = Observable.of(5, 10, 15, 20); - var expected = '#'; - - function faultyPredicate(x) { - if (x === 15) { - throw 'error'; - } - return true; - } - - expectObservable(source.every(faultyPredicate)).toBe(expected); - }); - - it('should emit true if all source element matches with predicate', function () { - var source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15, d: 20, e: 25}); - var sourceSubs = '^ !'; - var expected = '-----------------(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: true}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should raise error if source raises error', function () { - var source = hot('--#'); - var sourceSubs = '^ !'; - var expected = '--#'; - - expectObservable(source.every(truePredicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not completes if source never emits', function () { - var source = cold('-'); - var sourceSubs = '^'; - var expected = '-'; - - expectObservable(source.every(truePredicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit true if source element matches with predicate after subscription', function () { - var source = hot('--z--^--a--b--c--d--e--|', {a: 5, b: 10, c: 15, d: 20, e: 25}); - var sourceSubs = '^ !'; - var expected = '------------------(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: true}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit false if source element does not match with predicate after subscription', function () { - var source = hot('--z--^--b--c--z--d--|', {a: 5, b: 10, c: 15, d: 20}); - var sourceSubs = '^ !'; - var expected = '---------(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: false}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should raise error if source raises error after subscription', function () { - var source = hot('--z--^--#'); - var sourceSubs = '^ !'; - var expected = '---#'; - - expectObservable(source.every(truePredicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit true if source does not emit after subscription', function () { - var source = hot('--z--^-----|'); - var sourceSubs = '^ !'; - var expected = '------(x|)'; - - expectObservable(source.every(predicate)).toBe(expected, {x: true}); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); -}); \ No newline at end of file diff --git a/spec/operators/every-spec.ts b/spec/operators/every-spec.ts new file mode 100644 index 0000000000..d8eea2810e --- /dev/null +++ b/spec/operators/every-spec.ts @@ -0,0 +1,260 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.every()', () => { + function truePredicate(x) { + return true; + } + + function predicate(x) { + return x % 5 === 0; + } + + asDiagram('every(x => x % 5 === 0)')('should return false if only some of element matches with predicate', () => { + const source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15, d: 18, e: 20}); + const sourceSubs = '^ ! '; + const expected = '-----------(F|) '; + + expectObservable(source.every(predicate)).toBe(expected, {F: false}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should accept thisArg with scalar observables', () => { + const thisArg = {}; + + Observable.of(1).every(function (value: number, index: number) { + expect(this).toBe(thisArg); + return true; + }, thisArg).subscribe(); + + }); + + it('should accept thisArg with array observables', () => { + const thisArg = {}; + + Observable.of(1,2,3,4).every(function (value: number, index: number) { + expect(this).toBe(thisArg); + return true; + }, thisArg).subscribe(); + }); + + it('should accept thisArg with ordinary observables', () => { + const thisArg = {}; + + Observable.create((observer: Rx.Observer) => { + observer.next(1); + observer.complete(); + }) + .every(function (value: number, index: number) { + expect(this).toBe(thisArg); + }, thisArg).subscribe(); + }); + + it('should emit true if source is empty', () => { + const source = hot('-----|'); + const sourceSubs = '^ !'; + const expected = '-----(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: true}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit false if single source of element does not match with predicate', () => { + const source = hot('--a--|'); + const sourceSubs = '^ !'; + const expected = '--(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: false}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit false if none of element does not match with predicate', () => { + const source = hot('--a--b--c--d--e--|'); + const sourceSubs = '^ !'; + const expected = '--(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: false}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should return false if only some of element matches with predicate', () => { + const source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15}); + const sourceSubs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: false}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15}); + const sourceSubs = '^ ! '; + const expected = '-------- '; + const unsub = ' ! '; + + const result = source.every(predicate); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not break unsubscription chains when result Observable is unsubscribed', () => { + const source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15}); + const sourceSubs = '^ ! '; + const expected = '-------- '; + const unsub = ' ! '; + + const result = source + .mergeMap((x: any) => Observable.of(x)) + .every(predicate) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should propagate error if predicate eventually throws', () => { + const source = hot('--a--b--c--d--e--|'); + const sourceSubs = '^ !'; + const expected = '--------#'; + + function faultyPredicate(x) { + if (x === 'c') { + throw 'error'; + } else { + return true; + } + } + + expectObservable(source.every(faultyPredicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit true if single source element match with predicate', () => { + const source = hot('--a--|', {a: 5}); + const sourceSubs = '^ !'; + const expected = '-----(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: true}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit true if Scalar source matches with predicate', () => { + const source = Observable.of(5); + const expected = '(T|)'; + + expectObservable(source.every(predicate)).toBe(expected, {T: true}); + }); + + it('should emit false if Scalar source does not match with predicate', () => { + const source = Observable.of(3); + const expected = '(F|)'; + + expectObservable(source.every(predicate)).toBe(expected, {F: false}); + }); + + it('should propagate error if predicate throws on Scalar source', () => { + const source = Observable.of(3); + const expected = '#'; + + function faultyPredicate(x) { + throw 'error'; + } + + expectObservable(source.every(faultyPredicate)).toBe(expected); + }); + + it('should emit true if Array source matches with predicate', () => { + const source = Observable.of(5, 10, 15, 20); + const expected = '(T|)'; + + expectObservable(source.every(predicate)).toBe(expected, {T: true}); + }); + + it('should emit false if Array source does not match with predicate', () => { + const source = Observable.of(5, 9, 15, 20); + const expected = '(F|)'; + + expectObservable(source.every(predicate)).toBe(expected, {F: false}); + }); + + it('should propagate error if predicate eventually throws on Array source', () => { + const source = Observable.of(5, 10, 15, 20); + const expected = '#'; + + function faultyPredicate(x) { + if (x === 15) { + throw 'error'; + } + return true; + } + + expectObservable(source.every(faultyPredicate)).toBe(expected); + }); + + it('should emit true if all source element matches with predicate', () => { + const source = hot('--a--b--c--d--e--|', {a: 5, b: 10, c: 15, d: 20, e: 25}); + const sourceSubs = '^ !'; + const expected = '-----------------(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: true}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should raise error if source raises error', () => { + const source = hot('--#'); + const sourceSubs = '^ !'; + const expected = '--#'; + + expectObservable(source.every(truePredicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not completes if source never emits', () => { + const source = cold('-'); + const sourceSubs = '^'; + const expected = '-'; + + expectObservable(source.every(truePredicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit true if source element matches with predicate after subscription', () => { + const source = hot('--z--^--a--b--c--d--e--|', {a: 5, b: 10, c: 15, d: 20, e: 25}); + const sourceSubs = '^ !'; + const expected = '------------------(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: true}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit false if source element does not match with predicate after subscription', () => { + const source = hot('--z--^--b--c--z--d--|', {a: 5, b: 10, c: 15, d: 20}); + const sourceSubs = '^ !'; + const expected = '---------(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: false}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should raise error if source raises error after subscription', () => { + const source = hot('--z--^--#'); + const sourceSubs = '^ !'; + const expected = '---#'; + + expectObservable(source.every(truePredicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit true if source does not emit after subscription', () => { + const source = hot('--z--^-----|'); + const sourceSubs = '^ !'; + const expected = '------(x|)'; + + expectObservable(source.every(predicate)).toBe(expected, {x: true}); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); +}); \ No newline at end of file diff --git a/spec/operators/exhaust-spec.js b/spec/operators/exhaust-spec.js deleted file mode 100644 index 6f6f039a44..0000000000 --- a/spec/operators/exhaust-spec.js +++ /dev/null @@ -1,215 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Promise = require('promise'); - -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.exhaust()', function () { - it.asDiagram('exhaust')('should handle a hot observable of hot observables', function () { - var x = cold( '--a---b---c--| '); - var y = cold( '---d--e---f---| '); - var z = cold( '---g--h---i---|'); - var e1 = hot( '------x-------y-----z-------------|', { x: x, y: y, z: z }); - var expected = '--------a---b---c------g--h---i---|'; - - expectObservable(e1.exhaust()).toBe(expected); - }); - - it('should switch to first immediately-scheduled inner Observable', function () { - var e1 = cold( '(ab|)'); - var e1subs = '(^!)'; - var e2 = cold( '(cd|)'); - var e2subs = []; - var expected = '(ab|)'; - - expectObservable(Observable.of(e1, e2).exhaust()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a hot observable of observables', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---| '); - var ysubs = []; - var z = cold( '---g--h---i---|'); - var zsubs = ' ^ !'; - var e1 = hot( '------x-------y-----z-------------|', { x: x, y: y, z: z }); - var expected = '--------a---b---c------g--h---i---|'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - }); - - it('should handle a hot observable of observables, outer is unsubscribed early', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = []; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var unsub = ' ! '; - var expected = '--------a---b--- '; - - expectObservable(e1.exhaust(), unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = []; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var unsub = ' ! '; - var expected = '--------a---b---- '; - - var result = e1 - .mergeMap(function (i) { return Observable.of(i); }) - .exhaust() - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, inner never completes', function () { - var x = cold( '--a---b--| '); - var xsubs = ' ^ ! '; - var y = cold( '-d---e- '); - var ysubs = []; - var z = cold( '---f--g---h--'); - var zsubs = ' ^ '; - var e1 = hot( '---x---y------z----------| ', { x: x, y: y, z: z }); - var expected = '-----a---b-------f--g---h--'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - }); - - it('should handle a synchronous switch and stay on the first inner observable', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---| '); - var ysubs = []; - var e1 = hot( '------(xy)------------|', { x: x, y: y }); - var expected = '--------a---b---c-----|'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, one inner throws', function () { - var x = cold( '--a---# '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = []; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var expected = '--------a---# '; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, outer throws', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = []; - var e1 = hot( '------x-------y-------# ', { x: x, y: y }); - var expected = '--------a---b---c-----# '; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle an empty hot observable', function () { - var e1 = hot( '------|'); - var e1subs = '^ !'; - var expected = '------|'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a never hot observable', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete not before the outer completes', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var e1 = hot( '------x---------------|', { x: x }); - var expected = '--------a---b---c-----|'; - - expectObservable(e1.exhaust()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - }); - - it('should handle an observable of promises', function (done) { - var expected = [1]; - - Observable.of(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)) - .exhaust() - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - done(); - }); - }); - - it('should handle an observable of promises, where one rejects', function (done) { - Observable.of(Promise.reject(2), Promise.resolve(1)) - .exhaust() - .subscribe(function (x) { - expect(false).toBe(true); - }, function (err) { - expect(err).toBe(2); - done(); - }, function () { - expect(false).toBe(true); - }); - }); -}); diff --git a/spec/operators/exhaust-spec.ts b/spec/operators/exhaust-spec.ts new file mode 100644 index 0000000000..4452aba128 --- /dev/null +++ b/spec/operators/exhaust-spec.ts @@ -0,0 +1,215 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.exhaust()', () => { + asDiagram('exhaust')('should handle a hot observable of hot observables', () => { + const x = cold( '--a---b---c--| '); + const y = cold( '---d--e---f---| '); + const z = cold( '---g--h---i---|'); + const e1 = hot( '------x-------y-----z-------------|', { x: x, y: y, z: z }); + const expected = '--------a---b---c------g--h---i---|'; + + expectObservable((e1).exhaust()).toBe(expected); + }); + + it('should switch to first immediately-scheduled inner Observable', () => { + const e1 = cold( '(ab|)'); + const e1subs = '(^!)'; + const e2 = cold( '(cd|)'); + const e2subs = []; + const expected = '(ab|)'; + + expectObservable((Observable.of(e1, e2)).exhaust()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a hot observable of observables', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---| '); + const ysubs = []; + const z = cold( '---g--h---i---|'); + const zsubs = ' ^ !'; + const e1 = hot( '------x-------y-----z-------------|', { x: x, y: y, z: z }); + const expected = '--------a---b---c------g--h---i---|'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + }); + + it('should handle a hot observable of observables, outer is unsubscribed early', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = []; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const unsub = ' ! '; + const expected = '--------a---b--- '; + + expectObservable((e1).exhaust(), unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = []; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const unsub = ' ! '; + const expected = '--------a---b---- '; + + const result = (e1) + .mergeMap((x: any) => Observable.of(x)) + .exhaust() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, inner never completes', () => { + const x = cold( '--a---b--| '); + const xsubs = ' ^ ! '; + const y = cold( '-d---e- '); + const ysubs = []; + const z = cold( '---f--g---h--'); + const zsubs = ' ^ '; + const e1 = hot( '---x---y------z----------| ', { x: x, y: y, z: z }); + const expected = '-----a---b-------f--g---h--'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + }); + + it('should handle a synchronous switch and stay on the first inner observable', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---| '); + const ysubs = []; + const e1 = hot( '------(xy)------------|', { x: x, y: y }); + const expected = '--------a---b---c-----|'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, one inner throws', () => { + const x = cold( '--a---# '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = []; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const expected = '--------a---# '; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, outer throws', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = []; + const e1 = hot( '------x-------y-------# ', { x: x, y: y }); + const expected = '--------a---b---c-----# '; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle an empty hot observable', () => { + const e1 = hot( '------|'); + const e1subs = '^ !'; + const expected = '------|'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a never hot observable', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete not before the outer completes', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const e1 = hot( '------x---------------|', { x: x }); + const expected = '--------a---b---c-----|'; + + expectObservable((e1).exhaust()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + }); + + it('should handle an observable of promises', (done: DoneSignature) => { + const expected = [1]; + + (Observable.of(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3))) + .exhaust() + .subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + done(); + }); + }); + + it('should handle an observable of promises, where one rejects', (done: DoneSignature) => { + (Observable.of(Promise.reject(2), Promise.resolve(1))) + .exhaust() + .subscribe((x: any) => { + done.fail('should not be called'); + }, (err: any) => { + expect(err).toBe(2); + done(); + }, () => { + done.fail('should not be called'); + }); + }); +}); diff --git a/spec/operators/exhaustMap-spec.js b/spec/operators/exhaustMap-spec.ts similarity index 79% rename from spec/operators/exhaustMap-spec.js rename to spec/operators/exhaustMap-spec.ts index 714df76441..c2454d15a5 100644 --- a/spec/operators/exhaustMap-spec.js +++ b/spec/operators/exhaustMap-spec.ts @@ -1,58 +1,58 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Promise = require('promise'); +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; -describe('Observable.prototype.exhaustMap()', function () { - it('should handle outer throw', function () { +describe('Observable.prototype.exhaustMap()', () => { + it('should handle outer throw', () => { var x = cold('--a--b--c--|'); var xsubs = []; var e1 = cold('#'); var e1subs = '(^!)'; var expected = '#'; - var result = e1.exhaustMap(function () { return x; }); + var result = (e1).exhaustMap(() => x); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should handle outer empty', function () { + it('should handle outer empty', () => { var x = cold('--a--b--c--|'); var xsubs = []; var e1 = cold('|'); var e1subs = '(^!)'; var expected = '|'; - var result = e1.exhaustMap(function () { return x; }); + var result = (e1).exhaustMap(() => x); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should handle outer never', function () { + it('should handle outer never', () => { var x = cold('--a--b--c--|'); var xsubs = []; var e1 = cold('-'); var e1subs = '^'; var expected = '-'; - var result = e1.exhaustMap(function () { return x; }); + var result = (e1).exhaustMap(() => x); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should raise error if project throws', function () { + it('should raise error if project throws', () => { var e1 = hot('---x---------y-----------------z-------------|'); var e1subs = '^ !'; var expected = '---#'; - var result = e1.exhaustMap(function (value) { + var result = (e1).exhaustMap((value: any) => { throw 'error'; }); @@ -60,25 +60,24 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should raise error if selector throws', function () { + it('should raise error if selector throws', () => { var x = cold( '--a--b--c--| '); var xsubs = ' ^ ! '; var e1 = hot('---x---------y----z----|'); var e1subs = '^ ! '; var expected = '-----# '; - var result = e1.exhaustMap(function (value) { - return x; - }, function () { - throw 'error'; - }); + var result = (e1).exhaustMap((value: any) => x, + () => { + throw 'error'; + }); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch with a selector function', function () { + it('should switch with a selector function', () => { var x = cold( '--a--b--c--| '); var xsubs = ' ^ ! '; var y = cold( '--d--e--f--| '); @@ -91,9 +90,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y, z: z }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -102,7 +99,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner cold observables, outer is unsubscribed early', function () { + it('should switch inner cold observables, outer is unsubscribed early', () => { var x = cold( '--a--b--c--| '); var xsubs = ' ^ ! '; var y = cold( '--d--e--f--| '); @@ -116,9 +113,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y, z: z }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result, unsub).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -127,7 +122,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { var x = cold( '--a--b--c--| '); var xsubs = ' ^ ! '; var y = cold( '--d--e--f--| '); @@ -141,10 +136,10 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y, z: z }; - var result = e1 - .mergeMap(function (i) { return Observable.of(i); }) - .exhaustMap(function (value) { return observableLookup[value]; }) - .mergeMap(function (i) { return Observable.of(i); }); + var result = (e1) + .mergeMap((x: any) => Observable.of(x)) + .exhaustMap((value: any) => observableLookup[value]) + .mergeMap((x: any) => Observable.of(x)); expectObservable(result, unsub).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -153,7 +148,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner cold observables, inner never completes', function () { + it('should switch inner cold observables, inner never completes', () => { var x = cold( '--a--b--c--| '); var xsubs = ' ^ ! '; var y = cold( '--d--e--f--| '); @@ -166,9 +161,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y, z: z }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -177,7 +170,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should handle a synchronous switch an stay on the first inner observable', function () { + it('should handle a synchronous switch an stay on the first inner observable', () => { var x = cold( '--a--b--c--d--e--| '); var xsubs = ' ^ ! '; var y = cold( '---f---g---h---i--| '); @@ -188,9 +181,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -198,7 +189,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner cold observables, one inner throws', function () { + it('should switch inner cold observables, one inner throws', () => { var x = cold( '--a--b--c--d--# '); var xsubs = ' ^ ! '; var y = cold( '---f---g---h---i--'); @@ -209,9 +200,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -219,7 +208,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner hot observables', function () { + it('should switch inner hot observables', () => { var x = hot('-----a--b--c--d--e--| '); var xsubs = ' ^ ! '; var y = hot('--p-o-o-p-------f---g---h---i--| '); @@ -232,9 +221,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y, z: z }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -243,7 +230,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner empty and empty', function () { + it('should switch inner empty and empty', () => { var x = cold('|'); var y = cold('|'); var xsubs = ' (^!) '; @@ -254,9 +241,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -264,7 +249,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner empty and never', function () { + it('should switch inner empty and never', () => { var x = cold('|'); var y = cold('-'); var xsubs = ' (^!) '; @@ -275,9 +260,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -285,7 +268,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should never switch inner never', function () { + it('should never switch inner never', () => { var x = cold('-'); var y = cold('#'); var xsubs = ' ^ '; @@ -296,9 +279,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -306,7 +287,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch inner empty and throw', function () { + it('should switch inner empty and throw', () => { var x = cold('|'); var y = cold('#'); var xsubs = ' (^!) '; @@ -317,9 +298,7 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x, y: y }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -327,7 +306,7 @@ describe('Observable.prototype.exhaustMap()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should handle outer error', function () { + it('should handle outer error', () => { var x = cold( '--a--b--c--d--e--|'); var xsubs = ' ^ ! '; var e1 = hot('---------x---------# '); @@ -336,16 +315,14 @@ describe('Observable.prototype.exhaustMap()', function () { var observableLookup = { x: x }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should switch with resultSelector goodness', function () { + it('should switch with resultSelector goodness', () => { var x = cold( '--a--b--c--d--e-| '); var xsubs = ' ^ ! '; var y = cold( '---f---g---h---i--| '); @@ -370,11 +347,8 @@ describe('Observable.prototype.exhaustMap()', function () { n: ['z', 'n', 1, 3], }; - var result = e1.exhaustMap(function (value) { - return observableLookup[value]; - }, function (innerValue, outerValue, innerIndex, outerIndex) { - return [innerValue, outerValue, innerIndex, outerIndex]; - }); + var result = (e1).exhaustMap((value: any) => observableLookup[value], + (innerValue, outerValue, innerIndex, outerIndex) => [innerValue, outerValue, innerIndex, outerIndex]); expectObservable(result).toBe(expected, expectedValues); expectSubscriptions(x.subscriptions).toBe(xsubs); diff --git a/spec/operators/expand-spec.js b/spec/operators/expand-spec.ts similarity index 56% rename from spec/operators/expand-spec.js rename to spec/operators/expand-spec.ts index db750075d7..a05b7f5b85 100644 --- a/spec/operators/expand-spec.js +++ b/spec/operators/expand-spec.ts @@ -1,21 +1,23 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.expand()', function () { - it('should map and recursively flatten', function () { - var values = { +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const Symbol: any; +const Observable = Rx.Observable; + +describe('Observable.prototype.expand()', () => { + it('should map and recursively flatten', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a--b--c--d--(e|)'; + const e1 = hot('(a|)', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a--b--c--d--(e|)'; /* expectation explanation: (conjunction junction?) ... @@ -31,31 +33,32 @@ describe('Observable.prototype.expand()', function () { a--b--c--d--(e|) */ - var result = e1.expand(function (x) { + const result = (e1).expand((x: any, index: number): Rx.Observable => { if (x === 16) { return Observable.empty(); + } else { + return cold(e2shape, { z: x + x }); } - return cold(e2shape, { z: x + x }); }); expectObservable(result).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should map and recursively flatten, and handle event raised error', function () { - var values = { + it('should map and recursively flatten, and handle event raised error', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a--b--c--(d#)'; + const e1 = hot('(a|)', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a--b--c--(d#)'; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number) => { if (x === 8) { return cold('#'); } @@ -66,20 +69,20 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should map and recursively flatten, and propagate error thrown from projection', function () { - var values = { + it('should map and recursively flatten, and propagate error thrown from projection', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a--b--c--(d#)'; + const e1 = hot('(a|)', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a--b--c--(d#)'; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number) => { if (x === 8) { throw 'error'; } @@ -90,21 +93,21 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should allow unsubscribing early', function () { - var values = { + it('should allow unsubscribing early', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var unsub = ' ! '; - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a--b--c- '; + const e1 = hot('(a|)', values); + const unsub = ' ! '; + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a--b--c- '; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number): Rx.Observable => { if (x === 16) { return Observable.empty(); } @@ -115,48 +118,48 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var values = { + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a--b--c- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .expand(function (x) { + const e1 = hot('(a|)', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a--b--c- '; + const unsub = ' ! '; + + const result = (e1) + .mergeMap((x: any) => Observable.of(x)) + .expand((x: number): Rx.Observable => { if (x === 16) { return Observable.empty(); } return cold(e2shape, { z: x + x }); }) - .mergeMap(function (x) { return Observable.of(x); }); + .mergeMap((x: any) => Observable.of(x)); expectObservable(result, unsub).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should allow concurrent expansions', function () { - var values = { + it('should allow concurrent expansions', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('a-a| ', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a-ab-bc-cd-de-(e|)'; + const e1 = hot('a-a| ', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a-ab-bc-cd-de-(e|)'; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number): Rx.Observable => { if (x === 16) { return Observable.empty(); } @@ -167,8 +170,8 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should allow configuring the concurrency limit parameter to 1', function () { - var values = { + it('should allow configuring the concurrency limit parameter to 1', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, @@ -180,8 +183,8 @@ describe('Observable.prototype.expand()', function () { y: 80, // x + x z: 160, // y + y }; - var e1 = hot('a-u|', values); - var e2shape = '---(z|)'; + const e1 = hot('a-u|', values); + const e2shape = '---(z|)'; // ---(z|) // ---(z|) // ---(z|) @@ -190,11 +193,11 @@ describe('Observable.prototype.expand()', function () { // ---(z|) // ---(z|) // Notice how for each column, there is at most 1 `-` character. - var e1subs = '^ ! '; - var expected = 'a--u--b--v--c--x--d--y--(ez|)'; - var concurrencyLimit = 1; + const e1subs = '^ ! '; + const expected = 'a--u--b--v--c--x--d--y--(ez|)'; + const concurrencyLimit = 1; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number): Rx.Observable => { if (x === 16 || x === 160) { return Observable.empty(); } @@ -205,8 +208,8 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should allow configuring the concurrency limit parameter to 2', function () { - var values = { + it('should allow configuring the concurrency limit parameter to 2', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, @@ -214,8 +217,8 @@ describe('Observable.prototype.expand()', function () { v: 20, // u + u x: 40, // v + v }; - var e1 = hot('a---au|', values); - var e2shape = '------(z|)'; + const e1 = hot('a---au|', values); + const e2shape = '------(z|)'; // ------(z|) // ------(z|) // ------(z|) @@ -223,11 +226,11 @@ describe('Observable.prototype.expand()', function () { // ------(z|) // ------(z|) // Notice how for each column, there is at most 2 `-` characters. - var e1subs = '^ ! '; - var expected = 'a---a-u---b-b---v-(cc)(x|)'; - var concurrencyLimit = 2; + const e1subs = '^ ! '; + const expected = 'a---a-u---b-b---v-(cc)(x|)'; + const concurrencyLimit = 2; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number): Rx.Observable => { if (x === 4 || x === 40) { return Observable.empty(); } @@ -238,8 +241,8 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should ignore concurrency limit if it is not passed', function () { - var values = { + it('should ignore concurrency limit if it is not passed', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, @@ -251,13 +254,13 @@ describe('Observable.prototype.expand()', function () { y: 80, // x + x z: 160, // y + y }; - var e1 = hot('a-u| ', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a-ub-vc-xd-ye-(z|)'; - var concurrencyLimit = 100; + const e1 = hot('a-u| ', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a-ub-vc-xd-ye-(z|)'; + const concurrencyLimit = 100; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number): Rx.Observable => { if (x === 16 || x === 160) { return Observable.empty(); } @@ -268,19 +271,19 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should map and recursively flatten with scalars', function () { - var values = { + it('should map and recursively flatten with scalars', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var e1subs = '(^!)'; - var expected = '(abcde|)'; + const e1 = hot('(a|)', values); + const e1subs = '(^!)'; + const expected = '(abcde|)'; - var result = e1.expand(function (x) { + const result = (e1).expand((x: number) => { if (x === 16) { return Observable.empty(); } @@ -291,86 +294,91 @@ describe('Observable.prototype.expand()', function () { expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should recursively flatten promises', function (done) { - var expected = [1, 2, 4, 8, 16]; - Observable.of(1) - .expand(function (x) { + it('should recursively flatten promises', (done: DoneSignature) => { + const expected = [1, 2, 4, 8, 16]; + (Observable.of(1)) + .expand((x: number): any => { if (x === 16) { return Observable.empty(); } return Promise.resolve(x + x); }) - .subscribe(function (x) { + .subscribe((x: number) => { expect(x).toBe(expected.shift()); - }, null, function () { + }, null, () => { expect(expected.length).toBe(0); done(); }); }); - it('should recursively flatten Arrays', function (done) { - var expected = [1, 2, 4, 8, 16]; - Observable.of(1) - .expand(function (x) { + it('should recursively flatten Arrays', (done: DoneSignature) => { + const expected = [1, 2, 4, 8, 16]; + (Observable).of(1) + .expand((x: number): any => { if (x === 16) { return Observable.empty(); } return [x + x]; }) - .subscribe(function (x) { + .subscribe((x: number) => { expect(x).toBe(expected.shift()); - }, null, function () { + }, null, () => { expect(expected.length).toBe(0); done(); }); }); - it('should recursively flatten lowercase-o observables', function (done) { - var expected = [1, 2, 4, 8, 16]; + it('should recursively flatten lowercase-o observables', (done: DoneSignature) => { + const expected = [1, 2, 4, 8, 16]; + const project = (x: any, index: number) => { + if (x === 16) { + return Observable.empty(); + } - Observable.of(1) - .expand(function (x) { - if (x === 16) { - return Observable.empty(); + const ish = { + subscribe: (observer: Rx.Observer) => { + observer.next(x + x); + observer.complete(); } + }; - var ish = { - subscribe: function (observer) { - observer.next(x + x); - observer.complete(); - } - }; + ish[Symbol.observable] = function () { + return this; + }; + return ish; + }; - ish[Symbol.observable] = function () { return this; }; - return ish; - }) - .subscribe(function (x) { + (Observable.of(1)) + .expand(project) + .subscribe((x: number) => { expect(x).toBe(expected.shift()); - }, null, function () { + }, null, () => { expect(expected.length).toBe(0); done(); }); }); - it('should work when passing undefined for the optional arguments', function () { - var values = { + it('should work when passing undefined for the optional arguments', () => { + const values = { a: 1, b: 1 + 1, // a + a, c: 2 + 2, // b + b, d: 4 + 4, // c + c, e: 8 + 8, // d + d }; - var e1 = hot('(a|)', values); - var e1subs = '^ ! '; - var e2shape = '---(z|) '; - var expected = 'a--b--c--d--(e|)'; + const e1 = hot('(a|)', values); + const e1subs = '^ ! '; + const e2shape = '---(z|) '; + const expected = 'a--b--c--d--(e|)'; - var result = e1.expand(function (x) { + const project = (x: any, index: number): Rx.Observable => { if (x === 16) { return Observable.empty(); } return cold(e2shape, { z: x + x }); - }, undefined, undefined); + }; + + const result = (e1).expand(project, undefined, undefined); expectObservable(result).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); diff --git a/spec/operators/filter-spec.js b/spec/operators/filter-spec.js deleted file mode 100644 index 59cd8aa68e..0000000000 --- a/spec/operators/filter-spec.js +++ /dev/null @@ -1,274 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot, cold, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.filter()', function () { - function oddFilter(x) { - return (+x) % 2 === 1; - } - - function isPrime(i) { - if (+i <= 1) { return false; } - var max = Math.floor(Math.sqrt(+i)); - for (var j = 2; j <= max; ++j) { - if (+i % j === 0) { return false; } - } - return true; - } - - it.asDiagram('filter(x => x % 2 === 1)')('should filter out even values', function () { - var source = hot('--0--1--2--3--4--|'); - var subs = '^ !'; - var expected = '-----1-----3-----|'; - - expectObservable(source.filter(oddFilter)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter in only prime numbers', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ !'; - var expected = '--3---5----7-------|'; - - expectObservable(source.filter(isPrime)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter with an always-true predicate', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var expected = '--3-4-5-6--7-8--9--|'; - var predicate = function () { return true; }; - - expectObservable(source.filter(predicate)).toBe(expected); - }); - - it('should filter with an always-false predicate', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var expected = '-------------------|'; - var predicate = function () { return false; }; - - expectObservable(source.filter(predicate)).toBe(expected); - }); - - it('should filter in only prime numbers, source unsubscribes early', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ ! '; - var unsub = ' ! '; - var expected = '--3---5----7- '; - - expectObservable(source.filter(isPrime), unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter in only prime numbers, source throws', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--#'); - var subs = '^ !'; - var expected = '--3---5----7-------#'; - - expectObservable(source.filter(isPrime)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter in only prime numbers, but predicate throws', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ ! '; - var expected = '--3---5-# '; - - var invoked = 0; - var predicate = function (x) { - invoked++; - if (invoked === 4) { - throw 'error'; - } - return isPrime(x); - }; - - expectObservable(source.filter(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter in only prime numbers, predicate with index', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ !'; - var expected = '--3--------7-------|'; - - var predicate = function (x, i) { - return isPrime((+x) + i * 10); - }; - - expectObservable(source.filter(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should invoke predicate once for each checked value', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var expected = '--3---5----7-------|'; - - var invoked = 0; - var predicate = function (x) { - invoked++; - return isPrime(x); - }; - - var r = source - .filter(predicate) - .do(null, null, function () { - expect(invoked).toEqual(7); - }); - - expectObservable(r).toBe(expected); - }); - - it('should filter in only prime numbers, predicate with index, ' + - 'source unsubscribes early', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ ! '; - var unsub = ' ! '; - var expected = '--3--------7- '; - - var predicate = function (x, i) { - return isPrime((+x) + i * 10); - }; - - expectObservable(source.filter(predicate), unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter in only prime numbers, predicate with index, source throws', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--#'); - var subs = '^ !'; - var expected = '--3--------7-------#'; - - var predicate = function (x, i) { - return isPrime((+x) + i * 10); - }; - - expectObservable(source.filter(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should filter in only prime numbers, predicate with index and throws', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ ! '; - var expected = '--3-----# '; - - var invoked = 0; - var predicate = function (x, i) { - invoked++; - if (invoked === 4) { - throw 'error'; - } - return isPrime((+x) + i * 10); - }; - - expectObservable(source.filter(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should compose with another filter to allow multiples of six', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var expected = '--------6----------|'; - - expectObservable( - source - .filter(function (x) { return x % 2 === 0; }) - .filter(function (x) { return x % 3 === 0; }) - ).toBe(expected); - }); - - it('should be able to accept and use a thisArg', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var expected = '--------6----------|'; - - function Filterer() { - this.filter1 = function (x) { return x % 2 === 0; }; - this.filter2 = function (x) { return x % 3 === 0; }; - } - - var filterer = new Filterer(); - - expectObservable( - source - .filter(function (x) { return this.filter1(x); }, filterer) - .filter(function (x) { return this.filter2(x); }, filterer) - .filter(function (x) { return this.filter1(x); }, filterer) - ).toBe(expected); - }); - - it('should be able to use filter and map composed', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var expected = '----a---b----c-----|'; - var values = { a: 16, b: 36, c: 64 }; - - expectObservable( - source - .filter(function (x) { return x % 2 === 0; }) - .map(function (x) { return x * x; }) - ).toBe(expected, values); - }); - - it('should propagate errors from the source', function () { - var source = hot('--0--1--2--3--4--#'); - var subs = '^ !'; - var expected = '-----1-----3-----#'; - - expectObservable(source.filter(oddFilter)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should support Observable.empty', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '|'; - - expectObservable(source.filter(oddFilter)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should support Observable.never', function () { - var source = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.filter(oddFilter)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should support Observable.throw', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(source.filter(oddFilter)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should send errors down the error path', function (done) { - Observable.of(42).filter(function (x) { - throw 'bad'; - }) - .subscribe(function (x) { - expect(true).toBe(false); - }, function (err) { - expect(err).toBe('bad'); - done(); - }, function () { - expect(true).toBe(false); - }); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var source = hot('-1--2--^-3-4-5-6--7-8--9--|'); - var subs = '^ ! '; - var unsub = ' ! '; - var expected = '--3---5----7- '; - - var r = source - .mergeMap(function (x) { return Observable.of(x); }) - .filter(isPrime) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(r, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); diff --git a/spec/operators/filter-spec.ts b/spec/operators/filter-spec.ts new file mode 100644 index 0000000000..a788e9f1d9 --- /dev/null +++ b/spec/operators/filter-spec.ts @@ -0,0 +1,272 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.filter()', () => { + function oddFilter(x) { + return (+x) % 2 === 1; + } + + function isPrime(i) { + if (+i <= 1) { return false; } + const max = Math.floor(Math.sqrt(+i)); + for (let j = 2; j <= max; ++j) { + if (+i % j === 0) { return false; } + } + return true; + } + + asDiagram('filter(x => x % 2 === 1)')('should filter out even values', () => { + const source = hot('--0--1--2--3--4--|'); + const subs = '^ !'; + const expected = '-----1-----3-----|'; + + expectObservable(source.filter(oddFilter)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter in only prime numbers', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ !'; + const expected = '--3---5----7-------|'; + + expectObservable(source.filter(isPrime)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter with an always-true predicate', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const expected = '--3-4-5-6--7-8--9--|'; + const predicate = () => { return true; }; + + expectObservable(source.filter(predicate)).toBe(expected); + }); + + it('should filter with an always-false predicate', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const expected = '-------------------|'; + const predicate = () => { return false; }; + + expectObservable(source.filter(predicate)).toBe(expected); + }); + + it('should filter in only prime numbers, source unsubscribes early', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ ! '; + const unsub = ' ! '; + const expected = '--3---5----7- '; + + expectObservable(source.filter(isPrime), unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter in only prime numbers, source throws', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--#'); + const subs = '^ !'; + const expected = '--3---5----7-------#'; + + expectObservable(source.filter(isPrime)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter in only prime numbers, but predicate throws', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ ! '; + const expected = '--3---5-# '; + + let invoked = 0; + function predicate(x: any, index: number) { + invoked++; + if (invoked === 4) { + throw 'error'; + } + return isPrime(x); + }; + + expectObservable((source).filter(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter in only prime numbers, predicate with index', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ !'; + const expected = '--3--------7-------|'; + + function predicate(x: any, i: number) { + return isPrime((+x) + i * 10); + } + + expectObservable((source).filter(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should invoke predicate once for each checked value', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const expected = '--3---5----7-------|'; + + let invoked = 0; + const predicate = (x: any) => { + invoked++; + return isPrime(x); + }; + + const r = source + .filter(predicate) + .do(null, null, () => { + expect(invoked).toEqual(7); + }); + + expectObservable(r).toBe(expected); + }); + + it('should filter in only prime numbers, predicate with index, ' + + 'source unsubscribes early', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ ! '; + const unsub = ' ! '; + const expected = '--3--------7- '; + + function predicate(x: any, i: number) { + return isPrime((+x) + i * 10); + } + expectObservable((source).filter(predicate), unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter in only prime numbers, predicate with index, source throws', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--#'); + const subs = '^ !'; + const expected = '--3--------7-------#'; + + function predicate(x: any, i: number) { + return isPrime((+x) + i * 10); + } + expectObservable((source).filter(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should filter in only prime numbers, predicate with index and throws', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ ! '; + const expected = '--3-----# '; + + let invoked = 0; + function predicate(x: any, i: number) { + invoked++; + if (invoked === 4) { + throw 'error'; + } + return isPrime((+x) + i * 10); + }; + + expectObservable((source).filter(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should compose with another filter to allow multiples of six', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const expected = '--------6----------|'; + + expectObservable( + source + .filter((x: number) => x % 2 === 0) + .filter((x: number) => x % 3 === 0) + ).toBe(expected); + }); + + it('should be able to accept and use a thisArg', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const expected = '--------6----------|'; + + function Filterer() { + this.filter1 = (x: number) => x % 2 === 0; + this.filter2 = (x: number) => x % 3 === 0; + } + + const filterer = new Filterer(); + + expectObservable( + source + .filter(function (x) { return this.filter1(x); }, filterer) + .filter(function (x) { return this.filter2(x); }, filterer) + .filter(function (x) { return this.filter1(x); }, filterer) + ).toBe(expected); + }); + + it('should be able to use filter and map composed', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const expected = '----a---b----c-----|'; + const values = { a: 16, b: 36, c: 64 }; + + expectObservable( + source + .filter((x: number) => x % 2 === 0) + .map((x: number) => x * x) + ).toBe(expected, values); + }); + + it('should propagate errors from the source', () => { + const source = hot('--0--1--2--3--4--#'); + const subs = '^ !'; + const expected = '-----1-----3-----#'; + + expectObservable(source.filter(oddFilter)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should support Observable.empty', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '|'; + + expectObservable(source.filter(oddFilter)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should support Observable.never', () => { + const source = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable(source.filter(oddFilter)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should support Observable.throw', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable(source.filter(oddFilter)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should send errors down the error path', (done: DoneSignature) => { + Observable.of(42).filter(((x: number, index: number) => { + throw 'bad'; + })) + .subscribe((x: number) => { + done.fail('should not be called'); + }, (err: any) => { + expect(err).toBe('bad'); + done(); + }, done.fail); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const source = hot('-1--2--^-3-4-5-6--7-8--9--|'); + const subs = '^ ! '; + const unsub = ' ! '; + const expected = '--3---5----7- '; + + const r = source + .mergeMap((x: any) => Observable.of(x)) + .filter(isPrime) + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(r, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); diff --git a/spec/operators/finally-spec.js b/spec/operators/finally-spec.ts similarity index 57% rename from spec/operators/finally-spec.js rename to spec/operators/finally-spec.ts index e0c1dbaaf1..49474d353c 100644 --- a/spec/operators/finally-spec.js +++ b/spec/operators/finally-spec.ts @@ -1,22 +1,23 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; -describe('Observable.prototype.finally()', function () { - it('should call finally after complete', function (done) { - var completed = false; +const Observable = Rx.Observable; + +describe('Observable.prototype.finally()', () => { + it('should call finally after complete', (done: DoneSignature) => { + let completed = false; Observable.of(1, 2, 3) - .finally(function () { + .finally(() => { expect(completed).toBe(true); done(); }) - .subscribe(null, null, function () { + .subscribe(null, null, () => { completed = true; }); }); - it('should call finally after error', function (done) { - var thrown = false; + it('should call finally after error', (done: DoneSignature) => { + let thrown = false; Observable.of(1, 2, 3) .map(function (x) { if (x === 3) { @@ -24,20 +25,20 @@ describe('Observable.prototype.finally()', function () { } return x; }) - .finally(function () { + .finally(() => { expect(thrown).toBe(true); done(); }) - .subscribe(null, function () { + .subscribe(null, () => { thrown = true; }); }); - it('should call finally upon disposal', function (done) { - var disposed = false; - var subscription = Observable + it('should call finally upon disposal', (done: DoneSignature) => { + let disposed = false; + const subscription = Observable .timer(100) - .finally(function () { + .finally(() => { expect(disposed).toBe(true); done(); }).subscribe(); @@ -46,7 +47,7 @@ describe('Observable.prototype.finally()', function () { }); it('should call finally when synchronously subscribing to and unsubscribing ' + - 'from a shared Observable', function (done) { + 'from a shared Observable', (done: DoneSignature) => { Observable.interval(50) .finally(done) .share() @@ -54,8 +55,8 @@ describe('Observable.prototype.finally()', function () { .unsubscribe(); }); - it('should call two finally instances in succession on a shared Observable', function (done) { - var invoked = 0; + it('should call two finally instances in succession on a shared Observable', (done: DoneSignature) => { + let invoked = 0; function checkFinally() { invoked += 1; if (invoked === 2) { diff --git a/spec/operators/find-spec.js b/spec/operators/find-spec.js deleted file mode 100644 index 0416e0b348..0000000000 --- a/spec/operators/find-spec.js +++ /dev/null @@ -1,155 +0,0 @@ -/* globals describe, it, expect, cold, hot, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.find()', function () { - function truePredicate(x) { - return true; - } - - it.asDiagram('find(x => x % 5 === 0)')('should return matching element from source emits single element', function () { - var values = {a: 3, b: 9, c: 15, d: 20}; - var source = hot('---a--b--c--d---|', values); - var subs = '^ ! '; - var expected = '---------(c|) '; - - var predicate = function (x) { return x % 5 === 0; }; - - expectObservable(source.find(predicate)).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should throw if not provided a function', function () { - expect(function () { - Observable.of('yut', 'yee', 'sam').find('yee'); - }).toThrow(new TypeError('predicate is not a function')); - }); - - it('should not emit if source does not emit', function () { - var source = hot('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.find(truePredicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return undefined if source is empty to match predicate', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '(x|)'; - - var result = source.find(truePredicate); - - expectObservable(result).toBe(expected, {x: undefined}); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return matching element from source emits single element', function () { - var source = hot('--a--|'); - var subs = '^ !'; - var expected = '--(a|)'; - - var predicate = function (value) { - return value === 'a'; - }; - - expectObservable(source.find(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return matching element from source emits multiple elements', function () { - var source = hot('--a--b---c-|'); - var subs = '^ !'; - var expected = '-----(b|)'; - - var predicate = function (value) { - return value === 'b'; - }; - - expectObservable(source.find(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should work with a custom thisArg', function () { - var source = hot('--a--b---c-|'); - var subs = '^ !'; - var expected = '-----(b|)'; - - var finder = { - target: 'b' - }; - var predicate = function (value) { - return value === this.target; - }; - - expectObservable(source.find(predicate, finder)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return undefined if element does not match with predicate', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '-----------(x|)'; - - var predicate = function (value) { - return value === 'z'; - }; - - expectObservable(source.find(predicate)).toBe(expected, { x: undefined }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source.find(function (value) { return value === 'z'; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--a--b--c--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .find(function (value) { return value === 'z'; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise if source raise error while element does not match with predicate', function () { - var source = hot('--a--b--#'); - var subs = '^ !'; - var expected = '--------#'; - - var predicate = function (value) { - return value === 'z'; - }; - - expectObservable(source.find(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if predicate throws error', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '--#'; - - var predicate = function (value) { - throw 'error'; - }; - - expectObservable(source.find(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/find-spec.ts b/spec/operators/find-spec.ts new file mode 100644 index 0000000000..62c82b5ea3 --- /dev/null +++ b/spec/operators/find-spec.ts @@ -0,0 +1,157 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.find()', () => { + function truePredicate(x) { + return true; + } + + asDiagram('find(x => x % 5 === 0)')('should return matching element from source emits single element', () => { + const values = {a: 3, b: 9, c: 15, d: 20}; + const source = hot('---a--b--c--d---|', values); + const subs = '^ ! '; + const expected = '---------(c|) '; + + const predicate = function (x) { return x % 5 === 0; }; + + expectObservable((source).find(predicate)).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should throw if not provided a function', () => { + expect(() => { + (Observable.of('yut', 'yee', 'sam')).find('yee'); + }).toThrow(new TypeError('predicate is not a function')); + }); + + it('should not emit if source does not emit', () => { + const source = hot('-'); + const subs = '^'; + const expected = '-'; + + expectObservable((source).find(truePredicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return undefined if source is empty to match predicate', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '(x|)'; + + const result = (source).find(truePredicate); + + expectObservable(result).toBe(expected, {x: undefined}); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return matching element from source emits single element', () => { + const source = hot('--a--|'); + const subs = '^ !'; + const expected = '--(a|)'; + + const predicate = function (value) { + return value === 'a'; + }; + + expectObservable((source).find(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return matching element from source emits multiple elements', () => { + const source = hot('--a--b---c-|'); + const subs = '^ !'; + const expected = '-----(b|)'; + + const predicate = function (value) { + return value === 'b'; + }; + + expectObservable((source).find(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should work with a custom thisArg', () => { + const source = hot('--a--b---c-|'); + const subs = '^ !'; + const expected = '-----(b|)'; + + const finder = { + target: 'b' + }; + const predicate = function (value) { + return value === this.target; + }; + + expectObservable((source).find(predicate, finder)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return undefined if element does not match with predicate', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '-----------(x|)'; + + const predicate = function (value) { + return value === 'z'; + }; + + expectObservable((source).find(predicate)).toBe(expected, { x: undefined }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source).find((value: string) => value === 'z'); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--a--b--c--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source) + .mergeMap((x: string) => Observable.of(x)) + .find((value: string) => value === 'z') + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise if source raise error while element does not match with predicate', () => { + const source = hot('--a--b--#'); + const subs = '^ !'; + const expected = '--------#'; + + const predicate = function (value) { + return value === 'z'; + }; + + expectObservable((source).find(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if predicate throws error', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '--#'; + + const predicate = function (value) { + throw 'error'; + }; + + expectObservable((source).find(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/findIndex-spec.js b/spec/operators/findIndex-spec.js deleted file mode 100644 index 0dd856299e..0000000000 --- a/spec/operators/findIndex-spec.js +++ /dev/null @@ -1,149 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.findIndex()', function () { - function truePredicate(x) { - return true; - } - - it.asDiagram('findIndex(x => x % 5 === 0)')('should return matching element from source emits single element', function () { - var values = {a: 3, b: 9, c: 15, d: 20}; - var source = hot('---a--b--c--d---|', values); - var subs = '^ ! '; - var expected = '---------(x|) '; - - var predicate = function (x) { return x % 5 === 0; }; - - expectObservable(source.findIndex(predicate)).toBe(expected, { x: 2 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not emit if source does not emit', function () { - var source = hot('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.findIndex(truePredicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return negative index if source is empty to match predicate', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '(x|)'; - - var result = source.findIndex(truePredicate); - - expectObservable(result).toBe(expected, {x: -1}); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return index of element from source emits single element', function () { - var sourceValue = 1; - var source = hot('--a--|', { a: sourceValue }); - var subs = '^ ! '; - var expected = '--(x|)'; - - var predicate = function (value) { - return value === sourceValue; - }; - - expectObservable(source.findIndex(predicate)).toBe(expected, { x: 0 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return index of matching element from source emits multiple elements', function () { - var source = hot('--a--b---c-|', { b: 7 }); - var subs = '^ !'; - var expected = '-----(x|)'; - - var predicate = function (value) { - return value === 7; - }; - - expectObservable(source.findIndex(predicate)).toBe(expected, { x: 1 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should work with a custom thisArg', function () { - var sourceValues = { b: 7 }; - var source = hot('--a--b---c-|', sourceValues); - var subs = '^ !'; - var expected = '-----(x|)'; - - var predicate = function (value) { - return value === this.b; - }; - var result = source.findIndex(predicate, sourceValues); - - expectObservable(result).toBe(expected, { x: 1 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return negative index if element does not match with predicate', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '-----------(x|)'; - - var predicate = function (value) { - return value === 'z'; - }; - - expectObservable(source.findIndex(predicate)).toBe(expected, { x: -1 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source.findIndex(function (value) { return value === 'z'; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--a--b--c--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .findIndex(function (value) { return value === 'z'; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise if source raise error while element does not match with predicate', function () { - var source = hot('--a--b--#'); - var subs = '^ !'; - var expected = '--------#'; - - var predicate = function (value) { - return value === 'z'; - }; - - expectObservable(source.findIndex(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if predicate throws error', function () { - var source = hot('--a--b--c--|'); - var subs = '^ !'; - var expected = '--#'; - - var predicate = function (value) { - throw 'error'; - }; - - expectObservable(source.findIndex(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/findIndex-spec.ts b/spec/operators/findIndex-spec.ts new file mode 100644 index 0000000000..9ea4220e06 --- /dev/null +++ b/spec/operators/findIndex-spec.ts @@ -0,0 +1,151 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.findIndex()', () => { + function truePredicate(x) { + return true; + } + + asDiagram('findIndex(x => x % 5 === 0)')('should return matching element from source emits single element', () => { + const values = {a: 3, b: 9, c: 15, d: 20}; + const source = hot('---a--b--c--d---|', values); + const subs = '^ ! '; + const expected = '---------(x|) '; + + const predicate = function (x) { return x % 5 === 0; }; + + expectObservable((source).findIndex(predicate)).toBe(expected, { x: 2 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not emit if source does not emit', () => { + const source = hot('-'); + const subs = '^'; + const expected = '-'; + + expectObservable((source).findIndex(truePredicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return negative index if source is empty to match predicate', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '(x|)'; + + const result = (source).findIndex(truePredicate); + + expectObservable(result).toBe(expected, {x: -1}); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return index of element from source emits single element', () => { + const sourceValue = 1; + const source = hot('--a--|', { a: sourceValue }); + const subs = '^ ! '; + const expected = '--(x|)'; + + const predicate = function (value) { + return value === sourceValue; + }; + + expectObservable((source).findIndex(predicate)).toBe(expected, { x: 0 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return index of matching element from source emits multiple elements', () => { + const source = hot('--a--b---c-|', { b: 7 }); + const subs = '^ !'; + const expected = '-----(x|)'; + + const predicate = function (value) { + return value === 7; + }; + + expectObservable((source).findIndex(predicate)).toBe(expected, { x: 1 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should work with a custom thisArg', () => { + const sourceValues = { b: 7 }; + const source = hot('--a--b---c-|', sourceValues); + const subs = '^ !'; + const expected = '-----(x|)'; + + const predicate = function (value) { + return value === this.b; + }; + const result = (source).findIndex(predicate, sourceValues); + + expectObservable(result).toBe(expected, { x: 1 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return negative index if element does not match with predicate', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '-----------(x|)'; + + const predicate = function (value) { + return value === 'z'; + }; + + expectObservable((source).findIndex(predicate)).toBe(expected, { x: -1 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source).findIndex((value: string) => value === 'z'); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--a--b--c--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source) + .mergeMap((x: string) => Observable.of(x)) + .findIndex((value: string) => value === 'z') + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise if source raise error while element does not match with predicate', () => { + const source = hot('--a--b--#'); + const subs = '^ !'; + const expected = '--------#'; + + const predicate = function (value) { + return value === 'z'; + }; + + expectObservable((source).findIndex(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if predicate throws error', () => { + const source = hot('--a--b--c--|'); + const subs = '^ !'; + const expected = '--#'; + + const predicate = function (value) { + throw 'error'; + }; + + expectObservable((source).findIndex(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/first-spec.js b/spec/operators/first-spec.js deleted file mode 100644 index 8fe6e51c44..0000000000 --- a/spec/operators/first-spec.js +++ /dev/null @@ -1,199 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); - -describe('Observable.prototype.first()', function () { - it.asDiagram('first')('should take the first value of an observable with many values', function () { - var e1 = hot('-----a--b--c---d---|'); - var expected = '-----(a|) '; - var sub = '^ ! '; - - expectObservable(e1.first()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should take the first value of an observable with one value', function () { - var e1 = hot('---(a|)'); - var expected = '---(a|)'; - var sub = '^ !'; - - expectObservable(e1.first()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should error on empty', function () { - var e1 = hot('--a--^----|'); - var expected = '-----#'; - var sub = '^ !'; - - expectObservable(e1.first()).toBe(expected, null, new Rx.EmptyError()); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should return the default value if source observable was empty', function () { - var e1 = hot('-----^----|'); - var expected = '-----(a|)'; - var sub = '^ !'; - - expectObservable(e1.first(null, null, 'a')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should propagate error from the source observable', function () { - var e1 = hot('---^---#'); - var expected = '----#'; - var sub = '^ !'; - - expectObservable(e1.first()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should go on forever on never', function () { - var e1 = hot('--^-------'); - var expected = '--------'; - var sub = '^ '; - - expectObservable(e1.first()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--^-----b----c---d--|'); - var e1subs = '^ ! '; - var expected = '---- '; - var unsub = ' ! '; - - expectObservable(e1.first(), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^-----b----c---d--|'); - var e1subs = '^ ! '; - var expected = '---- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .first() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return first value that matches a predicate', function () { - var e1 = hot('--a-^--b--c--a--c--|'); - var expected = '------(c|)'; - var sub = '^ !'; - var predicate = function (value) { - return value === 'c'; - }; - - expectObservable(e1.first(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should return first value that matches a predicate for odd numbers', function () { - var e1 = hot('--a-^--b--c--d--e--|', {a: 1, b: 2, c: 3, d: 4, e: 5}); - var expected = '------(c|)'; - var sub = '^ !'; - var predicate = function (value) { - return value % 2 === 1; - }; - - expectObservable(e1.first(predicate)).toBe(expected, {c: 3}); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should error when no value matches the predicate', function () { - var e1 = hot('--a-^--b--c--a--c--|'); - var expected = '---------------#'; - var sub = '^ !'; - var predicate = function (value) { - return value === 's'; - }; - - expectObservable(e1.first(predicate)).toBe(expected, null, new Rx.EmptyError()); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should return the default value when no value matches the predicate', function () { - var e1 = hot('--a-^--b--c--a--c--|'); - var expected = '---------------(d|)'; - var sub = '^ !'; - var predicate = function (value) { - return value === 's'; - }; - - expectObservable(e1.first(predicate, null, 'd')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should propagate error when no value matches the predicate', function () { - var e1 = hot('--a-^--b--c--a--#'); - var expected = '------------#'; - var sub = '^ !'; - var predicate = function (value) { - return value === 's'; - }; - - expectObservable(e1.first(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should return first value that matches the index in the predicate', function () { - var e1 = hot('--a-^--b--c--a--c--|'); - var expected = '---------(a|)'; - var sub = '^ !'; - var predicate = function (value, index) { - return index === 2; - }; - - expectObservable(e1.first(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should propagate error from predicate', function () { - var e1 = hot('--a-^--b--c--d--e--|', {a: 1, b: 2, c: 3, d: 4, e: 5}); - var expected = '---------#'; - var sub = '^ !'; - var predicate = function (value) { - if (value < 4) { - return false; - } else { - throw 'error'; - } - }; - - expectObservable(e1.first(predicate)).toBe(expected, null, 'error'); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should support a result selector argument', function () { - var e1 = hot('--a--^---b---c---d---e--|'); - var expected = '--------(x|)'; - var sub = '^ !'; - var predicate = function (x) { return x === 'c'; }; - var resultSelector = function (x, i) { - expect(i).toBe(1); - expect(x).toBe('c'); - return 'x'; - }; - - expectObservable(e1.first(predicate, resultSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should raise error when result selector throws', function () { - var e1 = hot('--a--^---b---c---d---e--|'); - var expected = '--------#'; - var sub = '^ !'; - var predicate = function (x) { return x === 'c'; }; - var resultSelector = function (x, i) { - throw 'error'; - }; - - expectObservable(e1.first(predicate, resultSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); -}); diff --git a/spec/operators/first-spec.ts b/spec/operators/first-spec.ts new file mode 100644 index 0000000000..9abb4d7c27 --- /dev/null +++ b/spec/operators/first-spec.ts @@ -0,0 +1,202 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.first()', () => { + asDiagram('first')('should take the first value of an observable with many values', () => { + const e1 = hot('-----a--b--c---d---|'); + const expected = '-----(a|) '; + const sub = '^ ! '; + + expectObservable(e1.first()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should take the first value of an observable with one value', () => { + const e1 = hot('---(a|)'); + const expected = '---(a|)'; + const sub = '^ !'; + + expectObservable(e1.first()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should error on empty', () => { + const e1 = hot('--a--^----|'); + const expected = '-----#'; + const sub = '^ !'; + + expectObservable(e1.first()).toBe(expected, null, new Rx.EmptyError()); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should return the default value if source observable was empty', () => { + const e1 = hot('-----^----|'); + const expected = '-----(a|)'; + const sub = '^ !'; + + expectObservable(e1.first(null, null, 'a')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should propagate error from the source observable', () => { + const e1 = hot('---^---#'); + const expected = '----#'; + const sub = '^ !'; + + expectObservable(e1.first()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should go on forever on never', () => { + const e1 = hot('--^-------'); + const expected = '--------'; + const sub = '^ '; + + expectObservable(e1.first()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--^-----b----c---d--|'); + const e1subs = '^ ! '; + const expected = '---- '; + const unsub = ' ! '; + + expectObservable(e1.first(), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^-----b----c---d--|'); + const e1subs = '^ ! '; + const expected = '---- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .first() + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return first value that matches a predicate', () => { + const e1 = hot('--a-^--b--c--a--c--|'); + const expected = '------(c|)'; + const sub = '^ !'; + const predicate = function (value) { + return value === 'c'; + }; + + expectObservable(e1.first(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should return first value that matches a predicate for odd numbers', () => { + const e1 = hot('--a-^--b--c--d--e--|', {a: 1, b: 2, c: 3, d: 4, e: 5}); + const expected = '------(c|)'; + const sub = '^ !'; + const predicate = function (value) { + return value % 2 === 1; + }; + + expectObservable(e1.first(predicate)).toBe(expected, {c: 3}); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should error when no value matches the predicate', () => { + const e1 = hot('--a-^--b--c--a--c--|'); + const expected = '---------------#'; + const sub = '^ !'; + const predicate = function (value) { + return value === 's'; + }; + + expectObservable(e1.first(predicate)).toBe(expected, null, new Rx.EmptyError()); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should return the default value when no value matches the predicate', () => { + const e1 = hot('--a-^--b--c--a--c--|'); + const expected = '---------------(d|)'; + const sub = '^ !'; + const predicate = function (value) { + return value === 's'; + }; + + expectObservable(e1.first(predicate, null, 'd')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should propagate error when no value matches the predicate', () => { + const e1 = hot('--a-^--b--c--a--#'); + const expected = '------------#'; + const sub = '^ !'; + const predicate = function (value) { + return value === 's'; + }; + + expectObservable(e1.first(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should return first value that matches the index in the predicate', () => { + const e1 = hot('--a-^--b--c--a--c--|'); + const expected = '---------(a|)'; + const sub = '^ !'; + const predicate = function (value, index) { + return index === 2; + }; + + expectObservable(e1.first(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should propagate error from predicate', () => { + const e1 = hot('--a-^--b--c--d--e--|', {a: 1, b: 2, c: 3, d: 4, e: 5}); + const expected = '---------#'; + const sub = '^ !'; + const predicate = function (value) { + if (value < 4) { + return false; + } else { + throw 'error'; + } + }; + + expectObservable(e1.first(predicate)).toBe(expected, null, 'error'); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should support a result selector argument', () => { + const e1 = hot('--a--^---b---c---d---e--|'); + const expected = '--------(x|)'; + const sub = '^ !'; + const predicate = function (x) { return x === 'c'; }; + const resultSelector = function (x, i) { + expect(i).toBe(1); + expect(x).toBe('c'); + return 'x'; + }; + + expectObservable(e1.first(predicate, resultSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should raise error when result selector throws', () => { + const e1 = hot('--a--^---b---c---d---e--|'); + const expected = '--------#'; + const sub = '^ !'; + const predicate = function (x) { return x === 'c'; }; + const resultSelector = function (x, i) { + throw 'error'; + }; + + expectObservable(e1.first(predicate, resultSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); +}); diff --git a/spec/operators/groupBy-spec.js b/spec/operators/groupBy-spec.js deleted file mode 100644 index 0b350fbaed..0000000000 --- a/spec/operators/groupBy-spec.js +++ /dev/null @@ -1,1390 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; -var GroupedObservable = require('../../dist/cjs/operator/groupBy').GroupedObservable; - -describe('Observable.prototype.groupBy()', function () { - it.asDiagram('groupBy(i => i % 2)')('should group numbers by odd/even', function () { - var e1 = hot('--1---2---3---4---5---|'); - var expected = '--x---y---------------|'; - var x = cold( '1-------3-------5---|'); - var y = cold( '2-------4-------|'); - var expectedValues = { x: x, y: y }; - - var source = e1 - .groupBy(function (val) { return parseInt(val) % 2; }); - expectObservable(source).toBe(expected, expectedValues); - }); - - function reverseString(str) { - return str.split('').reverse().join(''); - } - - function mapObject(obj, fn) { - var out = {}; - for (var p in obj) { - if (obj.hasOwnProperty(p)) { - out[p] = fn(obj[p]); - } - } - return out; - } - - it('should group values', function (done) { - var expectedGroups = [ - { key: 1, values: [1, 3] }, - { key: 0, values: [2] } - ]; - - Observable.of(1, 2, 3) - .groupBy(function (x) { return x % 2; }) - .subscribe(function (g) { - var expectedGroup = expectedGroups.shift(); - expect(g.key).toBe(expectedGroup.key); - - g.subscribe(function (x) { - expect(x).toBe(expectedGroup.values.shift()); - }); - }, null, done); - }); - - it('should group values with an element selector', function (done) { - var expectedGroups = [ - { key: 1, values: ['1!', '3!'] }, - { key: 0, values: ['2!'] } - ]; - - Observable.of(1, 2, 3) - .groupBy(function (x) { return x % 2; }, function (x) { return x + '!'; }) - .subscribe(function (g) { - var expectedGroup = expectedGroups.shift(); - expect(g.key).toBe(expectedGroup.key); - - g.subscribe(function (x) { - expect(x).toBe(expectedGroup.values.shift()); - }); - }, null, done); - }); - - it('should group values with a duration selector', function (done) { - var expectedGroups = [ - { key: 1, values: [1, 3] }, - { key: 0, values: [2, 4] }, - { key: 1, values: [5] }, - { key: 0, values: [6] } - ]; - - Observable.of(1, 2, 3, 4, 5, 6) - .groupBy( - function (x) { return x % 2; }, - function (x) { return x; }, - function (g) { return g.skip(1); }) - .subscribe(function (g) { - var expectedGroup = expectedGroups.shift(); - expect(g.key).toBe(expectedGroup.key); - - g.subscribe(function (x) { - expect(x).toBe(expectedGroup.values.shift()); - }); - }, null, done); - }); - - it('should handle an empty Observable', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a never Observable', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a just-throw Observable', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an Observable with a single value', function () { - var values = { a: ' foo' }; - var e1 = hot('^--a--|', values); - var e1subs = '^ !'; - var expected = '---g--|'; - var g = cold( 'a--|', values); - var expectedValues = { g: g }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should group values with a keySelector', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--w---x---y-z-------------|'; - var w = cold( 'a-b---d---------i-----l-|', values); - var x = cold( 'c-------g-h---------|', values); - var y = cold( 'e---------j-k---|', values); - var z = cold( 'f-------------|', values); - var expectedValues = { w: w, x: x, y: y, z: z }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit GroupObservables', function () { - var values = { - a: ' foo', - b: ' FoO ' - }; - var e1 = hot('-1--2--^-a-b----|', values); - var e1subs = '^ !'; - var expected = '--g------|'; - var expectedValues = { g: 'foo' }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }) - .do(function (group) { - expect(group.key).toBe('foo'); - expect(group instanceof GroupedObservable).toBe(true); - }) - .map(function (group) { return group.key; }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should group values with a keySelector, assert GroupSubject key', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--w---x---y-z-------------|'; - var expectedValues = { w: 'foo', x: 'bar', y: 'baz', z: 'qux' }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }) - .map(function (g) { return g.key; }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should group values with a keySelector, but outer throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values); - var e1subs = '^ !'; - var expected = '--w---x---y-z-------------#'; - var expectedValues = { w: 'foo', x: 'bar', y: 'baz', z: 'qux' }; - - var source = e1 - .groupBy(function (x) { return x.toLowerCase().trim(); }) - .map(function (g) { return g.key; }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should group values with a keySelector, inners propagate error from outer', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values); - var e1subs = '^ !'; - var expected = '--w---x---y-z-------------#'; - var w = cold( 'a-b---d---------i-----l-#', values); - var x = cold( 'c-------g-h---------#', values); - var y = cold( 'e---------j-k---#', values); - var z = cold( 'f-------------#', values); - var expectedValues = { w: w, x: x, y: y, z: z }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow outer to be unsubscribed early', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var unsub = ' !'; - var e1subs = '^ !'; - var expected = '--w---x---y-'; - var expectedValues = { w: 'foo', x: 'bar', y: 'baz' }; - - var source = e1 - .groupBy(function (x) { return x.toLowerCase().trim(); }) - .map(function (group) { return group.key; }); - - expectObservable(source, unsub).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--w---x---y-'; - var unsub = ' !'; - var expectedValues = { w: 'foo', x: 'bar', y: 'baz' }; - - var source = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .groupBy(function (x) { return x.toLowerCase().trim(); }) - .mergeMap(function (group) { return Observable.of(group.key); }); - - expectObservable(source, unsub).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should group values with a keySelector which eventually throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--w---x---y-z-------#'; - var w = cold( 'a-b---d---------i-#', values); - var x = cold( 'c-------g-h---#', values); - var y = cold( 'e---------#', values); - var z = cold( 'f-------#', values); - var expectedValues = { w: w, x: x, y: y, z: z }; - - var invoked = 0; - var source = e1 - .groupBy(function (val) { - invoked++; - if (invoked === 10) { - throw 'error'; - } - return val.toLowerCase().trim(); - }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should group values with a keySelector and elementSelector, ' + - 'but elementSelector throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var reversedValues = mapObject(values, reverseString); - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--w---x---y-z-------#'; - var w = cold( 'a-b---d---------i-#', reversedValues); - var x = cold( 'c-------g-h---#', reversedValues); - var y = cold( 'e---------#', reversedValues); - var z = cold( 'f-------#', reversedValues); - var expectedValues = { w: w, x: x, y: y, z: z }; - - var invoked = 0; - var source = e1 - .groupBy(function (val) { - return val.toLowerCase().trim(); - }, function (val) { - invoked++; - if (invoked === 10) { - throw 'error'; - } - return reverseString(val); - }); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow the outer to be unsubscribed early but inners continue', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var unsub = ' !'; - var expected = '--w---x---'; - var w = cold( 'a-b---d---------i-----l-|', values); - var x = cold( 'c-------g-h---------|', values); - var expectedValues = { w: w, x: x }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }); - - expectObservable(source, unsub).toBe(expected, expectedValues); - }); - - it('should allow an inner to be unsubscribed early but other inners continue', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var expected = '--w---x---y-z-------------|'; - var w = '--a-b---d-'; - var unsubw = ' !'; - var x = '------c-------g-h---------|'; - var y = '----------e---------j-k---|'; - var z = '------------f-------------|'; - - var expectedGroups = { - w: Rx.TestScheduler.parseMarbles(w, values), - x: Rx.TestScheduler.parseMarbles(x, values), - y: Rx.TestScheduler.parseMarbles(y, values), - z: Rx.TestScheduler.parseMarbles(z, values) - }; - - var fooUnsubscriptionFrame = Rx.TestScheduler - .parseMarblesAsSubscriptions(unsubw) - .unsubscribedFrame; - - var source = e1 - .groupBy(function (val) { - return val.toLowerCase().trim(); - }) - .map(function (group) { - var arr = []; - - var subscription = group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - - if (group.key === 'foo') { - rxTestScheduler.schedule(function () { - subscription.unsubscribe(); - }, fooUnsubscriptionFrame - rxTestScheduler.frame); - } - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - }); - - it('should allow inners to be unsubscribed early at different times', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var expected = '--w---x---y-z-------------|'; - var w = '--a-b---d-'; - var unsubw = ' !'; - var x = '------c------'; - var unsubx = ' !'; - var y = '----------e------'; - var unsuby = ' !'; - var z = '------------f-------'; - var unsubz = ' !'; - - var expectedGroups = { - w: Rx.TestScheduler.parseMarbles(w, values), - x: Rx.TestScheduler.parseMarbles(x, values), - y: Rx.TestScheduler.parseMarbles(y, values), - z: Rx.TestScheduler.parseMarbles(z, values) - }; - - var unsubscriptionFrames = { - foo: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubw).unsubscribedFrame, - bar: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubx).unsubscribedFrame, - baz: Rx.TestScheduler.parseMarblesAsSubscriptions(unsuby).unsubscribedFrame, - qux: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubz).unsubscribedFrame - }; - - var source = e1 - .groupBy(function (val) { - return val.toLowerCase().trim(); - }) - .map(function (group) { - var arr = []; - - var subscription = group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - - rxTestScheduler.schedule(function () { - subscription.unsubscribe(); - }, unsubscriptionFrames[group.key] - rxTestScheduler.frame); - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - }); - - it('should allow subscribing late to an inner Observable, outer completes', function () { - var values = { - a: ' foo', - b: ' FoO ', - d: 'foO ', - i: 'FOO ', - l: ' fOo ' - }; - var e1 = hot( '--a-b---d---------i-----l-|', values); - var subs = '^ !'; - var expected = '----------------------------|'; - - e1.groupBy(function (val) { return val.toLowerCase().trim(); }) - .subscribe(function (group) { - rxTestScheduler.schedule(function () { - expectObservable(group).toBe(expected); - }, 260); - }); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should allow subscribing late to an inner Observable, outer throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - d: 'foO ', - i: 'FOO ', - l: ' fOo ' - }; - var e1 = hot( '--a-b---d---------i-----l-#', values); - var subs = '^ !'; - var expected = '----------------------------#'; - - e1.groupBy(function (val) { return val.toLowerCase().trim(); }) - .subscribe(function (group) { - rxTestScheduler.schedule(function () { - expectObservable(group).toBe(expected); - }, 260); - }, function () {}); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should allow subscribing late to inner, unsubscribe outer early', function () { - var values = { - a: ' foo', - b: ' FoO ', - d: 'foO ', - i: 'FOO ', - l: ' fOo ' - }; - var e1 = hot( '--a-b---d---------i-----l-#', values); - var unsub = ' !'; - var e1subs = '^ !'; - var expectedOuter = '--w----------'; - var expectedInner = '-------------'; - var outerValues = { w: 'foo' }; - - var source = e1 - .groupBy(function (val) { return val.toLowerCase().trim(); }) - .do(function (group) { - rxTestScheduler.schedule(function () { - expectObservable(group).toBe(expectedInner); - }, 260); - }) - .map(function (group) { return group.key; }); - - expectObservable(source, unsub).toBe(expectedOuter, outerValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow using a keySelector, elementSelector, and durationSelector', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var reversedValues = mapObject(values, reverseString); - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--v---w---x-y-----z-------|'; - var v = cold( 'a-b---(d|)' , reversedValues); - var w = cold( 'c-------g-(h|)' , reversedValues); - var x = cold( 'e---------j-(k|)' , reversedValues); - var y = cold( 'f-------------|', reversedValues); - var z = cold( 'i-----l-|', reversedValues); - var expectedValues = { v: v, w: w, x: x, y: y, z: z }; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return reverseString(val); }, - function (group) { return group.skip(2); } - ); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow using a keySelector, elementSelector, and durationSelector that throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var reversedValues = mapObject(values, reverseString); - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var expected = '--v---w---x-y-----z-------|'; - var v = cold( 'a-b---(d#)' , reversedValues); - var w = cold( 'c-------g-(h#)' , reversedValues); - var x = cold( 'e---------j-(k#)' , reversedValues); - var y = cold( 'f-------------|', reversedValues); - var z = cold( 'i-----l-|', reversedValues); - var expectedValues = { v: v, w: w, x: x, y: y, z: z }; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return reverseString(val); }, - function (group) { return group.skip(2).map(function () { throw 'error'; }); - } - ); - expectObservable(source).toBe(expected, expectedValues); - }); - - it('should allow using a keySelector and a durationSelector, outer throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values); - var e1subs = '^ !'; - var expected = '--v---w---x-y-----z-------#'; - var v = cold( 'a-b---(d|)' , values); - var w = cold( 'c-------g-(h|)' , values); - var x = cold( 'e---------j-(k|)' , values); - var y = cold( 'f-------------#', values); - var z = cold( 'i-----l-#', values); - var expectedValues = { v: v, w: w, x: x, y: y, z: z }; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(2); } - ); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow using a durationSelector, and outer unsubscribed early', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var unsub = ' !'; - var expected = '--v---w---x-'; - var v = cold( 'a-b---(d|)' , values); - var w = cold( 'c-------g-(h|)' , values); - var x = cold( 'e---------j-(k|)' , values); - var expectedValues = { v: v, w: w, x: x }; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(2); } - ); - - expectObservable(source, unsub).toBe(expected, expectedValues); - }); - - it('should allow using a durationSelector, outer and all inners unsubscribed early', - function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var unsub = ' !'; - var expected = '--v---w---x-'; - var v = '--a-b---(d|)'; - var w = '------c-----'; - var x = '----------e-'; - - var expectedGroups = { - v: Rx.TestScheduler.parseMarbles(v, values), - w: Rx.TestScheduler.parseMarbles(w, values), - x: Rx.TestScheduler.parseMarbles(x, values) - }; - - var unsubscriptionFrame = Rx.TestScheduler - .parseMarblesAsSubscriptions(unsub) - .unsubscribedFrame; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(2); } - ) - .map(function (group) { - var arr = []; - - var subscription = group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - - rxTestScheduler.schedule(function () { - subscription.unsubscribe(); - }, unsubscriptionFrame - rxTestScheduler.frame); - return arr; - }); - - expectObservable(source, unsub).toBe(expected, expectedGroups); - }); - - it('should allow using a durationSelector, but keySelector throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--v---w---x-y-----z-#' ; - var v = cold( 'a-b---(d|)' , values); - var w = cold( 'c-------g-(h|)' , values); - var x = cold( 'e---------#' , values); - var y = cold( 'f-------#' , values); - var z = cold( 'i-#' , values); - var expectedValues = { v: v, w: w, x: x, y: y, z: z }; - - var invoked = 0; - var source = e1 - .groupBy( - function (val) { - invoked++; - if (invoked === 10) { - throw 'error'; - } - return val.toLowerCase().trim(); - }, - function (val) { return val; }, - function (group) { return group.skip(2); } - ); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow using a durationSelector, but elementSelector throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ ! '; - var expected = '--v---w---x-y-----z-# '; - var v = cold( 'a-b---(d|) ', values); - var w = cold( 'c-------g-(h|) ', values); - var x = cold( 'e---------# ', values); - var y = cold( 'f-------# ', values); - var z = cold( 'i-# ', values); - var expectedValues = { v: v, w: w, x: x, y: y, z: z }; - - var invoked = 0; - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { - invoked++; - if (invoked === 10) { - throw 'error'; - } - return val; - }, - function (group) { return group.skip(2); } - ); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow using a durationSelector which eventually throws', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ ! '; - var expected = '--v---w---x-# '; - var v = cold( 'a-b---(d|) ', values); - var w = cold( 'c-----# ', values); - var x = cold( 'e-# ', values); - var y = cold( '# ', values); - var expectedValues = { v: v, w: w, x: x, y: y }; - - var invoked = 0; - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { - invoked++; - if (invoked === 4) { - throw 'error'; - } - return group.skip(2); - } - ); - - expectObservable(source).toBe(expected, expectedValues); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow an inner to be unsubscribed early but other inners continue, ' + - 'with durationSelector', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var reversedValues = mapObject(values, reverseString); - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--v---w---x-y-----z-------|'; - var v = '--a-b---' ; - var unsubv = ' !'; - var w = '------c-------g-(h|)' ; - var x = '----------e---------j-(k|)' ; - var y = '------------f-------------|'; - var z = '------------------i-----l-|'; - - var expectedGroups = { - v: Rx.TestScheduler.parseMarbles(v, reversedValues), - w: Rx.TestScheduler.parseMarbles(w, reversedValues), - x: Rx.TestScheduler.parseMarbles(x, reversedValues), - y: Rx.TestScheduler.parseMarbles(y, reversedValues), - z: Rx.TestScheduler.parseMarbles(z, reversedValues) - }; - - var fooUnsubscriptionFrame = Rx.TestScheduler - .parseMarblesAsSubscriptions(unsubv) - .unsubscribedFrame; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return reverseString(val); }, - function (group) { return group.skip(2); } - ) - .map(function (group, index) { - var arr = []; - - var subscription = group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - - if (group.key === 'foo' && index === 0) { - rxTestScheduler.schedule(function () { - subscription.unsubscribe(); - }, fooUnsubscriptionFrame - rxTestScheduler.frame); - } - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow inners to be unsubscribed early at different times, with durationSelector', - function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--v---w---x-y-----z-------|'; - var v = '--a-b---' ; - var unsubv = ' !' ; - var w = '------c---' ; - var unsubw = ' !' ; - var x = '----------e---------j-' ; - var unsubx = ' !' ; - var y = '------------f----' ; - var unsuby = ' !' ; - var z = '------------------i----' ; - var unsubz = ' !' ; - - var expectedGroups = { - v: Rx.TestScheduler.parseMarbles(v, values), - w: Rx.TestScheduler.parseMarbles(w, values), - x: Rx.TestScheduler.parseMarbles(x, values), - y: Rx.TestScheduler.parseMarbles(y, values), - z: Rx.TestScheduler.parseMarbles(z, values) - }; - - var unsubscriptionFrames = { - foo: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubv).unsubscribedFrame, - bar: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubw).unsubscribedFrame, - baz: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubx).unsubscribedFrame, - qux: Rx.TestScheduler.parseMarblesAsSubscriptions(unsuby).unsubscribedFrame, - foo2: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubz).unsubscribedFrame - }; - var hasUnsubscribed = {}; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(2); } - ) - .map(function (group) { - var arr = []; - - var subscription = group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - - var unsubscriptionFrame = hasUnsubscribed[group.key] ? - unsubscriptionFrames[group.key + '2'] : - unsubscriptionFrames[group.key]; - rxTestScheduler.schedule(function () { - subscription.unsubscribe(); - hasUnsubscribed[group.key] = true; - }, unsubscriptionFrame - rxTestScheduler.frame); - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return inners that when subscribed late exhibit hot behavior', function () { - var values = { - a: ' foo', - b: ' FoO ', - c: 'baR ', - d: 'foO ', - e: ' Baz ', - f: ' qux ', - g: ' bar', - h: ' BAR ', - i: 'FOO ', - j: 'baz ', - k: ' bAZ ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); - var e1subs = '^ !'; - var expected = '--v---w---x-y-----z-------|'; - var subv = ' ^ '; - var v = '--------(d|)' ; - var subw = ' ^ '; - var w = '----------------(h|)' ; - var subx = ' ^ '; - var x = '----------------------(k|)' ; - var suby = ' ^'; - var y = '------------------------------|'; - var subz = ' ^'; - var z = '--------------------------------|'; - - var expectedGroups = { - v: Rx.TestScheduler.parseMarbles(v, values), - w: Rx.TestScheduler.parseMarbles(w, values), - x: Rx.TestScheduler.parseMarbles(x, values), - y: Rx.TestScheduler.parseMarbles(y, values), - z: Rx.TestScheduler.parseMarbles(z, values) - }; - - var subscriptionFrames = { - foo: Rx.TestScheduler.parseMarblesAsSubscriptions(subv).subscribedFrame, - bar: Rx.TestScheduler.parseMarblesAsSubscriptions(subw).subscribedFrame, - baz: Rx.TestScheduler.parseMarblesAsSubscriptions(subx).subscribedFrame, - qux: Rx.TestScheduler.parseMarblesAsSubscriptions(suby).subscribedFrame, - foo2: Rx.TestScheduler.parseMarblesAsSubscriptions(subz).subscribedFrame - }; - var hasSubscribed = {}; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(2); } - ) - .map(function (group) { - var arr = []; - - var subscriptionFrame = hasSubscribed[group.key] ? - subscriptionFrames[group.key + '2'] : - subscriptionFrames[group.key]; - - rxTestScheduler.schedule(function () { - group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - hasSubscribed[group.key] = true; - }, subscriptionFrame - rxTestScheduler.frame); - - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return inner group that when subscribed late emits complete()', function () { - var values = { - a: ' foo', - b: ' FoO ', - d: 'foO ', - i: 'FOO ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b---d---------i-----l-|', values); - var e1subs = '^ !'; - var expected = '--g-----------------------|'; - var innerSub = ' ^'; - var g = '--------------------------------|'; - - var expectedGroups = { - g: Rx.TestScheduler.parseMarbles(g, values) - }; - - var innerSubscriptionFrame = Rx.TestScheduler - .parseMarblesAsSubscriptions(innerSub) - .subscribedFrame; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(7); } - ) - .map(function (group) { - var arr = []; - - rxTestScheduler.schedule(function () { - group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - }, innerSubscriptionFrame - rxTestScheduler.frame); - - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return inner group that when subscribed late emits error()', function () { - var values = { - a: ' foo', - b: ' FoO ', - d: 'foO ', - i: 'FOO ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b---d---------i-----l-#', values); - var e1subs = '^ !'; - var expected = '--g-----------------------#'; - var innerSub = ' ^'; - var g = '--------------------------------#'; - - var expectedGroups = { - g: Rx.TestScheduler.parseMarbles(g, values) - }; - - var innerSubscriptionFrame = Rx.TestScheduler - .parseMarblesAsSubscriptions(innerSub) - .subscribedFrame; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(7); } - ) - .map(function (group) { - var arr = []; - - rxTestScheduler.schedule(function () { - group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - }, innerSubscriptionFrame - rxTestScheduler.frame); - - return arr; - }); - - expectObservable(source).toBe(expected, expectedGroups); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return inner that does not throw when faulty outer is unsubscribed early', - function () { - var values = { - a: ' foo', - b: ' FoO ', - d: 'foO ', - i: 'FOO ', - l: ' fOo ' - }; - var e1 = hot('-1--2--^-a-b---d---------i-----l-#', values); - var unsub = ' !'; - var expectedSubs = '^ !'; - var expected = '--g----'; - var innerSub = ' ^'; - var g = '-'; - - var expectedGroups = { - g: Rx.TestScheduler.parseMarbles(g, values) - }; - - var innerSubscriptionFrame = Rx.TestScheduler - .parseMarblesAsSubscriptions(innerSub) - .subscribedFrame; - - var source = e1 - .groupBy( - function (val) { return val.toLowerCase().trim(); }, - function (val) { return val; }, - function (group) { return group.skip(7); } - ) - .map(function (group) { - var arr = []; - - rxTestScheduler.schedule(function () { - group - .materialize() - .map(function (notification) { - return { frame: rxTestScheduler.frame, notification: notification }; - }) - .subscribe(function (value) { - arr.push(value); - }); - }, innerSubscriptionFrame - rxTestScheduler.frame); - - return arr; - }); - - expectObservable(source, unsub).toBe(expected, expectedGroups); - expectSubscriptions(e1.subscriptions).toBe(expectedSubs); - }); - - it('should not break lift() composability', function (done) { - function MyCustomObservable() { - Observable.apply(this, arguments); - } - MyCustomObservable.prototype = Object.create(Observable.prototype); - MyCustomObservable.prototype.constructor = MyCustomObservable; - MyCustomObservable.prototype.lift = function (operator) { - var obs = new MyCustomObservable(); - obs.source = this; - obs.operator = operator; - return obs; - }; - - var result = new MyCustomObservable(function (observer) { - observer.next(1); - observer.next(2); - observer.next(3); - observer.complete(); - }).groupBy( - function (x) { return x % 2; }, - function (x) { return x + '!'; } - ); - - expect(result instanceof MyCustomObservable).toBe(true); - - var expectedGroups = [ - { key: 1, values: ['1!', '3!'] }, - { key: 0, values: ['2!'] } - ]; - - result - .subscribe(function (g) { - var expectedGroup = expectedGroups.shift(); - expect(g.key).toBe(expectedGroup.key); - - g.subscribe(function (x) { - expect(x).toBe(expectedGroup.values.shift()); - }); - }, done.fail, done); - }); -}); diff --git a/spec/operators/groupBy-spec.ts b/spec/operators/groupBy-spec.ts new file mode 100644 index 0000000000..480be27f26 --- /dev/null +++ b/spec/operators/groupBy-spec.ts @@ -0,0 +1,1383 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {GroupedObservable} from '../../dist/cjs/operator/groupBy'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.groupBy()', () => { + asDiagram('groupBy(i => i % 2)')('should group numbers by odd/even', () => { + const e1 = hot('--1---2---3---4---5---|'); + const expected = '--x---y---------------|'; + const x = cold( '1-------3-------5---|'); + const y = cold( '2-------4-------|'); + const expectedValues = { x: x, y: y }; + + const source = e1 + .groupBy((val: string) => parseInt(val) % 2); + expectObservable(source).toBe(expected, expectedValues); + }); + + function reverseString(str) { + return str.split('').reverse().join(''); + } + + function mapObject(obj, fn) { + const out = {}; + for (const p in obj) { + if (obj.hasOwnProperty(p)) { + out[p] = fn(obj[p]); + } + } + return out; + } + + it('should group values', (done: DoneSignature) => { + const expectedGroups = [ + { key: 1, values: [1, 3] }, + { key: 0, values: [2] } + ]; + + Observable.of(1, 2, 3) + .groupBy((x: number) => x % 2) + .subscribe((g: any) => { + const expectedGroup = expectedGroups.shift(); + expect(g.key).toBe(expectedGroup.key); + + g.subscribe((x: any) => { + expect(x).toBe(expectedGroup.values.shift()); + }); + }, null, done); + }); + + it('should group values with an element selector', (done: DoneSignature) => { + const expectedGroups = [ + { key: 1, values: ['1!', '3!'] }, + { key: 0, values: ['2!'] } + ]; + + Observable.of(1, 2, 3) + .groupBy((x: number) => x % 2, (x: number) => x + '!') + .subscribe((g: any) => { + const expectedGroup = expectedGroups.shift(); + expect(g.key).toBe(expectedGroup.key); + + g.subscribe((x: any) => { + expect(x).toBe(expectedGroup.values.shift()); + }); + }, null, done); + }); + + it('should group values with a duration selector', (done: DoneSignature) => { + const expectedGroups = [ + { key: 1, values: [1, 3] }, + { key: 0, values: [2, 4] }, + { key: 1, values: [5] }, + { key: 0, values: [6] } + ]; + + Observable.of(1, 2, 3, 4, 5, 6) + .groupBy( + (x: number) => x % 2, + (x: number) => x, + (g: any) => g.skip(1)) + .subscribe((g: any) => { + const expectedGroup = expectedGroups.shift(); + expect(g.key).toBe(expectedGroup.key); + + g.subscribe((x: any) => { + expect(x).toBe(expectedGroup.values.shift()); + }); + }, null, done); + }); + + it('should handle an empty Observable', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a never Observable', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a just-throw Observable', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an Observable with a single value', () => { + const values = { a: ' foo' }; + const e1 = hot('^--a--|', values); + const e1subs = '^ !'; + const expected = '---g--|'; + const g = cold( 'a--|', values); + const expectedValues = { g: g }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should group values with a keySelector', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--w---x---y-z-------------|'; + const w = cold( 'a-b---d---------i-----l-|', values); + const x = cold( 'c-------g-h---------|', values); + const y = cold( 'e---------j-k---|', values); + const z = cold( 'f-------------|', values); + const expectedValues = { w: w, x: x, y: y, z: z }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit GroupObservables', () => { + const values = { + a: ' foo', + b: ' FoO ' + }; + const e1 = hot('-1--2--^-a-b----|', values); + const e1subs = '^ !'; + const expected = '--g------|'; + const expectedValues = { g: 'foo' }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .do((group: any) => { + expect(group.key).toBe('foo'); + expect(group instanceof GroupedObservable).toBe(true); + }) + .map((group: any) => { return group.key; }); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should group values with a keySelector, assert GroupSubject key', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--w---x---y-z-------------|'; + const expectedValues = { w: 'foo', x: 'bar', y: 'baz', z: 'qux' }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .map((g: any) => g.key); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should group values with a keySelector, but outer throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values); + const e1subs = '^ !'; + const expected = '--w---x---y-z-------------#'; + const expectedValues = { w: 'foo', x: 'bar', y: 'baz', z: 'qux' }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .map((g: any) => g.key); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should group values with a keySelector, inners propagate error from outer', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values); + const e1subs = '^ !'; + const expected = '--w---x---y-z-------------#'; + const w = cold( 'a-b---d---------i-----l-#', values); + const x = cold( 'c-------g-h---------#', values); + const y = cold( 'e---------j-k---#', values); + const z = cold( 'f-------------#', values); + const expectedValues = { w: w, x: x, y: y, z: z }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow outer to be unsubscribed early', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const unsub = ' !'; + const e1subs = '^ !'; + const expected = '--w---x---y-'; + const expectedValues = { w: 'foo', x: 'bar', y: 'baz' }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .map((group: any) => group.key); + + expectObservable(source, unsub).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--w---x---y-'; + const unsub = ' !'; + const expectedValues = { w: 'foo', x: 'bar', y: 'baz' }; + + const source = e1 + .mergeMap((x: string) => Observable.of(x)) + .groupBy((x: string) => x.toLowerCase().trim()) + .mergeMap((group: any) => Observable.of(group.key)); + + expectObservable(source, unsub).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should group values with a keySelector which eventually throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--w---x---y-z-------#'; + const w = cold( 'a-b---d---------i-#', values); + const x = cold( 'c-------g-h---#', values); + const y = cold( 'e---------#', values); + const z = cold( 'f-------#', values); + const expectedValues = { w: w, x: x, y: y, z: z }; + + let invoked = 0; + const source = e1 + .groupBy((val: string) => { + invoked++; + if (invoked === 10) { + throw 'error'; + } + return val.toLowerCase().trim(); + }); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should group values with a keySelector and elementSelector, ' + + 'but elementSelector throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const reversedValues = mapObject(values, reverseString); + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--w---x---y-z-------#'; + const w = cold( 'a-b---d---------i-#', reversedValues); + const x = cold( 'c-------g-h---#', reversedValues); + const y = cold( 'e---------#', reversedValues); + const z = cold( 'f-------#', reversedValues); + const expectedValues = { w: w, x: x, y: y, z: z }; + + let invoked = 0; + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim(), + (val: string) => { + invoked++; + if (invoked === 10) { + throw 'error'; + } + return reverseString(val); + }); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow the outer to be unsubscribed early but inners continue', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const unsub = ' !'; + const expected = '--w---x---'; + const w = cold( 'a-b---d---------i-----l-|', values); + const x = cold( 'c-------g-h---------|', values); + const expectedValues = { w: w, x: x }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()); + + expectObservable(source, unsub).toBe(expected, expectedValues); + }); + + it('should allow an inner to be unsubscribed early but other inners continue', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const expected = '--w---x---y-z-------------|'; + const w = '--a-b---d-'; + const unsubw = ' !'; + const x = '------c-------g-h---------|'; + const y = '----------e---------j-k---|'; + const z = '------------f-------------|'; + + const expectedGroups = { + w: Rx.TestScheduler.parseMarbles(w, values), + x: Rx.TestScheduler.parseMarbles(x, values), + y: Rx.TestScheduler.parseMarbles(y, values), + z: Rx.TestScheduler.parseMarbles(z, values) + }; + + const fooUnsubscriptionFrame = Rx.TestScheduler + .parseMarblesAsSubscriptions(unsubw) + .unsubscribedFrame; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .map((group: any) => { + const arr = []; + + const subscription = group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }).subscribe((value: any) => { + arr.push(value); + }); + + if (group.key === 'foo') { + rxTestScheduler.schedule(() => { + subscription.unsubscribe(); + }, fooUnsubscriptionFrame - rxTestScheduler.frame); + } + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + }); + + it('should allow inners to be unsubscribed early at different times', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const expected = '--w---x---y-z-------------|'; + const w = '--a-b---d-'; + const unsubw = ' !'; + const x = '------c------'; + const unsubx = ' !'; + const y = '----------e------'; + const unsuby = ' !'; + const z = '------------f-------'; + const unsubz = ' !'; + + const expectedGroups = { + w: Rx.TestScheduler.parseMarbles(w, values), + x: Rx.TestScheduler.parseMarbles(x, values), + y: Rx.TestScheduler.parseMarbles(y, values), + z: Rx.TestScheduler.parseMarbles(z, values) + }; + + const unsubscriptionFrames = { + foo: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubw).unsubscribedFrame, + bar: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubx).unsubscribedFrame, + baz: Rx.TestScheduler.parseMarblesAsSubscriptions(unsuby).unsubscribedFrame, + qux: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubz).unsubscribedFrame + }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .map((group: any) => { + const arr = []; + + const subscription = group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }).subscribe((value: any) => { + arr.push(value); + }); + + rxTestScheduler.schedule(() => { + subscription.unsubscribe(); + }, unsubscriptionFrames[group.key] - rxTestScheduler.frame); + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + }); + + it('should allow subscribing late to an inner Observable, outer completes', () => { + const values = { + a: ' foo', + b: ' FoO ', + d: 'foO ', + i: 'FOO ', + l: ' fOo ' + }; + const e1 = hot( '--a-b---d---------i-----l-|', values); + const subs = '^ !'; + const expected = '----------------------------|'; + + e1.groupBy((val: string) => val.toLowerCase().trim()) + .subscribe((group: any) => { + rxTestScheduler.schedule(() => { + expectObservable(group).toBe(expected); + }, 260); + }); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should allow subscribing late to an inner Observable, outer throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + d: 'foO ', + i: 'FOO ', + l: ' fOo ' + }; + const e1 = hot( '--a-b---d---------i-----l-#', values); + const subs = '^ !'; + const expected = '----------------------------#'; + + e1.groupBy((val: string) => val.toLowerCase().trim()) + .subscribe((group: any) => { + rxTestScheduler.schedule(() => { + expectObservable(group).toBe(expected); + }, 260); + }, () => {}); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should allow subscribing late to inner, unsubscribe outer early', () => { + const values = { + a: ' foo', + b: ' FoO ', + d: 'foO ', + i: 'FOO ', + l: ' fOo ' + }; + const e1 = hot( '--a-b---d---------i-----l-#', values); + const unsub = ' !'; + const e1subs = '^ !'; + const expectedOuter = '--w----------'; + const expectedInner = '-------------'; + const outerValues = { w: 'foo' }; + + const source = e1 + .groupBy((val: string) => val.toLowerCase().trim()) + .do((group: any) => { + rxTestScheduler.schedule(() => { + expectObservable(group).toBe(expectedInner); + }, 260); + }) + .map((group: any) => { return group.key; }); + + expectObservable(source, unsub).toBe(expectedOuter, outerValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow using a keySelector, elementSelector, and durationSelector', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const reversedValues = mapObject(values, reverseString); + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--v---w---x-y-----z-------|'; + const v = cold( 'a-b---(d|)' , reversedValues); + const w = cold( 'c-------g-(h|)' , reversedValues); + const x = cold( 'e---------j-(k|)' , reversedValues); + const y = cold( 'f-------------|', reversedValues); + const z = cold( 'i-----l-|', reversedValues); + const expectedValues = { v: v, w: w, x: x, y: y, z: z }; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => reverseString(val), + (group: any) => group.skip(2) + ); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow using a keySelector, elementSelector, and durationSelector that throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const reversedValues = mapObject(values, reverseString); + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const expected = '--v---w---x-y-----z-------|'; + const v = cold( 'a-b---(d#)' , reversedValues); + const w = cold( 'c-------g-(h#)' , reversedValues); + const x = cold( 'e---------j-(k#)' , reversedValues); + const y = cold( 'f-------------|', reversedValues); + const z = cold( 'i-----l-|', reversedValues); + const expectedValues = { v: v, w: w, x: x, y: y, z: z }; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => reverseString(val), + (group: any) => group.skip(2).map(() => { throw 'error'; }) + ); + expectObservable(source).toBe(expected, expectedValues); + }); + + it('should allow using a keySelector and a durationSelector, outer throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-#', values); + const e1subs = '^ !'; + const expected = '--v---w---x-y-----z-------#'; + const v = cold( 'a-b---(d|)' , values); + const w = cold( 'c-------g-(h|)' , values); + const x = cold( 'e---------j-(k|)' , values); + const y = cold( 'f-------------#', values); + const z = cold( 'i-----l-#', values); + const expectedValues = { v: v, w: w, x: x, y: y, z: z }; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(2) + ); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow using a durationSelector, and outer unsubscribed early', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const unsub = ' !'; + const expected = '--v---w---x-'; + const v = cold( 'a-b---(d|)' , values); + const w = cold( 'c-------g-(h|)' , values); + const x = cold( 'e---------j-(k|)' , values); + const expectedValues = { v: v, w: w, x: x }; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(2) + ); + + expectObservable(source, unsub).toBe(expected, expectedValues); + }); + + it('should allow using a durationSelector, outer and all inners unsubscribed early', + () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const unsub = ' !'; + const expected = '--v---w---x-'; + const v = '--a-b---(d|)'; + const w = '------c-----'; + const x = '----------e-'; + + const expectedGroups = { + v: Rx.TestScheduler.parseMarbles(v, values), + w: Rx.TestScheduler.parseMarbles(w, values), + x: Rx.TestScheduler.parseMarbles(x, values) + }; + + const unsubscriptionFrame = Rx.TestScheduler + .parseMarblesAsSubscriptions(unsub) + .unsubscribedFrame; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(2) + ) + .map((group: any) => { + const arr = []; + + const subscription = group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + + rxTestScheduler.schedule(() => { + subscription.unsubscribe(); + }, unsubscriptionFrame - rxTestScheduler.frame); + return arr; + }); + + expectObservable(source, unsub).toBe(expected, expectedGroups); + }); + + it('should allow using a durationSelector, but keySelector throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--v---w---x-y-----z-#' ; + const v = cold( 'a-b---(d|)' , values); + const w = cold( 'c-------g-(h|)' , values); + const x = cold( 'e---------#' , values); + const y = cold( 'f-------#' , values); + const z = cold( 'i-#' , values); + const expectedValues = { v: v, w: w, x: x, y: y, z: z }; + + let invoked = 0; + const source = e1 + .groupBy( + (val: any) => { + invoked++; + if (invoked === 10) { + throw 'error'; + } + return val.toLowerCase().trim(); + }, + (val: string) => val, + (group: any) => group.skip(2) + ); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow using a durationSelector, but elementSelector throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ ! '; + const expected = '--v---w---x-y-----z-# '; + const v = cold( 'a-b---(d|) ', values); + const w = cold( 'c-------g-(h|) ', values); + const x = cold( 'e---------# ', values); + const y = cold( 'f-------# ', values); + const z = cold( 'i-# ', values); + const expectedValues = { v: v, w: w, x: x, y: y, z: z }; + + let invoked = 0; + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => { + invoked++; + if (invoked === 10) { + throw 'error'; + } + return val; + }, + (group: any) => group.skip(2) + ); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow using a durationSelector which eventually throws', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ ! '; + const expected = '--v---w---x-# '; + const v = cold( 'a-b---(d|) ', values); + const w = cold( 'c-----# ', values); + const x = cold( 'e-# ', values); + const y = cold( '# ', values); + const expectedValues = { v: v, w: w, x: x, y: y }; + + let invoked = 0; + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => { + invoked++; + if (invoked === 4) { + throw 'error'; + } + return group.skip(2); + } + ); + + expectObservable(source).toBe(expected, expectedValues); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow an inner to be unsubscribed early but other inners continue, ' + + 'with durationSelector', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const reversedValues = mapObject(values, reverseString); + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--v---w---x-y-----z-------|'; + const v = '--a-b---' ; + const unsubv = ' !'; + const w = '------c-------g-(h|)' ; + const x = '----------e---------j-(k|)' ; + const y = '------------f-------------|'; + const z = '------------------i-----l-|'; + + const expectedGroups = { + v: Rx.TestScheduler.parseMarbles(v, reversedValues), + w: Rx.TestScheduler.parseMarbles(w, reversedValues), + x: Rx.TestScheduler.parseMarbles(x, reversedValues), + y: Rx.TestScheduler.parseMarbles(y, reversedValues), + z: Rx.TestScheduler.parseMarbles(z, reversedValues) + }; + + const fooUnsubscriptionFrame = Rx.TestScheduler + .parseMarblesAsSubscriptions(unsubv) + .unsubscribedFrame; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => reverseString(val), + (group: any) => group.skip(2) + ) + .map((group: any, index: number) => { + const arr = []; + + const subscription = group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + + if (group.key === 'foo' && index === 0) { + rxTestScheduler.schedule(() => { + subscription.unsubscribe(); + }, fooUnsubscriptionFrame - rxTestScheduler.frame); + } + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow inners to be unsubscribed early at different times, with durationSelector', + () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--v---w---x-y-----z-------|'; + const v = '--a-b---' ; + const unsubv = ' !' ; + const w = '------c---' ; + const unsubw = ' !' ; + const x = '----------e---------j-' ; + const unsubx = ' !' ; + const y = '------------f----' ; + const unsuby = ' !' ; + const z = '------------------i----' ; + const unsubz = ' !' ; + + const expectedGroups = { + v: Rx.TestScheduler.parseMarbles(v, values), + w: Rx.TestScheduler.parseMarbles(w, values), + x: Rx.TestScheduler.parseMarbles(x, values), + y: Rx.TestScheduler.parseMarbles(y, values), + z: Rx.TestScheduler.parseMarbles(z, values) + }; + + const unsubscriptionFrames = { + foo: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubv).unsubscribedFrame, + bar: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubw).unsubscribedFrame, + baz: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubx).unsubscribedFrame, + qux: Rx.TestScheduler.parseMarblesAsSubscriptions(unsuby).unsubscribedFrame, + foo2: Rx.TestScheduler.parseMarblesAsSubscriptions(unsubz).unsubscribedFrame + }; + const hasUnsubscribed = {}; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(2) + ) + .map((group: any) => { + const arr = []; + + const subscription = group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + + const unsubscriptionFrame = hasUnsubscribed[group.key] ? + unsubscriptionFrames[group.key + '2'] : + unsubscriptionFrames[group.key]; + rxTestScheduler.schedule(() => { + subscription.unsubscribe(); + hasUnsubscribed[group.key] = true; + }, unsubscriptionFrame - rxTestScheduler.frame); + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return inners that when subscribed late exhibit hot behavior', () => { + const values = { + a: ' foo', + b: ' FoO ', + c: 'baR ', + d: 'foO ', + e: ' Baz ', + f: ' qux ', + g: ' bar', + h: ' BAR ', + i: 'FOO ', + j: 'baz ', + k: ' bAZ ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b-c-d-e-f-g-h-i-j-k-l-|', values); + const e1subs = '^ !'; + const expected = '--v---w---x-y-----z-------|'; + const subv = ' ^ '; + const v = '--------(d|)' ; + const subw = ' ^ '; + const w = '----------------(h|)' ; + const subx = ' ^ '; + const x = '----------------------(k|)' ; + const suby = ' ^'; + const y = '------------------------------|'; + const subz = ' ^'; + const z = '--------------------------------|'; + + const expectedGroups = { + v: Rx.TestScheduler.parseMarbles(v, values), + w: Rx.TestScheduler.parseMarbles(w, values), + x: Rx.TestScheduler.parseMarbles(x, values), + y: Rx.TestScheduler.parseMarbles(y, values), + z: Rx.TestScheduler.parseMarbles(z, values) + }; + + const subscriptionFrames = { + foo: Rx.TestScheduler.parseMarblesAsSubscriptions(subv).subscribedFrame, + bar: Rx.TestScheduler.parseMarblesAsSubscriptions(subw).subscribedFrame, + baz: Rx.TestScheduler.parseMarblesAsSubscriptions(subx).subscribedFrame, + qux: Rx.TestScheduler.parseMarblesAsSubscriptions(suby).subscribedFrame, + foo2: Rx.TestScheduler.parseMarblesAsSubscriptions(subz).subscribedFrame + }; + const hasSubscribed = {}; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(2) + ) + .map((group: any) => { + const arr = []; + + const subscriptionFrame = hasSubscribed[group.key] ? + subscriptionFrames[group.key + '2'] : + subscriptionFrames[group.key]; + + rxTestScheduler.schedule(() => { + group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + hasSubscribed[group.key] = true; + }, subscriptionFrame - rxTestScheduler.frame); + + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return inner group that when subscribed late emits complete()', () => { + const values = { + a: ' foo', + b: ' FoO ', + d: 'foO ', + i: 'FOO ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b---d---------i-----l-|', values); + const e1subs = '^ !'; + const expected = '--g-----------------------|'; + const innerSub = ' ^'; + const g = '--------------------------------|'; + + const expectedGroups = { + g: Rx.TestScheduler.parseMarbles(g, values) + }; + + const innerSubscriptionFrame = Rx.TestScheduler + .parseMarblesAsSubscriptions(innerSub) + .subscribedFrame; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(7) + ) + .map((group: any) => { + const arr = []; + + rxTestScheduler.schedule(() => { + group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + }, innerSubscriptionFrame - rxTestScheduler.frame); + + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return inner group that when subscribed late emits error()', () => { + const values = { + a: ' foo', + b: ' FoO ', + d: 'foO ', + i: 'FOO ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b---d---------i-----l-#', values); + const e1subs = '^ !'; + const expected = '--g-----------------------#'; + const innerSub = ' ^'; + const g = '--------------------------------#'; + + const expectedGroups = { + g: Rx.TestScheduler.parseMarbles(g, values) + }; + + const innerSubscriptionFrame = Rx.TestScheduler + .parseMarblesAsSubscriptions(innerSub) + .subscribedFrame; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(7) + ) + .map((group: any) => { + const arr = []; + + rxTestScheduler.schedule(() => { + group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + }, innerSubscriptionFrame - rxTestScheduler.frame); + + return arr; + }); + + expectObservable(source).toBe(expected, expectedGroups); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return inner that does not throw when faulty outer is unsubscribed early', + () => { + const values = { + a: ' foo', + b: ' FoO ', + d: 'foO ', + i: 'FOO ', + l: ' fOo ' + }; + const e1 = hot('-1--2--^-a-b---d---------i-----l-#', values); + const unsub = ' !'; + const expectedSubs = '^ !'; + const expected = '--g----'; + const innerSub = ' ^'; + const g = '-'; + + const expectedGroups = { + g: Rx.TestScheduler.parseMarbles(g, values) + }; + + const innerSubscriptionFrame = Rx.TestScheduler + .parseMarblesAsSubscriptions(innerSub) + .subscribedFrame; + + const source = e1 + .groupBy( + (val: string) => val.toLowerCase().trim(), + (val: string) => val, + (group: any) => group.skip(7) + ) + .map((group: any) => { + const arr = []; + + rxTestScheduler.schedule(() => { + group + .materialize() + .map((notification: Rx.Notification) => { + return { frame: rxTestScheduler.frame, notification: notification }; + }) + .subscribe((value: any) => { + arr.push(value); + }); + }, innerSubscriptionFrame - rxTestScheduler.frame); + + return arr; + }); + + expectObservable(source, unsub).toBe(expected, expectedGroups); + expectSubscriptions(e1.subscriptions).toBe(expectedSubs); + }); + + it('should not break lift() composability', (done: DoneSignature) => { + class MyCustomObservable extends Rx.Observable { + lift(operator: Rx.Operator): Rx.Observable { + const observable = new MyCustomObservable(); + (observable).source = this; + (observable).operator = operator; + return observable; + } + } + + const result = new MyCustomObservable((observer: Rx.Observer) => { + observer.next(1); + observer.next(2); + observer.next(3); + observer.complete(); + }).groupBy( + (x: number) => x % 2, + (x: string) => x + '!' + ); + + expect(result instanceof MyCustomObservable).toBe(true); + + const expectedGroups = [ + { key: 1, values: ['1!', '3!'] }, + { key: 0, values: ['2!'] } + ]; + + result + .subscribe((g: any) => { + const expectedGroup = expectedGroups.shift(); + expect(g.key).toBe(expectedGroup.key); + + g.subscribe((x: any) => { + expect(x).toBe(expectedGroup.values.shift()); + }); + }, done.fail, done); + }); +}); diff --git a/spec/operators/ignoreElements-spec.js b/spec/operators/ignoreElements-spec.js deleted file mode 100644 index 7e292aaa1f..0000000000 --- a/spec/operators/ignoreElements-spec.js +++ /dev/null @@ -1,77 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.ignoreElements', function () { - it.asDiagram('ignoreElements')('should ignore all the elements of the source', function () { - var source = hot('--a--b--c--d--|'); - var subs = '^ !'; - var expected = '--------------|'; - - expectObservable(source.ignoreElements()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--d--|'); - var subs = '^ ! '; - var expected = '-------- '; - var unsub = ' ! '; - - var result = source.ignoreElements(); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var source = hot('--a--b--c--d--|'); - var subs = '^ ! '; - var expected = '-------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .ignoreElements() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should propagate errors from the source', function () { - var source = hot('--a--#'); - var subs = '^ !'; - var expected = '-----#'; - - expectObservable(source.ignoreElements()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should support Observable.empty', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '|'; - - expectObservable(source.ignoreElements()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should support Observable.never', function () { - var source = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.ignoreElements()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should support Observable.throw', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(source.ignoreElements()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); diff --git a/spec/operators/ignoreElements-spec.ts b/spec/operators/ignoreElements-spec.ts new file mode 100644 index 0000000000..0d510b4d43 --- /dev/null +++ b/spec/operators/ignoreElements-spec.ts @@ -0,0 +1,79 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.ignoreElements', () => { + asDiagram('ignoreElements')('should ignore all the elements of the source', () => { + const source = hot('--a--b--c--d--|'); + const subs = '^ !'; + const expected = '--------------|'; + + expectObservable(source.ignoreElements()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--d--|'); + const subs = '^ ! '; + const expected = '-------- '; + const unsub = ' ! '; + + const result = source.ignoreElements(); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const source = hot('--a--b--c--d--|'); + const subs = '^ ! '; + const expected = '-------- '; + const unsub = ' ! '; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .ignoreElements() + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should propagate errors from the source', () => { + const source = hot('--a--#'); + const subs = '^ !'; + const expected = '-----#'; + + expectObservable(source.ignoreElements()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should support Observable.empty', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '|'; + + expectObservable(source.ignoreElements()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should support Observable.never', () => { + const source = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable(source.ignoreElements()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should support Observable.throw', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable(source.ignoreElements()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); diff --git a/spec/operators/inspect-spec.js b/spec/operators/inspect-spec.js deleted file mode 100644 index c2dbc1ab36..0000000000 --- a/spec/operators/inspect-spec.js +++ /dev/null @@ -1,329 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscription, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Scheduler = Rx.Scheduler; -var Promise = require('promise'); - -describe('Observable.prototype.inspect()', function () { - it.asDiagram('inspect')('should emit the last value in each time window', function () { - var e1 = hot('-a-xy-----b--x--cxxx-|'); - var e1subs = '^ !'; - var e2 = cold( '----| '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-----y--------x-----x|'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should delay the source if values are not emitted often enough', function () { - var e1 = hot('-a--------b-----c----|'); - var e1subs = '^ !'; - var e2 = cold( '----| '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-----a--------b-----c|'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should inspect with duration Observable using next to close the duration', function () { - var e1 = hot('-a-xy-----b--x--cxxx-|'); - var e1subs = '^ !'; - var e2 = cold( '----x-y-z '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-----y--------x-----x|'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should interrupt source and duration when result is unsubscribed early', function () { - var e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var e2 = cold( '-----x------------| '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^! ']; - var expected = '------y-----z-- '; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); - var e1subs = '^ ! '; - var e2 = cold( '-----x------------| '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^! ']; - var expected = '------y-----z-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .inspect(function () { return e2; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a busy producer emitting a regular repeating sequence', function () { - var e1 = hot('abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ !'; - var e2 = cold('-----| '); - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^!']; - var expected = '-----f-----f-----f-----f-|'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should mirror source if durations are always empty', function () { - var e1 = hot('abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ !'; - var e2 = cold('|'); - var expected = 'abcdefabcdefabcdefabcdefa|'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit no values if duration is a never', function () { - var e1 = hot('----abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ !'; - var e2 = cold('-'); - var e2subs = ' ^ !'; - var expected = '-----------------------------|'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe duration Observable when source raise error', function () { - var e1 = hot('----abcdefabcdefabcdefabcdefa#'); - var e1subs = '^ !'; - var e2 = cold('-'); - var e2subs = ' ^ !'; - var expected = '-----------------------------#'; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error as soon as just-throw duration is used', function () { - var e1 = hot('----abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ ! '; - var e2 = cold('#'); - var e2subs = ' (^!) '; - var expected = '----(-#) '; - - var result = e1.inspect(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should inspect using durations of varying lengths', function () { - var e1 = hot('abcdefabcdabcdefghabca| '); - var e1subs = '^ ! '; - var e2 = [cold('-----| '), - cold( '---| '), - cold( '-------| '), - cold( '--| '), - cold( '----|')]; - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^! ']; - var expected = '-----f---d-------h--c-| '; - - var i = 0; - var result = e1.inspect(function () { return e2[i++]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var j = 0; j < e2.length; j++) { - expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); - } - }); - - it('should propagate error from duration Observable', function () { - var e1 = hot('abcdefabcdabcdefghabca| '); - var e1subs = '^ ! '; - var e2 = [cold('-----| '), - cold( '---| '), - cold( '-------# ')]; - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-----f---d-------# '; - - var i = 0; - var result = e1.inspect(function () { return e2[i++]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var j = 0; j < e2.length; j++) { - expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); - } - }); - - it('should propagate error thrown from durationSelector function', function () { - var e1 = hot('abcdefabcdabcdefghabca| '); - var e1subs = '^ ! '; - var e2 = [cold('-----| '), - cold( '---| '), - cold( '-------| ')]; - var e2subs = ['^ ! ', - ' ^ ! ']; - var expected = '-----f---d# '; - - var i = 0; - var result = e1.inspect(function () { - if (i === 2) { - throw 'error'; - } - return e2[i++]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var j = 0; j < e2subs.length; j++) { - expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); - } - }); - - it('should complete when source does not emit', function () { - var e1 = hot('-----|'); - var subs = '^ !'; - var expected = '-----|'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.inspect(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source does not emit and raises error', function () { - var e1 = hot('-----#'); - var subs = '^ !'; - var expected = '-----#'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.inspect(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle an empty source', function () { - var e1 = cold('|'); - var subs = '(^!)'; - var expected = '|'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.inspect(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a never source', function () { - var e1 = cold('-'); - var subs = '^'; - var expected = '-'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.inspect(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a throw source', function () { - var e1 = cold('#'); - var subs = '(^!)'; - var expected = '#'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.inspect(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should inspect by promise resolves', function (done) { - var e1 = Observable.interval(10).take(5); - var expected = [0,1,2,3]; - - e1.inspect(function () { - return new Promise(function (resolve) { resolve(42); }); - }).subscribe( - function (x) { - expect(x).toEqual(expected.shift()); }, - function () { - done('should not be called'); - }, - function () { - expect(expected.length).toBe(0); - done(); - } - ); - }); - - it('should raise error when promise rejects', function (done) { - var e1 = Observable.interval(10).take(4); - var expected = [0,1,2]; - var error = new Error('error'); - - e1.inspect(function (x) { - if (x === 4) { - return new Promise(function (resolve, reject) {reject(error);}); - } else { - return new Promise(function (resolve) {resolve(42);}); - } - }).subscribe( - function (x) { - expect(x).toEqual(expected.shift()); }, - function (err) { - expect(err).toBe(error); - expect(expected.length).toBe(0); - done(); - }, - function () { - done('should not be called'); - } - ); - }); -}); diff --git a/spec/operators/inspect-spec.ts b/spec/operators/inspect-spec.ts new file mode 100644 index 0000000000..116e1ddc69 --- /dev/null +++ b/spec/operators/inspect-spec.ts @@ -0,0 +1,330 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Scheduler = Rx.Scheduler; + +describe('Observable.prototype.inspect()', () => { + asDiagram('inspect')('should emit the last value in each time window', () => { + const e1 = hot('-a-xy-----b--x--cxxx-|'); + const e1subs = '^ !'; + const e2 = cold( '----| '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-----y--------x-----x|'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should delay the source if values are not emitted often enough', () => { + const e1 = hot('-a--------b-----c----|'); + const e1subs = '^ !'; + const e2 = cold( '----| '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-----a--------b-----c|'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should inspect with duration Observable using next to close the duration', () => { + const e1 = hot('-a-xy-----b--x--cxxx-|'); + const e1subs = '^ !'; + const e2 = cold( '----x-y-z '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-----y--------x-----x|'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should interrupt source and duration when result is unsubscribed early', () => { + const e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const e2 = cold( '-----x------------| '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^! ']; + const expected = '------y-----z-- '; + + const result = e1.inspect(() => e2); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); + const e1subs = '^ ! '; + const e2 = cold( '-----x------------| '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^! ']; + const expected = '------y-----z-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .inspect(() => e2) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a busy producer emitting a regular repeating sequence', () => { + const e1 = hot('abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ !'; + const e2 = cold('-----| '); + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^!']; + const expected = '-----f-----f-----f-----f-|'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should mirror source if durations are always empty', () => { + const e1 = hot('abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ !'; + const e2 = cold('|'); + const expected = 'abcdefabcdefabcdefabcdefa|'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit no values if duration is a never', () => { + const e1 = hot('----abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ !'; + const e2 = cold('-'); + const e2subs = ' ^ !'; + const expected = '-----------------------------|'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should unsubscribe duration Observable when source raise error', () => { + const e1 = hot('----abcdefabcdefabcdefabcdefa#'); + const e1subs = '^ !'; + const e2 = cold('-'); + const e2subs = ' ^ !'; + const expected = '-----------------------------#'; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error as soon as just-throw duration is used', () => { + const e1 = hot('----abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ ! '; + const e2 = cold('#'); + const e2subs = ' (^!) '; + const expected = '----(-#) '; + + const result = e1.inspect(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should inspect using durations of constying lengths', () => { + const e1 = hot('abcdefabcdabcdefghabca| '); + const e1subs = '^ ! '; + const e2 = [cold('-----| '), + cold( '---| '), + cold( '-------| '), + cold( '--| '), + cold( '----|')]; + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^! ']; + const expected = '-----f---d-------h--c-| '; + + let i = 0; + const result = e1.inspect(() => e2[i++]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + for (let j = 0; j < e2.length; j++) { + expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); + } + }); + + it('should propagate error from duration Observable', () => { + const e1 = hot('abcdefabcdabcdefghabca| '); + const e1subs = '^ ! '; + const e2 = [cold('-----| '), + cold( '---| '), + cold( '-------# ')]; + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-----f---d-------# '; + + let i = 0; + const result = e1.inspect(() => e2[i++]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + for (let j = 0; j < e2.length; j++) { + expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); + } + }); + + it('should propagate error thrown from durationSelector function', () => { + const e1 = hot('abcdefabcdabcdefghabca| '); + const e1subs = '^ ! '; + const e2 = [cold('-----| '), + cold( '---| '), + cold( '-------| ')]; + const e2subs = ['^ ! ', + ' ^ ! ']; + const expected = '-----f---d# '; + + let i = 0; + const result = e1.inspect(() => { + if (i === 2) { + throw 'error'; + } + return e2[i++]; + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + for (let j = 0; j < e2subs.length; j++) { + expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); + } + }); + + it('should complete when source does not emit', () => { + const e1 = hot('-----|'); + const subs = '^ !'; + const expected = '-----|'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.inspect(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source does not emit and raises error', () => { + const e1 = hot('-----#'); + const subs = '^ !'; + const expected = '-----#'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.inspect(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle an empty source', () => { + const e1 = cold('|'); + const subs = '(^!)'; + const expected = '|'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.inspect(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a never source', () => { + const e1 = cold('-'); + const subs = '^'; + const expected = '-'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.inspect(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a throw source', () => { + const e1 = cold('#'); + const subs = '(^!)'; + const expected = '#'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.inspect(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should inspect by promise resolves', (done: DoneSignature) => { + const e1 = Observable.interval(10).take(5); + const expected = [0,1,2,3]; + + e1.inspect(() => { + return new Promise((resolve: any) => { resolve(42); }); + }).subscribe( + (x: number) => { + expect(x).toEqual(expected.shift()); }, + () => { + done.fail('should not be called'); + }, + () => { + expect(expected.length).toBe(0); + done(); + } + ); + }); + + it('should raise error when promise rejects', (done: DoneSignature) => { + const e1 = Observable.interval(10).take(10); + const expected = [0,1,2]; + const error = new Error('error'); + + e1.inspect((x: number) => { + if (x === 3) { + return new Promise((resolve: any, reject: any) => {reject(error);}); + } else { + return new Promise((resolve: any) => {resolve(42);}); + } + }).subscribe( + (x: number) => { + expect(x).toEqual(expected.shift()); }, + (err: any) => { + expect(err).toBe(error); + expect(expected.length).toBe(0); + done(); + }, + () => { + done.fail('should not be called'); + } + ); + }); +}); diff --git a/spec/operators/inspectTime-spec.js b/spec/operators/inspectTime-spec.js deleted file mode 100644 index 41a7c8cbce..0000000000 --- a/spec/operators/inspectTime-spec.js +++ /dev/null @@ -1,136 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscription, hot, cold, rxTestScheduler, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Scheduler = Rx.Scheduler; - -describe('Observable.prototype.inspectTime()', function () { - it.asDiagram('inspectTime(50)')('should emit the last value in each time window', function () { - var e1 = hot('-a-x-y----b---x-cx---|'); - var subs = '^ !'; - var expected = '------y--------x-----|'; - - var result = e1.inspectTime(50, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should inspect events by 50 time units', function (done) { - Observable.of(1, 2, 3) - .inspectTime(50) - .subscribe(function (x) { - done('should not be called'); - }, null, done); - }); - - it('should inspect events multiple times', function () { - var expected = ['1-2', '2-2']; - Observable.concat( - Observable.timer(0, 10, rxTestScheduler).take(3).map(function (x) { return '1-' + x; }), - Observable.timer(80, 10, rxTestScheduler).take(5).map(function (x) { return '2-' + x; }) - ) - .inspectTime(50, rxTestScheduler) - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }); - - rxTestScheduler.flush(); - }); - - it('should delay the source if values are not emitted often enough', function () { - var e1 = hot('-a--------b-----c----|'); - var subs = '^ !'; - var expected = '------a--------b-----|'; - - expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a busy producer emitting a regular repeating sequence', function () { - var e1 = hot('abcdefabcdefabcdefabcdefa|'); - var subs = '^ !'; - var expected = '-----f-----f-----f-----f-|'; - - expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should complete when source does not emit', function () { - var e1 = hot('-----|'); - var subs = '^ !'; - var expected = '-----|'; - - expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source does not emit and raises error', function () { - var e1 = hot('-----#'); - var subs = '^ !'; - var expected = '-----#'; - - expectObservable(e1.inspectTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle an empty source', function () { - var e1 = cold('|'); - var subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.inspectTime(30, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a never source', function () { - var e1 = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(e1.inspectTime(30, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a throw source', function () { - var e1 = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.inspectTime(30, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should not complete when source does not complete', function () { - var e1 = hot('-a--(bc)-------d----------------'); - var unsub = ' !'; - var subs = '^ !'; - var expected = '------c-------------d-----------'; - - expectObservable(e1.inspectTime(50, rxTestScheduler), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-a--(bc)-------d----------------'); - var subs = '^ !'; - var expected = '------c-------------d-----------'; - var unsub = ' !'; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .inspectTime(50, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should inspect values until source raises error', function () { - var e1 = hot('-a--(bc)-------d---------------#'); - var subs = '^ !'; - var expected = '------c-------------d----------#'; - - expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); -}); diff --git a/spec/operators/inspectTime-spec.ts b/spec/operators/inspectTime-spec.ts new file mode 100644 index 0000000000..c226e62be6 --- /dev/null +++ b/spec/operators/inspectTime-spec.ts @@ -0,0 +1,139 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; +const Scheduler = Rx.Scheduler; + +describe('Observable.prototype.inspectTime()', () => { + asDiagram('inspectTime(50)')('should emit the last value in each time window', () => { + const e1 = hot('-a-x-y----b---x-cx---|'); + const subs = '^ !'; + const expected = '------y--------x-----|'; + + const result = e1.inspectTime(50, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should inspect events by 50 time units', (done: DoneSignature) => { + Observable.of(1, 2, 3) + .inspectTime(50) + .subscribe((x: number) => { + done.fail('should not be called'); + }, null, done); + }); + + it('should inspect events multiple times', () => { + const expected = ['1-2', '2-2']; + Observable.concat( + Observable.timer(0, 10, rxTestScheduler).take(3).map((x: number) => '1-' + x), + Observable.timer(80, 10, rxTestScheduler).take(5).map((x: number) => '2-' + x) + ) + .inspectTime(50, rxTestScheduler) + .subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }); + + rxTestScheduler.flush(); + }); + + it('should delay the source if values are not emitted often enough', () => { + const e1 = hot('-a--------b-----c----|'); + const subs = '^ !'; + const expected = '------a--------b-----|'; + + expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a busy producer emitting a regular repeating sequence', () => { + const e1 = hot('abcdefabcdefabcdefabcdefa|'); + const subs = '^ !'; + const expected = '-----f-----f-----f-----f-|'; + + expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should complete when source does not emit', () => { + const e1 = hot('-----|'); + const subs = '^ !'; + const expected = '-----|'; + + expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source does not emit and raises error', () => { + const e1 = hot('-----#'); + const subs = '^ !'; + const expected = '-----#'; + + expectObservable(e1.inspectTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle an empty source', () => { + const e1 = cold('|'); + const subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.inspectTime(30, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a never source', () => { + const e1 = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable(e1.inspectTime(30, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a throw source', () => { + const e1 = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.inspectTime(30, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not complete when source does not complete', () => { + const e1 = hot('-a--(bc)-------d----------------'); + const unsub = ' !'; + const subs = '^ !'; + const expected = '------c-------------d-----------'; + + expectObservable(e1.inspectTime(50, rxTestScheduler), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-a--(bc)-------d----------------'); + const subs = '^ !'; + const expected = '------c-------------d-----------'; + const unsub = ' !'; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .inspectTime(50, rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should inspect values until source raises error', () => { + const e1 = hot('-a--(bc)-------d---------------#'); + const subs = '^ !'; + const expected = '------c-------------d----------#'; + + expectObservable(e1.inspectTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); +}); diff --git a/spec/operators/isEmpty-spec.js b/spec/operators/isEmpty-spec.js deleted file mode 100644 index fbbb18f63f..0000000000 --- a/spec/operators/isEmpty-spec.js +++ /dev/null @@ -1,74 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); - -describe('Observable.prototype.isEmpty()', function () { - it.asDiagram('isEmpty')('should return true if source is empty', function () { - var source = hot('-----|'); - var subs = '^ !'; - var expected = '-----(T|)'; - - expectObservable(source.isEmpty()).toBe(expected, { T: true }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return false if source emits element', function () { - var source = hot('--a--^--b--|'); - var subs = '^ !'; - var expected = '---(F|)'; - - expectObservable(source.isEmpty()).toBe(expected, { F: false }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if source raise error', function () { - var source = hot('--#'); - var subs = '^ !'; - var expected = '--#'; - - expectObservable(source.isEmpty()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not completes if source never emits', function () { - var source = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.isEmpty()).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return true if source is Observable.empty()', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '(T|)'; - - expectObservable(source.isEmpty()).toBe(expected, { T: true }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var source = cold('-----------a--b--|'); - var unsub = ' ! '; - var subs = '^ ! '; - var expected = '------- '; - - expectObservable(source.isEmpty(), unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = cold('-----------a--b--|'); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .isEmpty() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/isEmpty-spec.ts b/spec/operators/isEmpty-spec.ts new file mode 100644 index 0000000000..3d61262dfb --- /dev/null +++ b/spec/operators/isEmpty-spec.ts @@ -0,0 +1,75 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +describe('Observable.prototype.isEmpty()', () => { + asDiagram('isEmpty')('should return true if source is empty', () => { + const source = hot('-----|'); + const subs = '^ !'; + const expected = '-----(T|)'; + + expectObservable((source).isEmpty()).toBe(expected, { T: true }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return false if source emits element', () => { + const source = hot('--a--^--b--|'); + const subs = '^ !'; + const expected = '---(F|)'; + + expectObservable((source).isEmpty()).toBe(expected, { F: false }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if source raise error', () => { + const source = hot('--#'); + const subs = '^ !'; + const expected = '--#'; + + expectObservable((source).isEmpty()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not completes if source never emits', () => { + const source = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable((source).isEmpty()).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return true if source is Observable.empty()', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '(T|)'; + + expectObservable((source).isEmpty()).toBe(expected, { T: true }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const source = cold('-----------a--b--|'); + const unsub = ' ! '; + const subs = '^ ! '; + const expected = '------- '; + + expectObservable((source).isEmpty(), unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = cold('-----------a--b--|'); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source) + .mergeMap((x: string) => Rx.Observable.of(x)) + .isEmpty() + .mergeMap((x: string) => Rx.Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/last-spec.js b/spec/operators/last-spec.js deleted file mode 100644 index 732377c342..0000000000 --- a/spec/operators/last-spec.js +++ /dev/null @@ -1,144 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.last()', function () { - it.asDiagram('last')('should take the last value of an observable', function () { - var e1 = hot('--a----b--c--|'); - var e1subs = '^ !'; - var expected = '-------------(c|)'; - - expectObservable(e1.last()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error on nothing sent but completed', function () { - var e1 = hot('--a--^----|'); - var e1subs = '^ !'; - var expected = '-----#'; - - expectObservable(e1.last()).toBe(expected, null, new Rx.EmptyError()); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error on empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.last()).toBe(expected, null, new Rx.EmptyError()); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should go on forever on never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.last()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return last element matches with predicate', function () { - var e1 = hot('--a--b--a--b--|'); - var e1subs = '^ !'; - var expected = '--------------(b|)'; - - var predicate = function (value) { - return value === 'b'; - }; - - expectObservable(e1.last(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--c--d--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '-------- '; - - expectObservable(e1.last(), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--c--d--|'); - var e1subs = '^ ! '; - var expected = '-------- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .last() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return a default value if no element found', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(a|)'; - - expectObservable(e1.last(null, null, 'a')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not return default value if an element is found', function () { - var e1 = hot('--a---^---b---c---d---|'); - var e1subs = '^ !'; - var expected = '----------------(d|)'; - - expectObservable(e1.last(null, null, 'x')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should support a result selector argument', function () { - var e1 = hot('--a--^---b---c---d---e--|'); - var e1subs = '^ !'; - var expected = '-------------------(x|)'; - - var predicate = function (x) { return x === 'c'; }; - var resultSelector = function (x, i) { - expect(i).toBe(1); - expect(x).toBe('c'); - return 'x'; - }; - - expectObservable(e1.last(predicate, resultSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when predicate throws', function () { - var e1 = hot('--a--^---b---c---d---e--|'); - var e1subs = '^ ! '; - var expected = '--------# '; - - var predicate = function (x) { - if (x === 'c') { - throw 'error'; - } else { - return false; - } - }; - - expectObservable(e1.last(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when result selector throws', function () { - var e1 = hot('--a--^---b---c---d---e--|'); - var e1subs = '^ ! '; - var expected = '--------# '; - - var predicate = function (x) { return x === 'c'; }; - var resultSelector = function (x, i) { - throw 'error'; - }; - - expectObservable(e1.last(predicate, resultSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/last-spec.ts b/spec/operators/last-spec.ts new file mode 100644 index 0000000000..3bc51128f0 --- /dev/null +++ b/spec/operators/last-spec.ts @@ -0,0 +1,144 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +describe('Observable.prototype.last()', () => { + asDiagram('last')('should take the last value of an observable', () => { + const e1 = hot('--a----b--c--|'); + const e1subs = '^ !'; + const expected = '-------------(c|)'; + + expectObservable(e1.last()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error on nothing sent but completed', () => { + const e1 = hot('--a--^----|'); + const e1subs = '^ !'; + const expected = '-----#'; + + expectObservable(e1.last()).toBe(expected, null, new Rx.EmptyError()); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error on empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.last()).toBe(expected, null, new Rx.EmptyError()); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should go on forever on never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.last()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return last element matches with predicate', () => { + const e1 = hot('--a--b--a--b--|'); + const e1subs = '^ !'; + const expected = '--------------(b|)'; + + const predicate = function (value) { + return value === 'b'; + }; + + expectObservable(e1.last(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c--d--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '-------- '; + + expectObservable(e1.last(), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--c--d--|'); + const e1subs = '^ ! '; + const expected = '-------- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Rx.Observable.of(x)) + .last() + .mergeMap((x: string) => Rx.Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return a default value if no element found', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(a|)'; + + expectObservable(e1.last(null, null, 'a')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not return default value if an element is found', () => { + const e1 = hot('--a---^---b---c---d---|'); + const e1subs = '^ !'; + const expected = '----------------(d|)'; + + expectObservable(e1.last(null, null, 'x')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should support a result selector argument', () => { + const e1 = hot('--a--^---b---c---d---e--|'); + const e1subs = '^ !'; + const expected = '-------------------(x|)'; + + const predicate = function (x) { return x === 'c'; }; + const resultSelector = function (x, i) { + expect(i).toBe(1); + expect(x).toBe('c'); + return 'x'; + }; + + expectObservable(e1.last(predicate, resultSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when predicate throws', () => { + const e1 = hot('--a--^---b---c---d---e--|'); + const e1subs = '^ ! '; + const expected = '--------# '; + + const predicate = function (x) { + if (x === 'c') { + throw 'error'; + } else { + return false; + } + }; + + expectObservable(e1.last(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when result selector throws', () => { + const e1 = hot('--a--^---b---c---d---e--|'); + const e1subs = '^ ! '; + const expected = '--------# '; + + const predicate = function (x) { return x === 'c'; }; + const resultSelector = function (x, i) { + throw 'error'; + }; + + expectObservable(e1.last(predicate, resultSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/let-spec.js b/spec/operators/let-spec.js deleted file mode 100644 index 405a4dd811..0000000000 --- a/spec/operators/let-spec.js +++ /dev/null @@ -1,24 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('let', function () { - it('should be able to compose with let', function (done) { - var expected = ['aa', 'bb']; - var i = 0; - - var foo = function (observable) { - return observable - .map(function (x) { - return x + x; - }); - }; - - Observable - .fromArray(['a','b']) - .let(foo) - .subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }); -}); diff --git a/spec/operators/let-spec.ts b/spec/operators/let-spec.ts new file mode 100644 index 0000000000..0147749878 --- /dev/null +++ b/spec/operators/let-spec.ts @@ -0,0 +1,18 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; + +describe('let', () => { + it('should be able to compose with let', (done: DoneSignature) => { + const expected = ['aa', 'bb']; + let i = 0; + + const foo = (observable: Rx.Observable) => observable.map((x: string) => x + x); + + Rx.Observable + .fromArray(['a','b']) + .let(foo) + .subscribe(function (x) { + expect(x).toBe(expected[i++]); + }, done.fail, done); + }); +}); diff --git a/spec/operators/map-spec.js b/spec/operators/map-spec.js deleted file mode 100644 index 3eb27c00bb..0000000000 --- a/spec/operators/map-spec.js +++ /dev/null @@ -1,252 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -// function shortcuts -var addDrama = function (x) { return x + '!'; }; -var identity = function (x) { return x; }; -var throwError = function () { throw new Error(); }; - -describe('Observable.prototype.map()', function () { - it.asDiagram('map(x => 10 * x)')('should map multiple values', function () { - var a = cold('--1--2--3--|'); - var asubs = '^ !'; - var expected = '--x--y--z--|'; - - var r = a.map(function (x) { return 10 * x; }); - - expectObservable(r).toBe(expected, {x: 10, y: 20, z: 30}); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map one value', function () { - var a = cold('--x--|', {x: 42}); - var asubs = '^ !'; - var expected = '--y--|'; - - var r = a.map(addDrama); - - expectObservable(r).toBe(expected, {y: '42!'}); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should throw an error if not passed a function', function () { - expect(function () { - Observable.of(1, 2, 3).map('potato'); - }).toThrow(new TypeError('argument is not a function. Are you looking for `mapTo()`?')); - }); - - it('should map multiple values', function () { - var a = cold('--1--2--3--|'); - var asubs = '^ !'; - var expected = '--x--y--z--|'; - - var r = a.map(addDrama); - - expectObservable(r).toBe(expected, {x: '1!', y: '2!', z: '3!'}); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from map function', function () { - var a = cold('--x--|', {x: 42}); - var asubs = '^ ! '; - var expected = '--# '; - - var r = a.map(function (x) { - throw 'too bad'; - }); - - expectObservable(r).toBe(expected, null, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from observable that emits only errors', function () { - var a = cold('#'); - var asubs = '(^!)'; - var expected = '#'; - - var r = a.map(identity); - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from observable that emit values', function () { - var a = cold('--a--b--#', {a: 1, b: 2}, 'too bad'); - var asubs = '^ !'; - var expected = '--x--y--#'; - - var r = a.map(addDrama); - expectObservable(r).toBe(expected, {x: '1!', y: '2!'}, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from subscribe', function () { - var r = function () { - Observable.of(1) - .map(identity) - .subscribe(throwError); - }; - - expect(r).toThrow(); - }); - - it('should not map an empty observable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var expected = '|'; - - var invoked = 0; - var r = a - .map(function (x) { invoked++; return x; }) - .do(null, null, function () { - expect(invoked).toBe(0); - }); - - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var a = cold('--1--2--3--|'); - var unsub = ' ! '; - var asubs = '^ ! '; - var expected = '--x--y- '; - - var r = a.map(addDrama); - - expectObservable(r, unsub).toBe(expected, {x: '1!', y: '2!'}); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map with index', function () { - var a = hot('-5-^-4--3---2----1--|'); - var asubs = '^ !'; - var expected = '--a--b---c----d--|'; - var values = {a: 5, b: 14, c: 23, d: 32}; - - var invoked = 0; - var r = a.map(function (x, index) { - invoked++; - return (parseInt(x) + 1) + (index * 10); - }).do(null, null, function () { - expect(invoked).toBe(4); - }); - - expectObservable(r).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map with index until completed', function () { - var a = hot('-5-^-4--3---2----1--|'); - var asubs = '^ !'; - var expected = '--a--b---c----d--|'; - var values = {a: 5, b: 14, c: 23, d: 32}; - - var invoked = 0; - var r = a.map(function (x, index) { - invoked++; - return (parseInt(x) + 1) + (index * 10); - }).do(null, null, function () { - expect(invoked).toBe(4); - }); - - expectObservable(r).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map with index until an error occurs', function () { - var a = hot('-5-^-4--3---2----1--#', undefined, 'too bad'); - var asubs = '^ !'; - var expected = '--a--b---c----d--#'; - var values = {a: 5, b: 14, c: 23, d: 32}; - - var invoked = 0; - var r = a.map(function (x, index) { - invoked++; - return (parseInt(x) + 1) + (index * 10); - }).do(null, null, function () { - expect(invoked).toBe(4); - }); - - expectObservable(r).toBe(expected, values, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map using a custom thisArg', function () { - var a = hot('-5-^-4--3---2----1--|'); - var asubs = '^ !'; - var expected = '--a--b---c----d--|'; - var values = {a: 5, b: 14, c: 23, d: 32}; - - var invoked = 0; - var foo = 42; - var r = a - .map(function (x, index) { - invoked++; - expect(this).toEqual(foo); - return (parseInt(x) + 1) + (index * 10); - }, 42) - .do(null, null, function () { - expect(invoked).toBe(4); - }); - - expectObservable(r).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map twice', function () { - var a = hot('-0----1-^-2---3--4-5--6--7-8-|'); - var asubs = '^ !'; - var expected = '--a---b--c-d--e--f-g-|'; - var values = {a: 2, b: 3, c: 4, d: 5, e: 6, f: 7, g: 8}; - - var invoked1 = 0; - var invoked2 = 0; - var r = a - .map(function (x) { invoked1++; return parseInt(x) * 2; }) - .map(function (x) { invoked2++; return x / 2; }) - .do(null, null, function () { - expect(invoked1).toBe(7); - expect(invoked2).toBe(7); - }); - - expectObservable(r).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should do multiple maps using a custom thisArg', function () { - var a = hot('--1--2--3--4--|'); - var asubs = '^ !'; - var expected = '--a--b--c--d--|'; - var values = {a: 11, b: 14, c: 17, d: 20}; - - function Filterer() { - this.selector1 = function (x) { return parseInt(x) + 2; }; - this.selector2 = function (x) { return parseInt(x) * 3; }; - } - var filterer = new Filterer(); - - var r = a - .map(function (x) { return this.selector1(x);}, filterer) - .map(function (x) { return this.selector2(x);}, filterer) - .map(function (x) { return this.selector1(x);}, filterer); - - expectObservable(r).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var a = cold('--1--2--3--|'); - var unsub = ' ! '; - var asubs = '^ ! '; - var expected = '--x--y- '; - - var r = a - .mergeMap(function (x) { return Observable.of(x); }) - .map(addDrama) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(r, unsub).toBe(expected, {x: '1!', y: '2!'}); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); -}); diff --git a/spec/operators/map-spec.ts b/spec/operators/map-spec.ts new file mode 100644 index 0000000000..ca1de2af78 --- /dev/null +++ b/spec/operators/map-spec.ts @@ -0,0 +1,254 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +// function shortcuts +const addDrama = function (x) { return x + '!'; }; +const identity = function (x) { return x; }; +const throwError = function () { throw new Error(); }; + +describe('Observable.prototype.map()', () => { + asDiagram('map(x => 10 * x)')('should map multiple values', () => { + const a = cold('--1--2--3--|'); + const asubs = '^ !'; + const expected = '--x--y--z--|'; + + const r = a.map(function (x) { return 10 * x; }); + + expectObservable(r).toBe(expected, {x: 10, y: 20, z: 30}); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map one value', () => { + const a = cold('--x--|', {x: 42}); + const asubs = '^ !'; + const expected = '--y--|'; + + const r = a.map(addDrama); + + expectObservable(r).toBe(expected, {y: '42!'}); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should throw an error if not passed a function', () => { + expect(() => { + Observable.of(1, 2, 3).map('potato'); + }).toThrow(new TypeError('argument is not a function. Are you looking for `mapTo()`?')); + }); + + it('should map multiple values', () => { + const a = cold('--1--2--3--|'); + const asubs = '^ !'; + const expected = '--x--y--z--|'; + + const r = a.map(addDrama); + + expectObservable(r).toBe(expected, {x: '1!', y: '2!', z: '3!'}); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from map function', () => { + const a = cold('--x--|', {x: 42}); + const asubs = '^ ! '; + const expected = '--# '; + + const r = a.map((x: any) => { + throw 'too bad'; + }); + + expectObservable(r).toBe(expected, null, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from observable that emits only errors', () => { + const a = cold('#'); + const asubs = '(^!)'; + const expected = '#'; + + const r = a.map(identity); + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from observable that emit values', () => { + const a = cold('--a--b--#', {a: 1, b: 2}, 'too bad'); + const asubs = '^ !'; + const expected = '--x--y--#'; + + const r = a.map(addDrama); + expectObservable(r).toBe(expected, {x: '1!', y: '2!'}, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from subscribe', () => { + const r = () => { + Observable.of(1) + .map(identity) + .subscribe(throwError); + }; + + expect(r).toThrow(); + }); + + it('should not map an empty observable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const expected = '|'; + + let invoked = 0; + const r = a + .map((x: any) => { invoked++; return x; }) + .do(null, null, () => { + expect(invoked).toBe(0); + }); + + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const a = cold('--1--2--3--|'); + const unsub = ' ! '; + const asubs = '^ ! '; + const expected = '--x--y- '; + + const r = a.map(addDrama); + + expectObservable(r, unsub).toBe(expected, {x: '1!', y: '2!'}); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map with index', () => { + const a = hot('-5-^-4--3---2----1--|'); + const asubs = '^ !'; + const expected = '--a--b---c----d--|'; + const values = {a: 5, b: 14, c: 23, d: 32}; + + let invoked = 0; + const r = a.map((x: string, index: number) => { + invoked++; + return (parseInt(x) + 1) + (index * 10); + }).do(null, null, () => { + expect(invoked).toBe(4); + }); + + expectObservable(r).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map with index until completed', () => { + const a = hot('-5-^-4--3---2----1--|'); + const asubs = '^ !'; + const expected = '--a--b---c----d--|'; + const values = {a: 5, b: 14, c: 23, d: 32}; + + let invoked = 0; + const r = a.map((x: string, index: number) => { + invoked++; + return (parseInt(x) + 1) + (index * 10); + }).do(null, null, () => { + expect(invoked).toBe(4); + }); + + expectObservable(r).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map with index until an error occurs', () => { + const a = hot('-5-^-4--3---2----1--#', undefined, 'too bad'); + const asubs = '^ !'; + const expected = '--a--b---c----d--#'; + const values = {a: 5, b: 14, c: 23, d: 32}; + + let invoked = 0; + const r = a.map((x: string, index: number) => { + invoked++; + return (parseInt(x) + 1) + (index * 10); + }).do(null, null, () => { + expect(invoked).toBe(4); + }); + + expectObservable(r).toBe(expected, values, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map using a custom thisArg', () => { + const a = hot('-5-^-4--3---2----1--|'); + const asubs = '^ !'; + const expected = '--a--b---c----d--|'; + const values = {a: 5, b: 14, c: 23, d: 32}; + + let invoked = 0; + const foo = 42; + const r = a + .map(function (x: string, index: number) { + invoked++; + expect(this).toEqual(foo); + return (parseInt(x) + 1) + (index * 10); + }, 42) + .do(null, null, () => { + expect(invoked).toBe(4); + }); + + expectObservable(r).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map twice', () => { + const a = hot('-0----1-^-2---3--4-5--6--7-8-|'); + const asubs = '^ !'; + const expected = '--a---b--c-d--e--f-g-|'; + const values = {a: 2, b: 3, c: 4, d: 5, e: 6, f: 7, g: 8}; + + let invoked1 = 0; + let invoked2 = 0; + const r = a + .map((x: string) => { invoked1++; return parseInt(x) * 2; }) + .map((x: number) => { invoked2++; return x / 2; }) + .do(null, null, () => { + expect(invoked1).toBe(7); + expect(invoked2).toBe(7); + }); + + expectObservable(r).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should do multiple maps using a custom thisArg', () => { + const a = hot('--1--2--3--4--|'); + const asubs = '^ !'; + const expected = '--a--b--c--d--|'; + const values = {a: 11, b: 14, c: 17, d: 20}; + + function Filterer() { + this.selector1 = (x: string) => parseInt(x) + 2; + this.selector2 = (x: string) => parseInt(x) * 3; + } + const filterer = new Filterer(); + + const r = a + .map(function (x) { return this.selector1(x);}, filterer) + .map(function (x) { return this.selector2(x);}, filterer) + .map(function (x) { return this.selector1(x);}, filterer); + + expectObservable(r).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const a = cold('--1--2--3--|'); + const unsub = ' ! '; + const asubs = '^ ! '; + const expected = '--x--y- '; + + const r = a + .mergeMap((x: string) => Observable.of(x)) + .map(addDrama) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(r, unsub).toBe(expected, {x: '1!', y: '2!'}); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); +}); diff --git a/spec/operators/mapTo-spec.js b/spec/operators/mapTo-spec.js deleted file mode 100644 index cd415441b6..0000000000 --- a/spec/operators/mapTo-spec.js +++ /dev/null @@ -1,99 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -// function shortcuts -var throwError = function () { throw new Error(); }; - -describe('Observable.prototype.mapTo()', function () { - it.asDiagram('mapTo(\'a\')')('should map multiple values', function () { - var a = cold('--1--2--3--|'); - var asubs = '^ !'; - var expected = '--a--a--a--|'; - - expectObservable(a.mapTo('a')).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map one value', function () { - var a = cold('--7--|'); - var asubs = '^ !'; - var expected = '--y--|'; - - expectObservable(a.mapTo('y')).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var a = cold('--1--2--3--|'); - var unsub = ' ! '; - var asubs = '^ ! '; - var expected = '--x--x- '; - - expectObservable(a.mapTo('x'), unsub).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from observable that emits only errors', function () { - var a = cold('--#', null, 'too bad'); - var asubs = '^ !'; - var expected = '--#'; - - expectObservable(a.mapTo(1)).toBe(expected, null, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from observable that emit values', function () { - var a = cold('--1--2--#', undefined, 'too bad'); - var asubs = '^ !'; - var expected = '--x--x--#'; - - expectObservable(a.mapTo('x')).toBe(expected, undefined, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from subscribe', function () { - var r = function () { - Observable.of(1) - .mapTo(-1) - .subscribe(throwError); - }; - - expect(r).toThrow(); - }); - - it('should not map an empty observable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var expected = '|'; - - expectObservable(a.mapTo(-1)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should map twice', function () { - var a = hot('-0----1-^-2---3--4-5--6--7-8-|'); - var asubs = '^ !'; - var expected = '--h---h--h-h--h--h-h-|'; - - var r = a.mapTo(-1).mapTo('h'); - - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var a = cold('--1--2--3--|'); - var unsub = ' ! '; - var asubs = '^ ! '; - var expected = '--x--x- '; - - var r = a - .mergeMap(function (x) { return Observable.of(x); }) - .mapTo('x') - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(r, unsub).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); -}); diff --git a/spec/operators/mapTo-spec.ts b/spec/operators/mapTo-spec.ts new file mode 100644 index 0000000000..5a298658ec --- /dev/null +++ b/spec/operators/mapTo-spec.ts @@ -0,0 +1,101 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +// function shortcuts +const throwError = function () { throw new Error(); }; + +describe('Observable.prototype.mapTo()', () => { + asDiagram('mapTo(\'a\')')('should map multiple values', () => { + const a = cold('--1--2--3--|'); + const asubs = '^ !'; + const expected = '--a--a--a--|'; + + expectObservable(a.mapTo('a')).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map one value', () => { + const a = cold('--7--|'); + const asubs = '^ !'; + const expected = '--y--|'; + + expectObservable(a.mapTo('y')).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const a = cold('--1--2--3--|'); + const unsub = ' ! '; + const asubs = '^ ! '; + const expected = '--x--x- '; + + expectObservable(a.mapTo('x'), unsub).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from observable that emits only errors', () => { + const a = cold('--#', null, 'too bad'); + const asubs = '^ !'; + const expected = '--#'; + + expectObservable(a.mapTo(1)).toBe(expected, null, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from observable that emit values', () => { + const a = cold('--1--2--#', undefined, 'too bad'); + const asubs = '^ !'; + const expected = '--x--x--#'; + + expectObservable(a.mapTo('x')).toBe(expected, undefined, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from subscribe', () => { + const r = () => { + Observable.of(1) + .mapTo(-1) + .subscribe(throwError); + }; + + expect(r).toThrow(); + }); + + it('should not map an empty observable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const expected = '|'; + + expectObservable(a.mapTo(-1)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should map twice', () => { + const a = hot('-0----1-^-2---3--4-5--6--7-8-|'); + const asubs = '^ !'; + const expected = '--h---h--h-h--h--h-h-|'; + + const r = a.mapTo(-1).mapTo('h'); + + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const a = cold('--1--2--3--|'); + const unsub = ' ! '; + const asubs = '^ ! '; + const expected = '--x--x- '; + + const r = a + .mergeMap((x: string) => Observable.of(x)) + .mapTo('x') + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(r, unsub).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); +}); diff --git a/spec/operators/materialize-spec.js b/spec/operators/materialize-spec.js deleted file mode 100644 index 65fc460566..0000000000 --- a/spec/operators/materialize-spec.js +++ /dev/null @@ -1,136 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Notification = Rx.Notification; - -describe('Observable.prototype.materialize()', function () { - it.asDiagram('materialize')('should materialize an Observable', function () { - var e1 = hot('--x--y--z--|'); - var expected = '--a--b--c--(d|)'; - var values = { a: '{x}', b: '{y}', c: '{z}', d: '|' }; - - var result = e1 - .materialize() - .map(function (x) { - if (x.kind === 'C') { - return '|'; - } else { - return '{' + x.value + '}'; - } - }); - - expectObservable(result).toBe(expected, values); - }); - - it('should materialize a happy stream', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var expected = '--w--x--y--(z|)'; - - var expectedValue = { - w: Notification.createNext('a'), - x: Notification.createNext('b'), - y: Notification.createNext('c'), - z: Notification.createComplete() - }; - - expectObservable(e1.materialize()).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should materialize a sad stream', function () { - var e1 = hot('--a--b--c--#'); - var e1subs = '^ !'; - var expected = '--w--x--y--(z|)'; - - var expectedValue = { - w: Notification.createNext('a'), - x: Notification.createNext('b'), - y: Notification.createNext('c'), - z: Notification.createError('error') - }; - - expectObservable(e1.materialize()).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--c--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '--w--x- '; - - var expectedValue = { - w: Notification.createNext('a'), - x: Notification.createNext('b') - }; - - expectObservable(e1.materialize(), unsub).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ ! '; - var expected = '--w--x- '; - var unsub = ' ! '; - - var expectedValue = { - w: Notification.createNext('a'), - x: Notification.createNext('b') - }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .materialize() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should materialize stream does not completes', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.materialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should materialize stream never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.materialize()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should materialize stream does not emit', function () { - var e1 = hot('----|'); - var e1subs = '^ !'; - var expected = '----(x|)'; - - expectObservable(e1.materialize()).toBe(expected, { x: Notification.createComplete() }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should materialize empty stream', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(x|)'; - - expectObservable(e1.materialize()).toBe(expected, { x: Notification.createComplete() }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should materialize stream throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '(x|)'; - - expectObservable(e1.materialize()).toBe(expected, { x: Notification.createError('error') }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/materialize-spec.ts b/spec/operators/materialize-spec.ts new file mode 100644 index 0000000000..f366968f86 --- /dev/null +++ b/spec/operators/materialize-spec.ts @@ -0,0 +1,138 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Notification = Rx.Notification; + +describe('Observable.prototype.materialize()', () => { + asDiagram('materialize')('should materialize an Observable', () => { + const e1 = hot('--x--y--z--|'); + const expected = '--a--b--c--(d|)'; + const values = { a: '{x}', b: '{y}', c: '{z}', d: '|' }; + + const result = e1 + .materialize() + .map((x: Rx.Notification) => { + if (x.kind === 'C') { + return '|'; + } else { + return '{' + x.value + '}'; + } + }); + + expectObservable(result).toBe(expected, values); + }); + + it('should materialize a happy stream', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const expected = '--w--x--y--(z|)'; + + const expectedValue = { + w: Notification.createNext('a'), + x: Notification.createNext('b'), + y: Notification.createNext('c'), + z: Notification.createComplete() + }; + + expectObservable(e1.materialize()).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should materialize a sad stream', () => { + const e1 = hot('--a--b--c--#'); + const e1subs = '^ !'; + const expected = '--w--x--y--(z|)'; + + const expectedValue = { + w: Notification.createNext('a'), + x: Notification.createNext('b'), + y: Notification.createNext('c'), + z: Notification.createError('error') + }; + + expectObservable(e1.materialize()).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '--w--x- '; + + const expectedValue = { + w: Notification.createNext('a'), + x: Notification.createNext('b') + }; + + expectObservable(e1.materialize(), unsub).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ ! '; + const expected = '--w--x- '; + const unsub = ' ! '; + + const expectedValue = { + w: Notification.createNext('a'), + x: Notification.createNext('b') + }; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .materialize() + .mergeMap((x: Rx.Notification) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should materialize stream does not completes', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.materialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should materialize stream never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.materialize()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should materialize stream does not emit', () => { + const e1 = hot('----|'); + const e1subs = '^ !'; + const expected = '----(x|)'; + + expectObservable(e1.materialize()).toBe(expected, { x: Notification.createComplete() }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should materialize empty stream', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(x|)'; + + expectObservable(e1.materialize()).toBe(expected, { x: Notification.createComplete() }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should materialize stream throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '(x|)'; + + expectObservable(e1.materialize()).toBe(expected, { x: Notification.createError('error') }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/max-spec.js b/spec/operators/max-spec.js deleted file mode 100644 index aa7f58ddd4..0000000000 --- a/spec/operators/max-spec.js +++ /dev/null @@ -1,248 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('max', function () { - it.asDiagram('max')('should find the max of values of an observable', function () { - var source = hot('--a--b--c--|', { a: 42, b: -1, c: 3 }); - var subs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.max()).toBe(expected, { x: 42 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should be never when source is never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.max()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be zero when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.max()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be never when source doesn\'t complete', function () { - var e1 = hot('--x--^--y--'); - var e1subs = '^ '; - var expected = '------'; - - expectObservable(e1.max()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be completes when source doesn\'t have values', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----|'; - - expectObservable(e1.max()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should max the unique value of an observable', function () { - var e1 = hot('-x-^--y--|', { y: 42 }); - var e1subs = '^ !'; - var expected = '------(w|)'; - - expectObservable(e1.max()).toBe(expected, { w: 42 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should max the values of an ongoing hot observable', function () { - var source = hot('--a-^-b--c--d--|', { a: 42, b: -1, c: 0, d: 666 }); - var subs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.max()).toBe(expected, { x: 666 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var source = hot('--a--b--c--|', { a: 42, b: -1, c: 0 }); - var unsub = ' ! '; - var subs = '^ ! '; - var expected = '------- '; - - expectObservable(source.max(), unsub).toBe(expected, { x: 42 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--a--b--c--|', { a: 42, b: -1, c: 0 }); - var subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .max() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, { x: 42 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should max a range() source observable', function (done) { - Rx.Observable.range(1, 10000).max().subscribe( - function (value) { - expect(value).toEqual(10000); - }, - done.fail, - done - ); - }); - - it('should max a range().skip(1) source observable', function (done) { - Rx.Observable.range(1, 10).skip(1).max().subscribe( - function (value) { - expect(value).toEqual(10); - }, - done.fail, - done - ); - }); - - it('should max a range().take(1) source observable', function (done) { - Rx.Observable.range(1, 10).take(1).max().subscribe( - function (value) { - expect(value).toEqual(1); - }, - done.fail, - done - ); - }); - - it('should work with error', function () { - var e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); - var e1subs = '^ !'; - var expected = '---------#'; - - expectObservable(e1.max()).toBe(expected, null, 'too bad'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.max()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on an empty hot observable', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----|'; - - var predicate = function (x, y) { - return 42; - }; - - expectObservable(e1.max(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on an never hot observable', function () { - var e1 = hot('-x-^----'); - var e1subs = '^ '; - var expected = '-----'; - - var predicate = function (x, y) { - return 42; - }; - - expectObservable(e1.max(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on a simple hot observable', function () { - var e1 = hot('-x-^-a-|', { a: 1 }); - var e1subs = '^ !'; - var expected = '----(w|)'; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.max(predicate)).toBe(expected, { w: 1 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on observable with many values', function () { - var e1 = hot('-x-^-a-b-c-d-e-f-g-|'); - var e1subs = '^ !'; - var expected = '----------------(w|)'; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.max(predicate)).toBe(expected, { w: 42 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate on observable with many values', function () { - var e1 = hot('-a-^-b--c--d-|', { a: 42, b: -1, c: 0, d: 666 }); - var e1subs = '^ !'; - var expected = '----------(w|)'; - - var predicate = function (x, y) { - return Math.min(x, y); - }; - - expectObservable(e1.max(predicate)).toBe(expected, { w: -1 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate for string on observable with many values', function () { - var e1 = hot('-1-^-2--3--4-|'); - var e1subs = '^ !'; - var expected = '----------(w|)'; - - var predicate = function (x, y) { - return x > y ? x : y; - }; - - expectObservable(e1.max(predicate)).toBe(expected, { w: '4' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on observable that throws', function () { - var e1 = hot('-1-^---#'); - var e1subs = '^ !'; - var expected = '----#'; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.max(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate that throws, on observable with many values', function () { - var e1 = hot('-1-^-2--3--|'); - var e1subs = '^ ! '; - var expected = '-----# '; - - var predicate = function (x, y) { - if (y === '3') { - throw 'error'; - } - return x > y ? x : y; - }; - - expectObservable(e1.max(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/max-spec.ts b/spec/operators/max-spec.ts new file mode 100644 index 0000000000..8a974cc494 --- /dev/null +++ b/spec/operators/max-spec.ts @@ -0,0 +1,250 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('max', () => { + asDiagram('max')('should find the max of values of an observable', () => { + const e1 = hot('--a--b--c--|', { a: 42, b: -1, c: 3 }); + const subs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable((e1).max()).toBe(expected, { x: 42 }); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should be never when source is never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).max()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be zero when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).max()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be never when source doesn\'t complete', () => { + const e1 = hot('--x--^--y--'); + const e1subs = '^ '; + const expected = '------'; + + expectObservable((e1).max()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be completes when source doesn\'t have values', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----|'; + + expectObservable((e1).max()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should max the unique value of an observable', () => { + const e1 = hot('-x-^--y--|', { y: 42 }); + const e1subs = '^ !'; + const expected = '------(w|)'; + + expectObservable((e1).max()).toBe(expected, { w: 42 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should max the values of an ongoing hot observable', () => { + const e1 = hot('--a-^-b--c--d--|', { a: 42, b: -1, c: 0, d: 666 }); + const subs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable((e1).max()).toBe(expected, { x: 666 }); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c--|', { a: 42, b: -1, c: 0 }); + const unsub = ' ! '; + const subs = '^ ! '; + const expected = '------- '; + + expectObservable((e1).max(), unsub).toBe(expected, { x: 42 }); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--a--b--c--|', { a: 42, b: -1, c: 0 }); + const subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const result = (source) + .mergeMap((x: string) => Observable.of(x)) + .max() + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, { x: 42 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should max a range() source observable', (done: DoneSignature) => { + (Rx.Observable.range(1, 10000)).max().subscribe( + (value: number) => { + expect(value).toEqual(10000); + }, + done.fail, + done + ); + }); + + it('should max a range().skip(1) source observable', (done: DoneSignature) => { + (Rx.Observable.range(1, 10)).skip(1).max().subscribe( + (value: number) => { + expect(value).toEqual(10); + }, + done.fail, + done + ); + }); + + it('should max a range().take(1) source observable', (done: DoneSignature) => { + (Rx.Observable.range(1, 10)).take(1).max().subscribe( + (value: number) => { + expect(value).toEqual(1); + }, + done.fail, + done + ); + }); + + it('should work with error', () => { + const e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); + const e1subs = '^ !'; + const expected = '---------#'; + + expectObservable((e1).max()).toBe(expected, null, 'too bad'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).max()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on an empty hot observable', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----|'; + + const predicate = function (x, y) { + return 42; + }; + + expectObservable((e1).max(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on an never hot observable', () => { + const e1 = hot('-x-^----'); + const e1subs = '^ '; + const expected = '-----'; + + const predicate = function (x, y) { + return 42; + }; + + expectObservable((e1).max(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on a simple hot observable', () => { + const e1 = hot('-x-^-a-|', { a: 1 }); + const e1subs = '^ !'; + const expected = '----(w|)'; + + const predicate = function () { + return 42; + }; + + expectObservable((e1).max(predicate)).toBe(expected, { w: 1 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on observable with many values', () => { + const e1 = hot('-x-^-a-b-c-d-e-f-g-|'); + const e1subs = '^ !'; + const expected = '----------------(w|)'; + + const predicate = () => { + return 42; + }; + + expectObservable((e1).max(predicate)).toBe(expected, { w: 42 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate on observable with many values', () => { + const e1 = hot('-a-^-b--c--d-|', { a: 42, b: -1, c: 0, d: 666 }); + const e1subs = '^ !'; + const expected = '----------(w|)'; + + const predicate = function (x, y) { + return Math.min(x, y); + }; + + expectObservable((e1).max(predicate)).toBe(expected, { w: -1 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate for string on observable with many values', () => { + const e1 = hot('-1-^-2--3--4-|'); + const e1subs = '^ !'; + const expected = '----------(w|)'; + + const predicate = function (x, y) { + return x > y ? x : y; + }; + + expectObservable((e1).max(predicate)).toBe(expected, { w: '4' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on observable that throws', () => { + const e1 = hot('-1-^---#'); + const e1subs = '^ !'; + const expected = '----#'; + + const predicate = () => { + return 42; + }; + + expectObservable((e1).max(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate that throws, on observable with many values', () => { + const e1 = hot('-1-^-2--3--|'); + const e1subs = '^ ! '; + const expected = '-----# '; + + const predicate = function (x, y) { + if (y === '3') { + throw 'error'; + } + return x > y ? x : y; + }; + + expectObservable((e1).max(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/merge-spec.js b/spec/operators/merge-spec.js deleted file mode 100644 index 8ad6b5b482..0000000000 --- a/spec/operators/merge-spec.js +++ /dev/null @@ -1,287 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.merge', function () { - it.asDiagram('merge')('should handle merging two hot observables', function () { - var e1 = hot('--a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('-----d-----e-----f---|'); - var e2subs = '^ !'; - var expected = '--a--d--b--e--c--f---|'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge a source with a second', function (done) { - var a = Observable.of(1, 2, 3); - var b = Observable.of(4, 5, 6, 7, 8); - var r = [1, 2, 3, 4, 5, 6, 7, 8]; - var i = 0; - a.merge(b).subscribe(function (val) { - expect(val).toBe(r[i++]); - }, null, done); - }); - - it('should merge an immediately-scheduled source with an immediately-scheduled second', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [1, 2, 4, 3, 5, 6, 7, 8]; - var i = 0; - a.merge(b, queueScheduler).subscribe(function (val) { - expect(val).toBe(r[i++]); - }, null, done); - }); - - it('should merge cold and cold', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a--x--b--y--c--z----|'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and hot', function () { - var e1 = hot('---a---^-b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('-----x-^----y-----z----|'); - var e2subs = '^ !'; - var expected = '--b--y--c--z----|'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and cold', function () { - var e1 = hot('---a-^---b-----c----|'); - var e1subs = '^ !'; - var e2 = cold( '--x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '--x-b---y-c---z----|'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge parallel emissions', function () { - var e1 = hot('---a----b----c----|'); - var e1subs = '^ !'; - var e2 = hot('---x----y----z----|'); - var e2subs = '^ !'; - var expected = '---(ax)-(by)-(cz)-|'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a-----b-----c----| '); - var e1subs = '^ ! '; - var e2 = hot('-----d-----e-----f---|'); - var e2subs = '^ ! '; - var expected = '--a--d--b-- '; - var unsub = ' ! '; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a-----b-----c----| '); - var e1subs = '^ ! '; - var e2 = hot('-----d-----e-----f---|'); - var e2subs = '^ ! '; - var expected = '--a--d--b-- '; - var unsub = ' ! '; - - var result = e1 - .map(function (x) { return x; }) - .merge(e2, rxTestScheduler) - .map(function (x) { return x; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge empty and empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe('|'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge three empties', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('|'); - var e2subs = '(^!)'; - var e3 = cold('|'); - var e3subs = '(^!)'; - - var result = e1.merge(e2, e3, rxTestScheduler); - - expectObservable(result).toBe('|'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should merge never and empty', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('|'); - var e2subs = '(^!)'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe('-'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge never and never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var e2 = cold('-'); - var e2subs = '^'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe('-'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge empty and throw', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('#'); - var e2subs = '(^!)'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe('#'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and throw', function () { - var e1 = hot( '--a--b--c--|'); - var e1subs = '(^!)'; - var e2 = cold('#'); - var e2subs = '(^!)'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe('#'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge never and throw', function () { - var e1 = cold('-'); - var e1subs = '(^!)'; - var e2 = cold('#'); - var e2subs = '(^!)'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe('#'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge empty and eventual error', function () { - var e1 = cold( '|'); - var e1subs = '(^!) '; - var e2 = hot('-------#'); - var e2subs = '^ !'; - var expected = '-------#'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge hot and error', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ ! '; - var e2 = hot('-------# '); - var e2subs = '^ ! '; - var expected = '--a--b-# '; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should merge never and error', function () { - var e1 = hot( '-'); - var e1subs = '^ !'; - var e2 = hot('-------#'); - var e2subs = '^ !'; - var expected = '-------#'; - - var result = e1.merge(e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); - -describe('Observable.prototype.mergeAll', function () { - it('should merge two observables', function (done) { - var a = Observable.of(1, 2, 3); - var b = Observable.of(4, 5, 6, 7, 8); - var r = [1, 2, 3, 4, 5, 6, 7, 8]; - var i = 0; - Observable.of(a, b).mergeAll().subscribe(function (val) { - expect(val).toBe(r[i++]); - }, null, done); - }); - - it('should merge two immediately-scheduled observables', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [1, 2, 4, 3, 5, 6, 7, 8]; - var i = 0; - Observable.of(a, b, queueScheduler).mergeAll().subscribe(function (val) { - expect(val).toBe(r[i++]); - }, null, done); - }); -}); \ No newline at end of file diff --git a/spec/operators/merge-spec.ts b/spec/operators/merge-spec.ts new file mode 100644 index 0000000000..92ccae5c7d --- /dev/null +++ b/spec/operators/merge-spec.ts @@ -0,0 +1,290 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.merge', () => { + asDiagram('merge')('should handle merging two hot observables', () => { + const e1 = hot('--a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('-----d-----e-----f---|'); + const e2subs = '^ !'; + const expected = '--a--d--b--e--c--f---|'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge a source with a second', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3); + const b = Observable.of(4, 5, 6, 7, 8); + const r = [1, 2, 3, 4, 5, 6, 7, 8]; + + a.merge(b).subscribe((val: number) => { + expect(val).toBe(r.shift()); + }, done.fail, done); + }); + + it('should merge an immediately-scheduled source with an immediately-scheduled second', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [1, 2, 4, 3, 5, 6, 7, 8]; + + a.merge(b, queueScheduler).subscribe((val: number) => { + expect(val).toBe(r.shift()); + }, done.fail, done); + }); + + it('should merge cold and cold', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a--x--b--y--c--z----|'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and hot', () => { + const e1 = hot('---a---^-b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('-----x-^----y-----z----|'); + const e2subs = '^ !'; + const expected = '--b--y--c--z----|'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and cold', () => { + const e1 = hot('---a-^---b-----c----|'); + const e1subs = '^ !'; + const e2 = cold( '--x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '--x-b---y-c---z----|'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge parallel emissions', () => { + const e1 = hot('---a----b----c----|'); + const e1subs = '^ !'; + const e2 = hot('---x----y----z----|'); + const e2subs = '^ !'; + const expected = '---(ax)-(by)-(cz)-|'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a-----b-----c----| '); + const e1subs = '^ ! '; + const e2 = hot('-----d-----e-----f---|'); + const e2subs = '^ ! '; + const expected = '--a--d--b-- '; + const unsub = ' ! '; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a-----b-----c----| '); + const e1subs = '^ ! '; + const e2 = hot('-----d-----e-----f---|'); + const e2subs = '^ ! '; + const expected = '--a--d--b-- '; + const unsub = ' ! '; + + const result = e1 + .map((x: string) => x) + .merge(e2, rxTestScheduler) + .map((x: string) => x); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge empty and empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe('|'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge three empties', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('|'); + const e2subs = '(^!)'; + const e3 = cold('|'); + const e3subs = '(^!)'; + + const result = e1.merge(e2, e3, rxTestScheduler); + + expectObservable(result).toBe('|'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should merge never and empty', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('|'); + const e2subs = '(^!)'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe('-'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge never and never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const e2 = cold('-'); + const e2subs = '^'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe('-'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge empty and throw', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('#'); + const e2subs = '(^!)'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe('#'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and throw', () => { + const e1 = hot( '--a--b--c--|'); + const e1subs = '(^!)'; + const e2 = cold('#'); + const e2subs = '(^!)'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe('#'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge never and throw', () => { + const e1 = cold('-'); + const e1subs = '(^!)'; + const e2 = cold('#'); + const e2subs = '(^!)'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe('#'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge empty and eventual error', () => { + const e1 = cold( '|'); + const e1subs = '(^!) '; + const e2 = hot('-------#'); + const e2subs = '^ !'; + const expected = '-------#'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge hot and error', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ ! '; + const e2 = hot('-------# '); + const e2subs = '^ ! '; + const expected = '--a--b-# '; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should merge never and error', () => { + const e1 = hot( '-'); + const e1subs = '^ !'; + const e2 = hot('-------#'); + const e2subs = '^ !'; + const expected = '-------#'; + + const result = e1.merge(e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); + +describe('Observable.prototype.mergeAll', () => { + it('should merge two observables', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3); + const b = Observable.of(4, 5, 6, 7, 8); + const r = [1, 2, 3, 4, 5, 6, 7, 8]; + + Observable.of(a, b).mergeAll().subscribe((val: number) => { + expect(val).toBe(r.shift()); + }, null, done); + }); + + it('should merge two immediately-scheduled observables', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [1, 2, 4, 3, 5, 6, 7, 8]; + + Observable.of>(a, b, queueScheduler).mergeAll().subscribe((val: number) => { + expect(val).toBe(r.shift()); + }, null, done); + }); +}); \ No newline at end of file diff --git a/spec/operators/mergeAll-spec.js b/spec/operators/mergeAll-spec.js deleted file mode 100644 index 2355b520d4..0000000000 --- a/spec/operators/mergeAll-spec.js +++ /dev/null @@ -1,410 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.mergeAll()', function () { - it.asDiagram('mergeAll')('should merge a hot observable of cold observables', function () { - var x = cold( '--a---b--c---d--| '); - var y = cold( '----e---f--g---|'); - var e1 = hot( '--x------y-------| ', { x: x, y: y }); - var expected = '----a---b--c-e-d-f--g---|'; - - expectObservable(e1.mergeAll()).toBe(expected); - }); - - it('should merge all observables in an observable', function () { - var e1 = Observable.fromArray([ - Observable.of('a'), - Observable.of('b'), - Observable.of('c') - ]); - var expected = '(abc|)'; - - expectObservable(e1.mergeAll()).toBe(expected); - }); - - it('should throw if any child observable throws', function () { - var e1 = Observable.fromArray([ - Observable.of('a'), - Observable.throw('error'), - Observable.of('c') - ]); - var expected = '(a#)'; - - expectObservable(e1.mergeAll()).toBe(expected); - }); - - it('should handle merging a hot observable of observables', function () { - var x = cold( 'a---b---c---| '); - var xsubs = ' ^ ! '; - var y = cold( 'd---e---f---|'); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '--a--db--ec--f---|'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge one cold Observable at a time with parameter concurrency=1', function () { - var x = cold( 'a---b---c---| '); - var xsubs = ' ^ ! '; - var y = cold( 'd---e---f---|'); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '--a---b---c---d---e---f---|'; - - expectObservable(e1.mergeAll(1)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge two cold Observables at a time with parameter concurrency=2', function () { - var x = cold( 'a---b---c---| '); - var xsubs = ' ^ ! '; - var y = cold( 'd---e---f---| '); - var ysubs = ' ^ ! '; - var z = cold( '--g---h-|'); - var zsubs = ' ^ !'; - var e1 = hot('--x--y--z--| ', { x: x, y: y, z: z }); - var e1subs = '^ !'; - var expected = '--a--db--ec--f--g---h-|'; - - expectObservable(e1.mergeAll(2)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge one hot Observable at a time with parameter concurrency=1', function () { - var x = hot('---a---b---c---| '); - var xsubs = ' ^ ! '; - var y = hot('-------------d---e---f---|'); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '---a---b---c-----e---f---|'; - - expectObservable(e1.mergeAll(1)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge two hot Observables at a time with parameter concurrency=2', function () { - var x = hot('i--a---b---c---| '); - var xsubs = ' ^ ! '; - var y = hot('-i-i--d---e---f---| '); - var ysubs = ' ^ ! '; - var z = hot('--i--i--i--i-----g---h-|'); - var zsubs = ' ^ !'; - var e1 = hot('--x--y--z--| ', { x: x, y: y, z: z }); - var e1subs = '^ !'; - var expected = '---a--db--ec--f--g---h-|'; - - expectObservable(e1.mergeAll(2)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle merging a hot observable of observables, outer unsubscribed early', function () { - var x = cold( 'a---b---c---| '); - var xsubs = ' ^ ! '; - var y = cold( 'd---e---f---|'); - var ysubs = ' ^ ! '; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ ! '; - var unsub = ' ! '; - var expected = '--a--db--ec-- '; - - expectObservable(e1.mergeAll(), unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var x = cold( 'a---b---c---| '); - var xsubs = ' ^ ! '; - var y = cold( 'd---e---f---|'); - var ysubs = ' ^ ! '; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ ! '; - var expected = '--a--db--ec-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (i) { return Observable.of(i); }) - .mergeAll() - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge parallel emissions', function () { - var x = cold( '----a----b----c---|'); - var xsubs = ' ^ !'; - var y = cold( '-d----e----f---|'); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '------(ad)-(be)-(cf)|'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge empty and empty', function () { - var x = cold( '|'); - var xsubs = ' (^!) '; - var y = cold( '|'); - var ysubs = ' (^!)'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '--------|'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge three empties', function () { - var x = cold( '|'); - var xsubs = ' (^!) '; - var y = cold( '|'); - var ysubs = ' (^!) '; - var z = cold( '|'); - var zsubs = ' (^!)'; - var e1 = hot('--x--y-z---|', { x: x, y: y, z: z }); - var e1subs = '^ !'; - var expected = '-----------|'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge never and empty', function () { - var x = cold( '-'); - var xsubs = ' ^'; - var y = cold( '|'); - var ysubs = ' (^!)'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ '; - var expected = '---------'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge never and never', function () { - var x = cold( '-'); - var xsubs = ' ^'; - var y = cold( '-'); - var ysubs = ' ^'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ '; - var expected = '---------'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge empty and throw', function () { - var x = cold( '|'); - var xsubs = ' (^!) '; - var y = cold( '#'); - var ysubs = ' (^!)'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ ! '; - var expected = '-----# '; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge never and throw', function () { - var x = cold( '-'); - var xsubs = ' ^ !'; - var y = cold( '#'); - var ysubs = ' (^!)'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ ! '; - var expected = '-----# '; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge empty and eventual error', function () { - var x = cold( '|'); - var xsubs = ' (^!)'; - var y = cold( '------#'); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '-----------#'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge never and eventual error', function () { - var x = cold( '-'); - var xsubs = ' ^ !'; - var y = cold( '------#'); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--|', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '-----------#'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take an empty source and return empty too', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take a never source and return never too', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take a throw source and return throw too', function () { - var e1 = cold( '#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle merging a hot observable of non-overlapped observables', function () { - var x = cold( 'a-b---------| '); - var xsubs = ' ^ ! '; - var y = cold( 'c-d-e-f-| '); - var ysubs = ' ^ ! '; - var z = cold( 'g-h-i-j-k-|'); - var zsubs = ' ^ !'; - var e1 = hot('--x---------y--------z--------| ', { x: x, y: y, z: z }); - var e1subs = '^ !'; - var expected = '--a-b-------c-d-e-f--g-h-i-j-k-|'; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if inner observable raises error', function () { - var x = cold( 'a-b---------| '); - var xsubs = ' ^ ! '; - var y = cold( 'c-d-e-f-# '); - var ysubs = ' ^ ! '; - var z = cold( 'g-h-i-j-k-|'); - var zsubs = []; - var e1 = hot('--x---------y--------z--------| ', { x: x, y: y, z: z }); - var e1subs = '^ ! '; - var expected = '--a-b-------c-d-e-f-# '; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if outer observable raises error', function () { - var y = cold( 'a-b---------| '); - var ysubs = ' ^ ! '; - var z = cold( 'c-d-e-f-| '); - var zsubs = ' ^ ! '; - var e1 = hot('--y---------z---# ', { y: y, z: z }); - var e1subs = '^ ! '; - var expected = '--a-b-------c-d-# '; - - expectObservable(e1.mergeAll()).toBe(expected); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should merge all promises in an observable', function (done) { - var e1 = Rx.Observable.fromArray([ - new Promise(function (res) { res('a'); }), - new Promise(function (res) { res('b'); }), - new Promise(function (res) { res('c'); }), - new Promise(function (res) { res('d'); }), - ]); - var expected = ['a', 'b', 'c', 'd']; - - var res = []; - e1.mergeAll().subscribe( - function (x) { res.push(x); }, - function (err) { throw 'should not be called'; }, - function () { - expect(res).toEqual(expected); - done(); - }); - }); - - it('should raise error when promise rejects', function (done) { - var error = 'error'; - var e1 = Rx.Observable.fromArray([ - new Promise(function (res) { res('a'); }), - new Promise(function (res, rej) { rej(error); }), - new Promise(function (res) { res('c'); }), - new Promise(function (res) { res('d'); }), - ]); - - var res = []; - e1.mergeAll().subscribe( - function (x) { res.push(x); }, - function (err) { - expect(res.length).toEqual(1); - expect(err).toBe(error); - done(); - }, - function () { throw 'should not be called'; }); - }); -}); \ No newline at end of file diff --git a/spec/operators/mergeAll-spec.ts b/spec/operators/mergeAll-spec.ts new file mode 100644 index 0000000000..cb8a87efde --- /dev/null +++ b/spec/operators/mergeAll-spec.ts @@ -0,0 +1,411 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.mergeAll()', () => { + asDiagram('mergeAll')('should merge a hot observable of cold observables', () => { + const x = cold( '--a---b--c---d--| '); + const y = cold( '----e---f--g---|'); + const e1 = hot( '--x------y-------| ', { x: x, y: y }); + const expected = '----a---b--c-e-d-f--g---|'; + + expectObservable(e1.mergeAll()).toBe(expected); + }); + + it('should merge all observables in an observable', () => { + const e1 = Observable.fromArray([ + Observable.of('a'), + Observable.of('b'), + Observable.of('c') + ]); + const expected = '(abc|)'; + + expectObservable(e1.mergeAll()).toBe(expected); + }); + + it('should throw if any child observable throws', () => { + const e1 = Observable.fromArray([ + Observable.of('a'), + Observable.throw('error'), + Observable.of('c') + ]); + const expected = '(a#)'; + + expectObservable(e1.mergeAll()).toBe(expected); + }); + + it('should handle merging a hot observable of observables', () => { + const x = cold( 'a---b---c---| '); + const xsubs = ' ^ ! '; + const y = cold( 'd---e---f---|'); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '--a--db--ec--f---|'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge one cold Observable at a time with parameter concurrency=1', () => { + const x = cold( 'a---b---c---| '); + const xsubs = ' ^ ! '; + const y = cold( 'd---e---f---|'); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '--a---b---c---d---e---f---|'; + + expectObservable((e1).mergeAll(1)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge two cold Observables at a time with parameter concurrency=2', () => { + const x = cold( 'a---b---c---| '); + const xsubs = ' ^ ! '; + const y = cold( 'd---e---f---| '); + const ysubs = ' ^ ! '; + const z = cold( '--g---h-|'); + const zsubs = ' ^ !'; + const e1 = hot('--x--y--z--| ', { x: x, y: y, z: z }); + const e1subs = '^ !'; + const expected = '--a--db--ec--f--g---h-|'; + + expectObservable((e1).mergeAll(2)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge one hot Observable at a time with parameter concurrency=1', () => { + const x = hot('---a---b---c---| '); + const xsubs = ' ^ ! '; + const y = hot('-------------d---e---f---|'); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '---a---b---c-----e---f---|'; + + expectObservable((e1).mergeAll(1)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge two hot Observables at a time with parameter concurrency=2', () => { + const x = hot('i--a---b---c---| '); + const xsubs = ' ^ ! '; + const y = hot('-i-i--d---e---f---| '); + const ysubs = ' ^ ! '; + const z = hot('--i--i--i--i-----g---h-|'); + const zsubs = ' ^ !'; + const e1 = hot('--x--y--z--| ', { x: x, y: y, z: z }); + const e1subs = '^ !'; + const expected = '---a--db--ec--f--g---h-|'; + + expectObservable((e1).mergeAll(2)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle merging a hot observable of observables, outer unsubscribed early', () => { + const x = cold( 'a---b---c---| '); + const xsubs = ' ^ ! '; + const y = cold( 'd---e---f---|'); + const ysubs = ' ^ ! '; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ ! '; + const unsub = ' ! '; + const expected = '--a--db--ec-- '; + + expectObservable(e1.mergeAll(), unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const x = cold( 'a---b---c---| '); + const xsubs = ' ^ ! '; + const y = cold( 'd---e---f---|'); + const ysubs = ' ^ ! '; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ ! '; + const expected = '--a--db--ec-- '; + const unsub = ' ! '; + + const result = (e1) + .mergeMap((x: string) => Observable.of(x)) + .mergeAll() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge parallel emissions', () => { + const x = cold( '----a----b----c---|'); + const xsubs = ' ^ !'; + const y = cold( '-d----e----f---|'); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '------(ad)-(be)-(cf)|'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge empty and empty', () => { + const x = cold( '|'); + const xsubs = ' (^!) '; + const y = cold( '|'); + const ysubs = ' (^!)'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '--------|'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge three empties', () => { + const x = cold( '|'); + const xsubs = ' (^!) '; + const y = cold( '|'); + const ysubs = ' (^!) '; + const z = cold( '|'); + const zsubs = ' (^!)'; + const e1 = hot('--x--y-z---|', { x: x, y: y, z: z }); + const e1subs = '^ !'; + const expected = '-----------|'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge never and empty', () => { + const x = cold( '-'); + const xsubs = ' ^'; + const y = cold( '|'); + const ysubs = ' (^!)'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ '; + const expected = '---------'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge never and never', () => { + const x = cold( '-'); + const xsubs = ' ^'; + const y = cold( '-'); + const ysubs = ' ^'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ '; + const expected = '---------'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge empty and throw', () => { + const x = cold( '|'); + const xsubs = ' (^!) '; + const y = cold( '#'); + const ysubs = ' (^!)'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ ! '; + const expected = '-----# '; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge never and throw', () => { + const x = cold( '-'); + const xsubs = ' ^ !'; + const y = cold( '#'); + const ysubs = ' (^!)'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ ! '; + const expected = '-----# '; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge empty and eventual error', () => { + const x = cold( '|'); + const xsubs = ' (^!)'; + const y = cold( '------#'); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '-----------#'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge never and eventual error', () => { + const x = cold( '-'); + const xsubs = ' ^ !'; + const y = cold( '------#'); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--|', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '-----------#'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take an empty source and return empty too', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take a never source and return never too', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take a throw source and return throw too', () => { + const e1 = cold( '#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle merging a hot observable of non-overlapped observables', () => { + const x = cold( 'a-b---------| '); + const xsubs = ' ^ ! '; + const y = cold( 'c-d-e-f-| '); + const ysubs = ' ^ ! '; + const z = cold( 'g-h-i-j-k-|'); + const zsubs = ' ^ !'; + const e1 = hot('--x---------y--------z--------| ', { x: x, y: y, z: z }); + const e1subs = '^ !'; + const expected = '--a-b-------c-d-e-f--g-h-i-j-k-|'; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if inner observable raises error', () => { + const x = cold( 'a-b---------| '); + const xsubs = ' ^ ! '; + const y = cold( 'c-d-e-f-# '); + const ysubs = ' ^ ! '; + const z = cold( 'g-h-i-j-k-|'); + const zsubs = []; + const e1 = hot('--x---------y--------z--------| ', { x: x, y: y, z: z }); + const e1subs = '^ ! '; + const expected = '--a-b-------c-d-e-f-# '; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if outer observable raises error', () => { + const y = cold( 'a-b---------| '); + const ysubs = ' ^ ! '; + const z = cold( 'c-d-e-f-| '); + const zsubs = ' ^ ! '; + const e1 = hot('--y---------z---# ', { y: y, z: z }); + const e1subs = '^ ! '; + const expected = '--a-b-------c-d-# '; + + expectObservable(e1.mergeAll()).toBe(expected); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should merge all promises in an observable', (done: DoneSignature) => { + const e1 = Rx.Observable.fromArray([ + new Promise((res: any) => { res('a'); }), + new Promise((res: any) => { res('b'); }), + new Promise((res: any) => { res('c'); }), + new Promise((res: any) => { res('d'); }), + ]); + const expected = ['a', 'b', 'c', 'd']; + + const res = []; + (e1.mergeAll()).subscribe( + (x: any) => { res.push(x); }, + (err: any) => { done.fail('should not be called'); }, + () => { + expect(res).toEqual(expected); + done(); + }); + }); + + it('should raise error when promise rejects', (done: DoneSignature) => { + const error = 'error'; + const e1 = Rx.Observable.fromArray([ + new Promise((res: any) => { res('a'); }), + new Promise((res: any, rej: any) => { rej(error); }), + new Promise((res: any) => { res('c'); }), + new Promise((res: any) => { res('d'); }), + ]); + + const res = []; + (e1.mergeAll()).subscribe( + (x: any) => { res.push(x); }, + (err: any) => { + expect(res.length).toEqual(1); + expect(err).toBe(error); + done(); + }, + () => { done.fail('should not be called'); }); + }); +}); \ No newline at end of file diff --git a/spec/operators/mergeMap-spec.js b/spec/operators/mergeMap-spec.js deleted file mode 100644 index 125438c13b..0000000000 --- a/spec/operators/mergeMap-spec.js +++ /dev/null @@ -1,700 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.mergeMap()', function () { - it('should mergeMap many regular interval inners', function () { - var a = cold('----a---a---a---(a|) '); - var b = cold( '----b---b---(b|) '); - var c = cold( '----c---c---c---c---(c|)'); - var d = cold( '----(d|) '); - var e1 = hot('a---b-----------c-------d-------| '); - var e1subs = '^ ! '; - var expected = '----a---(ab)(ab)(ab)c---c---(cd)c---(c|)'; - - var observableLookup = { a: a, b: b, c: c, d: d }; - var source = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should map values to constant resolved promises and merge', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value) { - return Observable.from(Promise.resolve(42)); - }; - - var results = []; - source.mergeMap(project).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([42,42,42,42]); - done(); - }); - }); - - it('should map values to constant rejected promises and merge', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value) { - return Observable.from(Promise.reject(42)); - }; - - source.mergeMap(project).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual(42); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should map values to resolved promises and merge', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value, index) { - return Observable.from(Promise.resolve(value + index)); - }; - - var results = []; - source.mergeMap(project).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([4,4,4,4]); - done(); - }); - }); - - it('should map values to rejected promises and merge', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value, index) { - return Observable.from(Promise.reject('' + value + '-' + index)); - }; - - source.mergeMap(project).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual('4-0'); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should mergeMap values to resolved promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var resultSelectorCalledWith = []; - var project = function (value, index) { - return Observable.from(Promise.resolve([value, index])); - }; - var resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { - resultSelectorCalledWith.push([].slice.call(arguments)); - return 8; - }; - - var results = []; - var expectedCalls = [ - [4, [4,0], 0, 0], - [3, [3,1], 1, 0], - [2, [2,2], 2, 0], - [1, [1,3], 3, 0], - ]; - source.mergeMap(project, resultSelector).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([8,8,8,8]); - expect(resultSelectorCalledWith).toDeepEqual(expectedCalls); - done(); - }); - }); - - it('should mergeMap values to rejected promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var project = function (value, index) { - return Observable.from(Promise.reject('' + value + '-' + index)); - }; - var resultSelector = function () { - throw 'this should not be called'; - }; - - source.mergeMap(project, resultSelector).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual('4-0'); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should mergeMap many outer values to many inner values', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------| '); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l---|'; - - var result = e1.mergeMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to many inner, complete late', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-----------------------|'); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-------|'; - - var result = e1.mergeMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to many inner, outer never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------e---------------f------'); - var unsub = ' !'; - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i--'; - - var source = e1.mergeMap(function (value) { return inner; }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------e---------------f------'); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i--'; - var unsub = ' !'; - - var source = e1 - .map(function (x) { return x; }) - .mergeMap(function (value) { return inner; }) - .map(function (x) { return x; }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to many inner, inner never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------| '); - var e1subs = '^ '; - var inner = cold('----i---j---k---l-------------------------', values); - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-'; - - var result = e1.mergeMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to many inner, and inner throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------|'); - var e1subs = '^ ! '; - var inner = cold('----i---j---k---l-------# ', values); - var expected = '-----i---j---(ki)(lj)(ki)# '; - - var result = e1.mergeMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to many inner, and outer throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------#'); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)#'; - - var result = e1.mergeMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to many inner, both inner and outer throw', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------#'); - var e1subs = '^ ! '; - var inner = cold('----i---j---k---l---# ', values); - var expected = '-----i---j---(ki)(lj)# '; - - var result = e1.mergeMap(function (value) { return inner; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap to many cold Observable, with parameter concurrency=1', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c---| '); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|'; - - function project() { return inner; } - function resultSelector(oV, iV, oI, iI) { return iV; } - var result = e1.mergeMap(project, resultSelector, 1); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap to many cold Observable, with parameter concurrency=2', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c---| '); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|'; - - function project() { return inner; } - function resultSelector(oV, iV, oI, iI) { return iV; } - var result = e1.mergeMap(project, resultSelector, 2); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap to many hot Observable, with parameter concurrency=1', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c---| '); - var e1subs = '^ !'; - var hotA = hot('x----i---j---k---l---| ', values); - var hotB = hot('-x-x-xxxx-x-x-xxxxx-x----i---j---k---l---| ', values); - var hotC = hot('x-xxxx---x-x-x-x-x-xx--x--x-x--x--xxxx-x-----i---j---k---l---|', values); - var asubs = ' ^ ! '; - var bsubs = ' ^ ! '; - var csubs = ' ^ !'; - var expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|'; - var inners = { a: hotA, b: hotB, c: hotC }; - - function project(x) { return inners[x]; } - function resultSelector(oV, iV, oI, iI) { return iV; } - var result = e1.mergeMap(project, resultSelector, 1); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(hotA.subscriptions).toBe(asubs); - expectSubscriptions(hotB.subscriptions).toBe(bsubs); - expectSubscriptions(hotC.subscriptions).toBe(csubs); - }); - - it('should mergeMap to many hot Observable, with parameter concurrency=2', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c---| '); - var e1subs = '^ !'; - var hotA = hot('x----i---j---k---l---| ', values); - var hotB = hot('-x-x-xxxx----i---j---k---l---| ', values); - var hotC = hot('x-xxxx---x-x-x-x-x-xx----i---j---k---l---|', values); - var asubs = ' ^ ! '; - var bsubs = ' ^ ! '; - var csubs = ' ^ !'; - var expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|'; - var inners = { a: hotA, b: hotB, c: hotC }; - - function project(x) { return inners[x]; } - function resultSelector(oV, iV, oI, iI) { return iV; } - var result = e1.mergeMap(project, resultSelector, 2); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(hotA.subscriptions).toBe(asubs); - expectSubscriptions(hotB.subscriptions).toBe(bsubs); - expectSubscriptions(hotC.subscriptions).toBe(csubs); - }); - - it('should mergeMap many complex, where all inners are finite', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-|' ); - var d = cold( '-----------2--3|' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); - var e1subs = '^ !'; - var expected = '---2--3--4--5---1--2--3--2--3--6--4--5---1-2--|'; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many complex, all inners finite except one', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-|' ); - var d = cold( '-----------2--3-' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); - var e1subs = '^ '; - var expected = '---2--3--4--5---1--2--3--2--3--6--4--5---1-2----'; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many complex, inners finite, outer does not complete', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-|' ); - var d = cold( '-----------2--3|' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g--------'); - var e1subs = '^ '; - var expected = '---2--3--4--5---1--2--3--2--3--6--4--5---1-2----'; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many complex, all inners finite, and outer throws', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-|' ); - var d = cold( '-----------2--3|' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g# '); - var e1subs = '^ ! '; - var expected = '---2--3--4--5---1--2--3--2--3--6--4--5-# '; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many complex, all inners complete except one throws', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-#' ); - var d = cold( '-----------2--3|' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); - var e1subs = '^ ! '; - var expected = '---2--3--4--5---1--2--3--2--3--6-# '; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - - var result = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many complex, all inners finite, outer is unsubscribed', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-|' ); - var d = cold( '-----------2--3|' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---2--3--4--5---1--2--3--2--3-- '; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - var source = e1.mergeMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(source, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many complex, all inners finite, project throws', function () { - var a = cold( '-#' ); - var b = cold( '-#' ); - var c = cold( '-2--3--4--5------------------6-|' ); - var d = cold( '-----------2--3|' ); - var e = cold( '-1--------2--3-----4--5--------|'); - var f = cold( '--|' ); - var g = cold( '---1-2|' ); - var e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); - var e1subs = '^ ! '; - var expected = '---2--3--4--5--# '; - - var observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; - var invoked = 0; - var source = e1.mergeMap(function (value) { - invoked++; - if (invoked === 3) { - throw 'error'; - } - return observableLookup[value]; - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - function arrayRepeat(value, times) { - var results = []; - for (var i = 0; i < times; i++) { - results.push(value); - } - return results; - } - - it('should mergeMap many outer to an array for each value', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(22)--(4444)---(333)----(22)----|'; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, using resultSelector', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(44)--(8888)---(666)----(44)----|'; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }, function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, and outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var e1subs = '^ !'; - var expected = '(22)--(4444)---(333)----(22)----#'; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, resultSelector, outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var e1subs = '^ !'; - var expected = '(44)--(8888)---(666)----(44)----#'; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }, function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, outer gets unsubscribed', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '(22)--(4444)-- '; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }); - - expectObservable(source, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, resultSelector, outer unsubscribed', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '(44)--(8888)-- '; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }, function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(source, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, project throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var expected = '(22)--(4444)---# '; - - var invoked = 0; - var source = e1.mergeMap(function (value) { - invoked++; - if (invoked === 3) { - throw 'error'; - } - return arrayRepeat(value, value); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, resultSelector throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var expected = '(44)--(8888)---# '; - - var source = e1.mergeMap(function (value) { - return arrayRepeat(value, value); - }, function (inner, outer) { - if (outer === '3') { - throw 'error'; - } - return String(parseInt(outer) + parseInt(inner)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap many outer to inner arrays, resultSelector, project throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ ! '; - var expected = '(44)--(8888)---# '; - - var invoked = 0; - var source = e1.mergeMap(function (value) { - invoked++; - if (invoked === 3) { - throw 'error'; - } - return arrayRepeat(value, value); - }, function (inner, outer) { - return String(parseInt(outer) + parseInt(inner)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should map and flatten', function () { - var source = Observable.of(1, 2, 3, 4).mergeMap(function (x) { - return Observable.of(x + '!'); - }); - - var expected = ['1!', '2!', '3!', '4!']; - var completed = false; - - var sub = source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - completed = true; - }); - - expect(completed).toBe(true); - }); - - it('should map and flatten an Array', function () { - var source = Observable.of(1, 2, 3, 4).mergeMap(function (x) { - return [x + '!']; - }); - - var expected = ['1!', '2!', '3!', '4!']; - var completed = false; - - var sub = source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - completed = true; - }); - - expect(completed).toBe(true); - }); -}); diff --git a/spec/operators/mergeMap-spec.ts b/spec/operators/mergeMap-spec.ts new file mode 100644 index 0000000000..2a2efa899c --- /dev/null +++ b/spec/operators/mergeMap-spec.ts @@ -0,0 +1,665 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.mergeMap()', () => { + it('should mergeMap many regular interval inners', () => { + const a = cold('----a---a---a---(a|) '); + const b = cold( '----b---b---(b|) '); + const c = cold( '----c---c---c---c---(c|)'); + const d = cold( '----(d|) '); + const e1 = hot('a---b-----------c-------d-------| '); + const e1subs = '^ ! '; + const expected = '----a---(ab)(ab)(ab)c---c---(cd)c---(c|)'; + + const observableLookup = { a: a, b: b, c: c, d: d }; + const source = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should map values to constant resolved promises and merge', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = (value: any) => Observable.from(Promise.resolve(42)); + + const results = []; + source.mergeMap(project).subscribe( + (x: number) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([42,42,42,42]); + done(); + }); + }); + + it('should map values to constant rejected promises and merge', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = function (value) { + return Observable.from(Promise.reject(42)); + }; + + source.mergeMap(project).subscribe( + (x: number) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual(42); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should map values to resolved promises and merge', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = function (value, index) { + return Observable.from(Promise.resolve(value + index)); + }; + + const results = []; + source.mergeMap(project).subscribe( + (x: number) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([4,4,4,4]); + done(); + }); + }); + + it('should map values to rejected promises and merge', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = function (value, index) { + return Observable.from(Promise.reject('' + value + '-' + index)); + }; + + source.mergeMap(project).subscribe( + (x: number) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual('4-0'); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should mergeMap values to resolved promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const resultSelectorCalledWith = []; + const project = function (value, index) { + return Observable.from(Promise.resolve([value, index])); + }; + const resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { + resultSelectorCalledWith.push([].slice.call(arguments)); + return 8; + }; + + const results = []; + const expectedCalls = [ + [4, [4,0], 0, 0], + [3, [3,1], 1, 0], + [2, [2,2], 2, 0], + [1, [1,3], 3, 0], + ]; + source.mergeMap(project, resultSelector).subscribe( + (x: number) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([8,8,8,8]); + (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); + done(); + }); + }); + + it('should mergeMap values to rejected promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const project = function (value, index) { + return Observable.from(Promise.reject('' + value + '-' + index)); + }; + const resultSelector = () => { + throw 'this should not be called'; + }; + + source.mergeMap(project, resultSelector).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual('4-0'); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should mergeMap many outer values to many inner values', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------| '); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l---|'; + + const result = e1.mergeMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to many inner, complete late', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-----------------------|'); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-------|'; + + const result = e1.mergeMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to many inner, outer never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------e---------------f------'); + const unsub = ' !'; + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i--'; + + const source = e1.mergeMap((value: any) => inner); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------e---------------f------'); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i--'; + const unsub = ' !'; + + const source = e1 + .map(function (x) { return x; }) + .mergeMap((value: any) => inner) + .map(function (x) { return x; }); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to many inner, inner never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------| '); + const e1subs = '^ '; + const inner = cold('----i---j---k---l-------------------------', values); + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-'; + + const result = e1.mergeMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to many inner, and inner throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------|'); + const e1subs = '^ ! '; + const inner = cold('----i---j---k---l-------# ', values); + const expected = '-----i---j---(ki)(lj)(ki)# '; + + const result = e1.mergeMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to many inner, and outer throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------#'); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)#'; + + const result = e1.mergeMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to many inner, both inner and outer throw', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------#'); + const e1subs = '^ ! '; + const inner = cold('----i---j---k---l---# ', values); + const expected = '-----i---j---(ki)(lj)# '; + + const result = e1.mergeMap((value: any) => inner); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap to many cold Observable, with parameter concurrency=1', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c---| '); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|'; + + function project() { return inner; } + function resultSelector(oV, iV, oI, iI) { return iV; } + const result = e1.mergeMap(project, resultSelector, 1); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap to many cold Observable, with parameter concurrency=2', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c---| '); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|'; + + function project() { return inner; } + function resultSelector(oV, iV, oI, iI) { return iV; } + const result = e1.mergeMap(project, resultSelector, 2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap to many hot Observable, with parameter concurrency=1', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c---| '); + const e1subs = '^ !'; + const hotA = hot('x----i---j---k---l---| ', values); + const hotB = hot('-x-x-xxxx-x-x-xxxxx-x----i---j---k---l---| ', values); + const hotC = hot('x-xxxx---x-x-x-x-x-xx--x--x-x--x--xxxx-x-----i---j---k---l---|', values); + const asubs = ' ^ ! '; + const bsubs = ' ^ ! '; + const csubs = ' ^ !'; + const expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|'; + const inners = { a: hotA, b: hotB, c: hotC }; + + function project(x) { return inners[x]; } + function resultSelector(oV, iV, oI, iI) { return iV; } + const result = e1.mergeMap(project, resultSelector, 1); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(hotA.subscriptions).toBe(asubs); + expectSubscriptions(hotB.subscriptions).toBe(bsubs); + expectSubscriptions(hotC.subscriptions).toBe(csubs); + }); + + it('should mergeMap to many hot Observable, with parameter concurrency=2', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c---| '); + const e1subs = '^ !'; + const hotA = hot('x----i---j---k---l---| ', values); + const hotB = hot('-x-x-xxxx----i---j---k---l---| ', values); + const hotC = hot('x-xxxx---x-x-x-x-x-xx----i---j---k---l---|', values); + const asubs = ' ^ ! '; + const bsubs = ' ^ ! '; + const csubs = ' ^ !'; + const expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|'; + const inners = { a: hotA, b: hotB, c: hotC }; + + function project(x) { return inners[x]; } + function resultSelector(oV, iV, oI, iI) { return iV; } + const result = e1.mergeMap(project, resultSelector, 2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(hotA.subscriptions).toBe(asubs); + expectSubscriptions(hotB.subscriptions).toBe(bsubs); + expectSubscriptions(hotC.subscriptions).toBe(csubs); + }); + + it('should mergeMap many complex, where all inners are finite', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-|' ); + const d = cold( '-----------2--3|' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); + const e1subs = '^ !'; + const expected = '---2--3--4--5---1--2--3--2--3--6--4--5---1-2--|'; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many complex, all inners finite except one', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-|' ); + const d = cold( '-----------2--3-' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); + const e1subs = '^ '; + const expected = '---2--3--4--5---1--2--3--2--3--6--4--5---1-2----'; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many complex, inners finite, outer does not complete', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-|' ); + const d = cold( '-----------2--3|' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g--------'); + const e1subs = '^ '; + const expected = '---2--3--4--5---1--2--3--2--3--6--4--5---1-2----'; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many complex, all inners finite, and outer throws', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-|' ); + const d = cold( '-----------2--3|' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g# '); + const e1subs = '^ ! '; + const expected = '---2--3--4--5---1--2--3--2--3--6--4--5-# '; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many complex, all inners complete except one throws', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-#' ); + const d = cold( '-----------2--3|' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); + const e1subs = '^ ! '; + const expected = '---2--3--4--5---1--2--3--2--3--6-# '; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + + const result = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many complex, all inners finite, outer is unsubscribed', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-|' ); + const d = cold( '-----------2--3|' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---2--3--4--5---1--2--3--2--3-- '; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + const source = e1.mergeMap((value: any) => observableLookup[value]); + + expectObservable(source, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many complex, all inners finite, project throws', () => { + const a = cold( '-#' ); + const b = cold( '-#' ); + const c = cold( '-2--3--4--5------------------6-|' ); + const d = cold( '-----------2--3|' ); + const e = cold( '-1--------2--3-----4--5--------|'); + const f = cold( '--|' ); + const g = cold( '---1-2|' ); + const e1 = hot('-a-b--^-c-----d------e----------------f-----g|' ); + const e1subs = '^ ! '; + const expected = '---2--3--4--5--# '; + + const observableLookup = { a: a, b: b, c: c, d: d, e: e, f: f, g: g }; + let invoked = 0; + const source = e1.mergeMap((value: any) => { + invoked++; + if (invoked === 3) { + throw 'error'; + } + return observableLookup[value]; + }); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + function arrayRepeat(value, times): any { + const results = []; + for (let i = 0; i < times; i++) { + results.push(value); + } + return results; + } + + it('should mergeMap many outer to an array for each value', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(22)--(4444)---(333)----(22)----|'; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value)); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, using resultSelector', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(44)--(8888)---(666)----(44)----|'; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value), + (x: string, y: string) =>String(parseInt(x) + parseInt(y))); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, and outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const e1subs = '^ !'; + const expected = '(22)--(4444)---(333)----(22)----#'; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value)); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, resultSelector, outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const e1subs = '^ !'; + const expected = '(44)--(8888)---(666)----(44)----#'; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value), + (x: string, y: string) =>String(parseInt(x) + parseInt(y))); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, outer gets unsubscribed', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '(22)--(4444)-- '; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value)); + + expectObservable(source, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, resultSelector, outer unsubscribed', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '(44)--(8888)-- '; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value), + (x: string, y: string) =>String(parseInt(x) + parseInt(y))); + + expectObservable(source, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, project throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const expected = '(22)--(4444)---# '; + + let invoked = 0; + const source = e1.mergeMap((value: any) => { + invoked++; + if (invoked === 3) { + throw 'error'; + } + return arrayRepeat(value, value); + }); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, resultSelector throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const expected = '(44)--(8888)---# '; + + const source = e1.mergeMap((value: any) => arrayRepeat(value, value), + (inner: string, outer: string) => { + if (outer === '3') { + throw 'error'; + } + return String(parseInt(outer) + parseInt(inner)); + }); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap many outer to inner arrays, resultSelector, project throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ ! '; + const expected = '(44)--(8888)---# '; + + let invoked = 0; + const source = e1.mergeMap((value: any) => { + invoked++; + if (invoked === 3) { + throw 'error'; + } + return arrayRepeat(value, value); + }, (inner: string, outer: string) => { + return String(parseInt(outer) + parseInt(inner)); + }); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should map and flatten', () => { + const source = Observable.of(1, 2, 3, 4).mergeMap((x: number) => Observable.of(x + '!')); + + const expected = ['1!', '2!', '3!', '4!']; + let completed = false; + + const sub = source.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + completed = true; + }); + + expect(completed).toBe(true); + }); + + it('should map and flatten an Array', () => { + const source = Observable.of(1, 2, 3, 4).mergeMap((x: number): any => [x + '!']); + + const expected = ['1!', '2!', '3!', '4!']; + let completed = false; + + const sub = source.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + completed = true; + }); + + expect(completed).toBe(true); + }); +}); diff --git a/spec/operators/mergeMapTo-spec.js b/spec/operators/mergeMapTo-spec.js deleted file mode 100644 index a1b625db0b..0000000000 --- a/spec/operators/mergeMapTo-spec.js +++ /dev/null @@ -1,406 +0,0 @@ -/* globals expectObservable, expectSubscriptions, cold, hot, describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.mergeMapTo()', function () { - it('should mergeMapTo many regular interval inners', function () { - var x = cold('----1---2---3---(4|) '); - var xsubs = ['^ ! ', - // ----1---2---3---(4|) - ' ^ ! ', - // ----1---2---3---(4|) - ' ^ ! ', - // ----1---2---3---(4|) - ' ^ ! ']; - var e1 = hot('a---b-----------c-------d-------| '); - var e1subs = '^ !'; - var expected = '----1---(21)(32)(43)(41)2---(31)(42)3---(4|)'; - - var source = e1.mergeMapTo(x); - - expectObservable(source).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should map values to constant resolved promises and merge', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - - var results = []; - source.mergeMapTo(Observable.from(Promise.resolve(42))).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([42,42,42,42]); - done(); - }); - }); - - it('should map values to constant rejected promises and merge', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - - source.mergeMapTo(Observable.from(Promise.reject(42))).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual(42); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should mergeMapTo values to resolved promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var resultSelectorCalledWith = []; - var inner = Observable.from(Promise.resolve(42)); - var resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { - resultSelectorCalledWith.push([].slice.call(arguments)); - return 8; - }; - - var results = []; - var expectedCalls = [ - [4, 42, 0, 0], - [3, 42, 1, 0], - [2, 42, 2, 0], - [1, 42, 3, 0], - ]; - source.mergeMapTo(inner, resultSelector).subscribe( - function next(x) { - results.push(x); - }, - function error(err) { - done.fail('Subscriber error handler not supposed to be called.'); - }, - function complete() { - expect(results).toEqual([8,8,8,8]); - expect(resultSelectorCalledWith).toDeepEqual(expectedCalls); - done(); - }); - }); - - it('should mergeMapTo values to rejected promises with resultSelector', function (done) { - var source = Rx.Observable.from([4,3,2,1]); - var inner = Observable.from(Promise.reject(42)); - var resultSelector = function () { - throw 'this should not be called'; - }; - - source.mergeMapTo(inner, resultSelector).subscribe( - function next(x) { - done.fail('Subscriber next handler not supposed to be called.'); - }, - function error(err) { - expect(err).toEqual(42); - done(); - }, - function complete() { - done.fail('Subscriber complete handler not supposed to be called.'); - }); - }); - - it('should mergeMapTo many outer values to many inner values', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------| '); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l---|'; - - expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to many inner, complete late', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-----------------------|'); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---|', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-------|'; - - expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to many inner, outer never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------e---------------f------'); - var e1subs = '^ !'; - var inner = cold( '----i---j---k---l---|', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var unsub = ' !'; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i-'; - - var source = e1.mergeMapTo(inner); - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------e---------------f------'); - var e1subs = '^ !'; - var inner = cold( '----i---j---k---l---|', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var unsub = ' !'; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i-'; - - var source = e1 - .map(function (x) { return x; }) - .mergeMapTo(inner) - .map(function (x) { return x; }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to many inner, inner never completes', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------| '); - var e1subs = '^ '; - var inner = cold('----i---j---k---l-', values); - var innersubs = [' ^ ', - ' ^ ', - ' ^ ', - ' ^ ']; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-'; - - expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to many inner, and inner throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------|'); - var e1subs = '^ ! '; - var inner = cold('----i---j---k---l-------# ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' (^!) ']; - var expected = '-----i---j---(ki)(lj)(ki)#'; - - expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to many inner, and outer throws', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------#'); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ !', - ' ^ !']; - var expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)#'; - - expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to many inner, both inner and outer throw', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c-------d-------#'); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---#', values); - var innersubs = [' ^ !', - ' ^ !', - ' ^ !']; - var expected = '-----i---j---(ki)(lj)#'; - - expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many cold Observable, with parameter concurrency=1', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c---| '); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|'; - - function resultSelector(oV, iV, oI, iI) { return iV; } - var result = e1.mergeMapTo(inner, resultSelector, 1); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMap to many cold Observable, with parameter concurrency=2', function () { - var values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; - var e1 = hot('-a-------b-------c---| '); - var e1subs = '^ !'; - var inner = cold('----i---j---k---l---| ', values); - var innersubs = [' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|'; - - function resultSelector(oV, iV, oI, iI) { return iV; } - var result = e1.mergeMapTo(inner, resultSelector, 2); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(inner.subscriptions).toBe(innersubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to arrays', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(0123)(0123)---(0123)---(0123)--|'; - - var source = e1.mergeMapTo(['0', '1', '2', '3']); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to inner arrays, using resultSelector', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(2345)(4567)---(3456)---(2345)--|'; - - var source = e1.mergeMapTo(['0', '1', '2', '3'], function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to inner arrays, and outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var e1subs = '^ !'; - var expected = '(0123)(0123)---(0123)---(0123)--#'; - - var source = e1.mergeMapTo(['0', '1', '2', '3']); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to inner arrays, resultSelector, outer throws', function () { - var e1 = hot('2-----4--------3--------2-------#'); - var e1subs = '^ !'; - var expected = '(2345)(4567)---(3456)---(2345)--#'; - - var source = e1.mergeMapTo(['0', '1', '2', '3'], function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to inner arrays, outer gets unsubscribed', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var unsub = ' !'; - var expected = '(0123)(0123)--'; - - var source = e1.mergeMapTo(['0', '1', '2', '3']); - - expectObservable(source, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to inner arrays, resultSelector, outer unsubscribed', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var unsub = ' !'; - var expected = '(2345)(4567)--'; - - var source = e1.mergeMapTo(['0', '1', '2', '3'], function (x, y) { - return String(parseInt(x) + parseInt(y)); - }); - - expectObservable(source, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeMapTo many outer to inner arrays, resultSelector throws', function () { - var e1 = hot('2-----4--------3--------2-------|'); - var e1subs = '^ !'; - var expected = '(2345)(4567)---#'; - - var source = e1.mergeMapTo(['0', '1', '2', '3'], function (outer, inner) { - if (outer === '3') { - throw 'error'; - } - return String(parseInt(outer) + parseInt(inner)); - }); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should map and flatten', function () { - var source = Observable.of(1, 2, 3, 4).mergeMapTo(Observable.of('!')); - - var expected = ['!', '!', '!', '!']; - var completed = false; - - var sub = source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - completed = true; - }); - - expect(completed).toBe(true); - }); - - it('should map and flatten an Array', function () { - var source = Observable.of(1, 2, 3, 4).mergeMapTo(['!']); - - var expected = ['!', '!', '!', '!']; - var completed = false; - - var sub = source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - completed = true; - }); - - expect(completed).toBe(true); - }); -}); diff --git a/spec/operators/mergeMapTo-spec.ts b/spec/operators/mergeMapTo-spec.ts new file mode 100644 index 0000000000..28eadd9c6b --- /dev/null +++ b/spec/operators/mergeMapTo-spec.ts @@ -0,0 +1,404 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.mergeMapTo()', () => { + it('should mergeMapTo many regular interval inners', () => { + const x = cold('----1---2---3---(4|) '); + const xsubs = ['^ ! ', + // ----1---2---3---(4|) + ' ^ ! ', + // ----1---2---3---(4|) + ' ^ ! ', + // ----1---2---3---(4|) + ' ^ ! ']; + const e1 = hot('a---b-----------c-------d-------| '); + const e1subs = '^ !'; + const expected = '----1---(21)(32)(43)(41)2---(31)(42)3---(4|)'; + + const source = e1.mergeMapTo(x); + + expectObservable(source).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should map values to constant resolved promises and merge', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + + const results = []; + source.mergeMapTo(Observable.from(Promise.resolve(42))).subscribe( + (x: any) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([42,42,42,42]); + done(); + }); + }); + + it('should map values to constant rejected promises and merge', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + + source.mergeMapTo(Observable.from(Promise.reject(42))).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual(42); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should mergeMapTo values to resolved promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const resultSelectorCalledWith = []; + const inner = Observable.from(Promise.resolve(42)); + const resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { + resultSelectorCalledWith.push([].slice.call(arguments)); + return 8; + }; + + const results = []; + const expectedCalls = [ + [4, 42, 0, 0], + [3, 42, 1, 0], + [2, 42, 2, 0], + [1, 42, 3, 0], + ]; + source.mergeMapTo(inner, resultSelector).subscribe( + (x: any) => { + results.push(x); + }, + (err: any) => { + done.fail('Subscriber error handler not supposed to be called.'); + }, + () => { + expect(results).toEqual([8,8,8,8]); + (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); + done(); + }); + }); + + it('should mergeMapTo values to rejected promises with resultSelector', (done: DoneSignature) => { + const source = Rx.Observable.from([4,3,2,1]); + const inner = Observable.from(Promise.reject(42)); + const resultSelector = () => { + throw 'this should not be called'; + }; + + source.mergeMapTo(inner, resultSelector).subscribe( + (x: any) => { + done.fail('Subscriber next handler not supposed to be called.'); + }, + (err: any) => { + expect(err).toEqual(42); + done(); + }, + () => { + done.fail('Subscriber complete handler not supposed to be called.'); + }); + }); + + it('should mergeMapTo many outer values to many inner values', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------| '); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l---|'; + + expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to many inner, complete late', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-----------------------|'); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---|', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-------|'; + + expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to many inner, outer never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------e---------------f------'); + const e1subs = '^ !'; + const inner = cold( '----i---j---k---l---|', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const unsub = ' !'; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i-'; + + const source = e1.mergeMapTo(inner); + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------e---------------f------'); + const e1subs = '^ !'; + const inner = cold( '----i---j---k---l---|', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const unsub = ' !'; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)(ki)(lj)k---l---i-'; + + const source = e1 + .map(function (x) { return x; }) + .mergeMapTo(inner) + .map(function (x) { return x; }); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to many inner, inner never completes', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------| '); + const e1subs = '^ '; + const inner = cold('----i---j---k---l-', values); + const innersubs = [' ^ ', + ' ^ ', + ' ^ ', + ' ^ ']; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)(lj)k---l-'; + + expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to many inner, and inner throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------|'); + const e1subs = '^ ! '; + const inner = cold('----i---j---k---l-------# ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' (^!) ']; + const expected = '-----i---j---(ki)(lj)(ki)#'; + + expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to many inner, and outer throws', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------#'); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ !', + ' ^ !']; + const expected = '-----i---j---(ki)(lj)(ki)(lj)(ki)#'; + + expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to many inner, both inner and outer throw', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c-------d-------#'); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---#', values); + const innersubs = [' ^ !', + ' ^ !', + ' ^ !']; + const expected = '-----i---j---(ki)(lj)#'; + + expectObservable(e1.mergeMapTo(inner)).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many cold Observable, with parameter concurrency=1', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c---| '); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-----i---j---k---l-------i---j---k---l-------i---j---k---l---|'; + + function resultSelector(oV, iV, oI, iI) { return iV; } + const result = e1.mergeMapTo(inner, resultSelector, 1); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMap to many cold Observable, with parameter concurrency=2', () => { + const values = {i: 'foo', j: 'bar', k: 'baz', l: 'qux'}; + const e1 = hot('-a-------b-------c---| '); + const e1subs = '^ !'; + const inner = cold('----i---j---k---l---| ', values); + const innersubs = [' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-----i---j---(ki)(lj)k---(li)j---k---l---|'; + + function resultSelector(oV, iV, oI, iI) { return iV; } + const result = e1.mergeMapTo(inner, resultSelector, 2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(inner.subscriptions).toBe(innersubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to arrays', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(0123)(0123)---(0123)---(0123)--|'; + + const source = e1.mergeMapTo(['0', '1', '2', '3']); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to inner arrays, using resultSelector', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(2345)(4567)---(3456)---(2345)--|'; + + const source = e1.mergeMapTo(['0', '1', '2', '3'], + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to inner arrays, and outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const e1subs = '^ !'; + const expected = '(0123)(0123)---(0123)---(0123)--#'; + + const source = e1.mergeMapTo(['0', '1', '2', '3']); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to inner arrays, resultSelector, outer throws', () => { + const e1 = hot('2-----4--------3--------2-------#'); + const e1subs = '^ !'; + const expected = '(2345)(4567)---(3456)---(2345)--#'; + + const source = e1.mergeMapTo(['0', '1', '2', '3'], + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to inner arrays, outer gets unsubscribed', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const unsub = ' !'; + const expected = '(0123)(0123)--'; + + const source = e1.mergeMapTo(['0', '1', '2', '3']); + + expectObservable(source, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to inner arrays, resultSelector, outer unsubscribed', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const unsub = ' !'; + const expected = '(2345)(4567)--'; + + const source = e1.mergeMapTo(['0', '1', '2', '3'], + (x: string, y: string) => String(parseInt(x) + parseInt(y))); + + expectObservable(source, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeMapTo many outer to inner arrays, resultSelector throws', () => { + const e1 = hot('2-----4--------3--------2-------|'); + const e1subs = '^ !'; + const expected = '(2345)(4567)---#'; + + const source = e1.mergeMapTo(['0', '1', '2', '3'], (outer: string, inner: string) => { + if (outer === '3') { + throw 'error'; + } + return String(parseInt(outer) + parseInt(inner)); + }); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should map and flatten', () => { + const source = Observable.of(1, 2, 3, 4).mergeMapTo(Observable.of('!')); + + const expected = ['!', '!', '!', '!']; + let completed = false; + + const sub = source.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + completed = true; + }); + + expect(completed).toBe(true); + }); + + it('should map and flatten an Array', () => { + const source = Observable.of(1, 2, 3, 4).mergeMapTo(['!']); + + const expected = ['!', '!', '!', '!']; + let completed = false; + + const sub = source.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + completed = true; + }); + + expect(completed).toBe(true); + }); +}); diff --git a/spec/operators/mergeScan-spec.js b/spec/operators/mergeScan-spec.js deleted file mode 100644 index 2b9af949cc..0000000000 --- a/spec/operators/mergeScan-spec.js +++ /dev/null @@ -1,400 +0,0 @@ -/* globals describe, it, expect, rxTestScheduler, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.mergeScan()', function () { - it('should mergeScan things', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '---u--v--w--x--y--z--|'; - - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1.mergeScan(function (acc, x) { return Observable.of(acc.concat(x)); }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle errors', function () { - var e1 = hot('--a--^--b--c--d--#'); - var e1subs = '^ !'; - var expected = '---u--v--w--#'; - - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'] - }; - - var source = e1.mergeScan(function (acc, x) { return Observable.of(acc.concat(x)); }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeScan values and be able to asynchronously project them', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '-----u--v--w--x--y--z|'; - - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1.mergeScan(function (acc, x) { - return Observable.of(acc.concat(x)).delay(20, rxTestScheduler); - }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not stop ongoing async projections when source completes', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '--------u--v--w--x--y--(z|)'; - - var values = { - u: ['b'], - v: ['c'], - w: ['b', 'd'], - x: ['c', 'e'], - y: ['b', 'd', 'f'], - z: ['c', 'e', 'g'], - }; - - var source = e1.mergeScan(function (acc, x) { - return Observable.of(acc.concat(x)).delay(50, rxTestScheduler); - }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should interrupt ongoing async projections when result is unsubscribed early', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var expected = '--------u--v--w-- '; - - var values = { - u: ['b'], - v: ['c'], - w: ['b', 'd'], - x: ['c', 'e'], - y: ['b', 'd', 'f'], - z: ['c', 'e', 'g'], - }; - - var source = e1.mergeScan(function (acc, x) { - return Observable.of(acc.concat(x)).delay(50, rxTestScheduler); - }, []); - - expectObservable(source, e1subs).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var expected = '--------u--v--w-- '; - var unsub = ' ! '; - - var values = { - u: ['b'], - v: ['c'], - w: ['b', 'd'], - x: ['c', 'e'], - y: ['b', 'd', 'f'], - z: ['c', 'e', 'g'], - }; - - var source = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .mergeScan(function (acc, x) { - return Observable.of(acc.concat(x)).delay(50, rxTestScheduler); - }, []) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle errors in the projection function', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '---u--v--#'; - - var values = { - u: ['b'], - v: ['b', 'c'] - }; - - var source = e1.mergeScan(function (acc, x) { - if (x === 'd') { - throw 'bad!'; - } - return Observable.of(acc.concat(x)); - }, []); - - expectObservable(source).toBe(expected, values, 'bad!'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should propagate errors from the projected Observable', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '---#'; - - var source = e1.mergeScan(function (acc, x) { - return Observable.throw('bad!'); - }, []); - - expectObservable(source).toBe(expected, undefined, 'bad!'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an empty projected Observable', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '---------------------(x|)'; - - var values = { x: [] }; - - var source = e1.mergeScan(function (acc, x) { - return Observable.empty(); - }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a never projected Observable', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ '; - var expected = '----------------------'; - - var values = { x: [] }; - - var source = e1.mergeScan(function (acc, x) { - return Observable.never(); - }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(u|)'; - - var values = { - u: [] - }; - - var source = e1.mergeScan(function (acc, x) { return Observable.of(acc.concat(x)); }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var source = e1.mergeScan(function (acc, x) { return Observable.of(acc.concat(x)); }, []); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - var source = e1.mergeScan(function (acc, x) { return Observable.of(acc.concat(x)); }, []); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergeScan unsubscription', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var expected = '---u--v--w--x--'; - var sub = '^ !'; - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1.mergeScan(function (acc, x) { return Observable.of(acc.concat(x)); }, []); - - expectObservable(source, sub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should mergescan projects cold Observable with single concurrency', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - - var inner = [ - cold( '--d--e--f--| '), - cold( '--g--h--i--| '), - cold( '--j--k--l--|') - ]; - - var xsubs = ' ^ !'; - var ysubs = ' ^ !'; - var zsubs = ' ^ !'; - - var expected = '--x-d--e--f--f-g--h--i--i-j--k--l--|'; - - var index = 0; - var source = e1.mergeScan(function (acc, x) { - var value = inner[index++]; - return value.startWith(acc); - }, 'x', 1); - - expectObservable(source).toBe(expected); - - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner[0].subscriptions).toBe(xsubs); - expectSubscriptions(inner[1].subscriptions).toBe(ysubs); - expectSubscriptions(inner[2].subscriptions).toBe(zsubs); - }); - - it('should emit accumulator if inner completes without value', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '---------------------(x|)'; - - var source = e1.mergeScan(function (acc, x) { - return Observable.empty(); - }, ['1']); - - expectObservable(source).toBe(expected, {x: ['1']}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should emit accumulator if inner completes without value after source completes', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '-----------------------(x|)'; - - var source = e1.mergeScan(function (acc, x) { - return Observable.empty().delay(50, rxTestScheduler); - }, ['1']); - - expectObservable(source).toBe(expected, {x: ['1']}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should mergescan projects hot Observable with single concurrency', function () { - var e1 = hot('---a---b---c---|'); - var e1subs = '^ !'; - - var inner = [ - hot( '--d--e--f--|'), - hot( '----g----h----i----|'), - hot( '------j------k-------l------|') - ]; - - var xsubs = ' ^ !'; - var ysubs = ' ^ !'; - var zsubs = ' ^ !'; - - var expected = '---x-e--f--f--i----i-l------|'; - - var index = 0; - var source = e1.mergeScan(function (acc, x) { - var value = inner[index++]; - return value.startWith(acc); - }, 'x', 1); - - expectObservable(source).toBe(expected); - - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner[0].subscriptions).toBe(xsubs); - expectSubscriptions(inner[1].subscriptions).toBe(ysubs); - expectSubscriptions(inner[2].subscriptions).toBe(zsubs); - }); - - it('should mergescan projects cold Observable with dual concurrency', function () { - var e1 = hot('----a----b----c----|'); - var e1subs = '^ !'; - - var inner = [ - cold( '---d---e---f---| '), - cold( '---g---h---i---| '), - cold( '---j---k---l---|') - ]; - - var xsubs = ' ^ !'; - var ysubs = ' ^ !'; - var zsubs = ' ^ !'; - - var expected = '----x--d-d-eg--fh--hi-j---k---l---|'; - - var index = 0; - var source = e1.mergeScan(function (acc, x) { - var value = inner[index++]; - return value.startWith(acc); - }, 'x', 2); - - expectObservable(source).toBe(expected); - - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner[0].subscriptions).toBe(xsubs); - expectSubscriptions(inner[1].subscriptions).toBe(ysubs); - expectSubscriptions(inner[2].subscriptions).toBe(zsubs); - }); - - it('should mergescan projects hot Observable with dual concurrency', function () { - var e1 = hot('---a---b---c---|'); - var e1subs = '^ !'; - - var inner = [ - hot( '--d--e--f--|'), - hot( '----g----h----i----|'), - hot( '------j------k-------l------|') - ]; - - var xsubs = ' ^ !'; - var ysubs = ' ^ !'; - var zsubs = ' ^ !'; - - var expected = '---x-e-efh-h-ki------l------|'; - - var index = 0; - var source = e1.mergeScan(function (acc, x) { - var value = inner[index++]; - return value.startWith(acc); - }, 'x', 2); - - expectObservable(source).toBe(expected); - - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(inner[0].subscriptions).toBe(xsubs); - expectSubscriptions(inner[1].subscriptions).toBe(ysubs); - expectSubscriptions(inner[2].subscriptions).toBe(zsubs); - }); -}); diff --git a/spec/operators/mergeScan-spec.ts b/spec/operators/mergeScan-spec.ts new file mode 100644 index 0000000000..5c5b028070 --- /dev/null +++ b/spec/operators/mergeScan-spec.ts @@ -0,0 +1,390 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.mergeScan()', () => { + it('should mergeScan things', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '---u--v--w--x--y--z--|'; + + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.of(acc.concat(x)), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle errors', () => { + const e1 = hot('--a--^--b--c--d--#'); + const e1subs = '^ !'; + const expected = '---u--v--w--#'; + + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'] + }; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.of(acc.concat(x)), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeScan values and be able to asynchronously project them', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '-----u--v--w--x--y--z|'; + + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = (e1).mergeScan((acc: any, x: string) => + Observable.of(acc.concat(x)).delay(20, rxTestScheduler), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not stop ongoing async projections when source completes', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '--------u--v--w--x--y--(z|)'; + + const values = { + u: ['b'], + v: ['c'], + w: ['b', 'd'], + x: ['c', 'e'], + y: ['b', 'd', 'f'], + z: ['c', 'e', 'g'], + }; + + const source = (e1).mergeScan((acc: any, x: string) => + Observable.of(acc.concat(x)).delay(50, rxTestScheduler), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should interrupt ongoing async projections when result is unsubscribed early', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const expected = '--------u--v--w-- '; + + const values = { + u: ['b'], + v: ['c'], + w: ['b', 'd'], + x: ['c', 'e'], + y: ['b', 'd', 'f'], + z: ['c', 'e', 'g'], + }; + + const source = (e1).mergeScan((acc: any, x: string) => + Observable.of(acc.concat(x)).delay(50, rxTestScheduler), []); + + expectObservable(source, e1subs).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const expected = '--------u--v--w-- '; + const unsub = ' ! '; + + const values = { + u: ['b'], + v: ['c'], + w: ['b', 'd'], + x: ['c', 'e'], + y: ['b', 'd', 'f'], + z: ['c', 'e', 'g'], + }; + + const source = (e1) + .mergeMap((x: string) => Observable.of(x)) + .mergeScan((acc: any, x: string) => + Observable.of(acc.concat(x)).delay(50, rxTestScheduler), []) + .mergeMap(function (x) { return Observable.of(x); }); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle errors in the projection function', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '---u--v--#'; + + const values = { + u: ['b'], + v: ['b', 'c'] + }; + + const source = (e1).mergeScan((acc: any, x: string) => { + if (x === 'd') { + throw 'bad!'; + } + return Observable.of(acc.concat(x)); + }, []); + + expectObservable(source).toBe(expected, values, 'bad!'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should propagate errors from the projected Observable', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '---#'; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.throw('bad!'), []); + + expectObservable(source).toBe(expected, undefined, 'bad!'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an empty projected Observable', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '---------------------(x|)'; + + const values = { x: [] }; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.empty(), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a never projected Observable', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ '; + const expected = '----------------------'; + + const values = { x: [] }; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.never(), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(u|)'; + + const values = { + u: [] + }; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.of(acc.concat(x)), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.of(acc.concat(x)), []); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.of(acc.concat(x)), []); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergeScan unsubscription', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const expected = '---u--v--w--x--'; + const sub = '^ !'; + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.of(acc.concat(x)), []); + + expectObservable(source, sub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should mergescan projects cold Observable with single concurrency', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + + const inner = [ + cold( '--d--e--f--| '), + cold( '--g--h--i--| '), + cold( '--j--k--l--|') + ]; + + const xsubs = ' ^ !'; + const ysubs = ' ^ !'; + const zsubs = ' ^ !'; + + const expected = '--x-d--e--f--f-g--h--i--i-j--k--l--|'; + + let index = 0; + const source = (e1).mergeScan((acc: any, x: string) => { + const value = inner[index++]; + return value.startWith(acc); + }, 'x', 1); + + expectObservable(source).toBe(expected); + + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner[0].subscriptions).toBe(xsubs); + expectSubscriptions(inner[1].subscriptions).toBe(ysubs); + expectSubscriptions(inner[2].subscriptions).toBe(zsubs); + }); + + it('should emit accumulator if inner completes without value', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '---------------------(x|)'; + + const source = (e1).mergeScan((acc: any, x: string) => Observable.empty(), ['1']); + + expectObservable(source).toBe(expected, {x: ['1']}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should emit accumulator if inner completes without value after source completes', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '-----------------------(x|)'; + + const source = (e1).mergeScan((acc: any, x: string) => + Observable.empty().delay(50, rxTestScheduler), ['1']); + + expectObservable(source).toBe(expected, {x: ['1']}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should mergescan projects hot Observable with single concurrency', () => { + const e1 = hot('---a---b---c---|'); + const e1subs = '^ !'; + + const inner = [ + hot( '--d--e--f--|'), + hot( '----g----h----i----|'), + hot( '------j------k-------l------|') + ]; + + const xsubs = ' ^ !'; + const ysubs = ' ^ !'; + const zsubs = ' ^ !'; + + const expected = '---x-e--f--f--i----i-l------|'; + + let index = 0; + const source = (e1).mergeScan((acc: any, x: string) => { + const value = inner[index++]; + return value.startWith(acc); + }, 'x', 1); + + expectObservable(source).toBe(expected); + + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner[0].subscriptions).toBe(xsubs); + expectSubscriptions(inner[1].subscriptions).toBe(ysubs); + expectSubscriptions(inner[2].subscriptions).toBe(zsubs); + }); + + it('should mergescan projects cold Observable with dual concurrency', () => { + const e1 = hot('----a----b----c----|'); + const e1subs = '^ !'; + + const inner = [ + cold( '---d---e---f---| '), + cold( '---g---h---i---| '), + cold( '---j---k---l---|') + ]; + + const xsubs = ' ^ !'; + const ysubs = ' ^ !'; + const zsubs = ' ^ !'; + + const expected = '----x--d-d-eg--fh--hi-j---k---l---|'; + + let index = 0; + const source = (e1).mergeScan((acc: any, x: string) => { + const value = inner[index++]; + return value.startWith(acc); + }, 'x', 2); + + expectObservable(source).toBe(expected); + + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner[0].subscriptions).toBe(xsubs); + expectSubscriptions(inner[1].subscriptions).toBe(ysubs); + expectSubscriptions(inner[2].subscriptions).toBe(zsubs); + }); + + it('should mergescan projects hot Observable with dual concurrency', () => { + const e1 = hot('---a---b---c---|'); + const e1subs = '^ !'; + + const inner = [ + hot( '--d--e--f--|'), + hot( '----g----h----i----|'), + hot( '------j------k-------l------|') + ]; + + const xsubs = ' ^ !'; + const ysubs = ' ^ !'; + const zsubs = ' ^ !'; + + const expected = '---x-e-efh-h-ki------l------|'; + + let index = 0; + const source = (e1).mergeScan((acc: any, x: string) => { + const value = inner[index++]; + return value.startWith(acc); + }, 'x', 2); + + expectObservable(source).toBe(expected); + + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(inner[0].subscriptions).toBe(xsubs); + expectSubscriptions(inner[1].subscriptions).toBe(ysubs); + expectSubscriptions(inner[2].subscriptions).toBe(zsubs); + }); +}); diff --git a/spec/operators/min-spec.js b/spec/operators/min-spec.js deleted file mode 100644 index e714c87d6a..0000000000 --- a/spec/operators/min-spec.js +++ /dev/null @@ -1,256 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('min', function () { - it.asDiagram('min')('should min the values of an observable', function () { - var source = hot('--a--b--c--|', { a: 42, b: -1, c: 3 }); - var subs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.min()).toBe(expected, { x: -1 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should be never when source is never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.min()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be zero when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.min()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be never when source doesn\'t complete', function () { - var e1 = hot('--x--^--y--'); - var e1subs = '^ '; - var expected = '------'; - - expectObservable(e1.min()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be completes when source doesn\'t have values', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----|'; - - expectObservable(e1.min()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should min the unique value of an observable', function () { - var e1 = hot('-x-^--y--|', { y: 42 }); - var e1subs = '^ !'; - var expected = '------(w|)'; - - expectObservable(e1.min()).toBe(expected, { w: 42 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should min the values of an ongoing hot observable', function () { - var source = hot('--a-^-b--c--d--|', { a: 42, b: -1, c: 0, d: 666 }); - var subs = '^ !'; - var expected = '-----------(x|)'; - - expectObservable(source.min()).toBe(expected, { x: -1 }); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should min a range() source observable', function (done) { - Rx.Observable.range(1, 10000).min().subscribe( - function (value) { - expect(value).toEqual(1); - }, - done.fail, - done - ); - }); - - it('should min a range().skip(1) source observable', function (done) { - Rx.Observable.range(1, 10).skip(1).min().subscribe( - function (value) { - expect(value).toEqual(2); - }, - done.fail, - done - ); - }); - - it('should min a range().take(1) source observable', function (done) { - Rx.Observable.range(1, 10).take(1).min().subscribe( - function (value) { - expect(value).toEqual(1); - }, - done.fail, - done - ); - }); - - it('should work with error', function () { - var e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); - var e1subs = '^ !'; - var expected = '---------#'; - - expectObservable(e1.min()).toBe(expected, null, 'too bad'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.min()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on an empty hot observable', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----|'; - - var predicate = function (x, y) { - return 42; - }; - - expectObservable(e1.min(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on an never hot observable', function () { - var e1 = hot('-x-^----'); - var e1subs = '^ '; - var expected = '-----'; - - var predicate = function (x, y) { - return 42; - }; - - expectObservable(e1.min(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on a simple hot observable', function () { - var e1 = hot('-x-^-a-|', { a: 1 }); - var e1subs = '^ !'; - var expected = '----(w|)'; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.min(predicate)).toBe(expected, { w: 1 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('-x-^-a-b-c-d-e-f-g-|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '-------- '; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.min(predicate), unsub).toBe(expected, { w: 42 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-x-^-a-b-c-d-e-f-g-|'); - var e1subs = '^ ! '; - var expected = '-------- '; - var unsub = ' ! '; - - var predicate = function () { - return 42; - }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .min(predicate) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, { w: 42 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on observable with many values', function () { - var e1 = hot('-x-^-a-b-c-d-e-f-g-|'); - var e1subs = '^ !'; - var expected = '----------------(w|)'; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.min(predicate)).toBe(expected, { w: 42 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate on observable with many values', function () { - var e1 = hot('-a-^-b--c--d-|', { a: 42, b: -1, c: 0, d: 666 }); - var e1subs = '^ !'; - var expected = '----------(w|)'; - - var predicate = function (x, y) { - return Math.max(x, y); - }; - - expectObservable(e1.min(predicate)).toBe(expected, { w: 666 }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate for string on observable with many values', function () { - var e1 = hot('-1-^-2--3--4-|'); - var e1subs = '^ !'; - var expected = '----------(w|)'; - - var predicate = function (x, y) { - return x < y ? x : y; - }; - - expectObservable(e1.min(predicate)).toBe(expected, { w: '2' }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a constant predicate on observable that throws', function () { - var e1 = hot('-1-^---#'); - var e1subs = '^ !'; - var expected = '----#'; - - var predicate = function () { - return 42; - }; - - expectObservable(e1.min(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a predicate that throws, on observable with many values', function () { - var e1 = hot('-1-^-2--3--|'); - var e1subs = '^ ! '; - var expected = '-----# '; - - var predicate = function (x, y) { - if (y === '3') { - throw 'error'; - } - return x > y ? x : y; - }; - - expectObservable(e1.min(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/min-spec.ts b/spec/operators/min-spec.ts new file mode 100644 index 0000000000..82d1340120 --- /dev/null +++ b/spec/operators/min-spec.ts @@ -0,0 +1,258 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('min', () => { + asDiagram('min')('should min the values of an observable', () => { + const source = hot('--a--b--c--|', { a: 42, b: -1, c: 3 }); + const subs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable((source).min()).toBe(expected, { x: -1 }); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should be never when source is never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).min()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be zero when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).min()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be never when source doesn\'t complete', () => { + const e1 = hot('--x--^--y--'); + const e1subs = '^ '; + const expected = '------'; + + expectObservable((e1).min()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be completes when source doesn\'t have values', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----|'; + + expectObservable((e1).min()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should min the unique value of an observable', () => { + const e1 = hot('-x-^--y--|', { y: 42 }); + const e1subs = '^ !'; + const expected = '------(w|)'; + + expectObservable((e1).min()).toBe(expected, { w: 42 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should min the values of an ongoing hot observable', () => { + const e1 = hot('--a-^-b--c--d--|', { a: 42, b: -1, c: 0, d: 666 }); + const subs = '^ !'; + const expected = '-----------(x|)'; + + expectObservable((e1).min()).toBe(expected, { x: -1 }); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should min a range() source observable', (done: DoneSignature) => { + (Rx.Observable.range(1, 10000)).min().subscribe( + (value: number) => { + expect(value).toEqual(1); + }, + done.fail, + done + ); + }); + + it('should min a range().skip(1) source observable', (done: DoneSignature) => { + (Rx.Observable.range(1, 10)).skip(1).min().subscribe( + (value: number) => { + expect(value).toEqual(2); + }, + done.fail, + done + ); + }); + + it('should min a range().take(1) source observable', (done: DoneSignature) => { + (Rx.Observable.range(1, 10)).take(1).min().subscribe( + (value: number) => { + expect(value).toEqual(1); + }, + done.fail, + done + ); + }); + + it('should work with error', () => { + const e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); + const e1subs = '^ !'; + const expected = '---------#'; + + expectObservable((e1).min()).toBe(expected, null, 'too bad'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).min()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on an empty hot observable', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----|'; + + const predicate = function (x, y) { + return 42; + }; + + expectObservable((e1).min(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on an never hot observable', () => { + const e1 = hot('-x-^----'); + const e1subs = '^ '; + const expected = '-----'; + + const predicate = function (x, y) { + return 42; + }; + + expectObservable((e1).min(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on a simple hot observable', () => { + const e1 = hot('-x-^-a-|', { a: 1 }); + const e1subs = '^ !'; + const expected = '----(w|)'; + + const predicate = () => { + return 42; + }; + + expectObservable((e1).min(predicate)).toBe(expected, { w: 1 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('-x-^-a-b-c-d-e-f-g-|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '-------- '; + + const predicate = () => { + return 42; + }; + + expectObservable((e1).min(predicate), unsub).toBe(expected, { w: 42 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-x-^-a-b-c-d-e-f-g-|'); + const e1subs = '^ ! '; + const expected = '-------- '; + const unsub = ' ! '; + + const predicate = function () { + return 42; + }; + + const result = (e1) + .mergeMap((x: string) => Observable.of(x)) + .min(predicate) + .mergeMap((x: number) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, { w: 42 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on observable with many values', () => { + const e1 = hot('-x-^-a-b-c-d-e-f-g-|'); + const e1subs = '^ !'; + const expected = '----------------(w|)'; + + const predicate = () => { + return 42; + }; + + expectObservable((e1).min(predicate)).toBe(expected, { w: 42 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate on observable with many values', () => { + const e1 = hot('-a-^-b--c--d-|', { a: 42, b: -1, c: 0, d: 666 }); + const e1subs = '^ !'; + const expected = '----------(w|)'; + + const predicate = function (x, y) { + return Math.max(x, y); + }; + + expectObservable((e1).min(predicate)).toBe(expected, { w: 666 }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate for string on observable with many values', () => { + const e1 = hot('-1-^-2--3--4-|'); + const e1subs = '^ !'; + const expected = '----------(w|)'; + + const predicate = function (x, y) { + return x < y ? x : y; + }; + + expectObservable((e1).min(predicate)).toBe(expected, { w: '2' }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a constant predicate on observable that throws', () => { + const e1 = hot('-1-^---#'); + const e1subs = '^ !'; + const expected = '----#'; + + const predicate = () => { + return 42; + }; + + expectObservable((e1).min(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a predicate that throws, on observable with many values', () => { + const e1 = hot('-1-^-2--3--|'); + const e1subs = '^ ! '; + const expected = '-----# '; + + const predicate = function (x, y) { + if (y === '3') { + throw 'error'; + } + return x > y ? x : y; + }; + + expectObservable((e1).min(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/multicast-spec.js b/spec/operators/multicast-spec.js deleted file mode 100644 index b49a14bb64..0000000000 --- a/spec/operators/multicast-spec.js +++ /dev/null @@ -1,573 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Subject = Rx.Subject; - -describe('Observable.prototype.multicast()', function () { - it.asDiagram('multicast(() => new Subject())')('should mirror a simple source Observable', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var multicasted = source.multicast(function () { return new Subject(); }); - var expected = '--1-2---3-4--5-|'; - - expectObservable(multicasted).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - multicasted.connect(); - }); - - it('should accept Subjects', function (done) { - var expected = [1,2,3,4]; - - var connectable = Observable.of(1,2,3,4).multicast(new Subject()); - - connectable.subscribe(function (x) { expect(x).toBe(expected.shift()); }, - done.throw, - done); - - connectable.connect(); - }); - - it('should accept Subject factory functions', function (done) { - var expected = [1,2,3,4]; - - var connectable = Observable.of(1,2,3,4).multicast(function () { - return new Subject(); - }); - - connectable.subscribe(function (x) { expect(x).toBe(expected.shift()); }, - done.throw, - done); - - connectable.connect(); - }); - - it('should do nothing if connect is not called, despite subscriptions', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = []; - var multicasted = source.multicast(function () { return new Subject(); }); - var expected = '-'; - - expectObservable(multicasted).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should multicast the same values to multiple observers', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var multicasted = source.multicast(function () { return new Subject(); }); - var subscriber1 = hot('a| ').mergeMapTo(multicasted); - var expected1 = '-1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(multicasted); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(multicasted); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - multicasted.connect(); - }); - - it('should multicast an error from the source to multiple observers', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var multicasted = source.multicast(function () { return new Subject(); }); - var subscriber1 = hot('a| ').mergeMapTo(multicasted); - var expected1 = '-1-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(multicasted); - var expected2 = ' -3----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(multicasted); - var expected3 = ' --4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - multicasted.connect(); - }); - - it('should multicast the same values to multiple observers, ' + - 'but is unsubscribed explicitly and early', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var multicasted = source.multicast(function () { return new Subject(); }); - var unsub = ' u '; - var subscriber1 = hot('a| ').mergeMapTo(multicasted); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(multicasted); - var expected2 = ' -3---- '; - var subscriber3 = hot(' c| ').mergeMapTo(multicasted); - var expected3 = ' -- '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = multicasted.connect(); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var multicasted = source - .mergeMap(function (x) { return Observable.of(x); }) - .multicast(function () { return new Subject(); }); - var subscriber1 = hot('a| ').mergeMapTo(multicasted); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(multicasted); - var expected2 = ' -3---- '; - var subscriber3 = hot(' c| ').mergeMapTo(multicasted); - var expected3 = ' -- '; - var unsub = ' u '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = multicasted.connect(); - }); - - it('should multicast an empty source', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var multicasted = source.multicast(function () { return new Subject(); }); - var expected = '|'; - - expectObservable(multicasted).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - multicasted.connect(); - }); - - it('should multicast a never source', function () { - var source = cold('-'); - var sourceSubs = '^'; - var multicasted = source.multicast(function () { return new Subject(); }); - var expected = '-'; - - expectObservable(multicasted).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - multicasted.connect(); - }); - - it('should multicast a throw source', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var multicasted = source.multicast(function () { return new Subject(); }); - var expected = '#'; - - expectObservable(multicasted).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - multicasted.connect(); - }); - - describe('with refCount() and subject factory', function () { - it('should connect when first subscriber subscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ !'; - var multicasted = source.multicast(function () { return new Subject(); }).refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(multicasted); - var expected1 = ' -1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(multicasted); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(multicasted); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should disconnect when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var multicasted = source.multicast(function () { return new Subject(); }).refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(multicasted); - var unsub1 = ' ! '; - var expected1 = ' -1-2-3-- '; - var subscriber2 = hot(' b| ').mergeMapTo(multicasted); - var unsub2 = ' ! '; - var expected2 = ' -3---- '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be retryable when cold source is synchronous', function () { - function subjectFactory() { return new Subject(); } - var source = cold('(123#)'); - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '(123123123123#) '; - var subscribe2 = ' s '; - var expected2 = ' (123123123123#)'; - var sourceSubs = ['(^!)', - '(^!)', - '(^!)', - '(^!)', - ' (^!)', - ' (^!)', - ' (^!)', - ' (^!)']; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.retry(3)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.retry(3)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be retryable with ReplaySubject and cold source is synchronous', function () { - function subjectFactory() { return new Rx.ReplaySubject(1); } - var source = cold('(123#)'); - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '(123123123123#) '; - var subscribe2 = ' s '; - var expected2 = ' (123123123123#)'; - var sourceSubs = ['(^!)', - '(^!)', - '(^!)', - '(^!)', - ' (^!)', - ' (^!)', - ' (^!)', - ' (^!)']; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.retry(3)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.retry(3)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be repeatable when cold source is synchronous', function () { - function subjectFactory() { return new Subject(); } - var source = cold('(123|)'); - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '(123123123123123|) '; - var subscribe2 = ' s '; - var expected2 = ' (123123123123123|)'; - var sourceSubs = ['(^!)', - '(^!)', - '(^!)', - '(^!)', - '(^!)', - ' (^!)', - ' (^!)', - ' (^!)', - ' (^!)', - ' (^!)']; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.repeat(5)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.repeat(5)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be repeatable with ReplaySubject and cold source is synchronous', function () { - function subjectFactory() { return new Rx.ReplaySubject(1); } - var source = cold('(123|)'); - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '(123123123123123|) '; - var subscribe2 = ' s '; - var expected2 = ' (123123123123123|)'; - var sourceSubs = ['(^!)', - '(^!)', - '(^!)', - '(^!)', - '(^!)', - ' (^!)', - ' (^!)', - ' (^!)', - ' (^!)', - ' (^!)']; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.repeat(5)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.repeat(5)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be retryable', function () { - function subjectFactory() { return new Subject(); } - var source = cold('-1-2-3----4-# '); - var sourceSubs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-#'; - var subscribe2 = ' s '; - var expected2 = ' -3----4--1-2-3----4--1-2-3----4-#'; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.retry(2)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.retry(2)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be retryable using a ReplaySubject', function () { - function subjectFactory() { return new Rx.ReplaySubject(1); } - var source = cold('-1-2-3----4-# '); - var sourceSubs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-#'; - var subscribe2 = ' s '; - var expected2 = ' 23----4--1-2-3----4--1-2-3----4-#'; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.retry(2)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.retry(2)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be repeatable', function () { - function subjectFactory() { return new Subject(); } - var source = cold('-1-2-3----4-| '); - var sourceSubs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-|'; - var subscribe2 = ' s '; - var expected2 = ' -3----4--1-2-3----4--1-2-3----4-|'; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.repeat(3)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.repeat(3)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be repeatable using a ReplaySubject', function () { - function subjectFactory() { return new Rx.ReplaySubject(1); } - var source = cold('-1-2-3----4-| '); - var sourceSubs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var multicasted = source.multicast(subjectFactory).refCount(); - var subscribe1 = 's '; - var expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-|'; - var subscribe2 = ' s '; - var expected2 = ' 23----4--1-2-3----4--1-2-3----4-|'; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(multicasted.repeat(3)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(multicasted.repeat(3)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - }); - - it('should multicast one observable to multiple observers', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.multicast(function () { - return new Subject(); - }); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - connectable.subscribe(function (x) { - results2.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([1, 2, 3, 4]); - expect(results1).toEqual([1, 2, 3, 4]); - expect(subscriptions).toBe(1); - done(); - }); - - it('should remove all subscribers from the subject when disconnected', function (done) { - var subject = new Subject(); - var expected = [1, 2, 3, 4]; - var i = 0; - - var source = Observable.fromArray([1, 2, 3, 4]).multicast(subject); - - source.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, function () { - expect(subject.isUnsubscribed).toBe(true); - done(); - }); - - source.connect(); - }); - - describe('when given a subject factory', function () { - it('should allow you to reconnect by subscribing again', function (done) { - var expected = [1, 2, 3, 4]; - var i = 0; - - var source = Observable.of(1, 2, 3, 4).multicast(function () { - return new Subject(); - }); - - source.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, - function () { - i = 0; - - source.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - - source.connect(); - }); - - source.connect(); - }); - - it('should not throw ObjectUnsubscribedError when used in ' + - 'a switchMap', function (done) { - var source = Observable.of(1, 2, 3) - .multicast(function () { return new Subject(); }) - .refCount(); - - var expected = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']; - - Observable.of('a', 'b', 'c') - .switchMap(function (letter) { - return source.map(function (number) { - return String(letter + number); - }); - }) - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, done.fail, function () { - expect(expected.length).toBe(0); - done(); - }); - }); - }); - - describe('when given a subject', function () { - it('should NOT allow you to reconnect by subscribing again', function (done) { - var expected = [1, 2, 3, 4]; - var i = 0; - - var source = Observable.of(1, 2, 3, 4).multicast(new Subject()); - - source.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, - null, - function () { - source.subscribe(function (x) { - throw 'this should not be called'; - }, null, done); - - source.connect(); - }); - - source.connect(); - }); - - it('should not throw ObjectUnsubscribedError when used in ' + - 'a switchMap', function (done) { - var source = Observable.of(1, 2, 3) - .multicast(new Subject()) - .refCount(); - - var expected = ['a1', 'a2', 'a3']; - - Observable.of('a', 'b', 'c') - .switchMap(function (letter) { - return source.map(function (number) { - return String(letter + number); - }); - }) - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, done.fail, function () { - expect(expected.length).toBe(0); - done(); - }); - }); - }); -}); \ No newline at end of file diff --git a/spec/operators/multicast-spec.ts b/spec/operators/multicast-spec.ts new file mode 100644 index 0000000000..d52fcf35d8 --- /dev/null +++ b/spec/operators/multicast-spec.ts @@ -0,0 +1,563 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Subject = Rx.Subject; + +describe('Observable.prototype.multicast()', () => { + asDiagram('multicast(() => new Subject())')('should mirror a simple source Observable', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const multicasted = source.multicast(() => new Subject()); + const expected = '--1-2---3-4--5-|'; + + expectObservable(multicasted).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + multicasted.connect(); + }); + + it('should accept Subjects', (done: DoneSignature) => { + const expected = [1, 2, 3, 4]; + + const connectable = Observable.of(1, 2, 3, 4).multicast(new Subject()); + + connectable.subscribe((x: number) => { expect(x).toBe(expected.shift()); }, + done.fail, + done); + + connectable.connect(); + }); + + it('should accept Subject factory functions', (done: DoneSignature) => { + const expected = [1, 2, 3, 4]; + + const connectable = Observable.of(1, 2, 3, 4).multicast(() => new Subject()); + + connectable.subscribe((x: number) => { expect(x).toBe(expected.shift()); }, + done.fail, + done); + + connectable.connect(); + }); + + it('should do nothing if connect is not called, despite subscriptions', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = []; + const multicasted = source.multicast(() => new Subject()); + const expected = '-'; + + expectObservable(multicasted).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should multicast the same values to multiple observers', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const multicasted = source.multicast(() => new Subject()); + const subscriber1 = hot('a| ').mergeMapTo(multicasted); + const expected1 = '-1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(multicasted); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(multicasted); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + multicasted.connect(); + }); + + it('should multicast an error from the source to multiple observers', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const multicasted = source.multicast(() => new Subject()); + const subscriber1 = hot('a| ').mergeMapTo(multicasted); + const expected1 = '-1-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(multicasted); + const expected2 = ' -3----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(multicasted); + const expected3 = ' --4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + multicasted.connect(); + }); + + it('should multicast the same values to multiple observers, ' + + 'but is unsubscribed explicitly and early', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const multicasted = source.multicast(() => new Subject()); + const unsub = ' u '; + const subscriber1 = hot('a| ').mergeMapTo(multicasted); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(multicasted); + const expected2 = ' -3---- '; + const subscriber3 = hot(' c| ').mergeMapTo(multicasted); + const expected3 = ' -- '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = multicasted.connect(); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const multicasted = source + .mergeMap((x: string) => Observable.of(x)) + .multicast(() => new Subject()); + const subscriber1 = hot('a| ').mergeMapTo(multicasted); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(multicasted); + const expected2 = ' -3---- '; + const subscriber3 = hot(' c| ').mergeMapTo(multicasted); + const expected3 = ' -- '; + const unsub = ' u '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = multicasted.connect(); + }); + + it('should multicast an empty source', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const multicasted = source.multicast(() => new Subject()); + const expected = '|'; + + expectObservable(multicasted).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + multicasted.connect(); + }); + + it('should multicast a never source', () => { + const source = cold('-'); + const sourceSubs = '^'; + const multicasted = source.multicast(() => new Subject()); + const expected = '-'; + + expectObservable(multicasted).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + multicasted.connect(); + }); + + it('should multicast a throw source', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const multicasted = source.multicast(() => new Subject()); + const expected = '#'; + + expectObservable(multicasted).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + multicasted.connect(); + }); + + describe('with refCount() and subject factory', () => { + it('should connect when first subscriber subscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ !'; + const multicasted = source.multicast(() => new Subject()).refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(multicasted); + const expected1 = ' -1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(multicasted); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(multicasted); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should disconnect when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const multicasted = source.multicast(() => new Subject()).refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(multicasted); + const unsub1 = ' ! '; + const expected1 = ' -1-2-3-- '; + const subscriber2 = hot(' b| ').mergeMapTo(multicasted); + const unsub2 = ' ! '; + const expected2 = ' -3---- '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be retryable when cold source is synchronous', () => { + function subjectFactory() { return new Subject(); } + const source = cold('(123#)'); + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '(123123123123#) '; + const subscribe2 = ' s '; + const expected2 = ' (123123123123#)'; + const sourceSubs = ['(^!)', + '(^!)', + '(^!)', + '(^!)', + ' (^!)', + ' (^!)', + ' (^!)', + ' (^!)']; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.retry(3)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.retry(3)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be retryable with ReplaySubject and cold source is synchronous', () => { + function subjectFactory() { return new Rx.ReplaySubject(1); } + const source = cold('(123#)'); + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '(123123123123#) '; + const subscribe2 = ' s '; + const expected2 = ' (123123123123#)'; + const sourceSubs = ['(^!)', + '(^!)', + '(^!)', + '(^!)', + ' (^!)', + ' (^!)', + ' (^!)', + ' (^!)']; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.retry(3)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.retry(3)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be repeatable when cold source is synchronous', () => { + function subjectFactory() { return new Subject(); } + const source = cold('(123|)'); + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '(123123123123123|) '; + const subscribe2 = ' s '; + const expected2 = ' (123123123123123|)'; + const sourceSubs = ['(^!)', + '(^!)', + '(^!)', + '(^!)', + '(^!)', + ' (^!)', + ' (^!)', + ' (^!)', + ' (^!)', + ' (^!)']; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.repeat(5)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.repeat(5)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be repeatable with ReplaySubject and cold source is synchronous', () => { + function subjectFactory() { return new Rx.ReplaySubject(1); } + const source = cold('(123|)'); + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '(123123123123123|) '; + const subscribe2 = ' s '; + const expected2 = ' (123123123123123|)'; + const sourceSubs = ['(^!)', + '(^!)', + '(^!)', + '(^!)', + '(^!)', + ' (^!)', + ' (^!)', + ' (^!)', + ' (^!)', + ' (^!)']; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.repeat(5)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.repeat(5)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be retryable', () => { + function subjectFactory() { return new Subject(); } + const source = cold('-1-2-3----4-# '); + const sourceSubs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-#'; + const subscribe2 = ' s '; + const expected2 = ' -3----4--1-2-3----4--1-2-3----4-#'; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.retry(2)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.retry(2)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be retryable using a ReplaySubject', () => { + function subjectFactory() { return new Rx.ReplaySubject(1); } + const source = cold('-1-2-3----4-# '); + const sourceSubs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-#'; + const subscribe2 = ' s '; + const expected2 = ' 23----4--1-2-3----4--1-2-3----4-#'; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.retry(2)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.retry(2)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be repeatable', () => { + function subjectFactory() { return new Subject(); } + const source = cold('-1-2-3----4-| '); + const sourceSubs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-|'; + const subscribe2 = ' s '; + const expected2 = ' -3----4--1-2-3----4--1-2-3----4-|'; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.repeat(3)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.repeat(3)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be repeatable using a ReplaySubject', () => { + function subjectFactory() { return new Rx.ReplaySubject(1); } + const source = cold('-1-2-3----4-| '); + const sourceSubs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const multicasted = source.multicast(subjectFactory).refCount(); + const subscribe1 = 's '; + const expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-|'; + const subscribe2 = ' s '; + const expected2 = ' 23----4--1-2-3----4--1-2-3----4-|'; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(multicasted.repeat(3)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(multicasted.repeat(3)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + }); + + it('should multicast one observable to multiple observers', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.multicast(() => { + return new Subject(); + }); + + connectable.subscribe((x: number) => { + results1.push(x); + }); + + connectable.subscribe((x: number) => { + results2.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([1, 2, 3, 4]); + expect(results1).toEqual([1, 2, 3, 4]); + expect(subscriptions).toBe(1); + done(); + }); + + it('should remove all subscribers from the subject when disconnected', (done: DoneSignature) => { + const subject = new Subject(); + const expected = [1, 2, 3, 4]; + let i = 0; + + const source = Observable.fromArray([1, 2, 3, 4]).multicast(subject); + + source.subscribe((x: number) => { + expect(x).toBe(expected[i++]); + }, null, () => { + expect(subject.isUnsubscribed).toBe(true); + done(); + }); + + source.connect(); + }); + + describe('when given a subject factory', () => { + it('should allow you to reconnect by subscribing again', (done: DoneSignature) => { + const expected = [1, 2, 3, 4]; + let i = 0; + + const source = Observable.of(1, 2, 3, 4).multicast(() => new Subject()); + + source.subscribe((x: number) => { + expect(x).toBe(expected[i++]); + }, null, + () => { + i = 0; + + source.subscribe((x: number) => { + expect(x).toBe(expected[i++]); + }, null, done); + + source.connect(); + }); + + source.connect(); + }); + + it('should not throw ObjectUnsubscribedError when used in ' + + 'a switchMap', (done: DoneSignature) => { + const source = Observable.of(1, 2, 3) + .multicast(() => new Subject()) + .refCount(); + + const expected = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']; + + Observable.of('a', 'b', 'c') + .switchMap((letter: string) => source.map((n :number) => String(letter + n))) + .subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, done.fail, () => { + expect(expected.length).toBe(0); + done(); + }); + }); + }); + + describe('when given a subject', () => { + it('should NOT allow you to reconnect by subscribing again', (done: DoneSignature) => { + const expected = [1, 2, 3, 4]; + let i = 0; + + const source = Observable.of(1, 2, 3, 4).multicast(new Subject()); + + source.subscribe((x: number) => { + expect(x).toBe(expected[i++]); + }, + null, + () => { + source.subscribe((x: number) => { + done.fail('this should not be called'); + }, null, done); + + source.connect(); + }); + + source.connect(); + }); + + it('should not throw ObjectUnsubscribedError when used in ' + + 'a switchMap', (done: DoneSignature) => { + const source = Observable.of(1, 2, 3) + .multicast(new Subject()) + .refCount(); + + const expected = ['a1', 'a2', 'a3']; + + Observable.of('a', 'b', 'c') + .switchMap((letter: string) => source.map((n :number) => String(letter + n))) + .subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, done.fail, () => { + expect(expected.length).toBe(0); + done(); + }); + }); + }); +}); diff --git a/spec/operators/observeOn-spec.js b/spec/operators/observeOn-spec.js deleted file mode 100644 index 9cd35000d4..0000000000 --- a/spec/operators/observeOn-spec.js +++ /dev/null @@ -1,77 +0,0 @@ -/* globals describe, it, expect, hot, expectObservable, expectSubscriptions, rxTestScheduler*/ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.observeOn()', function () { - it.asDiagram('observeOn(scheduler)')('should observe on specified scheduler', function () { - var e1 = hot('--a--b--|'); - var expected = '--a--b--|'; - var sub = '^ !'; - - expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should observe after specified delay', function () { - var e1 = hot('--a--b--|'); - var expected = '-----a--b--|'; - var sub = '^ !'; - - expectObservable(e1.observeOn(rxTestScheduler, 30)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should observe when source raises error', function () { - var e1 = hot('--a--#'); - var expected = '--a--#'; - var sub = '^ !'; - - expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should observe when source is empty', function () { - var e1 = hot('-----|'); - var expected = '-----|'; - var sub = '^ !'; - - expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should observe when source does not complete', function () { - var e1 = hot('-----'); - var expected = '-----'; - var sub = '^ '; - - expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--b--|'); - var sub = '^ ! '; - var expected = '--a-- '; - var unsub = ' ! '; - - var result = e1.observeOn(rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should not break unsubscription chains when the result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--|'); - var sub = '^ ! '; - var expected = '--a-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .observeOn(rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); -}); diff --git a/spec/operators/observeOn-spec.ts b/spec/operators/observeOn-spec.ts new file mode 100644 index 0000000000..f80ec64e80 --- /dev/null +++ b/spec/operators/observeOn-spec.ts @@ -0,0 +1,80 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.observeOn()', () => { + asDiagram('observeOn(scheduler)')('should observe on specified scheduler', () => { + const e1 = hot('--a--b--|'); + const expected = '--a--b--|'; + const sub = '^ !'; + + expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should observe after specified delay', () => { + const e1 = hot('--a--b--|'); + const expected = '-----a--b--|'; + const sub = '^ !'; + + expectObservable(e1.observeOn(rxTestScheduler, 30)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should observe when source raises error', () => { + const e1 = hot('--a--#'); + const expected = '--a--#'; + const sub = '^ !'; + + expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should observe when source is empty', () => { + const e1 = hot('-----|'); + const expected = '-----|'; + const sub = '^ !'; + + expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should observe when source does not complete', () => { + const e1 = hot('-----'); + const expected = '-----'; + const sub = '^ '; + + expectObservable(e1.observeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--b--|'); + const sub = '^ ! '; + const expected = '--a-- '; + const unsub = ' ! '; + + const result = e1.observeOn(rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should not break unsubscription chains when the result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--|'); + const sub = '^ ! '; + const expected = '--a-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .observeOn(rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)) + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); +}); diff --git a/spec/operators/pairwise-spec.js b/spec/operators/pairwise-spec.js deleted file mode 100644 index f7fbc7db63..0000000000 --- a/spec/operators/pairwise-spec.js +++ /dev/null @@ -1,88 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.pairwise()', function () { - it('should pairwise things', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '------v--w--x--y--z--|'; - - var values = { - v: ['b', 'c'], - w: ['c', 'd'], - x: ['d', 'e'], - y: ['e', 'f'], - z: ['f', 'g'] - }; - - var source = e1.pairwise(); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not emit on single-element streams', function () { - var e1 = hot('-----^--b----|'); - var e1subs = '^ !'; - var expected = '--------|'; - - var values = { - }; - - var source = e1.pairwise(); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle mid-stream throw', function () { - var e1 = hot('--a--^--b--c--d--e--#'); - var e1subs = '^ !'; - var expected = '------v--w--x--#'; - - var values = { - v: ['b', 'c'], - w: ['c', 'd'], - x: ['d', 'e'] - }; - - var source = e1.pairwise(); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - var source = e1.pairwise(); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var source = e1.pairwise(); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - var source = e1.pairwise(); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/pairwise-spec.ts b/spec/operators/pairwise-spec.ts new file mode 100644 index 0000000000..5f2a39fa34 --- /dev/null +++ b/spec/operators/pairwise-spec.ts @@ -0,0 +1,90 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.pairwise()', () => { + it('should pairwise things', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '------v--w--x--y--z--|'; + + const values = { + v: ['b', 'c'], + w: ['c', 'd'], + x: ['d', 'e'], + y: ['e', 'f'], + z: ['f', 'g'] + }; + + const source = (e1).pairwise(); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not emit on single-element streams', () => { + const e1 = hot('-----^--b----|'); + const e1subs = '^ !'; + const expected = '--------|'; + + const values = { + }; + + const source = (e1).pairwise(); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle mid-stream throw', () => { + const e1 = hot('--a--^--b--c--d--e--#'); + const e1subs = '^ !'; + const expected = '------v--w--x--#'; + + const values = { + v: ['b', 'c'], + w: ['c', 'd'], + x: ['d', 'e'] + }; + + const source = (e1).pairwise(); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + const source = (e1).pairwise(); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const source = (e1).pairwise(); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + const source = (e1).pairwise(); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/partition-spec.js b/spec/operators/partition-spec.ts similarity index 56% rename from spec/operators/partition-spec.js rename to spec/operators/partition-spec.ts index 68a15a8806..420bcd4a02 100644 --- a/spec/operators/partition-spec.js +++ b/spec/operators/partition-spec.ts @@ -1,31 +1,33 @@ -/* globals describe, it, expect, expectObservable, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; -describe('Observable.prototype.partition()', function () { +const Observable = Rx.Observable; + +describe('Observable.prototype.partition()', () => { function expectObservableArray(result, expected) { - for (var idx = 0; idx < result.length; idx++ ) { + for (let idx = 0; idx < result.length; idx++ ) { expectObservable(result[idx]).toBe(expected[idx]); } } - it.asDiagram('partition(x => x % 2 === 1)')('should partition an observable of ' + - 'integers into even and odd', function () { - var e1 = hot('--1-2---3------4--5---6--|'); - var e1subs = '^ !'; - var expected = ['--1-----3---------5------|', + asDiagram('partition(x => x % 2 === 1)')('should partition an observable of ' + + 'integers into even and odd', () => { + const e1 = hot('--1-2---3------4--5---6--|'); + const e1subs = '^ !'; + const expected = ['--1-----3---------5------|', '----2----------4------6--|']; - var result = e1.partition(function (x) { return x % 2 === 1; }); + const result = e1.partition((x: any) => x % 2 === 1); expectObservableArray(result, expected); expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition an observable into two using a predicate', function () { - var e1 = hot('--a-b---a------d--a---c--|'); - var e1subs = '^ !'; - var expected = ['--a-----a---------a------|', + it('should partition an observable into two using a predicate', () => { + const e1 = hot('--a-b---a------d--a---c--|'); + const e1subs = '^ !'; + const expected = ['--a-----a---------a------|', '----b----------d------c--|']; function predicate(x) { @@ -36,10 +38,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should pass errors to both returned observables', function () { - var e1 = hot('--a-b---#'); - var e1subs = '^ !'; - var expected = ['--a-----#', + it('should pass errors to both returned observables', () => { + const e1 = hot('--a-b---#'); + const e1subs = '^ !'; + const expected = ['--a-----#', '----b---#']; function predicate(x) { @@ -50,10 +52,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should pass errors to both returned observables if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = ['#', + it('should pass errors to both returned observables if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = ['#', '#']; function predicate(x) { @@ -64,16 +66,16 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should pass errors to both returned observables if predicate throws', function () { - var e1 = hot('--a-b--a--|'); - var e1subs = '^ ! '; - var expected = ['--a----# ', + it('should pass errors to both returned observables if predicate throws', () => { + const e1 = hot('--a-b--a--|'); + const e1subs = '^ ! '; + const expected = ['--a----# ', '----b--# ']; - var index = 0; - var error = 'error'; + let index = 0; + const error = 'error'; function predicate(x) { - var match = x === 'a'; + const match = x === 'a'; if (match && index++ > 1) { throw error; } @@ -84,10 +86,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition empty observable if source does not emits', function () { - var e1 = hot('----|'); - var e1subs = '^ !'; - var expected = ['----|', + it('should partition empty observable if source does not emits', () => { + const e1 = hot('----|'); + const e1subs = '^ !'; + const expected = ['----|', '----|']; function predicate(x) { @@ -98,10 +100,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition empty observable if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = ['|', + it('should partition empty observable if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = ['|', '|']; function predicate(x) { @@ -112,10 +114,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition if source emits single elements', function () { - var e1 = hot('--a--|'); - var e1subs = '^ !'; - var expected = ['--a--|', + it('should partition if source emits single elements', () => { + const e1 = hot('--a--|'); + const e1subs = '^ !'; + const expected = ['--a--|', '-----|']; function predicate(x) { @@ -126,10 +128,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition if predicate matches all of source elements', function () { - var e1 = hot('--a--a--a--a--a--a--a--|'); - var e1subs = '^ !'; - var expected = ['--a--a--a--a--a--a--a--|', + it('should partition if predicate matches all of source elements', () => { + const e1 = hot('--a--a--a--a--a--a--a--|'); + const e1subs = '^ !'; + const expected = ['--a--a--a--a--a--a--a--|', '-----------------------|']; function predicate(x) { @@ -140,10 +142,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition if predicate does not match all of source elements', function () { - var e1 = hot('--b--b--b--b--b--b--b--|'); - var e1subs = '^ !'; - var expected = ['-----------------------|', + it('should partition if predicate does not match all of source elements', () => { + const e1 = hot('--b--b--b--b--b--b--b--|'); + const e1subs = '^ !'; + const expected = ['-----------------------|', '--b--b--b--b--b--b--b--|']; function predicate(x) { @@ -154,10 +156,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition to infinite observable if source does not completes', function () { - var e1 = hot('--a-b---a------d----'); - var e1subs = '^ '; - var expected = ['--a-----a-----------', + it('should partition to infinite observable if source does not completes', () => { + const e1 = hot('--a-b---a------d----'); + const e1subs = '^ '; + const expected = ['--a-----a-----------', '----b----------d----']; function predicate(x) { @@ -168,10 +170,10 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition to infinite observable if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = ['-', + it('should partition to infinite observable if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = ['-', '-']; function predicate(x) { @@ -182,45 +184,44 @@ describe('Observable.prototype.partition()', function () { expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should partition into two observable with early unsubscription', function () { - var e1 = hot('--a-b---a------d-|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = ['--a----- ', + it('should partition into two observable with early unsubscription', () => { + const e1 = hot('--a-b---a------d-|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = ['--a----- ', '----b--- ']; function predicate(x) { return x === 'a'; } - var result = e1.partition(predicate); + const result = e1.partition(predicate); - for (var idx = 0; idx < result.length; idx++ ) { + for (let idx = 0; idx < result.length; idx++ ) { expectObservable(result[idx], unsub).toBe(expected[idx]); } expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a-b---a------d-|'); - var e1subs = '^ ! '; - var expected = ['--a----- ', + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a-b---a------d-|'); + const e1subs = '^ ! '; + const expected = ['--a----- ', '----b--- ']; - var unsub = ' ! '; + const unsub = ' ! '; - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .partition(function (x) { return x === 'a'; }) - .map(function (observable) { - return observable.mergeMap(function (x) { return Observable.of(x); }); - }); + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .partition((x: string) => x === 'a') + .map((observable: Rx.Observable) => + observable.mergeMap((x: string) => Observable.of(x))); expectObservable(result[0], unsub).toBe(expected[0]); expectObservable(result[1], unsub).toBe(expected[1]); expectSubscriptions(e1.subscriptions).toBe([e1subs, e1subs]); }); - it('should throw without predicate', function () { - var e1 = hot('--a-b---a------d----'); + it('should throw without predicate', () => { + const e1 = hot('--a-b---a------d----'); expect(e1.partition).toThrow(); }); }); \ No newline at end of file diff --git a/spec/operators/pluck-spec.js b/spec/operators/pluck-spec.js deleted file mode 100644 index 507b00d0bf..0000000000 --- a/spec/operators/pluck-spec.js +++ /dev/null @@ -1,152 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.pluck()', function () { - it('should work for one object', function () { - var a = cold('--x--|', {x: {prop: 42}}); - var asubs = '^ !'; - var expected = '--y--|'; - - var r = a.pluck('prop'); - expectObservable(r).toBe(expected, {y: 42}); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work for multiple objects', function () { - var inputs = { - a: {prop: '1'}, - b: {prop: '2'}, - c: {prop: '3'}, - d: {prop: '4'}, - e: {prop: '5'}, - }; - var a = cold('--a-b--c-d---e-|', inputs); - var asubs = '^ !'; - var expected = '--1-2--3-4---5-|'; - - var r = a.pluck('prop'); - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with deep nested properties', function () { - var inputs = { - a: {a: {b: {c: '1'}}}, - b: {a: {b: {c: '2'}}}, - c: {a: {b: {c: '3'}}}, - d: {a: {b: {c: '4'}}}, - e: {a: {b: {c: '5'}}}, - }; - var a = cold('--a-b--c-d---e-|', inputs); - var asubs = '^ !'; - var expected = '--1-2--3-4---5-|'; - - var r = a.pluck('a', 'b', 'c'); - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with edge cases of deep nested properties', function () { - var inputs = { - a: {a: {b: {c: 1}}}, - b: {a: {b: 2}}, - c: {a: {c: {c: 3}}}, - d: {}, - e: {a: {b: {c: 5}}}, - }; - var a = cold('--a-b--c-d---e-|', inputs); - var asubs = '^ !'; - var expected = '--r-x--y-z---w-|'; - var values = {r: 1, x: undefined, y: undefined, z: undefined, w: 5}; - - var r = a.pluck('a', 'b', 'c'); - expectObservable(r).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should throw an error if not property is passed', function () { - expect(function () { - Observable.of({prop: 1}, {prop: 2}).pluck(); - }).toThrow(new Error('List of properties cannot be empty.')); - }); - - it('should propagate errors from observable that emits only errors', function () { - var a = cold('#'); - var asubs = '(^!)'; - var expected = '#'; - - var r = a.pluck('whatever'); - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should propagate errors from observable that emit values', function () { - var a = cold('--a--b--#', {a: {prop: '1'}, b: {prop: '2'}}, 'too bad'); - var asubs = '^ !'; - var expected = '--1--2--#'; - - var r = a.pluck('prop'); - expectObservable(r).toBe(expected, undefined, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should not pluck an empty observable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var expected = '|'; - - var invoked = 0; - var r = a - .pluck('whatever') - .do(null, null, function () { - expect(invoked).toBe(0); - }); - - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var a = cold('--a--b--c--|', {a: {prop: '1'}, b: {prop: '2'}}); - var unsub = ' ! '; - var asubs = '^ ! '; - var expected = '--1--2- '; - - var r = a.pluck('prop'); - expectObservable(r, unsub).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should pluck twice', function () { - var inputs = { - a: {a: {b: {c: '1'}}}, - b: {a: {b: {c: '2'}}}, - c: {a: {b: {c: '3'}}}, - d: {a: {b: {c: '4'}}}, - e: {a: {b: {c: '5'}}}, - }; - var a = cold('--a-b--c-d---e-|', inputs); - var asubs = '^ !'; - var expected = '--1-2--3-4---5-|'; - - var r = a.pluck('a', 'b').pluck('c'); - expectObservable(r).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var a = cold('--a--b--c--|', {a: {prop: '1'}, b: {prop: '2'}}); - var unsub = ' ! '; - var asubs = '^ ! '; - var expected = '--1--2- '; - - var r = a - .mergeMap(function (x) { return Observable.of(x); }) - .pluck('prop') - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(r, unsub).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); -}); diff --git a/spec/operators/pluck-spec.ts b/spec/operators/pluck-spec.ts new file mode 100644 index 0000000000..e5c183dfaf --- /dev/null +++ b/spec/operators/pluck-spec.ts @@ -0,0 +1,154 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.pluck()', () => { + it('should work for one object', () => { + const a = cold('--x--|', {x: {prop: 42}}); + const asubs = '^ !'; + const expected = '--y--|'; + + const r = a.pluck('prop'); + expectObservable(r).toBe(expected, {y: 42}); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work for multiple objects', () => { + const inputs = { + a: {prop: '1'}, + b: {prop: '2'}, + c: {prop: '3'}, + d: {prop: '4'}, + e: {prop: '5'}, + }; + const a = cold('--a-b--c-d---e-|', inputs); + const asubs = '^ !'; + const expected = '--1-2--3-4---5-|'; + + const r = a.pluck('prop'); + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with deep nested properties', () => { + const inputs = { + a: {a: {b: {c: '1'}}}, + b: {a: {b: {c: '2'}}}, + c: {a: {b: {c: '3'}}}, + d: {a: {b: {c: '4'}}}, + e: {a: {b: {c: '5'}}}, + }; + const a = cold('--a-b--c-d---e-|', inputs); + const asubs = '^ !'; + const expected = '--1-2--3-4---5-|'; + + const r = a.pluck('a', 'b', 'c'); + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with edge cases of deep nested properties', () => { + const inputs = { + a: {a: {b: {c: 1}}}, + b: {a: {b: 2}}, + c: {a: {c: {c: 3}}}, + d: {}, + e: {a: {b: {c: 5}}}, + }; + const a = cold('--a-b--c-d---e-|', inputs); + const asubs = '^ !'; + const expected = '--r-x--y-z---w-|'; + const values = {r: 1, x: undefined, y: undefined, z: undefined, w: 5}; + + const r = a.pluck('a', 'b', 'c'); + expectObservable(r).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should throw an error if not property is passed', () => { + expect(() => { + Observable.of({prop: 1}, {prop: 2}).pluck(); + }).toThrow(new Error('List of properties cannot be empty.')); + }); + + it('should propagate errors from observable that emits only errors', () => { + const a = cold('#'); + const asubs = '(^!)'; + const expected = '#'; + + const r = a.pluck('whatever'); + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should propagate errors from observable that emit values', () => { + const a = cold('--a--b--#', {a: {prop: '1'}, b: {prop: '2'}}, 'too bad'); + const asubs = '^ !'; + const expected = '--1--2--#'; + + const r = a.pluck('prop'); + expectObservable(r).toBe(expected, undefined, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should not pluck an empty observable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const expected = '|'; + + const invoked = 0; + const r = a + .pluck('whatever') + .do(null, null, () => { + expect(invoked).toBe(0); + }); + + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const a = cold('--a--b--c--|', {a: {prop: '1'}, b: {prop: '2'}}); + const unsub = ' ! '; + const asubs = '^ ! '; + const expected = '--1--2- '; + + const r = a.pluck('prop'); + expectObservable(r, unsub).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should pluck twice', () => { + const inputs = { + a: {a: {b: {c: '1'}}}, + b: {a: {b: {c: '2'}}}, + c: {a: {b: {c: '3'}}}, + d: {a: {b: {c: '4'}}}, + e: {a: {b: {c: '5'}}}, + }; + const a = cold('--a-b--c-d---e-|', inputs); + const asubs = '^ !'; + const expected = '--1-2--3-4---5-|'; + + const r = a.pluck('a', 'b').pluck('c'); + expectObservable(r).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const a = cold('--a--b--c--|', {a: {prop: '1'}, b: {prop: '2'}}); + const unsub = ' ! '; + const asubs = '^ ! '; + const expected = '--1--2- '; + + const r = a + .mergeMap((x: string) => Observable.of(x)) + .pluck('prop') + .mergeMap((x: string) => Observable.of(x)) + + expectObservable(r, unsub).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); +}); diff --git a/spec/operators/publish-spec.js b/spec/operators/publish-spec.js deleted file mode 100644 index e4e8a0a42b..0000000000 --- a/spec/operators/publish-spec.js +++ /dev/null @@ -1,324 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Subject = Rx.Subject; - -describe('Observable.prototype.publish()', function () { - it.asDiagram('publish')('should mirror a simple source Observable', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var published = source.publish(); - var expected = '--1-2---3-4--5-|'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('To match RxJS 4 behavior, it should NOT allow you to reconnect by subscribing again', function (done) { - var expected = [1, 2, 3, 4]; - var i = 0; - - var source = Observable.of(1, 2, 3, 4).publish(); - - source.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, - null, - function () { - source.subscribe(function (x) { - done.fail('should not be called'); - }, null, done); - - source.connect(); - }); - - source.connect(); - }); - - it('should return a ConnectableObservable', function () { - var source = Observable.of(1).publish(); - expect(source instanceof Rx.ConnectableObservable).toBe(true); - }); - - it('should do nothing if connect is not called, despite subscriptions', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = []; - var published = source.publish(); - var expected = '-'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should multicast the same values to multiple observers', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publish(); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast an error from the source to multiple observers', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publish(); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' -3----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' --4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast the same values to multiple observers, ' + - 'but is unsubscribed explicitly and early', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source.publish(); - var unsub = ' u '; - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' -3---- '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' -- '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source - .mergeMap(function (x) { return Observable.of(x); }) - .publish(); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' -3---- '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' -- '; - var unsub = ' u '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - describe('with refCount()', function () { - it('should connect when first subscriber subscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ !'; - var replayed = source.publish().refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var expected1 = ' -1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(replayed); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should disconnect when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var replayed = source.publish().refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var unsub1 = ' ! '; - var expected1 = ' -1-2-3-- '; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var unsub2 = ' ! '; - var expected2 = ' -3---- '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be retryable', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publish().refCount().retry(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' -3----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' --4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be repeatable', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publish().refCount().repeat(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - }); - - it('should emit completed when subscribed after completed', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publish(); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([1, 2, 3, 4]); - expect(results2).toEqual([]); - expect(subscriptions).toBe(1); - - connectable.subscribe(function (x) { - results2.push(x); - }, done.fail, function () { - expect(results2).toEqual([]); - done(); - }); - }); - - it('should multicast an empty source', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var published = source.publish(); - var expected = '|'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a never source', function () { - var source = cold('-'); - var sourceSubs = '^'; - var published = source.publish(); - var expected = '-'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a throw source', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var published = source.publish(); - var expected = '#'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast one observable to multiple observers', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publish(); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - connectable.subscribe(function (x) { - results2.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([1, 2, 3, 4]); - expect(results2).toEqual([1, 2, 3, 4]); - expect(subscriptions).toBe(1); - done(); - }); -}); \ No newline at end of file diff --git a/spec/operators/publish-spec.ts b/spec/operators/publish-spec.ts new file mode 100644 index 0000000000..80d370d2a6 --- /dev/null +++ b/spec/operators/publish-spec.ts @@ -0,0 +1,326 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Subject = Rx.Subject; + +describe('Observable.prototype.publish()', () => { + asDiagram('publish')('should mirror a simple source Observable', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const published = source.publish(); + const expected = '--1-2---3-4--5-|'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('To match RxJS 4 behavior, it should NOT allow you to reconnect by subscribing again', (done: DoneSignature) => { + const expected = [1, 2, 3, 4]; + let i = 0; + + const source = Observable.of(1, 2, 3, 4).publish(); + + source.subscribe((x: number) => { + expect(x).toBe(expected[i++]); + }, + done.fail, + () => { + source.subscribe((x: any) => { + done.fail('should not be called'); + }, done.fail, done); + + source.connect(); + }); + + source.connect(); + }); + + it('should return a ConnectableObservable', () => { + const source = Observable.of(1).publish(); + expect(source instanceof Rx.ConnectableObservable).toBe(true); + }); + + it('should do nothing if connect is not called, despite subscriptions', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = []; + const published = source.publish(); + const expected = '-'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should multicast the same values to multiple observers', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publish(); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast an error from the source to multiple observers', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publish(); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' -3----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' --4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast the same values to multiple observers, ' + + 'but is unsubscribed explicitly and early', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source.publish(); + const unsub = ' u '; + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' -3---- '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' -- '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source + .mergeMap((x: any) => Observable.of(x)) + .publish(); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' -3---- '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' -- '; + const unsub = ' u '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + describe('with refCount()', () => { + it('should connect when first subscriber subscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ !'; + const replayed = source.publish().refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const expected1 = ' -1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(replayed); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should disconnect when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const replayed = source.publish().refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const unsub1 = ' ! '; + const expected1 = ' -1-2-3-- '; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const unsub2 = ' ! '; + const expected2 = ' -3---- '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be retryable', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publish().refCount().retry(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' -3----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' --4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be repeatable', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publish().refCount().repeat(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + }); + + it('should emit completed when subscribed after completed', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publish(); + + connectable.subscribe((x: any) => { + results1.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([1, 2, 3, 4]); + expect(results2).toEqual([]); + expect(subscriptions).toBe(1); + + connectable.subscribe((x: any) => { + results2.push(x); + }, done.fail, () => { + expect(results2).toEqual([]); + done(); + }); + }); + + it('should multicast an empty source', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const published = source.publish(); + const expected = '|'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a never source', () => { + const source = cold('-'); + const sourceSubs = '^'; + const published = source.publish(); + const expected = '-'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a throw source', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const published = source.publish(); + const expected = '#'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast one observable to multiple observers', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publish(); + + connectable.subscribe((x: any) => { + results1.push(x); + }); + + connectable.subscribe((x: any) => { + results2.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([1, 2, 3, 4]); + expect(results2).toEqual([1, 2, 3, 4]); + expect(subscriptions).toBe(1); + done(); + }); +}); \ No newline at end of file diff --git a/spec/operators/publishBehavior-spec.js b/spec/operators/publishBehavior-spec.js deleted file mode 100644 index 85f5bf493a..0000000000 --- a/spec/operators/publishBehavior-spec.js +++ /dev/null @@ -1,347 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.publishBehavior()', function () { - it.asDiagram('publishBehavior(0)')('should mirror a simple source Observable', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var published = source.publishBehavior('0'); - var expected = '0-1-2---3-4--5-|'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should follow the RxJS 4 behavior and NOT allow you to reconnect by subscribing again', function (done) { - var expected = [0, 1, 2, 3, 4]; - var i = 0; - - var source = Observable.of(1, 2, 3, 4).publishBehavior(0); - - source.subscribe( - function (x) { - expect(x).toBe(expected[i++]); - }, - null, - function () { - source.subscribe(function (x) { - done.fail('should not be called'); - }, null, done); - - source.connect(); - }); - - source.connect(); - }); - - it('should return a ConnectableObservable', function () { - var source = Observable.of(1).publishBehavior(1); - expect(source instanceof Rx.ConnectableObservable).toBe(true); - }); - - it('should only emit default value if connect is not called, despite subscriptions', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = []; - var published = source.publishBehavior('0'); - var expected = '0'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should multicast the same values to multiple observers', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publishBehavior('0'); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '01-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast an error from the source to multiple observers', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publishBehavior('0'); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '01-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast the same values to multiple observers, ' + - 'but is unsubscribed explicitly and early', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source.publishBehavior('0'); - var unsub = ' u '; - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '01-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23---- '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3- '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source - .mergeMap(function (x) { return Observable.of(x); }) - .publishBehavior('0'); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '01-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23---- '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3- '; - var unsub = ' u '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - describe('with refCount()', function () { - it('should connect when first subscriber subscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ !'; - var replayed = source.publishBehavior('0').refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var expected1 = ' 01-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var expected2 = ' 23----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(replayed); - var expected3 = ' 3-4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should disconnect when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var replayed = source.publishBehavior('0').refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var unsub1 = ' ! '; - var expected1 = ' 01-2-3-- '; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var unsub2 = ' ! '; - var expected2 = ' 23---- '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be retryable', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publishBehavior('0').refCount().retry(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '01-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be repeatable', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publishBehavior('0').refCount().repeat(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '01-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - }); - - it('should emit completed when subscribed after completed', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publishBehavior(0); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - expect(results1).toEqual([0]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([0, 1, 2, 3, 4]); - expect(results2).toEqual([]); - expect(subscriptions).toBe(1); - - connectable.subscribe(function (x) { - results2.push(x); - }, done.fail, function () { - expect(results2).toEqual([]); - done(); - }); - }); - - it('should multicast an empty source', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var published = source.publishBehavior('0'); - var expected = '(0|)'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a never source', function () { - var source = cold('-'); - var sourceSubs = '^'; - var published = source.publishBehavior('0'); - var expected = '0'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a throw source', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var published = source.publishBehavior('0'); - var expected = '(0#)'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast one observable to multiple observers', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - }); - - var connectable = source.publishBehavior(0); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - expect(results1).toEqual([0]); - - connectable.connect(); - - expect(results2).toEqual([]); - - connectable.subscribe(function (x) { - results2.push(x); - }); - - expect(results1).toEqual([0, 1, 2, 3, 4]); - expect(results2).toEqual([4]); - expect(subscriptions).toBe(1); - done(); - }); - - it('should follow the RxJS 4 behavior and emit nothing to observer after completed', function (done) { - var results = []; - - var source = new Observable(function (observer) { - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publishBehavior(0); - - connectable.connect(); - - connectable.subscribe(function (x) { - results.push(x); - }); - - expect(results).toEqual([]); - done(); - }); -}); \ No newline at end of file diff --git a/spec/operators/publishBehavior-spec.ts b/spec/operators/publishBehavior-spec.ts new file mode 100644 index 0000000000..3ab759d38a --- /dev/null +++ b/spec/operators/publishBehavior-spec.ts @@ -0,0 +1,349 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.publishBehavior()', () => { + asDiagram('publishBehavior(0)')('should mirror a simple source Observable', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const published = source.publishBehavior('0'); + const expected = '0-1-2---3-4--5-|'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should follow the RxJS 4 behavior and NOT allow you to reconnect by subscribing again', (done: DoneSignature) => { + const expected = [0, 1, 2, 3, 4]; + let i = 0; + + const source = Observable.of(1, 2, 3, 4).publishBehavior(0); + + source.subscribe( + (x: number) => { + expect(x).toBe(expected[i++]); + }, + done.fail, + () => { + source.subscribe((x: any) => { + done.fail('should not be called'); + }, done.fail, done); + + source.connect(); + }); + + source.connect(); + }); + + it('should return a ConnectableObservable', () => { + const source = Observable.of(1).publishBehavior(1); + expect(source instanceof Rx.ConnectableObservable).toBe(true); + }); + + it('should only emit default value if connect is not called, despite subscriptions', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = []; + const published = source.publishBehavior('0'); + const expected = '0'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should multicast the same values to multiple observers', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publishBehavior('0'); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '01-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast an error from the source to multiple observers', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publishBehavior('0'); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '01-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast the same values to multiple observers, ' + + 'but is unsubscribed explicitly and early', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source.publishBehavior('0'); + const unsub = ' u '; + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '01-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23---- '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3- '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source + .mergeMap((x: any) => Observable.of(x)) + .publishBehavior('0'); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '01-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23---- '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3- '; + const unsub = ' u '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + describe('with refCount()', () => { + it('should connect when first subscriber subscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ !'; + const replayed = source.publishBehavior('0').refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const expected1 = ' 01-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const expected2 = ' 23----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(replayed); + const expected3 = ' 3-4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should disconnect when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const replayed = source.publishBehavior('0').refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const unsub1 = ' ! '; + const expected1 = ' 01-2-3-- '; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const unsub2 = ' ! '; + const expected2 = ' 23---- '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be retryable', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publishBehavior('0').refCount().retry(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '01-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be repeatable', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publishBehavior('0').refCount().repeat(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '01-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + }); + + it('should emit completed when subscribed after completed', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publishBehavior(0); + + connectable.subscribe(function (x) { + results1.push(x); + }); + + expect(results1).toEqual([0]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([0, 1, 2, 3, 4]); + expect(results2).toEqual([]); + expect(subscriptions).toBe(1); + + connectable.subscribe(function (x) { + results2.push(x); + }, done.fail, () => { + expect(results2).toEqual([]); + done(); + }); + }); + + it('should multicast an empty source', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const published = source.publishBehavior('0'); + const expected = '(0|)'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a never source', () => { + const source = cold('-'); + const sourceSubs = '^'; + const published = source.publishBehavior('0'); + const expected = '0'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a throw source', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const published = source.publishBehavior('0'); + const expected = '(0#)'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast one observable to multiple observers', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + }); + + const connectable = source.publishBehavior(0); + + connectable.subscribe((x: any) => { + results1.push(x); + }); + + expect(results1).toEqual([0]); + + connectable.connect(); + + expect(results2).toEqual([]); + + connectable.subscribe((x: any) => { + results2.push(x); + }); + + expect(results1).toEqual([0, 1, 2, 3, 4]); + expect(results2).toEqual([4]); + expect(subscriptions).toBe(1); + done(); + }); + + it('should follow the RxJS 4 behavior and emit nothing to observer after completed', (done: DoneSignature) => { + const results = []; + + const source = new Observable((observer: Rx.Observer) => { + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publishBehavior(0); + + connectable.connect(); + + connectable.subscribe((x: any) => { + results.push(x); + }); + + expect(results).toEqual([]); + done(); + }); +}); \ No newline at end of file diff --git a/spec/operators/publishLast-spec.js b/spec/operators/publishLast-spec.js deleted file mode 100644 index 460d2c4694..0000000000 --- a/spec/operators/publishLast-spec.js +++ /dev/null @@ -1,250 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Subject = Rx.Subject; - -describe('Observable.prototype.publishLast()', function () { - it.asDiagram('publishLast')('should emit last notification of a simple source Observable', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var published = source.publishLast(); - var expected = '---------------(5|)'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should return a ConnectableObservable', function () { - var source = Observable.of(1).publishLast(); - - expect(source instanceof Rx.ConnectableObservable).toBe(true); - }); - - it('should do nothing if connect is not called, despite subscriptions', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = []; - var published = source.publishLast(); - var expected = '-'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should multicast the same values to multiple observers', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publishLast(); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '------------(4|)'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' --------(4|)'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' ----(4|)'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast an error from the source to multiple observers', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publishLast(); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '------------#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' --------#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' ----#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should not cast any values to multiple observers, ' + - 'when source is unsubscribed explicitly and early', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source.publishLast(); - var unsub = ' u '; - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '---------- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' ------ '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' -- '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source - .mergeMap(function (x) { return Observable.of(x); }) - .publishLast(); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '---------- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' ------ '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' -- '; - var unsub = ' u '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - describe('with refCount()', function () { - it('should connect when first subscriber subscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ !'; - var replayed = source.publishLast().refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var expected1 = ' ------------(4|)'; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var expected2 = ' --------(4|)'; - var subscriber3 = hot(' c| ').mergeMapTo(replayed); - var expected3 = ' ----(4|)'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should disconnect when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var replayed = source.publishLast().refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var unsub1 = ' ! '; - var expected1 = ' -------- '; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var unsub2 = ' ! '; - var expected2 = ' ------ '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be retryable', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publishLast().refCount().retry(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '------------#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' --------#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' ----#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - }); - - it('should multicast an empty source', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var published = source.publishLast(); - var expected = '|'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a never source', function () { - var source = cold('-'); - var sourceSubs = '^'; - var published = source.publishLast(); - var expected = '-'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a throw source', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var published = source.publishLast(); - var expected = '#'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast one observable to multiple observers', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publishLast(); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - connectable.subscribe(function (x) { - results2.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([4]); - expect(results2).toEqual([4]); - expect(subscriptions).toBe(1); - done(); - }); -}); \ No newline at end of file diff --git a/spec/operators/publishLast-spec.ts b/spec/operators/publishLast-spec.ts new file mode 100644 index 0000000000..624838627b --- /dev/null +++ b/spec/operators/publishLast-spec.ts @@ -0,0 +1,252 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Subject = Rx.Subject; + +describe('Observable.prototype.publishLast()', () => { + asDiagram('publishLast')('should emit last notification of a simple source Observable', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const published = source.publishLast(); + const expected = '---------------(5|)'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should return a ConnectableObservable', () => { + const source = Observable.of(1).publishLast(); + + expect(source instanceof Rx.ConnectableObservable).toBe(true); + }); + + it('should do nothing if connect is not called, despite subscriptions', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = []; + const published = source.publishLast(); + const expected = '-'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should multicast the same values to multiple observers', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publishLast(); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '------------(4|)'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' --------(4|)'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' ----(4|)'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast an error from the source to multiple observers', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publishLast(); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '------------#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' --------#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' ----#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should not cast any values to multiple observers, ' + + 'when source is unsubscribed explicitly and early', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source.publishLast(); + const unsub = ' u '; + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '---------- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' ------ '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' -- '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source + .mergeMap((x: string) => Observable.of(x)) + .publishLast(); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '---------- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' ------ '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' -- '; + const unsub = ' u '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + describe('with refCount()', () => { + it('should connect when first subscriber subscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ !'; + const replayed = source.publishLast().refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const expected1 = ' ------------(4|)'; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const expected2 = ' --------(4|)'; + const subscriber3 = hot(' c| ').mergeMapTo(replayed); + const expected3 = ' ----(4|)'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should disconnect when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const replayed = source.publishLast().refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const unsub1 = ' ! '; + const expected1 = ' -------- '; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const unsub2 = ' ! '; + const expected2 = ' ------ '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be retryable', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publishLast().refCount().retry(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '------------#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' --------#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' ----#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + }); + + it('should multicast an empty source', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const published = source.publishLast(); + const expected = '|'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a never source', () => { + const source = cold('-'); + const sourceSubs = '^'; + const published = source.publishLast(); + const expected = '-'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a throw source', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const published = source.publishLast(); + const expected = '#'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast one observable to multiple observers', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publishLast(); + + connectable.subscribe((x: any) => { + results1.push(x); + }); + + connectable.subscribe((x: any) => { + results2.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([4]); + expect(results2).toEqual([4]); + expect(subscriptions).toBe(1); + done(); + }); +}); \ No newline at end of file diff --git a/spec/operators/publishReplay-spec.js b/spec/operators/publishReplay-spec.js deleted file mode 100644 index e5d0257053..0000000000 --- a/spec/operators/publishReplay-spec.js +++ /dev/null @@ -1,383 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.publishReplay()', function () { - it.asDiagram('publishReplay(1)')('should mirror a simple source Observable', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var published = source.publishReplay(1); - var expected = '--1-2---3-4--5-|'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should return a ConnectableObservable', function () { - var source = Observable.of(1).publishReplay(); - expect(source instanceof Rx.ConnectableObservable).toBe(true); - }); - - it('should do nothing if connect is not called, despite subscriptions', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = []; - var published = source.publishReplay(1); - var expected = '-'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should multicast the same values to multiple observers, bufferSize=1', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publishReplay(1); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast the same values to multiple observers, bufferSize=2', function () { - var source = cold('-1-2-----3------4-|'); - var sourceSubs = '^ !'; - var published = source.publishReplay(2); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-----3------4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' (12)-3------4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' (23)-4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast an error from the source to multiple observers', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publishReplay(1); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast the same values to multiple observers, ' + - 'but is unsubscribed explicitly and early', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source.publishReplay(1); - var unsub = ' u '; - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23---- '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3- '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var published = source - .mergeMap(function (x) { return Observable.of(x); }) - .publishReplay(1); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23---- '; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3- '; - var unsub = ' u '; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - // Set up unsubscription action - var connection; - expectObservable(hot(unsub).do(function () { - connection.unsubscribe(); - })).toBe(unsub); - - connection = published.connect(); - }); - - describe('with refCount()', function () { - it('should connect when first subscriber subscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ !'; - var replayed = source.publishReplay(1).refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var expected1 = ' -1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var expected2 = ' 23----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(replayed); - var expected3 = ' 3-4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should disconnect when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var replayed = source.publishReplay(1).refCount(); - var subscriber1 = hot(' a| ').mergeMapTo(replayed); - var unsub1 = ' ! '; - var expected1 = ' -1-2-3-- '; - var subscriber2 = hot(' b| ').mergeMapTo(replayed); - var unsub2 = ' ! '; - var expected2 = ' 23---- '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be retryable', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var published = source.publishReplay(1).refCount().retry(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-(444#)'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-(444#)'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-(444#)'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should NOT be repeatable', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var published = source.publishReplay(1).refCount().repeat(3); - var subscriber1 = hot('a| ').mergeMapTo(published); - var expected1 = '-1-2-3----4-(44|)'; - var subscriber2 = hot(' b| ').mergeMapTo(published); - var expected2 = ' 23----4-(44|)'; - var subscriber3 = hot(' c| ').mergeMapTo(published); - var expected3 = ' 3-4-(44|)'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - }); - - it('should multicast one observable to multiple observers', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publishReplay(); - - connectable.subscribe(function (x) { - results1.push(x); - }); - connectable.subscribe(function (x) { - results2.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([1, 2, 3, 4]); - expect(results2).toEqual([1, 2, 3, 4]); - expect(subscriptions).toBe(1); - done(); - }); - - it('should replay as many events as specified by the bufferSize', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publishReplay(2); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - connectable.subscribe(function (x) { - results2.push(x); - }); - - expect(results1).toEqual([1, 2, 3, 4]); - expect(results2).toEqual([3, 4]); - expect(subscriptions).toBe(1); - done(); - }); - - it('should emit replayed values plus completed when subscribed after completed', function (done) { - var results1 = []; - var results2 = []; - var subscriptions = 0; - - var source = new Observable(function (observer) { - subscriptions++; - observer.next(1); - observer.next(2); - observer.next(3); - observer.next(4); - observer.complete(); - }); - - var connectable = source.publishReplay(2); - - connectable.subscribe(function (x) { - results1.push(x); - }); - - expect(results1).toEqual([]); - expect(results2).toEqual([]); - - connectable.connect(); - - expect(results1).toEqual([1, 2, 3, 4]); - expect(results2).toEqual([]); - expect(subscriptions).toBe(1); - - connectable.subscribe(function (x) { - results2.push(x); - }, done.fail, function () { - expect(results2).toEqual([3, 4]); - done(); - }); - }); - - it('should multicast an empty source', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var published = source.publishReplay(1); - var expected = '|'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a never source', function () { - var source = cold('-'); - var sourceSubs = '^'; - var published = source.publishReplay(1); - var expected = '-'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should multicast a throw source', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var published = source.publishReplay(1); - var expected = '#'; - - expectObservable(published).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - - published.connect(); - }); - - it('should follow the RxJS 4 behavior and NOT allow you to reconnect by subscribing again', function (done) { - var expected = [1, 2, 3, 4]; - var i = 0; - - var source = Observable.of(1, 2, 3, 4).publishReplay(1); - - var results = []; - - source.subscribe( - function (x) { - expect(x).toBe(expected[i++]); - }, - null, - function () { - i = 0; - - source.subscribe(function (x) { - results.push(x); - }, null, done); - - source.connect(); - }); - - source.connect(); - - expect(results).toEqual([4]); - }); -}); \ No newline at end of file diff --git a/spec/operators/publishReplay-spec.ts b/spec/operators/publishReplay-spec.ts new file mode 100644 index 0000000000..86c2482259 --- /dev/null +++ b/spec/operators/publishReplay-spec.ts @@ -0,0 +1,386 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.publishReplay()', () => { + asDiagram('publishReplay(1)')('should mirror a simple source Observable', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const published = source.publishReplay(1); + const expected = '--1-2---3-4--5-|'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should return a ConnectableObservable', () => { + const source = Observable.of(1).publishReplay(); + expect(source instanceof Rx.ConnectableObservable).toBe(true); + }); + + it('should do nothing if connect is not called, despite subscriptions', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = []; + const published = source.publishReplay(1); + const expected = '-'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should multicast the same values to multiple observers, bufferSize=1', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publishReplay(1); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast the same values to multiple observers, bufferSize=2', () => { + const source = cold('-1-2-----3------4-|'); + const sourceSubs = '^ !'; + const published = source.publishReplay(2); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-----3------4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' (12)-3------4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' (23)-4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast an error from the source to multiple observers', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publishReplay(1); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast the same values to multiple observers, ' + + 'but is unsubscribed explicitly and early', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source.publishReplay(1); + const unsub = ' u '; + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23---- '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3- '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const published = source + .mergeMap((x: any) => Observable.of(x)) + .publishReplay(1); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23---- '; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3- '; + const unsub = ' u '; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + // Set up unsubscription action + let connection; + expectObservable(hot(unsub).do(() => { + connection.unsubscribe(); + })).toBe(unsub); + + connection = published.connect(); + }); + + describe('with refCount()', () => { + it('should connect when first subscriber subscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ !'; + const replayed = source.publishReplay(1).refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const expected1 = ' -1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const expected2 = ' 23----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(replayed); + const expected3 = ' 3-4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should disconnect when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const replayed = source.publishReplay(1).refCount(); + const subscriber1 = hot(' a| ').mergeMapTo(replayed); + const unsub1 = ' ! '; + const expected1 = ' -1-2-3-- '; + const subscriber2 = hot(' b| ').mergeMapTo(replayed); + const unsub2 = ' ! '; + const expected2 = ' 23---- '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be retryable', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const published = source.publishReplay(1).refCount().retry(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-(444#)'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-(444#)'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-(444#)'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should NOT be repeatable', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const published = source.publishReplay(1).refCount().repeat(3); + const subscriber1 = hot('a| ').mergeMapTo(published); + const expected1 = '-1-2-3----4-(44|)'; + const subscriber2 = hot(' b| ').mergeMapTo(published); + const expected2 = ' 23----4-(44|)'; + const subscriber3 = hot(' c| ').mergeMapTo(published); + const expected3 = ' 3-4-(44|)'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + }); + + it('should multicast one observable to multiple observers', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publishReplay(); + + connectable.subscribe((x: number) => { + results1.push(x); + }); + connectable.subscribe((x: number) => { + results2.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([1, 2, 3, 4]); + expect(results2).toEqual([1, 2, 3, 4]); + expect(subscriptions).toBe(1); + done(); + }); + + it('should replay as many events as specified by the bufferSize', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publishReplay(2); + + connectable.subscribe((x: number) => { + results1.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + connectable.subscribe((x: number) => { + results2.push(x); + }); + + expect(results1).toEqual([1, 2, 3, 4]); + expect(results2).toEqual([3, 4]); + expect(subscriptions).toBe(1); + done(); + }); + + it('should emit replayed values plus completed when subscribed after completed', (done: DoneSignature) => { + const results1 = []; + const results2 = []; + let subscriptions = 0; + + const source = new Observable((observer: Rx.Observer) => { + subscriptions++; + observer.next(1); + observer.next(2); + observer.next(3); + observer.next(4); + observer.complete(); + }); + + const connectable = source.publishReplay(2); + + connectable.subscribe((x: number) => { + results1.push(x); + }); + + expect(results1).toEqual([]); + expect(results2).toEqual([]); + + connectable.connect(); + + expect(results1).toEqual([1, 2, 3, 4]); + expect(results2).toEqual([]); + expect(subscriptions).toBe(1); + + connectable.subscribe((x: number) => { + results2.push(x); + }, done.fail, () => { + expect(results2).toEqual([3, 4]); + done(); + }); + }); + + it('should multicast an empty source', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const published = source.publishReplay(1); + const expected = '|'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a never source', () => { + const source = cold('-'); + const sourceSubs = '^'; + + const published = source.publishReplay(1); + const expected = '-'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should multicast a throw source', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const published = source.publishReplay(1); + const expected = '#'; + + expectObservable(published).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + + published.connect(); + }); + + it('should follow the RxJS 4 behavior and NOT allow you to reconnect by subscribing again', (done: DoneSignature) => { + const expected = [1, 2, 3, 4]; + let i = 0; + + const source = Observable.of(1, 2, 3, 4).publishReplay(1); + + const results = []; + + source.subscribe( + (x: number) => { + expect(x).toBe(expected[i++]); + }, + done.fail, + () => { + i = 0; + + source.subscribe((x: number) => { + results.push(x); + }, done.fail, done); + + source.connect(); + }); + + source.connect(); + + expect(results).toEqual([4]); + }); +}); \ No newline at end of file diff --git a/spec/operators/race-spec.js b/spec/operators/race-spec.js deleted file mode 100644 index 58c90ab12d..0000000000 --- a/spec/operators/race-spec.js +++ /dev/null @@ -1,149 +0,0 @@ -/* globals expect, it, describe, hot, cold, expectObservable, expectSubscriptions */ - -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('...race(observables)', function () { - it('should race cold and cold', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race hot and hot', function () { - var e1 = hot('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race hot and cold', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race 2nd and 1st', function () { - var e1 = cold('------x-----y-----z----|'); - var e1subs = '^ !'; - var e2 = cold('---a-----b-----c----|'); - var e2subs = '^ !'; - var expected = '---a-----b-----c----|'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should race emit and complete', function () { - var e1 = cold('-----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '-----|'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = cold('---a-----b-----c----|'); - var e1subs = '^ !'; - var e2 = hot('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----b---'; - var unsub = ' !'; - - var result = e1.race(e2); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c---d-| '); - var e1subs = '^ ! '; - var e2 = hot('---e-^---f--g---h-|'); - var e2subs = '^ ! '; - var expected = '---b--c--- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .race(e2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should never emit when given non emitting sources', function () { - var e1 = cold('---|'); - var e2 = cold('---|'); - var e1subs = '^ !'; - var expected = '---|'; - - var source = e1.race(e2); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should throw when error occurs mid stream', function () { - var e1 = cold('---a-----#'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---a-----#'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should throw when error occurs before a winner is found', function () { - var e1 = cold('---#'); - var e1subs = '^ !'; - var e2 = cold('------x-----y-----z----|'); - var e2subs = '^ !'; - var expected = '---#'; - - var result = e1.race(e2); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); diff --git a/spec/operators/race-spec.ts b/spec/operators/race-spec.ts new file mode 100644 index 0000000000..dfa7222839 --- /dev/null +++ b/spec/operators/race-spec.ts @@ -0,0 +1,150 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('...race(observables)', () => { + it('should race cold and cold', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race hot and hot', () => { + const e1 = hot('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race hot and cold', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race 2nd and 1st', () => { + const e1 = cold('------x-----y-----z----|'); + const e1subs = '^ !'; + const e2 = cold('---a-----b-----c----|'); + const e2subs = '^ !'; + const expected = '---a-----b-----c----|'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should race emit and complete', () => { + const e1 = cold('-----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '-----|'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = cold('---a-----b-----c----|'); + const e1subs = '^ !'; + const e2 = hot('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----b---'; + const unsub = ' !'; + + const result = e1.race(e2); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c---d-| '); + const e1subs = '^ ! '; + const e2 = hot('---e-^---f--g---h-|'); + const e2subs = '^ ! '; + const expected = '---b--c--- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .race(e2) + .mergeMap((x: string) => Observable.of(x)) + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should never emit when given non emitting sources', () => { + const e1 = cold('---|'); + const e2 = cold('---|'); + const e1subs = '^ !'; + const expected = '---|'; + + const source = e1.race(e2); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should throw when error occurs mid stream', () => { + const e1 = cold('---a-----#'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---a-----#'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should throw when error occurs before a winner is found', () => { + const e1 = cold('---#'); + const e1subs = '^ !'; + const e2 = cold('------x-----y-----z----|'); + const e2subs = '^ !'; + const expected = '---#'; + + const result = e1.race(e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); diff --git a/spec/operators/reduce-spec.js b/spec/operators/reduce-spec.js deleted file mode 100644 index a756bf3381..0000000000 --- a/spec/operators/reduce-spec.js +++ /dev/null @@ -1,232 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.reduce()', function () { - it.asDiagram('reduce((acc, curr) => acc + curr, 0)')('should reduce', function () { - var values = { - a: 1, b: 3, c: 5, x: 9 - }; - var e1 = hot('--a--b--c--|', values); - var e1subs = '^ !'; - var expected = '-----------(x|)'; - - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, 0)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should reduce with seed', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ !'; - var expected = '--------(x|)'; - - var seed = 'n'; - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected, {x: seed + 'ab'}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should reduce with seed if source is empty', function () { - var e1 = hot('--a--^-------|'); - var e1subs = '^ !'; - var expected = '--------(x|)'; - - var expectedValue = '42'; - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, expectedValue)).toBe(expected, {x: expectedValue}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if reduce function throws without seed', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ ! '; - var expected = '-----# '; - - var reduceFunction = function (o, x) { - throw 'error'; - }; - - expectObservable(e1.reduce(reduceFunction)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '------- '; - - var reduceFunction = function (o, x) { - return o + x; - }; - - var result = e1.reduce(reduceFunction); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ ! '; - var expected = '------- '; - var unsub = ' ! '; - - var reduceFunction = function (o, x) { - return o + x; - }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .reduce(reduceFunction) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source emits and raises error with seed', function () { - var e1 = hot('--a--b--#'); - var e1subs = '^ !'; - var expected = '--------#'; - - var expectedValue = '42'; - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, expectedValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source raises error with seed', function () { - var e1 = hot('----#'); - var e1subs = '^ !'; - var expected = '----#'; - - var expectedValue = '42'; - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, expectedValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if reduce function throws with seed', function () { - var e1 = hot('--a--b--|'); - var e1subs = '^ ! '; - var expected = '--# '; - - var seed = 'n'; - var reduceFunction = function (o, x) { - throw 'error'; - }; - - expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete with seed if source emits but does not completes', function () { - var e1 = hot('--a--'); - var e1subs = '^ '; - var expected = '-----'; - - var seed = 'n'; - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete with seed if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var seed = 'n'; - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete without seed if source emits but does not completes', function () { - var e1 = hot('--a--b--'); - var e1subs = '^ '; - var expected = '--------'; - - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete without seed if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should reduce if source does not emit without seed', function () { - var e1 = hot('--a--^-------|'); - var e1subs = '^ !'; - var expected = '--------|'; - - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source emits and raises error without seed', function () { - var e1 = hot('--a--b--#'); - var e1subs = '^ !'; - var expected = '--------#'; - - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source raises error without seed', function () { - var e1 = hot('----#'); - var e1subs = '^ !'; - var expected = '----#'; - - var reduceFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.reduce(reduceFunction)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/reduce-spec.ts b/spec/operators/reduce-spec.ts new file mode 100644 index 0000000000..4b6a70b3d0 --- /dev/null +++ b/spec/operators/reduce-spec.ts @@ -0,0 +1,234 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.reduce()', () => { + asDiagram('reduce((acc, curr) => acc + curr, 0)')('should reduce', () => { + const values = { + a: 1, b: 3, c: 5, x: 9 + }; + const e1 = hot('--a--b--c--|', values); + const e1subs = '^ !'; + const expected = '-----------(x|)'; + + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, 0)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should reduce with seed', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ !'; + const expected = '--------(x|)'; + + const seed = 'n'; + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected, {x: seed + 'ab'}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should reduce with seed if source is empty', () => { + const e1 = hot('--a--^-------|'); + const e1subs = '^ !'; + const expected = '--------(x|)'; + + const expectedValue = '42'; + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, expectedValue)).toBe(expected, {x: expectedValue}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if reduce function throws without seed', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ ! '; + const expected = '-----# '; + + const reduceFunction = function (o, x) { + throw 'error'; + }; + + expectObservable(e1.reduce(reduceFunction)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '------- '; + + const reduceFunction = function (o, x) { + return o + x; + }; + + const result = e1.reduce(reduceFunction); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ ! '; + const expected = '------- '; + const unsub = ' ! '; + + const reduceFunction = function (o, x) { + return o + x; + }; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .reduce(reduceFunction) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source emits and raises error with seed', () => { + const e1 = hot('--a--b--#'); + const e1subs = '^ !'; + const expected = '--------#'; + + const expectedValue = '42'; + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, expectedValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source raises error with seed', () => { + const e1 = hot('----#'); + const e1subs = '^ !'; + const expected = '----#'; + + const expectedValue = '42'; + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, expectedValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if reduce function throws with seed', () => { + const e1 = hot('--a--b--|'); + const e1subs = '^ ! '; + const expected = '--# '; + + const seed = 'n'; + const reduceFunction = function (o, x) { + throw 'error'; + }; + + expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete with seed if source emits but does not completes', () => { + const e1 = hot('--a--'); + const e1subs = '^ '; + const expected = '-----'; + + const seed = 'n'; + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete with seed if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const seed = 'n'; + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction, seed)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete without seed if source emits but does not completes', () => { + const e1 = hot('--a--b--'); + const e1subs = '^ '; + const expected = '--------'; + + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete without seed if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should reduce if source does not emit without seed', () => { + const e1 = hot('--a--^-------|'); + const e1subs = '^ !'; + const expected = '--------|'; + + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source emits and raises error without seed', () => { + const e1 = hot('--a--b--#'); + const e1subs = '^ !'; + const expected = '--------#'; + + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source raises error without seed', () => { + const e1 = hot('----#'); + const e1subs = '^ !'; + const expected = '----#'; + + const reduceFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.reduce(reduceFunction)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/refCount-spec.js b/spec/operators/refCount-spec.js deleted file mode 100644 index 47b1657ba1..0000000000 --- a/spec/operators/refCount-spec.js +++ /dev/null @@ -1,58 +0,0 @@ -/* globals describe, it, expect, Symbol */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Subject = Rx.Subject; -var Observer = Rx.Observer; - -describe('Observable.prototype.publish().refCount()', function () { - it.asDiagram('refCount')('should turn a multicasted Observable an automatically ' + - '(dis)connecting hot one', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var expected = '--1-2---3-4--5-|'; - - var result = source.publish().refCount(); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should count references', function () { - var source = Observable.never().publish().refCount(); - - var sub1 = source.subscribe({ next: function () { } }); - var sub2 = source.subscribe({ next: function () { } }); - var sub3 = source.subscribe({ next: function () { } }); - - expect(source.refCount).toBe(3); - - sub1.unsubscribe(); - sub2.unsubscribe(); - sub3.unsubscribe(); - }); - - it('should unsub from the source when all other subscriptions are unsubbed', function (done) { - var unsubscribeCalled = false; - var source = new Observable(function (observer) { - observer.next(true); - - return function () { - unsubscribeCalled = true; - }; - }).publish().refCount(); - - var sub1 = source.subscribe(function () {}); - var sub2 = source.subscribe(function () {}); - var sub3 = source.subscribe(function (x) { - expect(source.refCount).toBe(1); - }); - - sub1.unsubscribe(); - sub2.unsubscribe(); - sub3.unsubscribe(); - - expect(source.refCount).toBe(0); - expect(unsubscribeCalled).toBe(true); - done(); - }); -}); \ No newline at end of file diff --git a/spec/operators/refCount-spec.ts b/spec/operators/refCount-spec.ts new file mode 100644 index 0000000000..6c4c95c933 --- /dev/null +++ b/spec/operators/refCount-spec.ts @@ -0,0 +1,59 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const Subject = Rx.Subject; + +describe('Observable.prototype.publish().refCount()', () => { + asDiagram('refCount')('should turn a multicasted Observable an automatically ' + + '(dis)connecting hot one', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const expected = '--1-2---3-4--5-|'; + + const result = source.publish().refCount(); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should count references', () => { + const source = Observable.never().publish().refCount(); + + const sub1 = source.subscribe({ next: () => { } }); + const sub2 = source.subscribe({ next: () => { } }); + const sub3 = source.subscribe({ next: () => { } }); + + expect((source).refCount).toBe(3); + + sub1.unsubscribe(); + sub2.unsubscribe(); + sub3.unsubscribe(); + }); + + it('should unsub from the source when all other subscriptions are unsubbed', (done: DoneSignature) => { + let unsubscribeCalled = false; + const source = new Observable((observer: Rx.Observer) => { + observer.next(true); + + return () => { + unsubscribeCalled = true; + }; + }).publish().refCount(); + + const sub1 = source.subscribe(() => {}); + const sub2 = source.subscribe(() => {}); + const sub3 = source.subscribe((x: any) => { + expect((source).refCount).toBe(1); + }); + + sub1.unsubscribe(); + sub2.unsubscribe(); + sub3.unsubscribe(); + + expect((source).refCount).toBe(0); + expect(unsubscribeCalled).toBe(true); + done(); + }); +}); \ No newline at end of file diff --git a/spec/operators/repeat-spec.js b/spec/operators/repeat-spec.ts similarity index 50% rename from spec/operators/repeat-spec.js rename to spec/operators/repeat-spec.ts index 644b1b17ff..69c5fcdc93 100644 --- a/spec/operators/repeat-spec.js +++ b/spec/operators/repeat-spec.ts @@ -1,256 +1,259 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.repeat()', function () { - it.asDiagram('repeat(3)')('should resubscribe count number of times', function () { - var e1 = cold('--a--b--| '); - var subs = ['^ ! ', +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.repeat()', () => { + asDiagram('repeat(3)')('should resubscribe count number of times', () => { + const e1 = cold('--a--b--| '); + const subs = ['^ ! ', ' ^ ! ', ' ^ !']; - var expected = '--a--b----a--b----a--b--|'; + const expected = '--a--b----a--b----a--b--|'; expectObservable(e1.repeat(3)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should resubscribe multiple times', function () { - var e1 = cold('--a--b--| '); - var subs = ['^ ! ', + it('should resubscribe multiple times', () => { + const e1 = cold('--a--b--| '); + const subs = ['^ ! ', ' ^ ! ', ' ^ ! ', ' ^ !']; - var expected = '--a--b----a--b----a--b----a--b--|'; + const expected = '--a--b----a--b----a--b----a--b--|'; expectObservable(e1.repeat(2).repeat(2)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should complete without emit when count is zero', function () { - var e1 = cold('--a--b--|'); - var subs = []; - var expected = '|'; + it('should complete without emit when count is zero', () => { + const e1 = cold('--a--b--|'); + const subs = []; + const expected = '|'; expectObservable(e1.repeat(0)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should emit source once when count is one', function () { - var e1 = cold('--a--b--|'); - var subs = '^ !'; - var expected = '--a--b--|'; + it('should emit source once when count is one', () => { + const e1 = cold('--a--b--|'); + const subs = '^ !'; + const expected = '--a--b--|'; expectObservable(e1.repeat(1)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should repeat until gets unsubscribed', function () { - var e1 = cold('--a--b--| '); - var subs = ['^ ! ', + it('should repeat until gets unsubscribed', () => { + const e1 = cold('--a--b--| '); + const subs = ['^ ! ', ' ^ !']; - var unsub = ' !'; - var expected = '--a--b----a--b-'; + const unsub = ' !'; + const expected = '--a--b----a--b-'; expectObservable(e1.repeat(10), unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should be able to repeat indefinitely until unsubscribed', function () { - var e1 = cold('--a--b--| '); - var subs = ['^ ! ', + it('should be able to repeat indefinitely until unsubscribed', () => { + const e1 = cold('--a--b--| '); + const subs = ['^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ !']; - var unsub = ' !'; - var expected = '--a--b----a--b----a--b----a--b----a--b----a--'; + const unsub = ' !'; + const expected = '--a--b----a--b----a--b----a--b----a--b----a--'; expectObservable(e1.repeat(), unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = cold('--a--b--| '); - var subs = ['^ ! ', + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = cold('--a--b--| '); + const subs = ['^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ !']; - var unsub = ' !'; - var expected = '--a--b----a--b----a--b----a--b----a--b----a--'; + const unsub = ' !'; + const expected = '--a--b----a--b----a--b----a--b----a--b----a--'; - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) + const result = e1 + .mergeMap((x: string) => Observable.of(x)) .repeat() - .mergeMap(function (x) { return Observable.of(x); }); + .mergeMap((x: string) => Observable.of(x)); expectObservable(result, unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should consider negative count as repeat indefinitely', function () { - var e1 = cold('--a--b--| '); - var subs = ['^ ! ', + it('should consider negative count as repeat indefinitely', () => { + const e1 = cold('--a--b--| '); + const subs = ['^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ ! ', ' ^ !']; - var unsub = ' !'; - var expected = '--a--b----a--b----a--b----a--b----a--b----a--'; + const unsub = ' !'; + const expected = '--a--b----a--b----a--b----a--b----a--b----a--'; expectObservable(e1.repeat(-1), unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should not complete when source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; + it('should not complete when source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; expectObservable(e1.repeat(3)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should not complete when source does not completes', function () { - var e1 = cold('-'); - var unsub = ' !'; - var subs = '^ !'; - var expected = '-'; + it('should not complete when source does not completes', () => { + const e1 = cold('-'); + const unsub = ' !'; + const subs = '^ !'; + const expected = '-'; expectObservable(e1.repeat(3), unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should complete immediately when source does not complete without emit but count is zero', function () { - var e1 = cold('-'); - var subs = []; - var expected = '|'; + it('should complete immediately when source does not complete without emit but count is zero', () => { + const e1 = cold('-'); + const subs = []; + const expected = '|'; expectObservable(e1.repeat(0)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should complete immediately when source does not complete but count is zero', function () { - var e1 = cold('--a--b--'); - var subs = []; - var expected = '|'; + it('should complete immediately when source does not complete but count is zero', () => { + const e1 = cold('--a--b--'); + const subs = []; + const expected = '|'; expectObservable(e1.repeat(0)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should emit source once and does not complete when source emits but does not complete', function () { - var e1 = cold('--a--b--'); - var subs = ['^ ']; - var expected = '--a--b--'; + it('should emit source once and does not complete when source emits but does not complete', () => { + const e1 = cold('--a--b--'); + const subs = ['^ ']; + const expected = '--a--b--'; expectObservable(e1.repeat(3)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should complete when source is empty', function () { - var e1 = cold('|'); - var e1subs = ['(^!)', '(^!)', '(^!)']; - var expected = '|'; + it('should complete when source is empty', () => { + const e1 = cold('|'); + const e1subs = ['(^!)', '(^!)', '(^!)']; + const expected = '|'; expectObservable(e1.repeat(3)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should complete when source does not emit', function () { - var e1 = cold('----| '); - var subs = ['^ ! ', + it('should complete when source does not emit', () => { + const e1 = cold('----| '); + const subs = ['^ ! ', ' ^ ! ', ' ^ !']; - var expected = '------------|'; + const expected = '------------|'; expectObservable(e1.repeat(3)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should complete immediately when source does not emit but count is zero', function () { - var e1 = cold('----|'); - var subs = []; - var expected = '|'; + it('should complete immediately when source does not emit but count is zero', () => { + const e1 = cold('----|'); + const subs = []; + const expected = '|'; expectObservable(e1.repeat(0)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should raise error when source raises error', function () { - var e1 = cold('--a--b--#'); - var subs = '^ !'; - var expected = '--a--b--#'; + it('should raise error when source raises error', () => { + const e1 = cold('--a--b--#'); + const subs = '^ !'; + const expected = '--a--b--#'; expectObservable(e1.repeat(2)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(subs); }); - it('should raises error if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; + it('should raises error if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; expectObservable(e1.repeat(3)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should raises error if source throws when repeating infinitely', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; + it('should raises error if source throws when repeating infinitely', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; expectObservable(e1.repeat()).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); - it('should terminate repeat and throw if source subscription to _next throws', function () { - var e1 = Observable.of(1, 2, rxTestScheduler); - e1.subscribe(function () { throw new Error('error'); }); + it('should terminate repeat and throw if source subscription to _next throws', () => { + const e1 = Observable.of(1, 2, rxTestScheduler); + e1.subscribe(() => { throw new Error('error'); }); - expect(function () { + expect(() => { e1.repeat(3); rxTestScheduler.flush(); }).toThrow(); }); - it('should terminate repeat and throw if source subscription to _complete throws', function () { - var e1 = Observable.of(1, 2, rxTestScheduler); - e1.subscribe(function () {}, function () {}, function () { throw new Error('error'); }); + it('should terminate repeat and throw if source subscription to _complete throws', () => { + const e1 = Observable.of(1, 2, rxTestScheduler); + e1.subscribe(() => {}, () => {}, () => { throw new Error('error'); }); - expect(function () { + expect(() => { e1.repeat(3); rxTestScheduler.flush(); }).toThrow(); }); - it('should terminate repeat and throw if source subscription to _next throws when repeating infinitely', function () { - var e1 = Observable.of(1, 2, rxTestScheduler); - e1.subscribe(function () { throw new Error('error'); }); + it('should terminate repeat and throw if source subscription to _next throws when repeating infinitely', () => { + const e1 = Observable.of(1, 2, rxTestScheduler); + e1.subscribe(() => { throw new Error('error'); }); - expect(function () { + expect(() => { e1.repeat(); rxTestScheduler.flush(); }).toThrow(); }); - it('should terminate repeat and throw if source subscription to _complete throws when repeating infinitely', function () { - var e1 = Observable.of(1, 2, rxTestScheduler); - e1.subscribe(function () {}, function () {}, function () { throw new Error('error'); }); + it('should terminate repeat and throw if source subscription to _complete throws when repeating infinitely', () => { + const e1 = Observable.of(1, 2, rxTestScheduler); + e1.subscribe(() => {}, () => {}, () => { throw new Error('error'); }); - expect(function () { + expect(() => { e1.repeat(); rxTestScheduler.flush(); }).toThrow(); }); - it('should raise error after first emit succeed', function () { - var repeated = false; + it('should raise error after first emit succeed', () => { + let repeated = false; - var e1 = cold('--a--|').map(function (x) { + const e1 = cold('--a--|').map((x: string) => { if (repeated) { throw 'error'; } else { @@ -258,22 +261,22 @@ describe('Observable.prototype.repeat()', function () { return x; } }); - var expected = '--a----#'; + const expected = '--a----#'; expectObservable(e1.repeat(2)).toBe(expected); }); - it('should repeat a synchronous source (multicasted and refCounted) multiple times', function (done) { - var expected = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]; + it('should repeat a synchronous source (multicasted and refCounted) multiple times', (done: DoneSignature) => { + const expected = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]; Observable.of(1, 2, 3) - .multicast(function () { return new Rx.Subject(); }) + .multicast(() => new Rx.Subject()) .refCount() .repeat(5) .subscribe( - function (x) { expect(x).toBe(expected.shift()); }, + (x: number) => { expect(x).toBe(expected.shift()); }, done.fail, - function () { + () => { expect(expected.length).toBe(0); done(); }); diff --git a/spec/operators/retry-spec.js b/spec/operators/retry-spec.js deleted file mode 100644 index 7587e8405b..0000000000 --- a/spec/operators/retry-spec.js +++ /dev/null @@ -1,208 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.retry()', function () { - it.asDiagram('retry(2)')('should handle a basic source that emits next then errors, count=3', function () { - var source = cold('--1-2-3-#'); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '--1-2-3---1-2-3---1-2-3-#'; - - var result = source.retry(2); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should retry a number of times, without error, then complete', function (done) { - var errors = 0; - var retries = 2; - Observable.create(function (observer) { - observer.next(42); - observer.complete(); - }) - .map(function (x) { - if (++errors < retries) { - throw 'bad'; - } - errors = 0; - return x; - }) - .retry(retries) - .subscribe( - function (x) { - expect(x).toBe(42); - }, - function (err) { - expect('this was called').toBe(false); - }, done); - }); - - it('should retry a number of times, then call error handler', function (done) { - var errors = 0; - var retries = 2; - Observable.create(function (observer) { - observer.next(42); - observer.complete(); - }) - .map(function (x) { - errors += 1; - throw 'bad'; - }) - .retry(retries - 1) - .subscribe( - function (x) { - expect(x).toBe(42); - }, - function (err) { - expect(errors).toBe(2); - done(); - }, function () { - expect('this was called').toBe(false); - }); - }); - - it('should retry until successful completion', function (done) { - var errors = 0; - var retries = 10; - Observable.create(function (observer) { - observer.next(42); - observer.complete(); - }) - .map(function (x) { - if (++errors < retries) { - throw 'bad'; - } - errors = 0; - return x; - }) - .retry() - .take(retries) - .subscribe( - function (x) { - expect(x).toBe(42); - }, - function (err) { - expect('this was called').toBe(false); - }, done); - }); - - it('should handle an empty source', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '|'; - - var result = source.retry(); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a never source', function () { - var source = cold('-'); - var subs = '^'; - var expected = '-'; - - var result = source.retry(); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return a never observable given an async just-throw source and no count', function () { - var source = cold('-#'); // important that it's not a sync error - var unsub = ' !'; - var expected = '--------------------------------------'; - - var result = source.retry(); - - expectObservable(result, unsub).toBe(expected); - }); - - it('should handle a basic source that emits next then completes', function () { - var source = hot('--1--2--^--3--4--5---|'); - var subs = '^ !'; - var expected = '---3--4--5---|'; - - var result = source.retry(); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a basic source that emits next but does not complete', function () { - var source = hot('--1--2--^--3--4--5---'); - var subs = '^ '; - var expected = '---3--4--5---'; - - var result = source.retry(); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a basic source that emits next then errors, no count', function () { - var source = cold('--1-2-3-#'); - var unsub = ' !'; - var subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '--1-2-3---1-2-3---1-2-3---1-2-3---1-2-'; - - var result = source.retry(); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a source which eventually throws, count=3, and result is ' + - 'unsubscribed early', function () { - var source = cold('--1-2-3-#'); - var unsub = ' ! '; - var subs = ['^ ! ', - ' ^ ! ']; - var expected = '--1-2-3---1-2-'; - - var result = source.retry(3); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var source = cold('--1-2-3-#'); - var subs = ['^ ! ', - ' ^ ! ']; - var expected = '--1-2-3---1-2-'; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .retry(100) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should retry a synchronous source (multicasted and refCounted) multiple times', function (done) { - var expected = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]; - - Observable.of(1, 2, 3).concat(Observable.throw('bad!')) - .multicast(function () { return new Rx.Subject(); }) - .refCount() - .retry(4) - .subscribe( - function (x) { expect(x).toBe(expected.shift()); }, - function (err) { - expect(err).toBe('bad!'); - expect(expected.length).toBe(0); - done(); - }, - done.fail); - }); -}); \ No newline at end of file diff --git a/spec/operators/retry-spec.ts b/spec/operators/retry-spec.ts new file mode 100644 index 0000000000..b40b8b7e39 --- /dev/null +++ b/spec/operators/retry-spec.ts @@ -0,0 +1,210 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.retry()', () => { + asDiagram('retry(2)')('should handle a basic source that emits next then errors, count=3', () => { + const source = cold('--1-2-3-#'); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '--1-2-3---1-2-3---1-2-3-#'; + + const result = source.retry(2); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should retry a number of times, without error, then complete', (done: DoneSignature) => { + let errors = 0; + const retries = 2; + Observable.create((observer: Rx.Observer) => { + observer.next(42); + observer.complete(); + }) + .map((x: any) => { + if (++errors < retries) { + throw 'bad'; + } + errors = 0; + return x; + }) + .retry(retries) + .subscribe( + (x: number) => { + expect(x).toBe(42); + }, + (err: any) => { + expect('this was called').toBe(false); + }, done); + }); + + it('should retry a number of times, then call error handler', (done: DoneSignature) => { + let errors = 0; + const retries = 2; + Observable.create((observer: Rx.Observer) => { + observer.next(42); + observer.complete(); + }) + .map((x: any) => { + errors += 1; + throw 'bad'; + }) + .retry(retries - 1) + .subscribe( + (x: number) => { + expect(x).toBe(42); + }, + (err: any) => { + expect(errors).toBe(2); + done(); + }, () => { + expect('this was called').toBe(false); + }); + }); + + it('should retry until successful completion', (done: DoneSignature) => { + let errors = 0; + const retries = 10; + Observable.create((observer: Rx.Observer) => { + observer.next(42); + observer.complete(); + }) + .map((x: any) => { + if (++errors < retries) { + throw 'bad'; + } + errors = 0; + return x; + }) + .retry() + .take(retries) + .subscribe( + (x: number) => { + expect(x).toBe(42); + }, + (err: any) => { + expect('this was called').toBe(false); + }, done); + }); + + it('should handle an empty source', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '|'; + + const result = source.retry(); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a never source', () => { + const source = cold('-'); + const subs = '^'; + const expected = '-'; + + const result = source.retry(); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return a never observable given an async just-throw source and no count', () => { + const source = cold('-#'); // important that it's not a sync error + const unsub = ' !'; + const expected = '--------------------------------------'; + + const result = source.retry(); + + expectObservable(result, unsub).toBe(expected); + }); + + it('should handle a basic source that emits next then completes', () => { + const source = hot('--1--2--^--3--4--5---|'); + const subs = '^ !'; + const expected = '---3--4--5---|'; + + const result = source.retry(); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a basic source that emits next but does not complete', () => { + const source = hot('--1--2--^--3--4--5---'); + const subs = '^ '; + const expected = '---3--4--5---'; + + const result = source.retry(); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a basic source that emits next then errors, no count', () => { + const source = cold('--1-2-3-#'); + const unsub = ' !'; + const subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '--1-2-3---1-2-3---1-2-3---1-2-3---1-2-'; + + const result = source.retry(); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a source which eventually throws, count=3, and result is ' + + 'unsubscribed early', () => { + const source = cold('--1-2-3-#'); + const unsub = ' ! '; + const subs = ['^ ! ', + ' ^ ! ']; + const expected = '--1-2-3---1-2-'; + + const result = source.retry(3); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const source = cold('--1-2-3-#'); + const subs = ['^ ! ', + ' ^ ! ']; + const expected = '--1-2-3---1-2-'; + const unsub = ' ! '; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .retry(100) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should retry a synchronous source (multicasted and refCounted) multiple times', (done: DoneSignature) => { + const expected = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]; + + Observable.of(1, 2, 3).concat(Observable.throw('bad!')) + .multicast(() => new Rx.Subject()) + .refCount() + .retry(4) + .subscribe( + (x: number) => { expect(x).toBe(expected.shift()); }, + (err: any) => { + expect(err).toBe('bad!'); + expect(expected.length).toBe(0); + done(); + }, + done.fail); + }); +}); \ No newline at end of file diff --git a/spec/operators/retryWhen-spec.js b/spec/operators/retryWhen-spec.js deleted file mode 100644 index 6427605934..0000000000 --- a/spec/operators/retryWhen-spec.js +++ /dev/null @@ -1,335 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.retryWhen()', function () { - it.asDiagram('retryWhen')('should handle a source with eventual error using a hot notifier', function () { - var source = cold('-1--2--#'); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var notifier = hot('-------------r------------r-|'); - var expected = '-1--2---------1--2---------1|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a source with eventual error using a hot notifier that raises error', function () { - var source = cold( '-1--2--#'); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var notifier = hot('-----------r-------r---------#'); - var expected = '-1--2-------1--2----1--2-----#'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should retry when notified via returned notifier on thrown error', function (done) { - var retried = false; - var expected = [1, 2, 1, 2]; - var i = 0; - Observable.of(1, 2, 3) - .map(function (n) { - if (n === 3) { - throw 'bad'; - } - return n; - }) - .retryWhen(function (errors) { - return errors.map(function (x) { - expect(x).toBe('bad'); - if (retried) { - throw 'done'; - } - retried = true; - return x; - }); - }) - .subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, - function (err) { - expect(err).toBe('done'); - done(); - }); - }); - - it('should retry when notified and complete on returned completion', function (done) { - var expected = [1, 2, 1, 2]; - Observable.of(1, 2, 3) - .map(function (n) { - if (n === 3) { - throw 'bad'; - } - return n; - }) - .retryWhen(function (errors) { - return Observable.empty(); - }) - .subscribe(function (n) { - expect(n).toBe(expected.shift()); - }, function (err) { - throw 'error should not be called'; - }, done); - }); - - it('should apply an empty notifier on an empty source', function () { - var source = cold( '|'); - var subs = '(^!)'; - var notifier = cold('|'); - var expected = '|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should apply a never notifier on an empty source', function () { - var source = cold( '|'); - var subs = '(^!)'; - var notifier = cold('-'); - var expected = '|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should apply an empty notifier on a never source', function () { - var source = cold( '-'); - var unsub = ' !'; - var subs = '^ !'; - var notifier = cold('|'); - var expected = '-'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should apply a never notifier on a never source', function () { - var source = cold( '-'); - var unsub = ' !'; - var subs = '^ !'; - var notifier = cold('-'); - var expected = '-'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return an empty observable given a just-throw source and empty notifier', function () { - var source = cold( '#'); - var notifier = cold('|'); - var expected = '|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - }); - - it('should return a never observable given a just-throw source and never notifier', function () { - var source = cold( '#'); - var notifier = cold('-'); - var expected = '-'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - }); - - it('should hide errors using a never notifier on a source with eventual error', function () { - var source = cold( '--a--b--c--#'); - var subs = '^ !'; - var notifier = cold( '-'); - var expected = '--a--b--c---------------------------------'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should propagate error thrown from notifierSelector function', function () { - var source = cold('--a--b--c--#'); - var subs = '^ !'; - var expected = '--a--b--c--#'; - - var result = source.retryWhen(function () { throw 'bad!'; }); - - expectObservable(result).toBe(expected, undefined, 'bad!'); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should replace error with complete using an empty notifier on a source ' + - 'with eventual error', function () { - var source = cold( '--a--b--c--#'); - var subs = '^ !'; - var notifier = cold( '|'); - var expected = '--a--b--c--|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should mirror a basic cold source with complete, given a never notifier', function () { - var source = cold( '--a--b--c--|'); - var subs = '^ !'; - var notifier = cold( '|'); - var expected = '--a--b--c--|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should mirror a basic cold source with no termination, given a never notifier', function () { - var source = cold( '--a--b--c---'); - var subs = '^ '; - var notifier = cold( '|'); - var expected = '--a--b--c---'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should mirror a basic hot source with complete, given a never notifier', function () { - var source = hot('-a-^--b--c--|'); - var subs = '^ !'; - var notifier = cold( '|'); - var expected = '---b--c--|'; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a hot source that raises error but eventually completes', function () { - var source = hot('-1--2--3----4--5---|'); - var ssubs = ['^ ! ', - ' ^ !']; - var notifier = hot('--------------r--------r---r--r--r---|'); - var nsubs = ' ^ !'; - var expected = '-1--2--- -5---|'; - - var result = source - .map(function (x) { - if (x === '3') { - throw 'error'; - } - return x; - }) - .retryWhen(function () { - return notifier; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(ssubs); - expectSubscriptions(notifier.subscriptions).toBe(nsubs); - }); - - it('should tear down resources when result is unsubscribed early', function () { - var source = cold( '-1--2--#'); - var unsub = ' ! '; - var subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var notifier = hot('---------r-------r---------#'); - var nsubs = ' ^ ! '; - var expected = '-1--2-----1--2----1-- '; - - var result = source.retryWhen(function (errors) { return notifier; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(notifier.subscriptions).toBe(nsubs); - }); - - it('should not break unsubscription chains when unsubscribed explicitly', function () { - var source = cold( '-1--2--#'); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var notifier = hot('---------r-------r-------r-#'); - var nsubs = ' ^ ! '; - var expected = '-1--2-----1--2----1-- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .retryWhen(function (errors) { return notifier; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(notifier.subscriptions).toBe(nsubs); - }); - - it('should handle a source with eventual error using a dynamic notifier ' + - 'selector which eventually throws', function () { - var source = cold('-1--2--#'); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-1--2---1--2---1--2--#'; - - var invoked = 0; - var result = source.retryWhen(function (errors) { - return errors.map(function (err) { - if (++invoked === 3) { - throw 'error'; - } else { - return 'x'; - } - }); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle a source with eventual error using a dynamic notifier ' + - 'selector which eventually completes', function () { - var source = cold('-1--2--#'); - var subs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var expected = '-1--2---1--2---1--2--|'; - - var invoked = 0; - var result = source.retryWhen(function (errors) { - return errors - .map(function () { return 'x'; }) - .takeUntil( - errors.flatMap(function () { - if (++invoked < 3) { - return Observable.empty(); - } else { - return Observable.of('stop!'); - } - }) - ); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/retryWhen-spec.ts b/spec/operators/retryWhen-spec.ts new file mode 100644 index 0000000000..f0f9af0699 --- /dev/null +++ b/spec/operators/retryWhen-spec.ts @@ -0,0 +1,327 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.retryWhen()', () => { + asDiagram('retryWhen')('should handle a source with eventual error using a hot notifier', () => { + const source = cold('-1--2--#'); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const notifier = hot('-------------r------------r-|'); + const expected = '-1--2---------1--2---------1|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a source with eventual error using a hot notifier that raises error', () => { + const source = cold( '-1--2--#'); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const notifier = hot('-----------r-------r---------#'); + const expected = '-1--2-------1--2----1--2-----#'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should retry when notified via returned notifier on thrown error', (done: DoneSignature) => { + let retried = false; + const expected = [1, 2, 1, 2]; + let i = 0; + Observable.of(1, 2, 3) + .map((n: number) => { + if (n === 3) { + throw 'bad'; + } + return n; + }) + .retryWhen((errors: any) => errors.map((x: any) => { + expect(x).toBe('bad'); + if (retried) { + throw 'done'; + } + retried = true; + return x; + })) + .subscribe((x: any) => { + expect(x).toBe(expected[i++]); + }, + (err: any) => { + expect(err).toBe('done'); + done(); + }); + }); + + it('should retry when notified and complete on returned completion', (done: DoneSignature) => { + const expected = [1, 2, 1, 2]; + Observable.of(1, 2, 3) + .map((n: number) => { + if (n === 3) { + throw 'bad'; + } + return n; + }) + .retryWhen((errors: any) => Observable.empty()) + .subscribe((n: number) => { + expect(n).toBe(expected.shift()); + }, (err: any) => { + done.fail('error should not be called'); + }, done); + }); + + it('should apply an empty notifier on an empty source', () => { + const source = cold( '|'); + const subs = '(^!)'; + const notifier = cold('|'); + const expected = '|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should apply a never notifier on an empty source', () => { + const source = cold( '|'); + const subs = '(^!)'; + const notifier = cold('-'); + const expected = '|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should apply an empty notifier on a never source', () => { + const source = cold( '-'); + const unsub = ' !'; + const subs = '^ !'; + const notifier = cold('|'); + const expected = '-'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should apply a never notifier on a never source', () => { + const source = cold( '-'); + const unsub = ' !'; + const subs = '^ !'; + const notifier = cold('-'); + const expected = '-'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return an empty observable given a just-throw source and empty notifier', () => { + const source = cold( '#'); + const notifier = cold('|'); + const expected = '|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + }); + + it('should return a never observable given a just-throw source and never notifier', () => { + const source = cold( '#'); + const notifier = cold('-'); + const expected = '-'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + }); + + it('should hide errors using a never notifier on a source with eventual error', () => { + const source = cold( '--a--b--c--#'); + const subs = '^ !'; + const notifier = cold( '-'); + const expected = '--a--b--c---------------------------------'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should propagate error thrown from notifierSelector function', () => { + const source = cold('--a--b--c--#'); + const subs = '^ !'; + const expected = '--a--b--c--#'; + + const result = source.retryWhen((() => { throw 'bad!'; })); + + expectObservable(result).toBe(expected, undefined, 'bad!'); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should replace error with complete using an empty notifier on a source ' + + 'with eventual error', () => { + const source = cold( '--a--b--c--#'); + const subs = '^ !'; + const notifier = cold( '|'); + const expected = '--a--b--c--|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should mirror a basic cold source with complete, given a never notifier', () => { + const source = cold( '--a--b--c--|'); + const subs = '^ !'; + const notifier = cold( '|'); + const expected = '--a--b--c--|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should mirror a basic cold source with no termination, given a never notifier', () => { + const source = cold( '--a--b--c---'); + const subs = '^ '; + const notifier = cold( '|'); + const expected = '--a--b--c---'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should mirror a basic hot source with complete, given a never notifier', () => { + const source = hot('-a-^--b--c--|'); + const subs = '^ !'; + const notifier = cold( '|'); + const expected = '---b--c--|'; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a hot source that raises error but eventually completes', () => { + const source = hot('-1--2--3----4--5---|'); + const ssubs = ['^ ! ', + ' ^ !']; + const notifier = hot('--------------r--------r---r--r--r---|'); + const nsubs = ' ^ !'; + const expected = '-1--2--- -5---|'; + + const result = source + .map((x: string) => { + if (x === '3') { + throw 'error'; + } + return x; + }).retryWhen(() => notifier); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(ssubs); + expectSubscriptions(notifier.subscriptions).toBe(nsubs); + }); + + it('should tear down resources when result is unsubscribed early', () => { + const source = cold( '-1--2--#'); + const unsub = ' ! '; + const subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const notifier = hot('---------r-------r---------#'); + const nsubs = ' ^ ! '; + const expected = '-1--2-----1--2----1-- '; + + const result = source.retryWhen((errors: any) => notifier); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(notifier.subscriptions).toBe(nsubs); + }); + + it('should not break unsubscription chains when unsubscribed explicitly', () => { + const source = cold( '-1--2--#'); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const notifier = hot('---------r-------r-------r-#'); + const nsubs = ' ^ ! '; + const expected = '-1--2-----1--2----1-- '; + const unsub = ' ! '; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .retryWhen((errors: any) => notifier) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(notifier.subscriptions).toBe(nsubs); + }); + + it('should handle a source with eventual error using a dynamic notifier ' + + 'selector which eventually throws', () => { + const source = cold('-1--2--#'); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-1--2---1--2---1--2--#'; + + let invoked = 0; + const result = source.retryWhen((errors: any) => + errors.map((err: any) => { + if (++invoked === 3) { + throw 'error'; + } else { + return 'x'; + } + })); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle a source with eventual error using a dynamic notifier ' + + 'selector which eventually completes', () => { + const source = cold('-1--2--#'); + const subs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const expected = '-1--2---1--2---1--2--|'; + + let invoked = 0; + const result = source.retryWhen((errors: any) => errors + .map(() => 'x') + .takeUntil( + errors.flatMap(() => { + if (++invoked < 3) { + return Observable.empty(); + } else { + return Observable.of('stop!'); + } + }) + )); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/sample-spec.js b/spec/operators/sample-spec.js deleted file mode 100644 index e94674537c..0000000000 --- a/spec/operators/sample-spec.js +++ /dev/null @@ -1,204 +0,0 @@ -/* globals describe, it, expect, hot, expectObservable,, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.sample', function () { - it.asDiagram('sample')('should get samples when the notifier emits', function () { - var e1 = hot('---a----b---c----------d-----| '); - var e1subs = '^ ! '; - var e2 = hot('-----x----------x---x------x---|'); - var e2subs = '^ ! '; - var expected = '-----a----------c----------d-| '; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should sample nothing if source has not nexted at all', function () { - var e1 = hot('----a-^------------|'); - var e1subs = '^ !'; - var e2 = hot( '-----x-------|'); - var e2subs = '^ !'; - var expected = '-------------|'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should sample nothing if source has nexted after all notifications, but notifier does not complete', function () { - var e1 = hot('----a-^------b-----|'); - var e1subs = '^ !'; - var e2 = hot( '-----x--------'); - var e2subs = '^ !'; - var expected = '-------------|'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should sample when the notifier completes', function () { - var e1 = hot('----a-^------b----------|'); - var e1subs = '^ !'; - var e2 = hot( '-----x-----|'); - var e2subs = '^ !'; - var expected = '-----------b------|'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete when the notifier completes, nor should it emit', function () { - var e1 = hot('----a----b----c----d----e----f----'); - var e1subs = '^ '; - var e2 = hot('------x-| '); - var e2subs = '^ ! '; - var expected = '------a---------------------------'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should complete only when the source completes, if notifier completes early', function () { - var e1 = hot('----a----b----c----d----e----f---|'); - var e1subs = '^ !'; - var e2 = hot('------x-| '); - var e2subs = '^ ! '; - var expected = '------a--------------------------|'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('----a-^--b----c----d----e----f----| '); - var unsub = ' ! '; - var e1subs = '^ ! '; - var e2 = hot( '-----x----------x----------x----------|'); - var e2subs = '^ ! '; - var expected = '-----b--------- '; - - expectObservable(e1.sample(e2), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('----a-^--b----c----d----e----f----| '); - var e1subs = '^ ! '; - var e2 = hot( '-----x----------x----------x----------|'); - var e2subs = '^ ! '; - var expected = '-----b--------- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .sample(e2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should only sample when a new value arrives, even if it is the same value', function () { - var e1 = hot('----a----b----c----c----e----f----| '); - var e1subs = '^ ! '; - var e2 = hot('------x-x------xx-x---x----x--------|'); - var e2subs = '^ ! '; - var expected = '------a--------c------c----e------| '; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error if source raises error', function () { - var e1 = hot('----a-^--b----c----d----# '); - var e1subs = '^ ! '; - var e2 = hot( '-----x----------x----------x----------|'); - var e2subs = '^ ! '; - var expected = '-----b----------d-# '; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should completes if source does not emits', function () { - var e1 = hot('|'); - var e2 = hot('------x-------|'); - var expected = '|'; - var e1subs = '(^!)'; - var e2subs = '(^!)'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error if source throws immediately', function () { - var e1 = hot('#'); - var e2 = hot('------x-------|'); - var expected = '#'; - var e1subs = '(^!)'; - var e2subs = '(^!)'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error if notification raises error', function () { - var e1 = hot('--a-----|'); - var e2 = hot('----#'); - var expected = '----#'; - var e1subs = '^ !'; - var e2subs = '^ !'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not completes if source does not complete', function () { - var e1 = hot('-'); - var e1subs = '^ '; - var e2 = hot('------x-------|'); - var e2subs = '^ !'; - var expected = '-'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should sample only until source completes', function () { - var e1 = hot('----a----b----c----d-|'); - var e1subs = '^ !'; - var e2 = hot('-----------x----------x------------|'); - var e2subs = '^ !'; - var expected = '-----------b---------|'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should complete sampling if sample observable completes', function () { - var e1 = hot('----a----b----c----d-|'); - var e1subs = '^ !'; - var e2 = hot('|'); - var e2subs = '(^!)'; - var expected = '---------------------|'; - - expectObservable(e1.sample(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/sample-spec.ts b/spec/operators/sample-spec.ts new file mode 100644 index 0000000000..48cf585893 --- /dev/null +++ b/spec/operators/sample-spec.ts @@ -0,0 +1,206 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.sample', () => { + asDiagram('sample')('should get samples when the notifier emits', () => { + const e1 = hot('---a----b---c----------d-----| '); + const e1subs = '^ ! '; + const e2 = hot('-----x----------x---x------x---|'); + const e2subs = '^ ! '; + const expected = '-----a----------c----------d-| '; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should sample nothing if source has not nexted at all', () => { + const e1 = hot('----a-^------------|'); + const e1subs = '^ !'; + const e2 = hot( '-----x-------|'); + const e2subs = '^ !'; + const expected = '-------------|'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should sample nothing if source has nexted after all notifications, but notifier does not complete', () => { + const e1 = hot('----a-^------b-----|'); + const e1subs = '^ !'; + const e2 = hot( '-----x--------'); + const e2subs = '^ !'; + const expected = '-------------|'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should sample when the notifier completes', () => { + const e1 = hot('----a-^------b----------|'); + const e1subs = '^ !'; + const e2 = hot( '-----x-----|'); + const e2subs = '^ !'; + const expected = '-----------b------|'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete when the notifier completes, nor should it emit', () => { + const e1 = hot('----a----b----c----d----e----f----'); + const e1subs = '^ '; + const e2 = hot('------x-| '); + const e2subs = '^ ! '; + const expected = '------a---------------------------'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should complete only when the source completes, if notifier completes early', () => { + const e1 = hot('----a----b----c----d----e----f---|'); + const e1subs = '^ !'; + const e2 = hot('------x-| '); + const e2subs = '^ ! '; + const expected = '------a--------------------------|'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('----a-^--b----c----d----e----f----| '); + const unsub = ' ! '; + const e1subs = '^ ! '; + const e2 = hot( '-----x----------x----------x----------|'); + const e2subs = '^ ! '; + const expected = '-----b--------- '; + + expectObservable(e1.sample(e2), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('----a-^--b----c----d----e----f----| '); + const e1subs = '^ ! '; + const e2 = hot( '-----x----------x----------x----------|'); + const e2subs = '^ ! '; + const expected = '-----b--------- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .sample(e2) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should only sample when a new value arrives, even if it is the same value', () => { + const e1 = hot('----a----b----c----c----e----f----| '); + const e1subs = '^ ! '; + const e2 = hot('------x-x------xx-x---x----x--------|'); + const e2subs = '^ ! '; + const expected = '------a--------c------c----e------| '; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error if source raises error', () => { + const e1 = hot('----a-^--b----c----d----# '); + const e1subs = '^ ! '; + const e2 = hot( '-----x----------x----------x----------|'); + const e2subs = '^ ! '; + const expected = '-----b----------d-# '; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should completes if source does not emits', () => { + const e1 = hot('|'); + const e2 = hot('------x-------|'); + const expected = '|'; + const e1subs = '(^!)'; + const e2subs = '(^!)'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error if source throws immediately', () => { + const e1 = hot('#'); + const e2 = hot('------x-------|'); + const expected = '#'; + const e1subs = '(^!)'; + const e2subs = '(^!)'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error if notification raises error', () => { + const e1 = hot('--a-----|'); + const e2 = hot('----#'); + const expected = '----#'; + const e1subs = '^ !'; + const e2subs = '^ !'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not completes if source does not complete', () => { + const e1 = hot('-'); + const e1subs = '^ '; + const e2 = hot('------x-------|'); + const e2subs = '^ !'; + const expected = '-'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should sample only until source completes', () => { + const e1 = hot('----a----b----c----d-|'); + const e1subs = '^ !'; + const e2 = hot('-----------x----------x------------|'); + const e2subs = '^ !'; + const expected = '-----------b---------|'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should complete sampling if sample observable completes', () => { + const e1 = hot('----a----b----c----d-|'); + const e1subs = '^ !'; + const e2 = hot('|'); + const e2subs = '(^!)'; + const expected = '---------------------|'; + + expectObservable(e1.sample(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/sampleTime-spec.js b/spec/operators/sampleTime-spec.js deleted file mode 100644 index 3d24d3324a..0000000000 --- a/spec/operators/sampleTime-spec.js +++ /dev/null @@ -1,109 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.sampleTime', function () { - it.asDiagram('sampleTime(110)')('should get samples on a delay', function () { - var e1 = hot('----a-^--b----c----d----e----f----|'); - var e1subs = '^ !'; - var expected = '-----------c----------e-----|'; - // timer -----------!----------!--------- - - expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should sample nothing if new value has not arrived', function () { - var e1 = hot('----a-^--b----c--------------f----|'); - var e1subs = '^ !'; - var expected = '-----------c----------------|'; - // timer -----------!----------!--------- - - expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should sample if new value has arrived, even if it is the same value', function () { - var e1 = hot('----a-^--b----c----------c---f----|'); - var e1subs = '^ !'; - var expected = '-----------c----------c-----|'; - // timer -----------!----------!--------- - - expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should sample nothing if source has not nexted by time of sample', function () { - var e1 = hot('----a-^-------------b-------------|'); - var e1subs = '^ !'; - var expected = '----------------------b-----|'; - // timer -----------!----------!--------- - - expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source raises error', function () { - var e1 = hot('----a-^--b----c----d----#'); - var e1subs = '^ !'; - var expected = '-----------c------#'; - // timer -----------!----------!--------- - - expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('----a-^--b----c----d----e----f----|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '-----------c----- '; - // timer -----------!----------!--------- - - expectObservable(e1.sampleTime(110, rxTestScheduler), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('----a-^--b----c----d----e----f----|'); - var e1subs = '^ ! '; - // timer -----------!----------!--------- - var expected = '-----------c----- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .sampleTime(110, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should completes if source does not emits', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.sampleTime(60, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source throws immediately', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.sampleTime(60, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source does not complete', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.sampleTime(60, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/sampleTime-spec.ts b/spec/operators/sampleTime-spec.ts new file mode 100644 index 0000000000..97a824bc76 --- /dev/null +++ b/spec/operators/sampleTime-spec.ts @@ -0,0 +1,112 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.sampleTime', () => { + asDiagram('sampleTime(110)')('should get samples on a delay', () => { + const e1 = hot('----a-^--b----c----d----e----f----|'); + const e1subs = '^ !'; + const expected = '-----------c----------e-----|'; + // timer -----------!----------!--------- + + expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should sample nothing if new value has not arrived', () => { + const e1 = hot('----a-^--b----c--------------f----|'); + const e1subs = '^ !'; + const expected = '-----------c----------------|'; + // timer -----------!----------!--------- + + expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should sample if new value has arrived, even if it is the same value', () => { + const e1 = hot('----a-^--b----c----------c---f----|'); + const e1subs = '^ !'; + const expected = '-----------c----------c-----|'; + // timer -----------!----------!--------- + + expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should sample nothing if source has not nexted by time of sample', () => { + const e1 = hot('----a-^-------------b-------------|'); + const e1subs = '^ !'; + const expected = '----------------------b-----|'; + // timer -----------!----------!--------- + + expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source raises error', () => { + const e1 = hot('----a-^--b----c----d----#'); + const e1subs = '^ !'; + const expected = '-----------c------#'; + // timer -----------!----------!--------- + + expectObservable(e1.sampleTime(110, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('----a-^--b----c----d----e----f----|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '-----------c----- '; + // timer -----------!----------!--------- + + expectObservable(e1.sampleTime(110, rxTestScheduler), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('----a-^--b----c----d----e----f----|'); + const e1subs = '^ ! '; + // timer -----------!----------!--------- + const expected = '-----------c----- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .sampleTime(110, rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should completes if source does not emits', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.sampleTime(60, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source throws immediately', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.sampleTime(60, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source does not complete', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.sampleTime(60, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/scan-spec.js b/spec/operators/scan-spec.js deleted file mode 100644 index 4ca54a305c..0000000000 --- a/spec/operators/scan-spec.js +++ /dev/null @@ -1,177 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.scan()', function () { - it.asDiagram('scan((acc, curr) => acc + curr, 0)')('should scan', function () { - var values = { - a: 1, b: 3, c: 5, - x: 1, y: 4, z: 9 - }; - var e1 = hot('--a--b--c--|', values); - var e1subs = '^ !'; - var expected = '--x--y--z--|'; - - var scanFunction = function (o, x) { - return o + x; - }; - - expectObservable(e1.scan(scanFunction, 0)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should scan things', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var expected = '---u--v--w--x--y--z--|'; - - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1.scan(function (acc, x) { return [].concat(acc, x); }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should scan without seed', function () { - var e1 = hot('--a--^--b--c--d--|'); - var e1subs = '^ !'; - var expected = '---x--y--z--|'; - - var values = { - x: 'b', - y: 'bc', - z: 'bcd' - }; - - var source = e1.scan(function (acc, x) { return acc + x; }); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle errors', function () { - var e1 = hot('--a--^--b--c--d--#'); - var e1subs = '^ !'; - var expected = '---u--v--w--#'; - - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'] - }; - - var source = e1.scan(function (acc, x) { return [].concat(acc, x); }, []); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle errors in the projection function', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var expected = '---u--v--# '; - - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1.scan(function (acc, x) { - if (x === 'd') { - throw 'bad!'; - } - return [].concat(acc, x); - }, []); - - expectObservable(source).toBe(expected, values, 'bad!'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - var source = e1.scan(function (acc, x) { return [].concat(acc, x); }, []); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var source = e1.scan(function (acc, x) { return [].concat(acc, x); }, []); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - var source = e1.scan(function (acc, x) { return [].concat(acc, x); }, []); - - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---u--v--w--x-- '; - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1.scan(function (acc, x) { return [].concat(acc, x); }, []); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var expected = '---u--v--w--x-- '; - var unsub = ' ! '; - var values = { - u: ['b'], - v: ['b', 'c'], - w: ['b', 'c', 'd'], - x: ['b', 'c', 'd', 'e'], - y: ['b', 'c', 'd', 'e', 'f'], - z: ['b', 'c', 'd', 'e', 'f', 'g'] - }; - - var source = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .scan(function (acc, x) { return [].concat(acc, x); }, []) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(source, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/scan-spec.ts b/spec/operators/scan-spec.ts new file mode 100644 index 0000000000..d28031ece2 --- /dev/null +++ b/spec/operators/scan-spec.ts @@ -0,0 +1,179 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.scan()', () => { + asDiagram('scan((acc, curr) => acc + curr, 0)')('should scan', () => { + const values = { + a: 1, b: 3, c: 5, + x: 1, y: 4, z: 9 + }; + const e1 = hot('--a--b--c--|', values); + const e1subs = '^ !'; + const expected = '--x--y--z--|'; + + const scanFunction = function (o, x) { + return o + x; + }; + + expectObservable(e1.scan(scanFunction, 0)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should scan things', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const expected = '---u--v--w--x--y--z--|'; + + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = e1.scan((acc: any, x: string) => [].concat(acc, x), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should scan without seed', () => { + const e1 = hot('--a--^--b--c--d--|'); + const e1subs = '^ !'; + const expected = '---x--y--z--|'; + + const values = { + x: 'b', + y: 'bc', + z: 'bcd' + }; + + const source = e1.scan((acc: any, x: string) => acc + x); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle errors', () => { + const e1 = hot('--a--^--b--c--d--#'); + const e1subs = '^ !'; + const expected = '---u--v--w--#'; + + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'] + }; + + const source = e1.scan((acc: any, x: string) => [].concat(acc, x), []); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle errors in the projection function', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const expected = '---u--v--# '; + + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = e1.scan((acc: any, x: string) => { + if (x === 'd') { + throw 'bad!'; + } + return [].concat(acc, x); + }, []); + + expectObservable(source).toBe(expected, values, 'bad!'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + const source = e1.scan((acc: any, x: string) => [].concat(acc, x), []); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const source = e1.scan((acc: any, x: string) => [].concat(acc, x), []); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + const source = e1.scan((acc: any, x: string) => [].concat(acc, x), []); + + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---u--v--w--x-- '; + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = e1.scan((acc: any, x: string) => [].concat(acc, x), []); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const expected = '---u--v--w--x-- '; + const unsub = ' ! '; + const values = { + u: ['b'], + v: ['b', 'c'], + w: ['b', 'c', 'd'], + x: ['b', 'c', 'd', 'e'], + y: ['b', 'c', 'd', 'e', 'f'], + z: ['b', 'c', 'd', 'e', 'f', 'g'] + }; + + const source = e1 + .mergeMap((x: string) => Observable.of(x)) + .scan((acc: any, x: string) => [].concat(acc, x), []) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(source, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/share-spec.js b/spec/operators/share-spec.js deleted file mode 100644 index 84a00d02e0..0000000000 --- a/spec/operators/share-spec.js +++ /dev/null @@ -1,309 +0,0 @@ -/* globals describe, expect, it, hot, cold, expectObservable, expectSubscriptions */ - -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.share()', function () { - it.asDiagram('share')('should mirror a simple source Observable', function () { - var source = cold('--1-2---3-4--5-|'); - var sourceSubs = '^ !'; - var expected = '--1-2---3-4--5-|'; - - var shared = source.share(); - - expectObservable(shared).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should share a single subscription', function () { - var subscriptionCount = 0; - var obs = new Observable(function (observer) { - subscriptionCount++; - }); - - var source = obs.share(); - - expect(subscriptionCount).toBe(0); - - source.subscribe(); - source.subscribe(); - - expect(subscriptionCount).toBe(1); - }); - - it('should not change the output of the observable when error', function () { - var e1 = hot('---a--^--b--c--d--e--#'); - var e1subs = '^ !'; - var expected = '---b--c--d--e--#'; - - expectObservable(e1.share()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not change the output of the observable when successful with cold observable', function () { - var e1 = cold('---a--b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '---a--b--c--d--e--|'; - - expectObservable(e1.share()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not change the output of the observable when error with cold observable', function () { - var e1 = cold('---a--b--c--d--e--#'); - var e1subs = '^ !'; - var expected = '---a--b--c--d--e--#'; - - expectObservable(e1.share()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should retry just fine', function () { - var e1 = cold('---a--b--c--d--e--#'); - var e1subs = ['^ ! ', - ' ^ !']; - var expected = '---a--b--c--d--e-----a--b--c--d--e--#'; - - expectObservable(e1.share().retry(1)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should share the same values to multiple observers', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ !'; - var shared = source.share(); - var subscriber1 = hot('a| ').mergeMapTo(shared); - var expected1 = '-1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(shared); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(shared); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should share an error from the source to multiple observers', function () { - var source = cold('-1-2-3----4-#'); - var sourceSubs = '^ !'; - var shared = source.share(); - var subscriber1 = hot('a| ').mergeMapTo(shared); - var expected1 = '-1-2-3----4-#'; - var subscriber2 = hot(' b| ').mergeMapTo(shared); - var expected2 = ' -3----4-#'; - var subscriber3 = hot(' c| ').mergeMapTo(shared); - var expected3 = ' --4-#'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should share the same values to multiple observers, ' + - 'but is unsubscribed explicitly and early', function () { - var source = cold('-1-2-3----4-|'); - var sourceSubs = '^ ! '; - var shared = source.share(); - var unsub = ' ! '; - var subscriber1 = hot('a| ').mergeMapTo(shared); - var expected1 = '-1-2-3---- '; - var subscriber2 = hot(' b| ').mergeMapTo(shared); - var expected2 = ' -3---- '; - var subscriber3 = hot(' c| ').mergeMapTo(shared); - var expected3 = ' -- '; - - expectObservable(subscriber1, unsub).toBe(expected1); - expectObservable(subscriber2, unsub).toBe(expected2); - expectObservable(subscriber3, unsub).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should share an empty source', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var shared = source.share(); - var expected = '|'; - - expectObservable(shared).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should share a never source', function () { - var source = cold('-'); - var sourceSubs = '^'; - var shared = source.share(); - var expected = '-'; - - expectObservable(shared).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should share a throw source', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var shared = source.share(); - var expected = '#'; - - expectObservable(shared).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should connect when first subscriber subscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ !'; - var shared = source.share(); - var subscriber1 = hot(' a| ').mergeMapTo(shared); - var expected1 = ' -1-2-3----4-|'; - var subscriber2 = hot(' b| ').mergeMapTo(shared); - var expected2 = ' -3----4-|'; - var subscriber3 = hot(' c| ').mergeMapTo(shared); - var expected3 = ' --4-|'; - - expectObservable(subscriber1).toBe(expected1); - expectObservable(subscriber2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should disconnect when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var shared = source.share(); - var subscriber1 = hot(' a| ').mergeMapTo(shared); - var unsub1 = ' ! '; - var expected1 = ' -1-2-3-- '; - var subscriber2 = hot(' b| ').mergeMapTo(shared); - var unsub2 = ' ! '; - var expected2 = ' -3---- '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not break unsubscription chain when last subscriber unsubscribes', function () { - var source = cold( '-1-2-3----4-|'); - var sourceSubs = ' ^ ! '; - var shared = source - .mergeMap(function (x) { return Observable.of(x); }) - .share() - .mergeMap(function (x) { return Observable.of(x); }); - var subscriber1 = hot(' a| ').mergeMapTo(shared); - var unsub1 = ' ! '; - var expected1 = ' -1-2-3-- '; - var subscriber2 = hot(' b| ').mergeMapTo(shared); - var unsub2 = ' ! '; - var expected2 = ' -3---- '; - - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be retryable when cold source is synchronous', function () { - var source = cold('(123#)'); - var shared = source.share(); - var subscribe1 = 's '; - var expected1 = '(123123#) '; - var subscribe2 = ' s '; - var expected2 = ' (123123#)'; - var sourceSubs = ['(^!)', - '(^!)', - ' (^!)', - ' (^!)']; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(shared.retry(1)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(shared.retry(1)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be repeatable when cold source is synchronous', function () { - var source = cold('(123|)'); - var shared = source.share(); - var subscribe1 = 's '; - var expected1 = '(123123|) '; - var subscribe2 = ' s '; - var expected2 = ' (123123|)'; - var sourceSubs = ['(^!)', - '(^!)', - ' (^!)', - ' (^!)']; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(shared.repeat(2)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(shared.repeat(2)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be retryable', function () { - var source = cold('-1-2-3----4-# '); - var sourceSubs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var shared = source.share(); - var subscribe1 = 's '; - var expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-#'; - var subscribe2 = ' s '; - var expected2 = ' -3----4--1-2-3----4--1-2-3----4-#'; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(shared.retry(2)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(shared.retry(2)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be repeatable', function () { - var source = cold('-1-2-3----4-| '); - var sourceSubs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var shared = source.share(); - var subscribe1 = 's '; - var expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-|'; - var subscribe2 = ' s '; - var expected2 = ' -3----4--1-2-3----4--1-2-3----4-|'; - - expectObservable(hot(subscribe1).do(function () { - expectObservable(shared.repeat(3)).toBe(expected1); - })).toBe(subscribe1); - - expectObservable(hot(subscribe2).do(function () { - expectObservable(shared.repeat(3)).toBe(expected2); - })).toBe(subscribe2); - - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not change the output of the observable when never', function () { - var e1 = Observable.never(); - var expected = '-'; - - expectObservable(e1.share()).toBe(expected); - }); - - it('should not change the output of the observable when empty', function () { - var e1 = Observable.empty(); - var expected = '|'; - - expectObservable(e1.share()).toBe(expected); - }); -}); diff --git a/spec/operators/share-spec.ts b/spec/operators/share-spec.ts new file mode 100644 index 0000000000..fd40a5e0e0 --- /dev/null +++ b/spec/operators/share-spec.ts @@ -0,0 +1,310 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.share()', () => { + asDiagram('share')('should mirror a simple source Observable', () => { + const source = cold('--1-2---3-4--5-|'); + const sourceSubs = '^ !'; + const expected = '--1-2---3-4--5-|'; + + const shared = source.share(); + + expectObservable(shared).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should share a single subscription', () => { + let subscriptionCount = 0; + const obs = new Observable((observer: Rx.Observer) => { + subscriptionCount++; + }); + + const source = obs.share(); + + expect(subscriptionCount).toBe(0); + + source.subscribe(); + source.subscribe(); + + expect(subscriptionCount).toBe(1); + }); + + it('should not change the output of the observable when error', () => { + const e1 = hot('---a--^--b--c--d--e--#'); + const e1subs = '^ !'; + const expected = '---b--c--d--e--#'; + + expectObservable(e1.share()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not change the output of the observable when successful with cold observable', () => { + const e1 = cold('---a--b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '---a--b--c--d--e--|'; + + expectObservable(e1.share()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not change the output of the observable when error with cold observable', () => { + const e1 = cold('---a--b--c--d--e--#'); + const e1subs = '^ !'; + const expected = '---a--b--c--d--e--#'; + + expectObservable(e1.share()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should retry just fine', () => { + const e1 = cold('---a--b--c--d--e--#'); + const e1subs = ['^ ! ', + ' ^ !']; + const expected = '---a--b--c--d--e-----a--b--c--d--e--#'; + + expectObservable(e1.share().retry(1)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should share the same values to multiple observers', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ !'; + const shared = source.share(); + const subscriber1 = hot('a| ').mergeMapTo(shared); + const expected1 = '-1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(shared); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(shared); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should share an error from the source to multiple observers', () => { + const source = cold('-1-2-3----4-#'); + const sourceSubs = '^ !'; + const shared = source.share(); + const subscriber1 = hot('a| ').mergeMapTo(shared); + const expected1 = '-1-2-3----4-#'; + const subscriber2 = hot(' b| ').mergeMapTo(shared); + const expected2 = ' -3----4-#'; + const subscriber3 = hot(' c| ').mergeMapTo(shared); + const expected3 = ' --4-#'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should share the same values to multiple observers, ' + + 'but is unsubscribed explicitly and early', () => { + const source = cold('-1-2-3----4-|'); + const sourceSubs = '^ ! '; + const shared = source.share(); + const unsub = ' ! '; + const subscriber1 = hot('a| ').mergeMapTo(shared); + const expected1 = '-1-2-3---- '; + const subscriber2 = hot(' b| ').mergeMapTo(shared); + const expected2 = ' -3---- '; + const subscriber3 = hot(' c| ').mergeMapTo(shared); + const expected3 = ' -- '; + + expectObservable(subscriber1, unsub).toBe(expected1); + expectObservable(subscriber2, unsub).toBe(expected2); + expectObservable(subscriber3, unsub).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should share an empty source', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const shared = source.share(); + const expected = '|'; + + expectObservable(shared).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should share a never source', () => { + const source = cold('-'); + const sourceSubs = '^'; + const shared = source.share(); + const expected = '-'; + + expectObservable(shared).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should share a throw source', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const shared = source.share(); + const expected = '#'; + + expectObservable(shared).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should connect when first subscriber subscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ !'; + const shared = source.share(); + const subscriber1 = hot(' a| ').mergeMapTo(shared); + const expected1 = ' -1-2-3----4-|'; + const subscriber2 = hot(' b| ').mergeMapTo(shared); + const expected2 = ' -3----4-|'; + const subscriber3 = hot(' c| ').mergeMapTo(shared); + const expected3 = ' --4-|'; + + expectObservable(subscriber1).toBe(expected1); + expectObservable(subscriber2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should disconnect when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const shared = source.share(); + const subscriber1 = hot(' a| ').mergeMapTo(shared); + const unsub1 = ' ! '; + const expected1 = ' -1-2-3-- '; + const subscriber2 = hot(' b| ').mergeMapTo(shared); + const unsub2 = ' ! '; + const expected2 = ' -3---- '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not break unsubscription chain when last subscriber unsubscribes', () => { + const source = cold( '-1-2-3----4-|'); + const sourceSubs = ' ^ ! '; + const shared = source + .mergeMap((x: string) => Observable.of(x)) + .share() + .mergeMap((x: string) => Observable.of(x)); + const subscriber1 = hot(' a| ').mergeMapTo(shared); + const unsub1 = ' ! '; + const expected1 = ' -1-2-3-- '; + const subscriber2 = hot(' b| ').mergeMapTo(shared); + const unsub2 = ' ! '; + const expected2 = ' -3---- '; + + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be retryable when cold source is synchronous', () => { + const source = cold('(123#)'); + const shared = source.share(); + const subscribe1 = 's '; + const expected1 = '(123123#) '; + const subscribe2 = ' s '; + const expected2 = ' (123123#)'; + const sourceSubs = ['(^!)', + '(^!)', + ' (^!)', + ' (^!)']; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(shared.retry(1)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(shared.retry(1)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be repeatable when cold source is synchronous', () => { + const source = cold('(123|)'); + const shared = source.share(); + const subscribe1 = 's '; + const expected1 = '(123123|) '; + const subscribe2 = ' s '; + const expected2 = ' (123123|)'; + const sourceSubs = ['(^!)', + '(^!)', + ' (^!)', + ' (^!)']; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(shared.repeat(2)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(shared.repeat(2)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be retryable', () => { + const source = cold('-1-2-3----4-# '); + const sourceSubs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const shared = source.share(); + const subscribe1 = 's '; + const expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-#'; + const subscribe2 = ' s '; + const expected2 = ' -3----4--1-2-3----4--1-2-3----4-#'; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(shared.retry(2)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(shared.retry(2)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be repeatable', () => { + const source = cold('-1-2-3----4-| '); + const sourceSubs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const shared = source.share(); + const subscribe1 = 's '; + const expected1 = '-1-2-3----4--1-2-3----4--1-2-3----4-|'; + const subscribe2 = ' s '; + const expected2 = ' -3----4--1-2-3----4--1-2-3----4-|'; + + expectObservable(hot(subscribe1).do(() => { + expectObservable(shared.repeat(3)).toBe(expected1); + })).toBe(subscribe1); + + expectObservable(hot(subscribe2).do(() => { + expectObservable(shared.repeat(3)).toBe(expected2); + })).toBe(subscribe2); + + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not change the output of the observable when never', () => { + const e1 = Observable.never(); + const expected = '-'; + + expectObservable(e1.share()).toBe(expected); + }); + + it('should not change the output of the observable when empty', () => { + const e1 = Observable.empty(); + const expected = '|'; + + expectObservable(e1.share()).toBe(expected); + }); +}); diff --git a/spec/operators/single-spec.js b/spec/operators/single-spec.js deleted file mode 100644 index 9134704bae..0000000000 --- a/spec/operators/single-spec.js +++ /dev/null @@ -1,148 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.single()', function () { - it.asDiagram('single')('should raise error from empty predicate if observable emits multiple time', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ ! '; - var expected = '-----# '; - var errorMsg = 'Sequence contains more than one element'; - - expectObservable(e1.single()).toBe(expected, null, errorMsg); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error from empty predicate if observable does not emit', function () { - var e1 = hot('--a--^--|'); - var e1subs = '^ !'; - var expected = '---#'; - - expectObservable(e1.single()).toBe(expected, null, new Rx.EmptyError()); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return only element from empty predicate if observable emits only once', function () { - var e1 = hot('--a--|'); - var e1subs = '^ !'; - var expected = '-----(a|)'; - - expectObservable(e1.single()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--c--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---- '; - - expectObservable(e1.single(), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ ! '; - var expected = '---- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .single() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error from empty predicate if observable emits error', function () { - var e1 = hot('--a--b^--#'); - var e1subs = '^ !'; - var expected = '---#'; - - expectObservable(e1.single()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error from predicate if observable emits error', function () { - var e1 = hot('--a--b^--#'); - var e1subs = '^ !'; - var expected = '---#'; - - var predicate = function (value) { - return value === 'c'; - }; - - expectObservable(e1.single(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if predicate throws error', function () { - var e1 = hot('--a--b--c--d--|'); - var e1subs = '^ ! '; - var expected = '-----------# '; - - var predicate = function (value) { - if (value !== 'd') { - return false; - } - throw 'error'; - }; - - expectObservable(e1.single(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return element from predicate if observable have single matching element', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var expected = '-----------(b|)'; - - var predicate = function (value) { - return value === 'b'; - }; - - expectObservable(e1.single(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error from predicate if observable have multiple matching element', function () { - var e1 = hot('--a--b--a--b--b--|'); - var e1subs = '^ ! '; - var expected = '-----------# '; - - var predicate = function (value) { - return value === 'b'; - }; - - expectObservable(e1.single(predicate)).toBe(expected, null, 'Sequence contains more than one element'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error from predicate if observable does not emit', function () { - var e1 = hot('--a--^--|'); - var e1subs = '^ !'; - var expected = '---#'; - - var predicate = function (value) { - return value === 'a'; - }; - - expectObservable(e1.single(predicate)).toBe(expected, null, new Rx.EmptyError()); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should return undefined from predicate if observable does not contain matching element', function () { - var e1 = hot('--a--b--c--|'); - var e1subs = '^ !'; - var expected = '-----------(z|)'; - - var predicate = function (value) { - return value === 'x'; - }; - - expectObservable(e1.single(predicate)).toBe(expected, {z: undefined}); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/single-spec.ts b/spec/operators/single-spec.ts new file mode 100644 index 0000000000..d758c99ecd --- /dev/null +++ b/spec/operators/single-spec.ts @@ -0,0 +1,149 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +describe('Observable.prototype.single()', () => { + asDiagram('single')('should raise error from empty predicate if observable emits multiple time', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ ! '; + const expected = '-----# '; + const errorMsg = 'Sequence contains more than one element'; + + expectObservable(e1.single()).toBe(expected, null, errorMsg); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error from empty predicate if observable does not emit', () => { + const e1 = hot('--a--^--|'); + const e1subs = '^ !'; + const expected = '---#'; + + expectObservable(e1.single()).toBe(expected, null, new Rx.EmptyError()); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return only element from empty predicate if observable emits only once', () => { + const e1 = hot('--a--|'); + const e1subs = '^ !'; + const expected = '-----(a|)'; + + expectObservable(e1.single()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---- '; + + expectObservable(e1.single(), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ ! '; + const expected = '---- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .single() + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error from empty predicate if observable emits error', () => { + const e1 = hot('--a--b^--#'); + const e1subs = '^ !'; + const expected = '---#'; + + expectObservable(e1.single()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error from predicate if observable emits error', () => { + const e1 = hot('--a--b^--#'); + const e1subs = '^ !'; + const expected = '---#'; + + const predicate = function (value) { + return value === 'c'; + }; + + expectObservable(e1.single(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if predicate throws error', () => { + const e1 = hot('--a--b--c--d--|'); + const e1subs = '^ ! '; + const expected = '-----------# '; + + const predicate = function (value) { + if (value !== 'd') { + return false; + } + throw 'error'; + }; + + expectObservable(e1.single(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return element from predicate if observable have single matching element', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const expected = '-----------(b|)'; + + const predicate = function (value) { + return value === 'b'; + }; + + expectObservable(e1.single(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error from predicate if observable have multiple matching element', () => { + const e1 = hot('--a--b--a--b--b--|'); + const e1subs = '^ ! '; + const expected = '-----------# '; + + const predicate = function (value) { + return value === 'b'; + }; + + expectObservable(e1.single(predicate)).toBe(expected, null, 'Sequence contains more than one element'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error from predicate if observable does not emit', () => { + const e1 = hot('--a--^--|'); + const e1subs = '^ !'; + const expected = '---#'; + + const predicate = function (value) { + return value === 'a'; + }; + + expectObservable(e1.single(predicate)).toBe(expected, null, new Rx.EmptyError()); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should return undefined from predicate if observable does not contain matching element', () => { + const e1 = hot('--a--b--c--|'); + const e1subs = '^ !'; + const expected = '-----------(z|)'; + + const predicate = function (value) { + return value === 'x'; + }; + + expectObservable(e1.single(predicate)).toBe(expected, {z: undefined}); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/skip-spec.js b/spec/operators/skip-spec.js deleted file mode 100644 index 148cb690e7..0000000000 --- a/spec/operators/skip-spec.js +++ /dev/null @@ -1,147 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.skip()', function () { - it.asDiagram('skip(3)')('should skip values before a total', function () { - var source = hot('--a--b--c--d--e--|'); - var subs = '^ !'; - var expected = '-----------d--e--|'; - - expectObservable(source.skip(3)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should skip all values without error if total is more than actual number of values', function () { - var source = hot('--a--b--c--d--e--|'); - var subs = '^ !'; - var expected = '-----------------|'; - - expectObservable(source.skip(6)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should skip all values without error if total is same as actual number of values', function () { - var source = hot('--a--b--c--d--e--|'); - var subs = '^ !'; - var expected = '-----------------|'; - - expectObservable(source.skip(5)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not skip if count is zero', function () { - var source = hot('--a--b--c--d--e--|'); - var subs = '^ !'; - var expected = '--a--b--c--d--e--|'; - - expectObservable(source.skip(0)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var source = hot('--a--b--c--d--e--|'); - var unsub = ' ! '; - var subs = '^ ! '; - var expected = '--------c-- '; - - expectObservable(source.skip(2), unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--a--b--c--d--e--|'); - var subs = '^ ! '; - var expected = '--------c-- '; - var unsub = ' ! '; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .skip(2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if skip count is more than actual number of emits and source raises error', function () { - var source = hot('--a--b--c--d--#'); - var subs = '^ !'; - var expected = '--------------#'; - - expectObservable(source.skip(6)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if skip count is same as emits of source and source raises error', function () { - var source = hot('--a--b--c--d--#'); - var subs = '^ !'; - var expected = '--------------#'; - - expectObservable(source.skip(4)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should skip values before a total and raises error if source raises error', function () { - var source = hot('--a--b--c--d--#'); - var subs = '^ !'; - var expected = '-----------d--#'; - - expectObservable(source.skip(3)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should complete regardless of skip count if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.skip(3)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete if source never completes without emit', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.skip(3)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should skip values before total and never completes if source emits and does not complete', function () { - var e1 = hot('--a--b--c-'); - var e1subs = '^ '; - var expected = '-----b--c-'; - - expectObservable(e1.skip(1)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should skip all values and never completes if total is more than numbers of value and source does not complete', function () { - var e1 = hot('--a--b--c-'); - var e1subs = '^ '; - var expected = '----------'; - - expectObservable(e1.skip(6)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should skip all values and never completes if total is same asnumbers of value and source does not complete', function () { - var e1 = hot('--a--b--c-'); - var e1subs = '^ '; - var expected = '----------'; - - expectObservable(e1.skip(3)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.skip(3)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/skip-spec.ts b/spec/operators/skip-spec.ts new file mode 100644 index 0000000000..92aa39dbfe --- /dev/null +++ b/spec/operators/skip-spec.ts @@ -0,0 +1,149 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.skip()', () => { + asDiagram('skip(3)')('should skip values before a total', () => { + const source = hot('--a--b--c--d--e--|'); + const subs = '^ !'; + const expected = '-----------d--e--|'; + + expectObservable(source.skip(3)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should skip all values without error if total is more than actual number of values', () => { + const source = hot('--a--b--c--d--e--|'); + const subs = '^ !'; + const expected = '-----------------|'; + + expectObservable(source.skip(6)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should skip all values without error if total is same as actual number of values', () => { + const source = hot('--a--b--c--d--e--|'); + const subs = '^ !'; + const expected = '-----------------|'; + + expectObservable(source.skip(5)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not skip if count is zero', () => { + const source = hot('--a--b--c--d--e--|'); + const subs = '^ !'; + const expected = '--a--b--c--d--e--|'; + + expectObservable(source.skip(0)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const source = hot('--a--b--c--d--e--|'); + const unsub = ' ! '; + const subs = '^ ! '; + const expected = '--------c-- '; + + expectObservable(source.skip(2), unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--a--b--c--d--e--|'); + const subs = '^ ! '; + const expected = '--------c-- '; + const unsub = ' ! '; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .skip(2) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if skip count is more than actual number of emits and source raises error', () => { + const source = hot('--a--b--c--d--#'); + const subs = '^ !'; + const expected = '--------------#'; + + expectObservable(source.skip(6)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if skip count is same as emits of source and source raises error', () => { + const source = hot('--a--b--c--d--#'); + const subs = '^ !'; + const expected = '--------------#'; + + expectObservable(source.skip(4)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should skip values before a total and raises error if source raises error', () => { + const source = hot('--a--b--c--d--#'); + const subs = '^ !'; + const expected = '-----------d--#'; + + expectObservable(source.skip(3)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should complete regardless of skip count if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.skip(3)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete if source never completes without emit', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.skip(3)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should skip values before total and never completes if source emits and does not complete', () => { + const e1 = hot('--a--b--c-'); + const e1subs = '^ '; + const expected = '-----b--c-'; + + expectObservable(e1.skip(1)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should skip all values and never completes if total is more than numbers of value and source does not complete', () => { + const e1 = hot('--a--b--c-'); + const e1subs = '^ '; + const expected = '----------'; + + expectObservable(e1.skip(6)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should skip all values and never completes if total is same asnumbers of value and source does not complete', () => { + const e1 = hot('--a--b--c-'); + const e1subs = '^ '; + const expected = '----------'; + + expectObservable(e1.skip(3)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.skip(3)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/skipUntil-spec.js b/spec/operators/skipUntil-spec.js deleted file mode 100644 index 2968d0521a..0000000000 --- a/spec/operators/skipUntil-spec.js +++ /dev/null @@ -1,235 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.skipUntil()', function () { - it.asDiagram('skipUntil')('should skip values until another observable notifies', function () { - var e1 = hot('--a--b--c--d--e----|'); - var e1subs = '^ !'; - var skip = hot('---------x------| '); - var skipSubs = '^ ! '; - var expected = ('-----------d--e----|'); - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should emit element only after another observable emits', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var skip = hot('-----------x----| '); - var skipSubs = '^ ! '; - var expected = ('--------------e--|'); - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip value and raises error until another observable raises error', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ ! '; - var skip = hot('-------------# '); - var skipSubs = '^ ! '; - var expected = '-------------# '; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip all element when another observable does not emit and completes early', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var skip = hot('------------| '); - var skipSubs = '^ ! '; - var expected = '-----------------|'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--c--d--e----|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var skip = hot('-------------x--| '); - var skipSubs = '^ ! '; - var expected = ('---------- '); - - expectObservable(e1.skipUntil(skip), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--c--d--e----|'); - var e1subs = '^ ! '; - var skip = hot('-------------x--| '); - var skipSubs = '^ ! '; - var expected = ('---------- '); - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .skipUntil(skip) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip all element when another observable is empty', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var skip = cold('|'); - var skipSubs = '(^!)'; - var expected = '-----------------|'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should keep subscription to source, to wait for its eventual complete', function () { - var e1 = hot('------------------------------|'); - var e1subs = '^ !'; - var skip = hot('-------| '); - var skipSubs = '^ ! '; - var expected = '------------------------------|'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should not complete if source observable does not complete', function () { - var e1 = hot('-'); - var e1subs = '^'; - var skip = hot('-------------x--|'); - var skipSubs = '^ !'; - var expected = '-'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should not complete if source observable never completes', function () { - var e1 = cold( '-'); - var e1subs = '^'; - var skip = hot('-------------x--|'); - var skipSubs = '^ !'; - var expected = '-'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should raise error if source does not completes when another observable raises error', function () { - var e1 = hot('-'); - var e1subs = '^ !'; - var skip = hot('-------------#'); - var skipSubs = '^ !'; - var expected = '-------------#'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should raise error if source never completes when another observable raises error', function () { - var e1 = cold( '-'); - var e1subs = '^ !'; - var skip = hot('-------------#'); - var skipSubs = '^ !'; - var expected = '-------------#'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip all element and does not complete when another observable never completes', function () { - var e1 = hot( '--a--b--c--d--e--|'); - var e1subs = '^ !'; - var skip = cold('-'); - var skipSubs = '^ !'; - var expected = '-'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip all element and does not complete when another observable does not completes', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var skip = hot('-'); - var skipSubs = '^ !'; - var expected = '-'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip all element and does not complete when another observable completes after source', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var skip = hot('------------------------|'); - var skipSubs = '^ !'; - var expected = '------------------'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should not completes if source does not completes when another observable does not emit', function () { - var e1 = hot('-'); - var e1subs = '^'; - var skip = hot('--------------|'); - var skipSubs = '^ !'; - var expected = '-'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should not completes if source and another observable both does not complete', function () { - var e1 = hot('-'); - var e1subs = '^'; - var skip = hot('-'); - var skipSubs = '^'; - var expected = '-'; - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(skip.subscriptions).toBe(skipSubs); - }); - - it('should skip all element when another observable unsubscribed early before emit', function () { - var e1 = hot( '--a--b--c--d--e--|'); - var e1subs = ['^ !', - '^ !']; // for the explicit subscribe some lines below - var skip = new Rx.Subject(); - var expected = '-'; - - e1.subscribe(function (x) { - if (x === 'd' && !skip.isUnsubscribed) { - skip.next('x'); - } - - skip.unsubscribe(); - }); - - expectObservable(e1.skipUntil(skip)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/skipUntil-spec.ts b/spec/operators/skipUntil-spec.ts new file mode 100644 index 0000000000..99b7b9ff1d --- /dev/null +++ b/spec/operators/skipUntil-spec.ts @@ -0,0 +1,237 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.skipUntil()', () => { + asDiagram('skipUntil')('should skip values until another observable notifies', () => { + const e1 = hot('--a--b--c--d--e----|'); + const e1subs = '^ !'; + const skip = hot('---------x------| '); + const skipSubs = '^ ! '; + const expected = ('-----------d--e----|'); + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should emit element only after another observable emits', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const skip = hot('-----------x----| '); + const skipSubs = '^ ! '; + const expected = ('--------------e--|'); + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip value and raises error until another observable raises error', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ ! '; + const skip = hot('-------------# '); + const skipSubs = '^ ! '; + const expected = '-------------# '; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip all element when another observable does not emit and completes early', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const skip = hot('------------| '); + const skipSubs = '^ ! '; + const expected = '-----------------|'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c--d--e----|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const skip = hot('-------------x--| '); + const skipSubs = '^ ! '; + const expected = ('---------- '); + + expectObservable(e1.skipUntil(skip), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--c--d--e----|'); + const e1subs = '^ ! '; + const skip = hot('-------------x--| '); + const skipSubs = '^ ! '; + const expected = ('---------- '); + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .skipUntil(skip) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip all element when another observable is empty', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const skip = cold('|'); + const skipSubs = '(^!)'; + const expected = '-----------------|'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should keep subscription to source, to wait for its eventual complete', () => { + const e1 = hot('------------------------------|'); + const e1subs = '^ !'; + const skip = hot('-------| '); + const skipSubs = '^ ! '; + const expected = '------------------------------|'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should not complete if source observable does not complete', () => { + const e1 = hot('-'); + const e1subs = '^'; + const skip = hot('-------------x--|'); + const skipSubs = '^ !'; + const expected = '-'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should not complete if source observable never completes', () => { + const e1 = cold( '-'); + const e1subs = '^'; + const skip = hot('-------------x--|'); + const skipSubs = '^ !'; + const expected = '-'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should raise error if source does not completes when another observable raises error', () => { + const e1 = hot('-'); + const e1subs = '^ !'; + const skip = hot('-------------#'); + const skipSubs = '^ !'; + const expected = '-------------#'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should raise error if source never completes when another observable raises error', () => { + const e1 = cold( '-'); + const e1subs = '^ !'; + const skip = hot('-------------#'); + const skipSubs = '^ !'; + const expected = '-------------#'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip all element and does not complete when another observable never completes', () => { + const e1 = hot( '--a--b--c--d--e--|'); + const e1subs = '^ !'; + const skip = cold('-'); + const skipSubs = '^ !'; + const expected = '-'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip all element and does not complete when another observable does not completes', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const skip = hot('-'); + const skipSubs = '^ !'; + const expected = '-'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip all element and does not complete when another observable completes after source', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const skip = hot('------------------------|'); + const skipSubs = '^ !'; + const expected = '------------------'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should not completes if source does not completes when another observable does not emit', () => { + const e1 = hot('-'); + const e1subs = '^'; + const skip = hot('--------------|'); + const skipSubs = '^ !'; + const expected = '-'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should not completes if source and another observable both does not complete', () => { + const e1 = hot('-'); + const e1subs = '^'; + const skip = hot('-'); + const skipSubs = '^'; + const expected = '-'; + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(skip.subscriptions).toBe(skipSubs); + }); + + it('should skip all element when another observable unsubscribed early before emit', () => { + const e1 = hot( '--a--b--c--d--e--|'); + const e1subs = ['^ !', + '^ !']; // for the explicit subscribe some lines below + const skip = new Rx.Subject(); + const expected = '-'; + + e1.subscribe((x: string) => { + if (x === 'd' && !skip.isUnsubscribed) { + skip.next('x'); + } + + skip.unsubscribe(); + }); + + expectObservable(e1.skipUntil(skip)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/skipWhile-spec.js b/spec/operators/skipWhile-spec.js deleted file mode 100644 index c77f8a8577..0000000000 --- a/spec/operators/skipWhile-spec.js +++ /dev/null @@ -1,189 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.skipWhile()', function () { - it.asDiagram('skipWhile(x => x < 4)')('should skip all elements until predicate is false', function () { - var source = hot('-1-^2--3--4--5--6--|'); - var sourceSubs = '^ !'; - var expected = '-------4--5--6--|'; - - var predicate = function (v) { - return +v < 4; - }; - - expectObservable(source.skipWhile(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should skip all elements with a true predicate', function () { - var source = hot('-1-^2--3--4--5--6--|'); - var sourceSubs = '^ !'; - var expected = '----------------|'; - - expectObservable(source.skipWhile(function () { return true; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should skip all elements with a truthy predicate', function () { - var source = hot('-1-^2--3--4--5--6--|'); - var sourceSubs = '^ !'; - var expected = '----------------|'; - - expectObservable(source.skipWhile(function () { return {}; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not skip any element with a false predicate', function () { - var source = hot('-1-^2--3--4--5--6--|'); - var sourceSubs = '^ !'; - var expected = '-2--3--4--5--6--|'; - - expectObservable(source.skipWhile(function () { return false; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not skip any elements with a falsy predicate', function () { - var source = hot('-1-^2--3--4--5--6--|'); - var sourceSubs = '^ !'; - var expected = '-2--3--4--5--6--|'; - - expectObservable(source.skipWhile(function () { return undefined; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should skip elements on hot source', function () { - var source = hot('--1--2-^-3--4--5--6--7--8--'); - var sourceSubs = '^ '; - var expected = '--------5--6--7--8--'; - - var predicate = function (v) { - return +v < 5; - }; - - expectObservable(source.skipWhile(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should be possible to skip using the element\'s index', function () { - var source = hot('--a--b-^-c--d--e--f--g--h--|'); - var sourceSubs = '^ !'; - var expected = '--------e--f--g--h--|'; - - var predicate = function (v, index) { - return index < 2; - }; - - expectObservable(source.skipWhile(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should skip using index with source unsubscribes early', function () { - var source = hot('--a--b-^-c--d--e--f--g--h--|'); - var sourceSubs = '^ !'; - var unsub = '-----------!'; - var expected = '-----d--e---'; - - var predicate = function (v, index) { - return index < 1; - }; - - expectObservable(source.skipWhile(predicate), unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--a--b-^-c--d--e--f--g--h--|'); - var sourceSubs = '^ !'; - var expected = '-----d--e---'; - var unsub = ' !'; - - var predicate = function (v, index) { - return index < 1; - }; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .skipWhile(predicate) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should skip using value with source throws', function () { - var source = hot('--a--b-^-c--d--e--f--g--h--#'); - var sourceSubs = '^ !'; - var expected = '-----d--e--f--g--h--#'; - - var predicate = function (v) { - return v !== 'd'; - }; - - expectObservable(source.skipWhile(predicate)).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should invoke predicate while its false and never again', function () { - var source = hot('--a--b-^-c--d--e--f--g--h--|'); - var sourceSubs = '^ !'; - var expected = '--------e--f--g--h--|'; - - var invoked = 0; - var predicate = function (v) { - invoked++; - return v !== 'e'; - }; - - expectObservable( - source.skipWhile(predicate).do(null, null, function () { - expect(invoked).toBe(3); - }) - ).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should handle predicate that throws', function () { - var source = hot('--a--b-^-c--d--e--f--g--h--|'); - var sourceSubs = '^ !'; - var expected = '--------#'; - - var predicate = function (v) { - if (v === 'e') { - throw new Error('nom d\'une pipe !'); - } - - return v !== 'f'; - }; - - expectObservable(source.skipWhile(predicate)).toBe(expected, undefined, new Error('nom d\'une pipe !')); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should handle Observable.empty', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '|'; - - expectObservable(source.skipWhile(function () { return true; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle Observable.never', function () { - var source = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(source.skipWhile(function () { return true; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle Observable.throw', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(source.skipWhile(function () { return true; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); diff --git a/spec/operators/skipWhile-spec.ts b/spec/operators/skipWhile-spec.ts new file mode 100644 index 0000000000..b2f1aedc9d --- /dev/null +++ b/spec/operators/skipWhile-spec.ts @@ -0,0 +1,191 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.skipWhile()', () => { + asDiagram('skipWhile(x => x < 4)')('should skip all elements until predicate is false', () => { + const source = hot('-1-^2--3--4--5--6--|'); + const sourceSubs = '^ !'; + const expected = '-------4--5--6--|'; + + const predicate = function (v) { + return +v < 4; + }; + + expectObservable(source.skipWhile(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should skip all elements with a true predicate', () => { + const source = hot('-1-^2--3--4--5--6--|'); + const sourceSubs = '^ !'; + const expected = '----------------|'; + + expectObservable(source.skipWhile(() => true)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should skip all elements with a truthy predicate', () => { + const source = hot('-1-^2--3--4--5--6--|'); + const sourceSubs = '^ !'; + const expected = '----------------|'; + + expectObservable(source.skipWhile((): any => { return {}; })).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not skip any element with a false predicate', () => { + const source = hot('-1-^2--3--4--5--6--|'); + const sourceSubs = '^ !'; + const expected = '-2--3--4--5--6--|'; + + expectObservable(source.skipWhile(() => false)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not skip any elements with a falsy predicate', () => { + const source = hot('-1-^2--3--4--5--6--|'); + const sourceSubs = '^ !'; + const expected = '-2--3--4--5--6--|'; + + expectObservable(source.skipWhile(() => undefined)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should skip elements on hot source', () => { + const source = hot('--1--2-^-3--4--5--6--7--8--'); + const sourceSubs = '^ '; + const expected = '--------5--6--7--8--'; + + const predicate = function (v) { + return +v < 5; + }; + + expectObservable(source.skipWhile(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should be possible to skip using the element\'s index', () => { + const source = hot('--a--b-^-c--d--e--f--g--h--|'); + const sourceSubs = '^ !'; + const expected = '--------e--f--g--h--|'; + + const predicate = function (v, index) { + return index < 2; + }; + + expectObservable(source.skipWhile(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should skip using index with source unsubscribes early', () => { + const source = hot('--a--b-^-c--d--e--f--g--h--|'); + const sourceSubs = '^ !'; + const unsub = '-----------!'; + const expected = '-----d--e---'; + + const predicate = function (v, index) { + return index < 1; + }; + + expectObservable(source.skipWhile(predicate), unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--a--b-^-c--d--e--f--g--h--|'); + const sourceSubs = '^ !'; + const expected = '-----d--e---'; + const unsub = ' !'; + + const predicate = function (v, index) { + return index < 1; + }; + + const result = source + .mergeMap(function (x) { return Observable.of(x); }) + .skipWhile(predicate) + .mergeMap(function (x) { return Observable.of(x); }); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should skip using value with source throws', () => { + const source = hot('--a--b-^-c--d--e--f--g--h--#'); + const sourceSubs = '^ !'; + const expected = '-----d--e--f--g--h--#'; + + const predicate = function (v) { + return v !== 'd'; + }; + + expectObservable(source.skipWhile(predicate)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should invoke predicate while its false and never again', () => { + const source = hot('--a--b-^-c--d--e--f--g--h--|'); + const sourceSubs = '^ !'; + const expected = '--------e--f--g--h--|'; + + let invoked = 0; + const predicate = function (v) { + invoked++; + return v !== 'e'; + }; + + expectObservable( + source.skipWhile(predicate).do(null, null, () => { + expect(invoked).toBe(3); + }) + ).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should handle predicate that throws', () => { + const source = hot('--a--b-^-c--d--e--f--g--h--|'); + const sourceSubs = '^ !'; + const expected = '--------#'; + + const predicate = function (v) { + if (v === 'e') { + throw new Error('nom d\'une pipe !'); + } + + return v !== 'f'; + }; + + expectObservable(source.skipWhile(predicate)).toBe(expected, undefined, new Error('nom d\'une pipe !')); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should handle Observable.empty', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '|'; + + expectObservable(source.skipWhile(() => true)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle Observable.never', () => { + const source = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable(source.skipWhile(() => true)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle Observable.throw', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable(source.skipWhile(() => true)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); diff --git a/spec/operators/startWith-spec.js b/spec/operators/startWith-spec.js deleted file mode 100644 index dc9ab17470..0000000000 --- a/spec/operators/startWith-spec.js +++ /dev/null @@ -1,153 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.startWith()', function () { - var defaultStartValue = 'x'; - - it.asDiagram('startWith(s)')('should prepend to a cold Observable', function () { - var e1 = cold('---a--b--c--|'); - var e1subs = '^ !'; - var expected = 's--a--b--c--|'; - - expectObservable(e1.startWith('s')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start an observable with given value', function () { - var e1 = hot('--a--|'); - var e1subs = '^ !'; - var expected = 'x-a--|'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and does not completes if source does not completes', function () { - var e1 = hot('----a-'); - var e1subs = '^ '; - var expected = 'x---a-'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and does not completes if source never emits', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = 'x-'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and completes if source does not emits', function () { - var e1 = hot('---|'); - var e1subs = '^ !'; - var expected = 'x--|'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and complete immediately if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(x|)'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and source both if source emits single value', function () { - var e1 = cold('(a|)'); - var e1subs = '(^!)'; - var expected = '(xa|)'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given values when given value is more than one', function () { - var e1 = hot('-----a--|'); - var e1subs = '^ !'; - var expected = '(yz)-a--|'; - - expectObservable(e1.startWith('y','z')).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and raises error if source raises error', function () { - var e1 = hot('--#'); - var e1subs = '^ !'; - var expected = 'x-#'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected, defaultStartValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with given value and raises error immediately if source throws error', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '(x#)'; - - expectObservable(e1.startWith(defaultStartValue)).toBe(expected, defaultStartValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('---a--b----c--d--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = 's--a--b---'; - var values = { s: 's', a: 'a', b: 'b' }; - - var result = e1.startWith('s', rxTestScheduler); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('---a--b----c--d--|'); - var e1subs = '^ ! '; - var expected = 's--a--b--- '; - var unsub = ' ! '; - var values = { s: 's', a: 'a', b: 'b' }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .startWith('s', rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should start with empty if given value is not specified', function () { - var e1 = hot('-a-|'); - var e1subs = '^ !'; - var expected = '-a-|'; - - expectObservable(e1.startWith(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should accept scheduler as last argument with single value', function () { - var e1 = hot('--a--|'); - var e1subs = '^ !'; - var expected = 'x-a--|'; - - expectObservable(e1.startWith(defaultStartValue, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should accept scheduler as last argument with multiple value', function () { - var e1 = hot('-----a--|'); - var e1subs = '^ !'; - var expected = '(yz)-a--|'; - - expectObservable(e1.startWith('y','z', rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/startWith-spec.ts b/spec/operators/startWith-spec.ts new file mode 100644 index 0000000000..cb23c0b4ff --- /dev/null +++ b/spec/operators/startWith-spec.ts @@ -0,0 +1,156 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.startWith()', () => { + const defaultStartValue = 'x'; + + asDiagram('startWith(s)')('should prepend to a cold Observable', () => { + const e1 = cold('---a--b--c--|'); + const e1subs = '^ !'; + const expected = 's--a--b--c--|'; + + expectObservable(e1.startWith('s')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start an observable with given value', () => { + const e1 = hot('--a--|'); + const e1subs = '^ !'; + const expected = 'x-a--|'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and does not completes if source does not completes', () => { + const e1 = hot('----a-'); + const e1subs = '^ '; + const expected = 'x---a-'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and does not completes if source never emits', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = 'x-'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and completes if source does not emits', () => { + const e1 = hot('---|'); + const e1subs = '^ !'; + const expected = 'x--|'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and complete immediately if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(x|)'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and source both if source emits single value', () => { + const e1 = cold('(a|)'); + const e1subs = '(^!)'; + const expected = '(xa|)'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given values when given value is more than one', () => { + const e1 = hot('-----a--|'); + const e1subs = '^ !'; + const expected = '(yz)-a--|'; + + expectObservable((e1).startWith('y','z')).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and raises error if source raises error', () => { + const e1 = hot('--#'); + const e1subs = '^ !'; + const expected = 'x-#'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected, defaultStartValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with given value and raises error immediately if source throws error', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '(x#)'; + + expectObservable(e1.startWith(defaultStartValue)).toBe(expected, defaultStartValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('---a--b----c--d--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = 's--a--b---'; + const values = { s: 's', a: 'a', b: 'b' }; + + const result = (e1).startWith('s', rxTestScheduler); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('---a--b----c--d--|'); + const e1subs = '^ ! '; + const expected = 's--a--b--- '; + const unsub = ' ! '; + const values = { s: 's', a: 'a', b: 'b' }; + + const result = (e1) + .mergeMap((x: string) => Observable.of(x)) + .startWith('s', rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should start with empty if given value is not specified', () => { + const e1 = hot('-a-|'); + const e1subs = '^ !'; + const expected = '-a-|'; + + expectObservable(e1.startWith(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should accept scheduler as last argument with single value', () => { + const e1 = hot('--a--|'); + const e1subs = '^ !'; + const expected = 'x-a--|'; + + expectObservable((e1).startWith(defaultStartValue, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should accept scheduler as last argument with multiple value', () => { + const e1 = hot('-----a--|'); + const e1subs = '^ !'; + const expected = '(yz)-a--|'; + + expectObservable((e1).startWith('y','z', rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/subscribeOn-spec.js b/spec/operators/subscribeOn-spec.js deleted file mode 100644 index 02f95940a4..0000000000 --- a/spec/operators/subscribeOn-spec.js +++ /dev/null @@ -1,77 +0,0 @@ -/* globals describe, it, expect, hot, expectObservable, expectSubscriptions, rxTestScheduler*/ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.subscribeOn()', function () { - it.asDiagram('subscribeOn(scheduler)')('should subscribe on specified scheduler', function () { - var e1 = hot('--a--b--|'); - var expected = '--a--b--|'; - var sub = '^ !'; - - expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should start subscribe after specified delay', function () { - var e1 = hot('--a--b--|'); - var expected = '-----b--|'; - var sub = ' ^ !'; - - expectObservable(e1.subscribeOn(rxTestScheduler, 30)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should subscribe when source raises error', function () { - var e1 = hot('--a--#'); - var expected = '--a--#'; - var sub = '^ !'; - - expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should subscribe when source is empty', function () { - var e1 = hot('----|'); - var expected = '----|'; - var sub = '^ !'; - - expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should subscribe when source does not complete', function () { - var e1 = hot('----'); - var expected = '----'; - var sub = '^ '; - - expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--b--|'); - var sub = '^ ! '; - var expected = '--a-- '; - var unsub = ' ! '; - - var result = e1.subscribeOn(rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); - - it('should not break unsubscription chains when the result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--|'); - var sub = '^ ! '; - var expected = '--a-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .subscribeOn(rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(sub); - }); -}); diff --git a/spec/operators/subscribeOn-spec.ts b/spec/operators/subscribeOn-spec.ts new file mode 100644 index 0000000000..b26bd0dfab --- /dev/null +++ b/spec/operators/subscribeOn-spec.ts @@ -0,0 +1,80 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.subscribeOn()', () => { + asDiagram('subscribeOn(scheduler)')('should subscribe on specified scheduler', () => { + const e1 = hot('--a--b--|'); + const expected = '--a--b--|'; + const sub = '^ !'; + + expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should start subscribe after specified delay', () => { + const e1 = hot('--a--b--|'); + const expected = '-----b--|'; + const sub = ' ^ !'; + + expectObservable(e1.subscribeOn(rxTestScheduler, 30)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should subscribe when source raises error', () => { + const e1 = hot('--a--#'); + const expected = '--a--#'; + const sub = '^ !'; + + expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should subscribe when source is empty', () => { + const e1 = hot('----|'); + const expected = '----|'; + const sub = '^ !'; + + expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should subscribe when source does not complete', () => { + const e1 = hot('----'); + const expected = '----'; + const sub = '^ '; + + expectObservable(e1.subscribeOn(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--b--|'); + const sub = '^ ! '; + const expected = '--a-- '; + const unsub = ' ! '; + + const result = e1.subscribeOn(rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); + + it('should not break unsubscription chains when the result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--|'); + const sub = '^ ! '; + const expected = '--a-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .subscribeOn(rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(sub); + }); +}); diff --git a/spec/operators/switch-spec.js b/spec/operators/switch-spec.js deleted file mode 100644 index e3da79b75d..0000000000 --- a/spec/operators/switch-spec.js +++ /dev/null @@ -1,219 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Promise = require('promise'); - -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.switch()', function () { - it.asDiagram('switch')('should switch a hot observable of cold observables', function () { - var x = cold( '--a---b--c---d--| '); - var y = cold( '----e---f--g---|'); - var e1 = hot( '--x------y-------| ', { x: x, y: y }); - var expected = '----a---b----e---f--g---|'; - - expectObservable(e1.switch()).toBe(expected); - }); - - it('should switch to each immediately-scheduled inner Observable', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, queueScheduler); - var r = [1, 4, 5, 6]; - var i = 0; - Observable.of(a, b, queueScheduler) - .switch() - .subscribe(function (x) { - expect(x).toBe(r[i++]); - }, null, done); - }); - - it('should unsub inner observables', function () { - var unsubbed = []; - - Observable.of('a', 'b').map(function (x) { - return Observable.create(function (subscriber) { - subscriber.complete(); - return function () { - unsubbed.push(x); - }; - }); - }) - .mergeAll() - .subscribe(); - - expect(unsubbed).toEqual(['a', 'b']); - }); - - it('should switch to each inner Observable', function (done) { - var a = Observable.of(1, 2, 3); - var b = Observable.of(4, 5, 6); - var r = [1, 2, 3, 4, 5, 6]; - var i = 0; - Observable.of(a, b).switch().subscribe(function (x) { - expect(x).toBe(r[i++]); - }, null, done); - }); - - it('should handle a hot observable of observables', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = ' ^ !'; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var expected = '--------a---b----d--e---f---|'; - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, outer is unsubscribed early', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = ' ^ ! '; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var unsub = ' ! '; - var expected = '--------a---b--- '; - expectObservable(e1.switch(), unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = ' ^ ! '; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var expected = '--------a---b---- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (i) { return Observable.of(i); }) - .switch() - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, inner never completes', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f-----'); - var ysubs = ' ^ '; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var expected = '--------a---b----d--e---f-----'; - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a synchronous switch to the second inner observable', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' (^!) '; - var y = cold( '---d--e---f---| '); - var ysubs = ' ^ ! '; - var e1 = hot( '------(xy)------------|', { x: x, y: y }); - var expected = '---------d--e---f-----|'; - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, one inner throws', function () { - var x = cold( '--a---# '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = []; - var e1 = hot( '------x-------y------| ', { x: x, y: y }); - var expected = '--------a---# '; - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle a hot observable of observables, outer throws', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var y = cold( '---d--e---f---|'); - var ysubs = ' ^ ! '; - var e1 = hot( '------x-------y-------# ', { x: x, y: y }); - var expected = '--------a---b----d--e-# '; - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - }); - - it('should handle an empty hot observable', function () { - var e1 = hot('------|'); - var e1subs = '^ !'; - var expected = '------|'; - - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a never hot observable', function () { - var e1 = hot('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete not before the outer completes', function () { - var x = cold( '--a---b---c--| '); - var xsubs = ' ^ ! '; - var e1 = hot( '------x---------------|', { x: x }); - var e1subs = '^ !'; - var expected = '--------a---b---c-----|'; - - expectObservable(e1.switch()).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an observable of promises', function (done) { - var expected = [3]; - - Observable.of(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)) - .switch() - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - done(); - }); - }); - - it('should handle an observable of promises, where one rejects', function (done) { - Observable.of(Promise.resolve(1), Promise.reject(2), Promise.resolve(3)) - .switch() - .subscribe(function (x) { - expect(x).toBe(3); - }, function (err) { - expect(err).toBe(2); - }, function () { - done(); - }); - }); - - it('should handle an observable with Arrays in it', function () { - var expected = [1,2,3,4]; - var completed = false; - - Observable.of(Observable.never(), Observable.never(), [1,2,3,4]) - .switch() - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - completed = true; - expect(expected.length).toBe(0); - }); - - expect(completed).toBe(true); - }); -}); \ No newline at end of file diff --git a/spec/operators/switch-spec.ts b/spec/operators/switch-spec.ts new file mode 100644 index 0000000000..f144dcd7ef --- /dev/null +++ b/spec/operators/switch-spec.ts @@ -0,0 +1,218 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.switch()', () => { + asDiagram('switch')('should switch a hot observable of cold observables', () => { + const x = cold( '--a---b--c---d--| '); + const y = cold( '----e---f--g---|'); + const e1 = hot( '--x------y-------| ', { x: x, y: y }); + const expected = '----a---b----e---f--g---|'; + + expectObservable(e1.switch()).toBe(expected); + }); + + it('should switch to each immediately-scheduled inner Observable', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, queueScheduler); + const r = [1, 4, 5, 6]; + let i = 0; + Observable.of>(a, b, queueScheduler) + .switch() + .subscribe((x: number) => { + expect(x).toBe(r[i++]); + }, null, done); + }); + + it('should unsub inner observables', () => { + const unsubbed = []; + + Observable.of('a', 'b').map((x: string) => + Observable.create((subscriber: Rx.Subscriber) => { + subscriber.complete(); + return () => { + unsubbed.push(x); + }; + })) + .mergeAll() + .subscribe(); + + expect(unsubbed).toEqual(['a', 'b']); + }); + + it('should switch to each inner Observable', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3); + const b = Observable.of(4, 5, 6); + const r = [1, 2, 3, 4, 5, 6]; + let i = 0; + Observable.of(a, b).switch().subscribe((x: number) => { + expect(x).toBe(r[i++]); + }, null, done); + }); + + it('should handle a hot observable of observables', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = ' ^ !'; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const expected = '--------a---b----d--e---f---|'; + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, outer is unsubscribed early', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = ' ^ ! '; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const unsub = ' ! '; + const expected = '--------a---b--- '; + expectObservable(e1.switch(), unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = ' ^ ! '; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const expected = '--------a---b---- '; + const unsub = ' ! '; + + const result = (e1) + .mergeMap((x: string) => Observable.of(x)) + .switch() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, inner never completes', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f-----'); + const ysubs = ' ^ '; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const expected = '--------a---b----d--e---f-----'; + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a synchronous switch to the second inner observable', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' (^!) '; + const y = cold( '---d--e---f---| '); + const ysubs = ' ^ ! '; + const e1 = hot( '------(xy)------------|', { x: x, y: y }); + const expected = '---------d--e---f-----|'; + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, one inner throws', () => { + const x = cold( '--a---# '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = []; + const e1 = hot( '------x-------y------| ', { x: x, y: y }); + const expected = '--------a---# '; + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle a hot observable of observables, outer throws', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const y = cold( '---d--e---f---|'); + const ysubs = ' ^ ! '; + const e1 = hot( '------x-------y-------# ', { x: x, y: y }); + const expected = '--------a---b----d--e-# '; + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + }); + + it('should handle an empty hot observable', () => { + const e1 = hot('------|'); + const e1subs = '^ !'; + const expected = '------|'; + + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a never hot observable', () => { + const e1 = hot('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete not before the outer completes', () => { + const x = cold( '--a---b---c--| '); + const xsubs = ' ^ ! '; + const e1 = hot( '------x---------------|', { x: x }); + const e1subs = '^ !'; + const expected = '--------a---b---c-----|'; + + expectObservable(e1.switch()).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an observable of promises', (done: DoneSignature) => { + const expected = [3]; + + (Observable.of(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3))) + .switch() + .subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + done(); + }); + }); + + it('should handle an observable of promises, where one rejects', (done: DoneSignature) => { + Observable.of(Promise.resolve(1), Promise.reject(2), Promise.resolve(3)) + .switch() + .subscribe((x: number) => { + expect(x).toBe(3); + }, (err: any) => { + expect(err).toBe(2); + }, () => { + done(); + }); + }); + + it('should handle an observable with Arrays in it', () => { + const expected = [1,2,3,4]; + let completed = false; + + Observable.of(Observable.never(), Observable.never(), [1,2,3,4]) + .switch() + .subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, null, () => { + completed = true; + expect(expected.length).toBe(0); + }); + + expect(completed).toBe(true); + }); +}); \ No newline at end of file diff --git a/spec/operators/switchMap-spec.js b/spec/operators/switchMap-spec.js deleted file mode 100644 index 4f35c9a874..0000000000 --- a/spec/operators/switchMap-spec.js +++ /dev/null @@ -1,408 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.switchMap()', function () { - it('should switch with a selector function', function (done) { - var a = Observable.of(1, 2, 3); - var expected = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'a3', 'b3', 'c3']; - a.switchMap(function (x) { - return Observable.of('a' + x, 'b' + x, 'c' + x); - }).subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, done); - }); - - it('should unsub inner observables', function () { - var unsubbed = []; - - Observable.of('a', 'b').switchMap(function (x) { - return Observable.create(function (subscriber) { - subscriber.complete(); - return function () { - unsubbed.push(x); - }; - }); - }).subscribe(); - - expect(unsubbed).toEqual(['a', 'b']); - }); - - it('should switch inner cold observables', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--|'); - var ysubs = ' ^ !'; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ !'; - var expected = '-----------a--b--c----f---g---h---i--|'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when projection throws', function () { - var e1 = hot('-------x-----y---|'); - var e1subs = '^ ! '; - var expected = '-------# '; - function project() { - throw 'error'; - } - - expectObservable(e1.switchMap(project)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when resultSelector throws', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ ! '; - var expected = '-----------# '; - - function selector() { - throw 'error'; - } - - var result = e1.switchMap(function (value) { - return x; - }, selector); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner cold observables, outer is unsubscribed early', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--|'); - var ysubs = ' ^ ! '; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ ! '; - var unsub = ' ! '; - var expected = '-----------a--b--c---- '; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--|'); - var ysubs = ' ^ ! '; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ ! '; - var expected = '-----------a--b--c---- '; - var unsub = ' ! '; - - var observableLookup = { x: x, y: y }; - - var result = e1 - .mergeMap(function (i) { return Observable.of(i); }) - .switchMap(function (value) { return observableLookup[value]; }) - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner cold observables, inner never completes', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--'); - var ysubs = ' ^ '; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ '; - var expected = '-----------a--b--c----f---g---h---i--'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a synchronous switch to the second inner observable', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' (^!) '; - var y = cold( '---f---g---h---i--| '); - var ysubs = ' ^ ! '; - var e1 = hot('---------(xy)----------------|'); - var e1subs = '^ !'; - var expected = '------------f---g---h---i----|'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner cold observables, one inner throws', function () { - var x = cold( '--a--b--#--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--'); - var ysubs = []; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ ! '; - var expected = '-----------a--b--# '; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner hot observables', function () { - var x = hot('-----a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = hot('--p-o-o-p-------------f---g---h---i--|'); - var ysubs = ' ^ !'; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ !'; - var expected = '-----------c--d--e----f---g---h---i--|'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner empty and empty', function () { - var x = cold('|'); - var y = cold('|'); - var xsubs = ' (^!) '; - var ysubs = ' (^!) '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ !'; - var expected = '-----------------------------|'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner empty and never', function () { - var x = cold('|'); - var y = cold('-'); - var xsubs = ' (^!) '; - var ysubs = ' ^ '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ '; - var expected = '------------------------------'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner never and empty', function () { - var x = cold('-'); - var y = cold('|'); - var xsubs = ' ^ ! '; - var ysubs = ' (^!) '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ !'; - var expected = '-----------------------------|'; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner never and throw', function () { - var x = cold('-'); - var y = cold('#', null, 'sad'); - var xsubs = ' ^ ! '; - var ysubs = ' (^!) '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ ! '; - var expected = '-------------------# '; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected, undefined, 'sad'); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch inner empty and throw', function () { - var x = cold('|'); - var y = cold('#', null, 'sad'); - var xsubs = ' (^!) '; - var ysubs = ' (^!) '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ ! '; - var expected = '-------------------# '; - - var observableLookup = { x: x, y: y }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected, undefined, 'sad'); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle outer empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - var result = e1.switchMap(function (value) { - return Observable.of(value); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle outer never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var result = e1.switchMap(function (value) { - return Observable.of(value); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle outer throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - var result = e1.switchMap(function (value) { - return Observable.of(value); - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle outer error', function () { - var x = cold( '--a--b--c--d--e--|'); - var xsubs = ' ^ ! '; - var e1 = hot('---------x---------# '); - var e1subs = '^ ! '; - var expected = '-----------a--b--c-# '; - - var observableLookup = { x: x }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch with resultSelector goodness', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--|'); - var ysubs = ' ^ !'; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ !'; - var expected = '-----------a--b--c----f---g---h---i--|'; - - var observableLookup = { x: x, y: y }; - - var expectedValues = { - a: ['x', 'a', 0, 0], - b: ['x', 'b', 0, 1], - c: ['x', 'c', 0, 2], - f: ['y', 'f', 1, 0], - g: ['y', 'g', 1, 1], - h: ['y', 'h', 1, 2], - i: ['y', 'i', 1, 3] - }; - - var result = e1.switchMap(function (value) { - return observableLookup[value]; - }, function (innerValue, outerValue, innerIndex, outerIndex) { - return [innerValue, outerValue, innerIndex, outerIndex]; - }); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/switchMap-spec.ts b/spec/operators/switchMap-spec.ts new file mode 100644 index 0000000000..17f031bca3 --- /dev/null +++ b/spec/operators/switchMap-spec.ts @@ -0,0 +1,373 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.switchMap()', () => { + it('should switch with a selector function', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3); + const expected = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'a3', 'b3', 'c3']; + a.switchMap((x: number) => Observable.of('a' + x, 'b' + x, 'c' + x)) + .subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, done); + }); + + it('should unsub inner observables', () => { + const unsubbed = []; + + Observable.of('a', 'b').switchMap((x: string) => + Observable.create((subscriber: Rx.Subscriber) => { + subscriber.complete(); + return () => { + unsubbed.push(x); + }; + })).subscribe(); + + expect(unsubbed).toEqual(['a', 'b']); + }); + + it('should switch inner cold observables', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--|'); + const ysubs = ' ^ !'; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ !'; + const expected = '-----------a--b--c----f---g---h---i--|'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when projection throws', () => { + const e1 = hot('-------x-----y---|'); + const e1subs = '^ ! '; + const expected = '-------# '; + function project() { + throw 'error'; + } + + expectObservable(e1.switchMap(project)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when resultSelector throws', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ ! '; + const expected = '-----------# '; + + function selector() { + throw 'error'; + } + + const result = e1.switchMap((value: string) => x, selector); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner cold observables, outer is unsubscribed early', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--|'); + const ysubs = ' ^ ! '; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ ! '; + const unsub = ' ! '; + const expected = '-----------a--b--c---- '; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--|'); + const ysubs = ' ^ ! '; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ ! '; + const expected = '-----------a--b--c---- '; + const unsub = ' ! '; + + const observableLookup = { x: x, y: y }; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .switchMap((value: string) => observableLookup[value]) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner cold observables, inner never completes', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--'); + const ysubs = ' ^ '; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ '; + const expected = '-----------a--b--c----f---g---h---i--'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a synchronous switch to the second inner observable', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' (^!) '; + const y = cold( '---f---g---h---i--| '); + const ysubs = ' ^ ! '; + const e1 = hot('---------(xy)----------------|'); + const e1subs = '^ !'; + const expected = '------------f---g---h---i----|'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner cold observables, one inner throws', () => { + const x = cold( '--a--b--#--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--'); + const ysubs = []; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ ! '; + const expected = '-----------a--b--# '; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner hot observables', () => { + const x = hot('-----a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = hot('--p-o-o-p-------------f---g---h---i--|'); + const ysubs = ' ^ !'; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ !'; + const expected = '-----------c--d--e----f---g---h---i--|'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner empty and empty', () => { + const x = cold('|'); + const y = cold('|'); + const xsubs = ' (^!) '; + const ysubs = ' (^!) '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ !'; + const expected = '-----------------------------|'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner empty and never', () => { + const x = cold('|'); + const y = cold('-'); + const xsubs = ' (^!) '; + const ysubs = ' ^ '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ '; + const expected = '------------------------------'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner never and empty', () => { + const x = cold('-'); + const y = cold('|'); + const xsubs = ' ^ ! '; + const ysubs = ' (^!) '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ !'; + const expected = '-----------------------------|'; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner never and throw', () => { + const x = cold('-'); + const y = cold('#', null, 'sad'); + const xsubs = ' ^ ! '; + const ysubs = ' (^!) '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ ! '; + const expected = '-------------------# '; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected, undefined, 'sad'); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch inner empty and throw', () => { + const x = cold('|'); + const y = cold('#', null, 'sad'); + const xsubs = ' (^!) '; + const ysubs = ' (^!) '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ ! '; + const expected = '-------------------# '; + + const observableLookup = { x: x, y: y }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected, undefined, 'sad'); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle outer empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + const result = e1.switchMap((value: any) => Observable.of(value)); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle outer never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const result = e1.switchMap((value: any) => Observable.of(value)); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle outer throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + const result = e1.switchMap((value: any) => Observable.of(value)); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle outer error', () => { + const x = cold( '--a--b--c--d--e--|'); + const xsubs = ' ^ ! '; + const e1 = hot('---------x---------# '); + const e1subs = '^ ! '; + const expected = '-----------a--b--c-# '; + + const observableLookup = { x: x }; + + const result = e1.switchMap((value: string) => observableLookup[value]); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch with resultSelector goodness', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--|'); + const ysubs = ' ^ !'; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ !'; + const expected = '-----------a--b--c----f---g---h---i--|'; + + const observableLookup = { x: x, y: y }; + + const expectedValues = { + a: ['x', 'a', 0, 0], + b: ['x', 'b', 0, 1], + c: ['x', 'c', 0, 2], + f: ['y', 'f', 1, 0], + g: ['y', 'g', 1, 1], + h: ['y', 'h', 1, 2], + i: ['y', 'i', 1, 3] + }; + + const result = e1.switchMap((value: string) => observableLookup[value], + (innerValue, outerValue, innerIndex, outerIndex) => [innerValue, outerValue, innerIndex, outerIndex]); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/switchMapTo-spec.js b/spec/operators/switchMapTo-spec.js deleted file mode 100644 index f0e90b53e6..0000000000 --- a/spec/operators/switchMapTo-spec.js +++ /dev/null @@ -1,251 +0,0 @@ -/* globals describe, it, expect, cold, hot, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.switchMapTo()', function () { - it('should switch a synchronous many outer to a synchronous many inner', function (done) { - var a = Observable.of(1, 2, 3); - var expected = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']; - a.switchMapTo(Observable.of('a', 'b', 'c')).subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, done); - }); - - it('should unsub inner observables', function () { - var unsubbed = 0; - - Observable.of('a', 'b').switchMapTo( - Observable.create(function (subscriber) { - subscriber.complete(); - return function () { - unsubbed++; - }; - }) - ).subscribe(); - - expect(unsubbed).toEqual(2); - }); - - it('should switch to an inner cold observable', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = [' ^ ! ', - // --a--b--c--d--e--| - ' ^ !']; - var e1 = hot('---------x---------x---------| '); - var e1subs = '^ !'; - var expected = '-----------a--b--c---a--b--c--d--e--|'; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner cold observable, outer eventually throws', function () { - var x = cold( '--a--b--c--d--e--|'); - var xsubs = ' ^ ! '; - var e1 = hot('---------x---------# '); - var e1subs = '^ ! '; - var expected = '-----------a--b--c-# '; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner cold observable, outer is unsubscribed early', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = [' ^ ! ', - // --a--b--c--d--e--| - ' ^ ! ']; - var e1 = hot('---------x---------x---------|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '-----------a--b--c---a- '; - - expectObservable(e1.switchMapTo(x), unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = [' ^ ! ', - // --a--b--c--d--e--| - ' ^ ! ']; - var e1 = hot('---------x---------x---------|'); - var e1subs = '^ ! '; - var expected = '-----------a--b--c---a- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (i) { return Observable.of(i); }) - .switchMapTo(x) - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner cold observable, inner never completes', function () { - var x = cold( '--a--b--c--d--e- '); - var xsubs = [' ^ ! ', - // --a--b--c--d--e- - ' ^ ']; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ '; - var expected = '-----------a--b--c---a--b--c--d--e-'; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a synchronous switch to the inner observable', function () { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = [' (^!) ', - ' ^ ! ']; - var e1 = hot('---------(xx)----------------|'); - var e1subs = '^ !'; - var expected = '-----------a--b--c--d--e-----|'; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner cold observable, inner raises an error', function () { - var x = cold( '--a--b--# '); - var xsubs = ' ^ ! '; - var e1 = hot('---------x---------x---------|'); - var e1subs = '^ ! '; - var expected = '-----------a--b--# '; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch an inner hot observable', function () { - var x = hot('--p-o-o-p---a--b--c--d-| '); - var xsubs = [' ^ ! ', - ' ^ ! ']; - var e1 = hot('---------x---------x---------|'); - var e1subs = '^ !'; - var expected = '------------a--b--c--d-------|'; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner empty', function () { - var x = cold('|'); - var xsubs = [' (^!) ', - ' (^!) ']; - var e1 = hot('---------x---------x---------|'); - var e1subs = '^ !'; - var expected = '-----------------------------|'; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner never', function () { - var x = cold('-'); - var xsubs = [' ^ ! ', - ' ^ ']; - var e1 = hot('---------x---------x---------|'); - var e1subs = '^ '; - var expected = '------------------------------'; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch to an inner that just raises an error', function () { - var x = cold('#'); - var xsubs = ' (^!) '; - var e1 = hot('---------x---------x---------|'); - var e1subs = '^ ! '; - var expected = '---------# '; - - expectObservable(e1.switchMapTo(x)).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an empty outer', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.switchMapTo(Observable.of('foo'))).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle a never outer', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.switchMapTo(Observable.of('foo'))).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle an outer that just raises and error', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.switchMapTo(Observable.of('foo'))).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should switch with resultSelector goodness', function () { - var x = cold( '--1--2--3--4--5--| '); - var xsubs = [' ^ ! ', - // --1--2--3--4--5--| - ' ^ !']; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ !'; - var expected = '-----------a--b--c---d--e--f--g--h--|'; - var expectedValues = { - a: ['x', '1', 0, 0], - b: ['x', '2', 0, 1], - c: ['x', '3', 0, 2], - d: ['y', '1', 1, 0], - e: ['y', '2', 1, 1], - f: ['y', '3', 1, 2], - g: ['y', '4', 1, 3], - h: ['y', '5', 1, 4] - }; - - var result = e1.switchMapTo(x, function (a, b, ai, bi) { - return [a, b, ai, bi]; - }); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when resultSelector throws', function () { - var x = cold( '--1--2--3--4--5--| '); - var xsubs = ' ^ ! '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ !'; - var expected = '-----------#'; - - var result = e1.switchMapTo(x, function () { - throw 'error'; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/switchMapTo-spec.ts b/spec/operators/switchMapTo-spec.ts new file mode 100644 index 0000000000..eb36dfba84 --- /dev/null +++ b/spec/operators/switchMapTo-spec.ts @@ -0,0 +1,251 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.switchMapTo()', () => { + it('should switch a synchronous many outer to a synchronous many inner', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3); + const expected = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']; + a.switchMapTo(Observable.of('a', 'b', 'c')).subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, done); + }); + + it('should unsub inner observables', () => { + let unsubbed = 0; + + Observable.of('a', 'b').switchMapTo( + Observable.create((subscriber: Rx.Subscriber) => { + subscriber.complete(); + return () => { + unsubbed++; + }; + }) + ).subscribe(); + + expect(unsubbed).toEqual(2); + }); + + it('should switch to an inner cold observable', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = [' ^ ! ', + // --a--b--c--d--e--| + ' ^ !']; + const e1 = hot('---------x---------x---------| '); + const e1subs = '^ !'; + const expected = '-----------a--b--c---a--b--c--d--e--|'; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner cold observable, outer eventually throws', () => { + const x = cold( '--a--b--c--d--e--|'); + const xsubs = ' ^ ! '; + const e1 = hot('---------x---------# '); + const e1subs = '^ ! '; + const expected = '-----------a--b--c-# '; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner cold observable, outer is unsubscribed early', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = [' ^ ! ', + // --a--b--c--d--e--| + ' ^ ! ']; + const e1 = hot('---------x---------x---------|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '-----------a--b--c---a- '; + + expectObservable(e1.switchMapTo(x), unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = [' ^ ! ', + // --a--b--c--d--e--| + ' ^ ! ']; + const e1 = hot('---------x---------x---------|'); + const e1subs = '^ ! '; + const expected = '-----------a--b--c---a- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .switchMapTo(x) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner cold observable, inner never completes', () => { + const x = cold( '--a--b--c--d--e- '); + const xsubs = [' ^ ! ', + // --a--b--c--d--e- + ' ^ ']; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ '; + const expected = '-----------a--b--c---a--b--c--d--e-'; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a synchronous switch to the inner observable', () => { + const x = cold( '--a--b--c--d--e--| '); + const xsubs = [' (^!) ', + ' ^ ! ']; + const e1 = hot('---------(xx)----------------|'); + const e1subs = '^ !'; + const expected = '-----------a--b--c--d--e-----|'; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner cold observable, inner raises an error', () => { + const x = cold( '--a--b--# '); + const xsubs = ' ^ ! '; + const e1 = hot('---------x---------x---------|'); + const e1subs = '^ ! '; + const expected = '-----------a--b--# '; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch an inner hot observable', () => { + const x = hot('--p-o-o-p---a--b--c--d-| '); + const xsubs = [' ^ ! ', + ' ^ ! ']; + const e1 = hot('---------x---------x---------|'); + const e1subs = '^ !'; + const expected = '------------a--b--c--d-------|'; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner empty', () => { + const x = cold('|'); + const xsubs = [' (^!) ', + ' (^!) ']; + const e1 = hot('---------x---------x---------|'); + const e1subs = '^ !'; + const expected = '-----------------------------|'; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner never', () => { + const x = cold('-'); + const xsubs = [' ^ ! ', + ' ^ ']; + const e1 = hot('---------x---------x---------|'); + const e1subs = '^ '; + const expected = '------------------------------'; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch to an inner that just raises an error', () => { + const x = cold('#'); + const xsubs = ' (^!) '; + const e1 = hot('---------x---------x---------|'); + const e1subs = '^ ! '; + const expected = '---------# '; + + expectObservable(e1.switchMapTo(x)).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an empty outer', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.switchMapTo(Observable.of('foo'))).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle a never outer', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.switchMapTo(Observable.of('foo'))).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle an outer that just raises and error', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.switchMapTo(Observable.of('foo'))).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should switch with resultSelector goodness', () => { + const x = cold( '--1--2--3--4--5--| '); + const xsubs = [' ^ ! ', + // --1--2--3--4--5--| + ' ^ !']; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ !'; + const expected = '-----------a--b--c---d--e--f--g--h--|'; + const expectedValues = { + a: ['x', '1', 0, 0], + b: ['x', '2', 0, 1], + c: ['x', '3', 0, 2], + d: ['y', '1', 1, 0], + e: ['y', '2', 1, 1], + f: ['y', '3', 1, 2], + g: ['y', '4', 1, 3], + h: ['y', '5', 1, 4] + }; + + const result = e1.switchMapTo(x, (a, b, ai, bi) => [a, b, ai, bi]); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when resultSelector throws', () => { + const x = cold( '--1--2--3--4--5--| '); + const xsubs = ' ^ ! '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ !'; + const expected = '-----------#'; + + const result = e1.switchMapTo(x, () => { + throw 'error'; + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/take-spec.js b/spec/operators/take-spec.js deleted file mode 100644 index 89d77ba80e..0000000000 --- a/spec/operators/take-spec.js +++ /dev/null @@ -1,125 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.take()', function () { - it.asDiagram('take(2)')('should take two values of an observable with many values', function () { - var e1 = cold('--a-----b----c---d--|'); - var e1subs = '^ ! '; - var expected = '--a-----(b|) '; - - expectObservable(e1.take(2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.take(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should go on forever on never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.take(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be empty on take(0)', function () { - var e1 = hot('--a--^--b----c---d--|'); - var e1subs = []; // Don't subscribe at all - var expected = '|'; - - expectObservable(e1.take(0)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take one value of an observable with one value', function () { - var e1 = hot('---(a|)'); - var e1subs = '^ ! '; - var expected = '---(a|)'; - - expectObservable(e1.take(1)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take one values of an observable with many values', function () { - var e1 = hot('--a--^--b----c---d--|'); - var e1subs = '^ ! '; - var expected = '---(b|) '; - - expectObservable(e1.take(1)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error on empty', function () { - var e1 = hot('--a--^----|'); - var e1subs = '^ !'; - var expected = '-----|'; - - expectObservable(e1.take(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should propagate error from the source observable', function () { - var e1 = hot('---^---#', null, 'too bad'); - var e1subs = '^ !'; - var expected = '----#'; - - expectObservable(e1.take(42)).toBe(expected, null, 'too bad'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should propagate error from an observable with values', function () { - var e1 = hot('---^--a--b--#'); - var e1subs = '^ !'; - var expected = '---a--b--#'; - - expectObservable(e1.take(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('---^--a--b-----c--d--e--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---a--b--- '; - - expectObservable(e1.take(42), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.take(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should throw if total is less than zero', function () { - expect(function () { Observable.range(0,10).take(-1); }) - .toThrow(new Rx.ArgumentOutOfRangeError()); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('---^--a--b-----c--d--e--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---a--b--- '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .take(42) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/take-spec.ts b/spec/operators/take-spec.ts new file mode 100644 index 0000000000..bfcb84059b --- /dev/null +++ b/spec/operators/take-spec.ts @@ -0,0 +1,127 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.take()', () => { + asDiagram('take(2)')('should take two values of an observable with many values', () => { + const e1 = cold('--a-----b----c---d--|'); + const e1subs = '^ ! '; + const expected = '--a-----(b|) '; + + expectObservable(e1.take(2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.take(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should go on forever on never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.take(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be empty on take(0)', () => { + const e1 = hot('--a--^--b----c---d--|'); + const e1subs = []; // Don't subscribe at all + const expected = '|'; + + expectObservable(e1.take(0)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take one value of an observable with one value', () => { + const e1 = hot('---(a|)'); + const e1subs = '^ ! '; + const expected = '---(a|)'; + + expectObservable(e1.take(1)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take one values of an observable with many values', () => { + const e1 = hot('--a--^--b----c---d--|'); + const e1subs = '^ ! '; + const expected = '---(b|) '; + + expectObservable(e1.take(1)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error on empty', () => { + const e1 = hot('--a--^----|'); + const e1subs = '^ !'; + const expected = '-----|'; + + expectObservable(e1.take(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should propagate error from the source observable', () => { + const e1 = hot('---^---#', null, 'too bad'); + const e1subs = '^ !'; + const expected = '----#'; + + expectObservable(e1.take(42)).toBe(expected, null, 'too bad'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should propagate error from an observable with values', () => { + const e1 = hot('---^--a--b--#'); + const e1subs = '^ !'; + const expected = '---a--b--#'; + + expectObservable(e1.take(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('---^--a--b-----c--d--e--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---a--b--- '; + + expectObservable(e1.take(42), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.take(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should throw if total is less than zero', () => { + expect(() => { Observable.range(0,10).take(-1); }) + .toThrow(new Rx.ArgumentOutOfRangeError()); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('---^--a--b-----c--d--e--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---a--b--- '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .take(42) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/takeLast-spec.js b/spec/operators/takeLast-spec.js deleted file mode 100644 index c79b789216..0000000000 --- a/spec/operators/takeLast-spec.js +++ /dev/null @@ -1,125 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.takeLast()', function () { - it.asDiagram('takeLast(2)')('should take two values of an observable with many values', function () { - var e1 = cold('--a-----b----c---d--| '); - var e1subs = '^ ! '; - var expected = '--------------------(cd|)'; - - expectObservable(e1.takeLast(2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.takeLast(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should go on forever on never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.takeLast(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be empty on takeLast(0)', function () { - var e1 = hot('--a--^--b----c---d--|'); - var e1subs = []; // Don't subscribe at all - var expected = '|'; - - expectObservable(e1.takeLast(0)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take one value from an observable with one value', function () { - var e1 = hot('---(a|)'); - var e1subs = '^ ! '; - var expected = '---(a|)'; - - expectObservable(e1.takeLast(1)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take one value from an observable with many values', function () { - var e1 = hot('--a--^--b----c---d--| '); - var e1subs = '^ ! '; - var expected = '---------------(d|)'; - - expectObservable(e1.takeLast(1)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should error on empty', function () { - var e1 = hot('--a--^----|'); - var e1subs = '^ !'; - var expected = '-----|'; - - expectObservable(e1.takeLast(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should propagate error from the source observable', function () { - var e1 = hot('---^---#', null, 'too bad'); - var e1subs = '^ !'; - var expected = '----#'; - - expectObservable(e1.takeLast(42)).toBe(expected, null, 'too bad'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should propagate error from an observable with values', function () { - var e1 = hot('---^--a--b--#'); - var e1subs = '^ !'; - var expected = '---------#'; - - expectObservable(e1.takeLast(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('---^--a--b-----c--d--e--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---------- '; - - expectObservable(e1.takeLast(42), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.takeLast(42)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should throw if total is less than zero', function () { - expect(function () { Observable.range(0,10).takeLast(-1); }) - .toThrow(new Rx.ArgumentOutOfRangeError()); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('---^--a--b-----c--d--e--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '---------- '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .takeLast(42) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/takeLast-spec.ts b/spec/operators/takeLast-spec.ts new file mode 100644 index 0000000000..52ba35fbce --- /dev/null +++ b/spec/operators/takeLast-spec.ts @@ -0,0 +1,127 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.takeLast()', () => { + asDiagram('takeLast(2)')('should take two values of an observable with many values', () => { + const e1 = cold('--a-----b----c---d--| '); + const e1subs = '^ ! '; + const expected = '--------------------(cd|)'; + + expectObservable(e1.takeLast(2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.takeLast(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should go on forever on never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.takeLast(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be empty on takeLast(0)', () => { + const e1 = hot('--a--^--b----c---d--|'); + const e1subs = []; // Don't subscribe at all + const expected = '|'; + + expectObservable(e1.takeLast(0)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take one value from an observable with one value', () => { + const e1 = hot('---(a|)'); + const e1subs = '^ ! '; + const expected = '---(a|)'; + + expectObservable(e1.takeLast(1)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take one value from an observable with many values', () => { + const e1 = hot('--a--^--b----c---d--| '); + const e1subs = '^ ! '; + const expected = '---------------(d|)'; + + expectObservable(e1.takeLast(1)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should error on empty', () => { + const e1 = hot('--a--^----|'); + const e1subs = '^ !'; + const expected = '-----|'; + + expectObservable(e1.takeLast(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should propagate error from the source observable', () => { + const e1 = hot('---^---#', null, 'too bad'); + const e1subs = '^ !'; + const expected = '----#'; + + expectObservable(e1.takeLast(42)).toBe(expected, null, 'too bad'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should propagate error from an observable with values', () => { + const e1 = hot('---^--a--b--#'); + const e1subs = '^ !'; + const expected = '---------#'; + + expectObservable(e1.takeLast(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('---^--a--b-----c--d--e--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---------- '; + + expectObservable(e1.takeLast(42), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.takeLast(42)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should throw if total is less than zero', () => { + expect(() => { Observable.range(0,10).takeLast(-1); }) + .toThrow(new Rx.ArgumentOutOfRangeError()); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('---^--a--b-----c--d--e--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '---------- '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .takeLast(42) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/takeUntil-spec.js b/spec/operators/takeUntil-spec.js deleted file mode 100644 index d2e88669fe..0000000000 --- a/spec/operators/takeUntil-spec.js +++ /dev/null @@ -1,192 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.takeUntil()', function () { - it.asDiagram('takeUntil')('should take values until notifier emits', function () { - var e1 = hot('--a--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var e2 = hot('-------------z--| '); - var e2subs = '^ ! '; - var expected = '--a--b--c--d-| '; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should take values and raises error when notifier raises error', function () { - var e1 = hot('--a--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var e2 = hot('-------------# '); - var e2subs = '^ ! '; - var expected = '--a--b--c--d-# '; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should take all values when notifier is empty', function () { - var e1 = hot('--a--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var e2 = hot('-------------| '); - var e2subs = '^ ! '; - var expected = '--a--b--c--d--e--f--g--|'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should take all values when notifier does not complete', function () { - var e1 = hot('--a--b--c--d--e--f--g--|'); - var e1subs = '^ !'; - var e2 = hot('-'); - var e2subs = '^ !'; - var expected = '--a--b--c--d--e--f--g--|'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var e2 = hot('-------------z--| '); - var e2subs = '^ ! '; - var unsub = ' ! '; - var expected = '--a--b-- '; - - expectObservable(e1.takeUntil(e2), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should complete when notifier emits if source observable does not complete', function () { - var e1 = hot('-'); - var e1subs = '^ !'; - var e2 = hot('--a--b--|'); - var e2subs = '^ !'; - var expected = '--|'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error when notifier raises error if source observable does not complete', function () { - var e1 = hot('-'); - var e1subs = '^ !'; - var e2 = hot('--#'); - var e2subs = '^ !'; - var expected = '--#'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete when notifier is empty if source observable does not complete', function () { - var e1 = hot('-'); - var e1subs = '^'; - var e2 = hot('--|'); - var e2subs = '^ !'; - var expected = '---'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not complete when source and notifier do not complete', function () { - var e1 = hot('-'); - var e1subs = '^'; - var e2 = hot('-'); - var e2subs = '^'; - var expected = '-'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should complete when notifier emits before source observable emits', function () { - var e1 = hot('----a--|'); - var e1subs = '^ ! '; - var e2 = hot('--x '); - var e2subs = '^ ! '; - var expected = '--| '; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error if source raises error before notifier emits', function () { - var e1 = hot('--a--b--c--d--# '); - var e1subs = '^ ! '; - var e2 = hot('----------------a--|'); - var e2subs = '^ ! '; - var expected = '--a--b--c--d--# '; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error immediately if source throws', function () { - var e1 = cold( '#'); - var e1subs = '(^!)'; - var e2 = hot('--x'); - var e2subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should dispose source observable if notifier emits before source emits', function () { - var e1 = hot('---a---|'); - var e1subs = '^ ! '; - var e2 = hot('--x-| '); - var e2subs = '^ ! '; - var expected = '--| '; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should dispose notifier if source observable completes', function () { - var e1 = hot('--a--| '); - var e1subs = '^ ! '; - var e2 = hot('-------x--|'); - var e2subs = '^ ! '; - var expected = '--a--| '; - - expectObservable(e1.takeUntil(e2)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('--a--b--c--d--e--f--g--|'); - var e1subs = '^ ! '; - var e2 = hot('-------------z--| '); - var e2subs = '^ ! '; - var unsub = ' ! '; - var expected = '--a--b-- '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .takeUntil(e2) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); diff --git a/spec/operators/takeUntil-spec.ts b/spec/operators/takeUntil-spec.ts new file mode 100644 index 0000000000..e6599c5ceb --- /dev/null +++ b/spec/operators/takeUntil-spec.ts @@ -0,0 +1,194 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.takeUntil()', () => { + asDiagram('takeUntil')('should take values until notifier emits', () => { + const e1 = hot('--a--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const e2 = hot('-------------z--| '); + const e2subs = '^ ! '; + const expected = '--a--b--c--d-| '; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should take values and raises error when notifier raises error', () => { + const e1 = hot('--a--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const e2 = hot('-------------# '); + const e2subs = '^ ! '; + const expected = '--a--b--c--d-# '; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should take all values when notifier is empty', () => { + const e1 = hot('--a--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const e2 = hot('-------------| '); + const e2subs = '^ ! '; + const expected = '--a--b--c--d--e--f--g--|'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should take all values when notifier does not complete', () => { + const e1 = hot('--a--b--c--d--e--f--g--|'); + const e1subs = '^ !'; + const e2 = hot('-'); + const e2subs = '^ !'; + const expected = '--a--b--c--d--e--f--g--|'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const e2 = hot('-------------z--| '); + const e2subs = '^ ! '; + const unsub = ' ! '; + const expected = '--a--b-- '; + + expectObservable(e1.takeUntil(e2), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should complete when notifier emits if source observable does not complete', () => { + const e1 = hot('-'); + const e1subs = '^ !'; + const e2 = hot('--a--b--|'); + const e2subs = '^ !'; + const expected = '--|'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error when notifier raises error if source observable does not complete', () => { + const e1 = hot('-'); + const e1subs = '^ !'; + const e2 = hot('--#'); + const e2subs = '^ !'; + const expected = '--#'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete when notifier is empty if source observable does not complete', () => { + const e1 = hot('-'); + const e1subs = '^'; + const e2 = hot('--|'); + const e2subs = '^ !'; + const expected = '---'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not complete when source and notifier do not complete', () => { + const e1 = hot('-'); + const e1subs = '^'; + const e2 = hot('-'); + const e2subs = '^'; + const expected = '-'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should complete when notifier emits before source observable emits', () => { + const e1 = hot('----a--|'); + const e1subs = '^ ! '; + const e2 = hot('--x '); + const e2subs = '^ ! '; + const expected = '--| '; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error if source raises error before notifier emits', () => { + const e1 = hot('--a--b--c--d--# '); + const e1subs = '^ ! '; + const e2 = hot('----------------a--|'); + const e2subs = '^ ! '; + const expected = '--a--b--c--d--# '; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error immediately if source throws', () => { + const e1 = cold( '#'); + const e1subs = '(^!)'; + const e2 = hot('--x'); + const e2subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should dispose source observable if notifier emits before source emits', () => { + const e1 = hot('---a---|'); + const e1subs = '^ ! '; + const e2 = hot('--x-| '); + const e2subs = '^ ! '; + const expected = '--| '; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should dispose notifier if source observable completes', () => { + const e1 = hot('--a--| '); + const e1subs = '^ ! '; + const e2 = hot('-------x--|'); + const e2subs = '^ ! '; + const expected = '--a--| '; + + expectObservable(e1.takeUntil(e2)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('--a--b--c--d--e--f--g--|'); + const e1subs = '^ ! '; + const e2 = hot('-------------z--| '); + const e2subs = '^ ! '; + const unsub = ' ! '; + const expected = '--a--b-- '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .takeUntil(e2) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); diff --git a/spec/operators/takeWhile-spec.js b/spec/operators/takeWhile-spec.js deleted file mode 100644 index a8f74b358b..0000000000 --- a/spec/operators/takeWhile-spec.js +++ /dev/null @@ -1,200 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.takeWhile()', function () { - it.asDiagram('takeWhile(x => x < 4)')('should take all elements until predicate is false', function () { - var source = hot('-1-^2--3--4--5--6--|'); - var sourceSubs = '^ ! '; - var expected = '-2--3--| '; - - var result = source.takeWhile(function (v) { return +v < 4; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should take all elements with predicate returns true', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '--b--c--d--e--|'; - - expectObservable(e1.takeWhile(function () { return true; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take all elements with truthy predicate', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '--b--c--d--e--|'; - - expectObservable(e1.takeWhile(function () { return {}; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should skip all elements with predicate returns false', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--| '; - - expectObservable(e1.takeWhile(function () { return false; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should skip all elements with falsy predicate', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--| '; - - expectObservable(e1.takeWhile(function () { return null; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take all elements until predicate return false', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--b--c--| '; - - function predicate(value) { - return value !== 'd'; - } - - expectObservable(e1.takeWhile(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take elements with predicate when source does not complete', function () { - var e1 = hot('--a-^-b--c--d--e--'); - var e1subs = '^ '; - var expected = '--b--c--d--e--'; - - expectObservable(e1.takeWhile(function () { return true; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not complete when source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - var result = e1.takeWhile(function () { return true; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete when source does not emit', function () { - var e1 = hot('--a-^------------|'); - var e1subs = '^ !'; - var expected = '-------------|'; - - expectObservable(e1.takeWhile(function () { return true; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - var result = e1.takeWhile(function () { return true; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should pass element index to predicate', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--b--c--| '; - - function predicate(value, index) { - return index < 2; - } - - expectObservable(e1.takeWhile(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when source raises error', function () { - var e1 = hot('--a-^-b--c--d--e--#'); - var e1subs = '^ !'; - var expected = '--b--c--d--e--#'; - - expectObservable(e1.takeWhile(function () { return true; })).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error when source throws', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(source.takeWhile(function () { return true; })).toBe(expected); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should invoke predicate until return false', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--b--c--| '; - - var invoked = 0; - function predicate(value) { - invoked++; - return value !== 'd'; - } - - var source = e1.takeWhile(predicate).do(null, null, function () { - expect(invoked).toBe(3); - }); - expectObservable(source).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if predicate throws', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--# '; - - function predicate(value) { - throw 'error'; - } - - expectObservable(e1.takeWhile(predicate)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take elements until unsubscribed', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var unsub = '-----! '; - var e1subs = '^ ! '; - var expected = '--b--- '; - - function predicate(value) { - return value !== 'd'; - } - - expectObservable(e1.takeWhile(predicate), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('--a-^-b--c--d--e--|'); - var unsub = '-----! '; - var e1subs = '^ ! '; - var expected = '--b--- '; - - function predicate(value) { - return value !== 'd'; - } - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .takeWhile(predicate) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/takeWhile-spec.ts b/spec/operators/takeWhile-spec.ts new file mode 100644 index 0000000000..db59cd8401 --- /dev/null +++ b/spec/operators/takeWhile-spec.ts @@ -0,0 +1,201 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; +describe('Observable.prototype.takeWhile()', () => { + asDiagram('takeWhile(x => x < 4)')('should take all elements until predicate is false', () => { + const source = hot('-1-^2--3--4--5--6--|'); + const sourceSubs = '^ ! '; + const expected = '-2--3--| '; + + const result = source.takeWhile((v: any) => +v < 4); + + expectObservable(result).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should take all elements with predicate returns true', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '--b--c--d--e--|'; + + expectObservable(e1.takeWhile(() => true)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take all elements with truthy predicate', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '--b--c--d--e--|'; + + expectObservable(e1.takeWhile((() => { return {}; }))).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should skip all elements with predicate returns false', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--| '; + + expectObservable(e1.takeWhile(() => false)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should skip all elements with falsy predicate', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--| '; + + expectObservable(e1.takeWhile(() => null)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take all elements until predicate return false', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--b--c--| '; + + function predicate(value) { + return value !== 'd'; + } + + expectObservable(e1.takeWhile(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take elements with predicate when source does not complete', () => { + const e1 = hot('--a-^-b--c--d--e--'); + const e1subs = '^ '; + const expected = '--b--c--d--e--'; + + expectObservable(e1.takeWhile(() => true)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not complete when source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + const result = e1.takeWhile(() => true); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete when source does not emit', () => { + const e1 = hot('--a-^------------|'); + const e1subs = '^ !'; + const expected = '-------------|'; + + expectObservable(e1.takeWhile(() => true)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + const result = e1.takeWhile(() => true); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should pass element index to predicate', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--b--c--| '; + + function predicate(value, index) { + return index < 2; + } + + expectObservable(e1.takeWhile(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when source raises error', () => { + const e1 = hot('--a-^-b--c--d--e--#'); + const e1subs = '^ !'; + const expected = '--b--c--d--e--#'; + + expectObservable(e1.takeWhile(() => true)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error when source throws', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable(source.takeWhile(() => true)).toBe(expected); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should invoke predicate until return false', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--b--c--| '; + + let invoked = 0; + function predicate(value) { + invoked++; + return value !== 'd'; + } + + const source = e1.takeWhile(predicate).do(null, null, () => { + expect(invoked).toBe(3); + }); + expectObservable(source).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if predicate throws', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--# '; + + function predicate(value) { + throw 'error'; + } + + expectObservable(e1.takeWhile(predicate)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take elements until unsubscribed', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const unsub = '-----! '; + const e1subs = '^ ! '; + const expected = '--b--- '; + + function predicate(value) { + return value !== 'd'; + } + + expectObservable(e1.takeWhile(predicate), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('--a-^-b--c--d--e--|'); + const unsub = '-----! '; + const e1subs = '^ ! '; + const expected = '--b--- '; + + function predicate(value) { + return value !== 'd'; + } + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .takeWhile(predicate) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/throttle-spec.js b/spec/operators/throttle-spec.js deleted file mode 100644 index 52ac90c327..0000000000 --- a/spec/operators/throttle-spec.js +++ /dev/null @@ -1,333 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscription, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Scheduler = Rx.Scheduler; -var Promise = require('promise'); - -describe('Observable.prototype.throttle()', function () { - it.asDiagram('throttle')('should immediately emit the first value in each time window', function () { - var e1 = hot('-a-xy-----b--x--cxxx-|'); - var e1subs = '^ !'; - var e2 = cold( '----| '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-a--------b-----c----|'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should simply mirror the source if values are not emitted often enough', function () { - var e1 = hot('-a--------b-----c----|'); - var e1subs = '^ !'; - var e2 = cold( '----| '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-a--------b-----c----|'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should throttle with duration Observable using next to close the duration', function () { - var e1 = hot('-a-xy-----b--x--cxxx-|'); - var e1subs = '^ !'; - var e2 = cold( '----x-y-z '); - var e2subs = [' ^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = '-a--------b-----c----|'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should interrupt source and duration when result is unsubscribed early', function () { - var e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var e2 = cold( '------------------| '); - var e2subs = ' ^ ! '; - var expected = '-a------------- '; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); - var e1subs = '^ ! '; - var e2 = cold( '------------------| '); - var e2subs = ' ^ ! '; - var expected = '-a------------- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .throttle(function () { return e2; }) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a busy producer emitting a regular repeating sequence', function () { - var e1 = hot('abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ !'; - var e2 = cold('-----| '); - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^!']; - var expected = 'a-----a-----a-----a-----a|'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should mirror source if durations are always empty', function () { - var e1 = hot('abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ !'; - var e2 = cold('|'); - var expected = 'abcdefabcdefabcdefabcdefa|'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should take only the first value emitted if duration is a never', function () { - var e1 = hot('----abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ !'; - var e2 = cold('-'); - var e2subs = ' ^ !'; - var expected = '----a------------------------|'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should unsubscribe duration Observable when source raise error', function () { - var e1 = hot('----abcdefabcdefabcdefabcdefa#'); - var e1subs = '^ !'; - var e2 = cold('-'); - var e2subs = ' ^ !'; - var expected = '----a------------------------#'; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should raise error as soon as just-throw duration is used', function () { - var e1 = hot('----abcdefabcdefabcdefabcdefa|'); - var e1subs = '^ ! '; - var e2 = cold('#'); - var e2subs = ' (^!) '; - var expected = '----(a#) '; - - var result = e1.throttle(function () { return e2; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should throttle using durations of varying lengths', function () { - var e1 = hot('abcdefabcdabcdefghabca| '); - var e1subs = '^ ! '; - var e2 = [cold('-----| '), - cold( '---| '), - cold( '-------| '), - cold( '--| '), - cold( '----|')]; - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^! ']; - var expected = 'a-----a---a-------a--a| '; - - var i = 0; - var result = e1.throttle(function () { return e2[i++]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var j = 0; j < e2.length; j++) { - expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); - } - }); - - it('should propagate error from duration Observable', function () { - var e1 = hot('abcdefabcdabcdefghabca| '); - var e1subs = '^ ! '; - var e2 = [cold('-----| '), - cold( '---| '), - cold( '-------# ')]; - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = 'a-----a---a------# '; - - var i = 0; - var result = e1.throttle(function () { return e2[i++]; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var j = 0; j < e2.length; j++) { - expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); - } - }); - - it('should propagate error thrown from durationSelector function', function () { - var e1 = hot('abcdefabcdabcdefghabca| '); - var e1subs = '^ ! '; - var e2 = [cold('-----| '), - cold( '---| '), - cold( '-------| ')]; - var e2subs = ['^ ! ', - ' ^ ! ']; - var expected = 'a-----a---# '; - - var i = 0; - var result = e1.throttle(function () { - if (i === 2) { - throw 'error'; - } - return e2[i++]; - }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - for (var j = 0; j < e2subs.length; j++) { - expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); - } - }); - - it('should complete when source does not emit', function () { - var e1 = hot('-----|'); - var subs = '^ !'; - var expected = '-----|'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.throttle(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source does not emit and raises error', function () { - var e1 = hot('-----#'); - var subs = '^ !'; - var expected = '-----#'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.throttle(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle an empty source', function () { - var e1 = cold('|'); - var subs = '(^!)'; - var expected = '|'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.throttle(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a never source', function () { - var e1 = cold('-'); - var subs = '^'; - var expected = '-'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.throttle(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a throw source', function () { - var e1 = cold('#'); - var subs = '(^!)'; - var expected = '#'; - function durationSelector() { return cold('-----|'); } - - expectObservable(e1.throttle(durationSelector)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should throttle by promise resolves', function (done) { - var e1 = Observable.concat(Observable.of(1), - Observable.timer(10).mapTo(2), - Observable.timer(10).mapTo(3), - Observable.timer(50).mapTo(4) - ); - var expected = [1,2,3,4]; - - e1.throttle(function () { - return new Promise(function (resolve) { resolve(42); }); - }).subscribe( - function (x) { - expect(x).toEqual(expected.shift()); }, - function () { - throw 'should not be called'; - }, - function () { - expect(expected.length).toBe(0); - done(); - } - ); - }); - - it('should raise error when promise rejects', function (done) { - var e1 = Observable.concat(Observable.of(1), - Observable.timer(10).mapTo(2), - Observable.timer(10).mapTo(3), - Observable.timer(50).mapTo(4) - ); - var expected = [1,2,3]; - var error = new Error('error'); - - e1.throttle(function (x) { - if (x === 3) { - return new Promise(function (resolve, reject) {reject(error);}); - } else { - return new Promise(function (resolve) {resolve(42);}); - } - }).subscribe( - function (x) { - expect(x).toEqual(expected.shift()); }, - function (err) { - expect(err).toBe(error); - expect(expected.length).toBe(0); - done(); - }, - function () { - throw 'should not be called'; - } - ); - }); -}); diff --git a/spec/operators/throttle-spec.ts b/spec/operators/throttle-spec.ts new file mode 100644 index 0000000000..6d1a9bb36b --- /dev/null +++ b/spec/operators/throttle-spec.ts @@ -0,0 +1,333 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.throttle()', () => { + asDiagram('throttle')('should immediately emit the first value in each time window', () => { + const e1 = hot('-a-xy-----b--x--cxxx-|'); + const e1subs = '^ !'; + const e2 = cold( '----| '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-a--------b-----c----|'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should simply mirror the source if values are not emitted often enough', () => { + const e1 = hot('-a--------b-----c----|'); + const e1subs = '^ !'; + const e2 = cold( '----| '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-a--------b-----c----|'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should throttle with duration Observable using next to close the duration', () => { + const e1 = hot('-a-xy-----b--x--cxxx-|'); + const e1subs = '^ !'; + const e2 = cold( '----x-y-z '); + const e2subs = [' ^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = '-a--------b-----c----|'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should interrupt source and duration when result is unsubscribed early', () => { + const e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const e2 = cold( '------------------| '); + const e2subs = ' ^ ! '; + const expected = '-a------------- '; + + const result = e1.throttle(() => e2); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-a-x-y-z-xyz-x-y-z----b--x-x-|'); + const e1subs = '^ ! '; + const e2 = cold( '------------------| '); + const e2subs = ' ^ ! '; + const expected = '-a------------- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .throttle(() => e2) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a busy producer emitting a regular repeating sequence', () => { + const e1 = hot('abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ !'; + const e2 = cold('-----| '); + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^!']; + const expected = 'a-----a-----a-----a-----a|'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should mirror source if durations are always empty', () => { + const e1 = hot('abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ !'; + const e2 = cold('|'); + const expected = 'abcdefabcdefabcdefabcdefa|'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should take only the first value emitted if duration is a never', () => { + const e1 = hot('----abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ !'; + const e2 = cold('-'); + const e2subs = ' ^ !'; + const expected = '----a------------------------|'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should unsubscribe duration Observable when source raise error', () => { + const e1 = hot('----abcdefabcdefabcdefabcdefa#'); + const e1subs = '^ !'; + const e2 = cold('-'); + const e2subs = ' ^ !'; + const expected = '----a------------------------#'; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should raise error as soon as just-throw duration is used', () => { + const e1 = hot('----abcdefabcdefabcdefabcdefa|'); + const e1subs = '^ ! '; + const e2 = cold('#'); + const e2subs = ' (^!) '; + const expected = '----(a#) '; + + const result = e1.throttle(() => e2); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should throttle using durations of constying lengths', () => { + const e1 = hot('abcdefabcdabcdefghabca| '); + const e1subs = '^ ! '; + const e2 = [cold('-----| '), + cold( '---| '), + cold( '-------| '), + cold( '--| '), + cold( '----|')]; + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^! ']; + const expected = 'a-----a---a-------a--a| '; + + let i = 0; + const result = e1.throttle(() => e2[i++]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + for (let j = 0; j < e2.length; j++) { + expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); + } + }); + + it('should propagate error from duration Observable', () => { + const e1 = hot('abcdefabcdabcdefghabca| '); + const e1subs = '^ ! '; + const e2 = [cold('-----| '), + cold( '---| '), + cold( '-------# ')]; + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = 'a-----a---a------# '; + + let i = 0; + const result = e1.throttle(() => e2[i++]); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + for (let j = 0; j < e2.length; j++) { + expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); + } + }); + + it('should propagate error thrown from durationSelector function', () => { + const e1 = hot('abcdefabcdabcdefghabca| '); + const e1subs = '^ ! '; + const e2 = [cold('-----| '), + cold( '---| '), + cold( '-------| ')]; + const e2subs = ['^ ! ', + ' ^ ! ']; + const expected = 'a-----a---# '; + + let i = 0; + const result = e1.throttle(() => { + if (i === 2) { + throw 'error'; + } + return e2[i++]; + }); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + for (let j = 0; j < e2subs.length; j++) { + expectSubscriptions(e2[j].subscriptions).toBe(e2subs[j]); + } + }); + + it('should complete when source does not emit', () => { + const e1 = hot('-----|'); + const subs = '^ !'; + const expected = '-----|'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.throttle(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source does not emit and raises error', () => { + const e1 = hot('-----#'); + const subs = '^ !'; + const expected = '-----#'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.throttle(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle an empty source', () => { + const e1 = cold('|'); + const subs = '(^!)'; + const expected = '|'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.throttle(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a never source', () => { + const e1 = cold('-'); + const subs = '^'; + const expected = '-'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.throttle(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a throw source', () => { + const e1 = cold('#'); + const subs = '(^!)'; + const expected = '#'; + function durationSelector() { return cold('-----|'); } + + expectObservable(e1.throttle(durationSelector)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should throttle by promise resolves', (done: DoneSignature) => { + const e1 = Observable.concat(Observable.of(1), + Observable.timer(10).mapTo(2), + Observable.timer(10).mapTo(3), + Observable.timer(50).mapTo(4) + ); + const expected = [1,2,3,4]; + + e1.throttle(() => { + return new Promise((resolve: any) => { resolve(42); }); + }).subscribe( + (x: number) => { + expect(x).toEqual(expected.shift()); }, + () => { + done.fail('should not be called'); + }, + () => { + expect(expected.length).toBe(0); + done(); + } + ); + }); + + it('should raise error when promise rejects', (done: DoneSignature) => { + const e1 = Observable.concat(Observable.of(1), + Observable.timer(10).mapTo(2), + Observable.timer(10).mapTo(3), + Observable.timer(50).mapTo(4) + ); + const expected = [1,2,3]; + const error = new Error('error'); + + e1.throttle((x: number) => { + if (x === 3) { + return new Promise((resolve: any, reject: any) => {reject(error);}); + } else { + return new Promise((resolve: any) => {resolve(42);}); + } + }).subscribe( + (x: number) => { + expect(x).toEqual(expected.shift()); }, + (err: any) => { + expect(err).toBe(error); + expect(expected.length).toBe(0); + done(); + }, + () => { + done.fail('should not be called'); + } + ); + }); +}); diff --git a/spec/operators/throttleTime-spec.js b/spec/operators/throttleTime-spec.js deleted file mode 100644 index 12ee7df523..0000000000 --- a/spec/operators/throttleTime-spec.js +++ /dev/null @@ -1,135 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscription, hot, cold, rxTestScheduler, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Scheduler = Rx.Scheduler; - -describe('Observable.prototype.throttleTime()', function () { - it.asDiagram('throttleTime(50)')('should immediately emit the first value in each time window', function () { - var e1 = hot('-a-x-y----b---x-cx---|'); - var subs = '^ !'; - var expected = '-a--------b-----c----|'; - - var result = e1.throttleTime(50, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should throttle events by 50 time units', function (done) { - Observable.of(1, 2, 3).throttleTime(50) - .subscribe(function (x) { - expect(x).toBe(1); - }, null, done); - }); - - it('should throttle events multiple times', function () { - var expected = ['1-0', '2-0']; - Observable.concat( - Observable.timer(0, 10, rxTestScheduler).take(3).map(function (x) { return '1-' + x; }), - Observable.timer(80, 10, rxTestScheduler).take(5).map(function (x) { return '2-' + x; }) - ) - .throttleTime(50, rxTestScheduler) - .subscribe(function (x) { - expect(x).toBe(expected.shift()); - }); - - rxTestScheduler.flush(); - }); - - it('should simply mirror the source if values are not emitted often enough', function () { - var e1 = hot('-a--------b-----c----|'); - var subs = '^ !'; - var expected = '-a--------b-----c----|'; - - expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a busy producer emitting a regular repeating sequence', function () { - var e1 = hot('abcdefabcdefabcdefabcdefa|'); - var subs = '^ !'; - var expected = 'a-----a-----a-----a-----a|'; - - expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should complete when source does not emit', function () { - var e1 = hot('-----|'); - var subs = '^ !'; - var expected = '-----|'; - - expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should raise error when source does not emit and raises error', function () { - var e1 = hot('-----#'); - var subs = '^ !'; - var expected = '-----#'; - - expectObservable(e1.throttleTime(10, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle an empty source', function () { - var e1 = cold('|'); - var subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.throttleTime(30, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a never source', function () { - var e1 = cold('-'); - var subs = '^'; - var expected = '-'; - - expectObservable(e1.throttleTime(30, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should handle a throw source', function () { - var e1 = cold('#'); - var subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.throttleTime(30, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should throttle and does not complete when source does not completes', function () { - var e1 = hot('-a--(bc)-------d----------------'); - var unsub = ' !'; - var subs = '^ !'; - var expected = '-a-------------d----------------'; - - expectObservable(e1.throttleTime(50, rxTestScheduler), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-a--(bc)-------d----------------'); - var subs = '^ !'; - var expected = '-a-------------d----------------'; - var unsub = ' !'; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .throttleTime(50, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); - - it('should throttle values until source raises error', function () { - var e1 = hot('-a--(bc)-------d---------------#'); - var subs = '^ !'; - var expected = '-a-------------d---------------#'; - - expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/throttleTime-spec.ts b/spec/operators/throttleTime-spec.ts new file mode 100644 index 0000000000..b22763af27 --- /dev/null +++ b/spec/operators/throttleTime-spec.ts @@ -0,0 +1,138 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; +const Scheduler = Rx.Scheduler; + +describe('Observable.prototype.throttleTime()', () => { + asDiagram('throttleTime(50)')('should immediately emit the first value in each time window', () => { + const e1 = hot('-a-x-y----b---x-cx---|'); + const subs = '^ !'; + const expected = '-a--------b-----c----|'; + + const result = e1.throttleTime(50, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should throttle events by 50 time units', (done: DoneSignature) => { + Observable.of(1, 2, 3).throttleTime(50) + .subscribe((x: number) => { + expect(x).toBe(1); + }, null, done); + }); + + it('should throttle events multiple times', () => { + const expected = ['1-0', '2-0']; + Observable.concat( + Observable.timer(0, 10, rxTestScheduler).take(3).map((x: number) => '1-' + x), + Observable.timer(80, 10, rxTestScheduler).take(5).map((x: number) => '2-' + x) + ) + .throttleTime(50, rxTestScheduler) + .subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }); + + rxTestScheduler.flush(); + }); + + it('should simply mirror the source if values are not emitted often enough', () => { + const e1 = hot('-a--------b-----c----|'); + const subs = '^ !'; + const expected = '-a--------b-----c----|'; + + expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a busy producer emitting a regular repeating sequence', () => { + const e1 = hot('abcdefabcdefabcdefabcdefa|'); + const subs = '^ !'; + const expected = 'a-----a-----a-----a-----a|'; + + expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should complete when source does not emit', () => { + const e1 = hot('-----|'); + const subs = '^ !'; + const expected = '-----|'; + + expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should raise error when source does not emit and raises error', () => { + const e1 = hot('-----#'); + const subs = '^ !'; + const expected = '-----#'; + + expectObservable(e1.throttleTime(10, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle an empty source', () => { + const e1 = cold('|'); + const subs = '(^!)'; + const expected = '|'; + + expectObservable(e1.throttleTime(30, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a never source', () => { + const e1 = cold('-'); + const subs = '^'; + const expected = '-'; + + expectObservable(e1.throttleTime(30, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should handle a throw source', () => { + const e1 = cold('#'); + const subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.throttleTime(30, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should throttle and does not complete when source does not completes', () => { + const e1 = hot('-a--(bc)-------d----------------'); + const unsub = ' !'; + const subs = '^ !'; + const expected = '-a-------------d----------------'; + + expectObservable(e1.throttleTime(50, rxTestScheduler), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-a--(bc)-------d----------------'); + const subs = '^ !'; + const expected = '-a-------------d----------------'; + const unsub = ' !'; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .throttleTime(50, rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); + + it('should throttle values until source raises error', () => { + const e1 = hot('-a--(bc)-------d---------------#'); + const subs = '^ !'; + const expected = '-a-------------d---------------#'; + + expectObservable(e1.throttleTime(50, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/timeInterval-spec.js b/spec/operators/timeInterval-spec.js deleted file mode 100644 index 46a231cdc4..0000000000 --- a/spec/operators/timeInterval-spec.js +++ /dev/null @@ -1,144 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.timeInterval()', function () { - it.asDiagram('timeInterval')('should record the time interval between source elements', function () { - var e1 = hot('--a--^b-c-----d--e--|'); - var e1subs = '^ !'; - var expected = '-w-x-----y--z--|'; - var expectedValue = { w: 10, x: 20, y: 60, z: 30 }; - - var result = e1.timeInterval(rxTestScheduler) - .map(function (x) { return x.interval; }); - - expectObservable(result).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should record interval if source emit elements', function () { - var e1 = hot('--a--^b--c----d---e--|'); - var e1subs = '^ !'; - var expected = '-w--x----y---z--|'; - - var expectedValue = { - w: new Rx.TimeInterval('b', 10), - x: new Rx.TimeInterval('c', 30), - y: new Rx.TimeInterval('d', 50), - z: new Rx.TimeInterval('e', 40) - }; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should completes without record interval if source does not emits', function () { - var e1 = hot('---------|'); - var e1subs = '^ !'; - var expected = '---------|'; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should complete immediately if source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should record interval then does not completes if source emits but not completes', function () { - var e1 = hot('-a--b--'); - var e1subs = '^ '; - var expected = '-y--z--'; - - var expectedValue = { - y: new Rx.TimeInterval('a', 10), - z: new Rx.TimeInterval('b', 30) - }; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('-a--b-----c---d---|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '-y--z--- '; - - var expectedValue = { - y: new Rx.TimeInterval('a', 10), - z: new Rx.TimeInterval('b', 30) - }; - - var result = e1.timeInterval(rxTestScheduler); - - expectObservable(result, unsub).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('-a--b-----c---d---|'); - var e1subs = '^ ! '; - var expected = '-y--z--- '; - var unsub = ' ! '; - - var expectedValue = { - y: new Rx.TimeInterval('a', 10), - z: new Rx.TimeInterval('b', 30) - }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .timeInterval(rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not completes if source never completes', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('raise error if source raises error', function () { - var e1 = hot('---#'); - var e1subs = '^ !'; - var expected = '---#'; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should record interval then raise error if source raises error after emit', function () { - var e1 = hot('-a--b--#'); - var e1subs = '^ !'; - var expected = '-y--z--#'; - - var expectedValue = { - y: new Rx.TimeInterval('a', 10), - z: new Rx.TimeInterval('b', 30) - }; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected, expectedValue); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if source immediately throws', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.timeInterval(rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/timeInterval-spec.ts b/spec/operators/timeInterval-spec.ts new file mode 100644 index 0000000000..42a9787fd2 --- /dev/null +++ b/spec/operators/timeInterval-spec.ts @@ -0,0 +1,147 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.timeInterval()', () => { + asDiagram('timeInterval')('should record the time interval between source elements', () => { + const e1 = hot('--a--^b-c-----d--e--|'); + const e1subs = '^ !'; + const expected = '-w-x-----y--z--|'; + const expectedValue = { w: 10, x: 20, y: 60, z: 30 }; + + const result = (e1).timeInterval(rxTestScheduler) + .map((x: any) => x.interval); + + expectObservable(result).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should record interval if source emit elements', () => { + const e1 = hot('--a--^b--c----d---e--|'); + const e1subs = '^ !'; + const expected = '-w--x----y---z--|'; + + const expectedValue = { + w: new Rx.TimeInterval('b', 10), + x: new Rx.TimeInterval('c', 30), + y: new Rx.TimeInterval('d', 50), + z: new Rx.TimeInterval('e', 40) + }; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should completes without record interval if source does not emits', () => { + const e1 = hot('---------|'); + const e1subs = '^ !'; + const expected = '---------|'; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should complete immediately if source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should record interval then does not completes if source emits but not completes', () => { + const e1 = hot('-a--b--'); + const e1subs = '^ '; + const expected = '-y--z--'; + + const expectedValue = { + y: new Rx.TimeInterval('a', 10), + z: new Rx.TimeInterval('b', 30) + }; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('-a--b-----c---d---|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '-y--z--- '; + + const expectedValue = { + y: new Rx.TimeInterval('a', 10), + z: new Rx.TimeInterval('b', 30) + }; + + const result = (e1).timeInterval(rxTestScheduler); + + expectObservable(result, unsub).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('-a--b-----c---d---|'); + const e1subs = '^ ! '; + const expected = '-y--z--- '; + const unsub = ' ! '; + + const expectedValue = { + y: new Rx.TimeInterval('a', 10), + z: new Rx.TimeInterval('b', 30) + }; + + const result = (e1) + .mergeMap((x: string) => Observable.of(x)) + .timeInterval(rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not completes if source never completes', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('raise error if source raises error', () => { + const e1 = hot('---#'); + const e1subs = '^ !'; + const expected = '---#'; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should record interval then raise error if source raises error after emit', () => { + const e1 = hot('-a--b--#'); + const e1subs = '^ !'; + const expected = '-y--z--#'; + + const expectedValue = { + y: new Rx.TimeInterval('a', 10), + z: new Rx.TimeInterval('b', 30) + }; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected, expectedValue); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if source immediately throws', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable((e1).timeInterval(rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/timeout-spec.js b/spec/operators/timeout-spec.js deleted file mode 100644 index 7c5f9ef848..0000000000 --- a/spec/operators/timeout-spec.js +++ /dev/null @@ -1,139 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.timeout()', function () { - var defaultTimeoutError = new Error('timeout'); - - it.asDiagram('timeout(50)')('should timeout after a specified timeout period', function () { - var e1 = cold('-------a--b--|'); - var e1subs = '^ ! '; - var expected = '-----# '; - - var result = e1.timeout(50, null, rxTestScheduler); - - expectObservable(result).toBe(expected, null, defaultTimeoutError); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should timeout after specified timeout period and send the passed error', function () { - var e1 = cold('-'); - var e1subs = '^ !'; - var expected = '-----#'; - var value = 'hello'; - - var result = e1.timeout(50, value, rxTestScheduler); - - expectObservable(result).toBe(expected, null, value); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not timeout if source completes within absolute timeout period', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '--a--b--c--d--e--|'; - - var timeoutValue = new Date(rxTestScheduler.now() + (expected.length + 2) * 10); - - expectObservable(e1.timeout(timeoutValue, null, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not timeout if source emits within timeout period', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var expected = '--a--b--c--d--e--|'; - - expectObservable(e1.timeout(50, null, rxTestScheduler)).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b--c---d--e--|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '--a--b--c-- '; - - var result = e1.timeout(50, null, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b--c---d--e--|'); - var e1subs = '^ ! '; - var expected = '--a--b--c-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .timeout(50, null, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should timeout after a specified timeout period between emit with default ' + - 'error while source emits', function () { - var e1 = hot('---a---b---c------d---e---|'); - var e1subs = '^ ! '; - var expected = '---a---b---c----# '; - var values = {a: 'a', b: 'b', c: 'c'}; - - var result = e1.timeout(50, null, rxTestScheduler); - - expectObservable(result).toBe(expected, values, defaultTimeoutError); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should timeout after a specified delay with passed error while source emits', function () { - var value = 'hello'; - var e1 = hot('---a---b---c------d---e---|'); - var e1subs = '^ ! '; - var expected = '---a---b---c----# '; - var values = {a: 'a', b: 'b', c: 'c'}; - - var result = e1.timeout(50, value, rxTestScheduler); - - expectObservable(result).toBe(expected, values, value); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should timeout at a specified Date', function () { - var e1 = cold('-'); - var e1subs = '^ !'; - var expected = '----------#'; - - var result = e1.timeout(new Date(rxTestScheduler.now() + 100), null, rxTestScheduler); - - expectObservable(result).toBe(expected, null, defaultTimeoutError); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should timeout specified Date with default error while source emits', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--a--b--c-# '; - var values = {a: 'a', b: 'b', c: 'c'}; - - var result = e1.timeout(new Date(rxTestScheduler.now() + 100), null, rxTestScheduler); - - expectObservable(result).toBe(expected, values, defaultTimeoutError); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should timeout specified Date with passed error while source emits', function () { - var value = 'hello'; - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ ! '; - var expected = '--a--b--c-# '; - var values = {a: 'a', b: 'b', c: 'c'}; - - var result = e1.timeout(new Date(rxTestScheduler.now() + 100), value, rxTestScheduler); - - expectObservable(result).toBe(expected, values, value); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/timeout-spec.ts b/spec/operators/timeout-spec.ts new file mode 100644 index 0000000000..1fd67351b3 --- /dev/null +++ b/spec/operators/timeout-spec.ts @@ -0,0 +1,142 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.timeout()', () => { + const defaultTimeoutError = new Error('timeout'); + + asDiagram('timeout(50)')('should timeout after a specified timeout period', () => { + const e1 = cold('-------a--b--|'); + const e1subs = '^ ! '; + const expected = '-----# '; + + const result = e1.timeout(50, null, rxTestScheduler); + + expectObservable(result).toBe(expected, null, defaultTimeoutError); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should timeout after specified timeout period and send the passed error', () => { + const e1 = cold('-'); + const e1subs = '^ !'; + const expected = '-----#'; + const value = 'hello'; + + const result = e1.timeout(50, value, rxTestScheduler); + + expectObservable(result).toBe(expected, null, value); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not timeout if source completes within absolute timeout period', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '--a--b--c--d--e--|'; + + const timeoutValue = new Date(rxTestScheduler.now() + (expected.length + 2) * 10); + + expectObservable(e1.timeout(timeoutValue, null, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not timeout if source emits within timeout period', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const expected = '--a--b--c--d--e--|'; + + expectObservable(e1.timeout(50, null, rxTestScheduler)).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b--c---d--e--|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '--a--b--c-- '; + + const result = e1.timeout(50, null, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b--c---d--e--|'); + const e1subs = '^ ! '; + const expected = '--a--b--c-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .timeout(50, null, rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should timeout after a specified timeout period between emit with default ' + + 'error while source emits', () => { + const e1 = hot('---a---b---c------d---e---|'); + const e1subs = '^ ! '; + const expected = '---a---b---c----# '; + const values = {a: 'a', b: 'b', c: 'c'}; + + const result = e1.timeout(50, null, rxTestScheduler); + + expectObservable(result).toBe(expected, values, defaultTimeoutError); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should timeout after a specified delay with passed error while source emits', () => { + const value = 'hello'; + const e1 = hot('---a---b---c------d---e---|'); + const e1subs = '^ ! '; + const expected = '---a---b---c----# '; + const values = {a: 'a', b: 'b', c: 'c'}; + + const result = e1.timeout(50, value, rxTestScheduler); + + expectObservable(result).toBe(expected, values, value); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should timeout at a specified Date', () => { + const e1 = cold('-'); + const e1subs = '^ !'; + const expected = '----------#'; + + const result = e1.timeout(new Date(rxTestScheduler.now() + 100), null, rxTestScheduler); + + expectObservable(result).toBe(expected, null, defaultTimeoutError); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should timeout specified Date with default error while source emits', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--a--b--c-# '; + const values = {a: 'a', b: 'b', c: 'c'}; + + const result = e1.timeout(new Date(rxTestScheduler.now() + 100), null, rxTestScheduler); + + expectObservable(result).toBe(expected, values, defaultTimeoutError); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should timeout specified Date with passed error while source emits', () => { + const value = 'hello'; + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ ! '; + const expected = '--a--b--c-# '; + const values = {a: 'a', b: 'b', c: 'c'}; + + const result = e1.timeout(new Date(rxTestScheduler.now() + 100), value, rxTestScheduler); + + expectObservable(result).toBe(expected, values, value); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/timeoutWith-spec.js b/spec/operators/timeoutWith-spec.js deleted file mode 100644 index d3cd5074aa..0000000000 --- a/spec/operators/timeoutWith-spec.js +++ /dev/null @@ -1,260 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('Observable.prototype.timeoutWith()', function () { - it.asDiagram('timeoutWith(50)')('should timeout after a specified period then subscribe to the passed observable', function () { - var e1 = cold('-------a--b--|'); - var e1subs = '^ ! '; - var e2 = cold('x-y-z-| '); - var e2subs = ' ^ ! '; - var expected = '-----x-y-z-| '; - - var result = e1.timeoutWith(50, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout at a specified date then subscribe to the passed observable', function () { - var e1 = cold('-'); - var e1subs = '^ ! '; - var e2 = cold( '--x--y--z--|'); - var e2subs = ' ^ !'; - var expected = '------------x--y--z--|'; - - var result = e1.timeoutWith(new Date(rxTestScheduler.now() + 100), e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout after a specified period between emit then subscribe ' + - 'to the passed observable when source emits', function () { - var e1 = hot('---a---b------c---|'); - var e1subs = '^ ! '; - var e2 = cold( '-x-y-| '); - var e2subs = ' ^ ! '; - var expected = '---a---b----x-y-| '; - - var result = e1.timeoutWith(40, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('---a---b-----c----|'); - var e1subs = '^ ! '; - var e2 = cold( '-x---y| '); - var e2subs = ' ^ ! '; - var expected = '---a---b----x-- '; - var unsub = ' ! '; - - var result = e1.timeoutWith(40, e2, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('---a---b-----c----|'); - var e1subs = '^ ! '; - var e2 = cold( '-x---y| '); - var e2subs = ' ^ ! '; - var expected = '---a---b----x-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .timeoutWith(40, e2, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not subscribe to withObservable after explicit unsubscription', function () { - var e1 = cold('---a------b------'); - var e1subs = '^ ! '; - var e2 = cold( 'i---j---|'); - var e2subs = []; - var expected = '---a-- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .timeoutWith(50, e2, rxTestScheduler) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout after a specified period then subscribe to the ' + - 'passed observable when source is empty', function () { - var e1 = hot('-------------| '); - var e1subs = '^ ! '; - var e2 = cold( '----x----|'); - var e2subs = ' ^ !'; - var expected = '--------------x----|'; - - var result = e1.timeoutWith(100, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout after a specified period between emit then never completes ' + - 'if other source does not complete', function () { - var e1 = hot('--a--b--------c--d--|'); - var e1subs = '^ ! '; - var e2 = cold('-'); - var e2subs = ' ^ '; - var expected = '--a--b---- '; - - var result = e1.timeoutWith(40, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout after a specified period then subscribe to the ' + - 'passed observable when source raises error after timeout', function () { - var e1 = hot('-------------# '); - var e1subs = '^ ! '; - var e2 = cold( '----x----|'); - var e2subs = ' ^ !'; - var expected = '--------------x----|'; - - var result = e1.timeoutWith(100, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout after a specified period between emit then never completes ' + - 'if other source emits but not complete', function () { - var e1 = hot('-------------| '); - var e1subs = '^ ! '; - var e2 = cold('----x----'); - var e2subs = ' ^ '; - var expected = '--------------x----'; - - var result = e1.timeoutWith(100, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not timeout if source completes within timeout period', function () { - var e1 = hot('-----|'); - var e1subs = '^ !'; - var e2 = cold( '----x----'); - var e2subs = []; - var expected = '-----|'; - - var result = e1.timeoutWith(100, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not timeout if source raises error within timeout period', function () { - var e1 = hot('-----#'); - var e1subs = '^ !'; - var e2 = cold( '----x----|'); - var e2subs = []; - var expected = '-----#'; - - var result = e1.timeoutWith(100, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not timeout if source emits within timeout period', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var e2 = cold('----x----|'); - var e2subs = []; - var expected = '--a--b--c--d--e--|'; - - var result = e1.timeoutWith(50, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout after specified Date then subscribe to the passed observable', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ ! '; - var e2 = cold( '--z--| '); - var e2subs = ' ^ ! '; - var expected = '--a--b---z--| '; - - var result = e1.timeoutWith(new Date(rxTestScheduler.now() + 70), e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not timeout if source completes within specified Date', function () { - var e1 = hot('--a--b--c--d--e--|'); - var e1subs = '^ !'; - var e2 = cold('--x--|'); - var e2subs = []; - var expected = '--a--b--c--d--e--|'; - - var timeoutValue = new Date(Date.now() + (expected.length + 2) * 10); - - var result = e1.timeoutWith(timeoutValue, e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should not timeout if source raises error within specified Date', function () { - var e1 = hot('---a---#'); - var e1subs = '^ !'; - var e2 = cold('--x--|'); - var e2subs = []; - var expected = '---a---#'; - - var result = e1.timeoutWith(new Date(Date.now() + 100), e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should timeout specified Date after specified Date then never completes ' + - 'if other source does not complete', function () { - var e1 = hot('---a---b---c---d---e---|'); - var e1subs = '^ ! '; - var e2 = cold('-'); - var e2subs = ' ^ '; - var expected = '---a---b--- '; - - var result = e1.timeoutWith(new Date(rxTestScheduler.now() + 100), e2, rxTestScheduler); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); diff --git a/spec/operators/timeoutWith-spec.ts b/spec/operators/timeoutWith-spec.ts new file mode 100644 index 0000000000..c278ba173d --- /dev/null +++ b/spec/operators/timeoutWith-spec.ts @@ -0,0 +1,263 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.timeoutWith()', () => { + asDiagram('timeoutWith(50)')('should timeout after a specified period then subscribe to the passed observable', () => { + const e1 = cold('-------a--b--|'); + const e1subs = '^ ! '; + const e2 = cold('x-y-z-| '); + const e2subs = ' ^ ! '; + const expected = '-----x-y-z-| '; + + const result = e1.timeoutWith(50, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout at a specified date then subscribe to the passed observable', () => { + const e1 = cold('-'); + const e1subs = '^ ! '; + const e2 = cold( '--x--y--z--|'); + const e2subs = ' ^ !'; + const expected = '------------x--y--z--|'; + + const result = e1.timeoutWith(new Date(rxTestScheduler.now() + 100), e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout after a specified period between emit then subscribe ' + + 'to the passed observable when source emits', () => { + const e1 = hot('---a---b------c---|'); + const e1subs = '^ ! '; + const e2 = cold( '-x-y-| '); + const e2subs = ' ^ ! '; + const expected = '---a---b----x-y-| '; + + const result = e1.timeoutWith(40, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('---a---b-----c----|'); + const e1subs = '^ ! '; + const e2 = cold( '-x---y| '); + const e2subs = ' ^ ! '; + const expected = '---a---b----x-- '; + const unsub = ' ! '; + + const result = e1.timeoutWith(40, e2, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('---a---b-----c----|'); + const e1subs = '^ ! '; + const e2 = cold( '-x---y| '); + const e2subs = ' ^ ! '; + const expected = '---a---b----x-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .timeoutWith(40, e2, rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not subscribe to withObservable after explicit unsubscription', () => { + const e1 = cold('---a------b------'); + const e1subs = '^ ! '; + const e2 = cold( 'i---j---|'); + const e2subs = []; + const expected = '---a-- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .timeoutWith(50, e2, rxTestScheduler) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout after a specified period then subscribe to the ' + + 'passed observable when source is empty', () => { + const e1 = hot('-------------| '); + const e1subs = '^ ! '; + const e2 = cold( '----x----|'); + const e2subs = ' ^ !'; + const expected = '--------------x----|'; + + const result = e1.timeoutWith(100, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout after a specified period between emit then never completes ' + + 'if other source does not complete', () => { + const e1 = hot('--a--b--------c--d--|'); + const e1subs = '^ ! '; + const e2 = cold('-'); + const e2subs = ' ^ '; + const expected = '--a--b---- '; + + const result = e1.timeoutWith(40, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout after a specified period then subscribe to the ' + + 'passed observable when source raises error after timeout', () => { + const e1 = hot('-------------# '); + const e1subs = '^ ! '; + const e2 = cold( '----x----|'); + const e2subs = ' ^ !'; + const expected = '--------------x----|'; + + const result = e1.timeoutWith(100, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout after a specified period between emit then never completes ' + + 'if other source emits but not complete', () => { + const e1 = hot('-------------| '); + const e1subs = '^ ! '; + const e2 = cold('----x----'); + const e2subs = ' ^ '; + const expected = '--------------x----'; + + const result = e1.timeoutWith(100, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not timeout if source completes within timeout period', () => { + const e1 = hot('-----|'); + const e1subs = '^ !'; + const e2 = cold( '----x----'); + const e2subs = []; + const expected = '-----|'; + + const result = e1.timeoutWith(100, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not timeout if source raises error within timeout period', () => { + const e1 = hot('-----#'); + const e1subs = '^ !'; + const e2 = cold( '----x----|'); + const e2subs = []; + const expected = '-----#'; + + const result = e1.timeoutWith(100, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not timeout if source emits within timeout period', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const e2 = cold('----x----|'); + const e2subs = []; + const expected = '--a--b--c--d--e--|'; + + const result = e1.timeoutWith(50, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout after specified Date then subscribe to the passed observable', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ ! '; + const e2 = cold( '--z--| '); + const e2subs = ' ^ ! '; + const expected = '--a--b---z--| '; + + const result = e1.timeoutWith(new Date(rxTestScheduler.now() + 70), e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not timeout if source completes within specified Date', () => { + const e1 = hot('--a--b--c--d--e--|'); + const e1subs = '^ !'; + const e2 = cold('--x--|'); + const e2subs = []; + const expected = '--a--b--c--d--e--|'; + + const timeoutValue = new Date(Date.now() + (expected.length + 2) * 10); + + const result = e1.timeoutWith(timeoutValue, e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should not timeout if source raises error within specified Date', () => { + const e1 = hot('---a---#'); + const e1subs = '^ !'; + const e2 = cold('--x--|'); + const e2subs = []; + const expected = '---a---#'; + + const result = e1.timeoutWith(new Date(Date.now() + 100), e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should timeout specified Date after specified Date then never completes ' + + 'if other source does not complete', () => { + const e1 = hot('---a---b---c---d---e---|'); + const e1subs = '^ ! '; + const e2 = cold('-'); + const e2subs = ' ^ '; + const expected = '---a---b--- '; + + const result = e1.timeoutWith(new Date(rxTestScheduler.now() + 100), e2, rxTestScheduler); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); diff --git a/spec/operators/toArray-spec.js b/spec/operators/toArray-spec.js deleted file mode 100644 index e1f66190a9..0000000000 --- a/spec/operators/toArray-spec.js +++ /dev/null @@ -1,102 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, cold, hot */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; - -describe('toArray', function () { - it.asDiagram('toArray')('should reduce the values of an observable into an array', function () { - var e1 = hot('---a--b--|'); - var e1subs = '^ !'; - var expected = '---------(w|)'; - - expectObservable(e1.toArray()).toBe(expected, { w: ['a', 'b'] }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be never when source is never', function () { - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; - - expectObservable(e1.toArray()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be never when source is empty', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '(w|)'; - - expectObservable(e1.toArray()).toBe(expected, { w: [] }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should be never when source doesn\'t complete', function () { - var e1 = hot('--x--^--y--'); - var e1subs = '^ '; - var expected = '------'; - - expectObservable(e1.toArray()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should reduce observable without values into an array of length zero', function () { - var e1 = hot('-x-^---|'); - var e1subs = '^ !'; - var expected = '----(w|)'; - - expectObservable(e1.toArray()).toBe(expected, { w: [] }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should reduce the a single value of an observable into an array', function () { - var e1 = hot('-x-^--y--|'); - var e1subs = '^ !'; - var expected = '------(w|)'; - - expectObservable(e1.toArray()).toBe(expected, { w: ['y'] }); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should allow unsubscribing explicitly and early', function () { - var e1 = hot('--a--b----c-----d----e---|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '--------- '; - - expectObservable(e1.toArray(), unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--b----c-----d----e---|'); - var e1subs = '^ ! '; - var expected = '--------- '; - var unsub = ' ! '; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .toArray() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with error', function () { - var e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); - var e1subs = '^ !'; - var expected = '---------#'; - - expectObservable(e1.toArray()).toBe(expected, null, 'too bad'); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; - - expectObservable(e1.toArray()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); -}); diff --git a/spec/operators/toArray-spec.ts b/spec/operators/toArray-spec.ts new file mode 100644 index 0000000000..65038547eb --- /dev/null +++ b/spec/operators/toArray-spec.ts @@ -0,0 +1,104 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('toArray', () => { + asDiagram('toArray')('should reduce the values of an observable into an array', () => { + const e1 = hot('---a--b--|'); + const e1subs = '^ !'; + const expected = '---------(w|)'; + + expectObservable(e1.toArray()).toBe(expected, { w: ['a', 'b'] }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be never when source is never', () => { + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; + + expectObservable(e1.toArray()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be never when source is empty', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '(w|)'; + + expectObservable(e1.toArray()).toBe(expected, { w: [] }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should be never when source doesn\'t complete', () => { + const e1 = hot('--x--^--y--'); + const e1subs = '^ '; + const expected = '------'; + + expectObservable(e1.toArray()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should reduce observable without values into an array of length zero', () => { + const e1 = hot('-x-^---|'); + const e1subs = '^ !'; + const expected = '----(w|)'; + + expectObservable(e1.toArray()).toBe(expected, { w: [] }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should reduce the a single value of an observable into an array', () => { + const e1 = hot('-x-^--y--|'); + const e1subs = '^ !'; + const expected = '------(w|)'; + + expectObservable(e1.toArray()).toBe(expected, { w: ['y'] }); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should allow unsubscribing explicitly and early', () => { + const e1 = hot('--a--b----c-----d----e---|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '--------- '; + + expectObservable(e1.toArray(), unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--b----c-----d----e---|'); + const e1subs = '^ ! '; + const expected = '--------- '; + const unsub = ' ! '; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .toArray() + .mergeMap((x: Array) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with error', () => { + const e1 = hot('-x-^--y--z--#', { x: 1, y: 2, z: 3 }, 'too bad'); + const e1subs = '^ !'; + const expected = '---------#'; + + expectObservable(e1.toArray()).toBe(expected, null, 'too bad'); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; + + expectObservable(e1.toArray()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); +}); diff --git a/spec/operators/toPromise-spec.js b/spec/operators/toPromise-spec.js deleted file mode 100644 index 2b26f30db8..0000000000 --- a/spec/operators/toPromise-spec.js +++ /dev/null @@ -1,38 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); -var Promise = require('promise'); -var Observable = Rx.Observable; - -describe('Observable.prototype.toPromise()', function () { - it('should convert an Observable to a promise of its last value', function (done) { - Observable.of(1, 2, 3).toPromise(Promise).then(function (x) { - expect(x).toBe(3); - done(); - }); - }); - - it('should handle errors properly', function (done) { - Observable.throw('bad').toPromise(Promise).then(function () { - throw 'should not be called'; - }, function (err) { - expect(err).toBe('bad'); - done(); - }); - }); - - it('should allow for global config via Rx.config.Promise', function (done) { - var wasCalled = false; - __root__.Rx = {}; - __root__.Rx.config = {}; - __root__.Rx.config.Promise = function MyPromise(callback) { - wasCalled = true; - return new Promise(callback); - }; - - Observable.of(42).toPromise().then(function (x) { - expect(wasCalled).toBe(true); - expect(x).toBe(42); - done(); - }); - }); -}); \ No newline at end of file diff --git a/spec/operators/toPromise-spec.ts b/spec/operators/toPromise-spec.ts new file mode 100644 index 0000000000..f5b5fbaad4 --- /dev/null +++ b/spec/operators/toPromise-spec.ts @@ -0,0 +1,40 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const __root__: any; +const Observable = Rx.Observable; + +describe('Observable.prototype.toPromise()', () => { + it('should convert an Observable to a promise of its last value', (done: DoneSignature) => { + Observable.of(1, 2, 3).toPromise(Promise).then((x: number) => { + expect(x).toBe(3); + done(); + }); + }); + + it('should handle errors properly', (done: DoneSignature) => { + Observable.throw('bad').toPromise(Promise).then(() => { + done.fail('should not be called'); + }, function (err) { + expect(err).toBe('bad'); + done(); + }); + }); + + it('should allow for global config via Rx.config.Promise', (done: DoneSignature) => { + var wasCalled = false; + __root__.Rx = {}; + __root__.Rx.config = {}; + __root__.Rx.config.Promise = function MyPromise(callback) { + wasCalled = true; + return new Promise(callback); + }; + + Observable.of(42).toPromise().then((x: number) => { + expect(wasCalled).toBe(true); + expect(x).toBe(42); + done(); + }); + }); +}); \ No newline at end of file diff --git a/spec/operators/window-spec.js b/spec/operators/window-spec.js deleted file mode 100644 index 2cec1abeb9..0000000000 --- a/spec/operators/window-spec.js +++ /dev/null @@ -1,255 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.window', function () { - it.asDiagram('window')('should emit windows that close and reopen', function () { - var source = hot('---a---b---c---d---e---f---g---h---i---| '); - var sourceSubs = '^ ! '; - var closings = hot('-------------w------------w----------------|'); - var closingSubs = '^ ! '; - var expected = 'x------------y------------z------------| '; - var x = cold( '---a---b---c-| '); - var y = cold( '--d---e---f--| '); - var z = cold( '-g---h---i---| '); - var expectedValues = { x: x, y: y, z: z }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should return a single empty window if source is empty and closings are basic', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var closings = cold('--x--x--|'); - var closingSubs = '(^!)'; - var expected = '(w|)'; - var w = cold('|'); - var expectedValues = { w: w }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should return a single empty window if source is empty and closing is empty', function () { - var source = cold('|'); - var sourceSubs = '(^!)'; - var closings = cold('|'); - var closingSubs = '(^!)'; - var expected = '(w|)'; - var w = cold('|'); - var expectedValues = { w: w }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should split a Just source into a single window identical to source, using a Never closing', - function () { - var source = cold('(a|)'); - var sourceSubs = '(^!)'; - var closings = cold('-'); - var closingSubs = '(^!)'; - var expected = '(w|)'; - var w = cold('(a|)'); - var expectedValues = { w: w }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should return a single Never window if source is Never', function () { - var source = cold('------'); - var sourceSubs = '^ '; - var closings = cold('------'); - var closingSubs = '^ '; - var expected = 'w-----'; - var w = cold('------'); - var expectedValues = { w: w }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should be able to split a never Observable into timely empty windows', function () { - var source = hot('^--------'); - var sourceSubs = '^ !'; - var closings = cold('--x--x--|'); - var closingSubs = '^ !'; - var expected = 'a-b--c--|'; - var a = cold('--| '); - var b = cold( '---| '); - var c = cold( '---|'); - var expectedValues = { a: a, b: b, c: c }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should emit an error-only window if outer is a simple throw-Observable', function () { - var source = cold('#'); - var sourceSubs = '(^!)'; - var closings = cold('--x--x--|'); - var closingSubs = '(^!)'; - var expected = '(w#)'; - var w = cold('#'); - var expectedValues = { w: w }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should handle basic case with window closings', function () { - var source = hot('-1-2-^3-4-5-6-7-8-9-| '); - var subs = '^ ! '; - var closings = hot('---^---x---x---x---x---x---|'); - var closingSubs = '^ ! '; - var expected = 'a---b---c---d--| '; - var a = cold( '-3-4| '); - var b = cold( '-5-6| '); - var c = cold( '-7-8| '); - var d = cold( '-9-| '); - var expectedValues = { a: a, b: b, c: c, d: d }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should handle basic case with window closings, but outer throws', function () { - var source = hot('-1-2-^3-4-5-6-7-8-9-# '); - var subs = '^ ! '; - var closings = hot('---^---x---x---x---x---x---|'); - var closingSubs = '^ ! '; - var expected = 'a---b---c---d--# '; - var a = cold( '-3-4| '); - var b = cold( '-5-6| '); - var c = cold( '-7-8| '); - var d = cold( '-9-# '); - var expectedValues = { a: a, b: b, c: c, d: d }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should stop emitting windows when outer is unsubscribed early', function () { - var source = hot('-1-2-^3-4-5-6-7-8-9-| '); - var subs = '^ ! '; - var closings = hot('---^---x---x---x---x---x---|'); - var closingSubs = '^ ! '; - var expected = 'a---b---- '; - var a = cold( '-3-4| '); - var b = cold( '-5-6 '); - var unsub = ' ! '; - var expectedValues = { a: a, b: b }; - - var result = source.window(closings); - - expectObservable(result, unsub).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('-1-2-^3-4-5-6-7-8-9-| '); - var subs = '^ ! '; - var closings = hot('---^---x---x---x---x---x---|'); - var closingSubs = '^ ! '; - var expected = 'a---b---- '; - var a = cold( '-3-4| '); - var b = cold( '-5-6- '); - var unsub = ' ! '; - var expectedValues = { a: a, b: b }; - - var result = source - .mergeMap(function (x) { return Observable.of(x); }) - .window(closings) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should dispose window Subjects if the outer is unsubscribed early', function () { - var source = hot('--a--b--c--d--e--f--g--h--|'); - var sourceSubs = '^ ! '; - var expected = 'x--------- '; - var x = cold( '--a--b--c- '); - var unsub = ' ! '; - var late = time('---------------| '); - var values = { x: x }; - - var window; - var result = source.window(Observable.never()) - .do(function (w) { window = w; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - rxTestScheduler.schedule(function () { - expect(function () { - window.subscribe(); - }).toThrow(new Rx.ObjectUnsubscribedError()); - }, late); - }); - - it('should make outer emit error when closing throws', function () { - var source = hot('-1-2-^3-4-5-6-7-8-9-#'); - var subs = '^ ! '; - var closings = hot('---^---# '); - var closingSubs = '^ ! '; - var expected = 'a---# '; - var a = cold( '-3-4# '); - var expectedValues = { a: a }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); - - it('should complete the resulting Observable when window closings completes', function () { - var source = hot('-1-2-^3-4-5-6-7-8-9-|'); - var subs = '^ ! '; - var closings = hot('---^---x---x---| '); - var closingSubs = '^ ! '; - var expected = 'a---b---c---| '; - var a = cold( '-3-4| '); - var b = cold( '-5-6| '); - var c = cold( '-7-8| '); - var expectedValues = { a: a, b: b, c: c }; - - var result = source.window(closings); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(closings.subscriptions).toBe(closingSubs); - }); -}); \ No newline at end of file diff --git a/spec/operators/window-spec.ts b/spec/operators/window-spec.ts new file mode 100644 index 0000000000..a92bda8015 --- /dev/null +++ b/spec/operators/window-spec.ts @@ -0,0 +1,258 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.window', () => { + asDiagram('window')('should emit windows that close and reopen', () => { + const source = hot('---a---b---c---d---e---f---g---h---i---| '); + const sourceSubs = '^ ! '; + const closings = hot('-------------w------------w----------------|'); + const closingSubs = '^ ! '; + const expected = 'x------------y------------z------------| '; + const x = cold( '---a---b---c-| '); + const y = cold( '--d---e---f--| '); + const z = cold( '-g---h---i---| '); + const expectedValues = { x: x, y: y, z: z }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should return a single empty window if source is empty and closings are basic', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const closings = cold('--x--x--|'); + const closingSubs = '(^!)'; + const expected = '(w|)'; + const w = cold('|'); + const expectedValues = { w: w }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should return a single empty window if source is empty and closing is empty', () => { + const source = cold('|'); + const sourceSubs = '(^!)'; + const closings = cold('|'); + const closingSubs = '(^!)'; + const expected = '(w|)'; + const w = cold('|'); + const expectedValues = { w: w }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should split a Just source into a single window identical to source, using a Never closing', + () => { + const source = cold('(a|)'); + const sourceSubs = '(^!)'; + const closings = cold('-'); + const closingSubs = '(^!)'; + const expected = '(w|)'; + const w = cold('(a|)'); + const expectedValues = { w: w }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should return a single Never window if source is Never', () => { + const source = cold('------'); + const sourceSubs = '^ '; + const closings = cold('------'); + const closingSubs = '^ '; + const expected = 'w-----'; + const w = cold('------'); + const expectedValues = { w: w }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should be able to split a never Observable into timely empty windows', () => { + const source = hot('^--------'); + const sourceSubs = '^ !'; + const closings = cold('--x--x--|'); + const closingSubs = '^ !'; + const expected = 'a-b--c--|'; + const a = cold('--| '); + const b = cold( '---| '); + const c = cold( '---|'); + const expectedValues = { a: a, b: b, c: c }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should emit an error-only window if outer is a simple throw-Observable', () => { + const source = cold('#'); + const sourceSubs = '(^!)'; + const closings = cold('--x--x--|'); + const closingSubs = '(^!)'; + const expected = '(w#)'; + const w = cold('#'); + const expectedValues = { w: w }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should handle basic case with window closings', () => { + const source = hot('-1-2-^3-4-5-6-7-8-9-| '); + const subs = '^ ! '; + const closings = hot('---^---x---x---x---x---x---|'); + const closingSubs = '^ ! '; + const expected = 'a---b---c---d--| '; + const a = cold( '-3-4| '); + const b = cold( '-5-6| '); + const c = cold( '-7-8| '); + const d = cold( '-9-| '); + const expectedValues = { a: a, b: b, c: c, d: d }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should handle basic case with window closings, but outer throws', () => { + const source = hot('-1-2-^3-4-5-6-7-8-9-# '); + const subs = '^ ! '; + const closings = hot('---^---x---x---x---x---x---|'); + const closingSubs = '^ ! '; + const expected = 'a---b---c---d--# '; + const a = cold( '-3-4| '); + const b = cold( '-5-6| '); + const c = cold( '-7-8| '); + const d = cold( '-9-# '); + const expectedValues = { a: a, b: b, c: c, d: d }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should stop emitting windows when outer is unsubscribed early', () => { + const source = hot('-1-2-^3-4-5-6-7-8-9-| '); + const subs = '^ ! '; + const closings = hot('---^---x---x---x---x---x---|'); + const closingSubs = '^ ! '; + const expected = 'a---b---- '; + const a = cold( '-3-4| '); + const b = cold( '-5-6 '); + const unsub = ' ! '; + const expectedValues = { a: a, b: b }; + + const result = source.window(closings); + + expectObservable(result, unsub).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('-1-2-^3-4-5-6-7-8-9-| '); + const subs = '^ ! '; + const closings = hot('---^---x---x---x---x---x---|'); + const closingSubs = '^ ! '; + const expected = 'a---b---- '; + const a = cold( '-3-4| '); + const b = cold( '-5-6- '); + const unsub = ' ! '; + const expectedValues = { a: a, b: b }; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .window(closings) + .mergeMap((x: Rx.Observable) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should dispose window Subjects if the outer is unsubscribed early', () => { + const source = hot('--a--b--c--d--e--f--g--h--|'); + const sourceSubs = '^ ! '; + const expected = 'x--------- '; + const x = cold( '--a--b--c- '); + const unsub = ' ! '; + const late = time('---------------| '); + const values = { x: x }; + + let window; + const result = source.window(Observable.never()) + .do((w: any) => { window = w; }); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + rxTestScheduler.schedule(() => { + expect(() => { + window.subscribe(); + }).toThrow(new Rx.ObjectUnsubscribedError()); + }, late); + }); + + it('should make outer emit error when closing throws', () => { + const source = hot('-1-2-^3-4-5-6-7-8-9-#'); + const subs = '^ ! '; + const closings = hot('---^---# '); + const closingSubs = '^ ! '; + const expected = 'a---# '; + const a = cold( '-3-4# '); + const expectedValues = { a: a }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); + + it('should complete the resulting Observable when window closings completes', () => { + const source = hot('-1-2-^3-4-5-6-7-8-9-|'); + const subs = '^ ! '; + const closings = hot('---^---x---x---| '); + const closingSubs = '^ ! '; + const expected = 'a---b---c---| '; + const a = cold( '-3-4| '); + const b = cold( '-5-6| '); + const c = cold( '-7-8| '); + const expectedValues = { a: a, b: b, c: c }; + + const result = source.window(closings); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(closings.subscriptions).toBe(closingSubs); + }); +}); \ No newline at end of file diff --git a/spec/operators/windowCount-spec.js b/spec/operators/windowCount-spec.js deleted file mode 100644 index 6b47b05279..0000000000 --- a/spec/operators/windowCount-spec.js +++ /dev/null @@ -1,171 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.windowCount', function () { - it.asDiagram('windowCount(3)')('should emit windows with count 3, no skip specified', function () { - var source = hot('---a---b---c---d---e---f---g---h---i---|'); - var sourceSubs = '^ !'; - var expected = 'x----------y-----------z-----------w---|'; - var x = cold( '---a---b---(c|) '); - var y = cold( '----d---e---(f|) '); - var z = cold( '----g---h---(i|) '); - var w = cold( '----|'); - var expectedValues = { x: x, y: y, z: z, w: w }; - - var result = source.windowCount(3); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - }); - - it('should emit windows with count 2 and skip 1', function () { - var source = hot('^-a--b--c--d--|'); - var subs = '^ !'; - var expected = 'u-v--x--y--z--|'; - var u = cold( '--a--(b|) '); - var v = cold( '---b--(c|) '); - var x = cold( '---c--(d|)'); - var y = cold( '---d--|'); - var z = cold( '---|'); - var values = { u: u, v: v, x: x, y: y, z: z }; - - var result = source.windowCount(2, 1); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should emit windows with count 2, and skip unspecified', function () { - var source = hot('--a--b--c--d--e--f--|'); - var subs = '^ !'; - var expected = 'x----y-----z-----w--|'; - var x = cold( '--a--(b|) '); - var y = cold( '---c--(d|) '); - var z = cold( '---e--(f|)'); - var w = cold( '---|'); - var values = { x: x, y: y, z: z, w: w }; - - var result = source.windowCount(2); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return empty if source is empty', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '(w|)'; - var w = cold('|'); - var values = { w: w }; - - var result = source.windowCount(2, 1); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return Never if source if Never', function () { - var source = cold('-'); - var subs = '^'; - var expected = 'w'; - var w = cold('-'); - var expectedValues = { w: w }; - - var result = source.windowCount(2, 1); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should propagate error from a just-throw source', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '(w#)'; - var w = cold('#'); - var expectedValues = { w: w }; - - var result = source.windowCount(2, 1); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should raise error if source raises error', function () { - var source = hot('--a--b--c--d--e--f--#'); - var subs = '^ !'; - var expected = 'u-v--w--x--y--z--q--#'; - var u = cold( '--a--b--(c|) '); - var v = cold( '---b--c--(d|) '); - var w = cold( '---c--d--(e|) '); - var x = cold( '---d--e--(f|)'); - var y = cold( '---e--f--#'); - var z = cold( '---f--#'); - var q = cold( '---#'); - var values = { u: u, v: v, w: w, x: x, y: y, z: z, q: q }; - - var result = source.windowCount(3, 1); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should dispose of inner windows once outer is unsubscribed early', function () { - var source = hot('^-a--b--c--d--|'); - var subs = '^ ! '; - var expected = 'w-x--y--z- '; - var w = cold( '--a--(b|) '); - var x = cold( '---b--(c|) '); - var y = cold( '---c- '); - var z = cold( '-- '); - var unsub = ' ! '; - var values = { w: w, x: x, y: y, z: z }; - - var result = source.windowCount(2, 1); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should dispose window Subjects if the outer is unsubscribed early', function () { - var source = hot('--a--b--c--d--e--f--g--h--|'); - var sourceSubs = '^ ! '; - var expected = 'x--------- '; - var x = cold( '--a--b--c- '); - var unsub = ' ! '; - var late = time('---------------| '); - var values = { x: x }; - - var window; - var result = source.windowCount(10, 10) - .do(function (w) { window = w; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - rxTestScheduler.schedule(function () { - expect(function () { - window.subscribe(); - }).toThrow(new Rx.ObjectUnsubscribedError()); - }, late); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('^-a--b--c--d--|'); - var subs = '^ ! '; - var expected = 'w-x--y--z- '; - var w = cold( '--a--(b|) '); - var x = cold( '---b--(c|) '); - var y = cold( '---c- '); - var z = cold( '-- '); - var unsub = ' ! '; - var values = { w: w, x: x, y: y, z: z }; - - var result = source - .mergeMap(function (i) { return Observable.of(i); }) - .windowCount(2, 1) - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/windowCount-spec.ts b/spec/operators/windowCount-spec.ts new file mode 100644 index 0000000000..65e64989da --- /dev/null +++ b/spec/operators/windowCount-spec.ts @@ -0,0 +1,174 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.windowCount', () => { + asDiagram('windowCount(3)')('should emit windows with count 3, no skip specified', () => { + const source = hot('---a---b---c---d---e---f---g---h---i---|'); + const sourceSubs = '^ !'; + const expected = 'x----------y-----------z-----------w---|'; + const x = cold( '---a---b---(c|) '); + const y = cold( '----d---e---(f|) '); + const z = cold( '----g---h---(i|) '); + const w = cold( '----|'); + const expectedValues = { x: x, y: y, z: z, w: w }; + + const result = source.windowCount(3); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + }); + + it('should emit windows with count 2 and skip 1', () => { + const source = hot('^-a--b--c--d--|'); + const subs = '^ !'; + const expected = 'u-v--x--y--z--|'; + const u = cold( '--a--(b|) '); + const v = cold( '---b--(c|) '); + const x = cold( '---c--(d|)'); + const y = cold( '---d--|'); + const z = cold( '---|'); + const values = { u: u, v: v, x: x, y: y, z: z }; + + const result = source.windowCount(2, 1); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should emit windows with count 2, and skip unspecified', () => { + const source = hot('--a--b--c--d--e--f--|'); + const subs = '^ !'; + const expected = 'x----y-----z-----w--|'; + const x = cold( '--a--(b|) '); + const y = cold( '---c--(d|) '); + const z = cold( '---e--(f|)'); + const w = cold( '---|'); + const values = { x: x, y: y, z: z, w: w }; + + const result = source.windowCount(2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return empty if source is empty', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '(w|)'; + const w = cold('|'); + const values = { w: w }; + + const result = source.windowCount(2, 1); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return Never if source if Never', () => { + const source = cold('-'); + const subs = '^'; + const expected = 'w'; + const w = cold('-'); + const expectedValues = { w: w }; + + const result = source.windowCount(2, 1); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should propagate error from a just-throw source', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '(w#)'; + const w = cold('#'); + const expectedValues = { w: w }; + + const result = source.windowCount(2, 1); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should raise error if source raises error', () => { + const source = hot('--a--b--c--d--e--f--#'); + const subs = '^ !'; + const expected = 'u-v--w--x--y--z--q--#'; + const u = cold( '--a--b--(c|) '); + const v = cold( '---b--c--(d|) '); + const w = cold( '---c--d--(e|) '); + const x = cold( '---d--e--(f|)'); + const y = cold( '---e--f--#'); + const z = cold( '---f--#'); + const q = cold( '---#'); + const values = { u: u, v: v, w: w, x: x, y: y, z: z, q: q }; + + const result = source.windowCount(3, 1); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should dispose of inner windows once outer is unsubscribed early', () => { + const source = hot('^-a--b--c--d--|'); + const subs = '^ ! '; + const expected = 'w-x--y--z- '; + const w = cold( '--a--(b|) '); + const x = cold( '---b--(c|) '); + const y = cold( '---c- '); + const z = cold( '-- '); + const unsub = ' ! '; + const values = { w: w, x: x, y: y, z: z }; + + const result = source.windowCount(2, 1); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should dispose window Subjects if the outer is unsubscribed early', () => { + const source = hot('--a--b--c--d--e--f--g--h--|'); + const sourceSubs = '^ ! '; + const expected = 'x--------- '; + const x = cold( '--a--b--c- '); + const unsub = ' ! '; + const late = time('---------------| '); + const values = { x: x }; + + let window; + const result = source.windowCount(10, 10) + .do((w: any) => { window = w; }); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + rxTestScheduler.schedule(() => { + expect(() => { + window.subscribe(); + }).toThrow(new Rx.ObjectUnsubscribedError()); + }, late); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('^-a--b--c--d--|'); + const subs = '^ ! '; + const expected = 'w-x--y--z- '; + const w = cold( '--a--(b|) '); + const x = cold( '---b--(c|) '); + const y = cold( '---c- '); + const z = cold( '-- '); + const unsub = ' ! '; + const values = { w: w, x: x, y: y, z: z }; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .windowCount(2, 1) + .mergeMap((x: Rx.Observable) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/windowTime-spec.js b/spec/operators/windowTime-spec.js deleted file mode 100644 index 6ea4f6ba65..0000000000 --- a/spec/operators/windowTime-spec.js +++ /dev/null @@ -1,215 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler, time*/ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.windowTime', function () { - it.asDiagram('windowTime(50, 100)')('should emit windows given windowTimeSpan ' + - 'and windowCreationInterval', function () { - var source = hot('--1--2--^-a--b--c--d--e---f--g--h-|'); - var subs = '^ !'; - // 100 frames 0---------1---------2-----| - // 50 ----| - // 50 ----| - // 50 ----| - var expected = 'x---------y---------z-----|'; - var x = cold( '--a--(b|) '); - var y = cold( '-d--e| '); - var z = cold( '-g--h| '); - var values = { x: x, y: y, z: z }; - - var result = source.windowTime(50, 100, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should emit windows given windowTimeSpan', function () { - var source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); - var subs = '^ !'; - var timeSpan = time( '----------|'); - // 100 frames 0---------1---------2------| - var expected = 'x---------y---------z------|'; - var x = cold( '---a--b--c| '); - var y = cold( '--d--e--f-| '); - var z = cold( '-g--h--|'); - var values = { x: x, y: y, z: z }; - - var result = source.windowTime(timeSpan, null, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should emit windows given windowTimeSpan and windowCreationInterval', function () { - var source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); - var subs = '^ !'; - var timeSpan = time( '-----|'); - var interval = time( '----------|'); - // 100 frames 0---------1---------2------| - // 50 ----| - // 50 ----| - // 50 ----| - var expected = 'x---------y---------z------|'; - var x = cold( '---a-| '); - var y = cold( '--d--(e|) '); - var z = cold( '-g--h| '); - var values = { x: x, y: y, z: z }; - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should return a single empty window if source is empty', function () { - var source = cold('|'); - var subs = '(^!)'; - var expected = '(w|)'; - var w = cold('|'); - var expectedValues = { w: w }; - var timeSpan = time('-----|'); - var interval = time('----------|'); - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should split a Just source into a single window identical to source', function () { - var source = cold('(a|)'); - var subs = '(^!)'; - var expected = '(w|)'; - var w = cold('(a|)'); - var expectedValues = { w: w }; - var timeSpan = time('-----|'); - var interval = time('----------|'); - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should be able to split a never Observable into timely empty windows', function () { - var source = hot('^----------'); - var subs = '^ !'; - var expected = 'a--b--c--d-'; - var timeSpan = time('---|'); - var interval = time( '---|'); - var a = cold('---| '); - var b = cold( '---| '); - var c = cold( '---| '); - var d = cold( '--'); - var unsub = ' !'; - var expectedValues = { a: a, b: b, c: c, d: d }; - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should emit an error-only window if outer is a simple throw-Observable', function () { - var source = cold('#'); - var subs = '(^!)'; - var expected = '(w#)'; - var w = cold('#'); - var expectedValues = { w: w }; - var timeSpan = time('-----|'); - var interval = time('----------|'); - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, expectedValues); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should handle source Observable which eventually emits an error', function () { - var source = hot('--1--2--^--a--b--c--d--e--f--g--h--#'); - var subs = '^ !'; - var timeSpan = time( '-----|'); - var interval = time( '----------|'); - // 100 frames 0---------1---------2------| - // 50 ----| - // 50 ----| - // 50 ----| - var expected = 'x---------y---------z------#'; - var x = cold( '---a-| '); - var y = cold( '--d--(e|) '); - var z = cold( '-g--h| '); - var values = { x: x, y: y, z: z }; - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should emit windows given windowTimeSpan and windowCreationInterval, ' + - 'but outer is unsubscribed early', function () { - var source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); - var subs = '^ ! '; - var timeSpan = time( '-----|'); - var interval = time( '----------|'); - // 100 frames 0---------1---------2------| - // 50 ----| - // 50 ----| - // 50 ----| - var expected = 'x---------y- '; - var x = cold( '---a-| '); - var y = cold( '-- '); - var unsub = ' ! '; - var values = { x: x, y: y }; - - var result = source.windowTime(timeSpan, interval, rxTestScheduler); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - }); - - it('should dispose window Subjects if the outer is unsubscribed early', function () { - var source = hot('--a--b--c--d--e--f--g--h--|'); - var sourceSubs = '^ ! '; - var expected = 'x--------- '; - var x = cold( '--a--b--c- '); - var unsub = ' ! '; - var values = { x: x }; - - var window; - var result = source.windowTime(1000, 1000, rxTestScheduler) - .do(function (w) { window = w; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - rxTestScheduler.schedule(function () { - expect(function () { - window.subscribe(); - }).toThrow(new Rx.ObjectUnsubscribedError()); - }, 150); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); - var sourcesubs = '^ ! '; - var timeSpan = time( '-----|'); - var interval = time( '----------|'); - // 100 frames 0---------1---------2------| - // 50 ----| - // 50 ----| - // 50 ----| - var expected = 'x---------y---- '; - var x = cold( '---a-| '); - var y = cold( '--d-- '); - var unsub = ' ! '; - var values = { x: x, y: y }; - - var result = source - .mergeMap(function (i) { return Observable.of(i); }) - .windowTime(timeSpan, interval, rxTestScheduler) - .mergeMap(function (i) { return Observable.of(i); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(sourcesubs); - }); -}); \ No newline at end of file diff --git a/spec/operators/windowTime-spec.ts b/spec/operators/windowTime-spec.ts new file mode 100644 index 0000000000..58078e0960 --- /dev/null +++ b/spec/operators/windowTime-spec.ts @@ -0,0 +1,218 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.windowTime', () => { + asDiagram('windowTime(50, 100)')('should emit windows given windowTimeSpan ' + + 'and windowCreationInterval', () => { + const source = hot('--1--2--^-a--b--c--d--e---f--g--h-|'); + const subs = '^ !'; + // 100 frames 0---------1---------2-----| + // 50 ----| + // 50 ----| + // 50 ----| + const expected = 'x---------y---------z-----|'; + const x = cold( '--a--(b|) '); + const y = cold( '-d--e| '); + const z = cold( '-g--h| '); + const values = { x: x, y: y, z: z }; + + const result = source.windowTime(50, 100, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should emit windows given windowTimeSpan', () => { + const source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); + const subs = '^ !'; + const timeSpan = time( '----------|'); + // 100 frames 0---------1---------2------| + const expected = 'x---------y---------z------|'; + const x = cold( '---a--b--c| '); + const y = cold( '--d--e--f-| '); + const z = cold( '-g--h--|'); + const values = { x: x, y: y, z: z }; + + const result = source.windowTime(timeSpan, null, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should emit windows given windowTimeSpan and windowCreationInterval', () => { + const source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); + const subs = '^ !'; + const timeSpan = time( '-----|'); + const interval = time( '----------|'); + // 100 frames 0---------1---------2------| + // 50 ----| + // 50 ----| + // 50 ----| + const expected = 'x---------y---------z------|'; + const x = cold( '---a-| '); + const y = cold( '--d--(e|) '); + const z = cold( '-g--h| '); + const values = { x: x, y: y, z: z }; + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should return a single empty window if source is empty', () => { + const source = cold('|'); + const subs = '(^!)'; + const expected = '(w|)'; + const w = cold('|'); + const expectedValues = { w: w }; + const timeSpan = time('-----|'); + const interval = time('----------|'); + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should split a Just source into a single window identical to source', () => { + const source = cold('(a|)'); + const subs = '(^!)'; + const expected = '(w|)'; + const w = cold('(a|)'); + const expectedValues = { w: w }; + const timeSpan = time('-----|'); + const interval = time('----------|'); + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should be able to split a never Observable into timely empty windows', () => { + const source = hot('^----------'); + const subs = '^ !'; + const expected = 'a--b--c--d-'; + const timeSpan = time('---|'); + const interval = time( '---|'); + const a = cold('---| '); + const b = cold( '---| '); + const c = cold( '---| '); + const d = cold( '--'); + const unsub = ' !'; + const expectedValues = { a: a, b: b, c: c, d: d }; + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should emit an error-only window if outer is a simple throw-Observable', () => { + const source = cold('#'); + const subs = '(^!)'; + const expected = '(w#)'; + const w = cold('#'); + const expectedValues = { w: w }; + const timeSpan = time('-----|'); + const interval = time('----------|'); + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, expectedValues); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should handle source Observable which eventually emits an error', () => { + const source = hot('--1--2--^--a--b--c--d--e--f--g--h--#'); + const subs = '^ !'; + const timeSpan = time( '-----|'); + const interval = time( '----------|'); + // 100 frames 0---------1---------2------| + // 50 ----| + // 50 ----| + // 50 ----| + const expected = 'x---------y---------z------#'; + const x = cold( '---a-| '); + const y = cold( '--d--(e|) '); + const z = cold( '-g--h| '); + const values = { x: x, y: y, z: z }; + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should emit windows given windowTimeSpan and windowCreationInterval, ' + + 'but outer is unsubscribed early', () => { + const source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); + const subs = '^ ! '; + const timeSpan = time( '-----|'); + const interval = time( '----------|'); + // 100 frames 0---------1---------2------| + // 50 ----| + // 50 ----| + // 50 ----| + const expected = 'x---------y- '; + const x = cold( '---a-| '); + const y = cold( '-- '); + const unsub = ' ! '; + const values = { x: x, y: y }; + + const result = source.windowTime(timeSpan, interval, rxTestScheduler); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + }); + + it('should dispose window Subjects if the outer is unsubscribed early', () => { + const source = hot('--a--b--c--d--e--f--g--h--|'); + const sourceSubs = '^ ! '; + const expected = 'x--------- '; + const x = cold( '--a--b--c- '); + const unsub = ' ! '; + const values = { x: x }; + + let window; + const result = source.windowTime(1000, 1000, rxTestScheduler) + .do((w: any) => { window = w; }); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + rxTestScheduler.schedule(() => { + expect(() => { + window.subscribe(); + }).toThrow(new Rx.ObjectUnsubscribedError()); + }, 150); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const source = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); + const sourcesubs = '^ ! '; + const timeSpan = time( '-----|'); + const interval = time( '----------|'); + // 100 frames 0---------1---------2------| + // 50 ----| + // 50 ----| + // 50 ----| + const expected = 'x---------y---- '; + const x = cold( '---a-| '); + const y = cold( '--d-- '); + const unsub = ' ! '; + const values = { x: x, y: y }; + + const result = source + .mergeMap((x: string) => Observable.of(x)) + .windowTime(timeSpan, interval, rxTestScheduler) + .mergeMap((x: Rx.Observable) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(sourcesubs); + }); +}); \ No newline at end of file diff --git a/spec/operators/windowToggle-spec.js b/spec/operators/windowToggle-spec.js deleted file mode 100644 index 590b826f82..0000000000 --- a/spec/operators/windowToggle-spec.js +++ /dev/null @@ -1,407 +0,0 @@ -/* globals describe, it, expect, hot, cold, expectObservable, expectSubscriptions, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.windowToggle', function () { - it.asDiagram('windowToggle')('should emit windows governed by openings and closings', function () { - var source = hot('--1--2--^-a--b--c--d--e--f--g--h-|'); - var subs = '^ !'; - var e2 = cold( '----w--------w--------w--|'); - var e2subs = '^ !'; - var e3 = cold( '-----| '); - // -----(c|) - // -----(c|) - var e3subs = [ ' ^ ! ', // eslint-disable-line array-bracket-spacing - ' ^ ! ', - ' ^ !']; - var expected = '----x--------y--------z--|'; - var x = cold( '-b--c| '); - var y = cold( '-e--f| '); - var z = cold( '-h-|'); - var values = { x: x, y: y, z: z }; - - var result = source.windowToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should emit windows that are opened by an observable from the first argument ' + - 'and closed by an observable returned by the function in the second argument', - function () { - var e1 = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); - var e1subs = '^ !'; - var e2 = cold( '--------x-------x-------x--|'); - var e2subs = '^ !'; - var e3 = cold( '----------(x|) '); - // ----------(x|) - // ----------(x|) - var e3subs = [ ' ^ ! ', // eslint-disable-line array-bracket-spacing - ' ^ ! ', - ' ^ !']; - var expected = '--------x-------y-------z--|'; - var x = cold( '-c--d--e--(f|) '); - var y = cold( '--f--g--h-| '); - var z = cold( '---|'); - var values = { x: x, y: y, z: z }; - - var source = e1.windowToggle(e2, function (value) { - expect(value).toBe('x'); - return e3; - }); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should emit windows using varying cold closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [ - cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var closeSubs = [ ' ^ ! ', // eslint-disable-line array-bracket-spacing - ' ^ ! ', - ' ^ ! ']; - var expected = '--x-----------y--------z-----------| '; - var x = cold( '--b---c---d---e| '); - var y = cold( '--e-| '); - var z = cold( '-g---h------| '); - var values = { x: x, y: y, z: z }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return close[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(close[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(close[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(close[2].subscriptions).toBe(closeSubs[2]); - }); - - it('should emit windows using varying hot closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var closings = [ - {obs: hot( '-1--^----------------s-| '), // eslint-disable-line key-spacing - sub: ' ^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '-----3----4-------(s|) '), // eslint-disable-line key-spacing - sub: ' ^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '-------3----4-------5----------------s|'), // eslint-disable-line key-spacing - sub: ' ^ ! '}]; // eslint-disable-line key-spacing - var expected = '--x-----------y--------z-----------| '; - var x = cold( '--b---c---d---e| '); - var y = cold( '--e-| '); - var z = cold( '-g---h------| '); - var values = { x: x, y: y, z: z }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return closings[i++].obs; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(closings[0].obs.subscriptions).toBe(closings[0].sub); - expectSubscriptions(closings[1].obs.subscriptions).toBe(closings[1].sub); - expectSubscriptions(closings[2].obs.subscriptions).toBe(closings[2].sub); - }); - - it('should emit windows using varying empty delayed closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '---------------| '), - cold( '----| '), - cold( '---------------|')]; - var expected = '--x-----------y--------z-----------| '; - var x = cold( '--b---c---d---e| '); - var y = cold( '--e-| '); - var z = cold( '-g---h------| '); - var values = { x: x, y: y, z: z }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return close[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit windows using varying cold closings, outer unsubscribed early', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '-------------s---| '), - cold( '-----(s|) '), - cold( '---------------(s|)')]; - var closeSubs = [' ^ ! ', - ' ^ ! ']; - var expected = '--x-----------y--- '; - var x = cold( '--b---c---d--| '); - var y = cold( '--e- '); - var unsub = ' ! '; - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return close[i++]; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(close[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(close[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(close[2].subscriptions).toBe([]); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var closeSubs = [' ^ ! ', - ' ^! ']; - var expected = '--x-----------y- '; - var x = cold( '--b---c---d--- '); - var y = cold( '-- '); - var unsub = ' ! '; - var values = { x: x, y: y }; - - var i = 0; - var result = e1 - .mergeMap(function (val) { return Observable.of(val); }) - .windowToggle(e2, function () { return close[i++]; }) - .mergeMap(function (val) { return Observable.of(val); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(close[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(close[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should dispose window Subjects if the outer is unsubscribed early', function () { - var source = hot('--a--b--c--d--e--f--g--h--|'); - var open = cold('o-------------------------|'); - var sourceSubs = '^ ! '; - var expected = 'x--------- '; - var x = cold( '--a--b--c- '); - var unsub = ' ! '; - var late = time('---------------| '); - var values = { x: x }; - - var window; - var result = source - .windowToggle(open, function () { return Observable.never(); }) - .do(function (w) { window = w; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - rxTestScheduler.schedule(function () { - expect(function () { - window.subscribe(); - }).toThrow(new Rx.ObjectUnsubscribedError()); - }, late); - }); - - it('should propagate error thrown from closingSelector', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '---------------s--| '), - cold( '----(s|) '), - cold( '---------------(s|)')]; - var expected = '--x-----------#---- '; - var x = cold( '--b---c---d-# '); - var values = { x: x }; - - var i = 0; - var result = e1.windowToggle(e2, function () { - if (i === 1) { - throw 'error'; - } - return close[i++]; - }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should propagate error emitted from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '---------------s--| '), - cold( '# ')]; - var expected = '--x-----------(y#) '; - var x = cold( '--b---c---d-# '); - var y = cold( '# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return close[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should propagate error emitted late from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '---------------s--| '), - cold( '-----# ')]; - var expected = '--x-----------y----# '; - var x = cold( '--b---c---d---e| '); - var y = cold( '--e--# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return close[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle errors', function () { - var e1 = hot('--a--^---b---c---d---e--# '); - var e1subs = '^ ! '; - var e2 = cold('--x-----------y--------z---| '); - var e2subs = '^ ! '; - var close = [cold( '---------------s--| '), - cold( '-------s| ')]; - var expected = '--x-----------y----# '; - var x = cold( '--b---c---d---e| '); - var y = cold( '--e--# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowToggle(e2, function () { return close[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle empty source', function () { - var e1 = cold('|'); - var e1subs = '(^!)'; - var e2 = cold('--o-----|'); - var e2subs = '(^!)'; - var e3 = cold( '-----c--|'); - var expected = '|'; - - var result = e1.windowToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var e2 = cold('--o-----|'); - var e2subs = '(^!)'; - var e3 = cold('-----c--|'); - var expected = '#'; - - var result = e1.windowToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle never', function () { - var e1 = hot('-'); - var e1subs = '^ !'; - var e2 = cold('--o-----o------o-----o---o-----| '); - var e2subs = '^ ! '; - var e3 = cold( '--c-| '); - var expected = '--u-----v------x-----y---z-------------------'; - var u = cold( '--| '); - var v = cold( '--| '); - var x = cold( '--| '); - var y = cold( '--| '); - var z = cold( '--| '); - var unsub = ' !'; - var values = { u: u, v: v, x: x, y: y, z: z }; - - var result = e1.windowToggle(e2, function () { return e3; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a never opening Observable', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '^ !'; - var e2 = cold( '-'); - var e2subs = '^ !'; - var e3 = cold( '--c-| '); - var expected = '-----------------------------------|'; - - var result = e1.windowToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a never closing Observable', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '^ !'; - var e2 = cold( '---o---------------o-----------| '); - var e2subs = '^ ! '; - var e3 = cold('-'); - var expected = '---x---------------y---------------|'; - var x = cold( '-b---c---d---e---f---g---h------|'); - var y = cold( '-f---g---h------|'); - var values = { x: x, y: y }; - - var result = e1.windowToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle opening Observable that just throws', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '(^!)'; - var e2 = cold( '#'); - var e2subs = '(^!)'; - var e3 = cold( '--c-|'); - var subs = '(^!)'; - var expected = '#'; - - var result = e1.windowToggle(e2, function () { return e3; }); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/windowToggle-spec.ts b/spec/operators/windowToggle-spec.ts new file mode 100644 index 0000000000..2078a16a2e --- /dev/null +++ b/spec/operators/windowToggle-spec.ts @@ -0,0 +1,410 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.windowToggle', () => { + asDiagram('windowToggle')('should emit windows governed by openings and closings', () => { + const source = hot('--1--2--^-a--b--c--d--e--f--g--h-|'); + const subs = '^ !'; + const e2 = cold( '----w--------w--------w--|'); + const e2subs = '^ !'; + const e3 = cold( '-----| '); + // -----(c|) + // -----(c|) + const e3subs = [ ' ^ ! ', // eslint-disable-line array-bracket-spacing + ' ^ ! ', + ' ^ !']; + const expected = '----x--------y--------z--|'; + const x = cold( '-b--c| '); + const y = cold( '-e--f| '); + const z = cold( '-h-|'); + const values = { x: x, y: y, z: z }; + + const result = source.windowToggle(e2, () => e3); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should emit windows that are opened by an observable from the first argument ' + + 'and closed by an observable returned by the function in the second argument', + () => { + const e1 = hot('--1--2--^--a--b--c--d--e--f--g--h--|'); + const e1subs = '^ !'; + const e2 = cold( '--------x-------x-------x--|'); + const e2subs = '^ !'; + const e3 = cold( '----------(x|) '); + // ----------(x|) + // ----------(x|) + const e3subs = [ ' ^ ! ', // eslint-disable-line array-bracket-spacing + ' ^ ! ', + ' ^ !']; + const expected = '--------x-------y-------z--|'; + const x = cold( '-c--d--e--(f|) '); + const y = cold( '--f--g--h-| '); + const z = cold( '---|'); + const values = { x: x, y: y, z: z }; + + const source = e1.windowToggle(e2, (value: string) => { + expect(value).toBe('x'); + return e3; + }); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should emit windows using constying cold closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [ + cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const closeSubs = [ ' ^ ! ', // eslint-disable-line array-bracket-spacing + ' ^ ! ', + ' ^ ! ']; + const expected = '--x-----------y--------z-----------| '; + const x = cold( '--b---c---d---e| '); + const y = cold( '--e-| '); + const z = cold( '-g---h------| '); + const values = { x: x, y: y, z: z }; + + let i = 0; + const result = e1.windowToggle(e2, () => close[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(close[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(close[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(close[2].subscriptions).toBe(closeSubs[2]); + }); + + it('should emit windows using constying hot closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const closings = [ + {obs: hot( '-1--^----------------s-| '), // eslint-disable-line key-spacing + sub: ' ^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '-----3----4-------(s|) '), // eslint-disable-line key-spacing + sub: ' ^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '-------3----4-------5----------------s|'), // eslint-disable-line key-spacing + sub: ' ^ ! '}]; // eslint-disable-line key-spacing + const expected = '--x-----------y--------z-----------| '; + const x = cold( '--b---c---d---e| '); + const y = cold( '--e-| '); + const z = cold( '-g---h------| '); + const values = { x: x, y: y, z: z }; + + let i = 0; + const result = e1.windowToggle(e2, () => closings[i++].obs); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(closings[0].obs.subscriptions).toBe(closings[0].sub); + expectSubscriptions(closings[1].obs.subscriptions).toBe(closings[1].sub); + expectSubscriptions(closings[2].obs.subscriptions).toBe(closings[2].sub); + }); + + it('should emit windows using constying empty delayed closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '---------------| '), + cold( '----| '), + cold( '---------------|')]; + const expected = '--x-----------y--------z-----------| '; + const x = cold( '--b---c---d---e| '); + const y = cold( '--e-| '); + const z = cold( '-g---h------| '); + const values = { x: x, y: y, z: z }; + + let i = 0; + const result = e1.windowToggle(e2, () => close[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit windows using constying cold closings, outer unsubscribed early', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '-------------s---| '), + cold( '-----(s|) '), + cold( '---------------(s|)')]; + const closeSubs = [' ^ ! ', + ' ^ ! ']; + const expected = '--x-----------y--- '; + const x = cold( '--b---c---d--| '); + const y = cold( '--e- '); + const unsub = ' ! '; + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowToggle(e2, () => close[i++]); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(close[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(close[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(close[2].subscriptions).toBe([]); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const closeSubs = [' ^ ! ', + ' ^! ']; + const expected = '--x-----------y- '; + const x = cold( '--b---c---d--- '); + const y = cold( '-- '); + const unsub = ' ! '; + const values = { x: x, y: y }; + + let i = 0; + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .windowToggle(e2, () => close[i++]) + .mergeMap((x: Rx.Observable) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(close[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(close[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should dispose window Subjects if the outer is unsubscribed early', () => { + const source = hot('--a--b--c--d--e--f--g--h--|'); + const open = cold('o-------------------------|'); + const sourceSubs = '^ ! '; + const expected = 'x--------- '; + const x = cold( '--a--b--c- '); + const unsub = ' ! '; + const late = time('---------------| '); + const values = { x: x }; + + let window; + const result = source + .windowToggle(open, () => Observable.never()) + .do((w: any) => { window = w; }); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + rxTestScheduler.schedule(() => { + expect(() => { + window.subscribe(); + }).toThrow(new Rx.ObjectUnsubscribedError()); + }, late); + }); + + it('should propagate error thrown from closingSelector', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '---------------s--| '), + cold( '----(s|) '), + cold( '---------------(s|)')]; + const expected = '--x-----------#---- '; + const x = cold( '--b---c---d-# '); + const values = { x: x }; + + let i = 0; + const result = e1.windowToggle(e2, () => { + if (i === 1) { + throw 'error'; + } + return close[i++]; + }); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should propagate error emitted from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '---------------s--| '), + cold( '# ')]; + const expected = '--x-----------(y#) '; + const x = cold( '--b---c---d-# '); + const y = cold( '# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowToggle(e2, () => close[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should propagate error emitted late from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '---------------s--| '), + cold( '-----# ')]; + const expected = '--x-----------y----# '; + const x = cold( '--b---c---d---e| '); + const y = cold( '--e--# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowToggle(e2, () => close[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle errors', () => { + const e1 = hot('--a--^---b---c---d---e--# '); + const e1subs = '^ ! '; + const e2 = cold('--x-----------y--------z---| '); + const e2subs = '^ ! '; + const close = [cold( '---------------s--| '), + cold( '-------s| ')]; + const expected = '--x-----------y----# '; + const x = cold( '--b---c---d---e| '); + const y = cold( '--e--# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowToggle(e2, () => close[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle empty source', () => { + const e1 = cold('|'); + const e1subs = '(^!)'; + const e2 = cold('--o-----|'); + const e2subs = '(^!)'; + const e3 = cold( '-----c--|'); + const expected = '|'; + + const result = e1.windowToggle(e2, () => e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const e2 = cold('--o-----|'); + const e2subs = '(^!)'; + const e3 = cold('-----c--|'); + const expected = '#'; + + const result = e1.windowToggle(e2, () => e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle never', () => { + const e1 = hot('-'); + const e1subs = '^ !'; + const e2 = cold('--o-----o------o-----o---o-----| '); + const e2subs = '^ ! '; + const e3 = cold( '--c-| '); + const expected = '--u-----v------x-----y---z-------------------'; + const u = cold( '--| '); + const v = cold( '--| '); + const x = cold( '--| '); + const y = cold( '--| '); + const z = cold( '--| '); + const unsub = ' !'; + const values = { u: u, v: v, x: x, y: y, z: z }; + + const result = e1.windowToggle(e2, () => e3); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a never opening Observable', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '^ !'; + const e2 = cold( '-'); + const e2subs = '^ !'; + const e3 = cold( '--c-| '); + const expected = '-----------------------------------|'; + + const result = e1.windowToggle(e2, () => e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a never closing Observable', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '^ !'; + const e2 = cold( '---o---------------o-----------| '); + const e2subs = '^ ! '; + const e3 = cold('-'); + const expected = '---x---------------y---------------|'; + const x = cold( '-b---c---d---e---f---g---h------|'); + const y = cold( '-f---g---h------|'); + const values = { x: x, y: y }; + + const result = e1.windowToggle(e2, () => e3); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle opening Observable that just throws', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '(^!)'; + const e2 = cold( '#'); + const e2subs = '(^!)'; + const e3 = cold( '--c-|'); + const subs = '(^!)'; + const expected = '#'; + + const result = e1.windowToggle(e2, () => e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/windowWhen-spec.js b/spec/operators/windowWhen-spec.js deleted file mode 100644 index 75301098a1..0000000000 --- a/spec/operators/windowWhen-spec.js +++ /dev/null @@ -1,355 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var Observable = Rx.Observable; - -describe('Observable.prototype.windowWhen', function () { - it.asDiagram('windowWhen')('should emit windows that close and reopen', function () { - var e1 = hot('--a--^--b--c--d--e--f--g--h--i--|'); - var e1subs = '^ !'; - var e2 = cold( '-----------| '); - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ !']; - var a = cold( '---b--c--d-| '); - var b = cold( '-e--f--g--h| '); - var c = cold( '--i--|'); - var expected = 'a----------b----------c----|'; - var values = { a: a, b: b, c: c }; - - var source = e1.windowWhen(function () { return e2; }); - - expectObservable(source).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should emit windows using varying cold closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '-----(s|) '), - cold( '---------------(s|)')]; - var closeSubs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = 'x----------------y----z------------| '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f-| '); - var z = cold( '--g---h------| '); - var values = { x: x, y: y, z: z }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); - }); - - it('should emit windows using varying hot closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var subs = '^ ! '; - var closings = [ - {obs: hot( '-1--^----------------s-| '), // eslint-disable-line key-spacing - sub: '^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '-----3----4-----------(s|) '), // eslint-disable-line key-spacing - sub: ' ^ ! '}, // eslint-disable-line key-spacing - {obs: hot( '-------3----4-------5----------------s|'), // eslint-disable-line key-spacing - sub: ' ^ ! '}]; // eslint-disable-line key-spacing - var expected = 'x----------------y----z------------| '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f-| '); - var z = cold( '--g---h------| '); - var values = { x: x, y: y, z: z }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++].obs; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(subs); - expectSubscriptions(closings[0].obs.subscriptions).toBe(closings[0].sub); - expectSubscriptions(closings[1].obs.subscriptions).toBe(closings[1].sub); - expectSubscriptions(closings[2].obs.subscriptions).toBe(closings[2].sub); - }); - - it('should emit windows using varying empty delayed closings', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------| '), - cold( '-----| '), - cold( '---------------|')]; - var closeSubs = ['^ ! ', - ' ^ ! ', - ' ^ ! ']; - var expected = 'x----------------y----z------------| '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f-| '); - var z = cold( '--g---h------| '); - var values = { x: x, y: y, z: z }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); - }); - - it('should emit windows using varying cold closings, outer unsubscribed early', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '---------(s|) ')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = 'x----------------y---- '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f- '); - var unsub = ' ! '; - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++]; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '---------(s|) ')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = 'x----------------y---- '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f- '); - var unsub = ' ! '; - var values = { x: x, y: y }; - - var i = 0; - var result = e1 - .mergeMap(function (val) { return Observable.of(val); }) - .windowWhen(function () { return closings[i++]; }) - .mergeMap(function (val) { return Observable.of(val); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should dispose window Subjects if the outer is unsubscribed early', function () { - var source = hot('--a--b--c--d--e--f--g--h--|'); - var open = cold('o-------------------------|'); - var sourceSubs = '^ ! '; - var expected = 'x--------- '; - var x = cold( '--a--b--c- '); - var unsub = ' ! '; - var late = time('---------------| '); - var values = { x: x }; - - var window; - var result = source - .windowWhen(function () { return Observable.never(); }) - .do(function (w) { window = w; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(source.subscriptions).toBe(sourceSubs); - rxTestScheduler.schedule(function () { - expect(function () { - window.subscribe(); - }).toThrow(new Rx.ObjectUnsubscribedError()); - }, late); - }); - - it('should propagate error thrown from closingSelector', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '-----(s|) '), - cold( '---------------(s|)')]; - var closeSubs = ['^ ! ']; - var expected = 'x----------------(y#) '; - var x = cold( '----b---c---d---e| '); - var y = cold( '# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowWhen(function () { - if (i === 1) { - throw 'error'; - } - return closings[i++]; - }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - }); - - it('should propagate error emitted from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '# ')]; - var closeSubs = ['^ ! ', - ' (^!) ']; - var expected = 'x----------------(y#) '; - var x = cold( '----b---c---d---e| '); - var y = cold( '# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should propagate error emitted late from a closing', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------| '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '-----# ')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = 'x----------------y----# '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f-# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should propagate errors emitted from the source', function () { - var e1 = hot('--a--^---b---c---d---e---f-# '); - var e1subs = '^ ! '; - var closings = [ - cold( '-----------------s--| '), - cold( '-------(s|) ')]; - var closeSubs = ['^ ! ', - ' ^ ! ']; - var expected = 'x----------------y----# '; - var x = cold( '----b---c---d---e| '); - var y = cold( '---f-# '); - var values = { x: x, y: y }; - - var i = 0; - var result = e1.windowWhen(function () { return closings[i++]; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); - expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); - }); - - it('should handle empty source', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var e2 = cold( '-----c--|'); - var e2subs = '(^!)'; - var expected = '(w|)'; - var values = { w: cold('|') }; - - var result = e1.windowWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a never source', function () { - var e1 = cold( '-'); - var unsub = ' !'; - var e1subs = '^ !'; - var e2 = cold( '-----c--|'); - // -----c--| - // -----c--| - // -----c--| - var e2subs = ['^ ! ', - ' ^ ! ', - ' ^ ! ', - ' ^ !']; - var win = cold('-----|'); - var d = cold( '---'); - var expected = 'a----b----c----d--'; - var values = { a: win, b: win, c: win, d: d }; - - var result = e1.windowWhen(function () { return e2; }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var e2 = cold('-----c--|'); - var e2subs = '(^!)'; - var win = cold('#'); - var expected = '(w#)'; - var values = { w: win }; - - var result = e1.windowWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a never closing Observable', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '^ !'; - var e2 = cold( '-'); - var e2subs = '^ !'; - var expected = 'x----------------------------------|'; - var x = cold( '----b---c---d---e---f---g---h------|'); - var values = { x: x }; - - var result = e1.windowWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); - - it('should handle a throw closing Observable', function () { - var e1 = hot('--a--^---b---c---d---e---f---g---h------|'); - var e1subs = '(^!) '; - var e2 = cold( '#'); - var e2subs = '(^!) '; - var expected = '(x#) '; - var x = cold( '# '); - var values = { x: x }; - - var result = e1.windowWhen(function () { return e2; }); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - }); -}); \ No newline at end of file diff --git a/spec/operators/windowWhen-spec.ts b/spec/operators/windowWhen-spec.ts new file mode 100644 index 0000000000..cc75e937d4 --- /dev/null +++ b/spec/operators/windowWhen-spec.ts @@ -0,0 +1,358 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, asDiagram} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Observable = Rx.Observable; + +describe('Observable.prototype.windowWhen', () => { + asDiagram('windowWhen')('should emit windows that close and reopen', () => { + const e1 = hot('--a--^--b--c--d--e--f--g--h--i--|'); + const e1subs = '^ !'; + const e2 = cold( '-----------| '); + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ !']; + const a = cold( '---b--c--d-| '); + const b = cold( '-e--f--g--h| '); + const c = cold( '--i--|'); + const expected = 'a----------b----------c----|'; + const values = { a: a, b: b, c: c }; + + const source = e1.windowWhen(() => e2); + + expectObservable(source).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should emit windows using constying cold closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '-----(s|) '), + cold( '---------------(s|)')]; + const closeSubs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = 'x----------------y----z------------| '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f-| '); + const z = cold( '--g---h------| '); + const values = { x: x, y: y, z: z }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); + }); + + it('should emit windows using constying hot closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const subs = '^ ! '; + const closings = [ + {obs: hot( '-1--^----------------s-| '), // eslint-disable-line key-spacing + sub: '^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '-----3----4-----------(s|) '), // eslint-disable-line key-spacing + sub: ' ^ ! '}, // eslint-disable-line key-spacing + {obs: hot( '-------3----4-------5----------------s|'), // eslint-disable-line key-spacing + sub: ' ^ ! '}]; // eslint-disable-line key-spacing + const expected = 'x----------------y----z------------| '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f-| '); + const z = cold( '--g---h------| '); + const values = { x: x, y: y, z: z }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++].obs); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(subs); + expectSubscriptions(closings[0].obs.subscriptions).toBe(closings[0].sub); + expectSubscriptions(closings[1].obs.subscriptions).toBe(closings[1].sub); + expectSubscriptions(closings[2].obs.subscriptions).toBe(closings[2].sub); + }); + + it('should emit windows using constying empty delayed closings', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------| '), + cold( '-----| '), + cold( '---------------|')]; + const closeSubs = ['^ ! ', + ' ^ ! ', + ' ^ ! ']; + const expected = 'x----------------y----z------------| '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f-| '); + const z = cold( '--g---h------| '); + const values = { x: x, y: y, z: z }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + expectSubscriptions(closings[2].subscriptions).toBe(closeSubs[2]); + }); + + it('should emit windows using constying cold closings, outer unsubscribed early', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '---------(s|) ')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = 'x----------------y---- '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f- '); + const unsub = ' ! '; + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++]); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '---------(s|) ')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = 'x----------------y---- '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f- '); + const unsub = ' ! '; + const values = { x: x, y: y }; + + let i = 0; + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .windowWhen(() => closings[i++]) + .mergeMap((x: Rx.Observable) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should dispose window Subjects if the outer is unsubscribed early', () => { + const source = hot('--a--b--c--d--e--f--g--h--|'); + const open = cold('o-------------------------|'); + const sourceSubs = '^ ! '; + const expected = 'x--------- '; + const x = cold( '--a--b--c- '); + const unsub = ' ! '; + const late = time('---------------| '); + const values = { x: x }; + + let window; + const result = source + .windowWhen(() => Observable.never()) + .do((w: any) => { window = w; }); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(source.subscriptions).toBe(sourceSubs); + rxTestScheduler.schedule(() => { + expect(() => { + window.subscribe(); + }).toThrow(new Rx.ObjectUnsubscribedError()); + }, late); + }); + + it('should propagate error thrown from closingSelector', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '-----(s|) '), + cold( '---------------(s|)')]; + const closeSubs = ['^ ! ']; + const expected = 'x----------------(y#) '; + const x = cold( '----b---c---d---e| '); + const y = cold( '# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowWhen(() => { + if (i === 1) { + throw 'error'; + } + return closings[i++]; + }); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + }); + + it('should propagate error emitted from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '# ')]; + const closeSubs = ['^ ! ', + ' (^!) ']; + const expected = 'x----------------(y#) '; + const x = cold( '----b---c---d---e| '); + const y = cold( '# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should propagate error emitted late from a closing', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------| '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '-----# ')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = 'x----------------y----# '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f-# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should propagate errors emitted from the source', () => { + const e1 = hot('--a--^---b---c---d---e---f-# '); + const e1subs = '^ ! '; + const closings = [ + cold( '-----------------s--| '), + cold( '-------(s|) ')]; + const closeSubs = ['^ ! ', + ' ^ ! ']; + const expected = 'x----------------y----# '; + const x = cold( '----b---c---d---e| '); + const y = cold( '---f-# '); + const values = { x: x, y: y }; + + let i = 0; + const result = e1.windowWhen(() => closings[i++]); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(closings[0].subscriptions).toBe(closeSubs[0]); + expectSubscriptions(closings[1].subscriptions).toBe(closeSubs[1]); + }); + + it('should handle empty source', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const e2 = cold( '-----c--|'); + const e2subs = '(^!)'; + const expected = '(w|)'; + const values = { w: cold('|') }; + + const result = e1.windowWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a never source', () => { + const e1 = cold( '-'); + const unsub = ' !'; + const e1subs = '^ !'; + const e2 = cold( '-----c--|'); + // -----c--| + // -----c--| + // -----c--| + const e2subs = ['^ ! ', + ' ^ ! ', + ' ^ ! ', + ' ^ !']; + const win = cold('-----|'); + const d = cold( '---'); + const expected = 'a----b----c----d--'; + const values = { a: win, b: win, c: win, d: d }; + + const result = e1.windowWhen(() => e2); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const e2 = cold('-----c--|'); + const e2subs = '(^!)'; + const win = cold('#'); + const expected = '(w#)'; + const values = { w: win }; + + const result = e1.windowWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a never closing Observable', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '^ !'; + const e2 = cold( '-'); + const e2subs = '^ !'; + const expected = 'x----------------------------------|'; + const x = cold( '----b---c---d---e---f---g---h------|'); + const values = { x: x }; + + const result = e1.windowWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); + + it('should handle a throw closing Observable', () => { + const e1 = hot('--a--^---b---c---d---e---f---g---h------|'); + const e1subs = '(^!) '; + const e2 = cold( '#'); + const e2subs = '(^!) '; + const expected = '(x#) '; + const x = cold( '# '); + const values = { x: x }; + + const result = e1.windowWhen(() => e2); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + }); +}); \ No newline at end of file diff --git a/spec/operators/withLatestFrom-spec.js b/spec/operators/withLatestFrom-spec.js deleted file mode 100644 index 7e9f6c1a15..0000000000 --- a/spec/operators/withLatestFrom-spec.js +++ /dev/null @@ -1,260 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot, cold, lowerCaseO */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var Promise = require('promise'); - -describe('Observable.prototype.withLatestFrom()', function () { - it.asDiagram('withLatestFrom')('should combine events from cold observables', function () { - var e1 = hot('-a--b-----c-d-e-|'); - var e2 = hot('--1--2-3-4---| '); - var expected = '----B-----C-D-E-|'; - - var result = e1.withLatestFrom(e2, function (a, b) { return String(a) + String(b); }); - - expectObservable(result).toBe(expected, { B: 'b1', C: 'c4', D: 'd4', E: 'e4' }); - }); - - it('should merge the value with the latest values from the other observables into arrays', function () { - var e1 = hot('--a--^---b---c---d-|'); - var e1subs = '^ !'; - var e2 = hot('--e--^-f---g---h------|'); - var e2subs = '^ !'; - var e3 = hot('--i--^-j---k---l------|'); - var e3subs = '^ !'; - var expected = '----x---y---z-|'; - var values = { - x: ['b', 'f', 'j'], - y: ['c', 'g', 'k'], - z: ['d', 'h', 'l'] - }; - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should merge the value with the latest values from the other observables into ' + - 'arrays and a project argument', function () { - var e1 = hot('--a--^---b---c---d-|'); - var e1subs = '^ !'; - var e2 = hot('--e--^-f---g---h------|'); - var e2subs = '^ !'; - var e3 = hot('--i--^-j---k---l------|'); - var e3subs = '^ !'; - var expected = '----x---y---z-|'; - var values = { - x: 'bfj', - y: 'cgk', - z: 'dhl' - }; - var project = function (a, b, c) { return a + b + c; }; - - var result = e1.withLatestFrom(e2, e3, project); - - expectObservable(result).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should allow unsubscribing early and explicitly', function () { - var e1 = hot('--a--^---b---c---d-|'); - var e1subs = '^ ! '; - var e2 = hot('--e--^-f---g---h------|'); - var e2subs = '^ ! '; - var e3 = hot('--i--^-j---k---l------|'); - var e3subs = '^ ! '; - var expected = '----x---y--- '; - var unsub = ' ! '; - var values = { - x: 'bfj', - y: 'cgk', - z: 'dhl' - }; - var project = function (a, b, c) { return a + b + c; }; - - var result = e1.withLatestFrom(e2, e3, project); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should not break unsubscription chains when result is unsubscribed explicitly', function () { - var e1 = hot('--a--^---b---c---d-|'); - var e1subs = '^ ! '; - var e2 = hot('--e--^-f---g---h------|'); - var e2subs = '^ ! '; - var e3 = hot('--i--^-j---k---l------|'); - var e3subs = '^ ! '; - var expected = '----x---y--- '; - var unsub = ' ! '; - var values = { - x: 'bfj', - y: 'cgk', - z: 'dhl' - }; - var project = function (a, b, c) { return a + b + c; }; - - var result = e1 - .mergeMap(function (x) { return Observable.of(x); }) - .withLatestFrom(e2, e3, project) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(result, unsub).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle empty', function () { - var e1 = cold( '|'); - var e1subs = '(^!)'; - var e2 = hot('--e--^-f---g---h----|'); - var e2subs = '(^!)'; - var e3 = hot('--i--^-j---k---l----|'); - var e3subs = '(^!)'; - var expected = '|'; // empty - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle never', function () { - var e1 = cold('-'); - var e1subs = '^ '; - var e2 = hot('--e--^-f---g---h----|'); - var e2subs = '^ !'; - var e3 = hot('--i--^-j---k---l----|'); - var e3subs = '^ !'; - var expected = '--------------------'; // never - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle throw', function () { - var e1 = cold('#'); - var e1subs = '(^!)'; - var e2 = hot('--e--^-f---g---h----|'); - var e2subs = '(^!)'; - var e3 = hot('--i--^-j---k---l----|'); - var e3subs = '(^!)'; - var expected = '#'; // throw - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle error', function () { - var e1 = hot('--a--^---b---#', undefined, new Error('boo-hoo')); - var e1subs = '^ !'; - var e2 = hot('--e--^-f---g---h----|'); - var e2subs = '^ !'; - var e3 = hot('--i--^-j---k---l----|'); - var e3subs = '^ !'; - var expected = '----x---#'; // throw - var values = { - x: ['b','f','j'] - }; - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected, values, new Error('boo-hoo')); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle error with project argument', function () { - var e1 = hot('--a--^---b---#', undefined, new Error('boo-hoo')); - var e1subs = '^ !'; - var e2 = hot('--e--^-f---g---h----|'); - var e2subs = '^ !'; - var e3 = hot('--i--^-j---k---l----|'); - var e3subs = '^ !'; - var expected = '----x---#'; // throw - var values = { - x: 'bfj' - }; - var project = function (a, b, c) { return a + b + c; }; - - var result = e1.withLatestFrom(e2, e3, project); - - expectObservable(result).toBe(expected, values, new Error('boo-hoo')); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle merging with empty', function () { - var e1 = hot('--a--^---b---c---d-| '); - var e1subs = '^ ! '; - var e2 = cold( '|' ); - var e2subs = '(^!)'; - var e3 = hot('--i--^-j---k---l------|'); - var e3subs = '^ ! '; - var expected = '--------------| '; - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle merging with never', function () { - var e1 = hot('--a--^---b---c---d-| '); - var e1subs = '^ ! '; - var e2 = cold( '-' ); - var e2subs = '^ ! '; - var e3 = hot('--i--^-j---k---l------|'); - var e3subs = '^ ! '; - var expected = '--------------| '; - - var result = e1.withLatestFrom(e2, e3); - - expectObservable(result).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should handle promises', function (done) { - Observable.of(1).delay(1).withLatestFrom(Promise.resolve(2), Promise.resolve(3)) - .subscribe(function (x) { - expect(x).toEqual([1,2,3]); - }, null, done); - }); - - it('should handle arrays', function () { - Observable.of(1).delay(1).withLatestFrom([2,3,4], [4,5,6]) - .subscribe(function (x) { - expect(x).toEqual([1,4,6]); - }); - }); - - it('should handle lowercase-o observables', function () { - Observable.of(1).delay(1).withLatestFrom(lowerCaseO(2, 3, 4), lowerCaseO(4, 5, 6)) - .subscribe(function (x) { - expect(x).toEqual([1,4,6]); - }); - }); -}); \ No newline at end of file diff --git a/spec/operators/withLatestFrom-spec.ts b/spec/operators/withLatestFrom-spec.ts new file mode 100644 index 0000000000..7464b74e1d --- /dev/null +++ b/spec/operators/withLatestFrom-spec.ts @@ -0,0 +1,261 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram, lowerCaseO} from '../helpers/test-helper'; + +const Observable = Rx.Observable; + +describe('Observable.prototype.withLatestFrom()', () => { + asDiagram('withLatestFrom')('should combine events from cold observables', () => { + const e1 = hot('-a--b-----c-d-e-|'); + const e2 = hot('--1--2-3-4---| '); + const expected = '----B-----C-D-E-|'; + + const result = e1.withLatestFrom(e2, (a: string, b: string) => String(a) + String(b)); + + expectObservable(result).toBe(expected, { B: 'b1', C: 'c4', D: 'd4', E: 'e4' }); + }); + + it('should merge the value with the latest values from the other observables into arrays', () => { + const e1 = hot('--a--^---b---c---d-|'); + const e1subs = '^ !'; + const e2 = hot('--e--^-f---g---h------|'); + const e2subs = '^ !'; + const e3 = hot('--i--^-j---k---l------|'); + const e3subs = '^ !'; + const expected = '----x---y---z-|'; + const values = { + x: ['b', 'f', 'j'], + y: ['c', 'g', 'k'], + z: ['d', 'h', 'l'] + }; + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should merge the value with the latest values from the other observables into ' + + 'arrays and a project argument', () => { + const e1 = hot('--a--^---b---c---d-|'); + const e1subs = '^ !'; + const e2 = hot('--e--^-f---g---h------|'); + const e2subs = '^ !'; + const e3 = hot('--i--^-j---k---l------|'); + const e3subs = '^ !'; + const expected = '----x---y---z-|'; + const values = { + x: 'bfj', + y: 'cgk', + z: 'dhl' + }; + const project = function (a, b, c) { return a + b + c; }; + + const result = e1.withLatestFrom(e2, e3, project); + + expectObservable(result).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should allow unsubscribing early and explicitly', () => { + const e1 = hot('--a--^---b---c---d-|'); + const e1subs = '^ ! '; + const e2 = hot('--e--^-f---g---h------|'); + const e2subs = '^ ! '; + const e3 = hot('--i--^-j---k---l------|'); + const e3subs = '^ ! '; + const expected = '----x---y--- '; + const unsub = ' ! '; + const values = { + x: 'bfj', + y: 'cgk', + z: 'dhl' + }; + const project = function (a, b, c) { return a + b + c; }; + + const result = e1.withLatestFrom(e2, e3, project); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should not break unsubscription chains when result is unsubscribed explicitly', () => { + const e1 = hot('--a--^---b---c---d-|'); + const e1subs = '^ ! '; + const e2 = hot('--e--^-f---g---h------|'); + const e2subs = '^ ! '; + const e3 = hot('--i--^-j---k---l------|'); + const e3subs = '^ ! '; + const expected = '----x---y--- '; + const unsub = ' ! '; + const values = { + x: 'bfj', + y: 'cgk', + z: 'dhl' + }; + const project = function (a, b, c) { return a + b + c; }; + + const result = e1 + .mergeMap((x: string) => Observable.of(x)) + .withLatestFrom(e2, e3, project) + .mergeMap((x: string) => Observable.of(x)); + + expectObservable(result, unsub).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle empty', () => { + const e1 = cold( '|'); + const e1subs = '(^!)'; + const e2 = hot('--e--^-f---g---h----|'); + const e2subs = '(^!)'; + const e3 = hot('--i--^-j---k---l----|'); + const e3subs = '(^!)'; + const expected = '|'; // empty + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle never', () => { + const e1 = cold('-'); + const e1subs = '^ '; + const e2 = hot('--e--^-f---g---h----|'); + const e2subs = '^ !'; + const e3 = hot('--i--^-j---k---l----|'); + const e3subs = '^ !'; + const expected = '--------------------'; // never + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle throw', () => { + const e1 = cold('#'); + const e1subs = '(^!)'; + const e2 = hot('--e--^-f---g---h----|'); + const e2subs = '(^!)'; + const e3 = hot('--i--^-j---k---l----|'); + const e3subs = '(^!)'; + const expected = '#'; // throw + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle error', () => { + const e1 = hot('--a--^---b---#', undefined, new Error('boo-hoo')); + const e1subs = '^ !'; + const e2 = hot('--e--^-f---g---h----|'); + const e2subs = '^ !'; + const e3 = hot('--i--^-j---k---l----|'); + const e3subs = '^ !'; + const expected = '----x---#'; // throw + const values = { + x: ['b','f','j'] + }; + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected, values, new Error('boo-hoo')); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle error with project argument', () => { + const e1 = hot('--a--^---b---#', undefined, new Error('boo-hoo')); + const e1subs = '^ !'; + const e2 = hot('--e--^-f---g---h----|'); + const e2subs = '^ !'; + const e3 = hot('--i--^-j---k---l----|'); + const e3subs = '^ !'; + const expected = '----x---#'; // throw + const values = { + x: 'bfj' + }; + const project = function (a, b, c) { return a + b + c; }; + + const result = e1.withLatestFrom(e2, e3, project); + + expectObservable(result).toBe(expected, values, new Error('boo-hoo')); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle merging with empty', () => { + const e1 = hot('--a--^---b---c---d-| '); + const e1subs = '^ ! '; + const e2 = cold( '|' ); + const e2subs = '(^!)'; + const e3 = hot('--i--^-j---k---l------|'); + const e3subs = '^ ! '; + const expected = '--------------| '; + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle merging with never', () => { + const e1 = hot('--a--^---b---c---d-| '); + const e1subs = '^ ! '; + const e2 = cold( '-' ); + const e2subs = '^ ! '; + const e3 = hot('--i--^-j---k---l------|'); + const e3subs = '^ ! '; + const expected = '--------------| '; + + const result = e1.withLatestFrom(e2, e3); + + expectObservable(result).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should handle promises', (done: DoneSignature) => { + Observable.of(1).delay(1).withLatestFrom(Promise.resolve(2), Promise.resolve(3)) + .subscribe((x: any) => { + expect(x).toEqual([1,2,3]); + }, null, done); + }); + + it('should handle arrays', () => { + Observable.of(1).delay(1).withLatestFrom([2,3,4], [4,5,6]) + .subscribe((x: any) => { + expect(x).toEqual([1,4,6]); + }); + }); + + it('should handle lowercase-o observables', () => { + Observable.of(1).delay(1).withLatestFrom(lowerCaseO(2, 3, 4), lowerCaseO(4, 5, 6)) + .subscribe((x: any) => { + expect(x).toEqual([1,4,6]); + }); + }); +}); \ No newline at end of file diff --git a/spec/operators/zip-spec.js b/spec/operators/zip-spec.js deleted file mode 100644 index 24c8fa01f4..0000000000 --- a/spec/operators/zip-spec.js +++ /dev/null @@ -1,591 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, hot, cold */ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('zip', function () { - it('should combine a source with a second', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - - expectObservable(a.zip(b)) - .toBe(expected, { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should zip the provided observables', function (done) { - var expected = ['a1', 'b2', 'c3']; - var i = 0; - - Observable.fromArray(['a','b','c']).zip( - Observable.fromArray([1,2,3]), - function (a, b) { - return a + b; - } - ) - .subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }); - - it('should end once one observable completes and its buffer is empty', function () { - var e1 = hot('---a--b--c--| '); - var e1subs = '^ ! '; - var e2 = hot('------d----e----f--------| '); - var e2subs = '^ ! '; - var e3 = hot('--------h----i----j---------'); // doesn't complete - var e3subs = '^ ! '; - var expected = '--------x----y----(z|) '; // e1 complete and buffer empty - var values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] - }; - - expectObservable(e1.zip(e2,e3)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should end once one observable nexts and zips value from completed other ' + - 'observable whose buffer is empty', function () { - var e1 = hot('---a--b--c--| '); - var e1subs = '^ ! '; - var e2 = hot('------d----e----f| '); - var e2subs = '^ ! '; - var e3 = hot('--------h----i----j-------'); // doesn't complete - var e3subs = '^ ! '; - var expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete - var values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] - }; - - expectObservable(e1.zip(e2,e3)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - describe('with iterables', function () { - it('should zip them with values', function () { - var myIterator = { - count: 0, - next: function () { - return { value: this.count++, done: false }; - } - }; - myIterator[Symbol.iterator] = function () { return this; }; - - var e1 = hot('---a---b---c---d---|'); - var e1subs = '^ !'; - var expected = '---w---x---y---z---|'; - - var values = { - w: ['a', 0], - x: ['b', 1], - y: ['c', 2], - z: ['d', 3] - }; - - expectObservable(e1.zip(myIterator)).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should only call `next` as needed', function () { - var nextCalled = 0; - var myIterator = { - count: 0, - next: function () { - nextCalled++; - return { value: this.count++, done: false }; - } - }; - myIterator[Symbol.iterator] = function () { return this; }; - - Observable.of(1,2,3).zip(myIterator) - .subscribe(); - - // since zip will call `next()` in advance, total calls when - // zipped with 3 other values should be 4. - expect(nextCalled).toBe(4); - }); - - it('should work with never observable and empty iterable', function () { - var a = cold( '-'); - var asubs = '^'; - var b = []; - var expected = '-'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with empty observable and empty iterable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var b = []; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with empty observable and non-empty iterable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var b = [1]; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and empty iterable', function () { - var a = hot('---^----a--|'); - var asubs = '^ !'; - var b = []; - var expected = '--------|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with never observable and non-empty iterable', function () { - var a = cold('-'); - var asubs = '^'; - var b = [1]; - var expected = '-'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and non-empty iterable', function () { - var a = hot('---^----1--|'); - var asubs = '^ ! '; - var b = [2]; - var expected = '-----(x|)'; - - expectObservable(a.zip(b)).toBe(expected, { x: ['1', 2] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and empty iterable', function () { - var a = hot('---^----#'); - var asubs = '^ !'; - var b = []; - var expected = '-----#'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with observable which raises error and non-empty iterable', function () { - var a = hot('---^----#'); - var asubs = '^ !'; - var b = [1]; - var expected = '-----#'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty many observable and non-empty many iterable', function () { - var a = hot('---^--1--2--3--|'); - var asubs = '^ ! '; - var b = [4, 5, 6]; - var expected = '---x--y--(z|)'; - - expectObservable(a.zip(b)).toBe(expected, - { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and non-empty iterable selector that throws', function () { - var a = hot('---^--1--2--3--|'); - var asubs = '^ !'; - var b = [4, 5, 6]; - var expected = '---x--#'; - - var selector = function (x, y) { - if (y === 5) { - throw new Error('too bad'); - } else { - return x + y; - }}; - expectObservable(a.zip(b,selector)).toBe(expected, - { x: '14' }, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - }); - - it('should combine two observables and selector', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - - expectObservable(a.zip(b, function (e1,e2) { return e1 + e2; })) - .toBe(expected, { x: '14', y: '25', z: '36' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - expectObservable(a.zip(b,c)).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric selector', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - var observable = a.zip(b,c, - function (r0, r1, r2) { return [r0, r1, r2]; }); - expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric array selector', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - var observable = a.zip(b,c, - function (r0, r1, r2) { return [r0, r1, r2]; }); - expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data asymmetric 1', function () { - var a = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--4--6--8--0--| '); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e--| '; - - expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data asymmetric 2', function () { - var a = hot('---1-^--2--4--6--8--0--| '); - var asubs = '^ ! '; - var b = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e--| '; - - expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data symmetric', function () { - var a = hot('---1-^-1-3-5-7-9------| '); - var asubs = '^ ! '; - var b = hot('---1-^--2--4--6--8--0--|'); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e-| '; - - expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with selector throws', function () { - var a = hot('---1-^-2---4----| '); - var asubs = '^ ! '; - var b = hot('---1-^--3----5----|'); - var bsubs = '^ ! '; - var expected = '---x----# '; - - var selector = function (x, y) { - if (y === '5') { - throw new Error('too bad'); - } else { - return x + y; - }}; - var observable = a.zip(b,selector); - expectObservable(observable).toBe(expected, - { x: '23' }, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with right completes first', function () { - var a = hot('---1-^-2-----|'); - var asubs = '^ !'; - var b = hot('---1-^--3--|'); - var bsubs = '^ !'; - var expected = '---x--|'; - - expectObservable(a.zip(b)).toBe(expected, { x: ['2', '3'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two nevers', function () { - var a = cold( '-'); - var asubs = '^'; - var b = cold( '-'); - var bsubs = '^'; - var expected = '-'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and empty', function () { - var a = cold( '-'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and never', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = cold( '-'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and empty', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and non-empty', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = hot( '---1--|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with non-empty and empty', function () { - var a = hot( '---1--|'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and non-empty', function () { - var a = cold( '-'); - var asubs = '^'; - var b = hot( '---1--|'); - var bsubs = '^ !'; - var expected = '-'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with non-empty and never', function () { - var a = hot( '---1--|'); - var asubs = '^ !'; - var b = cold( '-'); - var bsubs = '^'; - var expected = '-'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and error', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = hot( '------#', null, 'too bad'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and empty', function () { - var a = hot( '------#', null, 'too bad'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error', function () { - var a = hot('----------|'); - var asubs = '^ ! '; - var b = hot('------# '); - var bsubs = '^ ! '; - var expected = '------# '; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and error', function () { - var a = cold( '-'); - var asubs = '^ !'; - var b = hot('------#'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and never', function () { - var a = hot('------#'); - var asubs = '^ !'; - var b = cold( '-'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and error', function () { - var a = hot('------#', null, 'too bad'); - var asubs = '^ !'; - var b = hot('----------#', null, 'too bad 2'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(a.zip(b)).toBe(expected, null, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two sources that eventually raise errors', function () { - var a = hot('--w-----#----', { w: 1 }, 'too bad'); - var asubs = '^ !'; - var b = hot('-----z-----#-', { z: 2 }, 'too bad 2'); - var bsubs = '^ !'; - var expected = '-----x--#'; - - expectObservable(a.zip(b)).toBe(expected, { x: [1, 2] }, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two sources that eventually raise errors (swapped)', function () { - var a = hot('-----z-----#-', { z: 2 }, 'too bad 2'); - var asubs = '^ !'; - var b = hot('--w-----#----', { w: 1 }, 'too bad'); - var bsubs = '^ !'; - var expected = '-----x--#'; - - expectObservable(a.zip(b)).toBe(expected, { x: [2, 1] }, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and some', function () { - var a = cold( '#'); - var asubs = '(^!)'; - var b = hot( '--1--2--3--'); - var bsubs = '(^!)'; - var expected = '#'; - - expectObservable(a.zip(b)).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should combine an immediately-scheduled source with an immediately-scheduled second', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [[1, 4], [2, 5], [3, 6]]; - var i = 0; - - a.zip(b).subscribe(function (vals) { - expect(vals).toDeepEqual(r[i++]); - }, null, done); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var a = hot('---1---2---3---|'); - var unsub = ' !'; - var asubs = '^ !'; - var b = hot('--4--5--6--7--8--|'); - var bsubs = '^ !'; - var expected = '---x---y--'; - - var r = a - .mergeMap(function (x) { return Observable.of(x); }) - .zip(b) - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(r, unsub).toBe(expected, { x: ['1', '4'], y: ['2', '5']}); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); -}); diff --git a/spec/operators/zip-spec.ts b/spec/operators/zip-spec.ts new file mode 100644 index 0000000000..bdc4e30af8 --- /dev/null +++ b/spec/operators/zip-spec.ts @@ -0,0 +1,594 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const Symbol: any; +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('zip', () => { + it('should combine a source with a second', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + + expectObservable(a.zip(b)) + .toBe(expected, { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should zip the provided observables', (done: DoneSignature) => { + const expected = ['a1', 'b2', 'c3']; + let i = 0; + + Observable.fromArray(['a','b','c']).zip( + Observable.fromArray([1,2,3]), + function (a, b) { + return a + b; + } + ) + .subscribe(function (x) { + expect(x).toBe(expected[i++]); + }, null, done); + }); + + it('should end once one observable completes and its buffer is empty', () => { + const e1 = hot('---a--b--c--| '); + const e1subs = '^ ! '; + const e2 = hot('------d----e----f--------| '); + const e2subs = '^ ! '; + const e3 = hot('--------h----i----j---------'); // doesn't complete + const e3subs = '^ ! '; + const expected = '--------x----y----(z|) '; // e1 complete and buffer empty + const values = { + x: ['a','d','h'], + y: ['b','e','i'], + z: ['c','f','j'] + }; + + expectObservable(e1.zip(e2,e3)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should end once one observable nexts and zips value from completed other ' + + 'observable whose buffer is empty', () => { + const e1 = hot('---a--b--c--| '); + const e1subs = '^ ! '; + const e2 = hot('------d----e----f| '); + const e2subs = '^ ! '; + const e3 = hot('--------h----i----j-------'); // doesn't complete + const e3subs = '^ ! '; + const expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete + const values = { + x: ['a','d','h'], + y: ['b','e','i'], + z: ['c','f','j'] + }; + + expectObservable(e1.zip(e2,e3)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + describe('with iterables', () => { + it('should zip them with values', () => { + const myIterator = { + count: 0, + next: function () { + return { value: this.count++, done: false }; + } + }; + myIterator[Symbol.iterator] = function () { return this; }; + + const e1 = hot('---a---b---c---d---|'); + const e1subs = '^ !'; + const expected = '---w---x---y---z---|'; + + const values = { + w: ['a', 0], + x: ['b', 1], + y: ['c', 2], + z: ['d', 3] + }; + + expectObservable(e1.zip(myIterator)).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should only call `next` as needed', () => { + let nextCalled = 0; + const myIterator = { + count: 0, + next: function () { + nextCalled++; + return { value: this.count++, done: false }; + } + }; + myIterator[Symbol.iterator] = function () { return this; }; + + Observable.of(1,2,3).zip(myIterator) + .subscribe(); + + // since zip will call `next()` in advance, total calls when + // zipped with 3 other values should be 4. + expect(nextCalled).toBe(4); + }); + + it('should work with never observable and empty iterable', () => { + const a = cold( '-'); + const asubs = '^'; + const b = []; + const expected = '-'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with empty observable and empty iterable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const b = []; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with empty observable and non-empty iterable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const b = [1]; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and empty iterable', () => { + const a = hot('---^----a--|'); + const asubs = '^ !'; + const b = []; + const expected = '--------|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with never observable and non-empty iterable', () => { + const a = cold('-'); + const asubs = '^'; + const b = [1]; + const expected = '-'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and non-empty iterable', () => { + const a = hot('---^----1--|'); + const asubs = '^ ! '; + const b = [2]; + const expected = '-----(x|)'; + + expectObservable(a.zip(b)).toBe(expected, { x: ['1', 2] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and empty iterable', () => { + const a = hot('---^----#'); + const asubs = '^ !'; + const b = []; + const expected = '-----#'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with observable which raises error and non-empty iterable', () => { + const a = hot('---^----#'); + const asubs = '^ !'; + const b = [1]; + const expected = '-----#'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty many observable and non-empty many iterable', () => { + const a = hot('---^--1--2--3--|'); + const asubs = '^ ! '; + const b = [4, 5, 6]; + const expected = '---x--y--(z|)'; + + expectObservable(a.zip(b)).toBe(expected, + { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and non-empty iterable selector that throws', () => { + const a = hot('---^--1--2--3--|'); + const asubs = '^ !'; + const b = [4, 5, 6]; + const expected = '---x--#'; + + const selector = function (x, y) { + if (y === 5) { + throw new Error('too bad'); + } else { + return x + y; + }}; + expectObservable(a.zip(b,selector)).toBe(expected, + { x: '14' }, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + }); + + it('should combine two observables and selector', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + + expectObservable(a.zip(b, function (e1,e2) { return e1 + e2; })) + .toBe(expected, { x: '14', y: '25', z: '36' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + expectObservable(a.zip(b,c)).toBe(expected, + { x: ['1','2','3'], y: ['4','5','6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric selector', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + const observable = a.zip(b,c, + function (r0, r1, r2) { return [r0, r1, r2]; }); + expectObservable(observable).toBe(expected, + { x: ['1','2','3'], y: ['4','5','6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric array selector', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + const observable = a.zip(b,c, + function (r0, r1, r2) { return [r0, r1, r2]; }); + expectObservable(observable).toBe(expected, + { x: ['1','2','3'], y: ['4','5','6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data asymmetric 1', () => { + const a = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--4--6--8--0--| '); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e--| '; + + expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) + .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data asymmetric 2', () => { + const a = hot('---1-^--2--4--6--8--0--| '); + const asubs = '^ ! '; + const b = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e--| '; + + expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) + .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data symmetric', () => { + const a = hot('---1-^-1-3-5-7-9------| '); + const asubs = '^ ! '; + const b = hot('---1-^--2--4--6--8--0--|'); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e-| '; + + expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) + .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with selector throws', () => { + const a = hot('---1-^-2---4----| '); + const asubs = '^ ! '; + const b = hot('---1-^--3----5----|'); + const bsubs = '^ ! '; + const expected = '---x----# '; + + const selector = function (x, y) { + if (y === '5') { + throw new Error('too bad'); + } else { + return x + y; + }}; + const observable = a.zip(b,selector); + expectObservable(observable).toBe(expected, + { x: '23' }, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with right completes first', () => { + const a = hot('---1-^-2-----|'); + const asubs = '^ !'; + const b = hot('---1-^--3--|'); + const bsubs = '^ !'; + const expected = '---x--|'; + + expectObservable(a.zip(b)).toBe(expected, { x: ['2', '3'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two nevers', () => { + const a = cold( '-'); + const asubs = '^'; + const b = cold( '-'); + const bsubs = '^'; + const expected = '-'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and empty', () => { + const a = cold( '-'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and never', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = cold( '-'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and empty', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and non-empty', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = hot( '---1--|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with non-empty and empty', () => { + const a = hot( '---1--|'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and non-empty', () => { + const a = cold( '-'); + const asubs = '^'; + const b = hot( '---1--|'); + const bsubs = '^ !'; + const expected = '-'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with non-empty and never', () => { + const a = hot( '---1--|'); + const asubs = '^ !'; + const b = cold( '-'); + const bsubs = '^'; + const expected = '-'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and error', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = hot( '------#', null, 'too bad'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and empty', () => { + const a = hot( '------#', null, 'too bad'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error', () => { + const a = hot('----------|'); + const asubs = '^ ! '; + const b = hot('------# '); + const bsubs = '^ ! '; + const expected = '------# '; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and error', () => { + const a = cold( '-'); + const asubs = '^ !'; + const b = hot('------#'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and never', () => { + const a = hot('------#'); + const asubs = '^ !'; + const b = cold( '-'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and error', () => { + const a = hot('------#', null, 'too bad'); + const asubs = '^ !'; + const b = hot('----------#', null, 'too bad 2'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(a.zip(b)).toBe(expected, null, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two sources that eventually raise errors', () => { + const a = hot('--w-----#----', { w: 1 }, 'too bad'); + const asubs = '^ !'; + const b = hot('-----z-----#-', { z: 2 }, 'too bad 2'); + const bsubs = '^ !'; + const expected = '-----x--#'; + + expectObservable(a.zip(b)).toBe(expected, { x: [1, 2] }, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two sources that eventually raise errors (swapped)', () => { + const a = hot('-----z-----#-', { z: 2 }, 'too bad 2'); + const asubs = '^ !'; + const b = hot('--w-----#----', { w: 1 }, 'too bad'); + const bsubs = '^ !'; + const expected = '-----x--#'; + + expectObservable(a.zip(b)).toBe(expected, { x: [2, 1] }, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and some', () => { + const a = cold( '#'); + const asubs = '(^!)'; + const b = hot( '--1--2--3--'); + const bsubs = '(^!)'; + const expected = '#'; + + expectObservable(a.zip(b)).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should combine an immediately-scheduled source with an immediately-scheduled second', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [[1, 4], [2, 5], [3, 6]]; + let i = 0; + + a.zip(b).subscribe(function (vals) { + (expect(vals)).toDeepEqual(r[i++]); + }, null, done); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const a = hot('---1---2---3---|'); + const unsub = ' !'; + const asubs = '^ !'; + const b = hot('--4--5--6--7--8--|'); + const bsubs = '^ !'; + const expected = '---x---y--'; + + const r = a + .mergeMap((x: string) => Observable.of(x)) + .zip(b) + .mergeMap((x: Array) => Observable.of(x)); + + expectObservable(r, unsub).toBe(expected, { x: ['1', '4'], y: ['2', '5']}); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); +}); diff --git a/spec/operators/zipAll-spec.js b/spec/operators/zipAll-spec.js deleted file mode 100644 index 86180442d2..0000000000 --- a/spec/operators/zipAll-spec.js +++ /dev/null @@ -1,722 +0,0 @@ -/* globals describe, it, expect, expectSubscriptions, expectObservable, hot, cold*/ -var Rx = require('../../dist/cjs/Rx'); -var Observable = Rx.Observable; -var queueScheduler = Rx.Scheduler.queue; - -describe('Observable.prototype.zipAll', function () { - it.asDiagram('zipAll')('should combine paired events from two observables', function () { - var x = cold( '-a-----b-|'); - var y = cold( '--1-2-----'); - var outer = hot('-x----y--------| ', { x: x, y: y }); - var expected = '-----------------A----B-|'; - - var result = outer.zipAll(function (a, b) { return String(a) + String(b); }); - - expectObservable(result).toBe(expected, { A: 'a1', B: 'b2' }); - }); - - it('should combine two observables', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - var values = { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should take all observables from the source and zip them', function (done) { - var expected = ['a1', 'b2', 'c3']; - var i = 0; - Observable.of( - Observable.of('a','b','c'), - Observable.of(1,2,3) - ) - .zipAll(function (a, b) { - return a + b; - }) - .subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }); - - it('should end once one observable completes and its buffer is empty', function () { - var e1 = hot('---a--b--c--| '); - var e1subs = '^ ! '; - var e2 = hot('------d----e----f--------| '); - var e2subs = '^ ! '; - var e3 = hot('--------h----i----j---------'); // doesn't complete - var e3subs = '^ ! '; - var expected = '--------x----y----(z|) '; // e1 complete and buffer empty - var values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] - }; - - expectObservable(Observable.of(e1,e2,e3).zipAll()).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - it('should end once one observable nexts and zips value from completed other ' + - 'observable whose buffer is empty', function () { - var e1 = hot('---a--b--c--| '); - var e1subs = '^ ! '; - var e2 = hot('------d----e----f| '); - var e2subs = '^ ! '; - var e3 = hot('--------h----i----j-------'); // doesn't complete - var e3subs = '^ ! '; - var expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete - var values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] - }; - - expectObservable(Observable.of(e1,e2,e3).zipAll()).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - expectSubscriptions(e2.subscriptions).toBe(e2subs); - expectSubscriptions(e3.subscriptions).toBe(e3subs); - }); - - describe('with iterables', function () { - it('should zip them with values', function () { - var myIterator = { - count: 0, - next: function () { - return { value: this.count++, done: false }; - } - }; - myIterator[Symbol.iterator] = function () { return this; }; - - var e1 = hot('---a---b---c---d---|'); - var e1subs = '^ !'; - var expected = '---w---x---y---z---|'; - - var values = { - w: ['a', 0], - x: ['b', 1], - y: ['c', 2], - z: ['d', 3] - }; - - expectObservable(Observable.of(e1, myIterator).zipAll()).toBe(expected, values); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should only call `next` as needed', function () { - var nextCalled = 0; - var myIterator = { - count: 0, - next: function () { - nextCalled++; - return { value: this.count++, done: false }; - } - }; - myIterator[Symbol.iterator] = function () { return this; }; - - Observable.of(Observable.of(1,2,3), myIterator).zipAll() - .subscribe(); - - // since zip will call `next()` in advance, total calls when - // zipped with 3 other values should be 4. - expect(nextCalled).toBe(4); - }); - - it('should work with never observable and empty iterable', function () { - var a = cold( '-'); - var asubs = '^'; - var b = []; - var expected = '-'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with empty observable and empty iterable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var b = []; - var expected = '|'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with empty observable and non-empty iterable', function () { - var a = cold('|'); - var asubs = '(^!)'; - var b = [1]; - var expected = '|'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and empty iterable', function () { - var a = hot('---^----a--|'); - var asubs = '^ !'; - var b = []; - var expected = '--------|'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with never observable and non-empty iterable', function () { - var a = cold('-'); - var asubs = '^'; - var b = [1]; - var expected = '-'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and non-empty iterable', function () { - var a = hot('---^----1--|'); - var asubs = '^ ! '; - var b = [2]; - var expected = '-----(x|)'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected, { x: ['1', 2] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and empty iterable', function () { - var a = hot('---^----#'); - var asubs = '^ !'; - var b = []; - var expected = '-----#'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with observable which raises error and non-empty iterable', function () { - var a = hot('---^----#'); - var asubs = '^ !'; - var b = [1]; - var expected = '-----#'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty many observable and non-empty many iterable', function () { - var a = hot('---^--1--2--3--|'); - var asubs = '^ ! '; - var b = [4, 5, 6]; - var expected = '---x--y--(z|)'; - - expectObservable(Observable.of(a,b).zipAll()).toBe(expected, - { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - - it('should work with non-empty observable and non-empty iterable selector that throws', function () { - var a = hot('---^--1--2--3--|'); - var asubs = '^ !'; - var b = [4, 5, 6]; - var expected = '---x--#'; - - var selector = function (x, y) { - if (y === 5) { - throw new Error('too bad'); - } else { - return x + y; - }}; - expectObservable(Observable.of(a,b).zipAll(selector)).toBe(expected, - { x: '14' }, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(asubs); - }); - }); - - it('should combine two observables and selector', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - - expectObservable(Observable.of(a,b).zipAll(function (e1,e2) { return e1 + e2; })) - .toBe(expected, { x: '14', y: '25', z: '36' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - expectObservable(Observable.of(a,b,c).zipAll()).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric selector', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - var observable = Observable.of(a,b,c).zipAll( - function (r0, r1, r2) { return [r0, r1, r2]; }); - expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with n-ary symmetric array selector', function () { - var a = hot('---1-^-1----4----|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--5----| '); - var bsubs = '^ ! '; - var c = hot('---1-^---3---6-| '); - var expected = '----x---y-| '; - - var observable = Observable.of(a,b,c).zipAll( - function (r0, r1, r2) { return [r0, r1, r2]; }); - expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data asymmetric 1', function () { - var a = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); - var asubs = '^ ! '; - var b = hot('---1-^--2--4--6--8--0--| '); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e--| '; - - expectObservable(Observable.of(a,b).zipAll(function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data asymmetric 2', function () { - var a = hot('---1-^--2--4--6--8--0--| '); - var asubs = '^ ! '; - var b = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e--| '; - - expectObservable(Observable.of(a,b).zipAll(function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with some data symmetric', function () { - var a = hot('---1-^-1-3-5-7-9------| '); - var asubs = '^ ! '; - var b = hot('---1-^--2--4--6--8--0--|'); - var bsubs = '^ ! '; - var expected = '---a--b--c--d--e-| '; - - expectObservable(Observable.of(a,b).zipAll(function (r1,r2) { return r1 + r2; })) - .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with selector throws', function () { - var a = hot('---1-^-2---4----| '); - var asubs = '^ ! '; - var b = hot('---1-^--3----5----|'); - var bsubs = '^ ! '; - var expected = '---x----# '; - - var selector = function (x, y) { - if (y === '5') { - throw new Error('too bad'); - } else { - return x + y; - }}; - var observable = Observable.of(a,b).zipAll(selector); - expectObservable(observable).toBe(expected, - { x: '23' }, new Error('too bad')); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with right completes first', function () { - var a = hot('---1-^-2-----|'); - var asubs = '^ !'; - var b = hot('---1-^--3--|'); - var bsubs = '^ !'; - var expected = '---x--|'; - - expectObservable(Observable.zip(a,b)).toBe(expected, { x: ['2', '3'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should zip until one child terminates', function (done) { - var expected = ['a1', 'b2']; - var i = 0; - Observable.of( - Observable.of('a','b','c'), - Observable.of(1,2) - ) - .zipAll(function (a, b) { - return a + b; - }) - .subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - }); - - it('should handle a hot observable of observables', function () { - var x = cold( 'a---b---c---| '); - var xsubs = ' ^ !'; - var y = cold( 'd---e---f---| '); - var ysubs = ' ^ !'; - var e1 = hot('--x--y--| ', { x: x, y: y }); - var e1subs = '^ !'; - var expected = '--------u---v---w---|'; - var values = { - u: ['a', 'd'], - v: ['b', 'e'], - w: ['c', 'f'] - }; - - expectObservable(e1.zipAll()).toBe(expected, values); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should handle merging a hot observable of non-overlapped observables', function () { - var x = cold( 'a-b---------| '); - var xsubs = ' ^ !'; - var y = cold( 'c-d-e-f-| '); - var ysubs = ' ^ ! '; - var z = cold( 'g-h-i-j-k-| '); - var zsubs = ' ^ ! '; - var e1 = hot('--x------y--------z--------| ', { x: x, y: y, z: z }); - var e1subs = '^ !'; - var expected = '---------------------------u-v---------|'; - var values = { - u: ['a', 'c', 'g'], - v: ['b', 'd', 'h'] - }; - - expectObservable(e1.zipAll()).toBe(expected, values); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if inner observable raises error', function () { - var x = cold( 'a-b---------| '); - var xsubs = ' ^ !'; - var y = cold( 'c-d-e-f-# '); - var ysubs = ' ^ !'; - var z = cold( 'g-h-i-j-k-| '); - var zsubs = ' ^ !'; - var e1 = hot('--x---------y--------z--------|', { x: x, y: y, z: z }); - var e1subs = '^ !'; - var expected = '------------------------------u-v-----#'; - - var expectedValues = { - u: ['a', 'c', 'g'], - v: ['b', 'd', 'h'] - }; - - expectObservable(e1.zipAll()).toBe(expected, expectedValues); - expectSubscriptions(x.subscriptions).toBe(xsubs); - expectSubscriptions(y.subscriptions).toBe(ysubs); - expectSubscriptions(z.subscriptions).toBe(zsubs); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should raise error if outer observable raises error', function () { - var y = cold( 'a-b---------|'); - var z = cold( 'c-d-e-f-|'); - var e1 = hot('--y---------z---#', { y: y, z: z }); - var e1subs = '^ !'; - var expected = '----------------#'; - - expectObservable(e1.zipAll()).toBe(expected); - expectSubscriptions(e1.subscriptions).toBe(e1subs); - }); - - it('should work with two nevers', function () { - var a = cold( '-'); - var asubs = '^'; - var b = cold( '-'); - var bsubs = '^'; - var expected = '-'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and empty', function () { - var a = cold( '-'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and never', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = cold( '-'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and empty', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and non-empty', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = hot( '---1--|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with non-empty and empty', function () { - var a = hot( '---1--|'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and non-empty', function () { - var a = cold( '-'); - var asubs = '^'; - var b = hot( '---1--|'); - var bsubs = '^ !'; - var expected = '-'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with non-empty and never', function () { - var a = hot( '---1--|'); - var asubs = '^ !'; - var b = cold( '-'); - var bsubs = '^'; - var expected = '-'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should combine a source with a second', function () { - var a = hot('---1---2---3---'); - var asubs = '^'; - var b = hot('--4--5--6--7--8--'); - var bsubs = '^'; - var expected = '---x---y---z'; - - expectObservable(Observable.of(a, b).zipAll()) - .toBe(expected, { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with empty and error', function () { - var a = cold( '|'); - var asubs = '(^!)'; - var b = hot( '------#', null, 'too bad'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and empty', function () { - var a = hot( '------#', null, 'too bad'); - var asubs = '(^!)'; - var b = cold( '|'); - var bsubs = '(^!)'; - var expected = '|'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error', function () { - var a = hot('----------|'); - var asubs = '^ ! '; - var b = hot('------# '); - var bsubs = '^ ! '; - var expected = '------# '; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with never and error', function () { - var a = cold( '-'); - var asubs = '^ !'; - var b = hot('------#'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and never', function () { - var a = hot('------#'); - var asubs = '^ !'; - var b = cold( '-'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and error', function () { - var a = hot('------#', null, 'too bad'); - var asubs = '^ !'; - var b = hot('----------#', null, 'too bad 2'); - var bsubs = '^ !'; - var expected = '------#'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected, null, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two sources that eventually raise errors', function () { - var a = hot('--w-----#----', { w: 1 }, 'too bad'); - var asubs = '^ !'; - var b = hot('-----z-----#-', { z: 2 }, 'too bad 2'); - var bsubs = '^ !'; - var expected = '-----x--#'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected, { x: [1, 2] }, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with two sources that eventually raise errors (swapped)', function () { - var a = hot('-----z-----#-', { z: 2 }, 'too bad 2'); - var asubs = '^ !'; - var b = hot('--w-----#----', { w: 1 }, 'too bad'); - var bsubs = '^ !'; - var expected = '-----x--#'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected, { x: [2, 1] }, 'too bad'); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should work with error and some', function () { - var a = cold( '#'); - var asubs = '(^!)'; - var b = hot( '--1--2--3--'); - var bsubs = '(^!)'; - var expected = '#'; - - expectObservable(Observable.of(a, b).zipAll()).toBe(expected); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); - - it('should combine two immediately-scheduled observables', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8, queueScheduler); - var r = [[1, 4], [2, 5], [3, 6]]; - var i = 0; - - var result = Observable.of(a, b, queueScheduler).zipAll(); - - result.subscribe(function (vals) { - expect(vals).toDeepEqual(r[i++]); - }, null, done); - }); - - it('should combine a source with an immediately-scheduled source', function (done) { - var a = Observable.of(1, 2, 3, queueScheduler); - var b = Observable.of(4, 5, 6, 7, 8); - var r = [[1, 4], [2, 5], [3, 6]]; - var i = 0; - - var result = Observable.of(a, b, queueScheduler).zipAll(); - - result.subscribe(function (vals) { - expect(vals).toDeepEqual(r[i++]); - }, null, done); - }); - - it('should not break unsubscription chain when unsubscribed explicitly', function () { - var a = hot('---1---2---3---|'); - var unsub = ' !'; - var asubs = '^ !'; - var b = hot('--4--5--6--7--8--|'); - var bsubs = '^ !'; - var expected = '---x---y--'; - var values = { x: ['1', '4'], y: ['2', '5']}; - - var r = Observable.of(a, b) - .mergeMap(function (x) { return Observable.of(x); }) - .zipAll() - .mergeMap(function (x) { return Observable.of(x); }); - - expectObservable(r, unsub).toBe(expected, values); - expectSubscriptions(a.subscriptions).toBe(asubs); - expectSubscriptions(b.subscriptions).toBe(bsubs); - }); -}); diff --git a/spec/operators/zipAll-spec.ts b/spec/operators/zipAll-spec.ts new file mode 100644 index 0000000000..3f49f9466d --- /dev/null +++ b/spec/operators/zipAll-spec.ts @@ -0,0 +1,719 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; + +declare const Symbol: any; +const Observable = Rx.Observable; +const queueScheduler = Rx.Scheduler.queue; + +describe('Observable.prototype.zipAll', () => { + asDiagram('zipAll')('should combine paired events from two observables', () => { + const x = cold( '-a-----b-|'); + const y = cold( '--1-2-----'); + const outer = hot('-x----y--------| ', { x: x, y: y }); + const expected = '-----------------A----B-|'; + + const result = outer.zipAll((a: string, b: string) => String(a) + String(b)); + + expectObservable(result).toBe(expected, { A: 'a1', B: 'b2' }); + }); + + it('should combine two observables', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + const values = { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should take all observables from the source and zip them', (done: DoneSignature) => { + const expected = ['a1', 'b2', 'c3']; + let i = 0; + Observable.of( + Observable.of('a','b','c'), + Observable.of(1,2,3) + ) + .zipAll((a: any, b: any) => a + b) + .subscribe((x: any) => { + expect(x).toBe(expected[i++]); + }, null, done); + }); + + it('should end once one observable completes and its buffer is empty', () => { + const e1 = hot('---a--b--c--| '); + const e1subs = '^ ! '; + const e2 = hot('------d----e----f--------| '); + const e2subs = '^ ! '; + const e3 = hot('--------h----i----j---------'); // doesn't complete + const e3subs = '^ ! '; + const expected = '--------x----y----(z|) '; // e1 complete and buffer empty + const values = { + x: ['a','d','h'], + y: ['b','e','i'], + z: ['c','f','j'] + }; + + expectObservable(Observable.of(e1,e2,e3).zipAll()).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + it('should end once one observable nexts and zips value from completed other ' + + 'observable whose buffer is empty', () => { + const e1 = hot('---a--b--c--| '); + const e1subs = '^ ! '; + const e2 = hot('------d----e----f| '); + const e2subs = '^ ! '; + const e3 = hot('--------h----i----j-------'); // doesn't complete + const e3subs = '^ ! '; + const expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete + const values = { + x: ['a','d','h'], + y: ['b','e','i'], + z: ['c','f','j'] + }; + + expectObservable(Observable.of(e1,e2,e3).zipAll()).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + expectSubscriptions(e2.subscriptions).toBe(e2subs); + expectSubscriptions(e3.subscriptions).toBe(e3subs); + }); + + describe('with iterables', () => { + it('should zip them with values', () => { + const myIterator = { + count: 0, + next: function () { + return { value: this.count++, done: false }; + } + }; + myIterator[Symbol.iterator] = function () { return this; }; + + const e1 = hot('---a---b---c---d---|'); + const e1subs = '^ !'; + const expected = '---w---x---y---z---|'; + + const values = { + w: ['a', 0], + x: ['b', 1], + y: ['c', 2], + z: ['d', 3] + }; + + expectObservable(Observable.of(e1, myIterator).zipAll()).toBe(expected, values); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should only call `next` as needed', () => { + let nextCalled = 0; + const myIterator = { + count: 0, + next: function () { + nextCalled++; + return { value: this.count++, done: false }; + } + }; + myIterator[Symbol.iterator] = function () { return this; }; + + Observable.of(Observable.of(1,2,3), myIterator).zipAll() + .subscribe(); + + // since zip will call `next()` in advance, total calls when + // zipped with 3 other values should be 4. + expect(nextCalled).toBe(4); + }); + + it('should work with never observable and empty iterable', () => { + const a = cold( '-'); + const asubs = '^'; + const b = []; + const expected = '-'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with empty observable and empty iterable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const b = []; + const expected = '|'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with empty observable and non-empty iterable', () => { + const a = cold('|'); + const asubs = '(^!)'; + const b = [1]; + const expected = '|'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and empty iterable', () => { + const a = hot('---^----a--|'); + const asubs = '^ !'; + const b = []; + const expected = '--------|'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with never observable and non-empty iterable', () => { + const a = cold('-'); + const asubs = '^'; + const b = [1]; + const expected = '-'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and non-empty iterable', () => { + const a = hot('---^----1--|'); + const asubs = '^ ! '; + const b = [2]; + const expected = '-----(x|)'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected, { x: ['1', 2] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and empty iterable', () => { + const a = hot('---^----#'); + const asubs = '^ !'; + const b = []; + const expected = '-----#'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with observable which raises error and non-empty iterable', () => { + const a = hot('---^----#'); + const asubs = '^ !'; + const b = [1]; + const expected = '-----#'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty many observable and non-empty many iterable', () => { + const a = hot('---^--1--2--3--|'); + const asubs = '^ ! '; + const b = [4, 5, 6]; + const expected = '---x--y--(z|)'; + + expectObservable(Observable.of(a,b).zipAll()).toBe(expected, + { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + + it('should work with non-empty observable and non-empty iterable selector that throws', () => { + const a = hot('---^--1--2--3--|'); + const asubs = '^ !'; + const b = [4, 5, 6]; + const expected = '---x--#'; + + const selector = function (x, y) { + if (y === 5) { + throw new Error('too bad'); + } else { + return x + y; + }}; + expectObservable(Observable.of(a,b).zipAll(selector)).toBe(expected, + { x: '14' }, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(asubs); + }); + }); + + it('should combine two observables and selector', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + + expectObservable(Observable.of(a, b).zipAll((e1: string, e2: string) => e1 + e2)) + .toBe(expected, { x: '14', y: '25', z: '36' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + expectObservable(Observable.of(a, b, c).zipAll()).toBe(expected, + { x: ['1','2','3'], y: ['4','5','6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric selector', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + const observable = Observable.of(a, b, c).zipAll((r0, r1, r2) => [r0, r1, r2]); + expectObservable(observable).toBe(expected, + { x: ['1','2','3'], y: ['4','5','6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with n-ary symmetric array selector', () => { + const a = hot('---1-^-1----4----|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--5----| '); + const bsubs = '^ ! '; + const c = hot('---1-^---3---6-| '); + const expected = '----x---y-| '; + + const observable = Observable.of(a, b, c).zipAll((r0, r1, r2) => [r0, r1, r2]); + expectObservable(observable).toBe(expected, + { x: ['1','2','3'], y: ['4','5','6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data asymmetric 1', () => { + const a = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); + const asubs = '^ ! '; + const b = hot('---1-^--2--4--6--8--0--| '); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e--| '; + + expectObservable(Observable.of(a, b).zipAll((r1: string, r2: string) => r1 + r2)) + .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data asymmetric 2', () => { + const a = hot('---1-^--2--4--6--8--0--| '); + const asubs = '^ ! '; + const b = hot('---1-^-1-3-5-7-9-x-y-z-w-u-|'); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e--| '; + + expectObservable(Observable.of(a, b).zipAll((r1: string, r2: string) => r1 + r2)) + .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with some data symmetric', () => { + const a = hot('---1-^-1-3-5-7-9------| '); + const asubs = '^ ! '; + const b = hot('---1-^--2--4--6--8--0--|'); + const bsubs = '^ ! '; + const expected = '---a--b--c--d--e-| '; + + expectObservable(Observable.of(a, b).zipAll((r1: string, r2: string) => r1 + r2)) + .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with selector throws', () => { + const a = hot('---1-^-2---4----| '); + const asubs = '^ ! '; + const b = hot('---1-^--3----5----|'); + const bsubs = '^ ! '; + const expected = '---x----# '; + + const selector = function (x, y) { + if (y === '5') { + throw new Error('too bad'); + } else { + return x + y; + }}; + const observable = Observable.of(a, b).zipAll(selector); + expectObservable(observable).toBe(expected, + { x: '23' }, new Error('too bad')); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with right completes first', () => { + const a = hot('---1-^-2-----|'); + const asubs = '^ !'; + const b = hot('---1-^--3--|'); + const bsubs = '^ !'; + const expected = '---x--|'; + + expectObservable(Observable.zip(a, b)).toBe(expected, { x: ['2', '3'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should zip until one child terminates', (done: DoneSignature) => { + const expected = ['a1', 'b2']; + let i = 0; + Observable.of( + Observable.of('a','b','c'), + Observable.of(1,2) + ) + .zipAll((a: any, b: any) => a + b) + .subscribe((x: any) => { + expect(x).toBe(expected[i++]); + }, null, done); + }); + + it('should handle a hot observable of observables', () => { + const x = cold( 'a---b---c---| '); + const xsubs = ' ^ !'; + const y = cold( 'd---e---f---| '); + const ysubs = ' ^ !'; + const e1 = hot('--x--y--| ', { x: x, y: y }); + const e1subs = '^ !'; + const expected = '--------u---v---w---|'; + const values = { + u: ['a', 'd'], + v: ['b', 'e'], + w: ['c', 'f'] + }; + + expectObservable(e1.zipAll()).toBe(expected, values); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should handle merging a hot observable of non-overlapped observables', () => { + const x = cold( 'a-b---------| '); + const xsubs = ' ^ !'; + const y = cold( 'c-d-e-f-| '); + const ysubs = ' ^ ! '; + const z = cold( 'g-h-i-j-k-| '); + const zsubs = ' ^ ! '; + const e1 = hot('--x------y--------z--------| ', { x: x, y: y, z: z }); + const e1subs = '^ !'; + const expected = '---------------------------u-v---------|'; + const values = { + u: ['a', 'c', 'g'], + v: ['b', 'd', 'h'] + }; + + expectObservable(e1.zipAll()).toBe(expected, values); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if inner observable raises error', () => { + const x = cold( 'a-b---------| '); + const xsubs = ' ^ !'; + const y = cold( 'c-d-e-f-# '); + const ysubs = ' ^ !'; + const z = cold( 'g-h-i-j-k-| '); + const zsubs = ' ^ !'; + const e1 = hot('--x---------y--------z--------|', { x: x, y: y, z: z }); + const e1subs = '^ !'; + const expected = '------------------------------u-v-----#'; + + const expectedValues = { + u: ['a', 'c', 'g'], + v: ['b', 'd', 'h'] + }; + + expectObservable(e1.zipAll()).toBe(expected, expectedValues); + expectSubscriptions(x.subscriptions).toBe(xsubs); + expectSubscriptions(y.subscriptions).toBe(ysubs); + expectSubscriptions(z.subscriptions).toBe(zsubs); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should raise error if outer observable raises error', () => { + const y = cold( 'a-b---------|'); + const z = cold( 'c-d-e-f-|'); + const e1 = hot('--y---------z---#', { y: y, z: z }); + const e1subs = '^ !'; + const expected = '----------------#'; + + expectObservable(e1.zipAll()).toBe(expected); + expectSubscriptions(e1.subscriptions).toBe(e1subs); + }); + + it('should work with two nevers', () => { + const a = cold( '-'); + const asubs = '^'; + const b = cold( '-'); + const bsubs = '^'; + const expected = '-'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and empty', () => { + const a = cold( '-'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and never', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = cold( '-'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and empty', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and non-empty', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = hot( '---1--|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with non-empty and empty', () => { + const a = hot( '---1--|'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and non-empty', () => { + const a = cold( '-'); + const asubs = '^'; + const b = hot( '---1--|'); + const bsubs = '^ !'; + const expected = '-'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with non-empty and never', () => { + const a = hot( '---1--|'); + const asubs = '^ !'; + const b = cold( '-'); + const bsubs = '^'; + const expected = '-'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should combine a source with a second', () => { + const a = hot('---1---2---3---'); + const asubs = '^'; + const b = hot('--4--5--6--7--8--'); + const bsubs = '^'; + const expected = '---x---y---z'; + + expectObservable(Observable.of(a, b).zipAll()) + .toBe(expected, { x: ['1', '4'], y: ['2', '5'], z: ['3', '6'] }); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with empty and error', () => { + const a = cold( '|'); + const asubs = '(^!)'; + const b = hot( '------#', null, 'too bad'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and empty', () => { + const a = hot( '------#', null, 'too bad'); + const asubs = '(^!)'; + const b = cold( '|'); + const bsubs = '(^!)'; + const expected = '|'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error', () => { + const a = hot('----------|'); + const asubs = '^ ! '; + const b = hot('------# '); + const bsubs = '^ ! '; + const expected = '------# '; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with never and error', () => { + const a = cold( '-'); + const asubs = '^ !'; + const b = hot('------#'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and never', () => { + const a = hot('------#'); + const asubs = '^ !'; + const b = cold( '-'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and error', () => { + const a = hot('------#', null, 'too bad'); + const asubs = '^ !'; + const b = hot('----------#', null, 'too bad 2'); + const bsubs = '^ !'; + const expected = '------#'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected, null, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two sources that eventually raise errors', () => { + const a = hot('--w-----#----', { w: 1 }, 'too bad'); + const asubs = '^ !'; + const b = hot('-----z-----#-', { z: 2 }, 'too bad 2'); + const bsubs = '^ !'; + const expected = '-----x--#'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected, { x: [1, 2] }, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with two sources that eventually raise errors (swapped)', () => { + const a = hot('-----z-----#-', { z: 2 }, 'too bad 2'); + const asubs = '^ !'; + const b = hot('--w-----#----', { w: 1 }, 'too bad'); + const bsubs = '^ !'; + const expected = '-----x--#'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected, { x: [2, 1] }, 'too bad'); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should work with error and some', () => { + const a = cold( '#'); + const asubs = '(^!)'; + const b = hot( '--1--2--3--'); + const bsubs = '(^!)'; + const expected = '#'; + + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); + + it('should combine two immediately-scheduled observables', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8, queueScheduler); + const r = [[1, 4], [2, 5], [3, 6]]; + let i = 0; + + const result = Observable.of(a, b, queueScheduler).zipAll(); + + result.subscribe((vals: any) => { + (expect(vals)).toDeepEqual(r[i++]); + }, null, done); + }); + + it('should combine a source with an immediately-scheduled source', (done: DoneSignature) => { + const a = Observable.of(1, 2, 3, queueScheduler); + const b = Observable.of(4, 5, 6, 7, 8); + const r = [[1, 4], [2, 5], [3, 6]]; + let i = 0; + + const result = Observable.of(a, b, queueScheduler).zipAll(); + + result.subscribe((vals: any) => { + (expect(vals)).toDeepEqual(r[i++]); + }, null, done); + }); + + it('should not break unsubscription chain when unsubscribed explicitly', () => { + const a = hot('---1---2---3---|'); + const unsub = ' !'; + const asubs = '^ !'; + const b = hot('--4--5--6--7--8--|'); + const bsubs = '^ !'; + const expected = '---x---y--'; + const values = { x: ['1', '4'], y: ['2', '5']}; + + const r = Observable.of(a, b) + .mergeMap((x: string) => Observable.of(x)) + .zipAll() + .mergeMap((x: any) => Observable.of(x)); + + expectObservable(r, unsub).toBe(expected, values); + expectSubscriptions(a.subscriptions).toBe(asubs); + expectSubscriptions(b.subscriptions).toBe(bsubs); + }); +}); diff --git a/spec/root-module-spec.js b/spec/root-module-spec.js deleted file mode 100644 index 65d5c8bb07..0000000000 --- a/spec/root-module-spec.js +++ /dev/null @@ -1,8 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../index'); - -describe('Root Module', function () { - it('should contain exports from commonjs modules', function () { - expect(typeof Rx.Observable).toBe('function'); - }); -}); diff --git a/spec/root-module-spec.ts b/spec/root-module-spec.ts new file mode 100644 index 0000000000..2c0b3b3e09 --- /dev/null +++ b/spec/root-module-spec.ts @@ -0,0 +1,8 @@ +import * as Rx from '../dist/cjs/Rx'; +import {it} from './helpers/test-helper'; + +describe('Root Module', () => { + it('should contain exports from commonjs modules', () => { + expect(typeof Rx.Observable).toBe('function'); + }); +}); diff --git a/spec/schedulers/AsapScheduler-spec.js b/spec/schedulers/AsapScheduler-spec.js deleted file mode 100644 index 4db18eece5..0000000000 --- a/spec/schedulers/AsapScheduler-spec.js +++ /dev/null @@ -1,47 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, rxTestScheduler, hot, cold */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var asap = Rx.Scheduler.asap; -var Notification = Rx.Notification; - -describe('AsapScheduler', function () { - it('should exist', function () { - expect(asap).toBeDefined(); - }); - - it('should schedule an action to happen later', function (done) { - var actionHappened = false; - asap.schedule(function () { - actionHappened = true; - done(); - }); - if (actionHappened) { - done.fail('Scheduled action happened synchronously'); - } - }); - - it('should execute the rest of the scheduled actions if the first action is canceled', function (done) { - var actionHappened = false; - var firstSubscription = null; - var secondSubscription = null; - - firstSubscription = asap.schedule(function () { - actionHappened = true; - if (secondSubscription) { - secondSubscription.unsubscribe(); - } - done.fail('The first action should not have executed.'); - }); - - secondSubscription = asap.schedule(function () { - if (!actionHappened) { - done(); - } - }); - - if (actionHappened) { - done.fail('Scheduled action happened synchronously'); - } else { - firstSubscription.unsubscribe(); - } - }); -}); diff --git a/spec/schedulers/AsapScheduler-spec.ts b/spec/schedulers/AsapScheduler-spec.ts new file mode 100644 index 0000000000..35e32b86e8 --- /dev/null +++ b/spec/schedulers/AsapScheduler-spec.ts @@ -0,0 +1,47 @@ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const asap = Rx.Scheduler.asap; + +describe('AsapScheduler', () => { + it('should exist', () => { + expect(asap).toBeDefined(); + }); + + it('should schedule an action to happen later', (done: DoneSignature) => { + let actionHappened = false; + asap.schedule(() => { + actionHappened = true; + done(); + }); + if (actionHappened) { + done.fail('Scheduled action happened synchronously'); + } + }); + + it('should execute the rest of the scheduled actions if the first action is canceled', (done: DoneSignature) => { + let actionHappened = false; + let firstSubscription = null; + let secondSubscription = null; + + firstSubscription = asap.schedule(() => { + actionHappened = true; + if (secondSubscription) { + secondSubscription.unsubscribe(); + } + done.fail('The first action should not have executed.'); + }); + + secondSubscription = asap.schedule(() => { + if (!actionHappened) { + done(); + } + }); + + if (actionHappened) { + done.fail('Scheduled action happened synchronously'); + } else { + firstSubscription.unsubscribe(); + } + }); +}); diff --git a/spec/schedulers/TestScheduler-spec.js b/spec/schedulers/TestScheduler-spec.js deleted file mode 100644 index fe19ca7dc3..0000000000 --- a/spec/schedulers/TestScheduler-spec.js +++ /dev/null @@ -1,255 +0,0 @@ -/* globals describe, it, expect, expectObservable, expectSubscriptions, rxTestScheduler, hot, cold */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var TestScheduler = Rx.TestScheduler; -var Notification = Rx.Notification; - -describe('TestScheduler', function () { - it('should exist', function () { - expect(TestScheduler).toBeDefined(); - expect(typeof TestScheduler).toBe('function'); - }); - - describe('parseMarbles()', function () { - it('should parse a marble string into a series of notifications and types', function () { - var result = TestScheduler.parseMarbles('-------a---b---|', { a: 'A', b: 'B' }); - expect(result).toDeepEqual([ - { frame: 70, notification: Notification.createNext('A') }, - { frame: 110, notification: Notification.createNext('B') }, - { frame: 150, notification: Notification.createComplete() } - ]); - }); - - it('should parse a marble string, allowing spaces too', function () { - var result = TestScheduler.parseMarbles('--a--b--| ', { a: 'A', b: 'B' }); - expect(result).toDeepEqual([ - { frame: 20, notification: Notification.createNext('A') }, - { frame: 50, notification: Notification.createNext('B') }, - { frame: 80, notification: Notification.createComplete() } - ]); - }); - - it('should parse a marble string with a subscription point', function () { - var result = TestScheduler.parseMarbles('---^---a---b---|', { a: 'A', b: 'B' }); - expect(result).toDeepEqual([ - { frame: 40, notification: Notification.createNext('A') }, - { frame: 80, notification: Notification.createNext('B') }, - { frame: 120, notification: Notification.createComplete() } - ]); - }); - - it('should parse a marble string with an error', function () { - var result = TestScheduler.parseMarbles('-------a---b---#', { a: 'A', b: 'B' }, 'omg error!'); - expect(result).toDeepEqual([ - { frame: 70, notification: Notification.createNext('A') }, - { frame: 110, notification: Notification.createNext('B') }, - { frame: 150, notification: Notification.createError('omg error!') } - ]); - }); - - it('should default in the letter for the value if no value hash was passed', function () { - var result = TestScheduler.parseMarbles('--a--b--c--'); - expect(result).toDeepEqual([ - { frame: 20, notification: Notification.createNext('a') }, - { frame: 50, notification: Notification.createNext('b') }, - { frame: 80, notification: Notification.createNext('c') }, - ]); - }); - - it('should handle grouped values', function () { - var result = TestScheduler.parseMarbles('---(abc)---'); - expect(result).toDeepEqual([ - { frame: 30, notification: Notification.createNext('a') }, - { frame: 30, notification: Notification.createNext('b') }, - { frame: 30, notification: Notification.createNext('c') } - ]); - }); - }); - - describe('parseMarblesAsSubscriptions()', function () { - it('should parse a subscription marble string into a subscriptionLog', function () { - var result = TestScheduler.parseMarblesAsSubscriptions('---^---!-'); - expect(result.subscribedFrame).toEqual(30); - expect(result.unsubscribedFrame).toEqual(70); - }); - - it('should parse a subscription marble string with an unsubscription', function () { - var result = TestScheduler.parseMarblesAsSubscriptions('---^-'); - expect(result.subscribedFrame).toEqual(30); - expect(result.unsubscribedFrame).toEqual(Number.POSITIVE_INFINITY); - }); - - it('should parse a subscription marble string with a synchronous unsubscription', function () { - var result = TestScheduler.parseMarblesAsSubscriptions('---(^!)-'); - expect(result.subscribedFrame).toEqual(30); - expect(result.unsubscribedFrame).toEqual(30); - }); - }); - - describe('createTime()', function () { - it('should parse a simple time marble string to a number', function () { - var scheduler = new TestScheduler(); - var time = scheduler.createTime('-----|'); - expect(time).toBe(50); - }); - - it('should throw if not given good marble input', function () { - var scheduler = new TestScheduler(); - expect(function () { - var time = scheduler.createTime('-a-b-#'); - }).toThrow(); - }); - }); - - describe('createColdObservable()', function () { - it('should create a cold observable', function () { - var expected = ['A', 'B']; - var scheduler = new TestScheduler(); - var source = scheduler.createColdObservable('--a---b--|', { a: 'A', b: 'B' }); - expect(source instanceof Rx.Observable).toBe(true); - source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }); - scheduler.flush(); - expect(expected.length).toBe(0); - }); - }); - - describe('createHotObservable()', function () { - it('should create a cold observable', function () { - var expected = ['A', 'B']; - var scheduler = new TestScheduler(); - var source = scheduler.createHotObservable('--a---b--|', { a: 'A', b: 'B' }); - expect(source instanceof Rx.Subject).toBe(true); - source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }); - scheduler.flush(); - expect(expected.length).toBe(0); - }); - }); - - describe('jasmine helpers', function () { - describe('rxTestScheduler', function () { - it('should exist', function () { - expect(rxTestScheduler instanceof Rx.TestScheduler).toBe(true); - }); - }); - - describe('cold()', function () { - it('should exist', function () { - expect(cold).toBeDefined(); - expect(typeof cold).toBe('function'); - }); - - it('should create a cold observable', function () { - var expected = [1, 2]; - var source = cold('-a-b-|', { a: 1, b: 2 }); - source.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, function () { - expect(expected.length).toBe(0); - }); - expectObservable(source).toBe('-a-b-|', { a: 1, b: 2 }); - }); - }); - - describe('hot()', function () { - it('should exist', function () { - expect(hot).toBeDefined(); - expect(typeof hot).toBe('function'); - }); - - it('should create a hot observable', function () { - var source = hot('---^-a-b-|', { a: 1, b: 2 }); - expect(source instanceof Rx.Subject).toBe(true); - expectObservable(source).toBe('--a-b-|', { a: 1, b: 2 }); - }); - }); - - describe('time()', function () { - it('should exist', function () { - expect(time).toBeDefined(); - expect(typeof time).toBe('function'); - }); - - it('should parse a simple time marble string to a number', function () { - expect(time('-----|')).toBe(50); - }); - }); - - describe('expectObservable()', function () { - it('should exist', function () { - expect(expectObservable).toBeDefined(); - expect(typeof expectObservable).toBe('function'); - }); - - it('should return an object with a toBe function', function () { - expect(typeof (expectObservable(Rx.Observable.of(1)).toBe)).toBe('function'); - }); - - it('should append to flushTests array', function () { - expectObservable(Rx.Observable.empty()); - expect(rxTestScheduler.flushTests.length).toBe(1); - }); - - it('should handle empty', function () { - expectObservable(Rx.Observable.empty()).toBe('|', {}); - }); - - it('should handle never', function () { - expectObservable(Rx.Observable.never()).toBe('-', {}); - expectObservable(Rx.Observable.never()).toBe('---', {}); - }); - - it('should accept an unsubscription marble diagram', function () { - var source = hot('---^-a-b-|'); - var unsubscribe = '---!'; - var expected = '--a'; - expectObservable(source, unsubscribe).toBe(expected); - }); - }); - - describe('expectSubscriptions()', function () { - it('should exist', function () { - expect(expectSubscriptions).toBeDefined(); - expect(typeof expectSubscriptions).toBe('function'); - }); - - it('should return an object with a toBe function', function () { - expect(typeof (expectSubscriptions([]).toBe)).toBe('function'); - }); - - it('should append to flushTests array', function () { - expectSubscriptions([]); - expect(rxTestScheduler.flushTests.length).toBe(1); - }); - - it('should assert subscriptions of a cold observable', function () { - var source = cold('---a---b-|'); - var subs = '^--------!'; - expectSubscriptions(source.subscriptions).toBe(subs); - source.subscribe(); - }); - }); - - describe('end-to-end helper tests', function () { - it('should be awesome', function () { - var values = { a: 1, b: 2 }; - var myObservable = cold('---a---b--|', values); - var subs = '^---------!'; - expectObservable(myObservable).toBe('---a---b--|', values); - expectSubscriptions(myObservable.subscriptions).toBe(subs); - }); - - it('should support testing metastreams', function () { - var x = cold('-a-b|'); - var y = cold('-c-d|'); - var myObservable = hot('---x---y----|', { x: x, y: y }); - var expected = '---x---y----|'; - var expectedx = cold('-a-b|'); - var expectedy = cold('-c-d|'); - expectObservable(myObservable).toBe(expected, { x: expectedx, y: expectedy }); - }); - }); - }); -}); diff --git a/spec/schedulers/TestScheduler-spec.ts b/spec/schedulers/TestScheduler-spec.ts new file mode 100644 index 0000000000..bb2347bd75 --- /dev/null +++ b/spec/schedulers/TestScheduler-spec.ts @@ -0,0 +1,259 @@ +/* globals describe, it, expect, expectObservable, expectSubscriptions, rxTestScheduler, hot, cold */ +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; + +declare const rxTestScheduler: Rx.TestScheduler; +const Notification = Rx.Notification; +const TestScheduler = Rx.TestScheduler; + +describe('TestScheduler', () => { + it('should exist', () => { + expect(TestScheduler).toBeDefined(); + expect(typeof TestScheduler).toBe('function'); + }); + + describe('parseMarbles()', () => { + it('should parse a marble string into a series of notifications and types', () => { + const result = TestScheduler.parseMarbles('-------a---b---|', { a: 'A', b: 'B' }); + (expect(result)).toDeepEqual([ + { frame: 70, notification: Notification.createNext('A') }, + { frame: 110, notification: Notification.createNext('B') }, + { frame: 150, notification: Notification.createComplete() } + ]); + }); + + it('should parse a marble string, allowing spaces too', () => { + const result = TestScheduler.parseMarbles('--a--b--| ', { a: 'A', b: 'B' }); + (expect(result)).toDeepEqual([ + { frame: 20, notification: Notification.createNext('A') }, + { frame: 50, notification: Notification.createNext('B') }, + { frame: 80, notification: Notification.createComplete() } + ]); + }); + + it('should parse a marble string with a subscription point', () => { + const result = TestScheduler.parseMarbles('---^---a---b---|', { a: 'A', b: 'B' }); + (expect(result)).toDeepEqual([ + { frame: 40, notification: Notification.createNext('A') }, + { frame: 80, notification: Notification.createNext('B') }, + { frame: 120, notification: Notification.createComplete() } + ]); + }); + + it('should parse a marble string with an error', () => { + const result = TestScheduler.parseMarbles('-------a---b---#', { a: 'A', b: 'B' }, 'omg error!'); + (expect(result)).toDeepEqual([ + { frame: 70, notification: Notification.createNext('A') }, + { frame: 110, notification: Notification.createNext('B') }, + { frame: 150, notification: Notification.createError('omg error!') } + ]); + }); + + it('should default in the letter for the value if no value hash was passed', () => { + const result = TestScheduler.parseMarbles('--a--b--c--'); + (expect(result)).toDeepEqual([ + { frame: 20, notification: Notification.createNext('a') }, + { frame: 50, notification: Notification.createNext('b') }, + { frame: 80, notification: Notification.createNext('c') }, + ]); + }); + + it('should handle grouped values', () => { + const result = TestScheduler.parseMarbles('---(abc)---'); + (expect(result)).toDeepEqual([ + { frame: 30, notification: Notification.createNext('a') }, + { frame: 30, notification: Notification.createNext('b') }, + { frame: 30, notification: Notification.createNext('c') } + ]); + }); + }); + + describe('parseMarblesAsSubscriptions()', () => { + it('should parse a subscription marble string into a subscriptionLog', () => { + const result = TestScheduler.parseMarblesAsSubscriptions('---^---!-'); + expect(result.subscribedFrame).toEqual(30); + expect(result.unsubscribedFrame).toEqual(70); + }); + + it('should parse a subscription marble string with an unsubscription', () => { + const result = TestScheduler.parseMarblesAsSubscriptions('---^-'); + expect(result.subscribedFrame).toEqual(30); + expect(result.unsubscribedFrame).toEqual(Number.POSITIVE_INFINITY); + }); + + it('should parse a subscription marble string with a synchronous unsubscription', () => { + const result = TestScheduler.parseMarblesAsSubscriptions('---(^!)-'); + expect(result.subscribedFrame).toEqual(30); + expect(result.unsubscribedFrame).toEqual(30); + }); + }); + + describe('createTime()', () => { + it('should parse a simple time marble string to a number', () => { + const scheduler = new TestScheduler(null); + const time = scheduler.createTime('-----|'); + expect(time).toBe(50); + }); + + it('should throw if not given good marble input', () => { + const scheduler = new TestScheduler(null); + expect(() => { + scheduler.createTime('-a-b-#'); + }).toThrow(); + }); + }); + + describe('createColdObservable()', () => { + it('should create a cold observable', () => { + const expected = ['A', 'B']; + const scheduler = new TestScheduler(null); + const source = scheduler.createColdObservable('--a---b--|', { a: 'A', b: 'B' }); + expect(source instanceof Rx.Observable).toBe(true); + source.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }); + scheduler.flush(); + expect(expected.length).toBe(0); + }); + }); + + describe('createHotObservable()', () => { + it('should create a cold observable', () => { + const expected = ['A', 'B']; + const scheduler = new TestScheduler(null); + const source = scheduler.createHotObservable('--a---b--|', { a: 'A', b: 'B' }); + expect(source instanceof Rx.Subject).toBe(true); + source.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }); + scheduler.flush(); + expect(expected.length).toBe(0); + }); + }); + + describe('jasmine helpers', () => { + describe('rxTestScheduler', () => { + it('should exist', () => { + expect(rxTestScheduler instanceof TestScheduler).toBe(true); + }); + }); + + describe('cold()', () => { + it('should exist', () => { + expect(cold).toBeDefined(); + expect(typeof cold).toBe('function'); + }); + + it('should create a cold observable', () => { + const expected = [1, 2]; + const source = cold('-a-b-|', { a: 1, b: 2 }); + source.subscribe((x: number) => { + expect(x).toBe(expected.shift()); + }, null, () => { + expect(expected.length).toBe(0); + }); + expectObservable(source).toBe('-a-b-|', { a: 1, b: 2 }); + }); + }); + + describe('hot()', () => { + it('should exist', () => { + expect(hot).toBeDefined(); + expect(typeof hot).toBe('function'); + }); + + it('should create a hot observable', () => { + const source = hot('---^-a-b-|', { a: 1, b: 2 }); + expect(source instanceof Rx.Subject).toBe(true); + expectObservable(source).toBe('--a-b-|', { a: 1, b: 2 }); + }); + }); + + describe('time()', () => { + it('should exist', () => { + expect(time).toBeDefined(); + expect(typeof time).toBe('function'); + }); + + it('should parse a simple time marble string to a number', () => { + expect(time('-----|')).toBe(50); + }); + }); + + describe('expectObservable()', () => { + it('should exist', () => { + expect(expectObservable).toBeDefined(); + expect(typeof expectObservable).toBe('function'); + }); + + it('should return an object with a toBe function', () => { + expect(typeof (expectObservable(Rx.Observable.of(1)).toBe)).toBe('function'); + }); + + it('should append to flushTests array', () => { + expectObservable(Rx.Observable.empty()); + expect((rxTestScheduler).flushTests.length).toBe(1); + }); + + it('should handle empty', () => { + expectObservable(Rx.Observable.empty()).toBe('|', {}); + }); + + it('should handle never', () => { + expectObservable(Rx.Observable.never()).toBe('-', {}); + expectObservable(Rx.Observable.never()).toBe('---', {}); + }); + + it('should accept an unsubscription marble diagram', () => { + const source = hot('---^-a-b-|'); + const unsubscribe = '---!'; + const expected = '--a'; + expectObservable(source, unsubscribe).toBe(expected); + }); + }); + + describe('expectSubscriptions()', () => { + it('should exist', () => { + expect(expectSubscriptions).toBeDefined(); + expect(typeof expectSubscriptions).toBe('function'); + }); + + it('should return an object with a toBe function', () => { + expect(typeof (expectSubscriptions([]).toBe)).toBe('function'); + }); + + it('should append to flushTests array', () => { + expectSubscriptions([]); + expect((rxTestScheduler).flushTests.length).toBe(1); + }); + + it('should assert subscriptions of a cold observable', () => { + const source = cold('---a---b-|'); + const subs = '^--------!'; + expectSubscriptions(source.subscriptions).toBe(subs); + source.subscribe(); + }); + }); + + describe('end-to-end helper tests', () => { + it('should be awesome', () => { + const values = { a: 1, b: 2 }; + const myObservable = cold('---a---b--|', values); + const subs = '^---------!'; + expectObservable(myObservable).toBe('---a---b--|', values); + expectSubscriptions(myObservable.subscriptions).toBe(subs); + }); + + it('should support testing metastreams', () => { + const x = cold('-a-b|'); + const y = cold('-c-d|'); + const myObservable = hot('---x---y----|', { x: x, y: y }); + const expected = '---x---y----|'; + const expectedx = cold('-a-b|'); + const expectedy = cold('-c-d|'); + expectObservable(myObservable).toBe(expected, { x: expectedx, y: expectedy }); + }); + }); + }); +}); diff --git a/spec/schedulers/VirtualTimeScheduler-spec.js b/spec/schedulers/VirtualTimeScheduler-spec.ts similarity index 63% rename from spec/schedulers/VirtualTimeScheduler-spec.js rename to spec/schedulers/VirtualTimeScheduler-spec.ts index c7f6ac3ebb..66223ea782 100644 --- a/spec/schedulers/VirtualTimeScheduler-spec.js +++ b/spec/schedulers/VirtualTimeScheduler-spec.ts @@ -1,17 +1,19 @@ /* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx.KitchenSink'); -var VirtualTimeScheduler = Rx.VirtualTimeScheduler; +import * as Rx from '../../dist/cjs/Rx.KitchenSink'; +import {it} from '../helpers/test-helper'; -describe('VirtualTimeScheduler', function () { - it('should exist', function () { +const VirtualTimeScheduler = Rx.VirtualTimeScheduler; + +describe('VirtualTimeScheduler', () => { + it('should exist', () => { expect(VirtualTimeScheduler).toBeDefined(); expect(typeof VirtualTimeScheduler).toBe('function'); }); - it('should schedule things in order when flushed if each this is scheduled synchrously', function () { - var v = new VirtualTimeScheduler(); - var invoked = []; - var invoke = function (state) { + it('should schedule things in order when flushed if each this is scheduled synchrously', () => { + const v = new VirtualTimeScheduler(); + const invoked = []; + const invoke = (state: number) => { invoked.push(state); }; v.schedule(invoke, 0, 1); @@ -25,10 +27,10 @@ describe('VirtualTimeScheduler', function () { expect(invoked).toEqual([1, 2, 3, 4, 5]); }); - it('should schedule things in order when flushed if each this is scheduled at random', function () { - var v = new VirtualTimeScheduler(); - var invoked = []; - var invoke = function (state) { + it('should schedule things in order when flushed if each this is scheduled at random', () => { + const v = new VirtualTimeScheduler(); + const invoked = []; + const invoke = (state: number) => { invoked.push(state); }; v.schedule(invoke, 0, 1); @@ -43,10 +45,10 @@ describe('VirtualTimeScheduler', function () { expect(invoked).toEqual([1, 3, 5, 2, 6, 4]); }); - it('should schedule things in order when there are negative delays', function () { - var v = new VirtualTimeScheduler(); - var invoked = []; - var invoke = function (state) { + it('should schedule things in order when there are negative delays', () => { + const v = new VirtualTimeScheduler(); + const invoked = []; + const invoke = (state: number) => { invoked.push(state); }; v.schedule(invoke, 0, 1); @@ -61,12 +63,12 @@ describe('VirtualTimeScheduler', function () { expect(invoked).toEqual([6, 4, 1, 3, 5, 2]); }); - it('should support recursive scheduling', function () { - var v = new VirtualTimeScheduler(); - var count = 0; - var expected = [100, 200, 300]; + it('should support recursive scheduling', () => { + const v = new VirtualTimeScheduler(); + let count = 0; + const expected = [100, 200, 300]; - v.schedule(function (state) { + v.schedule(function(state) { if (++count === 3) { return; } diff --git a/spec/subjects/AsyncSubject-spec.js b/spec/subjects/AsyncSubject-spec.ts similarity index 59% rename from spec/subjects/AsyncSubject-spec.js rename to spec/subjects/AsyncSubject-spec.ts index 3c8c65fb4e..0c1ca5a25d 100644 --- a/spec/subjects/AsyncSubject-spec.js +++ b/spec/subjects/AsyncSubject-spec.ts @@ -1,22 +1,28 @@ -var Rx = require('../../dist/cjs/Rx'); +import * as Rx from '../../dist/cjs/Rx'; +import {it} from '../helpers/test-helper'; -var AsyncSubject = Rx.AsyncSubject; -var Observable = Rx.Observable; +const AsyncSubject = Rx.AsyncSubject; -var TestObserver = function () { - this.results = []; -}; +class TestObserver implements Rx.Observer { + results = []; -TestObserver.prototype = { - next: function (x) { this.results.push(x); }, - error: function (err) { this.results.push(err); }, - complete: function () { this.results.push('done'); } -}; + next(value: number): void { + this.results.push(value); + } -describe('AsyncSubject', function () { - it('should emit the last value when complete', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); + error(err: any): void { + this.results.push(err); + } + + complete(): void { + this.results.push('done'); + } +} + +describe('AsyncSubject', () => { + it('should emit the last value when complete', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); subject.subscribe(observer); subject.next(1); @@ -27,9 +33,9 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual([2, 'done']); }); - it('should emit the last value when subscribing after complete', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); + it('should emit the last value when subscribing after complete', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); subject.next(1); subject.next(2); @@ -39,10 +45,10 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual([2, 'done']); }); - it('should keep emitting the last value to subsequent subscriptions', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); - var subscription = subject.subscribe(observer); + it('should keep emitting the last value to subsequent subscriptions', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); + const subscription = subject.subscribe(observer); subject.next(1); expect(observer.results).toEqual([]); @@ -58,9 +64,9 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual([2, 'done']); }); - it('should not emit values after complete', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); + it('should not emit values after complete', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); subject.subscribe(observer); @@ -72,10 +78,10 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual([2, 'done']); }); - it('should not emit values if unsubscribed before complete', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); - var subscription = subject.subscribe(observer); + it('should not emit values if unsubscribed before complete', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); + const subscription = subject.subscribe(observer); subject.next(1); expect(observer.results).toEqual([]); @@ -90,9 +96,9 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual([]); }); - it('should just complete if no value has been nexted into it', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); + it('should just complete if no value has been nexted into it', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); subject.subscribe(observer); expect(observer.results).toEqual([]); @@ -100,10 +106,10 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual(['done']); }); - it('should keep emitting complete to subsequent subscriptions', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); - var subscription = subject.subscribe(observer); + it('should keep emitting complete to subsequent subscriptions', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); + const subscription = subject.subscribe(observer); expect(observer.results).toEqual([]); subject.complete(); @@ -115,9 +121,9 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual(['done']); }); - it('should only error if an error is passed into it', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); + it('should only error if an error is passed into it', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); subject.subscribe(observer); subject.next(1); @@ -126,10 +132,10 @@ describe('AsyncSubject', function () { expect(observer.results).toEqual([new Error('bad')]); }); - it('should keep emitting error to subsequent subscriptions', function () { - var subject = new AsyncSubject(); - var observer = new TestObserver(); - var subscription = subject.subscribe(observer); + it('should keep emitting error to subsequent subscriptions', () => { + const subject = new AsyncSubject(); + const observer = new TestObserver(); + const subscription = subject.subscribe(observer); subject.next(1); expect(observer.results).toEqual([]); diff --git a/spec/subjects/BehaviorSubject-spec.js b/spec/subjects/BehaviorSubject-spec.js deleted file mode 100644 index d6259a501e..0000000000 --- a/spec/subjects/BehaviorSubject-spec.js +++ /dev/null @@ -1,179 +0,0 @@ -/* globals describe, it, expect */ -var Rx = require('../../dist/cjs/Rx'); - -var BehaviorSubject = Rx.BehaviorSubject; -var asap = Rx.Scheduler.asap; -var Observable = Rx.Observable; -var ObjectUnsubscribedError = Rx.ObjectUnsubscribedError; - -describe('BehaviorSubject', function () { - it('should extend Subject', function (done) { - var subject = new BehaviorSubject(null); - expect(subject instanceof Rx.Subject).toBe(true); - done(); - }); - - it('should throw if it has received an error and getValue() is called', function () { - var subject = new BehaviorSubject(null); - subject.error(new Error('derp')); - expect(function () { - subject.getValue(); - }).toThrow(new Error('derp')); - }); - - it('should throw an ObjectUnsubscribedError if getValue() is called ' + - 'and the BehaviorSubject has been unsubscribed', function () { - var subject = new BehaviorSubject('hi there'); - subject.unsubscribe(); - expect(function () { - subject.getValue(); - }).toThrow(new ObjectUnsubscribedError()); - }); - - it('should have a getValue() method to retrieve the current value', function () { - var subject = new BehaviorSubject('staltz'); - expect(subject.getValue()).toBe('staltz'); - - subject.next('oj'); - - expect(subject.getValue()).toBe('oj'); - }); - - it('should not allow you to set `value` directly', function () { - var subject = new BehaviorSubject('flibberty'); - subject.value = 'jibbets'; - expect(subject.getValue()).toBe('flibberty'); - expect(subject.value).toBe('flibberty'); - }); - - it('should still allow you to retrieve the value from the value property', function () { - var subject = new BehaviorSubject('fuzzy'); - expect(subject.value).toBe('fuzzy'); - subject.next('bunny'); - expect(subject.value).toBe('bunny'); - }); - - it('should start with an initialization value', function (done) { - var subject = new BehaviorSubject('foo'); - var expected = ['foo', 'bar']; - var i = 0; - - subject.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }, null, done); - - subject.next('bar'); - subject.complete(); - }); - - it('should pump values to multiple subscribers', function (done) { - var subject = new BehaviorSubject('init'); - var expected = ['init', 'foo', 'bar']; - var i = 0; - var j = 0; - - subject.subscribe(function (x) { - expect(x).toBe(expected[i++]); - }); - - subject.subscribe(function (x) { - expect(x).toBe(expected[j++]); - }, null, done); - - expect(subject.observers.length).toBe(2); - subject.next('foo'); - subject.next('bar'); - subject.complete(); - }); - - it('should not allow values to be nexted after a return', function (done) { - var subject = new BehaviorSubject('init'); - var expected = ['init', 'foo']; - - subject.subscribe(function (x) { - expect(x).toBe(expected.shift()); - }, null, done); - - subject.next('foo'); - subject.complete(); - - expect(function () { - subject.next('bar'); - }).toThrow(new Rx.ObjectUnsubscribedError()); - }); - - it('should clean out unsubscribed subscribers', function (done) { - var subject = new BehaviorSubject('init'); - - var sub1 = subject.subscribe(function (x) { - expect(x).toBe('init'); - }); - - var sub2 = subject.subscribe(function (x) { - expect(x).toBe('init'); - }); - - expect(subject.observers.length).toBe(2); - sub1.unsubscribe(); - expect(subject.observers.length).toBe(1); - sub2.unsubscribe(); - expect(subject.observers.length).toBe(0); - done(); - }); - - it('should replay the previous value when subscribed', function () { - var behaviorSubject = new BehaviorSubject('0'); - function feedNextIntoSubject(x) { behaviorSubject.next(x); } - function feedErrorIntoSubject(err) { behaviorSubject.error(err); } - function feedCompleteIntoSubject() { behaviorSubject.complete(); } - - var sourceTemplate = '-1-2-3----4------5-6---7--8----9--|'; - var subscriber1 = hot(' (a|) ').mergeMapTo(behaviorSubject); - var unsub1 = ' ! '; - var expected1 = ' 3---4------5-6-- '; - var subscriber2 = hot(' (b|) ').mergeMapTo(behaviorSubject); - var unsub2 = ' ! '; - var expected2 = ' 4----5-6---7-- '; - var subscriber3 = hot(' (c|) ').mergeMapTo(behaviorSubject); - var expected3 = ' 8---9--|'; - - expectObservable(hot(sourceTemplate).do( - feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject - )).toBe(sourceTemplate); - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - }); - - it('should emit complete when subscribed after completed', function () { - var behaviorSubject = new BehaviorSubject('0'); - function feedNextIntoSubject(x) { behaviorSubject.next(x); } - function feedErrorIntoSubject(err) { behaviorSubject.error(err); } - function feedCompleteIntoSubject() { behaviorSubject.complete(); } - - var sourceTemplate = '-1-2-3--4--|'; - var subscriber1 = hot(' (a|)').mergeMapTo(behaviorSubject); - var expected1 = ' | '; - - expectObservable(hot(sourceTemplate).do( - feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject - )).toBe(sourceTemplate); - expectObservable(subscriber1).toBe(expected1); - }); - - it('should be an Observer which can be given to Observable.subscribe', function (done) { - var source = Observable.of(1, 2, 3, 4, 5); - var subject = new BehaviorSubject(0); - var expected = [0, 1, 2, 3, 4, 5]; - - subject.subscribe( - function (x) { - expect(x).toBe(expected.shift()); - }, - done.fail, - done - ); - - source.subscribe(subject); - }); -}); \ No newline at end of file diff --git a/spec/subjects/BehaviorSubject-spec.ts b/spec/subjects/BehaviorSubject-spec.ts new file mode 100644 index 0000000000..8f7e804ee5 --- /dev/null +++ b/spec/subjects/BehaviorSubject-spec.ts @@ -0,0 +1,181 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {hot, expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +const BehaviorSubject = Rx.BehaviorSubject; +const Observable = Rx.Observable; +const ObjectUnsubscribedError = Rx.ObjectUnsubscribedError; + +describe('BehaviorSubject', () => { + it('should extend Subject', (done: DoneSignature) => { + const subject = new BehaviorSubject(null); + expect(subject instanceof Rx.Subject).toBe(true); + done(); + }); + + it('should throw if it has received an error and getValue() is called', () => { + const subject = new BehaviorSubject(null); + subject.error(new Error('derp')); + expect(() => { + subject.getValue(); + }).toThrow(new Error('derp')); + }); + + it('should throw an ObjectUnsubscribedError if getValue() is called ' + + 'and the BehaviorSubject has been unsubscribed', () => { + const subject = new BehaviorSubject('hi there'); + subject.unsubscribe(); + expect(() => { + subject.getValue(); + }).toThrow(new ObjectUnsubscribedError()); + }); + + it('should have a getValue() method to retrieve the current value', () => { + const subject = new BehaviorSubject('staltz'); + expect(subject.getValue()).toBe('staltz'); + + subject.next('oj'); + + expect(subject.getValue()).toBe('oj'); + }); + + it('should not allow you to set `value` directly', () => { + const subject = new BehaviorSubject('flibberty'); + expect(() => { + subject.value = 'jibbets'; + }).toThrow(); + expect(subject.getValue()).toBe('flibberty'); + expect(subject.value).toBe('flibberty'); + }); + + it('should still allow you to retrieve the value from the value property', () => { + const subject = new BehaviorSubject('fuzzy'); + expect(subject.value).toBe('fuzzy'); + subject.next('bunny'); + expect(subject.value).toBe('bunny'); + }); + + it('should start with an initialization value', (done: DoneSignature) => { + const subject = new BehaviorSubject('foo'); + const expected = ['foo', 'bar']; + let i = 0; + + subject.subscribe((x: string) => { + expect(x).toBe(expected[i++]); + }, null, done); + + subject.next('bar'); + subject.complete(); + }); + + it('should pump values to multiple subscribers', (done: DoneSignature) => { + const subject = new BehaviorSubject('init'); + const expected = ['init', 'foo', 'bar']; + let i = 0; + let j = 0; + + subject.subscribe((x: string) => { + expect(x).toBe(expected[i++]); + }); + + subject.subscribe((x: string) => { + expect(x).toBe(expected[j++]); + }, null, done); + + expect(subject.observers.length).toBe(2); + subject.next('foo'); + subject.next('bar'); + subject.complete(); + }); + + it('should not allow values to be nexted after a return', (done: DoneSignature) => { + const subject = new BehaviorSubject('init'); + const expected = ['init', 'foo']; + + subject.subscribe((x: string) => { + expect(x).toBe(expected.shift()); + }, null, done); + + subject.next('foo'); + subject.complete(); + + expect(() => { + subject.next('bar'); + }).toThrow(new Rx.ObjectUnsubscribedError()); + }); + + it('should clean out unsubscribed subscribers', (done: DoneSignature) => { + const subject = new BehaviorSubject('init'); + + const sub1 = subject.subscribe((x: string) => { + expect(x).toBe('init'); + }); + + const sub2 = subject.subscribe((x: string) => { + expect(x).toBe('init'); + }); + + expect(subject.observers.length).toBe(2); + sub1.unsubscribe(); + expect(subject.observers.length).toBe(1); + sub2.unsubscribe(); + expect(subject.observers.length).toBe(0); + done(); + }); + + it('should replay the previous value when subscribed', () => { + const behaviorSubject = new BehaviorSubject('0'); + function feedNextIntoSubject(x) { behaviorSubject.next(x); } + function feedErrorIntoSubject(err) { behaviorSubject.error(err); } + function feedCompleteIntoSubject() { behaviorSubject.complete(); } + + const sourceTemplate = '-1-2-3----4------5-6---7--8----9--|'; + const subscriber1 = hot(' (a|) ').mergeMapTo(behaviorSubject); + const unsub1 = ' ! '; + const expected1 = ' 3---4------5-6-- '; + const subscriber2 = hot(' (b|) ').mergeMapTo(behaviorSubject); + const unsub2 = ' ! '; + const expected2 = ' 4----5-6---7-- '; + const subscriber3 = hot(' (c|) ').mergeMapTo(behaviorSubject); + const expected3 = ' 8---9--|'; + + expectObservable(hot(sourceTemplate).do( + feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject + )).toBe(sourceTemplate); + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + }); + + it('should emit complete when subscribed after completed', () => { + const behaviorSubject = new BehaviorSubject('0'); + function feedNextIntoSubject(x) { behaviorSubject.next(x); } + function feedErrorIntoSubject(err) { behaviorSubject.error(err); } + function feedCompleteIntoSubject() { behaviorSubject.complete(); } + + const sourceTemplate = '-1-2-3--4--|'; + const subscriber1 = hot(' (a|)').mergeMapTo(behaviorSubject); + const expected1 = ' | '; + + expectObservable(hot(sourceTemplate).do( + feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject + )).toBe(sourceTemplate); + expectObservable(subscriber1).toBe(expected1); + }); + + it('should be an Observer which can be given to Observable.subscribe', (done: DoneSignature) => { + const source = Observable.of(1, 2, 3, 4, 5); + const subject = new BehaviorSubject(0); + const expected = [0, 1, 2, 3, 4, 5]; + + subject.subscribe( + (x: number) => { + expect(x).toBe(expected.shift()); + }, + done.fail, + done + ); + + source.subscribe(subject); + }); +}); \ No newline at end of file diff --git a/spec/subjects/ReplaySubject-spec.js b/spec/subjects/ReplaySubject-spec.js deleted file mode 100644 index 3a0b80a983..0000000000 --- a/spec/subjects/ReplaySubject-spec.js +++ /dev/null @@ -1,232 +0,0 @@ -/* globals describe, it, expect, expectObservable, hot, rxTestScheduler */ -var Rx = require('../../dist/cjs/Rx'); - -var ReplaySubject = Rx.ReplaySubject; -var asap = Rx.Scheduler.asap; -var Observable = Rx.Observable; - -describe('ReplaySubject', function () { - it('should extend Subject', function (done) { - var subject = new ReplaySubject(); - expect(subject instanceof Rx.Subject).toBe(true); - done(); - }); - - it('should replay values upon subscription', function (done) { - var subject = new ReplaySubject(); - var expects = [1, 2, 3]; - var i = 0; - subject.next(1); - subject.next(2); - subject.next(3); - subject.subscribe(function (x) { - expect(x).toBe(expects[i++]); - if (i === 3) { - subject.complete(); - } - }, function (e) { - done.fail('should not be called'); - }, done); - }); - - it('should replay values and complete', function (done) { - var subject = new ReplaySubject(); - var expects = [1, 2, 3]; - var i = 0; - subject.next(1); - subject.next(2); - subject.next(3); - subject.complete(); - subject.subscribe(function (x) { - expect(x).toBe(expects[i++]); - }, null, done); - }); - - it('should replay values and error', function (done) { - var subject = new ReplaySubject(); - var expects = [1, 2, 3]; - var i = 0; - subject.next(1); - subject.next(2); - subject.next(3); - subject.error('fooey'); - subject.subscribe(function (x) { - expect(x).toBe(expects[i++]); - }, function (err) { - expect(err).toBe('fooey'); - done(); - }); - }); - - it('should only replay values within its buffer size', function (done) { - var subject = new ReplaySubject(2); - var expects = [2, 3]; - var i = 0; - subject.next(1); - subject.next(2); - subject.next(3); - subject.subscribe(function (x) { - expect(x).toBe(expects[i++]); - if (i === 2) { - subject.complete(); - } - }, function (e) { - done.fail('should not be called'); - }, done); - }); - - describe('with bufferSize=2', function () { - it('should replay 2 previous values when subscribed', function () { - var replaySubject = new ReplaySubject(2); - function feedNextIntoSubject(x) { replaySubject.next(x); } - function feedErrorIntoSubject(err) { replaySubject.error(err); } - function feedCompleteIntoSubject() { replaySubject.complete(); } - - var sourceTemplate = '-1-2-3----4------5-6---7--8----9--|'; - var subscriber1 = hot(' (a|) ').mergeMapTo(replaySubject); - var unsub1 = ' ! '; - var expected1 = ' (23)4------5-6-- '; - var subscriber2 = hot(' (b|) ').mergeMapTo(replaySubject); - var unsub2 = ' ! '; - var expected2 = ' (34)-5-6---7-- '; - var subscriber3 = hot(' (c|) ').mergeMapTo(replaySubject); - var expected3 = ' (78)9--|'; - - expectObservable(hot(sourceTemplate).do( - feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject - )).toBe(sourceTemplate); - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - }); - - it('should replay 2 last values for when subscribed after completed', function () { - var replaySubject = new ReplaySubject(2); - function feedNextIntoSubject(x) { replaySubject.next(x); } - function feedErrorIntoSubject(err) { replaySubject.error(err); } - function feedCompleteIntoSubject() { replaySubject.complete(); } - - var sourceTemplate = '-1-2-3--4--|'; - var subscriber1 = hot(' (a|) ').mergeMapTo(replaySubject); - var expected1 = ' (34|)'; - - expectObservable(hot(sourceTemplate).do( - feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject - )).toBe(sourceTemplate); - expectObservable(subscriber1).toBe(expected1); - }); - - it('should handle subscribers that arrive and leave at different times, ' + - 'subject does not complete', function () { - var subject = new ReplaySubject(2); - var results1 = []; - var results2 = []; - var results3 = []; - - subject.next(1); - subject.next(2); - subject.next(3); - subject.next(4); - - var subscription1 = subject.subscribe( - function (x) { results1.push(x); }, - function (e) { results1.push('E'); }, - function () { results1.push('C'); } - ); - - subject.next(5); - - var subscription2 = subject.subscribe( - function (x) { results2.push(x); }, - function (e) { results2.push('E'); }, - function () { results2.push('C'); } - ); - - subject.next(6); - subject.next(7); - - subscription1.unsubscribe(); - - subject.next(8); - - subscription2.unsubscribe(); - - subject.next(9); - subject.next(10); - - var subscription3 = subject.subscribe( - function (x) { results3.push(x); }, - function (e) { results3.push('E'); }, - function () { results3.push('C'); } - ); - - subject.next(11); - - subscription3.unsubscribe(); - - expect(results1).toEqual([3,4,5,6,7]); - expect(results2).toEqual([4,5,6,7,8]); - expect(results3).toEqual([9,10,11]); - - subject.complete(); - }); - }); - - describe('with windowTime=40', function () { - it('should replay previous values since 40 time units ago when subscribed', function () { - var replaySubject = new ReplaySubject(Number.POSITIVE_INFINITY, 40, rxTestScheduler); - function feedNextIntoSubject(x) { replaySubject.next(x); } - function feedErrorIntoSubject(err) { replaySubject.error(err); } - function feedCompleteIntoSubject() { replaySubject.complete(); } - - var sourceTemplate = '-1-2-3----4------5-6----7-8----9--|'; - var subscriber1 = hot(' (a|) ').mergeMapTo(replaySubject); - var unsub1 = ' ! '; - var expected1 = ' (23)4------5-6-- '; - var subscriber2 = hot(' (b|) ').mergeMapTo(replaySubject); - var unsub2 = ' ! '; - var expected2 = ' 4----5-6----7- '; - var subscriber3 = hot(' (c|) ').mergeMapTo(replaySubject); - var expected3 = ' (78)9--|'; - - expectObservable(hot(sourceTemplate).do( - feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject - )).toBe(sourceTemplate); - expectObservable(subscriber1, unsub1).toBe(expected1); - expectObservable(subscriber2, unsub2).toBe(expected2); - expectObservable(subscriber3).toBe(expected3); - }); - - it('should replay last values since 40 time units ago when subscribed', function () { - var replaySubject = new ReplaySubject(Number.POSITIVE_INFINITY, 40, rxTestScheduler); - function feedNextIntoSubject(x) { replaySubject.next(x); } - function feedErrorIntoSubject(err) { replaySubject.error(err); } - function feedCompleteIntoSubject() { replaySubject.complete(); } - - var sourceTemplate = '-1-2-3----4|'; - var subscriber1 = hot(' (a|)').mergeMapTo(replaySubject); - var expected1 = ' (4|)'; - - expectObservable(hot(sourceTemplate).do( - feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject - )).toBe(sourceTemplate); - expectObservable(subscriber1).toBe(expected1); - }); - }); - - it('should be an Observer which can be given to Observable.subscribe', function (done) { - var source = Observable.of(1, 2, 3, 4, 5); - var subject = new ReplaySubject(3); - var expected = [3, 4, 5]; - - source.subscribe(subject); - - subject.subscribe( - function (x) { - expect(x).toBe(expected.shift()); - }, - done.fail, - done - ); - }); -}); \ No newline at end of file diff --git a/spec/subjects/ReplaySubject-spec.ts b/spec/subjects/ReplaySubject-spec.ts new file mode 100644 index 0000000000..17fa2fe267 --- /dev/null +++ b/spec/subjects/ReplaySubject-spec.ts @@ -0,0 +1,235 @@ +import * as Rx from '../../dist/cjs/Rx'; +import {TestScheduler} from '../../dist/cjs/testing/TestScheduler'; +import {hot, expectObservable} from '../helpers/marble-testing'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const rxTestScheduler: TestScheduler; + +const ReplaySubject = Rx.ReplaySubject; +const Observable = Rx.Observable; + +describe('ReplaySubject', () => { + it('should extend Subject', (done: DoneSignature) => { + const subject = new ReplaySubject(); + expect(subject instanceof Rx.Subject).toBe(true); + done(); + }); + + it('should replay values upon subscription', (done: DoneSignature) => { + const subject = new ReplaySubject(); + const expects = [1, 2, 3]; + let i = 0; + subject.next(1); + subject.next(2); + subject.next(3); + subject.subscribe((x: number) => { + expect(x).toBe(expects[i++]); + if (i === 3) { + subject.complete(); + } + }, (err: any) => { + done.fail('should not be called'); + }, done); + }); + + it('should replay values and complete', (done: DoneSignature) => { + const subject = new ReplaySubject(); + const expects = [1, 2, 3]; + let i = 0; + subject.next(1); + subject.next(2); + subject.next(3); + subject.complete(); + subject.subscribe((x: number) => { + expect(x).toBe(expects[i++]); + }, null, done); + }); + + it('should replay values and error', (done: DoneSignature) => { + const subject = new ReplaySubject(); + const expects = [1, 2, 3]; + let i = 0; + subject.next(1); + subject.next(2); + subject.next(3); + subject.error('fooey'); + subject.subscribe((x: number) => { + expect(x).toBe(expects[i++]); + }, (err: any) => { + expect(err).toBe('fooey'); + done(); + }); + }); + + it('should only replay values within its buffer size', (done: DoneSignature) => { + const subject = new ReplaySubject(2); + const expects = [2, 3]; + let i = 0; + subject.next(1); + subject.next(2); + subject.next(3); + subject.subscribe((x: number) => { + expect(x).toBe(expects[i++]); + if (i === 2) { + subject.complete(); + } + }, (err: any) => { + done.fail('should not be called'); + }, done); + }); + + describe('with bufferSize=2', () => { + it('should replay 2 previous values when subscribed', () => { + const replaySubject = new ReplaySubject(2); + function feedNextIntoSubject(x) { replaySubject.next(x); } + function feedErrorIntoSubject(err) { replaySubject.error(err); } + function feedCompleteIntoSubject() { replaySubject.complete(); } + + const sourceTemplate = '-1-2-3----4------5-6---7--8----9--|'; + const subscriber1 = hot(' (a|) ').mergeMapTo(replaySubject); + const unsub1 = ' ! '; + const expected1 = ' (23)4------5-6-- '; + const subscriber2 = hot(' (b|) ').mergeMapTo(replaySubject); + const unsub2 = ' ! '; + const expected2 = ' (34)-5-6---7-- '; + const subscriber3 = hot(' (c|) ').mergeMapTo(replaySubject); + const expected3 = ' (78)9--|'; + + expectObservable(hot(sourceTemplate).do( + feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject + )).toBe(sourceTemplate); + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + }); + + it('should replay 2 last values for when subscribed after completed', () => { + const replaySubject = new ReplaySubject(2); + function feedNextIntoSubject(x) { replaySubject.next(x); } + function feedErrorIntoSubject(err) { replaySubject.error(err); } + function feedCompleteIntoSubject() { replaySubject.complete(); } + + const sourceTemplate = '-1-2-3--4--|'; + const subscriber1 = hot(' (a|) ').mergeMapTo(replaySubject); + const expected1 = ' (34|)'; + + expectObservable(hot(sourceTemplate).do( + feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject + )).toBe(sourceTemplate); + expectObservable(subscriber1).toBe(expected1); + }); + + it('should handle subscribers that arrive and leave at different times, ' + + 'subject does not complete', () => { + const subject = new ReplaySubject(2); + const results1 = []; + const results2 = []; + const results3 = []; + + subject.next(1); + subject.next(2); + subject.next(3); + subject.next(4); + + const subscription1 = subject.subscribe( + (x: number) => { results1.push(x); }, + (err: any) => { results1.push('E'); }, + () => { results1.push('C'); } + ); + + subject.next(5); + + const subscription2 = subject.subscribe( + (x: number) => { results2.push(x); }, + (err: any) => { results2.push('E'); }, + () => { results2.push('C'); } + ); + + subject.next(6); + subject.next(7); + + subscription1.unsubscribe(); + + subject.next(8); + + subscription2.unsubscribe(); + + subject.next(9); + subject.next(10); + + const subscription3 = subject.subscribe( + (x: number) => { results3.push(x); }, + (err: any) => { results3.push('E'); }, + () => { results3.push('C'); } + ); + + subject.next(11); + + subscription3.unsubscribe(); + + expect(results1).toEqual([3,4,5,6,7]); + expect(results2).toEqual([4,5,6,7,8]); + expect(results3).toEqual([9,10,11]); + + subject.complete(); + }); + }); + + describe('with windowTime=40', () => { + it('should replay previous values since 40 time units ago when subscribed', () => { + const replaySubject = new ReplaySubject(Number.POSITIVE_INFINITY, 40, rxTestScheduler); + function feedNextIntoSubject(x) { replaySubject.next(x); } + function feedErrorIntoSubject(err) { replaySubject.error(err); } + function feedCompleteIntoSubject() { replaySubject.complete(); } + + const sourceTemplate = '-1-2-3----4------5-6----7-8----9--|'; + const subscriber1 = hot(' (a|) ').mergeMapTo(replaySubject); + const unsub1 = ' ! '; + const expected1 = ' (23)4------5-6-- '; + const subscriber2 = hot(' (b|) ').mergeMapTo(replaySubject); + const unsub2 = ' ! '; + const expected2 = ' 4----5-6----7- '; + const subscriber3 = hot(' (c|) ').mergeMapTo(replaySubject); + const expected3 = ' (78)9--|'; + + expectObservable(hot(sourceTemplate).do( + feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject + )).toBe(sourceTemplate); + expectObservable(subscriber1, unsub1).toBe(expected1); + expectObservable(subscriber2, unsub2).toBe(expected2); + expectObservable(subscriber3).toBe(expected3); + }); + + it('should replay last values since 40 time units ago when subscribed', () => { + const replaySubject = new ReplaySubject(Number.POSITIVE_INFINITY, 40, rxTestScheduler); + function feedNextIntoSubject(x) { replaySubject.next(x); } + function feedErrorIntoSubject(err) { replaySubject.error(err); } + function feedCompleteIntoSubject() { replaySubject.complete(); } + + const sourceTemplate = '-1-2-3----4|'; + const subscriber1 = hot(' (a|)').mergeMapTo(replaySubject); + const expected1 = ' (4|)'; + + expectObservable(hot(sourceTemplate).do( + feedNextIntoSubject, feedErrorIntoSubject, feedCompleteIntoSubject + )).toBe(sourceTemplate); + expectObservable(subscriber1).toBe(expected1); + }); + }); + + it('should be an Observer which can be given to Observable.subscribe', (done: DoneSignature) => { + const source = Observable.of(1, 2, 3, 4, 5); + const subject = new ReplaySubject(3); + const expected = [3, 4, 5]; + + source.subscribe(subject); + + subject.subscribe( + (x: number) => { + expect(x).toBe(expected.shift()); + }, + done.fail, + done + ); + }); +}); \ No newline at end of file diff --git a/spec/symbol/rxSubscriber-spec.js b/spec/symbol/rxSubscriber-spec.js deleted file mode 100644 index 0774cbdce6..0000000000 --- a/spec/symbol/rxSubscriber-spec.js +++ /dev/null @@ -1,13 +0,0 @@ -var Rx = require('../../dist/cjs/Rx'); -var RxKitchenSink = require('../../dist/cjs/Rx.KitchenSink'); -var Symbol = require('../../dist/cjs/util/SymbolShim').SymbolShim; - -describe('rxSubscriber symbol', function () { - it('should exist on Rx', function () { - expect(Rx.Symbol.rxSubscriber).toBe(Symbol.for('rxSubscriber')); - }); - - it('should exist on Rx.KitchenSink', function () { - expect(RxKitchenSink.Symbol.rxSubscriber).toBe(Symbol.for('rxSubscriber')); - }); -}); \ No newline at end of file diff --git a/spec/symbol/rxSubscriber-spec.ts b/spec/symbol/rxSubscriber-spec.ts new file mode 100644 index 0000000000..1f7588c8c3 --- /dev/null +++ b/spec/symbol/rxSubscriber-spec.ts @@ -0,0 +1,14 @@ +import * as Rx from '../../dist/cjs/Rx'; +import * as RxKitchenSink from '../../dist/cjs/Rx.KitchenSink'; +import {SymbolShim} from '../../dist/cjs/util/SymbolShim'; +import {it} from '../helpers/test-helper'; + +describe('rxSubscriber symbol', () => { + it('should exist on Rx', () => { + expect(Rx.Symbol.rxSubscriber).toBe(SymbolShim.for('rxSubscriber')); + }); + + it('should exist on Rx.KitchenSink', () => { + expect(RxKitchenSink.Symbol.rxSubscriber).toBe(SymbolShim.for('rxSubscriber')); + }); +}); \ No newline at end of file diff --git a/spec/util/FastMap-spec.js b/spec/util/FastMap-spec.ts similarity index 52% rename from spec/util/FastMap-spec.js rename to spec/util/FastMap-spec.ts index b60f5bd971..f3de16dded 100644 --- a/spec/util/FastMap-spec.js +++ b/spec/util/FastMap-spec.ts @@ -1,14 +1,15 @@ -var FastMap = require('../../dist/cjs/util/FastMap').FastMap; +import {FastMap} from '../../dist/cjs/util/FastMap'; +import {it} from '../helpers/test-helper'; -describe('FastMap', function () { - it('should exist', function () { +describe('FastMap', () => { + it('should exist', () => { expect(typeof FastMap).toBe('function'); }); - it('should accept string as keys', function () { - var map = new FastMap(); - var key1 = 'keyOne'; - var key2 = 'keyTwo'; + it('should accept string as keys', () => { + const map = new FastMap(); + const key1 = 'keyOne'; + const key2 = 'keyTwo'; map.set(key1, 'yo'); map.set(key2, 'what up'); @@ -17,9 +18,9 @@ describe('FastMap', function () { expect(map.get(key2)).toBe('what up'); }); - it('should allow setting keys twice', function () { - var map = new FastMap(); - var key1 = 'keyOne'; + it('should allow setting keys twice', () => { + const map = new FastMap(); + const key1 = 'keyOne'; map.set(key1, 'sing'); map.set(key1, 'yodel'); @@ -27,9 +28,9 @@ describe('FastMap', function () { expect(map.get(key1)).toBe('yodel'); }); - it('should have a delete method that removes keys', function () { - var map = new FastMap(); - var key1 = 'keyOne'; + it('should have a delete method that removes keys', () => { + const map = new FastMap(); + const key1 = 'keyOne'; map.set(key1, 'sing'); @@ -37,10 +38,10 @@ describe('FastMap', function () { expect(map.get(key1)).toBe(null); }); - it('should clear all', function () { - var map = new FastMap(); - var key1 = 'keyOne'; - var key2 = 'keyTwo'; + it('should clear all', () => { + const map = new FastMap(); + const key1 = 'keyOne'; + const key2 = 'keyTwo'; map.set(key1, 'yo'); map.set(key2, 'what up'); @@ -51,20 +52,20 @@ describe('FastMap', function () { expect(map.get(key2)).toBe(undefined); }); - describe('prototype.forEach', function () { - it('should exist', function () { - var map = new FastMap(); + describe('prototype.forEach', () => { + it('should exist', () => { + const map = new FastMap(); expect(typeof map.forEach).toBe('function'); }); - it('should iterate over keys and values', function () { - var expectedKeys = ['a', 'b', 'c']; - var expectedValues = [1, 2, 3]; - var map = new FastMap(); + it('should iterate over keys and values', () => { + const expectedKeys = ['a', 'b', 'c']; + const expectedValues = [1, 2, 3]; + const map = new FastMap(); map.set('a', 1); map.set('b', 2); map.set('c', 3); - var thisArg = {}; + const thisArg = {}; map.forEach(function (value, key) { expect(this).toBe(thisArg); diff --git a/spec/util/Immediate-spec.js b/spec/util/Immediate-spec.ts similarity index 64% rename from spec/util/Immediate-spec.js rename to spec/util/Immediate-spec.ts index 8696f9e40a..76bb0c1e49 100644 --- a/spec/util/Immediate-spec.js +++ b/spec/util/Immediate-spec.ts @@ -1,56 +1,59 @@ -var ImmediateDefinition = require('../../dist/cjs/util/Immediate').ImmediateDefinition; -var Rx = require('../../dist/cjs/Rx'); +import {ImmediateDefinition} from '../../dist/cjs/util/Immediate'; +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; -describe('ImmediateDefinition', function () { - it('should have setImmediate and clearImmediate methods', function () { - var result = new ImmediateDefinition(__root__); +declare const __root__: any; + +describe('ImmediateDefinition', () => { + it('should have setImmediate and clearImmediate methods', () => { + const result = new ImmediateDefinition(__root__); expect(typeof result.setImmediate).toBe('function'); expect(typeof result.clearImmediate).toBe('function'); }); - describe('when setImmediate exists on root', function () { - it('should use the setImmediate and clearImmediate methods from root', function () { - var setImmediateCalled = false; - var clearImmediateCalled = false; + describe('when setImmediate exists on root', () => { + it('should use the setImmediate and clearImmediate methods from root', () => { + let setImmediateCalled = false; + let clearImmediateCalled = false; - var root = { - setImmediate: function () { + const root = { + setImmediate: () => { setImmediateCalled = true; }, - clearImmediate: function () { + clearImmediate: () => { clearImmediateCalled = true; } }; - var result = new ImmediateDefinition(root); + const result = new ImmediateDefinition(root); - result.setImmediate(function () {}); - result.clearImmediate(); + result.setImmediate(() => {}); + result.clearImmediate(null); expect(setImmediateCalled).toBeTruthy(); expect(clearImmediateCalled).toBeTruthy(); }); }); - describe('prototype.createProcessNextTickSetImmediate()', function () { - it('should create the proper flavor of setImmediate using process.nextTick', function () { - var instance = { + describe('prototype.createProcessNextTickSetImmediate()', () => { + it('should create the proper flavor of setImmediate using process.nextTick', () => { + const instance = { root: { process: { nextTick: jasmine.createSpy('nextTick') } }, - runIfPresent: function () {}, + runIfPresent: () => {}, partiallyApplied: jasmine.createSpy('partiallyApplied'), addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456) }; - var setImmediateImpl = ImmediateDefinition.prototype.createProcessNextTickSetImmediate.call(instance); + const setImmediateImpl = ImmediateDefinition.prototype.createProcessNextTickSetImmediate.call(instance); expect(typeof setImmediateImpl).toBe('function'); - var action = function () {}; - var handle = setImmediateImpl(action); + const action = () => {}; + const handle = setImmediateImpl(action); expect(handle).toBe(123456); expect(instance.addFromSetImmediateArguments).toHaveBeenCalled(); @@ -58,13 +61,13 @@ describe('ImmediateDefinition', function () { }); }); - describe('prototype.createPostMessageSetImmediate()', function () { - it('should create the proper flavor of setImmediate using postMessage', function () { - var addEventListenerCalledWith = null; + describe('prototype.createPostMessageSetImmediate()', () => { + it('should create the proper flavor of setImmediate using postMessage', () => { + let addEventListenerCalledWith = null; - var instance = { + const instance = { root: { - addEventListener: function (name, callback) { + addEventListener: (name: any, callback: any) => { addEventListenerCalledWith = [name, callback]; }, postMessage: jasmine.createSpy('root.postMessage'), @@ -76,7 +79,7 @@ describe('ImmediateDefinition', function () { addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456) }; - var setImmediateImpl = ImmediateDefinition.prototype.createPostMessageSetImmediate.call(instance); + const setImmediateImpl = ImmediateDefinition.prototype.createPostMessageSetImmediate.call(instance); expect(typeof setImmediateImpl).toBe('function'); expect(addEventListenerCalledWith[0]).toBe('message'); @@ -85,8 +88,8 @@ describe('ImmediateDefinition', function () { expect(instance.runIfPresent).toHaveBeenCalledWith(123456); - var action = function () {}; - var handle = setImmediateImpl(action); + const action = () => {}; + const handle = setImmediateImpl(action); expect(handle).toBe(123456); expect(instance.addFromSetImmediateArguments).toHaveBeenCalled(); @@ -94,10 +97,10 @@ describe('ImmediateDefinition', function () { }); }); - describe('prototype.createMessageChannelSetImmediate', function () { - it('should create the proper flavor of setImmediate that uses message channels', function () { - var port1 = {}; - var port2 = { + describe('prototype.createMessageChannelSetImmediate', () => { + it('should create the proper flavor of setImmediate that uses message channels', () => { + const port1 = {}; + const port2 = { postMessage: jasmine.createSpy('MessageChannel.port2.postMessage') }; @@ -106,7 +109,7 @@ describe('ImmediateDefinition', function () { this.port2 = port2; } - var instance = { + const instance = { root: { MessageChannel: MockMessageChannel }, @@ -114,28 +117,28 @@ describe('ImmediateDefinition', function () { addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456) }; - var setImmediateImpl = ImmediateDefinition.prototype.createMessageChannelSetImmediate.call(instance); + const setImmediateImpl = ImmediateDefinition.prototype.createMessageChannelSetImmediate.call(instance); expect(typeof setImmediateImpl).toBe('function'); - expect(typeof port1.onmessage).toBe('function'); + expect(typeof (port1).onmessage).toBe('function'); - port1.onmessage({ data: 'something' }); + (port1).onmessage({ data: 'something' }); expect(instance.runIfPresent).toHaveBeenCalledWith('something'); - var action = function () {}; - var handle = setImmediateImpl(action); + const action = () => {}; + const handle = setImmediateImpl(action); expect(handle).toBe(123456); expect(port2.postMessage).toHaveBeenCalledWith(123456); }); }); - describe('prototype.createReadyStateChangeSetImmediate', function () { - it('should create the proper flavor of setImmediate that uses readystatechange on a DOM element', function () { - var fakeScriptElement = {}; + describe('prototype.createReadyStateChangeSetImmediate', () => { + it('should create the proper flavor of setImmediate that uses readystatechange on a DOM element', () => { + const fakeScriptElement = {}; - var instance = { + const instance = { root: { document: { createElement: jasmine.createSpy('document.createElement').and.returnValue(fakeScriptElement), @@ -149,37 +152,37 @@ describe('ImmediateDefinition', function () { addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456) }; - var setImmediateImpl = ImmediateDefinition.prototype.createReadyStateChangeSetImmediate.call(instance); + const setImmediateImpl = ImmediateDefinition.prototype.createReadyStateChangeSetImmediate.call(instance); expect(typeof setImmediateImpl).toBe('function'); - var action = function () {}; - var handle = setImmediateImpl(action); + const action = () => {}; + const handle = setImmediateImpl(action); expect(handle).toBe(123456); expect(instance.root.document.createElement).toHaveBeenCalledWith('script'); - expect(typeof fakeScriptElement.onreadystatechange).toBe('function'); + expect(typeof (fakeScriptElement).onreadystatechange).toBe('function'); expect(instance.root.document.documentElement.appendChild).toHaveBeenCalledWith(fakeScriptElement); - fakeScriptElement.onreadystatechange(); + (fakeScriptElement).onreadystatechange(); expect(instance.runIfPresent).toHaveBeenCalledWith(handle); - expect(fakeScriptElement.onreadystatechange).toBe(null); + expect((fakeScriptElement).onreadystatechange).toBe(null); expect(instance.root.document.documentElement.removeChild).toHaveBeenCalledWith(fakeScriptElement); }); }); - describe('when setImmediate does *not* exist on root', function () { - describe('when it can use process.nextTick', function () { - it('should use the post message impl', function () { - var nextTickImpl = function () { }; + describe('when setImmediate does *not* exist on root', () => { + describe('when it can use process.nextTick', () => { + it('should use the post message impl', () => { + const nextTickImpl = () => { }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(true); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseReadyStateChange').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'createProcessNextTickSetImmediate').and.returnValue(nextTickImpl); - var result = new ImmediateDefinition({}); + const result = new ImmediateDefinition({}); expect(ImmediateDefinition.prototype.canUseProcessNextTick).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUsePostMessage).not.toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUseMessageChannel).not.toHaveBeenCalled(); @@ -189,16 +192,16 @@ describe('ImmediateDefinition', function () { }); }); - describe('when it cannot use process.nextTick', function () { - it('should use the post message impl', function () { - var postMessageImpl = function () { }; + describe('when it cannot use process.nextTick', () => { + it('should use the post message impl', () => { + const postMessageImpl = () => { }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(true); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseReadyStateChange').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'createPostMessageSetImmediate').and.returnValue(postMessageImpl); - var result = new ImmediateDefinition({}); + const result = new ImmediateDefinition({}); expect(ImmediateDefinition.prototype.canUseProcessNextTick).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUsePostMessage).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUseMessageChannel).not.toHaveBeenCalled(); @@ -208,16 +211,16 @@ describe('ImmediateDefinition', function () { }); }); - describe('when it cannot use process.nextTick or postMessage', function () { - it('should use the readystatechange impl', function () { - var messageChannelImpl = function () { }; + describe('when it cannot use process.nextTick or postMessage', () => { + it('should use the readystatechange impl', () => { + const messageChannelImpl = () => { }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(true); spyOn(ImmediateDefinition.prototype, 'canUseReadyStateChange').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'createMessageChannelSetImmediate').and.returnValue(messageChannelImpl); - var result = new ImmediateDefinition({}); + const result = new ImmediateDefinition({}); expect(ImmediateDefinition.prototype.canUseProcessNextTick).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUsePostMessage).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUseMessageChannel).toHaveBeenCalled(); @@ -227,16 +230,16 @@ describe('ImmediateDefinition', function () { }); }); - describe('when it cannot use process.nextTick, postMessage or Message channels', function () { - it('should use the readystatechange impl', function () { - var readyStateChangeImpl = function () { }; + describe('when it cannot use process.nextTick, postMessage or Message channels', () => { + it('should use the readystatechange impl', () => { + const readyStateChangeImpl = () => { }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseReadyStateChange').and.returnValue(true); spyOn(ImmediateDefinition.prototype, 'createReadyStateChangeSetImmediate').and.returnValue(readyStateChangeImpl); - var result = new ImmediateDefinition({}); + const result = new ImmediateDefinition({}); expect(ImmediateDefinition.prototype.canUseProcessNextTick).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUsePostMessage).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUseMessageChannel).toHaveBeenCalled(); @@ -246,16 +249,16 @@ describe('ImmediateDefinition', function () { }); }); - describe('when no other methods to implement setImmediate are available', function () { - it('should use the setTimeout impl', function () { - var setTimeoutImpl = function () { }; + describe('when no other methods to implement setImmediate are available', () => { + it('should use the setTimeout impl', () => { + const setTimeoutImpl = () => { }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseReadyStateChange').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'createSetTimeoutSetImmediate').and.returnValue(setTimeoutImpl); - var result = new ImmediateDefinition({}); + const result = new ImmediateDefinition({}); expect(ImmediateDefinition.prototype.canUseProcessNextTick).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUsePostMessage).toHaveBeenCalled(); expect(ImmediateDefinition.prototype.canUseMessageChannel).toHaveBeenCalled(); @@ -266,11 +269,11 @@ describe('ImmediateDefinition', function () { }); }); - describe('partiallyApplied', function () { - describe('when passed a function as the first argument', function () { - it('should return a function that takes no arguments and will be called with the passed arguments', function () { - var fn = jasmine.createSpy('spy'); - var result = ImmediateDefinition.prototype.partiallyApplied(fn, 'arg1', 'arg2', 'arg3'); + describe('partiallyApplied', () => { + describe('when passed a function as the first argument', () => { + it('should return a function that takes no arguments and will be called with the passed arguments', () => { + const fn = jasmine.createSpy('spy'); + const result = ImmediateDefinition.prototype.partiallyApplied(fn, 'arg1', 'arg2', 'arg3'); expect(typeof result).toBe('function'); expect(fn).not.toHaveBeenCalled(); @@ -281,15 +284,15 @@ describe('ImmediateDefinition', function () { }); }); - describe('when passed a non-function as an argument', function () { - it('should coerce to a string and convert to a function which will be called by the returned function', function () { + describe('when passed a non-function as an argument', () => { + it('should coerce to a string and convert to a function which will be called by the returned function', () => { __root__.__wasCalled = null; - var fnStr = '__wasCalled = true;'; - var result = ImmediateDefinition.prototype.partiallyApplied(fnStr); + const fnStr = '__wasCalled = true;'; + const result = ImmediateDefinition.prototype.partiallyApplied(fnStr); expect(typeof result).toBe('function'); - var calledWith = result(); + const calledWith = result(); expect(__root__.__wasCalled).toEqual(true); @@ -298,51 +301,51 @@ describe('ImmediateDefinition', function () { }); }); - describe('prototype.identify', function () { - it('should use Object.toString to return an identifier string', function () { + describe('prototype.identify', () => { + it('should use Object.toString to return an identifier string', () => { function MockObject() { } MockObject.prototype.toString = jasmine.createSpy('Object.prototype.toString').and.returnValue('[object HEYO!]'); - var instance = { + const instance = { root: { Object: MockObject } }; - var result = ImmediateDefinition.prototype.identify.call(instance); + const result = (ImmediateDefinition).prototype.identify.call(instance); expect(result).toBe('[object HEYO!]'); }); }); - describe('prototype.canUseProcessNextTick', function () { - describe('when root.process does not identify as [object process]', function () { - it('should return false', function () { - var instance = { + describe('prototype.canUseProcessNextTick', () => { + describe('when root.process does not identify as [object process]', () => { + it('should return false', () => { + const instance = { root: { process: {} }, identify: jasmine.createSpy('identify').and.returnValue('[object it-is-not-a-tumor]') }; - var result = ImmediateDefinition.prototype.canUseProcessNextTick.call(instance); + const result = ImmediateDefinition.prototype.canUseProcessNextTick.call(instance); expect(result).toBe(false); expect(instance.identify).toHaveBeenCalledWith(instance.root.process); }); }); - describe('when root.process identifies as [object process]', function () { - it('should return true', function () { - var instance = { + describe('when root.process identifies as [object process]', () => { + it('should return true', () => { + const instance = { root: { process: {} }, identify: jasmine.createSpy('identify').and.returnValue('[object process]') }; - var result = ImmediateDefinition.prototype.canUseProcessNextTick.call(instance); + const result = ImmediateDefinition.prototype.canUseProcessNextTick.call(instance); expect(result).toBe(true); expect(instance.identify).toHaveBeenCalledWith(instance.root.process); @@ -350,12 +353,12 @@ describe('ImmediateDefinition', function () { }); }); - describe('prototype.canUsePostMessage', function () { - describe('when there is a global postMessage function', function () { - describe('and importScripts does NOT exist', function () { - it('should maintain any existing onmessage handler', function () { - var originalOnMessage = function () {}; - var instance = { + describe('prototype.canUsePostMessage', () => { + describe('when there is a global postMessage function', () => { + describe('and importScripts does NOT exist', () => { + it('should maintain any existing onmessage handler', () => { + const originalOnMessage = () => {}; + const instance = { root: { onmessage: originalOnMessage } @@ -365,10 +368,10 @@ describe('ImmediateDefinition', function () { expect(instance.root.onmessage).toBe(originalOnMessage); }); - describe('and postMessage is synchronous', function () { - it('should return false', function () { - var postMessageCalled = false; - var instance = { + describe('and postMessage is synchronous', () => { + it('should return false', () => { + let postMessageCalled = false; + const instance = { root: { postMessage: function () { postMessageCalled = true; @@ -377,92 +380,92 @@ describe('ImmediateDefinition', function () { } }; - var result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); + const result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); expect(result).toBe(false); expect(postMessageCalled).toBe(true); }); }); - describe('and postMessage is asynchronous', function () { - it('should return true', function () { - var postMessageCalled = false; - var instance = { + describe('and postMessage is asynchronous', () => { + it('should return true', () => { + let postMessageCalled = false; + const instance = { root: { postMessage: function () { postMessageCalled = true; - var _onmessage = this.onmessage; - setTimeout(function () { _onmessage(); }); + const _onmessage = this.onmessage; + setTimeout(() => { _onmessage(); }); } } }; - var result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); + const result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); expect(result).toBe(true); expect(postMessageCalled).toBe(true); }); }); }); - describe('and importScripts *does* exist because it is a worker', function () { - it('should return false', function () { - var instance = { + describe('and importScripts *does* exist because it is a worker', () => { + it('should return false', () => { + const instance = { root: { - postMessage: function () {}, - importScripts: function () {} + postMessage: () => {}, + importScripts: () => {} } }; - var result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); + const result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); expect(result).toBe(false); }); }); }); - describe('when there is NOT a global postMessage function', function () { - it('should return false', function () { - var instance = { + describe('when there is NOT a global postMessage function', () => { + it('should return false', () => { + const instance = { root: {} }; - var result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); + const result = ImmediateDefinition.prototype.canUsePostMessage.call(instance); expect(result).toBe(false); }); }); }); - describe('prototype.canUseMessageChannel', function () { - it('should return true if MessageChannel exists', function () { - var instance = { + describe('prototype.canUseMessageChannel', () => { + it('should return true if MessageChannel exists', () => { + const instance = { root: { - MessageChannel: function () {} + MessageChannel: () => {} } }; - var result = ImmediateDefinition.prototype.canUseMessageChannel.call(instance); + const result = ImmediateDefinition.prototype.canUseMessageChannel.call(instance); expect(result).toBe(true); }); - it('should return false if MessageChannel does NOT exist', function () { - var instance = { + it('should return false if MessageChannel does NOT exist', () => { + const instance = { root: {} }; - var result = ImmediateDefinition.prototype.canUseMessageChannel.call(instance); + const result = ImmediateDefinition.prototype.canUseMessageChannel.call(instance); expect(result).toBe(false); }); }); - describe('prototype.canUseReadyStateChange', function () { - describe('when there is a document in global scope', function () { - it('should return true if created script elements have an onreadystatechange property', function () { - var fakeScriptElement = { + describe('prototype.canUseReadyStateChange', () => { + describe('when there is a document in global scope', () => { + it('should return true if created script elements have an onreadystatechange property', () => { + const fakeScriptElement = { onreadystatechange: null }; - var instance = { + const instance = { root: { document: { createElement: jasmine.createSpy('document.createElement').and.returnValue(fakeScriptElement) @@ -470,16 +473,16 @@ describe('ImmediateDefinition', function () { } }; - var result = ImmediateDefinition.prototype.canUseReadyStateChange.call(instance); + const result = ImmediateDefinition.prototype.canUseReadyStateChange.call(instance); expect(result).toBe(true); expect(instance.root.document.createElement).toHaveBeenCalledWith('script'); }); - it('should return false if created script elements do NOT have an onreadystatechange property', function () { - var fakeScriptElement = {}; + it('should return false if created script elements do NOT have an onreadystatechange property', () => { + const fakeScriptElement = {}; - var instance = { + const instance = { root: { document: { createElement: jasmine.createSpy('document.createElement').and.returnValue(fakeScriptElement) @@ -487,37 +490,37 @@ describe('ImmediateDefinition', function () { } }; - var result = ImmediateDefinition.prototype.canUseReadyStateChange.call(instance); + const result = ImmediateDefinition.prototype.canUseReadyStateChange.call(instance); expect(result).toBe(false); expect(instance.root.document.createElement).toHaveBeenCalledWith('script'); }); }); - it('should return false if there is no document in global scope', function () { - var instance = { + it('should return false if there is no document in global scope', () => { + const instance = { root: {} }; - var result = ImmediateDefinition.prototype.canUseReadyStateChange.call(instance); + const result = ImmediateDefinition.prototype.canUseReadyStateChange.call(instance); expect(result).toBe(false); }); }); - describe('prototype.addFromSetImmediateArguments', function () { - it('should add to tasksByHandle and increment the nextHandle', function () { - var partiallyAppliedResult = {}; + describe('prototype.addFromSetImmediateArguments', () => { + it('should add to tasksByHandle and increment the nextHandle', () => { + const partiallyAppliedResult = {}; - var instance = { + const instance = { tasksByHandle: {}, nextHandle: 42, partiallyApplied: jasmine.createSpy('partiallyApplied').and.returnValue(partiallyAppliedResult) }; - var args = [function () {}, 'foo', 'bar']; + const args = [() => {}, 'foo', 'bar']; - var handle = ImmediateDefinition.prototype.addFromSetImmediateArguments.call(instance, args); + const handle = ImmediateDefinition.prototype.addFromSetImmediateArguments.call(instance, args); expect(handle).toBe(42); expect(instance.nextHandle).toBe(43); @@ -525,17 +528,17 @@ describe('ImmediateDefinition', function () { }); }); - describe('clearImmediate', function () { - it('should delete values from tasksByHandle', function () { - var setTimeoutImpl = function () { }; + describe('clearImmediate', () => { + it('should delete values from tasksByHandle', () => { + const setTimeoutImpl = () => { }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseReadyStateChange').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'createSetTimeoutSetImmediate').and.returnValue(setTimeoutImpl); - var Immediate = new ImmediateDefinition({}); - Immediate.tasksByHandle[123456] = function () {}; + const Immediate = new ImmediateDefinition({}); + Immediate.tasksByHandle[123456] = () => {}; expect('123456' in Immediate.tasksByHandle).toBe(true); @@ -545,11 +548,11 @@ describe('ImmediateDefinition', function () { }); }); - describe('prototype.runIfPresent', function () { - it('should delay running the task if it is currently running a task', function () { - var mockApplied = function () {}; + describe('prototype.runIfPresent', () => { + it('should delay running the task if it is currently running a task', () => { + const mockApplied = () => {}; - var instance = { + const instance = { root: { setTimeout: jasmine.createSpy('setTimeout'), Object: Object @@ -560,13 +563,13 @@ describe('ImmediateDefinition', function () { ImmediateDefinition.prototype.runIfPresent.call(instance, 123456); - expect(instance.partiallyApplied).toHaveBeenCalledWith(instance.runIfPresent, 123456); + expect(instance.partiallyApplied).toHaveBeenCalledWith((instance).runIfPresent, 123456); expect(instance.root.setTimeout).toHaveBeenCalledWith(mockApplied, 0); }); - it('should not error if there is no task currently running and the handle passed is not found', function () { - expect(function () { - var instance = { + it('should not error if there is no task currently running and the handle passed is not found', () => { + expect(() => { + const instance = { root: { setTimeout: jasmine.createSpy('setTimeout'), Object: Object @@ -579,9 +582,9 @@ describe('ImmediateDefinition', function () { }).not.toThrow(); }); - describe('when a task is found for the handle', function () { - it('should execute the task and clean up after', function () { - var instance = { + describe('when a task is found for the handle', () => { + it('should execute the task and clean up after', () => { + const instance = { root: { setTimeout: jasmine.createSpy('setTimeout'), Object: Object @@ -591,7 +594,7 @@ describe('ImmediateDefinition', function () { clearImmediate: jasmine.createSpy('clearImmediate') }; - instance.tasksByHandle[123456] = jasmine.createSpy('task').and.callFake(function () { + instance.tasksByHandle[123456] = jasmine.createSpy('task').and.callFake(() => { expect(instance.currentlyRunningATask).toBe(true); }); @@ -601,22 +604,22 @@ describe('ImmediateDefinition', function () { }); }); - describe('prototype.createSetTimeoutSetImmediate', function () { - it('should create a proper setImmediate implementation that uses setTimeout', function () { - var mockApplied = function () {}; + describe('prototype.createSetTimeoutSetImmediate', () => { + it('should create a proper setImmediate implementation that uses setTimeout', () => { + const mockApplied = () => {}; - var instance = { + const instance = { root: { setTimeout: jasmine.createSpy('setTimeout') }, addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456), - runIfPresent: function () {}, + runIfPresent: () => {}, partiallyApplied: jasmine.createSpy('partiallyApplied').and.returnValue(mockApplied) }; - var setImmediateImpl = ImmediateDefinition.prototype.createSetTimeoutSetImmediate.call(instance); + const setImmediateImpl = ImmediateDefinition.prototype.createSetTimeoutSetImmediate.call(instance); - var handle = setImmediateImpl(); + const handle = setImmediateImpl(); expect(handle).toBe(123456); expect(instance.addFromSetImmediateArguments).toHaveBeenCalled(); @@ -624,14 +627,14 @@ describe('ImmediateDefinition', function () { }); }); - describe('integration test', function () { - it('should work', function (done) { - var results = []; - Rx.Observable.fromArray([1, 2, 3], Rx.Scheduler.nextTick) - .subscribe(function (x) { + describe('integration test', () => { + it('should work', (done: DoneSignature) => { + const results = []; + Rx.Observable.fromArray([1, 2, 3], Rx.Scheduler.asap) + .subscribe((x: number) => { results.push(x); - }, done.throw, - function () { + }, done.fail, + () => { expect(results).toEqual([1,2,3]); done(); }); diff --git a/spec/util/MapPolyfill-spec.js b/spec/util/MapPolyfill-spec.ts similarity index 53% rename from spec/util/MapPolyfill-spec.js rename to spec/util/MapPolyfill-spec.ts index b027e84399..dfaa948585 100644 --- a/spec/util/MapPolyfill-spec.js +++ b/spec/util/MapPolyfill-spec.ts @@ -1,14 +1,16 @@ -var MapPolyfill = require('../../dist/cjs/util/MapPolyfill').MapPolyfill; +import {MapPolyfill} from '../../dist/cjs/util/MapPolyfill'; +import * as Rx from '../../dist/cjs/Rx'; +import {it} from '../helpers/test-helper'; -describe('MapPolyfill', function () { - it('should exist', function () { +describe('MapPolyfill', () => { + it('should exist', () => { expect(typeof MapPolyfill).toBe('function'); }); - it('should act like a hashtable that accepts objects as keys', function () { - var map = new MapPolyfill(); - var key1 = {}; - var key2 = {}; + it('should act like a hashtable that accepts objects as keys', () => { + const map = new MapPolyfill(); + const key1 = {}; + const key2 = {}; map.set('test', 'hi'); map.set(key1, 'yo'); @@ -20,9 +22,9 @@ describe('MapPolyfill', function () { expect(map.size).toBe(3); }); - it('should allow setting keys twice', function () { - var map = new MapPolyfill(); - var key1 = {}; + it('should allow setting keys twice', () => { + const map = new MapPolyfill(); + const key1 = {}; map.set(key1, 'sing'); map.set(key1, 'yodel'); @@ -31,9 +33,9 @@ describe('MapPolyfill', function () { expect(map.size).toBe(1); }); - it('should have a delete method that removes keys', function () { - var map = new MapPolyfill(); - var key1 = {}; + it('should have a delete method that removes keys', () => { + const map = new MapPolyfill(); + const key1 = {}; map.set(key1, 'sing'); expect(map.size).toBe(1); @@ -44,21 +46,25 @@ describe('MapPolyfill', function () { expect(map.get(key1)).toBe(undefined); }); - describe('prototype.forEach', function () { - it('should exist', function () { - var map = new MapPolyfill(); + describe('prototype.forEach', () => { + it('should exist', () => { + const map = new MapPolyfill(); expect(typeof map.forEach).toBe('function'); }); - it('should iterate over keys and values', function () { - var expectedKeys = ['a', 'b', 'c']; - var expectedValues = [1, 2, 3]; - var map = new MapPolyfill(); + it('should iterate over keys and values', () => { + const expectedKeys = ['a', 'b', 'c']; + const expectedValues = [1, 2, 3]; + const map = new MapPolyfill(); map.set('a', 1); map.set('b', 2); map.set('c', 3); - var thisArg = {}; + const thisArg = { + arg: 'value' + }; + + //intentionally not using lambda to avoid typescript's this context capture map.forEach(function (value, key) { expect(this).toBe(thisArg); expect(value).toBe(expectedValues.shift()); diff --git a/spec/util/SymbolShim-spec.js b/spec/util/SymbolShim-spec.js deleted file mode 100644 index de77c8cab7..0000000000 --- a/spec/util/SymbolShim-spec.js +++ /dev/null @@ -1,123 +0,0 @@ -/* globals __root__ */ -var SymbolShim = require('../../dist/cjs/util/SymbolShim'); -var Map = require('../../dist/cjs/util/Map').Map; -var Rx = require('../../dist/cjs/Rx'); -var polyfillSymbol = SymbolShim.polyfillSymbol; -var ensureIterator = SymbolShim.ensureIterator; - -describe('SymbolShim.polyfillSymbol', function () { - it('should polyfill Symbol to be a function that returns a primitive that is unique', function () { - var Symbol = polyfillSymbol({ }); - - expect(typeof Symbol).toBe('function'); - var x = Symbol('test'); - var y = Symbol('test'); - expect(x !== y).toBe(true); // should be obvious, but this is the important part. - - expect(x).toBe('@@Symbol(test):0'); - expect(y).toBe('@@Symbol(test):1'); - }); - - it('should setup symbol if root does not have it', function () { - var root = {}; - - var result = polyfillSymbol(root); - expect(root.Symbol).toBeDefined(); - expect(result.observable).toBeDefined(); - expect(result.iterator).toBeDefined(); - expect(result.for).toBeDefined(); - }); - - it('should add a for method', function () { - var root = {}; - var result = polyfillSymbol(root); - expect(typeof result.for).toBe('function'); - - var test = result.for('test'); - expect(test).toBe('@@test'); - }); - - it('should add a for method even if Symbol already exists but does not have for', function () { - var root = { - Symbol: {} - }; - var result = polyfillSymbol(root); - - expect(typeof result.for).toBe('function'); - - var test = result.for('test'); - expect(test).toBe('@@test'); - }); - - describe('when symbols exists on root', function () { - it('should use symbols from root', function () { - var root = { - Symbol: { - observable: {}, - iterator: {} - } - }; - - var result = polyfillSymbol(root); - expect(result.observable).toBe(root.Symbol.observable); - expect(result.iterator).toBe(root.Symbol.iterator); - }); - }); - - describe('observable symbol', function () { - it('should patch root using for symbol if exist', function () { - var root = { - Symbol: { - for: function (x) { return x; } - } - }; - - var result = polyfillSymbol(root); - expect(result.observable).toBe(root.Symbol.for('observable')); - }); - - it('should patch root if for symbol does not exist', function () { - var root = {}; - - var result = polyfillSymbol(root); - expect(result.observable).toBe('@@observable'); - }); - }); - - it('should patch root using Symbol.for if exist', function () { - var root = { - Symbol: { - for: function (x) { return x; } - } - }; - var result = polyfillSymbol(root); - expect(result.iterator).toBe(root.Symbol.for('iterator')); - }); - - it('should patch using Set for mozilla bug', function () { - function Set() { - } - Set.prototype['@@iterator'] = function () {}; - - var root = { - Set: Set, - Symbol: {} - }; - - var result = polyfillSymbol(root); - expect(result.iterator).toBe('@@iterator'); - }); - - it('should patch using map for es6-shim', function () { - var root = { - Map: Map, - Symbol: {} - }; - - root.Map.prototype.key = 'iteratorValue'; - root.Map.prototype.entries = 'iteratorValue'; - - var result = polyfillSymbol(root); - expect(result.iterator).toBe('key'); - }); -}); diff --git a/spec/util/SymbolShim-spec.ts b/spec/util/SymbolShim-spec.ts new file mode 100644 index 0000000000..0f0403e8af --- /dev/null +++ b/spec/util/SymbolShim-spec.ts @@ -0,0 +1,123 @@ +import {polyfillSymbol, ensureIterator} from '../../dist/cjs/util/SymbolShim'; +import {Map} from '../../dist/cjs/util/Map'; +import * as Rx from '../../dist/cjs/Rx'; +import {it, DoneSignature} from '../helpers/test-helper'; + +declare const __root__: any; + +describe('SymbolShim.polyfillSymbol', () => { + it('should polyfill Symbol to be a function that returns a primitive that is unique', () => { + const Symbol = polyfillSymbol({ }); + + expect(typeof Symbol).toBe('function'); + const x = Symbol('test'); + const y = Symbol('test'); + expect(x !== y).toBe(true); // should be obvious, but this is the important part. + + expect(x).toBe('@@Symbol(test):0'); + expect(y).toBe('@@Symbol(test):1'); + }); + + it('should setup symbol if root does not have it', () => { + const root = {}; + + const result = polyfillSymbol(root); + expect((root).Symbol).toBeDefined(); + expect(result.observable).toBeDefined(); + expect(result.iterator).toBeDefined(); + expect(result.for).toBeDefined(); + }); + + it('should add a for method', () => { + const root = {}; + const result = polyfillSymbol(root); + expect(typeof result.for).toBe('function'); + + const test = result.for('test'); + expect(test).toBe('@@test'); + }); + + it('should add a for method even if Symbol already exists but does not have for', () => { + const root = { + Symbol: {} + }; + const result = polyfillSymbol(root); + + expect(typeof result.for).toBe('function'); + + const test = result.for('test'); + expect(test).toBe('@@test'); + }); + + describe('when symbols exists on root', () => { + it('should use symbols from root', () => { + const root = { + Symbol: { + observable: {}, + iterator: {} + } + }; + + const result = polyfillSymbol(root); + expect(result.observable).toBe(root.Symbol.observable); + expect(result.iterator).toBe(root.Symbol.iterator); + }); + }); + + describe('observable symbol', () => { + it('should patch root using for symbol if exist', () => { + const root = { + Symbol: { + for: (x: any) => x + } + }; + + const result = polyfillSymbol(root); + expect(result.observable).toBe(root.Symbol.for('observable')); + }); + + it('should patch root if for symbol does not exist', () => { + const root = {}; + + const result = polyfillSymbol(root); + expect(result.observable).toBe('@@observable'); + }); + }); + + it('should patch root using Symbol.for if exist', () => { + const root = { + Symbol: { + for: (x: any) => x + } + }; + const result = polyfillSymbol(root); + expect(result.iterator).toBe(root.Symbol.for('iterator')); + }); + + it('should patch using Set for mozilla bug', () => { + function Set() { + } + Set.prototype['@@iterator'] = () => {}; + + const root = { + Set: Set, + Symbol: {} + }; + + const result = polyfillSymbol(root); + expect(result.iterator).toBe('@@iterator'); + }); + + it('should patch using map for es6-shim', () => { + const root = { + Map: Map, + Symbol: {} + }; + + root.Map.prototype.key = 'iteratorValue'; + root.Map.prototype.entries = 'iteratorValue'; + + const result = polyfillSymbol(root); + expect(result.iterator).toBe('key'); + }); +}); From c1bd61fac9f74f8c5084aae364a59e32a59540b3 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Thu, 18 Feb 2016 23:08:07 -0800 Subject: [PATCH 4/8] chore(test): update browser test configurations --- .markdown-doctest-setup.js | 2 +- karma.conf.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.markdown-doctest-setup.js b/.markdown-doctest-setup.js index 4c7a7a23ee..f689ceb3a0 100644 --- a/.markdown-doctest-setup.js +++ b/.markdown-doctest-setup.js @@ -1,7 +1,7 @@ 'use strict'; var Rx = require(__dirname); -var marbleTesting = require('./spec/helpers/marble-testing'); +var marbleTesting = require('./tmp/helpers/marble-testing'); global.rxTestScheduler = new Rx.TestScheduler(marbleTesting.assertDeepEqual); diff --git a/karma.conf.js b/karma.conf.js index d63f2f94dc..fd7b93cc86 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -139,10 +139,10 @@ module.exports = function (config) { // list of files / patterns to load in the browser files: [ - 'spec/helpers/marble-testing.js', - 'spec/helpers/test-helper.js', - 'spec/helpers/ajax-helper.js', - 'spec/**/*-spec.js' + 'tmp/helpers/marble-testing.js', + 'tmp/helpers/test-helper.js', + 'tmp/helpers/ajax-helper.js', + 'tmp/**/*-spec.js' ], // list of files to exclude @@ -152,7 +152,7 @@ module.exports = function (config) { // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - 'spec/**/*.js': ['browserify'] + 'tmp/**/*.js': ['browserify'] }, // test results reporter to use From bcb1658017ed90f8664a21de24fceb902cec0e79 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Thu, 18 Feb 2016 23:19:30 -0800 Subject: [PATCH 5/8] chore(test): update code coverage configurations --- package.json | 2 +- spec/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 85d015679c..657e464a3c 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "lint_src": "tslint -c tslint.json src/*.ts src/**/*.ts src/**/**/*.ts", "lint": "npm run lint_src && npm run lint_spec && npm run lint_perf", "copy_src": "cp -r src/ dist/cjs/src && cp -r src/ dist/amd/src && cp -r src/ dist/es6/src", - "cover": "istanbul cover -x \"*-spec.js index.js *-helper.js spec/helpers/*\" ./node_modules/jasmine/bin/jasmine.js && npm run cover_remapping", + "cover": "istanbul cover -x \"*-spec.js index.js *-helper.js tmp/helpers/*\" ./node_modules/jasmine/bin/jasmine.js && npm run cover_remapping", "cover_remapping": "remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped.json && remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped.lcov -t lcovonly && remap-istanbul -b ./ -i coverage/coverage.json -o coverage/coverage-remapped -t html", "test_nobuild": "jasmine", "test_buildonly": "rm -rf tmp && tsc --project ./spec --pretty", diff --git a/spec/tsconfig.json b/spec/tsconfig.json index 535b61be55..e35fe7b765 100644 --- a/spec/tsconfig.json +++ b/spec/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "removeComments": false, "preserveConstEnums": true, - "sourceMap": false, + "sourceMap": true, "declaration": false, "target": "es5", "module": "commonjs", From 5956fb239c12f83dcc13f9ab466d0c674d8d244e Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Fri, 19 Feb 2016 00:16:16 -0800 Subject: [PATCH 6/8] style(test): update specs lint, hint friendly --- karma.conf.js | 1 + package.json | 3 +- spec/Notification-spec.ts | 2 +- spec/Observable-spec.ts | 39 +-- spec/Subject-spec.ts | 43 +-- spec/helpers/ajax-helper.ts | 9 +- spec/observables/bindCallback-spec.ts | 2 +- spec/observables/bindNodeCallback-spec.ts | 1 - spec/observables/dom/webSocket-spec.ts | 2 +- spec/observables/zip-spec.ts | 4 +- spec/operators/buffer-spec.ts | 8 +- spec/operators/bufferTime-spec.ts | 8 +- spec/operators/bufferToggle-spec.ts | 26 +- spec/operators/bufferWhen-spec.ts | 36 +-- spec/operators/cache-spec.ts | 6 +- spec/operators/catch-spec.ts | 8 +- spec/operators/combineLatest-spec.ts | 1 - spec/operators/concatAll-spec.ts | 2 +- spec/operators/concatMap-spec.ts | 28 +- spec/operators/concatMapTo-spec.ts | 12 +- spec/operators/debounce-spec.ts | 8 +- spec/operators/delayWhen-spec.ts | 1 - spec/operators/do-spec.ts | 8 +- spec/operators/elementAt-spec.ts | 2 +- spec/operators/every-spec.ts | 2 +- spec/operators/exhaust-spec.ts | 1 - spec/operators/exhaustMap-spec.ts | 327 +++++++++++----------- spec/operators/groupBy-spec.ts | 5 +- spec/operators/inspect-spec.ts | 9 +- spec/operators/inspectTime-spec.ts | 1 - spec/operators/let-spec.ts | 2 +- spec/operators/map-spec.ts | 6 +- spec/operators/mergeMap-spec.ts | 36 +-- spec/operators/mergeMapTo-spec.ts | 16 +- spec/operators/multicast-spec.ts | 4 +- spec/operators/observeOn-spec.ts | 4 +- spec/operators/pairwise-spec.ts | 3 - spec/operators/pluck-spec.ts | 4 +- spec/operators/publish-spec.ts | 1 - spec/operators/publishLast-spec.ts | 1 - spec/operators/race-spec.ts | 2 +- spec/operators/refCount-spec.ts | 20 +- spec/operators/repeat-spec.ts | 14 +- spec/operators/sample-spec.ts | 2 +- spec/operators/single-spec.ts | 2 +- spec/operators/startWith-spec.ts | 6 +- spec/operators/subscribeOn-spec.ts | 2 +- spec/operators/switch-spec.ts | 4 +- spec/operators/switchMap-spec.ts | 3 +- spec/operators/switchMapTo-spec.ts | 3 +- spec/operators/take-spec.ts | 2 +- spec/operators/takeLast-spec.ts | 2 +- spec/operators/throttle-spec.ts | 8 +- spec/operators/throttleTime-spec.ts | 1 - spec/operators/toPromise-spec.ts | 7 +- spec/operators/windowToggle-spec.ts | 2 +- spec/operators/windowWhen-spec.ts | 1 - spec/operators/withLatestFrom-spec.ts | 10 +- spec/operators/zip-spec.ts | 48 ++-- spec/operators/zipAll-spec.ts | 52 ++-- spec/subjects/AsyncSubject-spec.ts | 2 +- spec/subjects/ReplaySubject-spec.ts | 6 +- spec/util/Immediate-spec.ts | 89 ++++-- spec/util/MapPolyfill-spec.ts | 1 - spec/util/SymbolShim-spec.ts | 10 +- 65 files changed, 514 insertions(+), 467 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index fd7b93cc86..34bb30e030 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -139,6 +139,7 @@ module.exports = function (config) { // list of files / patterns to load in the browser files: [ + 'node_modules/babel-polyfill/dist/polyfill.js', 'tmp/helpers/marble-testing.js', 'tmp/helpers/test-helper.js', 'tmp/helpers/ajax-helper.js', diff --git a/package.json b/package.json index 657e464a3c..8d4e9decb9 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "build_docs": "npm run build_es6 && npm run tests2png && esdoc -c esdoc.json", "publish_docs": "./publish_docs.sh", "lint_perf": "eslint perf/", - "lint_spec": "eslint spec/", + "lint_spec": "tslint -c tslint.json spec/*.ts spec/**/*.ts spec/**/**/*.ts", "lint_src": "tslint -c tslint.json src/*.ts src/**/*.ts src/**/**/*.ts", "lint": "npm run lint_src && npm run lint_spec && npm run lint_perf", "copy_src": "cp -r src/ dist/cjs/src && cp -r src/ dist/amd/src && cp -r src/ dist/es6/src", @@ -93,6 +93,7 @@ }, "homepage": "https://github.com/ReactiveX/RxJS", "devDependencies": { + "babel-polyfill": "6.5.0", "benchmark": "1.0.0", "benchpress": "2.0.0-beta.1", "browserify": "13.0.0", diff --git a/spec/Notification-spec.ts b/spec/Notification-spec.ts index 4e68619c0d..2cf0d1c972 100644 --- a/spec/Notification-spec.ts +++ b/spec/Notification-spec.ts @@ -1,6 +1,6 @@ import * as Rx from '../dist/cjs/Rx'; import {expectObservable} from './helpers/marble-testing'; -import {it, DoneSignature} from './helpers/test-helper'; +import {it} from './helpers/test-helper'; const Notification = Rx.Notification; diff --git a/spec/Observable-spec.ts b/spec/Observable-spec.ts index c77472d81d..afafcf0b3c 100644 --- a/spec/Observable-spec.ts +++ b/spec/Observable-spec.ts @@ -1,11 +1,10 @@ import * as Rx from '../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from './helpers/marble-testing'; import {it, DoneSignature} from './helpers/test-helper'; const Subscriber = Rx.Subscriber; const Observable = Rx.Observable; -declare var __root__: any; +declare const __root__: any; function expectFullObserver(val) { expect(typeof val).toBe('object'); @@ -28,8 +27,8 @@ describe('Observable', () => { describe('forEach', () => { it('should iterate and return a Promise', (done: DoneSignature) => { - const expected = [1,2,3]; - const result = Observable.of(1,2,3).forEach(function (x) { + const expected = [1, 2, 3]; + const result = Observable.of(1, 2, 3).forEach(function (x) { expect(x).toBe(expected.shift()); }, null, Promise) .then(done); @@ -67,9 +66,9 @@ describe('Observable', () => { }); it('should accept a thisArg argument', (done: DoneSignature) => { - const expected = [1,2,3]; + const expected = [1, 2, 3]; const thisArg = {}; - const result = Observable.of(1,2,3).forEach(function (x) { + const result = Observable.of(1, 2, 3).forEach(function (x) { expect(this).toBe(thisArg); expect(x).toBe(expected.shift()); }, thisArg, Promise) @@ -80,7 +79,7 @@ describe('Observable', () => { it('should reject promise if nextHandler throws', (done: DoneSignature) => { const results = []; - Observable.of(1,2,3).forEach((x: number) => { + Observable.of(1, 2, 3).forEach((x: number) => { if (x === 3) { throw new Error('NO THREES!'); } @@ -88,7 +87,7 @@ describe('Observable', () => { }, null) .then(done.fail, function (err) { expect(err).toEqual(new Error('NO THREES!')); - expect(results).toEqual([1,2]); + expect(results).toEqual([1, 2]); }) .then(done); }); @@ -142,7 +141,9 @@ describe('Observable', () => { }; }); - const sub = source.subscribe(() => { }); + const sub = source.subscribe(() => { + //noop + }); expect(sub instanceof Rx.Subscription).toBe(true); expect(unsubscribeCalled).toBe(false); expect(typeof sub.unsubscribe).toBe('function'); @@ -209,7 +210,7 @@ describe('Observable', () => { it('should accept an anonymous observer with just a next function and call the next function in the context' + ' of the anonymous observer', (done: DoneSignature) => { //intentionally not using lambda to avoid typescript's this context capture - var o = { + const o = { next: function next(x) { expect(this).toBe(o); expect(x).toBe(1); @@ -223,7 +224,7 @@ describe('Observable', () => { it('should accept an anonymous observer with just an error function and call the error function in the context' + ' of the anonymous observer', (done: DoneSignature) => { //intentionally not using lambda to avoid typescript's this context capture - var o = { + const o = { error: function error(err) { expect(this).toBe(o); expect(err).toBe('bad'); @@ -237,7 +238,7 @@ describe('Observable', () => { it('should accept an anonymous observer with just a complete function and call the complete function in the' + ' context of the anonymous observer', (done: DoneSignature) => { //intentionally not using lambda to avoid typescript's this context capture - var o = { + const o = { complete: function complete() { expect(this).toBe(o); done(); @@ -260,7 +261,7 @@ describe('Observable', () => { let unsubscribeCalled = false; //intentionally not using lambda to avoid typescript's this context capture - var o = { + const o = { next: function next(x) { expect(this).toBe(o); throw x; @@ -293,7 +294,9 @@ describe('Observable', () => { describe('Observable.create', () => { it('should create an Observable', () => { - const result = Observable.create(() => { }); + const result = Observable.create(() => { + //noop + }); expect(result instanceof Observable).toBe(true); }); @@ -306,14 +309,16 @@ describe('Observable.create', () => { }); expect(called).toBe(false); - result.subscribe(() => { }); + result.subscribe(() => { + //noop + }); expect(called).toBe(true); }); }); describe('Observable.lift', () => { it('should be overrideable in a custom Observable type that composes', (done: DoneSignature) => { - class MyCustomObservable extends Rx.Observable{ + class MyCustomObservable extends Rx.Observable { lift(operator: Rx.Operator): Rx.Observable { const observable = new MyCustomObservable(); (observable).source = this; @@ -357,7 +362,7 @@ describe('Observable.lift', () => { // The custom Operator class LogOperator extends Rx.Operator { - constructor(private childOperator: Rx.Operator) { + constructor(private childOperator: Rx.Operator) { super(); } diff --git a/spec/Subject-spec.ts b/spec/Subject-spec.ts index 6db731037e..8f3a722599 100644 --- a/spec/Subject-spec.ts +++ b/spec/Subject-spec.ts @@ -1,9 +1,8 @@ import * as Rx from '../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from './helpers/marble-testing'; +import {hot, expectObservable} from './helpers/marble-testing'; import {it, DoneSignature} from './helpers/test-helper'; const Subject = Rx.Subject; -const asap = Rx.Scheduler.asap; const Observable = Rx.Observable; describe('Subject', () => { @@ -94,8 +93,8 @@ describe('Subject', () => { subscription3.unsubscribe(); - expect(results1).toEqual([5,6,7]); - expect(results2).toEqual([6,7,8]); + expect(results1).toEqual([5, 6, 7]); + expect(results2).toEqual([6, 7, 8]); expect(results3).toEqual([11]); }); @@ -142,8 +141,8 @@ describe('Subject', () => { subscription3.unsubscribe(); - expect(results1).toEqual([5,6,7]); - expect(results2).toEqual([6,7,'C']); + expect(results1).toEqual([5, 6, 7]); + expect(results2).toEqual([6, 7, 'C']); expect(results3).toEqual(['C']); }); @@ -190,8 +189,8 @@ describe('Subject', () => { subscription3.unsubscribe(); - expect(results1).toEqual([5,6,7]); - expect(results2).toEqual([6,7,'E']); + expect(results1).toEqual([5, 6, 7]); + expect(results2).toEqual([6, 7, 'E']); expect(results3).toEqual(['E']); }); @@ -263,15 +262,15 @@ describe('Subject', () => { subject.unsubscribe(); expect(() => { - const subscription3 = subject.subscribe( + subject.subscribe( function (x) { results3.push(x); }, function (e) { results3.push('E'); }, () => { results3.push('C'); } ); }).toThrow(); - expect(results1).toEqual([1,2,3,4,5]); - expect(results2).toEqual([3,4,5]); + expect(results1).toEqual([1, 2, 3, 4, 5]); + expect(results2).toEqual([3, 4, 5]); expect(results3).toEqual([]); }); @@ -307,9 +306,9 @@ describe('Subject', () => { auxSubject.next('c'); auxSubject.next('d'); - expect(results1).toEqual([1,2,3]); + expect(results1).toEqual([1, 2, 3]); expect(subscription2.isUnsubscribed).toBe(true); - expect(results2).toEqual(['a','b']); + expect(results2).toEqual(['a', 'b']); }); it('should allow ad-hoc subscription to be removed from itself', () => { @@ -345,9 +344,9 @@ describe('Subject', () => { auxSubject.next('c'); auxSubject.next('d'); - expect(results1).toEqual([1,2,3]); + expect(results1).toEqual([1, 2, 3]); expect(subscription2.isUnsubscribed).toBe(false); - expect(results2).toEqual(['a','b','c','d']); + expect(results2).toEqual(['a', 'b', 'c', 'd']); }); it('should not allow values to be nexted after a return', (done: DoneSignature) => { @@ -367,9 +366,11 @@ describe('Subject', () => { const subject = new Subject(); const sub1 = subject.subscribe(function (x) { + //noop }); const sub2 = subject.subscribe(function (x) { + //noop }); expect(subject.observers.length).toBe(2); @@ -382,7 +383,7 @@ describe('Subject', () => { it('should have a static create function that works', () => { expect(typeof Subject.create).toBe('function'); - const source = Observable.of(1,2,3,4,5); + const source = Observable.of(1, 2, 3, 4, 5); const nexts = []; const output = []; @@ -418,17 +419,17 @@ describe('Subject', () => { sub.next('c'); sub.complete(); - expect(nexts).toEqual(['a','b','c']); + expect(nexts).toEqual(['a', 'b', 'c']); expect(complete).toBe(true); expect(error).toBe(undefined); - expect(output).toEqual([1,2,3,4,5]); + expect(output).toEqual([1, 2, 3, 4, 5]); expect(outputComplete).toBe(true); }); it('should have a static create function that works also to raise errors', () => { expect(typeof Subject.create).toBe('function'); - const source = Observable.of(1,2,3,4,5); + const source = Observable.of(1, 2, 3, 4, 5); const nexts = []; const output = []; @@ -464,11 +465,11 @@ describe('Subject', () => { sub.next('c'); sub.error('boom'); - expect(nexts).toEqual(['a','b','c']); + expect(nexts).toEqual(['a', 'b', 'c']); expect(complete).toBe(false); expect(error).toBe('boom'); - expect(output).toEqual([1,2,3,4,5]); + expect(output).toEqual([1, 2, 3, 4, 5]); expect(outputComplete).toBe(true); }); diff --git a/spec/helpers/ajax-helper.ts b/spec/helpers/ajax-helper.ts index 4bb943ffb3..3d32f5d01a 100644 --- a/spec/helpers/ajax-helper.ts +++ b/spec/helpers/ajax-helper.ts @@ -30,7 +30,7 @@ export class MockWebSocket { const sent = this.sent; const length = sent.length; - return length > 0 ? sent[length -1] : undefined; + return length > 0 ? sent[length - 1] : undefined; } triggerClose(e: any): void { @@ -75,8 +75,8 @@ export class MockWebSocket { removeEventListener(name: string, handler: any): void { const lookup = this.handlers[name]; - if(lookup) { - for (let i = lookup.length - 1; i--;) { + if (lookup) { + for (let i = lookup.length - 1; i--; ) { if (lookup[i] === handler) { lookup.splice(i, 1); } @@ -121,7 +121,6 @@ export class MockXMLHttpRequest { private eventHandlers: Array = []; private readyState: number = 0; - private async: any; private user: any; private password: any; @@ -163,7 +162,7 @@ export class MockXMLHttpRequest { } removeEventListener(name: string, handler: any): void { - for (let i = this.eventHandlers.length - 1; i--;) { + for (let i = this.eventHandlers.length - 1; i--; ) { let eh = this.eventHandlers[i]; if (eh.name === name && eh.handler === handler) { this.eventHandlers.splice(i, 1); diff --git a/spec/observables/bindCallback-spec.ts b/spec/observables/bindCallback-spec.ts index 3c7ad5d150..5e77ba93c7 100644 --- a/spec/observables/bindCallback-spec.ts +++ b/spec/observables/bindCallback-spec.ts @@ -233,7 +233,7 @@ describe('Observable.bindCallback', () => { results1.push('done'); }); - source.subscribe((x: number) =>{ + source.subscribe((x: number) => { results2.push(x); }, null, () => { results2.push('done'); diff --git a/spec/observables/bindNodeCallback-spec.ts b/spec/observables/bindNodeCallback-spec.ts index c1d88ad703..b2720a422f 100644 --- a/spec/observables/bindNodeCallback-spec.ts +++ b/spec/observables/bindNodeCallback-spec.ts @@ -1,5 +1,4 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, DoneSignature} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; diff --git a/spec/observables/dom/webSocket-spec.ts b/spec/observables/dom/webSocket-spec.ts index 608c896681..6f9b7e3d29 100644 --- a/spec/observables/dom/webSocket-spec.ts +++ b/spec/observables/dom/webSocket-spec.ts @@ -5,7 +5,7 @@ import {it} from '../../helpers/test-helper'; declare const __root__: any; const Observable = Rx.Observable; -var __ws: any; +let __ws: any; function setupMockWebSocket() { MockWebSocket.clearSockets(); diff --git a/spec/observables/zip-spec.ts b/spec/observables/zip-spec.ts index b1600a6e10..5bf2508589 100644 --- a/spec/observables/zip-spec.ts +++ b/spec/observables/zip-spec.ts @@ -535,7 +535,7 @@ describe('Observable.zip', () => { const bsubs = '^ !'; const expected = '-----x--#'; - expectObservable(Observable.zip(a,b)).toBe(expected, { x: [1, 2] }, 'too bad'); + expectObservable(Observable.zip(a, b)).toBe(expected, { x: [1, 2] }, 'too bad'); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -570,7 +570,7 @@ describe('Observable.zip', () => { const r = [[1, 4], [2, 5], [3, 6]]; let i = 0; - Observable.zip(a, b).subscribe((vals:Array) => { + Observable.zip(a, b).subscribe((vals: Array) => { (expect(vals)).toDeepEqual(r[i++]); }, null, done); }); diff --git a/spec/operators/buffer-spec.ts b/spec/operators/buffer-spec.ts index 372dcb4377..54dda60d32 100644 --- a/spec/operators/buffer-spec.ts +++ b/spec/operators/buffer-spec.ts @@ -10,9 +10,9 @@ describe('Observable.prototype.buffer()', () => { const b = hot('-----B-----B-----B-|'); const expected = '-----x-----y-----z-|'; const expectedValues = { - x: ['a','b','c'], - y: ['d','e','f'], - z: ['g','h','i'] + x: ['a', 'b', 'c'], + y: ['d', 'e', 'f'], + z: ['g', 'h', 'i'] }; expectObservable(a.buffer(b)).toBe(expected, expectedValues); }); @@ -213,7 +213,7 @@ describe('Observable.prototype.buffer()', () => { const bsubs = '^ !'; const expected = '-----(x|)'; const expectedValues = { - x: ['a','b','c'], + x: ['a', 'b', 'c'], }; expectObservable(a.buffer(b).take(1)).toBe(expected, expectedValues); diff --git a/spec/operators/bufferTime-spec.ts b/spec/operators/bufferTime-spec.ts index 5fe1964de7..299e7b6978 100644 --- a/spec/operators/bufferTime-spec.ts +++ b/spec/operators/bufferTime-spec.ts @@ -12,8 +12,8 @@ describe('Observable.prototype.bufferTime', () => { const t = time( '----------|'); const expected = '----------w---------x---------y--(z|)'; const values = { - w: ['a','b'], - x: ['c','d','e'], + w: ['a', 'b'], + x: ['c', 'd', 'e'], y: ['f', 'g'], z: [] }; @@ -29,7 +29,7 @@ describe('Observable.prototype.bufferTime', () => { const t = time( '--------------------------------|'); const expected = '--------------------------------x-------------------------------y---(z|)'; const values = { - x: ['a','b','c'], + x: ['a', 'b', 'c'], y: ['d', 'e', 'g'], z: [] }; @@ -197,7 +197,7 @@ describe('Observable.prototype.bufferTime', () => { const t = time( '----------|'); const expected = '----------w----#'; const values = { - w: ['a','b'] + w: ['a', 'b'] }; const result = e1.bufferTime(t, null, rxTestScheduler); diff --git a/spec/operators/bufferToggle-spec.ts b/spec/operators/bufferToggle-spec.ts index 5a5b7fab88..3d7ca86080 100644 --- a/spec/operators/bufferToggle-spec.ts +++ b/spec/operators/bufferToggle-spec.ts @@ -11,7 +11,7 @@ describe('Observable.prototype.bufferToggle', () => { const e3 = hot('---------c---------------c-----|'); const expected = '---------x---------------y-----|'; const values = { - x: ['a','b'], + x: ['a', 'b'], y: ['f'], }; @@ -31,8 +31,8 @@ describe('Observable.prototype.bufferToggle', () => { const expected = '----------------------------q-------------r-------(s|)'; const values = { - q: ['c','d','e'], - r: ['f','g','h'], + q: ['c', 'd', 'e'], + r: ['f', 'g', 'h'], s: ['i'] }; const innerVals = ['x', 'y', 'z']; @@ -56,9 +56,9 @@ describe('Observable.prototype.bufferToggle', () => { ' ^ ! ']; const expected = '-----------------ij----------------(k|) '; const values = { - i: ['b','c','d','e'], + i: ['b', 'c', 'd', 'e'], j: ['e'], - k: ['g','h'] + k: ['g', 'h'] }; let i = 0; @@ -84,9 +84,9 @@ describe('Observable.prototype.bufferToggle', () => { sub: ' ^ ! '}]; // eslint-disable-line key-spacing const expected = '-----------------ij----------------(k|)'; const values = { - i: ['b','c','d','e'], + i: ['b', 'c', 'd', 'e'], j: ['e'], - k: ['g','h'] + k: ['g', 'h'] }; let i = 0; @@ -109,9 +109,9 @@ describe('Observable.prototype.bufferToggle', () => { cold( '---------------|')]; const expected = '-----------------ij----------------(k|)'; const values = { - i: ['b','c','d','e'], + i: ['b', 'c', 'd', 'e'], j: ['e'], - k: ['g','h'] + k: ['g', 'h'] }; let i = 0; @@ -133,7 +133,7 @@ describe('Observable.prototype.bufferToggle', () => { const expected = '----------- '; const unsub = ' ! '; const values = { - i: ['b','c','d','e'] + i: ['b', 'c', 'd', 'e'] }; let i = 0; @@ -157,7 +157,7 @@ describe('Observable.prototype.bufferToggle', () => { const expected = '-----------------i- '; const unsub = ' ! '; const values = { - i: ['b','c','d','e'] + i: ['b', 'c', 'd', 'e'] }; let i = 0; @@ -227,7 +227,7 @@ describe('Observable.prototype.bufferToggle', () => { ' ^ ! ']; const expected = '-----------------i-# '; const values = { - i: ['b','c','d','e'] + i: ['b', 'c', 'd', 'e'] }; let i = 0; @@ -250,7 +250,7 @@ describe('Observable.prototype.bufferToggle', () => { ' ^ ! ']; const expected = '-----------------i-# '; const values = { - i: ['b','c','d','e'] + i: ['b', 'c', 'd', 'e'] }; let i = 0; diff --git a/spec/operators/bufferWhen-spec.ts b/spec/operators/bufferWhen-spec.ts index 8d93c92f17..225173be16 100644 --- a/spec/operators/bufferWhen-spec.ts +++ b/spec/operators/bufferWhen-spec.ts @@ -11,8 +11,8 @@ describe('Observable.prototype.bufferWhen', () => { // --------------(s|) const expected = '--------------x-------------y-----(z|)'; const values = { - x: ['b','c','d'], - y: ['e','f','g'], + x: ['b', 'c', 'd'], + y: ['e', 'f', 'g'], z: [] }; @@ -28,8 +28,8 @@ describe('Observable.prototype.bufferWhen', () => { cold( '-------------(s|)')]; const expected = '---------------x---------y---------(z|) '; const values = { - x: ['b','c','d'], - y: ['e','f','g'], + x: ['b', 'c', 'd'], + y: ['e', 'f', 'g'], z: ['h'] }; @@ -52,8 +52,8 @@ describe('Observable.prototype.bufferWhen', () => { sub: ' ^ ! '}]; // eslint-disable-line key-spacing const expected = '---------------x---------y---------(z|)'; const values = { - x: ['b','c','d'], - y: ['e','f','g'], + x: ['b', 'c', 'd'], + y: ['e', 'f', 'g'], z: ['h'] }; @@ -79,8 +79,8 @@ describe('Observable.prototype.bufferWhen', () => { ' ^ ! ']; const expected = '---------------x---------y---------(z|)'; const values = { - x: ['b','c','d'], - y: ['e','f','g'], + x: ['b', 'c', 'd'], + y: ['e', 'f', 'g'], z: ['h'] }; @@ -106,7 +106,7 @@ describe('Observable.prototype.bufferWhen', () => { ' ^ ! ']; const expected = '---------------x--- '; const values = { - x: ['b','c','d'] + x: ['b', 'c', 'd'] }; let i = 0; @@ -131,7 +131,7 @@ describe('Observable.prototype.bufferWhen', () => { const expected = '---------------x--- '; const unsub = ' ! '; const values = { - x: ['b','c','d'] + x: ['b', 'c', 'd'] }; let i = 0; @@ -156,7 +156,7 @@ describe('Observable.prototype.bufferWhen', () => { cold( '-------------(s|)')]; const closeSubs0 = '^ ! '; const expected = '---------------(x#) '; - const values = { x: ['b','c','d'] }; + const values = { x: ['b', 'c', 'd'] }; let i = 0; const result = e1.bufferWhen(() => { @@ -180,7 +180,7 @@ describe('Observable.prototype.bufferWhen', () => { const closeSubs = ['^ ! ', ' (^!) ']; const expected = '---------------(x#) '; - const values = { x: ['b','c','d'] }; + const values = { x: ['b', 'c', 'd'] }; let i = 0; const result = e1.bufferWhen(() => closings[i++]); @@ -200,7 +200,7 @@ describe('Observable.prototype.bufferWhen', () => { const closeSubs = ['^ ! ', ' ^ ! ']; const expected = '---------------x-----# '; - const values = { x: ['b','c','d'] }; + const values = { x: ['b', 'c', 'd'] }; let i = 0; const result = e1.bufferWhen(() => closings[i++]); @@ -219,7 +219,7 @@ describe('Observable.prototype.bufferWhen', () => { ' ^ !']; const expected = '---------------x--------#'; const values = { - x: ['b','c','d'] + x: ['b', 'c', 'd'] }; const result = e1.bufferWhen(() => e2); @@ -286,7 +286,7 @@ describe('Observable.prototype.bufferWhen', () => { const e2 = cold('-'); const expected = '-----------------------------------(x|)'; const values = { - x: ['b','c','d','e','f','g','h'] + x: ['b', 'c', 'd', 'e', 'f', 'g', 'h'] }; expectObservable(e1.bufferWhen(() => e2)).toBe(expected, values); @@ -319,7 +319,7 @@ describe('Observable.prototype.bufferWhen', () => { const e2subs = '(^!)'; const expected = '#'; const values = { - x: ['b','c','d','e','f','g','h'] + x: ['b', 'c', 'd', 'e', 'f', 'g', 'h'] }; const result = e1.bufferWhen(() => e2); @@ -337,8 +337,8 @@ describe('Observable.prototype.bufferWhen', () => { // ---------------(s|) const expected = '---------------x-----'; const values = { - x: ['b','c','d'], - y: ['e','f','g','h'], + x: ['b', 'c', 'd'], + y: ['e', 'f', 'g', 'h'], z: [] }; diff --git a/spec/operators/cache-spec.ts b/spec/operators/cache-spec.ts index 8ad316e014..de2bc0977b 100644 --- a/spec/operators/cache-spec.ts +++ b/spec/operators/cache-spec.ts @@ -1,10 +1,8 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; -import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, asDiagram} from '../helpers/test-helper'; +import {hot, cold, time, expectObservable} from '../helpers/marble-testing'; +import {it} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; -const Observable = Rx.Observable; -const asap = Rx.Scheduler.asap; describe('Observable.prototype.cache', () => { it('should replay values upon subscription', () => { diff --git a/spec/operators/catch-spec.ts b/spec/operators/catch-spec.ts index 4a31278737..96547bddbf 100644 --- a/spec/operators/catch-spec.ts +++ b/spec/operators/catch-spec.ts @@ -218,10 +218,10 @@ describe('Observable.prototype.catch()', () => { expect(err).toBe('bad'); return Observable.empty(); }) - .subscribe(() => { }, - (err: any) => { + .subscribe(() => { + //noop + }, (err: any) => { done.fail('should not be called'); - }, - done); + }, done); }); }); diff --git a/spec/operators/combineLatest-spec.ts b/spec/operators/combineLatest-spec.ts index 214a0f4874..460fda786e 100644 --- a/spec/operators/combineLatest-spec.ts +++ b/spec/operators/combineLatest-spec.ts @@ -3,7 +3,6 @@ import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marbl import {it, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; -const queueScheduler = Rx.Scheduler.queue; describe('Observable.prototype.combineLatest', () => { asDiagram('combineLatest')('should combine events from two cold observables', () => { diff --git a/spec/operators/concatAll-spec.ts b/spec/operators/concatAll-spec.ts index 2e49c16b5e..6a5cd7777e 100644 --- a/spec/operators/concatAll-spec.ts +++ b/spec/operators/concatAll-spec.ts @@ -31,7 +31,7 @@ describe('Observable.prototype.concatAll()', () => { (x: number) => { res.push(x); }, (err: any) => { done.fail('should not be called.'); }, () => { - expect(res).toEqual([0,1,2,3]); + expect(res).toEqual([0, 1, 2, 3]); done(); }); }, 2000); diff --git a/spec/operators/concatMap-spec.ts b/spec/operators/concatMap-spec.ts index 80e4178e38..7f9f5d0ef1 100644 --- a/spec/operators/concatMap-spec.ts +++ b/spec/operators/concatMap-spec.ts @@ -40,7 +40,7 @@ describe('Observable.prototype.concatMap()', () => { ' ^ !']; const expected = '---i-j-k-l---i-j-k-l---i-j-k-l---i-j-k-l-|'; - const result = e1.concatMap((value: any) =>inner); + const result = e1.concatMap((value: any) => inner); expectObservable(result).toBe(expected, values); expectSubscriptions(inner.subscriptions).toBe(innersubs); @@ -637,7 +637,7 @@ describe('Observable.prototype.concatMap()', () => { }); it('should map values to constant resolved promises and concatenate', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = (value: any) => Observable.from(Promise.resolve(42)); const results = []; @@ -647,13 +647,13 @@ describe('Observable.prototype.concatMap()', () => { }, (err: any) => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([42,42,42,42]); + expect(results).toEqual([42, 42, 42, 42]); done(); }); }); it('should map values to constant rejected promises and concatenate', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = (value: any) => Observable.from(Promise.reject(42)); source.concatMap(project).subscribe( @@ -668,7 +668,7 @@ describe('Observable.prototype.concatMap()', () => { }); it('should map values to resolved promises and concatenate', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = (value: number, index: number) => Observable.from(Promise.resolve(value + index)); const results = []; @@ -678,13 +678,13 @@ describe('Observable.prototype.concatMap()', () => { }, (err: any) => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([4,4,4,4]); + expect(results).toEqual([4, 4, 4, 4]); done(); }); }); it('should map values to rejected promises and concatenate', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = (value: number, index: number) => Observable.from(Promise.reject('' + value + '-' + index)); source.concatMap(project).subscribe( @@ -699,7 +699,7 @@ describe('Observable.prototype.concatMap()', () => { }); it('should concatMap values to resolved promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const resultSelectorCalledWith = []; const project = (value: number, index: number) => Observable.from((Promise.resolve([value, index]))); @@ -710,10 +710,10 @@ describe('Observable.prototype.concatMap()', () => { const results = []; const expectedCalls = [ - [4, [4,0], 0, 0], - [3, [3,1], 1, 0], - [2, [2,2], 2, 0], - [1, [1,3], 3, 0] + [4, [4, 0], 0, 0], + [3, [3, 1], 1, 0], + [2, [2, 2], 2, 0], + [1, [1, 3], 3, 0] ]; source.concatMap(project, resultSelector).subscribe( (x: any) => { @@ -721,14 +721,14 @@ describe('Observable.prototype.concatMap()', () => { }, (err: any) => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([8,8,8,8]); + expect(results).toEqual([8, 8, 8, 8]); (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); done(); }); }); it('should concatMap values to rejected promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = (value: number, index: number) => Observable.from(Promise.reject('' + value + '-' + index)); const resultSelector = () => { diff --git a/spec/operators/concatMapTo-spec.ts b/spec/operators/concatMapTo-spec.ts index 2016b7ee52..51096a0b8c 100644 --- a/spec/operators/concatMapTo-spec.ts +++ b/spec/operators/concatMapTo-spec.ts @@ -300,7 +300,7 @@ describe('Observable.prototype.concatMapTo()', () => { }); it('should map values to constant resolved promises and concatenate', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const results = []; source.concatMapTo(Observable.from(Promise.resolve(42))).subscribe( @@ -311,13 +311,13 @@ describe('Observable.prototype.concatMapTo()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([42,42,42,42]); + expect(results).toEqual([42, 42, 42, 42]); done(); }); }); it('should map values to constant rejected promises and concatenate', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); source.concatMapTo(Observable.from(Promise.reject(42))).subscribe( (x: any) => { @@ -333,7 +333,7 @@ describe('Observable.prototype.concatMapTo()', () => { }); it('should concatMapTo values to resolved promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const resultSelectorCalledWith = []; const inner = Observable.from(Promise.resolve(42)); const resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { @@ -356,14 +356,14 @@ describe('Observable.prototype.concatMapTo()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([8,8,8,8]); + expect(results).toEqual([8, 8, 8, 8]); (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); done(); }); }); it('should concatMapTo values to rejected promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const inner = Observable.from(Promise.reject(42)); const resultSelector = () => { throw 'this should not be called'; diff --git a/spec/operators/debounce-spec.ts b/spec/operators/debounce-spec.ts index e841dddf48..80ddd54685 100644 --- a/spec/operators/debounce-spec.ts +++ b/spec/operators/debounce-spec.ts @@ -353,7 +353,7 @@ describe('Observable.prototype.debounce()', () => { Observable.timer(10).mapTo(3), Observable.timer(100).mapTo(4) ); - const expected = [1,2,3,4]; + const expected = [1, 2, 3, 4]; e1.debounce(() => { return new Promise((resolve: any) => { resolve(42); }); @@ -372,14 +372,14 @@ describe('Observable.prototype.debounce()', () => { Observable.timer(10).mapTo(3), Observable.timer(100).mapTo(4) ); - const expected = [1,2]; + const expected = [1, 2]; const error = new Error('error'); e1.debounce((x: number) => { if (x === 3) { - return new Promise((resolve: any, reject: any) => {reject(error);}); + return new Promise((resolve: any, reject: any) => { reject(error); }); } else { - return new Promise((resolve: any) => {resolve(42);}); + return new Promise((resolve: any) => { resolve(42); }); } }).subscribe((x: number) => { expect(x).toEqual(expected.shift()); }, diff --git a/spec/operators/delayWhen-spec.ts b/spec/operators/delayWhen-spec.ts index 6cd77adac5..d56dae56ca 100644 --- a/spec/operators/delayWhen-spec.ts +++ b/spec/operators/delayWhen-spec.ts @@ -3,7 +3,6 @@ import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marbl import {it, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; -const Observable = Rx.Observable; describe('Observable.prototype.delayWhen()', () => { asDiagram('delay(durationSelector)')('should delay by duration selector', () => { diff --git a/spec/operators/do-spec.ts b/spec/operators/do-spec.ts index e6d932f676..5da6153942 100644 --- a/spec/operators/do-spec.ts +++ b/spec/operators/do-spec.ts @@ -39,10 +39,10 @@ describe('Observable.prototype.do()', () => { }); it('should handle everything with an observer', () => { - const expected = [1,2,3]; + const expected = [1, 2, 3]; const results = []; let completeCalled = false; - Observable.of(1,2,3) + Observable.of(1, 2, 3) .do({ next: (x: number) => { results.push(x); @@ -61,7 +61,7 @@ describe('Observable.prototype.do()', () => { }); it('should handle everything with a Subject', () => { - const expected = [1,2,3]; + const expected = [1, 2, 3]; const results = []; let completeCalled = false; const subject = new Subject(); @@ -78,7 +78,7 @@ describe('Observable.prototype.do()', () => { } }); - Observable.of(1,2,3) + Observable.of(1, 2, 3) .do(subject) .subscribe(); diff --git a/spec/operators/elementAt-spec.ts b/spec/operators/elementAt-spec.ts index ff44e4f564..0ba8565fe4 100644 --- a/spec/operators/elementAt-spec.ts +++ b/spec/operators/elementAt-spec.ts @@ -96,7 +96,7 @@ describe('Observable.prototype.elementAt', () => { }); it('should throw if index is smaller than zero', () => { - expect(() => { (Observable.range(0,10)).elementAt(-1); }) + expect(() => { (Observable.range(0, 10)).elementAt(-1); }) .toThrow(new Rx.ArgumentOutOfRangeError()); }); diff --git a/spec/operators/every-spec.ts b/spec/operators/every-spec.ts index d8eea2810e..febaa971c5 100644 --- a/spec/operators/every-spec.ts +++ b/spec/operators/every-spec.ts @@ -35,7 +35,7 @@ describe('Observable.prototype.every()', () => { it('should accept thisArg with array observables', () => { const thisArg = {}; - Observable.of(1,2,3,4).every(function (value: number, index: number) { + Observable.of(1, 2, 3, 4).every(function (value: number, index: number) { expect(this).toBe(thisArg); return true; }, thisArg).subscribe(); diff --git a/spec/operators/exhaust-spec.ts b/spec/operators/exhaust-spec.ts index 4452aba128..a5954ed134 100644 --- a/spec/operators/exhaust-spec.ts +++ b/spec/operators/exhaust-spec.ts @@ -3,7 +3,6 @@ import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marbl import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; -const queueScheduler = Rx.Scheduler.queue; describe('Observable.prototype.exhaust()', () => { asDiagram('exhaust')('should handle a hot observable of hot observables', () => { diff --git a/spec/operators/exhaustMap-spec.ts b/spec/operators/exhaustMap-spec.ts index c2454d15a5..634cc46edf 100644 --- a/spec/operators/exhaustMap-spec.ts +++ b/spec/operators/exhaustMap-spec.ts @@ -1,19 +1,18 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, asDiagram} from '../helpers/test-helper'; +import {it} from '../helpers/test-helper'; const Observable = Rx.Observable; -const queueScheduler = Rx.Scheduler.queue; describe('Observable.prototype.exhaustMap()', () => { it('should handle outer throw', () => { - var x = cold('--a--b--c--|'); - var xsubs = []; - var e1 = cold('#'); - var e1subs = '(^!)'; - var expected = '#'; + const x = cold('--a--b--c--|'); + const xsubs = []; + const e1 = cold('#'); + const e1subs = '(^!)'; + const expected = '#'; - var result = (e1).exhaustMap(() => x); + const result = (e1).exhaustMap(() => x); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -21,26 +20,26 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should handle outer empty', () => { - var x = cold('--a--b--c--|'); - var xsubs = []; - var e1 = cold('|'); - var e1subs = '(^!)'; - var expected = '|'; + const x = cold('--a--b--c--|'); + const xsubs = []; + const e1 = cold('|'); + const e1subs = '(^!)'; + const expected = '|'; - var result = (e1).exhaustMap(() => x); + const result = (e1).exhaustMap(() => x); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); it('should handle outer never', () => { - var x = cold('--a--b--c--|'); - var xsubs = []; - var e1 = cold('-'); - var e1subs = '^'; - var expected = '-'; + const x = cold('--a--b--c--|'); + const xsubs = []; + const e1 = cold('-'); + const e1subs = '^'; + const expected = '-'; - var result = (e1).exhaustMap(() => x); + const result = (e1).exhaustMap(() => x); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -48,11 +47,11 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should raise error if project throws', () => { - var e1 = hot('---x---------y-----------------z-------------|'); - var e1subs = '^ !'; - var expected = '---#'; + const e1 = hot('---x---------y-----------------z-------------|'); + const e1subs = '^ !'; + const expected = '---#'; - var result = (e1).exhaustMap((value: any) => { + const result = (e1).exhaustMap((value: any) => { throw 'error'; }); @@ -61,13 +60,13 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should raise error if selector throws', () => { - var x = cold( '--a--b--c--| '); - var xsubs = ' ^ ! '; - var e1 = hot('---x---------y----z----|'); - var e1subs = '^ ! '; - var expected = '-----# '; + const x = cold( '--a--b--c--| '); + const xsubs = ' ^ ! '; + const e1 = hot('---x---------y----z----|'); + const e1subs = '^ ! '; + const expected = '-----# '; - var result = (e1).exhaustMap((value: any) => x, + const result = (e1).exhaustMap((value: any) => x, () => { throw 'error'; }); @@ -78,19 +77,19 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch with a selector function', () => { - var x = cold( '--a--b--c--| '); - var xsubs = ' ^ ! '; - var y = cold( '--d--e--f--| '); - var ysubs = []; - var z = cold( '--g--h--i--| '); - var zsubs = ' ^ ! '; - var e1 = hot('---x---------y-----------------z-------------|'); - var e1subs = '^ !'; - var expected = '-----a--b--c---------------------g--h--i-----|'; + const x = cold( '--a--b--c--| '); + const xsubs = ' ^ ! '; + const y = cold( '--d--e--f--| '); + const ysubs = []; + const z = cold( '--g--h--i--| '); + const zsubs = ' ^ ! '; + const e1 = hot('---x---------y-----------------z-------------|'); + const e1subs = '^ !'; + const expected = '-----a--b--c---------------------g--h--i-----|'; - var observableLookup = { x: x, y: y, z: z }; + const observableLookup = { x: x, y: y, z: z }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -100,20 +99,20 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner cold observables, outer is unsubscribed early', () => { - var x = cold( '--a--b--c--| '); - var xsubs = ' ^ ! '; - var y = cold( '--d--e--f--| '); - var ysubs = []; - var z = cold( '--g--h--i--| '); - var zsubs = ' ^ ! '; - var e1 = hot('---x---------y-----------------z-------------|'); - var unsub = ' ! '; - var e1subs = '^ ! '; - var expected = '-----a--b--c---------------------g- '; + const x = cold( '--a--b--c--| '); + const xsubs = ' ^ ! '; + const y = cold( '--d--e--f--| '); + const ysubs = []; + const z = cold( '--g--h--i--| '); + const zsubs = ' ^ ! '; + const e1 = hot('---x---------y-----------------z-------------|'); + const unsub = ' ! '; + const e1subs = '^ ! '; + const expected = '-----a--b--c---------------------g- '; - var observableLookup = { x: x, y: y, z: z }; + const observableLookup = { x: x, y: y, z: z }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result, unsub).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -123,20 +122,20 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should not break unsubscription chains when result is unsubscribed explicitly', () => { - var x = cold( '--a--b--c--| '); - var xsubs = ' ^ ! '; - var y = cold( '--d--e--f--| '); - var ysubs = []; - var z = cold( '--g--h--i--| '); - var zsubs = ' ^ ! '; - var e1 = hot('---x---------y-----------------z-------------|'); - var e1subs = '^ ! '; - var expected = '-----a--b--c---------------------g- '; - var unsub = ' ! '; - - var observableLookup = { x: x, y: y, z: z }; - - var result = (e1) + const x = cold( '--a--b--c--| '); + const xsubs = ' ^ ! '; + const y = cold( '--d--e--f--| '); + const ysubs = []; + const z = cold( '--g--h--i--| '); + const zsubs = ' ^ ! '; + const e1 = hot('---x---------y-----------------z-------------|'); + const e1subs = '^ ! '; + const expected = '-----a--b--c---------------------g- '; + const unsub = ' ! '; + + const observableLookup = { x: x, y: y, z: z }; + + const result = (e1) .mergeMap((x: any) => Observable.of(x)) .exhaustMap((value: any) => observableLookup[value]) .mergeMap((x: any) => Observable.of(x)); @@ -149,19 +148,19 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner cold observables, inner never completes', () => { - var x = cold( '--a--b--c--| '); - var xsubs = ' ^ ! '; - var y = cold( '--d--e--f--| '); - var ysubs = []; - var z = cold( '--g--h--i-----'); - var zsubs = ' ^ '; - var e1 = hot('---x---------y-----------------z---------| '); - var e1subs = '^ '; - var expected = '-----a--b--c---------------------g--h--i-----'; + const x = cold( '--a--b--c--| '); + const xsubs = ' ^ ! '; + const y = cold( '--d--e--f--| '); + const ysubs = []; + const z = cold( '--g--h--i-----'); + const zsubs = ' ^ '; + const e1 = hot('---x---------y-----------------z---------| '); + const e1subs = '^ '; + const expected = '-----a--b--c---------------------g--h--i-----'; - var observableLookup = { x: x, y: y, z: z }; + const observableLookup = { x: x, y: y, z: z }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -171,17 +170,17 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should handle a synchronous switch an stay on the first inner observable', () => { - var x = cold( '--a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--| '); - var ysubs = []; - var e1 = hot('---------(xy)----------------|'); - var e1subs = '^ !'; - var expected = '-----------a--b--c--d--e-----|'; + const x = cold( '--a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--| '); + const ysubs = []; + const e1 = hot('---------(xy)----------------|'); + const e1subs = '^ !'; + const expected = '-----------a--b--c--d--e-----|'; - var observableLookup = { x: x, y: y }; + const observableLookup = { x: x, y: y }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -190,17 +189,17 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner cold observables, one inner throws', () => { - var x = cold( '--a--b--c--d--# '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--'); - var ysubs = []; - var e1 = hot('---------x---------y---------| '); - var e1subs = '^ ! '; - var expected = '-----------a--b--c--d--# '; + const x = cold( '--a--b--c--d--# '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--'); + const ysubs = []; + const e1 = hot('---------x---------y---------| '); + const e1subs = '^ ! '; + const expected = '-----------a--b--c--d--# '; - var observableLookup = { x: x, y: y }; + const observableLookup = { x: x, y: y }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -209,19 +208,19 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner hot observables', () => { - var x = hot('-----a--b--c--d--e--| '); - var xsubs = ' ^ ! '; - var y = hot('--p-o-o-p-------f---g---h---i--| '); - var ysubs = []; - var z = hot('---z-o-o-m-------------j---k---l---m--|'); - var zsubs = ' ^ !'; - var e1 = hot('---------x----y-----z--------| '); - var e1subs = '^ !'; - var expected = '-----------c--d--e-----j---k---l---m--|'; + const x = hot('-----a--b--c--d--e--| '); + const xsubs = ' ^ ! '; + const y = hot('--p-o-o-p-------f---g---h---i--| '); + const ysubs = []; + const z = hot('---z-o-o-m-------------j---k---l---m--|'); + const zsubs = ' ^ !'; + const e1 = hot('---------x----y-----z--------| '); + const e1subs = '^ !'; + const expected = '-----------c--d--e-----j---k---l---m--|'; - var observableLookup = { x: x, y: y, z: z }; + const observableLookup = { x: x, y: y, z: z }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -231,17 +230,17 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner empty and empty', () => { - var x = cold('|'); - var y = cold('|'); - var xsubs = ' (^!) '; - var ysubs = ' (^!) '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ !'; - var expected = '-----------------------------|'; + const x = cold('|'); + const y = cold('|'); + const xsubs = ' (^!) '; + const ysubs = ' (^!) '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ !'; + const expected = '-----------------------------|'; - var observableLookup = { x: x, y: y }; + const observableLookup = { x: x, y: y }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -250,17 +249,17 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner empty and never', () => { - var x = cold('|'); - var y = cold('-'); - var xsubs = ' (^!) '; - var ysubs = ' ^ '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ '; - var expected = '------------------------------'; + const x = cold('|'); + const y = cold('-'); + const xsubs = ' (^!) '; + const ysubs = ' ^ '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ '; + const expected = '------------------------------'; - var observableLookup = { x: x, y: y }; + const observableLookup = { x: x, y: y }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -269,17 +268,17 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should never switch inner never', () => { - var x = cold('-'); - var y = cold('#'); - var xsubs = ' ^ '; - var ysubs = []; - var e1 = hot('---------x---------y----------|'); - var e1subs = '^ '; - var expected = '-------------------------------'; + const x = cold('-'); + const y = cold('#'); + const xsubs = ' ^ '; + const ysubs = []; + const e1 = hot('---------x---------y----------|'); + const e1subs = '^ '; + const expected = '-------------------------------'; - var observableLookup = { x: x, y: y }; + const observableLookup = { x: x, y: y }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -288,17 +287,17 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch inner empty and throw', () => { - var x = cold('|'); - var y = cold('#'); - var xsubs = ' (^!) '; - var ysubs = ' (^!) '; - var e1 = hot('---------x---------y---------|'); - var e1subs = '^ ! '; - var expected = '-------------------# '; + const x = cold('|'); + const y = cold('#'); + const xsubs = ' (^!) '; + const ysubs = ' (^!) '; + const e1 = hot('---------x---------y---------|'); + const e1subs = '^ ! '; + const expected = '-------------------# '; - var observableLookup = { x: x, y: y }; + const observableLookup = { x: x, y: y }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -307,15 +306,15 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should handle outer error', () => { - var x = cold( '--a--b--c--d--e--|'); - var xsubs = ' ^ ! '; - var e1 = hot('---------x---------# '); - var e1subs = '^ ! '; - var expected = '-----------a--b--c-# '; + const x = cold( '--a--b--c--d--e--|'); + const xsubs = ' ^ ! '; + const e1 = hot('---------x---------# '); + const e1subs = '^ ! '; + const expected = '-----------a--b--c-# '; - var observableLookup = { x: x }; + const observableLookup = { x: x }; - var result = (e1).exhaustMap((value: any) => observableLookup[value]); + const result = (e1).exhaustMap((value: any) => observableLookup[value]); expectObservable(result).toBe(expected); expectSubscriptions(x.subscriptions).toBe(xsubs); @@ -323,19 +322,19 @@ describe('Observable.prototype.exhaustMap()', () => { }); it('should switch with resultSelector goodness', () => { - var x = cold( '--a--b--c--d--e-| '); - var xsubs = ' ^ ! '; - var y = cold( '---f---g---h---i--| '); - var ysubs = []; - var z = cold( '---k---l---m---n--|'); - var zsubs = ' ^ !'; - var e1 = hot('--x---------y------z-| '); - var e1subs = '^ !'; - var expected = '----a--b--c--d--e-----k---l---m---n--|'; - - var observableLookup = { x: x, y: y, z: z }; - - var expectedValues = { + const x = cold( '--a--b--c--d--e-| '); + const xsubs = ' ^ ! '; + const y = cold( '---f---g---h---i--| '); + const ysubs = []; + const z = cold( '---k---l---m---n--|'); + const zsubs = ' ^ !'; + const e1 = hot('--x---------y------z-| '); + const e1subs = '^ !'; + const expected = '----a--b--c--d--e-----k---l---m---n--|'; + + const observableLookup = { x: x, y: y, z: z }; + + const expectedValues = { a: ['x', 'a', 0, 0], b: ['x', 'b', 0, 1], c: ['x', 'c', 0, 2], @@ -347,7 +346,7 @@ describe('Observable.prototype.exhaustMap()', () => { n: ['z', 'n', 1, 3], }; - var result = (e1).exhaustMap((value: any) => observableLookup[value], + const result = (e1).exhaustMap((value: any) => observableLookup[value], (innerValue, outerValue, innerIndex, outerIndex) => [innerValue, outerValue, innerIndex, outerIndex]); expectObservable(result).toBe(expected, expectedValues); diff --git a/spec/operators/groupBy-spec.ts b/spec/operators/groupBy-spec.ts index 480be27f26..84c1647fbe 100644 --- a/spec/operators/groupBy-spec.ts +++ b/spec/operators/groupBy-spec.ts @@ -100,7 +100,6 @@ describe('Observable.prototype.groupBy()', () => { const source = e1 .groupBy((val: string) => val.toLowerCase().trim()); - expectObservable(source).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); @@ -608,7 +607,9 @@ describe('Observable.prototype.groupBy()', () => { rxTestScheduler.schedule(() => { expectObservable(group).toBe(expected); }, 260); - }, () => {}); + }, () => { + //noop + }); expectSubscriptions(e1.subscriptions).toBe(subs); }); diff --git a/spec/operators/inspect-spec.ts b/spec/operators/inspect-spec.ts index 116e1ddc69..0bf3782ef4 100644 --- a/spec/operators/inspect-spec.ts +++ b/spec/operators/inspect-spec.ts @@ -3,7 +3,6 @@ import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marbl import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; -const Scheduler = Rx.Scheduler; describe('Observable.prototype.inspect()', () => { asDiagram('inspect')('should emit the last value in each time window', () => { @@ -286,7 +285,7 @@ describe('Observable.prototype.inspect()', () => { it('should inspect by promise resolves', (done: DoneSignature) => { const e1 = Observable.interval(10).take(5); - const expected = [0,1,2,3]; + const expected = [0, 1, 2, 3]; e1.inspect(() => { return new Promise((resolve: any) => { resolve(42); }); @@ -305,14 +304,14 @@ describe('Observable.prototype.inspect()', () => { it('should raise error when promise rejects', (done: DoneSignature) => { const e1 = Observable.interval(10).take(10); - const expected = [0,1,2]; + const expected = [0, 1, 2]; const error = new Error('error'); e1.inspect((x: number) => { if (x === 3) { - return new Promise((resolve: any, reject: any) => {reject(error);}); + return new Promise((resolve: any, reject: any) => { reject(error); }); } else { - return new Promise((resolve: any) => {resolve(42);}); + return new Promise((resolve: any) => { resolve(42); }); } }).subscribe( (x: number) => { diff --git a/spec/operators/inspectTime-spec.ts b/spec/operators/inspectTime-spec.ts index c226e62be6..793d1829a7 100644 --- a/spec/operators/inspectTime-spec.ts +++ b/spec/operators/inspectTime-spec.ts @@ -4,7 +4,6 @@ import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; const Observable = Rx.Observable; -const Scheduler = Rx.Scheduler; describe('Observable.prototype.inspectTime()', () => { asDiagram('inspectTime(50)')('should emit the last value in each time window', () => { diff --git a/spec/operators/let-spec.ts b/spec/operators/let-spec.ts index 0147749878..950d81750a 100644 --- a/spec/operators/let-spec.ts +++ b/spec/operators/let-spec.ts @@ -9,7 +9,7 @@ describe('let', () => { const foo = (observable: Rx.Observable) => observable.map((x: string) => x + x); Rx.Observable - .fromArray(['a','b']) + .fromArray(['a', 'b']) .let(foo) .subscribe(function (x) { expect(x).toBe(expected[i++]); diff --git a/spec/operators/map-spec.ts b/spec/operators/map-spec.ts index ca1de2af78..85b496e07f 100644 --- a/spec/operators/map-spec.ts +++ b/spec/operators/map-spec.ts @@ -229,9 +229,9 @@ describe('Observable.prototype.map()', () => { const filterer = new Filterer(); const r = a - .map(function (x) { return this.selector1(x);}, filterer) - .map(function (x) { return this.selector2(x);}, filterer) - .map(function (x) { return this.selector1(x);}, filterer); + .map(function (x) { return this.selector1(x); }, filterer) + .map(function (x) { return this.selector2(x); }, filterer) + .map(function (x) { return this.selector1(x); }, filterer); expectObservable(r).toBe(expected, values); expectSubscriptions(a.subscriptions).toBe(asubs); diff --git a/spec/operators/mergeMap-spec.ts b/spec/operators/mergeMap-spec.ts index 2a2efa899c..ef00fa64f5 100644 --- a/spec/operators/mergeMap-spec.ts +++ b/spec/operators/mergeMap-spec.ts @@ -22,7 +22,7 @@ describe('Observable.prototype.mergeMap()', () => { }); it('should map values to constant resolved promises and merge', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = (value: any) => Observable.from(Promise.resolve(42)); const results = []; @@ -34,13 +34,13 @@ describe('Observable.prototype.mergeMap()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([42,42,42,42]); + expect(results).toEqual([42, 42, 42, 42]); done(); }); }); it('should map values to constant rejected promises and merge', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = function (value) { return Observable.from(Promise.reject(42)); }; @@ -59,7 +59,7 @@ describe('Observable.prototype.mergeMap()', () => { }); it('should map values to resolved promises and merge', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = function (value, index) { return Observable.from(Promise.resolve(value + index)); }; @@ -73,13 +73,13 @@ describe('Observable.prototype.mergeMap()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([4,4,4,4]); + expect(results).toEqual([4, 4, 4, 4]); done(); }); }); it('should map values to rejected promises and merge', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = function (value, index) { return Observable.from(Promise.reject('' + value + '-' + index)); }; @@ -98,7 +98,7 @@ describe('Observable.prototype.mergeMap()', () => { }); it('should mergeMap values to resolved promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const resultSelectorCalledWith = []; const project = function (value, index) { return Observable.from(Promise.resolve([value, index])); @@ -110,10 +110,10 @@ describe('Observable.prototype.mergeMap()', () => { const results = []; const expectedCalls = [ - [4, [4,0], 0, 0], - [3, [3,1], 1, 0], - [2, [2,2], 2, 0], - [1, [1,3], 3, 0], + [4, [4, 0], 0, 0], + [3, [3, 1], 1, 0], + [2, [2, 2], 2, 0], + [1, [1, 3], 3, 0], ]; source.mergeMap(project, resultSelector).subscribe( (x: number) => { @@ -123,14 +123,14 @@ describe('Observable.prototype.mergeMap()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([8,8,8,8]); + expect(results).toEqual([8, 8, 8, 8]); (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); done(); }); }); it('should mergeMap values to rejected promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const project = function (value, index) { return Observable.from(Promise.reject('' + value + '-' + index)); }; @@ -522,7 +522,7 @@ describe('Observable.prototype.mergeMap()', () => { const expected = '(44)--(8888)---(666)----(44)----|'; const source = e1.mergeMap((value: any) => arrayRepeat(value, value), - (x: string, y: string) =>String(parseInt(x) + parseInt(y))); + (x: string, y: string) => String(parseInt(x) + parseInt(y))); expectObservable(source).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); @@ -545,7 +545,7 @@ describe('Observable.prototype.mergeMap()', () => { const expected = '(44)--(8888)---(666)----(44)----#'; const source = e1.mergeMap((value: any) => arrayRepeat(value, value), - (x: string, y: string) =>String(parseInt(x) + parseInt(y))); + (x: string, y: string) => String(parseInt(x) + parseInt(y))); expectObservable(source).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); @@ -570,7 +570,7 @@ describe('Observable.prototype.mergeMap()', () => { const expected = '(44)--(8888)-- '; const source = e1.mergeMap((value: any) => arrayRepeat(value, value), - (x: string, y: string) =>String(parseInt(x) + parseInt(y))); + (x: string, y: string) => String(parseInt(x) + parseInt(y))); expectObservable(source, unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); @@ -637,7 +637,7 @@ describe('Observable.prototype.mergeMap()', () => { const expected = ['1!', '2!', '3!', '4!']; let completed = false; - const sub = source.subscribe((x: string) => { + source.subscribe((x: string) => { expect(x).toBe(expected.shift()); }, null, () => { expect(expected.length).toBe(0); @@ -653,7 +653,7 @@ describe('Observable.prototype.mergeMap()', () => { const expected = ['1!', '2!', '3!', '4!']; let completed = false; - const sub = source.subscribe((x: string) => { + source.subscribe((x: string) => { expect(x).toBe(expected.shift()); }, null, () => { expect(expected.length).toBe(0); diff --git a/spec/operators/mergeMapTo-spec.ts b/spec/operators/mergeMapTo-spec.ts index 28eadd9c6b..ce2eec5084 100644 --- a/spec/operators/mergeMapTo-spec.ts +++ b/spec/operators/mergeMapTo-spec.ts @@ -26,7 +26,7 @@ describe('Observable.prototype.mergeMapTo()', () => { }); it('should map values to constant resolved promises and merge', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const results = []; source.mergeMapTo(Observable.from(Promise.resolve(42))).subscribe( @@ -37,13 +37,13 @@ describe('Observable.prototype.mergeMapTo()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([42,42,42,42]); + expect(results).toEqual([42, 42, 42, 42]); done(); }); }); it('should map values to constant rejected promises and merge', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); source.mergeMapTo(Observable.from(Promise.reject(42))).subscribe( (x: any) => { @@ -59,7 +59,7 @@ describe('Observable.prototype.mergeMapTo()', () => { }); it('should mergeMapTo values to resolved promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const resultSelectorCalledWith = []; const inner = Observable.from(Promise.resolve(42)); const resultSelector = function (outerVal, innerVal, outerIndex, innerIndex) { @@ -82,14 +82,14 @@ describe('Observable.prototype.mergeMapTo()', () => { done.fail('Subscriber error handler not supposed to be called.'); }, () => { - expect(results).toEqual([8,8,8,8]); + expect(results).toEqual([8, 8, 8, 8]); (expect(resultSelectorCalledWith)).toDeepEqual(expectedCalls); done(); }); }); it('should mergeMapTo values to rejected promises with resultSelector', (done: DoneSignature) => { - const source = Rx.Observable.from([4,3,2,1]); + const source = Rx.Observable.from([4, 3, 2, 1]); const inner = Observable.from(Promise.reject(42)); const resultSelector = () => { throw 'this should not be called'; @@ -376,7 +376,7 @@ describe('Observable.prototype.mergeMapTo()', () => { const expected = ['!', '!', '!', '!']; let completed = false; - const sub = source.subscribe((x: string) => { + source.subscribe((x: string) => { expect(x).toBe(expected.shift()); }, null, () => { expect(expected.length).toBe(0); @@ -392,7 +392,7 @@ describe('Observable.prototype.mergeMapTo()', () => { const expected = ['!', '!', '!', '!']; let completed = false; - const sub = source.subscribe((x: string) => { + source.subscribe((x: string) => { expect(x).toBe(expected.shift()); }, null, () => { expect(expected.length).toBe(0); diff --git a/spec/operators/multicast-spec.ts b/spec/operators/multicast-spec.ts index d52fcf35d8..b451b8fa3b 100644 --- a/spec/operators/multicast-spec.ts +++ b/spec/operators/multicast-spec.ts @@ -510,7 +510,7 @@ describe('Observable.prototype.multicast()', () => { const expected = ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']; Observable.of('a', 'b', 'c') - .switchMap((letter: string) => source.map((n :number) => String(letter + n))) + .switchMap((letter: string) => source.map((n: number) => String(letter + n))) .subscribe((x: string) => { expect(x).toBe(expected.shift()); }, done.fail, () => { @@ -551,7 +551,7 @@ describe('Observable.prototype.multicast()', () => { const expected = ['a1', 'a2', 'a3']; Observable.of('a', 'b', 'c') - .switchMap((letter: string) => source.map((n :number) => String(letter + n))) + .switchMap((letter: string) => source.map((n: number) => String(letter + n))) .subscribe((x: string) => { expect(x).toBe(expected.shift()); }, done.fail, () => { diff --git a/spec/operators/observeOn-spec.ts b/spec/operators/observeOn-spec.ts index f80ec64e80..edeb99b7a9 100644 --- a/spec/operators/observeOn-spec.ts +++ b/spec/operators/observeOn-spec.ts @@ -1,5 +1,5 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; @@ -72,7 +72,7 @@ describe('Observable.prototype.observeOn()', () => { const result = e1 .mergeMap((x: string) => Observable.of(x)) .observeOn(rxTestScheduler) - .mergeMap((x: string) => Observable.of(x)) + .mergeMap((x: string) => Observable.of(x)); expectObservable(result, unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(sub); diff --git a/spec/operators/pairwise-spec.ts b/spec/operators/pairwise-spec.ts index 5f2a39fa34..cf47fa0f9a 100644 --- a/spec/operators/pairwise-spec.ts +++ b/spec/operators/pairwise-spec.ts @@ -1,9 +1,6 @@ -import * as Rx from '../../dist/cjs/Rx.KitchenSink'; import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it} from '../helpers/test-helper'; -const Observable = Rx.Observable; - describe('Observable.prototype.pairwise()', () => { it('should pairwise things', () => { const e1 = hot('--a--^--b--c--d--e--f--g--|'); diff --git a/spec/operators/pluck-spec.ts b/spec/operators/pluck-spec.ts index e5c183dfaf..3d8f2fc7a2 100644 --- a/spec/operators/pluck-spec.ts +++ b/spec/operators/pluck-spec.ts @@ -1,5 +1,5 @@ import * as Rx from '../../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it} from '../helpers/test-helper'; const Observable = Rx.Observable; @@ -146,7 +146,7 @@ describe('Observable.prototype.pluck()', () => { const r = a .mergeMap((x: string) => Observable.of(x)) .pluck('prop') - .mergeMap((x: string) => Observable.of(x)) + .mergeMap((x: string) => Observable.of(x)); expectObservable(r, unsub).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); diff --git a/spec/operators/publish-spec.ts b/spec/operators/publish-spec.ts index 80d370d2a6..5fd8b4e8d3 100644 --- a/spec/operators/publish-spec.ts +++ b/spec/operators/publish-spec.ts @@ -3,7 +3,6 @@ import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marbl import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; -const Subject = Rx.Subject; describe('Observable.prototype.publish()', () => { asDiagram('publish')('should mirror a simple source Observable', () => { diff --git a/spec/operators/publishLast-spec.ts b/spec/operators/publishLast-spec.ts index 624838627b..e336206533 100644 --- a/spec/operators/publishLast-spec.ts +++ b/spec/operators/publishLast-spec.ts @@ -3,7 +3,6 @@ import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marbl import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; -const Subject = Rx.Subject; describe('Observable.prototype.publishLast()', () => { asDiagram('publishLast')('should emit last notification of a simple source Observable', () => { diff --git a/spec/operators/race-spec.ts b/spec/operators/race-spec.ts index dfa7222839..57bed6b522 100644 --- a/spec/operators/race-spec.ts +++ b/spec/operators/race-spec.ts @@ -101,7 +101,7 @@ describe('...race(observables)', () => { const result = e1 .mergeMap((x: string) => Observable.of(x)) .race(e2) - .mergeMap((x: string) => Observable.of(x)) + .mergeMap((x: string) => Observable.of(x)); expectObservable(result, unsub).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); diff --git a/spec/operators/refCount-spec.ts b/spec/operators/refCount-spec.ts index 6c4c95c933..52bdbe312c 100644 --- a/spec/operators/refCount-spec.ts +++ b/spec/operators/refCount-spec.ts @@ -1,9 +1,8 @@ import * as Rx from '../../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; -const Subject = Rx.Subject; describe('Observable.prototype.publish().refCount()', () => { asDiagram('refCount')('should turn a multicasted Observable an automatically ' + @@ -21,9 +20,12 @@ describe('Observable.prototype.publish().refCount()', () => { it('should count references', () => { const source = Observable.never().publish().refCount(); - const sub1 = source.subscribe({ next: () => { } }); - const sub2 = source.subscribe({ next: () => { } }); - const sub3 = source.subscribe({ next: () => { } }); + const sub1 = source.subscribe({ next: function () { //noop + } }); + const sub2 = source.subscribe({ next: function () { //noop + } }); + const sub3 = source.subscribe({ next: function () { //noop + } }); expect((source).refCount).toBe(3); @@ -42,8 +44,12 @@ describe('Observable.prototype.publish().refCount()', () => { }; }).publish().refCount(); - const sub1 = source.subscribe(() => {}); - const sub2 = source.subscribe(() => {}); + const sub1 = source.subscribe(() => { + //noop + }); + const sub2 = source.subscribe(() => { + //noop + }); const sub3 = source.subscribe((x: any) => { expect((source).refCount).toBe(1); }); diff --git a/spec/operators/repeat-spec.ts b/spec/operators/repeat-spec.ts index 69c5fcdc93..aa375c8155 100644 --- a/spec/operators/repeat-spec.ts +++ b/spec/operators/repeat-spec.ts @@ -1,5 +1,5 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; @@ -222,7 +222,11 @@ describe('Observable.prototype.repeat()', () => { it('should terminate repeat and throw if source subscription to _complete throws', () => { const e1 = Observable.of(1, 2, rxTestScheduler); - e1.subscribe(() => {}, () => {}, () => { throw new Error('error'); }); + e1.subscribe(() => { + //noop + }, () => { + //noop + }, () => { throw new Error('error'); }); expect(() => { e1.repeat(3); @@ -242,7 +246,11 @@ describe('Observable.prototype.repeat()', () => { it('should terminate repeat and throw if source subscription to _complete throws when repeating infinitely', () => { const e1 = Observable.of(1, 2, rxTestScheduler); - e1.subscribe(() => {}, () => {}, () => { throw new Error('error'); }); + e1.subscribe(() => { + //noop + }, () => { + //noop + }, () => { throw new Error('error'); }); expect(() => { e1.repeat(); diff --git a/spec/operators/sample-spec.ts b/spec/operators/sample-spec.ts index 48cf585893..2c192fbea8 100644 --- a/spec/operators/sample-spec.ts +++ b/spec/operators/sample-spec.ts @@ -1,5 +1,5 @@ import * as Rx from '../../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; diff --git a/spec/operators/single-spec.ts b/spec/operators/single-spec.ts index d758c99ecd..d3fb594bca 100644 --- a/spec/operators/single-spec.ts +++ b/spec/operators/single-spec.ts @@ -1,5 +1,5 @@ import * as Rx from '../../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, asDiagram} from '../helpers/test-helper'; const Observable = Rx.Observable; diff --git a/spec/operators/startWith-spec.ts b/spec/operators/startWith-spec.ts index cb23c0b4ff..cf07f2493d 100644 --- a/spec/operators/startWith-spec.ts +++ b/spec/operators/startWith-spec.ts @@ -1,6 +1,6 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; +import {it, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; const Observable = Rx.Observable; @@ -76,7 +76,7 @@ describe('Observable.prototype.startWith()', () => { const e1subs = '^ !'; const expected = '(yz)-a--|'; - expectObservable((e1).startWith('y','z')).toBe(expected); + expectObservable((e1).startWith('y', 'z')).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); @@ -150,7 +150,7 @@ describe('Observable.prototype.startWith()', () => { const e1subs = '^ !'; const expected = '(yz)-a--|'; - expectObservable((e1).startWith('y','z', rxTestScheduler)).toBe(expected); + expectObservable((e1).startWith('y', 'z', rxTestScheduler)).toBe(expected); expectSubscriptions(e1.subscriptions).toBe(e1subs); }); }); diff --git a/spec/operators/subscribeOn-spec.ts b/spec/operators/subscribeOn-spec.ts index b26bd0dfab..2b5df4074c 100644 --- a/spec/operators/subscribeOn-spec.ts +++ b/spec/operators/subscribeOn-spec.ts @@ -1,5 +1,5 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; +import {hot, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; import {it, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; diff --git a/spec/operators/switch-spec.ts b/spec/operators/switch-spec.ts index f144dcd7ef..cd8c3e5e80 100644 --- a/spec/operators/switch-spec.ts +++ b/spec/operators/switch-spec.ts @@ -201,10 +201,10 @@ describe('Observable.prototype.switch()', () => { }); it('should handle an observable with Arrays in it', () => { - const expected = [1,2,3,4]; + const expected = [1, 2, 3, 4]; let completed = false; - Observable.of(Observable.never(), Observable.never(), [1,2,3,4]) + Observable.of(Observable.never(), Observable.never(), [1, 2, 3, 4]) .switch() .subscribe((x: number) => { expect(x).toBe(expected.shift()); diff --git a/spec/operators/switchMap-spec.ts b/spec/operators/switchMap-spec.ts index 17f031bca3..6e92a22e5e 100644 --- a/spec/operators/switchMap-spec.ts +++ b/spec/operators/switchMap-spec.ts @@ -1,9 +1,8 @@ import * as Rx from '../../dist/cjs/Rx'; import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; +import {it, DoneSignature} from '../helpers/test-helper'; const Observable = Rx.Observable; -const queueScheduler = Rx.Scheduler.queue; describe('Observable.prototype.switchMap()', () => { it('should switch with a selector function', (done: DoneSignature) => { diff --git a/spec/operators/switchMapTo-spec.ts b/spec/operators/switchMapTo-spec.ts index eb36dfba84..6a13a8227e 100644 --- a/spec/operators/switchMapTo-spec.ts +++ b/spec/operators/switchMapTo-spec.ts @@ -1,9 +1,8 @@ import * as Rx from '../../dist/cjs/Rx'; import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; +import {it, DoneSignature} from '../helpers/test-helper'; const Observable = Rx.Observable; -const queueScheduler = Rx.Scheduler.queue; describe('Observable.prototype.switchMapTo()', () => { it('should switch a synchronous many outer to a synchronous many inner', (done: DoneSignature) => { diff --git a/spec/operators/take-spec.ts b/spec/operators/take-spec.ts index bfcb84059b..15fb52b403 100644 --- a/spec/operators/take-spec.ts +++ b/spec/operators/take-spec.ts @@ -106,7 +106,7 @@ describe('Observable.prototype.take()', () => { }); it('should throw if total is less than zero', () => { - expect(() => { Observable.range(0,10).take(-1); }) + expect(() => { Observable.range(0, 10).take(-1); }) .toThrow(new Rx.ArgumentOutOfRangeError()); }); diff --git a/spec/operators/takeLast-spec.ts b/spec/operators/takeLast-spec.ts index 52ba35fbce..a192221250 100644 --- a/spec/operators/takeLast-spec.ts +++ b/spec/operators/takeLast-spec.ts @@ -106,7 +106,7 @@ describe('Observable.prototype.takeLast()', () => { }); it('should throw if total is less than zero', () => { - expect(() => { Observable.range(0,10).takeLast(-1); }) + expect(() => { Observable.range(0, 10).takeLast(-1); }) .toThrow(new Rx.ArgumentOutOfRangeError()); }); diff --git a/spec/operators/throttle-spec.ts b/spec/operators/throttle-spec.ts index 6d1a9bb36b..e4643dffd8 100644 --- a/spec/operators/throttle-spec.ts +++ b/spec/operators/throttle-spec.ts @@ -285,7 +285,7 @@ describe('Observable.prototype.throttle()', () => { Observable.timer(10).mapTo(3), Observable.timer(50).mapTo(4) ); - const expected = [1,2,3,4]; + const expected = [1, 2, 3, 4]; e1.throttle(() => { return new Promise((resolve: any) => { resolve(42); }); @@ -308,14 +308,14 @@ describe('Observable.prototype.throttle()', () => { Observable.timer(10).mapTo(3), Observable.timer(50).mapTo(4) ); - const expected = [1,2,3]; + const expected = [1, 2, 3]; const error = new Error('error'); e1.throttle((x: number) => { if (x === 3) { - return new Promise((resolve: any, reject: any) => {reject(error);}); + return new Promise((resolve: any, reject: any) => { reject(error); }); } else { - return new Promise((resolve: any) => {resolve(42);}); + return new Promise((resolve: any) => { resolve(42); }); } }).subscribe( (x: number) => { diff --git a/spec/operators/throttleTime-spec.ts b/spec/operators/throttleTime-spec.ts index b22763af27..bc1ee2d16e 100644 --- a/spec/operators/throttleTime-spec.ts +++ b/spec/operators/throttleTime-spec.ts @@ -4,7 +4,6 @@ import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; const Observable = Rx.Observable; -const Scheduler = Rx.Scheduler; describe('Observable.prototype.throttleTime()', () => { asDiagram('throttleTime(50)')('should immediately emit the first value in each time window', () => { diff --git a/spec/operators/toPromise-spec.ts b/spec/operators/toPromise-spec.ts index f5b5fbaad4..af3c371162 100644 --- a/spec/operators/toPromise-spec.ts +++ b/spec/operators/toPromise-spec.ts @@ -1,6 +1,5 @@ import * as Rx from '../../dist/cjs/Rx'; -import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; +import {it, DoneSignature} from '../helpers/test-helper'; declare const __root__: any; const Observable = Rx.Observable; @@ -16,14 +15,14 @@ describe('Observable.prototype.toPromise()', () => { it('should handle errors properly', (done: DoneSignature) => { Observable.throw('bad').toPromise(Promise).then(() => { done.fail('should not be called'); - }, function (err) { + }, (err: any) => { expect(err).toBe('bad'); done(); }); }); it('should allow for global config via Rx.config.Promise', (done: DoneSignature) => { - var wasCalled = false; + let wasCalled = false; __root__.Rx = {}; __root__.Rx.config = {}; __root__.Rx.config.Promise = function MyPromise(callback) { diff --git a/spec/operators/windowToggle-spec.ts b/spec/operators/windowToggle-spec.ts index 2078a16a2e..3d6ebc4a83 100644 --- a/spec/operators/windowToggle-spec.ts +++ b/spec/operators/windowToggle-spec.ts @@ -1,6 +1,6 @@ import * as Rx from '../../dist/cjs/Rx.KitchenSink'; import {hot, cold, time, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; +import {it, asDiagram} from '../helpers/test-helper'; declare const rxTestScheduler: Rx.TestScheduler; const Observable = Rx.Observable; diff --git a/spec/operators/windowWhen-spec.ts b/spec/operators/windowWhen-spec.ts index cc75e937d4..7c15f235b1 100644 --- a/spec/operators/windowWhen-spec.ts +++ b/spec/operators/windowWhen-spec.ts @@ -155,7 +155,6 @@ describe('Observable.prototype.windowWhen', () => { it('should dispose window Subjects if the outer is unsubscribed early', () => { const source = hot('--a--b--c--d--e--f--g--h--|'); - const open = cold('o-------------------------|'); const sourceSubs = '^ ! '; const expected = 'x--------- '; const x = cold( '--a--b--c- '); diff --git a/spec/operators/withLatestFrom-spec.ts b/spec/operators/withLatestFrom-spec.ts index 7464b74e1d..90b816676d 100644 --- a/spec/operators/withLatestFrom-spec.ts +++ b/spec/operators/withLatestFrom-spec.ts @@ -172,7 +172,7 @@ describe('Observable.prototype.withLatestFrom()', () => { const e3subs = '^ !'; const expected = '----x---#'; // throw const values = { - x: ['b','f','j'] + x: ['b', 'f', 'j'] }; const result = e1.withLatestFrom(e2, e3); @@ -241,21 +241,21 @@ describe('Observable.prototype.withLatestFrom()', () => { it('should handle promises', (done: DoneSignature) => { Observable.of(1).delay(1).withLatestFrom(Promise.resolve(2), Promise.resolve(3)) .subscribe((x: any) => { - expect(x).toEqual([1,2,3]); + expect(x).toEqual([1, 2, 3]); }, null, done); }); it('should handle arrays', () => { - Observable.of(1).delay(1).withLatestFrom([2,3,4], [4,5,6]) + Observable.of(1).delay(1).withLatestFrom([2, 3, 4], [4, 5, 6]) .subscribe((x: any) => { - expect(x).toEqual([1,4,6]); + expect(x).toEqual([1, 4, 6]); }); }); it('should handle lowercase-o observables', () => { Observable.of(1).delay(1).withLatestFrom(lowerCaseO(2, 3, 4), lowerCaseO(4, 5, 6)) .subscribe((x: any) => { - expect(x).toEqual([1,4,6]); + expect(x).toEqual([1, 4, 6]); }); }); }); \ No newline at end of file diff --git a/spec/operators/zip-spec.ts b/spec/operators/zip-spec.ts index bdc4e30af8..36d401c54f 100644 --- a/spec/operators/zip-spec.ts +++ b/spec/operators/zip-spec.ts @@ -1,6 +1,6 @@ import * as Rx from '../../dist/cjs/Rx'; import {hot, cold, expectObservable, expectSubscriptions} from '../helpers/marble-testing'; -import {it, DoneSignature, asDiagram} from '../helpers/test-helper'; +import {it, DoneSignature} from '../helpers/test-helper'; declare const Symbol: any; const Observable = Rx.Observable; @@ -24,8 +24,8 @@ describe('zip', () => { const expected = ['a1', 'b2', 'c3']; let i = 0; - Observable.fromArray(['a','b','c']).zip( - Observable.fromArray([1,2,3]), + Observable.fromArray(['a', 'b', 'c']).zip( + Observable.fromArray([1, 2, 3]), function (a, b) { return a + b; } @@ -44,12 +44,12 @@ describe('zip', () => { const e3subs = '^ ! '; const expected = '--------x----y----(z|) '; // e1 complete and buffer empty const values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] + x: ['a', 'd', 'h'], + y: ['b', 'e', 'i'], + z: ['c', 'f', 'j'] }; - expectObservable(e1.zip(e2,e3)).toBe(expected, values); + expectObservable(e1.zip(e2, e3)).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); expectSubscriptions(e2.subscriptions).toBe(e2subs); expectSubscriptions(e3.subscriptions).toBe(e3subs); @@ -65,12 +65,12 @@ describe('zip', () => { const e3subs = '^ ! '; const expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete const values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] + x: ['a', 'd', 'h'], + y: ['b', 'e', 'i'], + z: ['c', 'f', 'j'] }; - expectObservable(e1.zip(e2,e3)).toBe(expected, values); + expectObservable(e1.zip(e2, e3)).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); expectSubscriptions(e2.subscriptions).toBe(e2subs); expectSubscriptions(e3.subscriptions).toBe(e3subs); @@ -112,7 +112,7 @@ describe('zip', () => { }; myIterator[Symbol.iterator] = function () { return this; }; - Observable.of(1,2,3).zip(myIterator) + Observable.of(1, 2, 3).zip(myIterator) .subscribe(); // since zip will call `next()` in advance, total calls when @@ -223,7 +223,7 @@ describe('zip', () => { } else { return x + y; }}; - expectObservable(a.zip(b,selector)).toBe(expected, + expectObservable(a.zip(b, selector)).toBe(expected, { x: '14' }, new Error('too bad')); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -236,7 +236,7 @@ describe('zip', () => { const bsubs = '^'; const expected = '---x---y---z'; - expectObservable(a.zip(b, function (e1,e2) { return e1 + e2; })) + expectObservable(a.zip(b, function (e1, e2) { return e1 + e2; })) .toBe(expected, { x: '14', y: '25', z: '36' }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); @@ -250,8 +250,8 @@ describe('zip', () => { const c = hot('---1-^---3---6-| '); const expected = '----x---y-| '; - expectObservable(a.zip(b,c)).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); + expectObservable(a.zip(b, c)).toBe(expected, + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -264,10 +264,10 @@ describe('zip', () => { const c = hot('---1-^---3---6-| '); const expected = '----x---y-| '; - const observable = a.zip(b,c, + const observable = a.zip(b, c, function (r0, r1, r2) { return [r0, r1, r2]; }); expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -280,10 +280,10 @@ describe('zip', () => { const c = hot('---1-^---3---6-| '); const expected = '----x---y-| '; - const observable = a.zip(b,c, + const observable = a.zip(b, c, function (r0, r1, r2) { return [r0, r1, r2]; }); expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -295,7 +295,7 @@ describe('zip', () => { const bsubs = '^ ! '; const expected = '---a--b--c--d--e--| '; - expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) + expectObservable(a.zip(b, function (r1, r2) { return r1 + r2; })) .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); @@ -308,7 +308,7 @@ describe('zip', () => { const bsubs = '^ ! '; const expected = '---a--b--c--d--e--| '; - expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) + expectObservable(a.zip(b, function (r1, r2) { return r1 + r2; })) .toBe(expected, { a: '21', b: '43', c: '65', d: '87', e: '09' }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); @@ -321,7 +321,7 @@ describe('zip', () => { const bsubs = '^ ! '; const expected = '---a--b--c--d--e-| '; - expectObservable(a.zip(b, function (r1,r2) { return r1 + r2; })) + expectObservable(a.zip(b, function (r1, r2) { return r1 + r2; })) .toBe(expected, { a: '12', b: '34', c: '56', d: '78', e: '90' }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); @@ -340,7 +340,7 @@ describe('zip', () => { } else { return x + y; }}; - const observable = a.zip(b,selector); + const observable = a.zip(b, selector); expectObservable(observable).toBe(expected, { x: '23' }, new Error('too bad')); expectSubscriptions(a.subscriptions).toBe(asubs); diff --git a/spec/operators/zipAll-spec.ts b/spec/operators/zipAll-spec.ts index 3f49f9466d..a1b8f5e544 100644 --- a/spec/operators/zipAll-spec.ts +++ b/spec/operators/zipAll-spec.ts @@ -35,8 +35,8 @@ describe('Observable.prototype.zipAll', () => { const expected = ['a1', 'b2', 'c3']; let i = 0; Observable.of( - Observable.of('a','b','c'), - Observable.of(1,2,3) + Observable.of('a', 'b', 'c'), + Observable.of(1, 2, 3) ) .zipAll((a: any, b: any) => a + b) .subscribe((x: any) => { @@ -53,12 +53,12 @@ describe('Observable.prototype.zipAll', () => { const e3subs = '^ ! '; const expected = '--------x----y----(z|) '; // e1 complete and buffer empty const values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] + x: ['a', 'd', 'h'], + y: ['b', 'e', 'i'], + z: ['c', 'f', 'j'] }; - expectObservable(Observable.of(e1,e2,e3).zipAll()).toBe(expected, values); + expectObservable(Observable.of(e1, e2, e3).zipAll()).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); expectSubscriptions(e2.subscriptions).toBe(e2subs); expectSubscriptions(e3.subscriptions).toBe(e3subs); @@ -74,12 +74,12 @@ describe('Observable.prototype.zipAll', () => { const e3subs = '^ ! '; const expected = '--------x----y----(z|) '; // e2 buffer empty and signaled complete const values = { - x: ['a','d','h'], - y: ['b','e','i'], - z: ['c','f','j'] + x: ['a', 'd', 'h'], + y: ['b', 'e', 'i'], + z: ['c', 'f', 'j'] }; - expectObservable(Observable.of(e1,e2,e3).zipAll()).toBe(expected, values); + expectObservable(Observable.of(e1, e2, e3).zipAll()).toBe(expected, values); expectSubscriptions(e1.subscriptions).toBe(e1subs); expectSubscriptions(e2.subscriptions).toBe(e2subs); expectSubscriptions(e3.subscriptions).toBe(e3subs); @@ -121,7 +121,7 @@ describe('Observable.prototype.zipAll', () => { }; myIterator[Symbol.iterator] = function () { return this; }; - Observable.of(Observable.of(1,2,3), myIterator).zipAll() + Observable.of(Observable.of(1, 2, 3), myIterator).zipAll() .subscribe(); // since zip will call `next()` in advance, total calls when @@ -135,7 +135,7 @@ describe('Observable.prototype.zipAll', () => { const b = []; const expected = '-'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -145,7 +145,7 @@ describe('Observable.prototype.zipAll', () => { const b = []; const expected = '|'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -155,7 +155,7 @@ describe('Observable.prototype.zipAll', () => { const b = [1]; const expected = '|'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -165,7 +165,7 @@ describe('Observable.prototype.zipAll', () => { const b = []; const expected = '--------|'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -175,7 +175,7 @@ describe('Observable.prototype.zipAll', () => { const b = [1]; const expected = '-'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -185,7 +185,7 @@ describe('Observable.prototype.zipAll', () => { const b = [2]; const expected = '-----(x|)'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected, { x: ['1', 2] }); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected, { x: ['1', 2] }); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -195,7 +195,7 @@ describe('Observable.prototype.zipAll', () => { const b = []; const expected = '-----#'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -205,7 +205,7 @@ describe('Observable.prototype.zipAll', () => { const b = [1]; const expected = '-----#'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected); + expectObservable(Observable.of(a, b).zipAll()).toBe(expected); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -215,7 +215,7 @@ describe('Observable.prototype.zipAll', () => { const b = [4, 5, 6]; const expected = '---x--y--(z|)'; - expectObservable(Observable.of(a,b).zipAll()).toBe(expected, + expectObservable(Observable.of(a, b).zipAll()).toBe(expected, { x: ['1', 4], y: ['2', 5], z: ['3', 6] }); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -232,7 +232,7 @@ describe('Observable.prototype.zipAll', () => { } else { return x + y; }}; - expectObservable(Observable.of(a,b).zipAll(selector)).toBe(expected, + expectObservable(Observable.of(a, b).zipAll(selector)).toBe(expected, { x: '14' }, new Error('too bad')); expectSubscriptions(a.subscriptions).toBe(asubs); }); @@ -260,7 +260,7 @@ describe('Observable.prototype.zipAll', () => { const expected = '----x---y-| '; expectObservable(Observable.of(a, b, c).zipAll()).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -275,7 +275,7 @@ describe('Observable.prototype.zipAll', () => { const observable = Observable.of(a, b, c).zipAll((r0, r1, r2) => [r0, r1, r2]); expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -290,7 +290,7 @@ describe('Observable.prototype.zipAll', () => { const observable = Observable.of(a, b, c).zipAll((r0, r1, r2) => [r0, r1, r2]); expectObservable(observable).toBe(expected, - { x: ['1','2','3'], y: ['4','5','6'] }); + { x: ['1', '2', '3'], y: ['4', '5', '6'] }); expectSubscriptions(a.subscriptions).toBe(asubs); expectSubscriptions(b.subscriptions).toBe(bsubs); }); @@ -370,8 +370,8 @@ describe('Observable.prototype.zipAll', () => { const expected = ['a1', 'b2']; let i = 0; Observable.of( - Observable.of('a','b','c'), - Observable.of(1,2) + Observable.of('a', 'b', 'c'), + Observable.of(1, 2) ) .zipAll((a: any, b: any) => a + b) .subscribe((x: any) => { diff --git a/spec/subjects/AsyncSubject-spec.ts b/spec/subjects/AsyncSubject-spec.ts index 0c1ca5a25d..152d6e9092 100644 --- a/spec/subjects/AsyncSubject-spec.ts +++ b/spec/subjects/AsyncSubject-spec.ts @@ -135,7 +135,7 @@ describe('AsyncSubject', () => { it('should keep emitting error to subsequent subscriptions', () => { const subject = new AsyncSubject(); const observer = new TestObserver(); - const subscription = subject.subscribe(observer); + subject.subscribe(observer); subject.next(1); expect(observer.results).toEqual([]); diff --git a/spec/subjects/ReplaySubject-spec.ts b/spec/subjects/ReplaySubject-spec.ts index 17fa2fe267..f391c87554 100644 --- a/spec/subjects/ReplaySubject-spec.ts +++ b/spec/subjects/ReplaySubject-spec.ts @@ -167,9 +167,9 @@ describe('ReplaySubject', () => { subscription3.unsubscribe(); - expect(results1).toEqual([3,4,5,6,7]); - expect(results2).toEqual([4,5,6,7,8]); - expect(results3).toEqual([9,10,11]); + expect(results1).toEqual([3, 4, 5, 6, 7]); + expect(results2).toEqual([4, 5, 6, 7, 8]); + expect(results3).toEqual([9, 10, 11]); subject.complete(); }); diff --git a/spec/util/Immediate-spec.ts b/spec/util/Immediate-spec.ts index 76bb0c1e49..37fe7c127b 100644 --- a/spec/util/Immediate-spec.ts +++ b/spec/util/Immediate-spec.ts @@ -27,7 +27,9 @@ describe('ImmediateDefinition', () => { const result = new ImmediateDefinition(root); - result.setImmediate(() => {}); + result.setImmediate(() => { + //noop + }); result.clearImmediate(null); expect(setImmediateCalled).toBeTruthy(); @@ -43,7 +45,9 @@ describe('ImmediateDefinition', () => { nextTick: jasmine.createSpy('nextTick') } }, - runIfPresent: () => {}, + runIfPresent: () => { + //noop + }, partiallyApplied: jasmine.createSpy('partiallyApplied'), addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456) }; @@ -52,7 +56,9 @@ describe('ImmediateDefinition', () => { expect(typeof setImmediateImpl).toBe('function'); - const action = () => {}; + const action = () => { + //noop + }; const handle = setImmediateImpl(action); expect(handle).toBe(123456); @@ -88,7 +94,9 @@ describe('ImmediateDefinition', () => { expect(instance.runIfPresent).toHaveBeenCalledWith(123456); - const action = () => {}; + const action = () => { + //noop + }; const handle = setImmediateImpl(action); expect(handle).toBe(123456); @@ -126,7 +134,9 @@ describe('ImmediateDefinition', () => { expect(instance.runIfPresent).toHaveBeenCalledWith('something'); - const action = () => {}; + const action = () => { + //noop + }; const handle = setImmediateImpl(action); expect(handle).toBe(123456); @@ -156,7 +166,9 @@ describe('ImmediateDefinition', () => { expect(typeof setImmediateImpl).toBe('function'); - const action = () => {}; + const action = () => { + //noop + }; const handle = setImmediateImpl(action); expect(handle).toBe(123456); @@ -175,7 +187,9 @@ describe('ImmediateDefinition', () => { describe('when setImmediate does *not* exist on root', () => { describe('when it can use process.nextTick', () => { it('should use the post message impl', () => { - const nextTickImpl = () => { }; + const nextTickImpl = () => { + //noop + }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(true); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); @@ -194,7 +208,9 @@ describe('ImmediateDefinition', () => { describe('when it cannot use process.nextTick', () => { it('should use the post message impl', () => { - const postMessageImpl = () => { }; + const postMessageImpl = () => { + //noop + }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(true); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); @@ -213,7 +229,9 @@ describe('ImmediateDefinition', () => { describe('when it cannot use process.nextTick or postMessage', () => { it('should use the readystatechange impl', () => { - const messageChannelImpl = () => { }; + const messageChannelImpl = () => { + //noop + }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(true); @@ -232,7 +250,9 @@ describe('ImmediateDefinition', () => { describe('when it cannot use process.nextTick, postMessage or Message channels', () => { it('should use the readystatechange impl', () => { - const readyStateChangeImpl = () => { }; + const readyStateChangeImpl = () => { + //noop + }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); @@ -251,7 +271,9 @@ describe('ImmediateDefinition', () => { describe('when no other methods to implement setImmediate are available', () => { it('should use the setTimeout impl', () => { - const setTimeoutImpl = () => { }; + const setTimeoutImpl = () => { + //noop + }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); @@ -292,7 +314,7 @@ describe('ImmediateDefinition', () => { expect(typeof result).toBe('function'); - const calledWith = result(); + result(); expect(__root__.__wasCalled).toEqual(true); @@ -304,6 +326,7 @@ describe('ImmediateDefinition', () => { describe('prototype.identify', () => { it('should use Object.toString to return an identifier string', () => { function MockObject() { + //noop } MockObject.prototype.toString = jasmine.createSpy('Object.prototype.toString').and.returnValue('[object HEYO!]'); @@ -357,7 +380,9 @@ describe('ImmediateDefinition', () => { describe('when there is a global postMessage function', () => { describe('and importScripts does NOT exist', () => { it('should maintain any existing onmessage handler', () => { - const originalOnMessage = () => {}; + const originalOnMessage = () => { + //noop + }; const instance = { root: { onmessage: originalOnMessage @@ -410,8 +435,12 @@ describe('ImmediateDefinition', () => { it('should return false', () => { const instance = { root: { - postMessage: () => {}, - importScripts: () => {} + postMessage: function () { + //noop + }, + importScripts: function () { + //noop + } } }; @@ -438,7 +467,9 @@ describe('ImmediateDefinition', () => { it('should return true if MessageChannel exists', () => { const instance = { root: { - MessageChannel: () => {} + MessageChannel: function () { + //noop + } } }; @@ -518,7 +549,9 @@ describe('ImmediateDefinition', () => { partiallyApplied: jasmine.createSpy('partiallyApplied').and.returnValue(partiallyAppliedResult) }; - const args = [() => {}, 'foo', 'bar']; + const args = [() => { + //noop + }, 'foo', 'bar']; const handle = ImmediateDefinition.prototype.addFromSetImmediateArguments.call(instance, args); @@ -530,7 +563,9 @@ describe('ImmediateDefinition', () => { describe('clearImmediate', () => { it('should delete values from tasksByHandle', () => { - const setTimeoutImpl = () => { }; + const setTimeoutImpl = () => { + //noop + }; spyOn(ImmediateDefinition.prototype, 'canUseProcessNextTick').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUsePostMessage').and.returnValue(false); spyOn(ImmediateDefinition.prototype, 'canUseMessageChannel').and.returnValue(false); @@ -538,7 +573,9 @@ describe('ImmediateDefinition', () => { spyOn(ImmediateDefinition.prototype, 'createSetTimeoutSetImmediate').and.returnValue(setTimeoutImpl); const Immediate = new ImmediateDefinition({}); - Immediate.tasksByHandle[123456] = () => {}; + Immediate.tasksByHandle[123456] = () => { + //noop + }; expect('123456' in Immediate.tasksByHandle).toBe(true); @@ -550,7 +587,9 @@ describe('ImmediateDefinition', () => { describe('prototype.runIfPresent', () => { it('should delay running the task if it is currently running a task', () => { - const mockApplied = () => {}; + const mockApplied = () => { + //noop + }; const instance = { root: { @@ -606,14 +645,18 @@ describe('ImmediateDefinition', () => { describe('prototype.createSetTimeoutSetImmediate', () => { it('should create a proper setImmediate implementation that uses setTimeout', () => { - const mockApplied = () => {}; + const mockApplied = () => { + //noop + }; const instance = { root: { setTimeout: jasmine.createSpy('setTimeout') }, addFromSetImmediateArguments: jasmine.createSpy('addFromSetImmediateArguments').and.returnValue(123456), - runIfPresent: () => {}, + runIfPresent: function () { + //noop + }, partiallyApplied: jasmine.createSpy('partiallyApplied').and.returnValue(mockApplied) }; @@ -635,7 +678,7 @@ describe('ImmediateDefinition', () => { results.push(x); }, done.fail, () => { - expect(results).toEqual([1,2,3]); + expect(results).toEqual([1, 2, 3]); done(); }); }); diff --git a/spec/util/MapPolyfill-spec.ts b/spec/util/MapPolyfill-spec.ts index dfaa948585..bf0bbdee2d 100644 --- a/spec/util/MapPolyfill-spec.ts +++ b/spec/util/MapPolyfill-spec.ts @@ -1,5 +1,4 @@ import {MapPolyfill} from '../../dist/cjs/util/MapPolyfill'; -import * as Rx from '../../dist/cjs/Rx'; import {it} from '../helpers/test-helper'; describe('MapPolyfill', () => { diff --git a/spec/util/SymbolShim-spec.ts b/spec/util/SymbolShim-spec.ts index 0f0403e8af..36290d1112 100644 --- a/spec/util/SymbolShim-spec.ts +++ b/spec/util/SymbolShim-spec.ts @@ -1,7 +1,6 @@ -import {polyfillSymbol, ensureIterator} from '../../dist/cjs/util/SymbolShim'; +import {polyfillSymbol} from '../../dist/cjs/util/SymbolShim'; import {Map} from '../../dist/cjs/util/Map'; -import * as Rx from '../../dist/cjs/Rx'; -import {it, DoneSignature} from '../helpers/test-helper'; +import {it} from '../helpers/test-helper'; declare const __root__: any; @@ -96,8 +95,11 @@ describe('SymbolShim.polyfillSymbol', () => { it('should patch using Set for mozilla bug', () => { function Set() { + //noop } - Set.prototype['@@iterator'] = () => {}; + Set.prototype['@@iterator'] = () => { + //noop + }; const root = { Set: Set, From 60631e0dbf7af0655fb3789a3e706fe64ed94e4b Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Mon, 29 Feb 2016 18:23:26 -0800 Subject: [PATCH 7/8] chore(package.json): upadte build script to trigger test case build also --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8d4e9decb9..51eb782233 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "build_closure_kitchensink": "java -jar ./node_modules/google-closure-compiler/compiler.jar --js ./dist/global/Rx.KitchenSink.umd.js --language_in ECMASCRIPT5 --create_source_map ./dist/global/Rx.KitchenSink.umd.min.js.map --js_output_file ./dist/global/Rx.KitchenSink.umd.min.js", "build_global": "rm -rf dist/global && mkdir \"dist/global\" && node tools/make-umd-bundle.js && node tools/make-system-bundle.js && npm run build_closure_core && npm run build_closure_kitchensink", "build_perf": "npm run build_cjs && npm run build_global && webdriver-manager update && npm run perf", - "build_test": "rm -rf dist/ && npm run lint && npm run build_cjs && jasmine", - "build_cover": "rm -rf dist/ && npm run lint && npm run build_cjs && npm run cover", + "build_test": "rm -rf dist/ && npm run lint && npm run build_cjs && npm run test_buildonly && npm run test_nobuild", + "build_cover": "rm -rf dist/ && npm run lint && npm run build_cjs && npm run test_buildonly && npm run cover", "build_docs": "npm run build_es6 && npm run tests2png && esdoc -c esdoc.json", "publish_docs": "./publish_docs.sh", "lint_perf": "eslint perf/", From 4bc32b77a41a53eee63ad39df0453fb0de29b42a Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Mon, 29 Feb 2016 21:01:26 -0800 Subject: [PATCH 8/8] test(tests2png): patch tests2png configuration to work with typescript test cases --- package.json | 2 +- spec/helpers/test-helper.ts | 3 +++ spec/support/tests2png.json | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 51eb782233..6b0935e865 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "test_buildonly": "rm -rf tmp && tsc --project ./spec --pretty", "test": "npm run test_buildonly && npm run test_nobuild", "test_karma": "karma start karma.conf.js", - "tests2png": "mkdirp tmp/docs/img && JASMINE_CONFIG_PATH=spec/support/tests2png.json jasmine", + "tests2png": "mkdirp tmp/docs/img && cp -r spec/helpers/tests2png tmp/helpers/tests2png && jasmine JASMINE_CONFIG_PATH=spec/support/tests2png.json", "watch": "watch \"echo triggering build && npm run build_test && echo build completed\" src -d -u -w=15", "perf": "protractor protractor.conf.js", "perf_micro": "node ./perf/micro/index.js", diff --git a/spec/helpers/test-helper.ts b/spec/helpers/test-helper.ts index ea95d640ed..ea290e8f1d 100644 --- a/spec/helpers/test-helper.ts +++ b/spec/helpers/test-helper.ts @@ -45,6 +45,9 @@ function assertAction(done: DoneSignature, assertion: (done?: DoneSignature) => } export function asDiagram(expectation: string): (expectation: string, assertion?: (done: DoneSignature) => void, timeout?: number) => void { + if (global.it.asDiagram) { + return global.it.asDiagram(expectation); + } return it; } diff --git a/spec/support/tests2png.json b/spec/support/tests2png.json index 3cc852b2ed..ac88469e2e 100644 --- a/spec/support/tests2png.json +++ b/spec/support/tests2png.json @@ -1,9 +1,10 @@ { - "spec_dir": "spec", + "spec_dir": "tmp", "spec_files": [ "**/*[sS]pec.js" ], "helpers": [ - "helpers/tests2png/diagram-test-runner.js" + "helpers/tests2png/diagram-test-runner.js", + "helpers/**/*helper.js" ] }