<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mateusz Garbaciak</title>
    <description>The latest articles on DEV Community by Mateusz Garbaciak (@getmagit).</description>
    <link>https://dev.to/getmagit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F650391%2F49e2066f-778b-48ba-a891-c9bdcfccf33d.jpeg</url>
      <title>DEV Community: Mateusz Garbaciak</title>
      <link>https://dev.to/getmagit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/getmagit"/>
    <language>en</language>
    <item>
      <title>Choosing e2e testing framework. Cypress vs Playwright case</title>
      <dc:creator>Mateusz Garbaciak</dc:creator>
      <pubDate>Fri, 27 Sep 2024 14:00:31 +0000</pubDate>
      <link>https://dev.to/getmagit/choosing-e2e-testing-framework-cypress-vs-playwright-case-2865</link>
      <guid>https://dev.to/getmagit/choosing-e2e-testing-framework-cypress-vs-playwright-case-2865</guid>
      <description>&lt;p&gt;In one of our client projects, we had to decide on an end-to-end (e2e) testing framework. While we were familiar with Cypress, we wanted to explore a newer option, Playwright. We compared how both frameworks addressed the issues that were most important to us, allowing us to establish criteria for making an informed decision. I'd like to summarize some of the key points we discussed and the conclusions we reached.&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Installation
&lt;/h1&gt;

&lt;p&gt;Both frameworks provide &lt;code&gt;npx&lt;/code&gt; scripts that manage package installation and create example tests to help users get a feel for the framework. They also offer Docker images that can be used for CI integration. While all necessary dependencies for Playwright are stored in &lt;code&gt;node_modules&lt;/code&gt; (with browsers included in the binary), Cypress relies on what is provided in the system (or Docker image). It's worth mentioning that the Cypress binary is stored &lt;a href="https://docs.cypress.io/guides/references/advanced-installation#Binary-cache" rel="noopener noreferrer"&gt;globally in the system&lt;/a&gt;, which can complicate installation if you're working on a corporate PC with restricted rights to install software. This has another implication: if you wish to cache dependencies between CI jobs, you'll need to set the caching directory and store it next to &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Test Explorer
&lt;/h1&gt;

&lt;p&gt;A comprehensive test explorer is essential for navigating and executing tests seamlessly. Both frameworks offer this functionality, but the developer experience (DX) varies. Cypress presents the real application in its explorer, allowing developers to click through the app and explore the tests once they finish execution. Playwright offers similar functionality, but instead of presenting the real application, it displays app screenshots on a timeline. This might feel like a limitation, but fortunately, there is a &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright" rel="noopener noreferrer"&gt;VSCode extension&lt;/a&gt; that helps overcome it.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Syntax and Execution Environment
&lt;/h1&gt;

&lt;p&gt;Both testing frameworks support TypeScript. Cypress handles asynchronous events with a wrapper that looks similar to Promises, while Playwright uses native Promises and supports async/await syntax. It's important to note that Cypress code is executed in the browser, whereas Playwright runs in a 'Node' environment and communicates with the browser through the &lt;a href="https://github.com/microsoft/playwright/issues/4862" rel="noopener noreferrer"&gt;DevTools&lt;/a&gt; protocol. As a result, environment variables can be accessed directly at runtime, which might be useful for passing test-user credentials or other test-related data.&lt;/p&gt;

&lt;p&gt;Below you'll find code snippets of what tests look like for both frameworks. Bear in mind that all selectors have been picked up automatically by the locator picker tool (available in both frameworks).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2hjko0sokket1tnli49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2hjko0sokket1tnli49.png" alt="Example test written in Cypress" width="800" height="464"&gt;&lt;/a&gt;&lt;br&gt;
Example test written in Cypress. Cypress manages asynchronous tasks internally, which is why one of the console logs is logged out of order, right at the start of the test. This might be surprising at first. To execute it after some action, you need to wrap it around the &lt;code&gt;then&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxndb837y16cpr7vxo9nr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxndb837y16cpr7vxo9nr.png" alt="Example test written in Playwright" width="800" height="444"&gt;&lt;/a&gt;&lt;br&gt;
Example Playwright test. The framework uses native async/await syntax, so each statement is executed in order, as one would expect.&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Parallel Test Execution
&lt;/h1&gt;

