How to write unit test with Higher Order Function with Jest in React JS - unit-testing

Hello i'm new to React and i'm trying to write a unit test on a Higher Order Functions with Jest and i don't know how to do it please can someone help me ? This is the code of my HIGHER ORDER FUNCTION below :
const updateSearchTopStoriesState = (hits, page) => (prevState) => {
const { searchKey, results } = prevState
const oldHits = results && results[searchKey]
? results[searchKey].hits
: []
const updatedHits = [
...oldHits,
...hits
]
// returning our previous state
return {
results: {
...results,
[searchKey]: { hits: updatedHits, page }
},
isLoading: false
}
}
export default updateSearchTopStoriesState

Without knowing WHAT you are trying to test, or WHAT the shape of any of the parameters are, this is near impossible to answer accurately. Here are a couple of unit tests I would write:
describe("updateSearchTopStoriesState", () => {
it("should return a function", () => {
expect(typeof updateSearchTopStoriesState()).toBe("function");
});
it("should return default return value", () => {
const { results, isLoading } = updateSearchTopStoriesState()({
searchKey: "test"
});
expect(results).toEqual({ test: { hits: [] } });
expect(isLoading).toBe(false);
});
});
In the sandbox I've started a third test that currently fails (admittedly likely due to my lack of context on the parameters, but should be passing based upon an internal implementation comment you left in the function code).
This should assist you in starting a unit test file for this function, but please comment if anything is unclear or this isn't quite what you are asking about.

Related

jest.spyOn mock return value not returning value

The code I'm trying to test:
const utils = require('../utils/utils');
let imageBuffer;
try {
imageBuffer = await utils.retrieveImageFromURI(params)
console.log(imageBuffer) // comes back as undefined when I mock the utils.retreieveImageFromURI
if (!imageBuffer || imageBuffer.length < 1024) {
throw new Error(`Retrieve from uri (${params.camera.ingest.uri}) was less than 1kb in size - indicating an error`)
}
console.log(`${params.camera.camId} - Successful Ingestion from URI`);
} catch (err) {
reject({ 'Task': `Attempting to pull image from camera (${params.camera.camId}) at ${params.camera.ingest.uri}`, 'Error': err.message, 'Stack': err.stack })
return;
}
Specifically, I'm trying to mock the utils.retrieveImageFromURI function - which has API calls and other things in it.
When I try to mock the function using spyOn I am trying it like so:
describe("FUNCTION: ingestAndSave", () => {
let fakeImageBuffer = Array(1200).fill('a').join('b'); // just get a long string
console.log(fakeImageBuffer.length) //2399
let retrieveImageFromURISpy
beforeAll(() => {
retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockReturnValue(fakeImageBuffer)
})
test("Will call retrieveImageFromURI", async () => {
await ingest.ingestAndSave({camera:TEST_CONSTANTS.validCameraObject, sourceQueueURL:"httpexamplecom", receiptHandle: "1234abcd"})
expect(retrieveImageFromURISpy).toHaveBeenCalledTimes(1)
})
afterEach(() => {
jest.resetAllMocks()
})
afterAll(() => {
jest.restoreAllMocks()
})
})
When I do this, I get a console log that imageBuffer (which is supposed to be the return of the mocked function) is undefined and that, in turn, triggers the thrown Error that "Retrieve from uri ...." ... which causes my test to fail. I know I could wrap the test call in a try/catch but the very next test will be a "does not throw error" test... so this needs to be solved.
It's not clear to me why the mockReturnValue isn't getting returned.
Other steps:
I've gone to the REAL retrieveImageFromURI function and added a console log - it is not running.
I've changed mockReturnValue to mockImplementation like so:
retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockImplementation(() => {
console.log("Here")
return fakeImageBuffer
})
And it does NOT console log 'here'. I'm unsure why not.
I have also tried to return it as a resolved Promise, like so:
retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockImplementation(() => {
console.log("Here")
return Promise.resolve(fakeImageBuffer)
})
Note, this also doesn't console log.
I've also tried to return the promise directly with a mockReturnValue:
`retrieveImageFromURISpy = jest.spyOn(utils, 'retrieveImageFromURI').mockReturnValue(Promise.resolve(fakeImageBuffer)`)

How to use CodeceptJS to unit-test a JS function

