jest-marbles
Version:
Marble testing helpers library for RxJs and Jest
1 lines • 27.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/rxjs/cold-observable.ts","../src/rxjs/scheduler.ts","../src/notification-event.ts","../src/notification-kind.ts","../src/marblizer.ts","../src/jest/custom-matchers.ts","../src/rxjs/assert-deep-equal.ts","../src/rxjs/hot-observable.ts","../src/rxjs/strip-alignment-chars.ts","../src/marble-test.ts","../src/animate.ts","../index.ts"],"sourcesContent":["import { Observable } from 'rxjs';\nimport { ColdObservable as RxColdObservable } from 'rxjs/internal/testing/ColdObservable';\nimport { SubscriptionLog } from '../rxjs/types';\n\nimport { Scheduler } from './scheduler';\n\nexport class ColdObservable<T = unknown> extends Observable<T> {\n source: RxColdObservable<T>;\n constructor(\n public marbles: string,\n public values?: Record<string, T>,\n public error?: any\n ) {\n super();\n\n this.source = Scheduler.get().createColdObservable<T>(marbles, values, error);\n }\n\n getSubscriptions(): SubscriptionLog[] {\n return this.source.subscriptions;\n }\n}\n","import { Observable } from 'rxjs';\nimport { TestMessages } from './types';\nimport { TestScheduler } from 'rxjs/testing';\n\nimport { assertDeepEqual } from './assert-deep-equal';\n\nconst NEGATED = Symbol('jest-marbles-negated');\n\nexport class Scheduler {\n public static instance: TestScheduler | null;\n\n private static onFlush: (() => void)[] = [];\n private static currentAnimate: ((marbles: string) => void) | null = null;\n private static prevFrameTimeFactor = 0;\n\n public static init(): void {\n const scheduler = new TestScheduler(assertDeepEqual);\n (scheduler as any).runMode = true;\n scheduler.maxFrames = Infinity;\n Scheduler.instance = scheduler;\n Scheduler.onFlush = [];\n Scheduler.currentAnimate = null;\n Scheduler.prevFrameTimeFactor = TestScheduler.frameTimeFactor;\n TestScheduler.frameTimeFactor = 1;\n }\n\n public static get(): TestScheduler {\n if (Scheduler.instance) {\n return Scheduler.instance;\n }\n throw new Error('Scheduler is not initialized');\n }\n\n public static reset(): void {\n Scheduler.instance = null;\n Scheduler.currentAnimate = null;\n }\n\n private static flushTests(): any[] {\n return (Scheduler.get() as any)['flushTests'];\n }\n\n public static captureAnimate(animate: (marbles: string) => void): void {\n Scheduler.currentAnimate = animate;\n }\n\n public static animate(marbles: string): void {\n if (!Scheduler.currentAnimate) {\n throw new Error('animate() can only be used inside marbleTest()');\n }\n Scheduler.currentAnimate(marbles);\n }\n\n public static markLastNegated(): void {\n const tests = Scheduler.flushTests();\n tests[tests.length - 1][NEGATED] = true;\n }\n\n public static markLastReady(): void {\n const tests = Scheduler.flushTests();\n tests[tests.length - 1].ready = true;\n }\n\n public static queueOnFlush(fn: () => void): void {\n Scheduler.onFlush.push(fn);\n }\n\n public static clearFlushTests(): void {\n Scheduler.flushTests().length = 0;\n }\n\n public static installNegationAwareAssert(): void {\n const scheduler = Scheduler.get();\n const flushTests = Scheduler.flushTests();\n const hasNegated = flushTests.some((t) => t[NEGATED]);\n if (!hasNegated) {\n return;\n }\n const negatedSet = new WeakSet<object>(flushTests.filter((t) => t[NEGATED]));\n const readyTests = flushTests.filter((t) => t.ready);\n let callIndex = 0;\n\n (scheduler as any).assertDeepEqual = (actual: any, expected: any) => {\n const test = readyTests[callIndex++];\n if (test && negatedSet.has(test)) {\n let threw = false;\n try {\n assertDeepEqual(actual, expected);\n } catch {\n threw = true;\n }\n if (!threw) {\n throw new Error(\n 'Expected observables to differ, but they matched.\\n' +\n ` Received: ${JSON.stringify(actual)}\\n` +\n ` Not expected: ${JSON.stringify(expected)}`\n );\n }\n } else {\n assertDeepEqual(actual, expected);\n }\n };\n }\n\n public static teardown(): void {\n const scheduler = Scheduler.get();\n Scheduler.installNegationAwareAssert();\n scheduler.run(() => {\n /* run() forces frameTimeFactor = 1 internally; no override needed */\n });\n while (Scheduler.onFlush.length > 0) {\n Scheduler.onFlush.shift()?.();\n }\n TestScheduler.frameTimeFactor = Scheduler.prevFrameTimeFactor;\n Scheduler.reset();\n }\n\n public static materializeInnerObservable(observable: Observable<any>, outerFrame: number): TestMessages {\n const scheduler = Scheduler.get();\n // @ts-expect-error to avoid code duplication\n return scheduler.materializeInnerObservable(observable, outerFrame);\n }\n}\n","export class NotificationEvent {\n marbles = '';\n constructor(public start: number) {}\n get end(): number {\n return this.start + this.marbles.length;\n }\n}\n","import { MarblesGlossary } from './marbles-glossary';\nexport const ValueLiteral = {};\n\nexport const NotificationKindChars = {\n N: ValueLiteral,\n C: MarblesGlossary.Completion,\n E: MarblesGlossary.Error,\n};\n","import { SubscriptionLog, TestMessages } from './rxjs/types';\nimport { MarblesGlossary } from './marbles-glossary';\nimport { NotificationEvent } from './notification-event';\nimport { NotificationKindChars, ValueLiteral } from './notification-kind';\n\nconst frameStep = 1;\n\nexport class Marblizer {\n public static marblize(messages: TestMessages): string {\n const emissions = Marblizer.getNotificationEvents(messages);\n let marbles = '';\n for (let i = 0, prevEndFrame = 0; i < emissions.length; prevEndFrame = emissions[i].end, i++) {\n marbles = `${marbles}${\n MarblesGlossary.TimeFrame.repeat(emissions[i].start - prevEndFrame) + emissions[i].marbles\n }`;\n }\n return marbles;\n }\n\n public static marblizeSubscriptions(logs: SubscriptionLog[]): string[] {\n return logs.map(\n (log) =>\n this.marblizeLogEntry(log.subscribedFrame / frameStep, MarblesGlossary.Subscription) +\n this.marblizeLogEntry(\n (log.unsubscribedFrame - log.subscribedFrame) / frameStep - 1,\n MarblesGlossary.Unsubscription\n )\n );\n }\n\n private static marblizeLogEntry(logPoint: number, symbol: string): string {\n if (logPoint !== Infinity) {\n return MarblesGlossary.TimeFrame.repeat(logPoint) + symbol;\n } else {\n return '';\n }\n }\n\n private static getNotificationEvents(messages: TestMessages) {\n const framesToEmissions = messages.reduce<{ [frame: number]: NotificationEvent }>((result, message) => {\n if (!result[message.frame]) {\n result[message.frame] = new NotificationEvent(message.frame / frameStep);\n }\n const event = result[message.frame];\n event.marbles += Marblizer.extractMarble(message);\n return result;\n }, {});\n\n const events = Object.values(framesToEmissions);\n\n Marblizer.encloseGroupEvents(events);\n return events;\n }\n\n private static extractMarble(message: TestMessages[0]) {\n let marble = NotificationKindChars[message.notification.kind];\n if (marble === ValueLiteral) marble = (message.notification as any).value;\n return marble;\n }\n\n private static encloseGroupEvents(events: NotificationEvent[]) {\n events.forEach((event) => {\n if (event.marbles.length > 1) {\n event.marbles = `${MarblesGlossary.GroupStart}${event.marbles}${MarblesGlossary.GroupEnd}`;\n }\n });\n }\n}\n","import { TestMessages, SubscriptionLog } from '../rxjs/types';\nimport { Marblizer } from '../marblizer';\n\nfunction canMarblize(...messages: TestMessages[]) {\n return messages.every(isMessagesMarblizable);\n}\n\nfunction isMessagesMarblizable(messages: TestMessages): boolean {\n return messages.every(\n ({ notification }) =>\n notification.kind === 'C' ||\n (notification.kind === 'E' && notification.error === 'error') ||\n (notification.kind === 'N' && isCharacter(notification.value))\n );\n}\n\nfunction isCharacter(value: any): boolean {\n return (\n (typeof value === 'string' && value.length === 1) || (value !== undefined && JSON.stringify(value).length === 1)\n );\n}\n\nexport const customTestMatchers: jest.ExpectExtendMap = {\n toBeNotifications(actual: TestMessages, expected: TestMessages) {\n let actualMarble: string | TestMessages = actual;\n let expectedMarble: string | TestMessages = expected;\n if (canMarblize(actual, expected)) {\n actualMarble = Marblizer.marblize(actual);\n expectedMarble = Marblizer.marblize(expected);\n }\n const pass = this.equals(actualMarble, expectedMarble);\n\n const message = pass\n ? () =>\n this.utils.matcherHint('.not.toBeNotifications') +\n '\\n\\n' +\n `Expected notifications to not be:\\n` +\n ` ${this.utils.printExpected(expectedMarble)}\\n` +\n `But got:\\n` +\n ` ${this.utils.printReceived(actualMarble)}`\n : () => {\n const diffString = this.utils.diff(expectedMarble, actualMarble, {\n expand: true,\n });\n return (\n this.utils.matcherHint('.toBeNotifications') +\n '\\n\\n' +\n `Expected notifications to be:\\n` +\n ` ${this.utils.printExpected(expectedMarble)}\\n` +\n `But got:\\n` +\n ` ${this.utils.printReceived(actualMarble)}` +\n (diffString ? `\\n\\nDifference:\\n\\n${diffString}` : '')\n );\n };\n\n return { message, pass };\n },\n\n toBeSubscriptions(actual: SubscriptionLog[], expected: SubscriptionLog[]) {\n const actualMarbleArray = Marblizer.marblizeSubscriptions(actual);\n const expectedMarbleArray = Marblizer.marblizeSubscriptions(expected);\n\n const pass = subscriptionsPass(actualMarbleArray, expectedMarbleArray);\n const message = pass\n ? () =>\n this.utils.matcherHint('.not.toHaveSubscriptions') +\n '\\n\\n' +\n `Expected observable to not have the following subscription points:\\n` +\n ` ${this.utils.printExpected(expectedMarbleArray)}\\n` +\n `But got:\\n` +\n ` ${this.utils.printReceived(actualMarbleArray)}`\n : () => {\n const diffString = this.utils.diff(expectedMarbleArray, actualMarbleArray, {\n expand: true,\n });\n return (\n this.utils.matcherHint('.toHaveSubscriptions') +\n '\\n\\n' +\n `Expected observable to have the following subscription points:\\n` +\n ` ${this.utils.printExpected(expectedMarbleArray)}\\n` +\n `But got:\\n` +\n ` ${this.utils.printReceived(actualMarbleArray)}` +\n (diffString ? `\\n\\nDifference:\\n\\n${diffString}` : '')\n );\n };\n\n return { message, pass };\n },\n\n toHaveEmptySubscriptions(actual: SubscriptionLog[] | undefined) {\n const pass = !(actual && actual.length > 0);\n let marbles: string[];\n if (actual && actual.length > 0) {\n marbles = Marblizer.marblizeSubscriptions(actual);\n }\n const message = pass\n ? () =>\n this.utils.matcherHint('.not.toHaveNoSubscriptions') +\n '\\n\\n' +\n `Expected observable to have at least one subscription point, but got nothing` +\n this.utils.printReceived('')\n : () =>\n this.utils.matcherHint('.toHaveNoSubscriptions') +\n '\\n\\n' +\n `Expected observable to have no subscription points\\n` +\n `But got:\\n` +\n ` ${this.utils.printReceived(marbles)}\\n\\n`;\n return { message, pass };\n },\n};\n\nfunction subscriptionsPass(actualMarbleArray: string[], expectedMarbleArray: string[]): boolean {\n if (actualMarbleArray.length !== expectedMarbleArray.length) {\n return false;\n }\n let pass = true;\n for (const actualMarble of actualMarbleArray) {\n if (!expectedMarbleArray.includes(actualMarble)) {\n pass = false;\n break;\n }\n }\n return pass;\n}\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace jest {\n interface Matchers<R extends void | Promise<void>> {\n toBeNotifications(notifications: TestMessages): R;\n\n toBeSubscriptions(subscriptions: SubscriptionLog[]): R;\n\n toHaveEmptySubscriptions(): R;\n }\n }\n}\n\nexpect.extend(customTestMatchers);\n","import { TestMessages, SubscriptionLog } from '../rxjs/types';\n\nimport '../jest/custom-matchers';\n\nexport type MessageOrSubscription = TestMessages | SubscriptionLog[];\n\nfunction expectedIsSubscriptionLogArray(\n actual: MessageOrSubscription,\n expected: MessageOrSubscription\n): expected is SubscriptionLog[] {\n return (\n (actual.length === 0 && expected.length === 0) ||\n (expected.length !== 0 && (expected[0] as any).subscribedFrame !== undefined)\n );\n}\n\nfunction actualIsSubscriptionsAndExpectedIsEmpty(\n actual: MessageOrSubscription,\n expected: MessageOrSubscription\n): actual is SubscriptionLog[] {\n return expected.length === 0 && actual.length !== 0 && (actual[0] as any).subscribedFrame !== undefined;\n}\n\nexport function assertDeepEqual(actual: MessageOrSubscription, expected: MessageOrSubscription) {\n if (!expected) return;\n if (actualIsSubscriptionsAndExpectedIsEmpty(actual, expected)) {\n expect(actual).toHaveEmptySubscriptions();\n } else if (expectedIsSubscriptionLogArray(actual, expected)) {\n expect(actual).toBeSubscriptions(expected);\n } else {\n expect(actual).toBeNotifications(expected);\n }\n}\n","import { Observable } from 'rxjs';\nimport { HotObservable as RxHotObservable } from 'rxjs/internal/testing/HotObservable';\nimport { SubscriptionLog } from '../rxjs/types';\n\nimport { Scheduler } from './scheduler';\n\nexport class HotObservable<T = unknown> extends Observable<T> {\n source: RxHotObservable<T>;\n constructor(\n public marbles: string,\n public values?: Record<string, T>,\n public error?: any\n ) {\n super();\n\n this.source = Scheduler.get().createHotObservable<T>(marbles, values, error);\n }\n\n getSubscriptions(): SubscriptionLog[] {\n return this.source.subscriptions;\n }\n}\n","export function stripAlignmentChars(marbles: string) {\n return marbles.replace(/^[ ]+/, '');\n}\n","import { RunHelpers } from 'rxjs/internal/testing/TestScheduler';\nimport { Scheduler } from './rxjs/scheduler';\n\nexport function marbleTest(fn: () => void): () => void {\n return () => {\n try {\n Scheduler.get().run((helpers: RunHelpers) => {\n Scheduler.captureAnimate(helpers.animate);\n fn();\n Scheduler.installNegationAwareAssert();\n });\n } finally {\n Scheduler.clearFlushTests();\n }\n };\n}\n","import { Scheduler } from './rxjs/scheduler';\n\nexport function animate(marbles: string): void {\n Scheduler.animate(marbles);\n}\n","import { ColdObservable } from './src/rxjs/cold-observable';\nimport { HotObservable } from './src/rxjs/hot-observable';\nimport { Scheduler } from './src/rxjs/scheduler';\nimport { stripAlignmentChars } from './src/rxjs/strip-alignment-chars';\nimport { Observable, Subscription } from 'rxjs';\n\nexport type ObservableWithSubscriptions = ColdObservable<any> | HotObservable<any>;\n\nexport { Scheduler } from './src/rxjs/scheduler';\nexport { marbleTest } from './src/marble-test';\nexport { animate } from './src/animate';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace jest {\n interface Matchers<R extends void | Promise<void>> {\n toBeObservable(observable: ObservableWithSubscriptions): R;\n\n toHaveSubscriptions(marbles: string | string[]): R;\n\n toHaveNoSubscriptions(): R;\n\n toBeMarble(marble: string): R;\n\n toSatisfyOnFlush(func: () => void): R;\n }\n }\n}\n\ndeclare module 'expect' {\n interface Matchers<R extends void | Promise<void>> {\n toBeObservable(observable: ObservableWithSubscriptions): R;\n toHaveSubscriptions(marbles: string | string[]): R;\n toHaveNoSubscriptions(): R;\n toBeMarble(marble: string): R;\n toSatisfyOnFlush(func: () => void): R;\n }\n}\n\nexport function hot<T = unknown>(marbles: string, values?: Record<string, T>, error?: any): HotObservable<T> {\n return new HotObservable<T>(stripAlignmentChars(marbles), values, error);\n}\n\nexport function cold<T = unknown>(marbles: string, values?: Record<string, T>, error?: any): ColdObservable<T> {\n return new ColdObservable<T>(stripAlignmentChars(marbles), values, error);\n}\n\nexport function time(marbles: string): number {\n return Scheduler.get().createTime(stripAlignmentChars(marbles));\n}\n\nexport function schedule(work: () => void, delay: number): Subscription {\n return Scheduler.get().schedule(work, delay);\n}\n\nconst dummyPass = {\n message: () => '',\n pass: true,\n};\n\nconst dummyFail = {\n message: () => '',\n pass: false,\n};\n\nexpect.extend({\n toHaveSubscriptions(actual: ObservableWithSubscriptions, marbles: string | string[]) {\n const sanitizedMarbles = Array.isArray(marbles) ? marbles.map(stripAlignmentChars) : stripAlignmentChars(marbles);\n if (this.isNot) {\n Scheduler.get().expectSubscriptions(actual.getSubscriptions()).toBe(sanitizedMarbles);\n Scheduler.markLastNegated();\n return dummyFail;\n }\n Scheduler.get().expectSubscriptions(actual.getSubscriptions()).toBe(sanitizedMarbles);\n return dummyPass;\n },\n\n toHaveNoSubscriptions(actual: ObservableWithSubscriptions) {\n if (this.isNot) {\n throw new Error('toHaveNoSubscriptions cannot be negated — use toHaveSubscriptions instead');\n }\n Scheduler.get().expectSubscriptions(actual.getSubscriptions()).toBe([]);\n return dummyPass;\n },\n\n toBeObservable(actual: Observable<unknown>, expected: ObservableWithSubscriptions) {\n if (this.isNot) {\n Scheduler.get().expectObservable(actual).toBe(expected.marbles, expected.values, expected.error);\n Scheduler.markLastNegated();\n return dummyFail;\n }\n Scheduler.get().expectObservable(actual).toBe(expected.marbles, expected.values, expected.error);\n return dummyPass;\n },\n\n toBeMarble(actual: ObservableWithSubscriptions, marbles: string) {\n if (this.isNot) {\n Scheduler.get().expectObservable(actual).toBe(stripAlignmentChars(marbles));\n Scheduler.markLastNegated();\n return dummyFail;\n }\n Scheduler.get().expectObservable(actual).toBe(stripAlignmentChars(marbles));\n return dummyPass;\n },\n\n toSatisfyOnFlush(actual: ObservableWithSubscriptions, func: () => void) {\n if (this.isNot) {\n throw new Error('toSatisfyOnFlush cannot be negated');\n }\n Scheduler.get().expectObservable(actual);\n Scheduler.markLastReady();\n Scheduler.queueOnFlush(func);\n return dummyPass;\n },\n});\n\nbeforeEach(() => {\n Scheduler.init();\n});\n\nafterEach(() => {\n Scheduler.teardown();\n});\n"],"mappings":"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","names":["animate","Observable","Observable"]}