{"id":13807979,"url":"https://github.com/just-jeb/jest-marbles","last_synced_at":"2025-04-05T07:06:08.435Z","repository":{"id":39790428,"uuid":"120318184","full_name":"just-jeb/jest-marbles","owner":"just-jeb","description":"Helpers library for marbles testing with Jest","archived":false,"fork":false,"pushed_at":"2024-10-29T18:02:04.000Z","size":2585,"stargazers_count":113,"open_issues_count":29,"forks_count":13,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-29T20:10:16.617Z","etag":null,"topics":["jest","jest-marbles","jest-matchers","jest-tests","marble-testing","marbles","marbles-testing","matcher","rxjs","rxjs5","rxjs6","testing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/just-jeb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":null,"patreon":"justjeb","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=43KX7EMK96A94\u0026currency_code=USD\u0026source=url"]}},"created_at":"2018-02-05T14:48:54.000Z","updated_at":"2024-10-29T01:30:08.000Z","dependencies_parsed_at":"2024-01-04T17:27:33.086Z","dependency_job_id":"b0e2f5c5-035c-4551-acc9-aad704c0f33e","html_url":"https://github.com/just-jeb/jest-marbles","commit_stats":{"total_commits":510,"total_committers":20,"mean_commits":25.5,"dds":0.6980392156862745,"last_synced_commit":"662e46657aa1133c358f48a369e8fff8e692a76f"},"previous_names":["meltedspark/jest-marbles"],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/just-jeb%2Fjest-marbles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/just-jeb%2Fjest-marbles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/just-jeb%2Fjest-marbles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/just-jeb%2Fjest-marbles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/just-jeb","download_url":"https://codeload.github.com/just-jeb/jest-marbles/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247226196,"owners_count":20904464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jest","jest-marbles","jest-matchers","jest-tests","marble-testing","marbles","marbles-testing","matcher","rxjs","rxjs5","rxjs6","testing"],"created_at":"2024-08-04T01:01:33.157Z","updated_at":"2025-04-05T07:06:08.399Z","avatar_url":"https://github.com/just-jeb.png","language":"TypeScript","funding_links":["https://patreon.com/justjeb","https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=43KX7EMK96A94\u0026currency_code=USD\u0026source=url"],"categories":["Testing"],"sub_categories":["Component"],"readme":"# jest-marbles\n[![npm version](https://badge.fury.io/js/jest-marbles.svg)](https://badge.fury.io/js/jest-marbles) ![Build Status](https://github.com/just-jeb/jest-marbles/actions/workflows/build.yml/badge.svg?branch=master) ![Packagist](https://img.shields.io/packagist/l/doctrine/orm.svg) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)\n\n\n\nA set of helper functions and Jest matchers for RxJs marble testing.\nThis library will help you to test your reactive code in easy and clear way.\n\n# Features\n - Typescript\n - Marblized error messages\n\n# Prerequisites\n - Jest\n - RxJs\n - Familiarity with [marbles syntax](https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md)\n\n# Not supported (but planning to)\n - Time progression syntax\n\n# Usage\n\nFor RxJs 7:\n```sh\nnpm i jest-marbles@latest -D\n```\n\nFor RxJs 6:\n```sh\nnpm i jest-marbles@2 -D\n```\n\nFor RxJs 5:\n```sh\nnpm i jest-marbles@1 -D\n```\n\nIn the test file:\n\n```js\nimport {cold, hot, time, schedule} from 'jest-marbles';\n```\n\nInside the test:\n\n```js\nexpect(stream).toBeObservable(expected);\nexpect(stream).toBeMarble(marbleString);\nexpect(stream).toHaveSubscriptions(marbleString);\nexpect(stream).toHaveSubscriptions(marbleStringsArray);\nexpect(stream).toHaveNoSubscriptions();\nexpect(stream).toSatisfyOnFlush(() =\u003e {\n  expect(someMock).toHaveBeenCalled();\n})\n```\n\n# Examples\n\n## toBeObservable\nVerifies that the resulting stream emits certain values at certain time frames\n```js\n    it('Should merge two hot observables and start emitting from the subscription point', () =\u003e {\n        const e1 = hot('----a--^--b-------c--|', {a: 0});\n        const e2 = hot('  ---d-^--e---------f-----|', {a: 0});\n        const expected = cold('---(be)----c-f-----|', {a: 0});\n\n        expect(e1.pipe(merge(e2))).toBeObservable(expected);\n    });\n```\nSample output when the test fails (if change the expected result to `'-d--(be)----c-f-----|'`):\n```\nExpected notifications to be:\n  \"-d--(be)----c-f-----|\"\nBut got:\n  \"---(be)----c-f-----|\"\n```\n\n## toBeMarble\nSame as `toBeObservable` but receives marble string instead\n```js\n    it('Should concatenate two cold observables into single cold observable', () =\u003e {\n        const a = cold('-a-|');\n        const b = cold('-b-|');\n        const expected = '-a--b-|';\n        expect(a.pipe(concat(b))).toBeMarble(expected);\n    });\n```\n\n## toHaveSubscriptions\nVerifies that the observable was subscribed in the provided time frames.\nUseful, for example, when you want to verify that particular `switchMap` worked as expected:\n```js\n  it('Should figure out single subscription points', () =\u003e {\n    const x = cold('        --a---b---c--|');\n    const xsubs = '   ------^-------!';\n    const y = cold('                ---d--e---f---|');\n    const ysubs = '   --------------^-------------!';\n    const e1 = hot('  ------x-------y------|', { x, y });\n    const expected = cold('--------a---b----d--e---f---|');\n\n    expect(e1.pipe(switchAll())).toBeObservable(expected);\n    expect(x).toHaveSubscriptions(xsubs);\n    expect(y).toHaveSubscriptions(ysubs);\n  });\n```\nThe matcher can also accept multiple subscription marbles:\n```js\n  it('Should figure out multiple subscription points', () =\u003e {\n    const x = cold('                    --a---b---c--|');\n\n    const y = cold('                ----x---x|', {x});\n    const ySubscription1 = '        ----^---!';\n    //                                     '--a---b---c--|'\n    const ySubscription2 = '        --------^------------!';\n    const expectedY = cold('        ------a---a---b---c--|');\n\n    const z = cold('                   -x|', {x});\n    //                                 '--a---b---c--|'\n    const zSubscription = '            -^------------!';\n    const expectedZ = cold('           ---a---b---c--|');\n\n    expect(y.pipe(switchAll())).toBeObservable(expectedY);\n    expect(z.pipe(switchAll())).toBeObservable(expectedZ);\n\n    expect(x).toHaveSubscriptions([ySubscription1, ySubscription2, zSubscription]);\n  });\n```\nSample output when the test fails (if change `ySubscription1` to `'-----------------^---!'`):\n```\nExpected observable to have the following subscription points:\n  [\"-----------------^---!\", \"--------^------------!\", \"-^------------!\"]\nBut got:\n  [\"-^------------!\", \"----^---!\", \"--------^------------!\"]\n```\n\n## toHaveNoSubscriptions\nVerifies that the observable was not subscribed during the test.\nEspecially useful when you want to verify that certain chain was not called due to an error:\n```js\n  it('Should verify that switchMap was not performed due to an error', () =\u003e {\n    const x = cold('--a---b---c--|');\n    const y = cold('---#-x--', {x});\n    const result = y.pipe(switchAll());\n    expect(result).toBeMarble('---#');\n    expect(x).toHaveNoSubscriptions();\n  });\n```\nSample output when the test fails (if remove error and change the expected marble to `'------a---b---c--|'`):\n```\nExpected observable to have no subscription points\nBut got:\n  [\"----^------------!\"]\n```\n\n## toSatisfyOnFlush\nAllows you to assert on certain side effects/conditions that should be satisfied when the observable has been flushed (finished)\n```js\n  it('should verify mock has been called', () =\u003e {\n      const mock = jest.fn();\n      const stream$ = cold('blah|').pipe(tap(mock));\n      expect(stream$).toSatisfyOnFlush(() =\u003e {\n          expect(mock).toHaveBeenCalledTimes(4);\n      });\n  })\n```\n\n## schedule\nAllows you to schedule task on specified frame\n```js\n  it('should verify subject values', () =\u003e {\n    const source = new Subject();\n    const expected = cold('ab');\n\n    schedule(() =\u003e source.next('a'), 1);\n    schedule(() =\u003e source.next('b'), 2);\n\n    expect(source).toBeObservable(expected);\n  });\n```\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjust-jeb%2Fjest-marbles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjust-jeb%2Fjest-marbles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjust-jeb%2Fjest-marbles/lists"}