I've set up CodeceptJS for a project and use it to test various end-to-end scenarios.
Now I want to extend the tests-suite to also run unit-tests to verify functionality of custom JS functions.
For example: I have a global object App that has a version attribute. As a first test, I want to confirm that App.version is present and has a value.
My first attempt is a test.js file with the following code:
Feature('Unit Tests');
Scenario('Test App presence', ({ I }) => {
I.amOnPage('/');
I.executeScript(function() {return App.version})
.then(function(value) { I.say(value) } );
});
Problems with this code
The major issue: How can I assert that the App.version is present?
My script can display the value but does not fail if it's missing
My code is very complex for such a simple test.
I'm sure there's a cleaner/faster way to perform that test, right?
Here is a solution that works for me:
Read data from the browser:
I created a custom helper via npx codecept gh and named it BrowserAccess.
The helper function getBrowserData uses this.helpers['Puppeteer'].page.evaluate() to run and return custom code from the browser scope. Documentation for .evaluate()
Custom assertions:
Install the codeceptjs-assert package, e.g. npm i codeceptjs-assert
Add the AssertWrapper-helper to the codecept-config file. This enables checks like I.assert(a, b)
Full Code
codecept.conf.js
exports.config = {
helpers: {
AssertWrapper: {
require: "codeceptjs-assert"
},
BrowserAccess: {
require: './browseraccess_helper.js'
},
...
},
...
}
browseraccess_helper.js
const Helper = require('#codeceptjs/helper');
class BrowserAccess extends Helper {
async getBrowserData(symbolName) {
const currentPage = this.helpers['Puppeteer'].page;
let res;
try {
res = await currentPage.evaluate((evalVar) => {
let res;
try {
res = eval(evalVar);
} catch (e) {
}
return Promise.resolve(res);
}, symbolName);
} catch (err) {
res = null;
}
return res;
}
}
jsapp_test.js (the test is now async)
Feature('Unit Tests');
Scenario('Test App presence', async ({ I }) => {
I.amOnPage('/');
const version = await I.getBrowserData('App.version');
I.assertOk(version);
});

How can I unit test a retryWhen operator in rxjs?