&lt;p&gt;Both frameworks support parallel test execution, but it's worth noting that this option is available in Playwright out of the box and for free. With Cypress, however, you need to subscribe to &lt;a href="https://www.cypress.io/pricing" rel="noopener noreferrer"&gt;Cypress Cloud&lt;/a&gt;, which is only free for small teams.&lt;/p&gt;

&lt;h1&gt;
  
  
  5. API Testing
&lt;/h1&gt;

&lt;p&gt;In our project, we wanted to cover some functionality with API tests. Our initial idea was to use 'Jest' for this purpose, but it would require us to implement a mechanism to manage auth tokens. With either framework (Playwright or Cypress), this process is simplified. The token can be acquired at the beginning of a test session using application logic (since we have access to the real application) and stored. Later, it can be reused for each API test.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n77d638cxirutf3dbbv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n77d638cxirutf3dbbv.png" alt="Example API test using Cypress" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example API test using Cypress. Cypress uses the &lt;a href="https://docs.cypress.io/guides/references/assertions" rel="noopener noreferrer"&gt;Chai&lt;/a&gt; assertion library. You might want to extend it with additional modules, allowing for &lt;a href="https://github.com/chaijs/deep-eql" rel="noopener noreferrer"&gt;deep checking arrays&lt;/a&gt; or checking &lt;a href="https://www.npmjs.com/package/chai-subset" rel="noopener noreferrer"&gt;the subset of properties&lt;/a&gt; in the result object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sl7tqeiu6zc3jowggts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sl7tqeiu6zc3jowggts.png" alt="Example API test using Playwright" width="798" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example API test using Playwright. For those familiar with Jest, Playwright's syntax looks familiar. It has built-in &lt;a href="https://playwright.dev/docs/api/class-genericassertions" rel="noopener noreferrer"&gt;generic assertions&lt;/a&gt;, a class that lets us check if a received object contains a specific value, if a value is close to another, or if a value is of a specific type, and so on.&lt;/p&gt;

&lt;h1&gt;
  
  
  6. Different Browser Tabs, Changing Origin During Test
&lt;/h1&gt;

&lt;p&gt;Simulating real-world scenarios often involves testing across multiple browser tabs or changing the origin during test execution. While Cypress has a workaround for &lt;a href="https://docs.cypress.io/guides/guides/cross-origin-testing" rel="noopener noreferrer"&gt;the latter&lt;/a&gt;, it's impossible to execute tests involving &lt;a href="https://docs.cypress.io/guides/references/trade-offs" rel="noopener noreferrer"&gt;changing browser tabs&lt;/a&gt;. Playwright, on the other hand, handles such tasks effortlessly due to its method of communicating with the browser. You can open new tabs and switch between them within a test case easily.&lt;/p&gt;

&lt;h1&gt;
  
  
  7. Mobile Viewports
&lt;/h1&gt;

&lt;p&gt;Both Cypress and Playwright support testing on mobile viewports, offering predefined resolutions for various devices. &lt;a href="https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/deviceDescriptorsSource.json" rel="noopener noreferrer"&gt;Playwright's&lt;/a&gt; list seems to be longer than &lt;a href="https://docs.cypress.io/api/commands/viewport" rel="noopener noreferrer"&gt;Cypress'&lt;/a&gt;. In both cases, the resolution can be set either &lt;a href="https://docs.cypress.io/api/commands/viewport" rel="noopener noreferrer"&gt;globally&lt;/a&gt; (or &lt;a href="https://playwright.dev/docs/emulation" rel="noopener noreferrer"&gt;per project&lt;/a&gt; in the case of Playwright) or within a test case. However, it's important to note that this is not about emulating a device, but a device resolution. For thorough testing in real-life scenarios, external tools like &lt;a href="https://www.browserstack.com/" rel="noopener noreferrer"&gt;Browserstack&lt;/a&gt; or &lt;a href="https://www.lambdatest.com/" rel="noopener noreferrer"&gt;Lambdatest&lt;/a&gt; are necessary.&lt;/p&gt;

