Difference between describe() and test() in Jest - unit-testing

I have found that expect() works within describe(). So the function test() is not necessary, if I see it right. Do I see it right?
In other words, is it enough to write that:
const sum = require('./sum');
describe('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Or does that bring advantages:
const sum = require('./sum');
describe('test sum', () => {
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
});

describe(name, fn) creates a block that groups together several
related tests.
Detail: https://jestjs.io/docs/api#describename-fn

Related

How to structure Tests for Vue Components to have a good coverage?

I was wondering in general how to properly test Vue Components to cover almost everything, to confidently tell a customer that it works and it will not fail unless something big happened.
In my case I am using Jest as the test framework. It comes with coverage reports that follow the Istanbul pattern.
However what I am uncertain about is how to structure the tests to minimize the overhead, maximize the test speed (or atleast not create bottlenecks), maximize extendability and maximize the test coverage.
Furthermore I am also uncertain with Integration-tests
where you handle the interaction of multiple components, mixins, vuex-store and other js-files.
Should they have a separate and dedicated file or would put everything into one file?
So my question is, how to put everything together as I can write good single tests in each but finding a good structure to help me and my co-workers with the coverage and low overhead is a bit difficult for me.
Here is an example of a structure I recently developed to test a certain Vue-component with jest & vue-test-utils:
//some imports
describe("Test Vue-Component X", () => {
let wrapper = null;
beforeAll(async () => { //could also be beforeEach. (Depends on the component I guess
localVue = createLocalVue();
localVue.use(Vuex);
vuetify = new Vuetify();
wrapper = mount(somecomponent, {
mocks: {
$t: (key) => translations["messages"]["EN"][key],
},
localVue,
store,
vuetify,
});
});
describe("Initial State test", () => {
/**
* GIVEN
* WHEN
* THEN
*/
test("checks if Component X exists", () => {
expect(wrapper.vm.$options.name).toBe("X");
expect(wrapper.exists()).toBe(true);
});
describe("Created", () => {});
describe("Mounted", () => {});
//Does it generally make sense to go throw each lifecycle-hook or is it rather test specific?
});
describe("computed Properties: ", () => {
describe("Property Y", () => {
/**
* GIVEN
* WHEN
* THEN
*/
test("Test some Expected Outcome", () => {
});
/**
* GIVEN
* WHEN
* THEN
*/
test("Test Error Cases", () => {});
});
describe("Proterty Z", () => {});
});
describe("methods ", () => {
describe("Method 1", () => {
/**
* GIVEN
* WHEN
* THEN
*/
test("Test some expected outcome given a specific imput ", () => {});
/**
* GIVEN
* WHEN
* THEN
*/
test("Test Error-case 1", () => {});
});
describe("Method 2 ", () => {});
describe("Method 3... ", () => {});
});
describe("Watch ", () => {
describe("Watcher A", () => {});
});
describe("Interaction Vuex store? ",()=>{
//e.g. test if the store yields some stuff that is breaking the UI
});
describe("Interaction with template? ",()=>{
// would go in the direction of ui-test similar to the selenium tests
});
describe("Dedicated Bug Area? ",()=>{
//all tests made because of bug reports
});
describe("Events or Interaction with other components? ",()=>{
//all tests made because of bug reports
});
});
The part where I am uncertain about are marked with a "?".
Maybe it would be great if you could link me to a test that was tests a complex Vue-Component with a 100% coverage (covering unit and integration-tests) in a middle to big project.

Writing tests for RxJS that uses retryWhen operator (understanding difference from retry operator)

I'm trying to write tests for the following function that uses retryWhen operator:
// some API I'm using and mocking out in test
import { geoApi } from "api/observable";
export default function retryEpic(actions$) {
return actions$.pipe(
filter(action => action === 'A'),
switchMap(action => {
return of(action).pipe(
mergeMap(() => geoApi.ipLocation$()),
map(data => ({ data })),
retryWhen(errors => {
return errors.pipe(take(2));
}),
);
}),
);
}
The code is supposed to perform a request to some remote API geoApi.ipLocation$(). If it gets an error, it retries 2 times before giving up.
I have written the following test code that uses Jest and RxJS TestScheduler:
function basicTestScheduler() {
return new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
}
const mockApi = jest.fn();
jest.mock('api/observable', () => {
return {
geoApi: {
ipLocation$: (...args) => mockApi(...args),
},
};
});
describe('retryEpic()', () => {
it('retries fetching 2 times before succeeding', () => {
basicTestScheduler().run(({ hot, cold, expectObservable, expectSubscriptions }) => {
const actions$ = hot('-A');
// The first two requests fail, third one succeeds
const stream1 = cold('-#', {}, new Error('Network fail'));
const stream2 = cold('-#', {}, new Error('Network fail'));
const stream3 = cold('-r', { r: 123 });
mockApi.mockImplementationOnce(() => stream1);
mockApi.mockImplementationOnce(() => stream2);
mockApi.mockImplementationOnce(() => stream3);
expectObservable(retryEpic(actions$)).toBe('----S', {
S: { data: 123 },
});
expectSubscriptions(stream1.subscriptions).toBe('-^!');
expectSubscriptions(stream2.subscriptions).toBe('--^!');
expectSubscriptions(stream3.subscriptions).toBe('---^');
});
});
});
This test fails.
However, when I replace retryWhen(...) with simply retry(2), then the test succeeds.
Looks like I don't quite understand how to implement retry with retryWhen. I suspect this take(2) is closing the stream and kind of preventing everything from continuing. But I don't quite understand it.
I actually want to write some additional logic inside retryWhen(), but first I need to understand how to properly implement retry() with retryWhen(). Or perhaps that's actually not possible?
Additional resources
My implementation of retryWhen + take was based on this SO answer:
How to create an RXjs RetryWhen with delay and limit on tries
Official docs:
retryWhen
You can use retryWhen for those two purposes, one to have your logic in it and the second is the retry numbers you'd like to give it (no need to use retry operator):
// some API I'm using and mocking out in test
import { geoApi } from "api/observable";
export default function retryEpic(actions$) {
return actions$.pipe(
filter(action => action === 'A'),
switchMap(action => {
return of(action).pipe(
mergeMap(() => geoApi.ipLocation$()),
map(data => ({ data })),
retryWhen(errors =>
errors.pipe(
mergeMap((error, i) => {
if (i === 2) {
throw Error();
}
// return your condition code
})
)
)
)
}),
);
}
Here is a simple DEMO of that.
As for understanding this logic:
retryWhen and retry operators, according to the Official docs you've referenced:
resubscribing to the source Observable (if no error or complete executes)
This is why you can't pipe retry and retryWhen together. You can say that these operators are a chain breakers...

RxJs Marble Test Fails When Using Observable.fromPromise

I have been attempting to write an RxJS marble test for a simple redux-observable epic but cannot get it to pass. It appears that using fromPromise in the observable chain under test does not emit the items per the expected marble sequence when flush is called on the testScheduler.
Providing a sample of the test. If I replace Observable.fromPromise to Observable.of the test will pass.
Any insight is appreciated. RxJS 5 / redux-observable 0.18
...
const MY_ACTION = 'MY_ACTION';
const myAction = () => ({
type: MY_ACTION,
payload: {test: 'testval'},
});
const epic = action$ =>
action$.ofType(MY_ACTION).switchMap(() =>
Observable.concat(
Observable.of({type: 'test1'}),
Observable.fromPromise(Promise.resolve({type: 'test2'})),
)
);
it('it should work', () => {
const deepEquals = (actual, expected) => {
expect(actual).to.deep.equal(expected);
};
const createTestScheduler = () =>
new TestScheduler(deepEquals);
const marbles1 = '-a-';
const marbles2 = '-(bc)-';
const values = {
a: myAction(),
b: {type: 'test1'},
c: {type: 'test2'},
};
const ts = createTestScheduler();
const source = ActionsObservable.from(
ts.createColdObservable(marbles1, values)
);
const actual = epic(source);
ts.expectObservable(actual);
ts.expectObservable(actual).toBe(marbles2, values);
ts.flush();
});
...
Take a look at the documentation under the 'Known issues' section: https://rxjs-dev.firebaseapp.com/guide/testing/marble-testing
You can use the from operator to wrap a promise like so:
const myAsyncCode = () => from(Promise.resolve('something'));
it('has async code', (done) => {
myAsyncCode().subscribe((d) => {
assertEqual(d, 'something');
done();
});
});

Unit testing reducers, test each slice reducer or combined reducer?

Suppose I have a reducer file reducers/group1.js like this
export default combineReducers({
A: combineReducers({ A1, A2 }),
B: reducerB,
C: reducerC
})
Is there any difference between testing each slice reducer (A1, A2, reducerB and reducerC) and testing the combined one?
import group1 from 'reducers/group1'
describe('reducers', () => {
describe('group1', () => {
it('should provide the initial state', () => {
expect(group1(undefined, {})).to.equal({ group1: { A: { ... }, B: ... } })
})
it(...)
// ...
})
})
or
import { A1, A2, reducerB, reducerC } from 'reducers/group1'
describe('reducers', () => {
describe('group1', () => {
describe('A1', () => {
it('should provide the initial state', () => {
expect(A1(undefined, {})).to.equal(0) // if A1 is just a number
})
})
describe('A2', () => { ... })
describe('reducerB', () => { ... })
describe('reducerC', () => { ... })
})
})
Your second example is usually better because it allows for simpler unit tests. I can imagine a scenario where a developer might want to write a bunch of tests for reducer C without knowing anything about reducers A and B. The second code sample allows for that developer to write a suite of C tests without being concerned about what A or B even are. It also helps when rewriting tests if a reducer's behavior is drastically changed: all those tests live in one place instead of being scattered all over the test file.
However, there might be some instances where you want to write a test for the entire reducer. For example, if you have a global reset action, you would want to test that the entire reducer properly responds to that action instead of writing an individual test for each reducer. Most of the time it's probably going to be cleaner to write tests for individual reducers though.

parametrized tests with Mocha

How can I create parametrized tests with Mocha?
Sample use case: I have 10 classes, that are 10 different implementations of the same interface. I want to run the exact same suit of tests for each class. I can create a function, that takes the class as a parameter and runs all tests with that class, but then I will have all tests in a single function - I won't be able to separate them nicely to different "describe" clauses...
Is there a natural way to do this in Mocha?
You do not need async package. You can use forEach loop directly:
[1,2,3].forEach(function (itemNumber) {
describe("Test # " + itemNumber, function () {
it("should be a number", function (done) {
expect(itemNumber).to.be.a('number')
expect(itemNumber).to.be(itemNumber)
});
});
});
I know this was posted a while ago but there is now a node module that makes this really easy!! mocha param
const itParam = require('mocha-param').itParam;
const myData = [{ name: 'rob', age: 23 }, { name: 'sally', age: 29 }];
describe('test with array of data', () => {
itParam("test each person object in the array", myData, (person) => {
expect(person.age).to.be.greaterThan(20);
})
})
Take a look at async.each. It should enable you to call the same describe, it, and expect/should statements, and you can pass in the parameters to the closure.
var async = require('async')
var expect = require('expect.js')
async.each([1,2,3], function(itemNumber, callback) {
describe('Test # ' + itemNumber, function () {
it("should be a number", function (done) {
expect(itemNumber).to.be.a('number')
expect(itemNumber).to.be(itemNumber)
done()
});
});
callback()
});
gives me:
$ mocha test.js -R spec
Test # 1
✓ should be a number
Test # 2
✓ should be a number
Test # 3
✓ should be a number
3 tests complete (19 ms)
Here's a more complex example combining async.series and async.parallel: Node.js Mocha async test doesn't return from callbacks
Actually the mocha documentation specifies how to create what you want here
describe('add()', function() {
var tests = [
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6},
{args: [1, 2, 3, 4], expected: 10}
];
tests.forEach(function(test) {
it('correctly adds ' + test.args.length + ' args', function() {
var res = add.apply(null, test.args);
assert.equal(res, test.expected);
});
});
});
The answer provided Jacob is correct just you need to define the variable first before iterating it.