I have saga generator function to write unit test. Here yield select(getLocation) returned value pass to next function isAvailable(location). I need to unit test the flow of gen function. Currently select() return undefined. So, How to mock to return value select(getLocation) selector.
export const getUserInfo = function*() {
const location = yield select(getLocation);
const avilable = isAvailable(location);
vailable ? yield put(User.getUserData()) : return;
};
// unit test
describe('test getUserINfo', ()=>{
//need to yield select(getLocation) to pass isAvailable
const gen = getUserInfo();
expect(gen.next().value).toEqual(put(User.getUserData()));
});
need to yield select(getLocation) to pass isAvailable
Related
For example, I need to cache last task outside of the loop (redux-saga).
export default function* () {
let lastTask;
while (true) {
const action = yield take(someActions);
// some conditions there
if (lastTask) {
yield cancel(lastTask);
}
lastTask = yield fork(send(action));
}
}
What pattern should I use there to make it in a functional immutable way without let?
One option is to have the generator recursively yield* itself:
function* gen (lastTask) {
const action = yield take(someActions);
// some conditions there
if (lastTask) {
yield cancel(lastTask);
}
const nextLastTask = yield fork(send(action));
yield* gen(nextLastTask);
}
export default gen;
But note that nothing in your original code (or this code) involves mutation - the problem with let is that it permits reassignment, which is somewhat similar, but not the same thing. (Best to avoid mutation and reassignment, if possible, as long as the code remains easy to read)
Make sure the consumer calls gen with no arguments, of course.
I ran into problem with generators and hopefully you can help me out.
So, basically I separated/wrote my functions in separate modules (packages) so that it would be easier to update my application.
In the image below you can have a good idea what I am trying to do. For some reason when I keep calling the function with the .next() only the first yield is run.
Code that isn't working correctly
How can I run the other yields?
In your code, this.sensorGenerator().next() create a new generator each time where you then call next function, returning same first value each time.
You need to create/instanciate your generator and store it in a variable somewhere, and then call its next function.
var gen = this.sensorGenerator();
gen.next(); // first value
gen.next(); // second value
...
Here is a working snippet showing how to do.
const div = document.getElementById("osef");
const obj = {
_generator: undefined,
init: function() {
this._generator = this.sensorGenerator();
return this.getNextGenValue();
},
sensorGenerator: function*() {
yield 1;
yield 2;
yield 3;
yield 4;
return 5;
},
getNextGenValue: function() {
const v = this._generator.next();
console.log("getNextGenValue", v);
div.innerHTML = "generated value: " + v.value;
return v;
},
};
obj.init();
const btn = document.getElementById("btn");
btn.addEventListener("click", x => obj.getNextGenValue());
<button id="btn">Next generator value</button>
<div id="osef">Nothing yet</div>
I have a snippet of code
function* dataConsumer() {
console.log('Started');
console.log(`1. ${yield}`);
console.log(`2. ${yield}`);
return 'result';
}
let genObj = dataConsumer();
genObj.next();
and the running result is
Started
I don't understand why the second console.log can't output anything. Thanks for help.
Generators are build on the top of Iterators. To understand generator, you need first to understand iterator. See the Documentation.
For a one flow it runs to the nearer yield and terminates the function call. After it when you call again next it will continue from where it was terminated and works again until the nearest yield and when there are no yields or it reaches to the return statement, it just finishes its call.
function* dataConsumer() {
console.log('Started');
console.log(`1. ${yield}`); // First `next` terminates before yield. Second `next` passes the value and terminates before the next yield.
console.log(`2. ${yield}`); // Third call continues from the `yield` part and finishes the function, because we have returned
return 'result';
}
let genObj = dataConsumer();
genObj.next();
genObj.next('yield1');
genObj.next('yield2');
You also can pass parameters to the next function, which will be put in the yield statement. Also the next function returns an object about the generator state with properties value and done. If function call is not finished, it returns done as false and at the end you can see that this is set to true.
function* dataConsumer() {
console.log('Started');
const x = yield;
console.log(`1. ${x}`);
console.log(`2. ${yield}`);
return 'result';
}
let genObj = dataConsumer();
let result = genObj.next();
console.log(result);
result = genObj.next('x is yield1');
console.log(result);
result = genObj.next('yield2');
console.log(result);
genObj.next(); // This one has nothing to do
As you can pass parameters to the generator each step, you also can return a value from . You need to write something similar to return something, just replacing return with yield.
function* dataConsumer() {
yield 1;
yield 2;
yield 3;
}
let genObj = dataConsumer();
let result = genObj.next();
console.log(result);
result = genObj.next();
console.log(result);
result = genObj.next();
console.log(result);
result = genObj.next();
console.log(result);
var A = {
demo : function() * {
/* Some logic here, but no yield is used */
}
}
What is the use of a generator method that does not yield anything?
Have you ever used something like this? What was the use case?
It's quite the same case like an empty function - someone wants to call a function, but you have nothing to do.
Similarly, an empty generator function is a function which creates a generator that does nothing. It does represent the empty sequence. However, a generator function that doesn't yield isn't necessarily empty - it can still do something and have a result value, but there simply are no intermediate results.
The following code prints 'someValue' on the response every 100 ms for 5 seconds. It does not use yield.
const Koa = require('koa');
const through = require('through');
(new Koa()).use(function *(){
const tr = through();
setInterval(() => tr.write('someValue\n'), 100);
setTimeout(tr.end, 5000);
this.body = tr;
}).listen(3003, () => {});
Access with: curl localhost:3003
I have the following code in my Koa app:
exports.home = function *(next){
yield save('bar')
}
var save = function(what){
var response = redis.save('foo', what)
return response
}
But I get the following error: TypeError: You may only yield a function, promise, generator, array, or object, but the following object was passed: "OK"
Now, "ok" is the response from the redis server, which makes sense. But I cannot fully grasp the concept of generators for this kinds of functions. Any help?
You don't yield save('bar') because SAVE is synchronous. (Are you sure you want to use save?)
Since it's synchronous, you should change this:
exports.home = function *(next){
yield save('bar')
}
to this:
exports.home = function *(next){
save('bar')
}
and it will block execution until it's finished.
Almost all other Redis methods are asynchronous, so you would need to yield them.
For example:
exports.home = function *(next){
var result = yield redis.set('foo', 'bar')
}
Yield is supposed to be used inside a generator function according to the documentation.
The purpose is to return the result of an iteration to be used in the next iteration.
Like in this example (taken from the documentation):
function* foo(){
var index = 0;
while (index <= 2) // when index reaches 3,
// yield's done will be true
// and its value will be undefined;
yield index++;
}
var iterator = foo();
console.log(iterator.next()); // { value:0, done:false }
console.log(iterator.next()); // { value:1, done:false }
console.log(iterator.next()); // { value:2, done:false }
console.log(iterator.next()); // { value:undefined, done:true }