Testing the Observer complete event with Jest? - javascript

The RxJS Observer fires the events:
complete
error
next
If we want to test for the complete event with Jest. How is this done?
For example we can test the next and error events, because those functions pass data:
o.subscribe(result => {
expect(result.data.length).toEqual(1);
},
(e)=>{expect(e).toBeFalsy()},
()=>{ WHAT TO EXPECT HERE? }
The complete event does not. The function signature is ()=>void. How do we test that function signature?
Also the line (e)=>{expect(e).toBeFalsy()} because it never actually fires. Is there a way to check that a callback does not run?

const toPromise = obs =>
new Promise((complete, error) => {
obs.subscribe({ complete, error });
});
import { getUserEvents } as user from '../user';
// The assertion for a promise must be returned.
it('works with promises', () =>
expect(toPromise(getUserEvents(4))).resolves.toEqual('Mark'))
Via:
https://jestjs.io/docs/en/tutorial-async
https://github.com/ReactiveX/rxjs/issues/3482#issuecomment-385106653
Furthermore, since Jest will fail on Errors being thrown, you can use any testing framework inside of its test. E.g. import 'rxjs/testing', like described here

How to test that the error callback is not called is here.
Looks like this will test the complete callback:
let complete = false;
let completeHandler = ()=>{
complete = true;
expect(complete).toBeTruthy()
};
let errorHandler = (e)=>{
console.log("THIS IS NEVER EXECUTED");
console.log("HOW DO WE VERIFY THAT IT IS NOT?");
let o:Observable<Result> = fn(data, errorHandler, completeHandler);
o.subscribe();
The errorHandler and completeHandler are baked into the Observable<Result returned by the fn function.

Related

How to mock a promise function with Jest that sets some value?

how to mock a promise in jest-test?
till now, we were using launchDarkly.getFlag directly without waiting for the onInitialization method/promise? so the tests had it mocked
// in myFunc.test.js file
jest.spyOn(launchDarkly, 'getFlag').mockImplementation(() => true);
But now that it has changed as mentioned below, the test(s) has started to fail, so what and how should I mock so that the test-flow is checked with isWhiteSpaceFeatureEnabled variable being tested against an if check?
// in componentUtility.js file
// before isWhitespaceOvertimeFeatureEnabled = launchDarkly.getFlag(WHITESPACE_OVERTIME_CHART_FLAG, false);
launchDarkly.onInitialization().then(() => {
isWhitespaceOvertimeFeatureEnabled = launchDarkly.getFlag(WHITESPACE_OVERTIME_CHART_FLAG, false);
});

NodeJs: How to handle delayed errors in streams

I have the following situation.
function emitErrorInStream() {
let resultStream = new PassThrough();
let testStream = new PassThrough();
testStream.on("error", () => {
throw new Error("AA");
}
// the setTimeout simulates what is actually happening in the code.
/*
* actual code
* let testStream = s3.getObject(params).createReadStream();
* if I pass in an incorrect parameter option to the getObject function
* it will be a few milliseconds before an error is thrown and subsequently caught by the stream's error handling method.
*/
setTimeout(() => {testStream.emit("error", "arg");}, 100);
return testStream.pipe(resultStream);
}
try{
let b = emitErrorInStream();
}
catch(err){
console.log(err) // error will not be caught
}
///... continue
I have tried a slew of things to catch the error thrown inside the error handler. I have tried using promises, which never resolve. How can I catch the error thrown inside thetestStream's error handler?
I have found that sending an end event inside the on("error") handler partially solves my issue as it does not crash the application running. It is not a recommended solution https://nodejs.org/api/stream.html#stream_event_end_1
Lastly, is catching this error possible if emitErrorInStream is a third party function to which I do not have access?
Any insights would be greatly appreciated.
// actual typescript code
downloadStream(bucketName: string, filename: string): Stream {
const emptyStream = new PassThrough();
const params = { Bucket: bucketName, Key: filename };
const s3Stream = this.s3.getObject(params).createReadStream();
// listen to errors returned by the service. i.e. the specified key does not exist.
s3Stream.on("error", (err: any) => {
log.error(`Service Error Downloading File: ${err}`);
// Have to emit an end event here.
// Cannot throw an error as it is outside of the event loop
// and can crash the server.
// TODO: find better solution as it is not recommended https://nodejs.org/api/stream.html#stream_event_end_1
s3Stream.emit("end");
});
return s3Stream.pipe(emptyStream);
}

How do I get everything covered?

I have a node module I'm trying to write unit tests for. Here's a part of the module:
function _write(level, message) {
if (level <= _current) {
message = message || "No message provided.";
const consoleFn = consoleFunction[level];
const logFn = console[consoleFn];
logFn(`${levelPrefix[level]}: ${message}`);
}
}
When I run the tests including this one:
test('test writing to error log', () => {
logger.__Rewire__('_write', function (level, message) {
console.error(`ERROR: ${message}`);
});
const spy = jest.spyOn(logger, 'error');
logger.error('error message');
expect(spy).toHaveBeenCalledTimes(1);
});
However after running the tests it still looks like the _write function isn't showing up in the coverage results. Is there a way to get jest to understand all the lines of code are getting exercised? Note that "Uncovered Line #s" refers to the exact line numbers of the _write function. I had hoped that by rewiring the function this would make my coverage 100%.
It looks to me like you are mocking the _write function for that test. I don’t expect those lines to get run in this case.
You could write another test that actually uses the _write function.

Wait for State to update using UseState hook and then run code inside a function

const startLive = () => {
// connect to websocket only on start button
setliveChartState({
...liveChartState,
liveActive: !liveChartState.liveActive,
historicLiveActive: true,
start: new Date(),
});
/*- - - -after updation this code needs to run - - - >*/
const { ws, liveActive } = liveChartState;
// if clicked on stop then close websocket
if (!liveActive && ws) {
ws.close();
clearLiveInterval();
}
// if clicked on start and websocket close then connect
if ((!ws || ws.readyState === WebSocket.CLOSED)&& liveActive) connect();
fetchData("historic");
/*----------*/
};
I have a functional component
The startlive function gets called when start button is clicked... This function is used to update the state and then execute the code which comes later as mentioned.
But it runs when setlivechartstate has not even completeted the updation.
I do not want to use Use effect hook as i just want to run the code only when button is clicked as it is working both as start and stop and also liveActive is getting changed in other functions also.. So using useEffect with this dependency created problem
What is the best way i can make this function work and only run the code after the updation is done
It would be better if you use useEffect. and for your issue you can check inside useEffect that if button is clicked : true then only useEffect will execute your updation code.
useEffect(() => {
if (ButtonClicked) {
// do updation stuff
}
}, [ButtonClicked]);
Considering your use case it would be great if you have a look at async/await functions and JavaScript Promises. In my opinion a good way to perform the update will be to maybe wrap your setliveChartState() function inside an async function, something like:
async function setLiveChart() {
setliveChartState(...)
}
And then call your async setLiveChart() function inside your const startLive = () => {} like:
const startLive = () => {
// connect to websocket only on start button
setLiveChart().then(() => {
/*- - - -after updation this code needs to run - - - >*/
const { ws, liveActive } = liveChartState;
// if clicked on stop then close websocket
if (!liveActive && ws) {
ws.close();
clearLiveInterval();
}
// if clicked on start and websocket close then connect
if ((!ws || ws.readyState === WebSocket.CLOSED)&& liveActive) connect();
fetchData("historic");
/*----------*/
}
};
You can also chain multiple then() callbacks like
setLiveChart()
.then(() => {})
.then(() => {})
.then...

Why does setTimeout behave this way in my stream implementation?

The final line of this code successfully calls the _read method of a custom Duplex stream in node.
const timeContext = new TimeContext(sampleRate);
const input = new InputStream(timeContext); // Stream.Readable
const throttle = new Throttle(sampleRate); // Stream.Transform
const stackSource = [];
const stack = new StackStream(stackSource); // Stream.Duplex
input.pipe(throttle).pipe(stack);
stack.read(); // This will call the _read method of StackStream
Adding setTimeout to delay the stream.read() call, setTimeout's callback does NOT get called:
const timeContext = new TimeContext(sampleRate);
const input = new InputStream(timeContext); // Stream.Readable
const throttle = new Throttle(sampleRate); // Stream.Transform
const stackSource = [];
const stack = new StackStream(stackSource); // Stack.Duplex
input.pipe(throttle).pipe(stack);
setTimeout(() => {
stack.read(); // This callback never gets called
}, 1000);
It definitely does get called but something else is erroring
setTimeout(() => {
console.log('We got here');
stack.read(); // This is what is crashing in your code
console.log('We don\'t get here');
}, 1000);
It is just not behaving as you expect because some other error is occurring. Look in the console to see what errors are raised.
Looks like, read() function is a local property of the stack object and the setTimeout is not able to see this local property of stack object. That's why it's behaving in such a way.
Refer this solution for reference,
https://stackoverflow.com/a/4536268/10371717

Categories

Resources