&lt;h1&gt;
  
  
  8. Visual Comparisons
&lt;/h1&gt;

&lt;p&gt;If you want to ensure that your CSS isn't broken after a change, visual comparison tests are a good idea. Both frameworks support this option, but with different levels of adoption simplicity. In Playwright, it works out of the box; you simply call &lt;code&gt;await expect(page).toHaveScreenshot();&lt;/code&gt;. &lt;a href="https://playwright.dev/docs/test-snapshots" rel="noopener noreferrer"&gt;This function&lt;/a&gt; generates a new screenshot if one isn't already defined; otherwise, it compares the current snapshot to what's stored in the project, with no additional setup required. Cypress, on the other hand, does not support this natively, so you need to rely on external plugins. I recommend checking the official Cypress docs to see what &lt;a href="https://docs.cypress.io/plugins#visual-testing" rel="noopener noreferrer"&gt;tools are recommended&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Taking everything into consideration, we decided to go with Playwright. Its ability to control the browser via the DevTools protocol is a significant advantage, as it allows for testing on different browser tabs without issues. Additionally, its syntax is more explicit, using native &lt;code&gt;Promises&lt;/code&gt; that can be consumed with standard &lt;code&gt;await&lt;/code&gt;, compared to the promise-like syntax of Cypress. We also appreciated how easy it is to perform visual testing with Playwright.&lt;/p&gt;

&lt;h1&gt;
  
  
  Miscellaneous
&lt;/h1&gt;

&lt;p&gt;In our case, running tests on CI turned out to be quite slow. After some investigation, we discovered that the issue was a misconfiguration of our Playwright setup specifically, the trace viewer configuration. We had been using the &lt;a href="https://playwright.dev/docs/trace-viewer" rel="noopener noreferrer"&gt;retain-on-failure&lt;/a&gt; setting, which records traces for all the specs. This resulted in a large number of files needing to be stored, which was very time-consuming for our GitLab runner. Switching to the 'on-first-retry' option resolved the issue.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>cypress</category>
      <category>webtesting</category>
    </item>
    <item>
      <title>RxJS: retry with exponential backoff</title>
      <dc:creator>Mateusz Garbaciak</dc:creator>
      <pubDate>Mon, 17 Apr 2023 09:22:52 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/rxjs-retry-with-exponential-backoff-dpe</link>
      <guid>https://dev.to/playfulprogramming/rxjs-retry-with-exponential-backoff-dpe</guid>
      <description>&lt;p&gt;Cover photo by &lt;a href="https://www.pexels.com/pl-pl/@lucasandrade/" rel="noopener noreferrer"&gt;Lucas Andrade&lt;/a&gt; on &lt;em&gt;Pexels&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Http request may occasionally fail. &lt;strong&gt;RxJS&lt;/strong&gt; provides us with a &lt;code&gt;retry&lt;/code&gt; operator that helps us make a call again in the case of a failure. Let's see how to implement retries with exponential backoff, i.e. delay that grows with every request.&lt;/p&gt;

&lt;p&gt;Back in the days, exponential backoff could be implemented using &lt;code&gt;zip&lt;/code&gt; operator to keep track of an index, or saving error index in closure. Currently it's possible to implement it in a simpler way.&lt;/p&gt;

&lt;p&gt;Let's first have a look at function signature.&lt;/p&gt;

&lt;p&gt;Type of &lt;code&gt;configOrCount&lt;/code&gt; is a union of &lt;code&gt;number&lt;/code&gt; or &lt;code&gt;RetryConfig&lt;/code&gt;. &lt;/p&gt;

&lt;h1&gt;
  
  
  Simple retry
&lt;/h1&gt;

&lt;p&gt;If we provide a number argument for a retry, it stands for maximum count of retries after error. The example below will retry for next 3 times, without a delay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Retry with a delay
&lt;/h1&gt;

&lt;p&gt;If we want to add some delay, we need to provide a retry config object. Below there is an Observable that is going to be retried 3 times, each attempt with a &lt;code&gt;200ms&lt;/code&gt; delay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Retry with backoff
&lt;/h1&gt;

&lt;p&gt;Exponential backoff is about increasing the delay with every failure, to reduce the rate of HTTP queries to server. We might want to make the first retry after &lt;code&gt;200ms&lt;/code&gt;, then after &lt;code&gt;400ms&lt;/code&gt;, third failed attempt should happen after &lt;code&gt;800ms&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;A delay can be either a number, as we have just seen that in the previous example, or a function returning an observable. We will concentrate on the latter now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryIndex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In configuration object we define maximum number of retries, setting it's &lt;code&gt;count&lt;/code&gt; to 3, same as in previous example, what changed is a &lt;code&gt;delay&lt;/code&gt; property, which is now a function. It accepts two parameters, error and current index of a retry. We are ignoring first one and using only &lt;code&gt;retryIndex&lt;/code&gt; to use it when calculating an exponent. &lt;/p&gt;

&lt;p&gt;Our expected backoff values should look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;attempt | value [ms]
1       | 200
2       | 400
3       | 800

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To calculate the dalay we are going to use this formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;delay = 2^(retryIndex-1) * interval

// results:
2^0*200 = 200
2^1*200 = 400
2^2*200 = 800
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have calculated the number of milliseconds to wait, last thing is to use &lt;code&gt;timer&lt;/code&gt; function from &lt;strong&gt;RxJS&lt;/strong&gt;. It is going to do the actual wait, as it emits a value (0) after a specific amount of time. &lt;/p&gt;

&lt;h1&gt;
  
  
  Extract it to RxJS operator
&lt;/h1&gt;

&lt;p&gt;To make this piece of code more reusable, we can extract it to another function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backoffRetry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obs$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;obs$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;retryIndex&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which could be later used as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;source$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;backoffRetry&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;We had a look at how to do retries with RxJS, from simplest form to our desired backoff solution. Using this technique you can decrease excessive load on server on error requests. &lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rxjs.dev/api/index/function/retry" rel="noopener noreferrer"&gt;https://rxjs.dev/api/index/function/retry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rxjs.dev/api/index/interface/RetryConfig" rel="noopener noreferrer"&gt;https://rxjs.dev/api/index/interface/RetryConfig&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rxjs.dev/api/index/function/timer" rel="noopener noreferrer"&gt;https://rxjs.dev/api/index/function/timer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/alex-okrushko/backoff-rxjs/blob/master/src/operators/retryBackoff.ts" rel="noopener noreferrer"&gt;https://github.com/alex-okrushko/backoff-rxjs/blob/master/src/operators/retryBackoff.ts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Exponential_backoff" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Exponential_backoff&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>javascript</category>
      <category>rxjs</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Beginners guide to RxJS Marble testing</title>
      <dc:creator>Mateusz Garbaciak</dc:creator>
      <pubDate>Mon, 31 Jan 2022 21:52:26 +0000</pubDate>
      <link>https://dev.to/playfulprogramming/beginners-guide-to-rxjs-marble-testing-2e88</link>
      <guid>https://dev.to/playfulprogramming/beginners-guide-to-rxjs-marble-testing-2e88</guid>
      <description>&lt;p&gt;RxJS Marble testing is a topic about which I heard quite some time ago for the first time. Since then I had a feeling that it's a big thing, that it might simplify testing, but somehow I was always put off. Sheer look at the docs made me feel stupid and decide to postpone the learning till next time. Majority of people whom I talked about it to felt similar.&lt;/p&gt;

&lt;p&gt;The aim of this article is to show you that marbles don't bite, and they are not as difficult as they seem at the very first glance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem description
&lt;/h2&gt;

