Getting started with MojiScript: Async, Infinity, Testing (part 2).
Tags: functional, javascript, mojiscript
Published: 2018-09-28 20:19:41

---
title: Getting started with MojiScript: Async, Infinity, Testing (part 2).
published: true
description: 
tags: functional, javascript, mojiscript
---

[![Infinity Loop](https://thepracticaldev.s3.amazonaws.com/i/k56udhgq2zmhbdzmah9u.gif)](https://dribbble.com/shots/2245706-Infinity-Loop)

This is part 2 to [Getting started with MojiScript: FizzBuzz (part 1)](https://dev.to/joelnet/getting-started-with-mojiscript-fizzbuzz-part-1-2fji). In Part 1 we created a basic FizzBuzz application using MojiScript.

# Skipped Part 1?

It is recommended to start with Part 1, but if you don't want to, this is how to catch up:

```bash
# download mojiscript-starter-app
git clone https://github.com/joelnet/mojiscript-starter-app.git
cd mojiscript-starter-app

# install, build and run
npm ci
npm run build
npm start --silent
```

Copy this into `src/index.mjs`

```javascript
import log from 'mojiscript/console/log'
import run from 'mojiscript/core/run'
import main from './main'

const dependencies = {
  log
}

const state = {
  start: 1,
  end: 100
}

run ({ dependencies, state, main })
```

Copy this into `src/main.mjs`

```javascript
import cond from 'mojiscript/logic/cond'
import pipe from 'mojiscript/core/pipe'
import map from 'mojiscript/list/map'
import range from 'mojiscript/list/range'
import allPass from 'mojiscript/logic/allPass'

const isFizz = num => num % 3 === 0
const isBuzz = num => num % 5 === 0
const isFizzBuzz = allPass ([ isFizz, isBuzz ])

const fizziness = cond ([
  [ isFizzBuzz, 'FizzBuzz' ],
  [ isFizz, 'Fizz' ],
  [ isBuzz, 'Buzz' ],
  [ () => true, x => x ]
])

const logFizziness = log => pipe ([
  fizziness,
  log
])

const main = ({ log }) => pipe ([
  ({ start, end }) => range (start) (end + 1),
  map (logFizziness (log))
])

export default main
```

Run `npm start --silent` to make sure it still works.

# Let the fun begin!

This is where all the fun stuff happens.

What if I want FizzBuzz to go to `Infinity`? If I ran the code with `Infinity` my console would go insane with logs, CPU would be at 100%. I don't know if I can even stop it, but I don't want to find out.

So the first thing I want to add is a delay between each log. This will save my sanity so I can just CTRL-C if I get impatient waiting for `Infinity` to come.

Like I said in Part 1, [asynchronous tasks not only become trivial, but become a pleasure to use](https://dev.to/joelnet/getting-started-with-mojiscript-fizzbuzz-part-1-2fji).

Add an `import` at the top.

```javascript
import sleep from 'mojiscript/threading/sleep'
```

Then just slip the `sleep` command into `logFizziness`.

```javascript
const logFizziness = log => pipe ([
  sleep (1000),
  fizziness,
  log
])
```

That's it. Seriously. Just add a `sleep` command. Try to imagine how much more complicated it would have been to do with JavaScript.

Run the app again and watch the fizziness stream out 1 second at a time.

Now that I have no worries about exploding my console, if I want to count to `Infinity` all I have to do is change...

```javascript
// change this:
const state = {
  start: 1,
  end: 100
}

// to this:
const state = {
  start: 1,
  end: Infinity
}
```

You see we can do that because `range` is an `Iterator` and not an `Array`. So it will enumerator over the range one number at a time!

But... `map` will turn that `Iterator` into an `Array`. So eventually `map` will explode our memory. How can I run this to `Infinity` if I run out of memory?

Okay, so let's throw away the `Array` map is slowly creating.

This is where `reduce` comes in handy. `reduce` will let us control what the output value is.

```javascript
// this is what map looks like
map (function) (iterable)

// this is what reduce looks like
reduce (function) (default) (iterable)
```

That's not the only difference, because `reduce`'s `function` also takes 1 additional argument. Let's compare a function for `map` with a function for `reduce`.

```javascript
const mapper = x => Object
const reducer = x => y => Object
```

Since the first argument is reduce's accumulator and I don't care about it, I can just ignore it.

```javascript
// instead of this:
logFizziness (log)

// I would write this:
() => logFizziness (log)
```

I just need to put this guy at the top.

```javascript
import reduce from 'mojiscript/list/reduce'
```

I also need to throw in a default value of `(0)` and then I can convert `main` to this:

```javascript
const main = ({ log }) => pipe ([
  ({ start, end }) => range (start) (end + 1),
  reduce (() => logFizziness (log)) (0)
])
```

We no longer have any memory issues because no `Array` is being created!

The final `src/main.mjs` should look like this:

```javascript
import cond from 'mojiscript/logic/cond'
import pipe from 'mojiscript/core/pipe'
import range from 'mojiscript/list/range'
import reduce from 'mojiscript/list/reduce'
import allPass from 'mojiscript/logic/allPass'
import sleep from 'mojiscript/threading/sleep'

const isFizz = num => num % 3 === 0
const isBuzz = num => num % 5 === 0
const isFizzBuzz = allPass ([ isFizz, isBuzz ])

const fizziness = cond ([
  [ isFizzBuzz, 'FizzBuzz' ],
  [ isFizz, 'Fizz' ],
  [ isBuzz, 'Buzz' ],
  [ () => true, x => x ]
])

const logFizziness = log => pipe ([
  sleep (1000),
  fizziness,
  log
])

const main = ({ log }) => pipe ([
  ({ start, end }) => range (start) (end + 1),
  reduce (() => logFizziness (log)) (0)
])

export default main
```

# Unit Tests

It's probably good practice to move `isFizz`, `isBuzz`, `isFizzBuzz` and `fizziness` to `src/fizziness.mjs`. But for article brevity I'm not doing that here.

To unit test these bad boys, just add the export keyword to them.

```javascript
export const isFizz = num => num % 3 === 0
export const isBuzz = num => num % 5 === 0
export const isFizzBuzz = allPass ([ isFizz, isBuzz ])

export const fizziness = cond ([
  [ isFizzBuzz, 'FizzBuzz' ],
  [ isFizz, 'Fizz' ],
  [ isBuzz, 'Buzz' ],
  [ () => true, x => x ]
])

export const logFizziness = log => pipe ([
  sleep (1000),
  fizziness,
  log
])

export const main = ({ log }) => pipe ([
  ({ start, end }) => range (start) (end + 1),
  reduce (() => logFizziness (log)) (0)
])

export default main
```

Create `src/__tests__/fizziness.test.mjs` and write some tests:

```javascript
import { isFizz } from '../main'

describe('fizziness', () => {
  describe('isFizz', () => {
    test('true when divisible by 5', () => {
      const expected = true
      const actual = isFizz(5)
      expect(actual).toBe(expected)
    })

    test('false when not divisible by 5', () => {
      const expected = false
      const actual = isFizz(6)
      expect(actual).toBe(expected)
    })
  })
})
```

Now here I am using the [Jest](https://jestjs.io) test framework. You can use whatever. Notice that I am writing the tests in JavaScript. I found it's best to just follow the format the test framework wants you to use. I don't think it's worth wrapping Jest so we can write tests in MojiScript.

# Testing Main

Testing `main` complex. We have a `sleep` command in there. So if we test numbers 1-15, then it'll take 15 seconds.

![Ain't nobody got time for that](https://thepracticaldev.s3.amazonaws.com/i/mqsmfcbhkf7wlrottdl4.jpg)

Fortunately, it's easy to mock `setTimeout`.

```javascript
// setup mocks
jest.spyOn(global, 'setTimeout').mockImplementation(func => func())

// take down mocks
global.setTimeout.mockReset()
```

Now our test should take about 7ms to run, not 15 seconds!

```javascript
import I from 'mojiscript/combinators/I'
import main from '../main'

describe('main', () => {
  const log = jest.fn(I)

  beforeEach(() => jest.spyOn(global, 'setTimeout').mockImplementation(func => func()))
  afterEach(() => global.setTimeout.mockReset())

  test('main', async () => {
    const expected = [[1], [2], ["Buzz"], [4], ["Fizz"], ["Buzz"], [7], [8], ["Buzz"], ["Fizz"], [11], ["Buzz"], [13], [14], ["FizzBuzz"]]
    expect.assertions(1)
    await main ({ log }) ({ start: 1, end: 15 })
    const actual = log.mock.calls
    expect(actual).toMatchObject(expected)
  })
})
```

# Summary

- We learned how trivial adding asynchronous code can be.
- We learned how separating dependencies from `main` into `index` can make testing easier.
- We learned how to asynchronously `map`. Wait... did I just say **`async`** `map`? You might have missed this because it was so easy, but `map`, `filter`, and `reduce` can be asynchronous. This is a big deal and I will be writing an entire article on this in the near future.

Oh ya, in Part 1 I said I would "reveal the mysteries of life!". Well, I don't want to disappoint, so the mystery of life is... LIFE. It's recursion, so loop on that.

Follow me here, or on Twitter [@joelnet](https://twitter.com/joelnet)!

If you thought MojiScript was fun, give it a star https://github.com/joelnet/MojiScript! Share your opinions with me in the comments!

**Read my other articles:**

[Why async code is so damn confusing (and a how to make it easy)](https://dev.to/joelnet/why-async-code-is-so-damn-confusing-and-a-how-to-make-it-easy-3441)

[How I rediscovered my love for JavaScript after throwing 90% of it in the trash](https://hackernoon.com/how-i-rediscovered-my-love-for-javascript-after-throwing-90-of-it-in-the-trash-f1baed075d1b)

![Cheers!](https://thepracticaldev.s3.amazonaws.com/i/6jsy3a866frzp3u5oda0.jpg)