I am attempting to unit test a custom RxJS operator. The operator is very simple, it uses RetryWhen to retry a failed HTTP request, but has a delay and will only retry when the HTTP Error is in the 500 range. Using jasmine, and this is in an Angular application.
I've looked at this:
rxjs unit test with retryWhen
Unfortunately, updating the SpyOn call doesn't seem to change the returned observable on successive retries. Each time it retries it is retrying with the original spyon Value.
I have also looked at a bunch of rxjs marble examples, none of which seem to work. I am not sure it is possible to use rxjs marbles here, because (AFAIK) there is no way to simulate a situation where you first submit an errored observable, then submit a successful observable on subsequent tries.
The code is basically a clone of this:
https://blog.angularindepth.com/retry-failed-http-requests-in-angular-f5959d486294
export function delayedRetry(delayMS: number, maxRetry) {
let retries = maxRetry;
return (src: Observable<any>) =>
src.pipe(
retryWhen((errors: Observable<any>) => errors.pipe(
delay(delayMS),
mergeMap(error =>
(retries-- > 0 && error.status >= 500) ? of(error) : throwError(error))
))
);
}
I would like to be able to demonstrate that it can subscribe to an observable that returns an error on the first attempt, but then returns a successful response. The end subscription should show whatever success value the observable emits.
Thank you in advance for any insights.
try use this observable as source observable to test
const source = (called,successAt)=>{
return defer(()=>{
if(called<successAt){
called++
return throwError({status:500})
}
else return of(true)
})
}
test
this.delayedRetry(1000,3)(source(0,3)).subscribe()
To test the retry functionality, you need a observable which emits different events each time you call it. For example:
let alreadyCalled = false;
const spy = spyOn<any>(TestBed.inject(MyService), 'getObservable').and.returnValue(
new Observable((observer) => {
if (alreadyCalled) {
observer.next(message);
}
alreadyCalled = true;
observer.error('error message');
})
);
This observable will emit an error first and after that a next event.
You can check, if your observable got the message like this:
it('should retry on error', async(done) => {
let alreadyCalled = false;
const spy = spyOn<any>(TestBed.inject(MyDependencyService), 'getObservable').and.returnValue(
new Observable((observer) => {
if (alreadyCalled) {
observer.next(message);
}
alreadyCalled = true;
observer.error('error message');
})
);
const observer = {
next: (result) => {
expect(result.value).toBe(expectedResult);
done();
}
}
subscription = service.methodUnderTest(observer);
expect(spy).toHaveBeenCalledTimes(1);
}
Building on a previous answer I have been using this, which gives you more control over what's returned.
const source = (observables) => {
let count = 0;
return defer(() => {
return observables[count++];
});
};
Which can then be used like this
const obsA = source([
throwError({status: 500}),
of(1),
]);
Or it can then be used with rxjs marbles like
const obsA = source([
cold('--#', null, { status: 500 }),
cold('--(a|)', { a: 1 }),
]);

Write a mocha unit test code for the following meteor code

I want to know how to write test code using mocha for the meteor function
export const physicalToLogical = (physicalStatus, planningStartDate, planningEndDate) => {
if(physicalStatus === STATUS_PHYSICAL_CREATING) {
return STATUS_LOGICAL_CREATING;
} else if (physicalStatus === STATUS_PHYSICAL_OPEN) {
const now = new Date();
if(planningStartDate.getTime() <= now && planningEndDate.getTime() > now) {
return STATUS_LOGICAL_OPEN_FOR_PLAN;
} else if(planningStartDate.getTime() > now) {
return STATUS_LOGICAL_PROSPECT;
}
return STATUS_LOGICAL_REVIEW;
} else if (physicalStatus === STATUS_PHYSICAL_CLOSED) {
return STATUS_LOGICAL_CLOSED;
} else if (physicalStatus === STATUS_PHYSICAL_ARCHIVED) {
return STATUS_LOGICAL_ARCHIVED;
}
throw new Error("Not implemented yet");
};
First, this function has nothing to do with Meteor.
Writing tests for such a function would involve sending different statuses to the method and expecting the different results.
Here's an example (using chai as the assertions library) :
describe('physicalToLogical', () => {
it('should return the given status', () => {
expect(physicalToLogical(STATUS_PHYSICAL_CREATING, null, null)).
toEqual(STATUS_LOGICAL_CREATING);
});
it('should...', () => {
...
});
...
});
This is one of the many simple cases you have to write for that code.
Several other tests need to be written for the cases involving dates, but the format is more or less the same.

How to mock DialogService.open(...).whenClosed(...) with Jasmine?

We have some TypeScript code using the Aurelia framework and Dialog plugin that we are trying to test with Jasmine, but can't work out how to do properly.
This is the source function:
openDialog(action: string) {
this._dialogService.open({ viewModel: AddAccountWizard })
.whenClosed(result => {
if (!result.wasCancelled && result.output) {
const step = this.steps.find((i) => i.action === action);
if (step) {
step.isCompleted = true;
}
}
});
}
We can create a DialogService spy, and verify the open method easily - but we can't work out how to make the spy invoke the whenClosed method with a mocked result parameter so that we can then assert that the step is completed.
This is the current Jasmine code:
it("opens a dialog when clicking on incomplete bank account", async done => {
// arrange
arrangeMemberVerificationStatus();
await component.create(bootstrap);
const vm = component.viewModel as GettingStartedCustomElement;
dialogService.open.and.callFake(() => {
return { whenClosed: () => Promise.resolve({})};
});
// act
$(".link, .-arrow")[0].click();
// assert
expect(dialogService.open).toHaveBeenCalledWith({ viewModel: AddAccountWizard });
expect(vm.steps[2].isCompleted).toBeTruthy(); // FAILS
done();
});
We've just recently updated our DialogService and ran into the same issue, so we've made this primitive mock that suited our purposes so far. It's fairly limited and doesn't do well for mocking multiple calls with different results, but should work for your above case:
export class DialogServiceMock {
shouldCancelDialog = false;
leaveDialogOpen = false;
desiredOutput = {};
open = () => {
let result = { wasCancelled: this.shouldCancelDialog, output: this.desiredOutput };
let closedPromise = this.leaveDialogOpen ? new Promise((r) => { }) : Promise.resolve(result);
let resultPromise = Promise.resolve({ closeResult: closedPromise });
resultPromise.whenClosed = (callback) => {
return this.leaveDialogOpen ? new Promise((r) => { }) : Promise.resolve(typeof callback == "function" ? callback(result) : null);
};
return resultPromise;
};
}
This mock can be configured to test various responses, when a user cancels the dialog, and scenarios where the dialog is still open.
We haven't done e2e testing yet, so I don't know of a good way to make sure you wait until the .click() call finishes so you don't have a race condition between your expect()s and the whenClosed() logic, but I think you should be able to use the mock in the test like so:
it("opens a dialog when clicking on incomplete bank account", async done => {
// arrange
arrangeMemberVerificationStatus();
await component.create(bootstrap);
const vm = component.viewModel as GettingStartedCustomElement;
let mockDialogService = new MockDialogService();
vm.dialogService = mockDialogService; //Or however you're injecting the mock into the constructor; I don't see the code where you're doing that right now.
spyOn(mockDialogService, 'open').and.callThrough();
// act
$(".link, .-arrow")[0].click();
browser.sleep(100)//I'm guessing there's a better way to verify that it's finished with e2e testing, but the point is to make sure it finishes before we assert.
// assert
expect(mockDialogService.open).toHaveBeenCalledWith({ viewModel: AddAccountWizard });
expect(vm.steps[2].isCompleted).toBeTruthy(); // FAILS
done();
});