aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/rxjs/src/internal/testing
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/rxjs/src/internal/testing')
-rw-r--r--node_modules/rxjs/src/internal/testing/ColdObservable.ts52
-rw-r--r--node_modules/rxjs/src/internal/testing/HotObservable.ts53
-rw-r--r--node_modules/rxjs/src/internal/testing/SubscriptionLog.ts5
-rw-r--r--node_modules/rxjs/src/internal/testing/SubscriptionLoggable.ts22
-rw-r--r--node_modules/rxjs/src/internal/testing/TestMessage.ts7
-rw-r--r--node_modules/rxjs/src/internal/testing/TestScheduler.ts690
6 files changed, 0 insertions, 829 deletions
diff --git a/node_modules/rxjs/src/internal/testing/ColdObservable.ts b/node_modules/rxjs/src/internal/testing/ColdObservable.ts
deleted file mode 100644
index 40cbe49..0000000
--- a/node_modules/rxjs/src/internal/testing/ColdObservable.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Observable } from '../Observable';
-import { Subscription } from '../Subscription';
-import { Scheduler } from '../Scheduler';
-import { TestMessage } from './TestMessage';
-import { SubscriptionLog } from './SubscriptionLog';
-import { SubscriptionLoggable } from './SubscriptionLoggable';
-import { applyMixins } from '../util/applyMixins';
-import { Subscriber } from '../Subscriber';
-import { observeNotification } from '../Notification';
-
-export class ColdObservable<T> extends Observable<T> implements SubscriptionLoggable {
- public subscriptions: SubscriptionLog[] = [];
- scheduler: Scheduler;
- // @ts-ignore: Property has no initializer and is not definitely assigned
- logSubscribedFrame: () => number;
- // @ts-ignore: Property has no initializer and is not definitely assigned
- logUnsubscribedFrame: (index: number) => void;
-
- constructor(public messages: TestMessage[], scheduler: Scheduler) {
- super(function (this: Observable<T>, subscriber: Subscriber<any>) {
- const observable: ColdObservable<T> = this as any;
- const index = observable.logSubscribedFrame();
- const subscription = new Subscription();
- subscription.add(
- new Subscription(() => {
- observable.logUnsubscribedFrame(index);
- })
- );
- observable.scheduleMessages(subscriber);
- return subscription;
- });
- this.scheduler = scheduler;
- }
-
- scheduleMessages(subscriber: Subscriber<any>) {
- const messagesLength = this.messages.length;
- for (let i = 0; i < messagesLength; i++) {
- const message = this.messages[i];
- subscriber.add(
- this.scheduler.schedule(
- (state) => {
- const { message: { notification }, subscriber: destination } = state!;
- observeNotification(notification, destination);
- },
- message.frame,
- { message, subscriber }
- )
- );
- }
- }
-}
-applyMixins(ColdObservable, [SubscriptionLoggable]);
diff --git a/node_modules/rxjs/src/internal/testing/HotObservable.ts b/node_modules/rxjs/src/internal/testing/HotObservable.ts
deleted file mode 100644
index c151480..0000000
--- a/node_modules/rxjs/src/internal/testing/HotObservable.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { Subject } from '../Subject';
-import { Subscriber } from '../Subscriber';
-import { Subscription } from '../Subscription';
-import { Scheduler } from '../Scheduler';
-import { TestMessage } from './TestMessage';
-import { SubscriptionLog } from './SubscriptionLog';
-import { SubscriptionLoggable } from './SubscriptionLoggable';
-import { applyMixins } from '../util/applyMixins';
-import { observeNotification } from '../Notification';
-
-export class HotObservable<T> extends Subject<T> implements SubscriptionLoggable {
- public subscriptions: SubscriptionLog[] = [];
- scheduler: Scheduler;
- // @ts-ignore: Property has no initializer and is not definitely assigned
- logSubscribedFrame: () => number;
- // @ts-ignore: Property has no initializer and is not definitely assigned
- logUnsubscribedFrame: (index: number) => void;
-
- constructor(public messages: TestMessage[], scheduler: Scheduler) {
- super();
- this.scheduler = scheduler;
- }
-
- /** @internal */
- protected _subscribe(subscriber: Subscriber<any>): Subscription {
- const subject: HotObservable<T> = this;
- const index = subject.logSubscribedFrame();
- const subscription = new Subscription();
- subscription.add(
- new Subscription(() => {
- subject.logUnsubscribedFrame(index);
- })
- );
- subscription.add(super._subscribe(subscriber));
- return subscription;
- }
-
- setup() {
- const subject = this;
- const messagesLength = subject.messages.length;
- /* tslint:disable:no-var-keyword */
- for (let i = 0; i < messagesLength; i++) {
- (() => {
- const { notification, frame } = subject.messages[i];
- /* tslint:enable */
- subject.scheduler.schedule(() => {
- observeNotification(notification, subject);
- }, frame);
- })();
- }
- }
-}
-applyMixins(HotObservable, [SubscriptionLoggable]);
diff --git a/node_modules/rxjs/src/internal/testing/SubscriptionLog.ts b/node_modules/rxjs/src/internal/testing/SubscriptionLog.ts
deleted file mode 100644
index 367a6d9..0000000
--- a/node_modules/rxjs/src/internal/testing/SubscriptionLog.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export class SubscriptionLog {
- constructor(public subscribedFrame: number,
- public unsubscribedFrame: number = Infinity) {
- }
-} \ No newline at end of file
diff --git a/node_modules/rxjs/src/internal/testing/SubscriptionLoggable.ts b/node_modules/rxjs/src/internal/testing/SubscriptionLoggable.ts
deleted file mode 100644
index e8def04..0000000
--- a/node_modules/rxjs/src/internal/testing/SubscriptionLoggable.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Scheduler } from '../Scheduler';
-import { SubscriptionLog } from './SubscriptionLog';
-
-export class SubscriptionLoggable {
- public subscriptions: SubscriptionLog[] = [];
- // @ts-ignore: Property has no initializer and is not definitely assigned
- scheduler: Scheduler;
-
- logSubscribedFrame(): number {
- this.subscriptions.push(new SubscriptionLog(this.scheduler.now()));
- return this.subscriptions.length - 1;
- }
-
- logUnsubscribedFrame(index: number) {
- const subscriptionLogs = this.subscriptions;
- const oldSubscriptionLog = subscriptionLogs[index];
- subscriptionLogs[index] = new SubscriptionLog(
- oldSubscriptionLog.subscribedFrame,
- this.scheduler.now()
- );
- }
-}
diff --git a/node_modules/rxjs/src/internal/testing/TestMessage.ts b/node_modules/rxjs/src/internal/testing/TestMessage.ts
deleted file mode 100644
index 918b477..0000000
--- a/node_modules/rxjs/src/internal/testing/TestMessage.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { ObservableNotification } from '../types';
-
-export interface TestMessage {
- frame: number;
- notification: ObservableNotification<any>;
- isGhost?: boolean;
-}
diff --git a/node_modules/rxjs/src/internal/testing/TestScheduler.ts b/node_modules/rxjs/src/internal/testing/TestScheduler.ts
deleted file mode 100644
index 0045166..0000000
--- a/node_modules/rxjs/src/internal/testing/TestScheduler.ts
+++ /dev/null
@@ -1,690 +0,0 @@
-import { Observable } from '../Observable';
-import { ColdObservable } from './ColdObservable';
-import { HotObservable } from './HotObservable';
-import { TestMessage } from './TestMessage';
-import { SubscriptionLog } from './SubscriptionLog';
-import { Subscription } from '../Subscription';
-import { VirtualTimeScheduler, VirtualAction } from '../scheduler/VirtualTimeScheduler';
-import { ObservableNotification } from '../types';
-import { COMPLETE_NOTIFICATION, errorNotification, nextNotification } from '../NotificationFactories';
-import { dateTimestampProvider } from '../scheduler/dateTimestampProvider';
-import { performanceTimestampProvider } from '../scheduler/performanceTimestampProvider';
-import { animationFrameProvider } from '../scheduler/animationFrameProvider';
-import type { TimerHandle } from '../scheduler/timerHandle';
-import { immediateProvider } from '../scheduler/immediateProvider';
-import { intervalProvider } from '../scheduler/intervalProvider';
-import { timeoutProvider } from '../scheduler/timeoutProvider';
-
-const defaultMaxFrame: number = 750;
-
-export interface RunHelpers {
- cold: typeof TestScheduler.prototype.createColdObservable;
- hot: typeof TestScheduler.prototype.createHotObservable;
- flush: typeof TestScheduler.prototype.flush;
- time: typeof TestScheduler.prototype.createTime;
- expectObservable: typeof TestScheduler.prototype.expectObservable;
- expectSubscriptions: typeof TestScheduler.prototype.expectSubscriptions;
- animate: (marbles: string) => void;
-}
-
-interface FlushableTest {
- ready: boolean;
- actual?: any[];
- expected?: any[];
-}
-
-export type observableToBeFn = (marbles: string, values?: any, errorValue?: any) => void;
-export type subscriptionLogsToBeFn = (marbles: string | string[]) => void;
-
-export class TestScheduler extends VirtualTimeScheduler {
- /**
- * The number of virtual time units each character in a marble diagram represents. If
- * the test scheduler is being used in "run mode", via the `run` method, this is temporarily
- * set to `1` for the duration of the `run` block, then set back to whatever value it was.
- */
- static frameTimeFactor = 10;
-
- /**
- * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.
- */
- public readonly hotObservables: HotObservable<any>[] = [];
-
- /**
- * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.
- */
- public readonly coldObservables: ColdObservable<any>[] = [];
-
- /**
- * Test meta data to be processed during `flush()`
- */
- private flushTests: FlushableTest[] = [];
-
- /**
- * Indicates whether the TestScheduler instance is operating in "run mode",
- * meaning it's processing a call to `run()`
- */
- private runMode = false;
-
- /**
- *
- * @param assertDeepEqual A function to set up your assertion for your test harness
- */
- constructor(public assertDeepEqual: (actual: any, expected: any) => boolean | void) {
- super(VirtualAction, defaultMaxFrame);
- }
-
- createTime(marbles: string): number {
- const indexOf = this.runMode ? marbles.trim().indexOf('|') : marbles.indexOf('|');
- if (indexOf === -1) {
- throw new Error('marble diagram for time should have a completion marker "|"');
- }
- return indexOf * TestScheduler.frameTimeFactor;
- }
-
- /**
- * @param marbles A diagram in the marble DSL. Letters map to keys in `values` if provided.
- * @param values Values to use for the letters in `marbles`. If omitted, the letters themselves are used.
- * @param error The error to use for the `#` marble (if present).
- */
- createColdObservable<T = string>(marbles: string, values?: { [marble: string]: T }, error?: any): ColdObservable<T> {
- if (marbles.indexOf('^') !== -1) {
- throw new Error('cold observable cannot have subscription offset "^"');
- }
- if (marbles.indexOf('!') !== -1) {
- throw new Error('cold observable cannot have unsubscription marker "!"');
- }
- const messages = TestScheduler.parseMarbles(marbles, values, error, undefined, this.runMode);
- const cold = new ColdObservable<T>(messages, this);
- this.coldObservables.push(cold);
- return cold;
- }
-
- /**
- * @param marbles A diagram in the marble DSL. Letters map to keys in `values` if provided.
- * @param values Values to use for the letters in `marbles`. If omitted, the letters themselves are used.
- * @param error The error to use for the `#` marble (if present).
- */
- createHotObservable<T = string>(marbles: string, values?: { [marble: string]: T }, error?: any): HotObservable<T> {
- if (marbles.indexOf('!') !== -1) {
- throw new Error('hot observable cannot have unsubscription marker "!"');
- }
- const messages = TestScheduler.parseMarbles(marbles, values, error, undefined, this.runMode);
- const subject = new HotObservable<T>(messages, this);
- this.hotObservables.push(subject);
- return subject;
- }
-
- private materializeInnerObservable(observable: Observable<any>, outerFrame: number): TestMessage[] {
- const messages: TestMessage[] = [];
- observable.subscribe({
- next: (value) => {
- messages.push({ frame: this.frame - outerFrame, notification: nextNotification(value) });
- },
- error: (error) => {
- messages.push({ frame: this.frame - outerFrame, notification: errorNotification(error) });
- },
- complete: () => {
- messages.push({ frame: this.frame - outerFrame, notification: COMPLETE_NOTIFICATION });
- },
- });
- return messages;
- }
-
- expectObservable<T>(observable: Observable<T>, subscriptionMarbles: string | null = null) {
- const actual: TestMessage[] = [];
- const flushTest: FlushableTest = { actual, ready: false };
- const subscriptionParsed = TestScheduler.parseMarblesAsSubscriptions(subscriptionMarbles, this.runMode);
- const subscriptionFrame = subscriptionParsed.subscribedFrame === Infinity ? 0 : subscriptionParsed.subscribedFrame;
- const unsubscriptionFrame = subscriptionParsed.unsubscribedFrame;
- let subscription: Subscription;
-
- this.schedule(() => {
- subscription = observable.subscribe({
- next: (x) => {
- // Support Observable-of-Observables
- const value = x instanceof Observable ? this.materializeInnerObservable(x, this.frame) : x;
- actual.push({ frame: this.frame, notification: nextNotification(value) });
- },
- error: (error) => {
- actual.push({ frame: this.frame, notification: errorNotification(error) });
- },
- complete: () => {
- actual.push({ frame: this.frame, notification: COMPLETE_NOTIFICATION });
- },
- });
- }, subscriptionFrame);
-
- if (unsubscriptionFrame !== Infinity) {
- this.schedule(() => subscription.unsubscribe(), unsubscriptionFrame);
- }
-
- this.flushTests.push(flushTest);
- const { runMode } = this;
-
- return {
- toBe(marbles: string, values?: any, errorValue?: any) {
- flushTest.ready = true;
- flushTest.expected = TestScheduler.parseMarbles(marbles, values, errorValue, true, runMode);
- },
- toEqual: (other: Observable<T>) => {
- flushTest.ready = true;
- flushTest.expected = [];
- this.schedule(() => {
- subscription = other.subscribe({
- next: (x) => {
- // Support Observable-of-Observables
- const value = x instanceof Observable ? this.materializeInnerObservable(x, this.frame) : x;
- flushTest.expected!.push({ frame: this.frame, notification: nextNotification(value) });
- },
- error: (error) => {
- flushTest.expected!.push({ frame: this.frame, notification: errorNotification(error) });
- },
- complete: () => {
- flushTest.expected!.push({ frame: this.frame, notification: COMPLETE_NOTIFICATION });
- },
- });
- }, subscriptionFrame);
- },
- };
- }
-
- expectSubscriptions(actualSubscriptionLogs: SubscriptionLog[]): { toBe: subscriptionLogsToBeFn } {
- const flushTest: FlushableTest = { actual: actualSubscriptionLogs, ready: false };
- this.flushTests.push(flushTest);
- const { runMode } = this;
- return {
- toBe(marblesOrMarblesArray: string | string[]) {
- const marblesArray: string[] = typeof marblesOrMarblesArray === 'string' ? [marblesOrMarblesArray] : marblesOrMarblesArray;
- flushTest.ready = true;
- flushTest.expected = marblesArray
- .map((marbles) => TestScheduler.parseMarblesAsSubscriptions(marbles, runMode))
- .filter((marbles) => marbles.subscribedFrame !== Infinity);
- },
- };
- }
-
- flush() {
- const hotObservables = this.hotObservables;
- while (hotObservables.length > 0) {
- hotObservables.shift()!.setup();
- }
-
- super.flush();
-
- this.flushTests = this.flushTests.filter((test) => {
- if (test.ready) {
- this.assertDeepEqual(test.actual, test.expected);
- return false;
- }
- return true;
- });
- }
-
- static parseMarblesAsSubscriptions(marbles: string | null, runMode = false): SubscriptionLog {
- if (typeof marbles !== 'string') {
- return new SubscriptionLog(Infinity);
- }
- // Spreading the marbles into an array leverages ES2015's support for emoji
- // characters when iterating strings.
- const characters = [...marbles];
- const len = characters.length;
- let groupStart = -1;
- let subscriptionFrame = Infinity;
- let unsubscriptionFrame = Infinity;
- let frame = 0;
-
- for (let i = 0; i < len; i++) {
- let nextFrame = frame;
- const advanceFrameBy = (count: number) => {
- nextFrame += count * this.frameTimeFactor;
- };
- const c = characters[i];
- switch (c) {
- case ' ':
- // Whitespace no longer advances time
- if (!runMode) {
- advanceFrameBy(1);
- }
- break;
- case '-':
- advanceFrameBy(1);
- break;
- case '(':
- groupStart = frame;
- advanceFrameBy(1);
- break;
- case ')':
- groupStart = -1;
- advanceFrameBy(1);
- break;
- case '^':
- if (subscriptionFrame !== Infinity) {
- throw new Error("found a second subscription point '^' in a " + 'subscription marble diagram. There can only be one.');
- }
- subscriptionFrame = groupStart > -1 ? groupStart : frame;
- advanceFrameBy(1);
- break;
- case '!':
- if (unsubscriptionFrame !== Infinity) {
- throw new Error("found a second unsubscription point '!' in a " + 'subscription marble diagram. There can only be one.');
- }
- unsubscriptionFrame = groupStart > -1 ? groupStart : frame;
- break;
- default:
- // time progression syntax
- if (runMode && c.match(/^[0-9]$/)) {
- // Time progression must be preceded by at least one space
- // if it's not at the beginning of the diagram
- if (i === 0 || characters[i - 1] === ' ') {
- const buffer = characters.slice(i).join('');
- const match = buffer.match(/^([0-9]+(?:\.[0-9]+)?)(ms|s|m) /);
- if (match) {
- i += match[0].length - 1;
- const duration = parseFloat(match[1]);
- const unit = match[2];
- let durationInMs: number;
-
- switch (unit) {
- case 'ms':
- durationInMs = duration;
- break;
- case 's':
- durationInMs = duration * 1000;
- break;
- case 'm':
- durationInMs = duration * 1000 * 60;
- break;
- default:
- break;
- }
-
- advanceFrameBy(durationInMs! / this.frameTimeFactor);
- break;
- }
- }
- }
-
- throw new Error("there can only be '^' and '!' markers in a " + "subscription marble diagram. Found instead '" + c + "'.");
- }
-
- frame = nextFrame;
- }
-
- if (unsubscriptionFrame < 0) {
- return new SubscriptionLog(subscriptionFrame);
- } else {
- return new SubscriptionLog(subscriptionFrame, unsubscriptionFrame);
- }
- }
-
- static parseMarbles(
- marbles: string,
- values?: any,
- errorValue?: any,
- materializeInnerObservables: boolean = false,
- runMode = false
- ): TestMessage[] {
- if (marbles.indexOf('!') !== -1) {
- throw new Error('conventional marble diagrams cannot have the ' + 'unsubscription marker "!"');
- }
- // Spreading the marbles into an array leverages ES2015's support for emoji
- // characters when iterating strings.
- const characters = [...marbles];
- const len = characters.length;
- const testMessages: TestMessage[] = [];
- const subIndex = runMode ? marbles.replace(/^[ ]+/, '').indexOf('^') : marbles.indexOf('^');
- let frame = subIndex === -1 ? 0 : subIndex * -this.frameTimeFactor;
- const getValue =
- typeof values !== 'object'
- ? (x: any) => x
- : (x: any) => {
- // Support Observable-of-Observables
- if (materializeInnerObservables && values[x] instanceof ColdObservable) {
- return values[x].messages;
- }
- return values[x];
- };
- let groupStart = -1;
-
- for (let i = 0; i < len; i++) {
- let nextFrame = frame;
- const advanceFrameBy = (count: number) => {
- nextFrame += count * this.frameTimeFactor;
- };
-
- let notification: ObservableNotification<any> | undefined;
- const c = characters[i];
- switch (c) {
- case ' ':
- // Whitespace no longer advances time
- if (!runMode) {
- advanceFrameBy(1);
- }
- break;
- case '-':
- advanceFrameBy(1);
- break;
- case '(':
- groupStart = frame;
- advanceFrameBy(1);
- break;
- case ')':
- groupStart = -1;
- advanceFrameBy(1);
- break;
- case '|':
- notification = COMPLETE_NOTIFICATION;
- advanceFrameBy(1);
- break;
- case '^':
- advanceFrameBy(1);
- break;
- case '#':
- notification = errorNotification(errorValue || 'error');
- advanceFrameBy(1);
- break;
- default:
- // Might be time progression syntax, or a value literal
- if (runMode && c.match(/^[0-9]$/)) {
- // Time progression must be preceded by at least one space
- // if it's not at the beginning of the diagram
- if (i === 0 || characters[i - 1] === ' ') {
- const buffer = characters.slice(i).join('');
- const match = buffer.match(/^([0-9]+(?:\.[0-9]+)?)(ms|s|m) /);
- if (match) {
- i += match[0].length - 1;
- const duration = parseFloat(match[1]);
- const unit = match[2];
- let durationInMs: number;
-
- switch (unit) {
- case 'ms':
- durationInMs = duration;
- break;
- case 's':
- durationInMs = duration * 1000;
- break;
- case 'm':
- durationInMs = duration * 1000 * 60;
- break;
- default:
- break;
- }
-
- advanceFrameBy(durationInMs! / this.frameTimeFactor);
- break;
- }
- }
- }
-
- notification = nextNotification(getValue(c));
- advanceFrameBy(1);
- break;
- }
-
- if (notification) {
- testMessages.push({ frame: groupStart > -1 ? groupStart : frame, notification });
- }
-
- frame = nextFrame;
- }
- return testMessages;
- }
-
- private createAnimator() {
- if (!this.runMode) {
- throw new Error('animate() must only be used in run mode');
- }
-
- // The TestScheduler assigns a delegate to the provider that's used for
- // requestAnimationFrame (rAF). The delegate works in conjunction with the
- // animate run helper to coordinate the invocation of any rAF callbacks,
- // that are effected within tests, with the animation frames specified by
- // the test's author - in the marbles that are passed to the animate run
- // helper. This allows the test's author to write deterministic tests and
- // gives the author full control over when - or if - animation frames are
- // 'painted'.
-
- let lastHandle = 0;
- let map: Map<number, FrameRequestCallback> | undefined;
-
- const delegate = {
- requestAnimationFrame(callback: FrameRequestCallback) {
- if (!map) {
- throw new Error('animate() was not called within run()');
- }
- const handle = ++lastHandle;
- map.set(handle, callback);
- return handle;
- },
- cancelAnimationFrame(handle: number) {
- if (!map) {
- throw new Error('animate() was not called within run()');
- }
- map.delete(handle);
- },
- };
-
- const animate = (marbles: string) => {
- if (map) {
- throw new Error('animate() must not be called more than once within run()');
- }
- if (/[|#]/.test(marbles)) {
- throw new Error('animate() must not complete or error');
- }
- map = new Map<number, FrameRequestCallback>();
- const messages = TestScheduler.parseMarbles(marbles, undefined, undefined, undefined, true);
- for (const message of messages) {
- this.schedule(() => {
- const now = this.now();
- // Capture the callbacks within the queue and clear the queue
- // before enumerating the callbacks, as callbacks might
- // reschedule themselves. (And, yeah, we're using a Map to represent
- // the queue, but the values are guaranteed to be returned in
- // insertion order, so it's all good. Trust me, I've read the docs.)
- const callbacks = Array.from(map!.values());
- map!.clear();
- for (const callback of callbacks) {
- callback(now);
- }
- }, message.frame);
- }
- };
-
- return { animate, delegate };
- }
-
- private createDelegates() {
- // When in run mode, the TestScheduler provides alternate implementations
- // of set/clearImmediate and set/clearInterval. These implementations are
- // consumed by the scheduler implementations via the providers. This is
- // done to effect deterministic asap and async scheduler behavior so that
- // all of the schedulers are testable in 'run mode'. Prior to v7,
- // delegation occurred at the scheduler level. That is, the asap and
- // animation frame schedulers were identical in behavior to the async
- // scheduler. Now, when in run mode, asap actions are prioritized over
- // async actions and animation frame actions are coordinated using the
- // animate run helper.
-
- let lastHandle = 0;
- const scheduleLookup = new Map<
- TimerHandle,
- {
- due: number;
- duration: number;
- handle: TimerHandle;
- handler: () => void;
- subscription: Subscription;
- type: 'immediate' | 'interval' | 'timeout';
- }
- >();
-
- const run = () => {
- // Whenever a scheduled run is executed, it must run a single immediate
- // or interval action - with immediate actions being prioritized over
- // interval and timeout actions.
- const now = this.now();
- const scheduledRecords = Array.from(scheduleLookup.values());
- const scheduledRecordsDue = scheduledRecords.filter(({ due }) => due <= now);
- const dueImmediates = scheduledRecordsDue.filter(({ type }) => type === 'immediate');
- if (dueImmediates.length > 0) {
- const { handle, handler } = dueImmediates[0];
- scheduleLookup.delete(handle);
- handler();
- return;
- }
- const dueIntervals = scheduledRecordsDue.filter(({ type }) => type === 'interval');
- if (dueIntervals.length > 0) {
- const firstDueInterval = dueIntervals[0];
- const { duration, handler } = firstDueInterval;
- firstDueInterval.due = now + duration;
- // The interval delegate must behave like setInterval, so run needs to
- // be rescheduled. This will continue until the clearInterval delegate
- // unsubscribes and deletes the handle from the map.
- firstDueInterval.subscription = this.schedule(run, duration);
- handler();
- return;
- }
- const dueTimeouts = scheduledRecordsDue.filter(({ type }) => type === 'timeout');
- if (dueTimeouts.length > 0) {
- const { handle, handler } = dueTimeouts[0];
- scheduleLookup.delete(handle);
- handler();
- return;
- }
- throw new Error('Expected a due immediate or interval');
- };
-
- // The following objects are the delegates that replace conventional
- // runtime implementations with TestScheduler implementations.
- //
- // The immediate delegate is depended upon by the asapScheduler.
- //
- // The interval delegate is depended upon by the asyncScheduler.
- //
- // The timeout delegate is not depended upon by any scheduler, but it's
- // included here because the onUnhandledError and onStoppedNotification
- // configuration points use setTimeout to avoid producer interference. It's
- // inclusion allows for the testing of these configuration points.
-
- const immediate = {
- setImmediate: (handler: () => void) => {
- const handle = ++lastHandle;
- scheduleLookup.set(handle, {
- due: this.now(),
- duration: 0,
- handle,
- handler,
- subscription: this.schedule(run, 0),
- type: 'immediate',
- });
- return handle;
- },
- clearImmediate: (handle: TimerHandle) => {
- const value = scheduleLookup.get(handle);
- if (value) {
- value.subscription.unsubscribe();
- scheduleLookup.delete(handle);
- }
- },
- };
-
- const interval = {
- setInterval: (handler: () => void, duration = 0) => {
- const handle = ++lastHandle;
- scheduleLookup.set(handle, {
- due: this.now() + duration,
- duration,
- handle,
- handler,
- subscription: this.schedule(run, duration),
- type: 'interval',
- });
- return handle;
- },
- clearInterval: (handle: TimerHandle) => {
- const value = scheduleLookup.get(handle);
- if (value) {
- value.subscription.unsubscribe();
- scheduleLookup.delete(handle);
- }
- },
- };
-
- const timeout = {
- setTimeout: (handler: () => void, duration = 0) => {
- const handle = ++lastHandle;
- scheduleLookup.set(handle, {
- due: this.now() + duration,
- duration,
- handle,
- handler,
- subscription: this.schedule(run, duration),
- type: 'timeout',
- });
- return handle;
- },
- clearTimeout: (handle: TimerHandle) => {
- const value = scheduleLookup.get(handle);
- if (value) {
- value.subscription.unsubscribe();
- scheduleLookup.delete(handle);
- }
- },
- };
-
- return { immediate, interval, timeout };
- }
-
- /**
- * The `run` method performs the test in 'run mode' - in which schedulers
- * used within the test automatically delegate to the `TestScheduler`. That
- * is, in 'run mode' there is no need to explicitly pass a `TestScheduler`
- * instance to observable creators or operators.
- *
- * @see {@link /guide/testing/marble-testing}
- */
- run<T>(callback: (helpers: RunHelpers) => T): T {
- const prevFrameTimeFactor = TestScheduler.frameTimeFactor;
- const prevMaxFrames = this.maxFrames;
-
- TestScheduler.frameTimeFactor = 1;
- this.maxFrames = Infinity;
- this.runMode = true;
-
- const animator = this.createAnimator();
- const delegates = this.createDelegates();
-
- animationFrameProvider.delegate = animator.delegate;
- dateTimestampProvider.delegate = this;
- immediateProvider.delegate = delegates.immediate;
- intervalProvider.delegate = delegates.interval;
- timeoutProvider.delegate = delegates.timeout;
- performanceTimestampProvider.delegate = this;
-
- const helpers: RunHelpers = {
- cold: this.createColdObservable.bind(this),
- hot: this.createHotObservable.bind(this),
- flush: this.flush.bind(this),
- time: this.createTime.bind(this),
- expectObservable: this.expectObservable.bind(this),
- expectSubscriptions: this.expectSubscriptions.bind(this),
- animate: animator.animate,
- };
- try {
- const ret = callback(helpers);
- this.flush();
- return ret;
- } finally {
- TestScheduler.frameTimeFactor = prevFrameTimeFactor;
- this.maxFrames = prevMaxFrames;
- this.runMode = false;
- animationFrameProvider.delegate = undefined;
- dateTimestampProvider.delegate = undefined;
- immediateProvider.delegate = undefined;
- intervalProvider.delegate = undefined;
- timeoutProvider.delegate = undefined;
- performanceTimestampProvider.delegate = undefined;
- }
- }
-}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage