How to have a stub return a specific stub if parameters match (like stub routing)? - sinon

So I've got code basically like this:
var myStub = sinon.stub();
myStub.withArgs(sinon.match.has("key":"value")).returns({status: "OK!"});
And I want to use that in a stub like this:
stub.WithArgs(sinon.match.has("name","Configuration)).returns(myStub(params))
where the arguments passed to my stub are essentially passed along to my getConfig call ONLY if there is a property called "name" with the value of "Configuration".
Where it is called like this:
myFunction(
{
name: "Configuration,
params: {
key: "value"
}
}
That make sense? What's the proper Sinon approach to this?
Thanks in advance!

You can use callsFake:
stub.withArgs(sinon.match.has("name", "Configuration")).callsFake((arg) => myStub(arg.params));
Here is a complete working Jest test:
import * as sinon from 'sinon';
test('call stub from stub', () => {
var myStub = sinon.stub();
myStub.withArgs(sinon.match.has("key", "value")).returns({ status: "OK!" });
const stub = sinon.stub();
stub.withArgs(sinon.match.has("name", "Configuration")).callsFake((arg) => myStub(arg.params));
const response = stub({
name: "Configuration",
params: {
key: "value"
}
});
expect(response).toEqual({ status: "OK!" }); // SUCCESS
});

Related

Also, the action creator overrides toString() so that the action type becomes its string representation

I'm learning redux-toolkit from the official docs and came across this line- Also, the action creator overrides toString() so that the action type becomes its string representation. What does it mean?
Here's the code from the docs:
const INCREMENT = 'counter/increment'
function increment(amount) {
return {
type: INCREMENT,
payload: amount
}
}
const action = increment(3)
// { type: 'counter/increment', payload: 3 }
const increment = createAction('counter/increment')
let action = increment()
// { type: 'counter/increment' }
action = increment(3)
// returns { type: 'counter/increment', payload: 3 }
console.log(increment.toString())
// 'counter/increment'
console.log(`The action type is: ${increment}`)
// 'The action type is: counter/increment'
So, for example, when I write something like
const increment = createAction("INCREMENT")
console.log(increment.toString())
It's logging INCREMENT. So is this overriding of toString()? I'm really confused.
I'm new to redux-toolkit and any help would be appreciated. Thanks.
Normally, if you call toString() on a function, it returns the literal source text that was used to define the function:
function myFunction() {
const a = 42;
console.log(a);
}
myFunction.toString()
"function myFunction() {
const a = 42;
console.log(a);
}"
However, in this case, we want someActionCreator.toString() to return the action type that will be part of the action objects it creates:
const addTodo = createAction("todos/addTodo");
console.log(addTodo("Buy milk"));
// {type: "todos/addTodo", payload: "Buy milk"}
console.log(addTodo.toString());
// "todos/addTodo"
To make this happen, createAction overrides the actual implementation of toString for these action creators:
export function createAction(type: string): any {
function actionCreator(...args: any[]) {
return { type, payload: args[0] }
}
actionCreator.toString = () => `${type}`
actionCreator.type = type
return actionCreator;
}
This is especially useful because ES6 object literal computed properties automatically try to stringify whatever values you've passed in. So, you can now use an action creator function as the key in an object, and it'll get converted to the type string:
const reducersObject = {
[addTodo]: (state, action) => state.push(action.payload)
}
console.log(reducersObject);
// { "todos/addTodo": Function}

How to change immutablejs Record with methods from derived class?

I have 3 classes derived from Record. Definitions of first two classes are below.
// Base.js
import {Record} from 'immutable';
import * as uuid from 'uuid';
export const Base = defaultValues => {
return class extends Record({
key: null,
...defaultValues,
}) {
constructor(props) {
super(Object.assign({}, props, {key: (props && props.key) || uuid.v4()}));
}
};
};
// LOBase.js
import {Base} from './BaseModel';
export const LOBase = defaultValues => {
return class extends Base({
created_at: new Date(null),
updated_at: new Date(null),
deleted_at: new Date(null),
isActive: new Boolean(),
isDeleted: new Boolean(),
publishState: new String(),
...defaultValues,
}) {};
};
And this is my last class derived from LOBase and where my problem is.
// Question.js
import {List, Record, fromJS} from 'immutable';
import _ from 'lodash';
import {LOBase} from './base/LOBaseModel';
export class Question extends LOBase({
id: '',
name: 'test',
description: '',
questionType: 1,
title: 'title',
version: new String(),
customData: {},
//...
}) {
insertOption() {
let index = this.customData.options.length;
this.updateIn(['customData', 'options'], options => {
return options.splice(index, 0, {
someGenericStuff: [],
// ...
});
});
return this;
}
static MultipleChoice() {
let defaultCustomData = {
options: [],
//...
};
let question = new Question()
.set('questionType', QUESTION_TYPE_MULTIPLE_CHOICE)
.set('customData', new Record(defaultCustomData)())
//...
.insertOption()
.insertOption()
.insertOption();
return question;
}
// ...
}
I use let question = Question.MultipleChoice() to create a new Question instance. And when i use question.insertOption() it works fine. But when I do this in the reducer on the state I get an error saying "A state mutation was detected inside a dispatch".
How can I achieve to change question object in the state? Should I clone original Record before doing that? What is the Immutablejs way to do that?
Thanks in advance.
insertOption uses this.updateIn but does not return or store the result.
When you return this at the end of the function you actually return the same immutable Record without the changes.
So, unless I'm missing something here, you should probably go with:
insertOption() {
let index = this.customData.options.length;
return this.updateIn(['customData', 'options'], options => {
return options.splice(index, 0, {
someGenericStuff: [],
// ...
});
});
}
The updateIn will return a new instance of the Record with the updated values.
You did not add your state structure and reducer (if you can please do), but you should be sure to return a new state object every time and not just changing the question field.
BTW, you are doing a sequence of mutation methods one after the other (set, set, updateIn). This is not suggestable from a performance perspective. I'd suggest replacing it with withMutations in the following manner:
static insertOption(record) {
let index = record.customData.options.length;
return record.updateIn(['customData', 'options'], options => {
return options.splice(index, 0, {
someGenericStuff: [],
// ...
});
});
}
static MultipleChoice() {
// ...
let question = new Question();
question.withMutations(record => {
record.merge({
questionType: QUESTION_TYPE_MULTIPLE_CHOICE,
customData: new Record(defaultCustomData)()
})
Question.insertOption(record);
})
return question;
}

Lazy loading references from normalized Redux store

Yo! I'm using Redux and Normalizr. The API I'm working with sends down objects that look like this:
{
name: 'Foo',
type: 'ABCD-EFGH-IJKL-MNOP'
}
or like this
{
name: 'Foo2',
children: [
'ABCD-EFGH-IJKL-MNOP',
'QRST-UVWX-YZAB-CDEF'
]
}
I want to be able to asynchronously fetch those related entities (type and children) when the above objects are accessed from the state (in mapStateToProps). Unfortunately, this does not seem to mesh with the Redux way as mapStateToProps is not the right place to call actions. Is there an obvious solution to this case that I'm overlooking (other than pre-fetching all of my data)?
Not sure that I have correctly understood your use-case, but if you want to fetch data, one simple common way is to trigger it from a React component:
var Component = React.createClass({
componentDidMount: function() {
if (!this.props.myObject) {
dispatch(actions.loadObject(this.props.myObjectId));
}
},
render: function() {
const heading = this.props.myObject ?
'My object name is ' + this.props.myObject.name
: 'No object loaded';
return (
<div>
{heading}
</div>
);
},
});
Given the "myObjectId" prop, the component triggers the "myObject" fetching after mounting.
Another common way would be to fetch the data, if it's not already here, from a Redux async action creator (see Redux's doc for more details about this pattern):
// sync action creator:
const FETCH_OBJECT_SUCCESS = 'FETCH_OBJECT_SUCCESS';
function fetchObjectSuccess(objectId, myObject) {
return {
type: FETCH_OBJECT_SUCCESS,
objectId,
myObject,
};
}
// async action creator:
function fetchObject(objectId) {
return (dispatch, getState) => {
const currentAppState = getState();
if (!currentAppState.allObjects[objectId]) {
// fetches the object if not already present in app state:
return fetch('some_url_.../' + objectId)
.then(myObject => (
dispatch(fetchObjectSuccess(objectId, myObject))
));
} else {
return Promise.resolve(); // nothing to wait for
}
};
}

How to listen to changes in all mongoDB collection

I'm writing a meteor app,
I would like to write an observer which will listen to changes on a remote mongoDB,
Though I would like to write somthing generic which will listen to all Collections and will send the old value and new value. I mean:
var DBCollections = new Meteor.Collection.getall(); -> whats the right way to do this?
var cursor = DBCollection.find();
// watch the cursor for changes
var handle = cursor.observe({
added: function (object) {
var result = Meteor.http.post(
"http://localhost:8080",
{ params: { command: "add_object", value: object} } );
},
changed: function (object) {
oldValue = ??? -> how can I get it?
var result = Meteor.http.post(
"http://localhost:8080",
{ params: {command:"modify_object",oldValue: oldValue,newValue: object}} );
},
removed: function (object) {
var result = Meteor.http.post(
"http://localhost:8080",
{ params: { command: "remove_object",value: object } } );
}
});
so my qustions are like this:
how can I get all collections and observe changes on them?
When object modified how can I get the old value?

Ember-cli & fullCalendar

Senario is:
mcalendar: model,
mevent: model,
relationship: mcalendar has_many mevents,
in the mcalendar.show route I have:
model: function(params) {
return this.store.find('mcalendar', params.mcalendar_id);
},
what I want to do is:
to have a function in the mcalendar.show route to return all mevents of mcalendar in the form of an array. Something like this:
A HOOK(maybe afterModel): function(){
//return all mevents like:
return {
events: Ember.A([
{
title: mevent.get('title'),
start: mevent.get('start')
}])
the purpose is to use this array for feeding fullCalendar. I have tried some ways but none of them was successful.
Ember cli: 0.2.7
Thanks
are your mevents returned in the payload when requesting mcalendar? if so, you could do this in the setupController hook instead like...
setupController: function(controller, model) {
controller.set('events', model.get('mevents').toArray());
}
afterModel: function () {
var _this = this;
var model = this.modelFor(this.routeName);
return model.get('mevents').then(function(mevents) {
var allMevents = mevents.map(function(mevent){
return {
title: mevent.get('title'),
start: mevent.get('start')
};
});
_this.controllerFor('mcalendars.show').set('events', allMevents);
});
},

Resources