&lt;p&gt;In our code snippets we are going to refer to a light switch/switches and a light bulb. We are going to write code allowing us to switch a bulb on and off. We are going to use &lt;code&gt;i&lt;/code&gt; to represent a high state, and &lt;code&gt;o&lt;/code&gt; for low state, boolean true and false respectively. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;true&lt;/code&gt;: switch or bulb is ON&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;false&lt;/code&gt;: switch or bulb is OFF&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lighting the bulb
&lt;/h2&gt;

&lt;p&gt;We have a stream of booleans that imitate a switch and a function that lights the bulb. Pretty straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;lightBulb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unit test (no marbles yet)
&lt;/h2&gt;

&lt;p&gt;Now lets try to write a unit test that would check if our function works as expected. Being afraid of marbles, we write sth like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should light the bulb when switch is on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;lightBulb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLightOn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLightOn&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem with this test is that we can't read it from top to bottom. First we subscribe to the observable &lt;code&gt;lightBulb&lt;/code&gt; returns, &lt;br&gt;
and a few lines below, we &lt;code&gt;next&lt;/code&gt; the &lt;code&gt;switch$&lt;/code&gt; subject. It's subscribe block in the middle of the test where we put the assertion. This does not seem right.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup for marble test
&lt;/h2&gt;

&lt;p&gt;Let's take our function and test it using RxJS Marbles. Before we start though, we need to copy a tiny bit of boilerplate code and put it in our test file.&lt;/p&gt;

&lt;p&gt;Sidenote: Assertion part looks different from what we see in RxJS docs, Jest being used here as a testing library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testScheduler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TestScheduler&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are instatiating a testScheduler object. It will allow us to run asynchronous code synchronously, using virtual time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit test with marbles
&lt;/h2&gt;

&lt;p&gt;Now we are ready to write our first marble test. We are going to refactor our previous test, so that it was doing the same thing, but with RxJS marbles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should light the bulb when switch is on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;testScheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectObservable&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lightBulb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;expectObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First thing you probably noticed is that we are executing a run method on &lt;code&gt;testScheduler&lt;/code&gt; object. We are providing it with a callback function, that takes &lt;code&gt;helpers&lt;/code&gt; object parameter. From that object we descructuring some of the functions used for marbles testing.&lt;/p&gt;

&lt;p&gt;Next, the way we create a &lt;code&gt;switch$&lt;/code&gt; observable is different. Now instead of assigning a &lt;code&gt;Subject&lt;/code&gt; instance to it, we use a &lt;code&gt;hot&lt;/code&gt; helper function destructured from a helper object, as &lt;code&gt;Subject&lt;/code&gt; is hot Observable. There is also &lt;code&gt;cold&lt;/code&gt; function helper to create cold observables.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;hot&lt;/code&gt; function's parameters we define what our stream should return and how it should do it. We do so with a string marble diagram and dictionary object, that defines values for a stream. In our example we say that it should emit high state 'i' (could be any other letter), and in the second parameter, we say that 'i' stands for 'true', i.e. switch is on.&lt;/p&gt;

&lt;p&gt;Once that is done, we pass our observable as a parameter to &lt;code&gt;lightBulb&lt;/code&gt; function, the same way as in our non-marble test version. Now we need a way to assess whether what function returns is what we expect. For that we use 'expectObservable' function. And there we say that what 'result$' returns, should be a stream that emits one thing: 'i', and it's value should be true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding more blocks to the test
&lt;/h2&gt;

