Unit Testing Using JEST

Hi All.

I have just started writing tests for the basic algorithm challenges using JEST. Yesterday, while completing the Slice and Splice challenge

I hit upon an issue with the tests. The challenge requires that the input arrays (arr1 & arr2) are not mutated. Can anyone point me in the right direction as to what I need to research to help write this type of test? The tests for the function itself are relatively easy - and also given in the challenge, but I have no clue on how to check for mutation.

I also know that I can do this using console.log(), and I am using Quokka so I can visually check for this as I am going along. What I would like to do is to be able to write a unit test for this.

This is one of the tests I used for the function:

test('Test One', () => {
    expect(frankenSplice([1, 2, 3], [4, 5], 1)).toEqual([4, 1, 2, 3, 5]);
});

I can pass the challenge, and I can get the function to work as it is supposed to, without mutating the original array, but I have no idea how to test for the mutation.

Thanks

This is slightly difficult, because:

const myArr = [1,2,3,4,5];

myArr is a reference, it doesn’t actually specify the values. So if I then do:

myArr.pop()
myArr.push(5)

myArr is still has exactly the same values at the start and end of the process, so a normal unit test that checks the output of a function matches what is expected will not work.

One way to do this would be to freeze the input array:

> const myArr = [1,2,3,4]
> const myFrozenArr = Object.freeze(myArr)
> myFrozenArr.push(1)
TypeError: Cannot add property 1, object is not extensible at Array.push

So that errors: you can now

  1. do a unit test that checks for errors, which is close.
  2. do a normal unit test for input/output, and if a mutating method is used, the output will not match expected.

But this only freezes the object in a shallow way — consider:

> const myArr = [1,2,3,[4, 5]]
> const myFrozenArr = Object.freeze(myArr)
> myFrozenArr[3].push(6)
> myFrozenArr
[1,2,3,[4,5,6]

So you actually want a deepFreeze, which prevents modification of any nested objects as well - MDN has an example function here (look under examples): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

Otherwise there used to be a method called Array.observe which allowed you to observe changes to arrays, but that’s been dropped and you have to use Proxies instead (which is complex) - here’s a Stack Overflow answer from someone asking about that - https://stackoverflow.com/questions/35610242/detecting-changes-in-a-javascript-array-using-the-proxy-object. Regardless, if you go down this route, you probably want to look at spies, which let you spy on a function - I’m not hugely familiar with Jest, as in what functionality it has built in, but normally Sinon is used.

Note that this is a useful exercise, but bear in mind that in reality your functions should really be black boxes — they take some input and produce some output. But how they produce that output should really be opaque, and it shouldn’t matter if, internally, the function mutates the array or not.

Hi Dan,

Thank you for your reply, I will play around with the freeze function and see if I can make them work.

I get what you mean regarding the function black box - to be honest I am doing this as a way of learning unit testing. At this point its a case of trying to become more familiar with the tools available and how to implement them most efficiently.

Thanks again for the advice - very much appreciated.

John.

1 Like