&lt;p&gt;As you can see, route to writing our first marble test was not that rocky, now let's change our requirement. The light bulb should lighten up 10 ms after switch has been turned on. Without marbles, we would have to introduce fakeTimers and waits. Look how easy it gets with marbles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should light the bulb after 10ms delay&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;testScheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectObservable&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lightBulb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;expectObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;----------i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We changed just a single line of code, adding 10 dashes. Each dash (and letter) stands for a single millisecond. It means that observable doesn't do anything for first 10 milliseconds, after that it emits &lt;code&gt;i&lt;/code&gt;, that stands for &lt;code&gt;true&lt;/code&gt;. If we feel that ten dashes are too verbose, below two lines of code are interchangable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;expectObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;----------i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// equals to&lt;/span&gt;
&lt;span class="nf"&gt;expectObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;10ms i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our tests will fail now, so we need to update &lt;code&gt;lightBulb&lt;/code&gt; function. Now it should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;lightBulb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's go one step further. We are going to build a staircase wiring, with two switches and a light bulb that lights up when switches are in opposite positions. Basically it's an XOR logical operation. Just as a reminder a truth table for it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogolk09usunn6h9g2rse.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogolk09usunn6h9g2rse.PNG" alt="XOR operation truth table" width="124" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When both switches are in OFF position, the light is OFF too, when we switch one of it to ON position, it lightens up. Then we move the other to ON, and light is OFF. Test for our code could look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it should light the bulb ON and OFF if switches are switching&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;testScheduler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectObservable&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;switch1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;---i---o---i&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;switch2$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-i---o---i--&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expected$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;   -i-o-i-o-i-o&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;lightBulbWithStaircaseWiring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nf"&gt;expectObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expected$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are three marble diagrams, representing each observable. Two switches and a light bulb. They are aligned vertically, so that it was easier to figure out what and when is expected. Time progression goes from left to right. Millisecond after millisecond.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz8vrumic1kw7qhr86q8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiz8vrumic1kw7qhr86q8.png" alt="Observable time progression" width="468" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After 2 ms has passed (marked with a red line), &lt;code&gt;switch2$&lt;/code&gt; has been set to high state, while &lt;code&gt;switch1$&lt;/code&gt; hasn't changed (we assume it's initial value is falsy), so we expect our light bulb to be lighten up.&lt;br&gt;
After 4 ms has passed, &lt;code&gt;switch1$&lt;/code&gt; has been set to high state (&lt;code&gt;switch2$&lt;/code&gt; still being high, marked with yellow dotted circle ), this is why we expect our light builb to be off.&lt;br&gt;
Next we change state of another switch, and so on.&lt;/p&gt;
&lt;h2&gt;
  
  
  Update of the function
&lt;/h2&gt;

&lt;p&gt;Ok, test is there, now let's write a function we are going to run it against:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;lightBulbWithStaircaseWiring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;combineLatest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;startWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;))]).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;s1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s1&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;s2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's taking two streams and combines them together. If values they emitted are different, we return &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; otherwise. We don't want to wait until all switches are moved, so we do &lt;code&gt;startWith(false)&lt;/code&gt; on both switches and skip the very first emission.&lt;/p&gt;

&lt;p&gt;Just for the sake of comparison, let's have a look at what would the test look like if we were not using marbles (the difference is self explanatory):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;it should light the bulb ON and OFF if switches are switching&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;switch1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;switch2$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;resultArray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useFakeTimers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;lightBulbWithStaircaseWiring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLightOn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;resultArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLightOn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;switch1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;advanceTimersByTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;switch2$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resultArray&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A bit of advice
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It might be useful to put the breakpoint on the assertion in the callback function provided in the constructor call of a TestScheduler. This way you'll be able to visually compare actual and expected objects, what and how was emitted in frames.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you write several tests in a suite, make sure test scheduler is instantiated before each test to avoid difficult to track side effects. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hopefully after reading this article you have a basic understanding of RxJS Marbles and you are now ready to (re)visit RxJS docs to&lt;br&gt;
investigate the subject further. You can also go and check my repo, where you'll find full code examples used in this article and some other examples on testing the observables.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://rxjs.dev/guide/testing/marble-testing" rel="noopener noreferrer"&gt;https://rxjs.dev/guide/testing/marble-testing&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Exclusive_or" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Exclusive_or&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Repo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/ragtam/marbles-testing" rel="noopener noreferrer"&gt;https://github.com/ragtam/marbles-testing&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rxjs</category>
      <category>marble</category>
      <category>diagrams</category>
      <category>unittest</category>
    </item>
  </channel>
</rss>
