i have this method that returns an object. if i run the code below i find that the second console.log() hits first and the object returns undefined
private routeAndPassengerDataObject: undefined | RouteAndPassenger;
public getDataFromRouteAndPassengerObject(fileName?: string): RouteAndPassenger {
if (this.routeAndPassengerDataObject) {
return this.routeAndPassengerDataObject;
}
if (typeof fileName !== 'string') {
throw new Error(`${fileName} has to be a string`);
}
cy.fixture(fileName).then((data: unknown) => {
if (!isValidRouteAndPassengerObject(data)) {
throw new Error(`${data} is not valid`);
}
console.log(`this is first`);
this.routeAndPassengerDataObject = data;
});
console.log(`this is second`);
return this.routeAndPassengerDataObject!;
}
}
const routeAndPassengerData = getDataFromRouteAndPassengerObject()
console.log(routeAndPassengerData);
result-
this is second
this is first
undefined
would like to know how to handle this please.
returing the object as cypress.chainable like below has worked for me-
public getDataFromRouteAndPassengerObject(fileName?: string): Cypress.Chainable<RouteAndPassenger> {
if (this.routeAndPassengerDataObject) {
return cy.wrap(this.routeAndPassengerDataObject);
}
if (typeof fileName !== 'string') {
throw new Error(`${fileName} has to be a string`);
}
return cy.fixture(fileName).then((data: unknown) => {
if (!isValidRouteAndPassengerObject(data)) {
throw new Error(`${data} is not valid`);
}
console.log(`this is first`);
this.routeAndPassengerDataObject = data;
return cy.wrap(this._routeAndPassengerDataObject);
});
}
and then calling the object like so-
const routeAndPassengerData = getDataFromRouteAndPassengerObject().then((routeAndPassenger)=>{
console.log(routeAndPassenger)
})
My code are:-
function showData(data) {
return {
type: 'SHOWDATA',
data,
};
}
export default {
fetchData() {
return function (dispatch) {
getDataApi.getData().then((response)=>dispatch(showData(response)).catch()
};},
updateData{
return function (dispatch) {
getDataApi.getData().then((response)=>if(response.isSucess)
{dispatch(fetchData())}).catch()
};}
}
After update call of the action I want to refresh the list thats why I
called dispatch(fetchData()); but it is showing that fetchData not
defined.How can I call the method defined in same export default function.
Can this help you? Not really exported as default but its named.
export const Actions = {
getAll,
add,
update,
view,
search
}
function getAll(){
return dispatch => {
dispatch(request());
Service.getAll()
.then(
response => {
// todo...
},
error => {
// catch error
}
);
}
function request() { return { type: Constants.LIST_REQUEST } }
function success(data) { return { type: Constants.LIST_SUCCESS, data } }
function failure(error) { return { type: Constants.LIST_FAILURE, error } }
}
function add(data){
return dispatch => {
dispatch(request());
Service.add(data)
.then(
response => {
if(response.status === 'fail'){
// do something
}else{
dispatch(success(response));
dispatch(getAll());
}
},
error => {
// do something
}
);
}
function request() { return { type: Constants.ADD_REQUEST } }
function success(data) { return { type: Constants.ADD_SUCCESS, data } }
function failure(error) { return { type: Constants.ADD_FAILURE, error } }
}
I'm new in react/redux, I've try to call a service cap from my sagas cap, but when I try to call the axios.get() method I get always a promime with PromiseStatus = "pending" and PromiseValue= undefined, I've try to get the promise but I don't know how can I do it.
My Sagas.js
try
{
let response = yield
StudentsService.getStudentByEmail(action.payload.studentUser)
yield put({type: studentActionsTypes.STUDENT_DATA_SUCCESS,
studentResponse: response});
}
catch (error)
{
console.log('El servicio me devolvió un error: ' + error.message);
yield put({type: studentActionsTypes.STUDENT_DATA_ERROR});
}
My service
export class StudentsService
{
static getStudentByEmail(email)
{
var userT = '';
const state = {
studentF: {
studentId: '',
studentFullName: ''
}
};
let userPromise = UsersService.getUsers();
userPromise.then((response) =>
{
if(response.data.users.length >= 0)
{
response.data.users.map(u =>
{
if(u.email == email)
{
userT = u;
console.log('Nombre en este objeto: ' + userT.name)
this.state = {
studentF: {
studentId: userT.id,
studentFullName: userT.name + ' ' + userT.lastName
}
}
}
});
}
});
return state.studentF;
}
}
I'll be grateful of your help.
I was able to solve my problem with the the answer in this other question
Currently, I have a function that sometimes return an object with some functions inside. When using expect(...).toEqual({...}) it doesn't seem to match those complex objects. Objects having functions or the File class (from input type file), it just can't. How to overcome this?
Try the Underscore _.isEqual() function:
expect(_.isEqual(obj1, obj2)).toEqual(true);
If that works, you could create a custom matcher:
this.addMatchers({
toDeepEqual: function(expected) {
return _.isEqual(this.actual, expected);
};
});
You can then write specs like the following:
expect(some_obj).toDeepEqual(expected_obj);
As Vlad Magdalin pointed out in the comments, making the object to a JSON string, it can be as deep as it is, and functions and File/FileList class. Of course, instead of toString() on the function, it could just be called 'Function'
function replacer(k, v) {
if (typeof v === 'function') {
v = v.toString();
} else if (window['File'] && v instanceof File) {
v = '[File]';
} else if (window['FileList'] && v instanceof FileList) {
v = '[FileList]';
}
return v;
}
beforeEach(function(){
this.addMatchers({
toBeJsonEqual: function(expected){
var one = JSON.stringify(this.actual, replacer).replace(/(\\t|\\n)/g,''),
two = JSON.stringify(expected, replacer).replace(/(\\t|\\n)/g,'');
return one === two;
}
});
});
expect(obj).toBeJsonEqual(obj2);
If anyone is using node.js like myself, the following method is what I use in my Jasmine tests when I am only concerned with comparing the simple properties while ignoring all functions. This method requires json-stable-stringify which is used to sort the object properties prior to serializing.
Usage:
var stringify = require('json-stable-stringify');
var obj1 = {
func: function() {
},
str1: 'str1 value',
str2: 'str2 value',
nest1: {
nest2: {
val1:'value 1',
val2:'value 2',
someOtherFunc: function() {
}
}
}
};
var obj2 = {
str2: 'str2 value',
str1: 'str1 value',
func: function() {
},
nest1: {
nest2: {
otherFunc: function() {
},
val2:'value 2',
val1:'value 1'
}
}
};
it('should compare object properties', function () {
expect(stringify(obj1)).toEqual(stringify(obj2));
});
Extending #Vlad Magdalin's answer, this worked in Jasmine 2:
http://jasmine.github.io/2.0/custom_matcher.html
beforeEach(function() {
jasmine.addMatchers({
toDeepEqual: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var result = {};
result.pass = _.isEqual(actual, expected);
return result;
}
}
}
});
});
If you're using Karma, put that in the startup callback:
callback: function() {
// Add custom Jasmine matchers.
beforeEach(function() {
jasmine.addMatchers({
toDeepEqual: function(util, customEqualityTesters) {
return {
compare: function(actual, expected) {
var result = {};
result.pass = _.isEqual(actual, expected);
return result;
}
}
}
});
});
window.__karma__.start();
});
here's how I did it using the Jasmine 2 syntax.
I created a customMatchers module in ../support/customMatchers.js (I like making modules).
"use strict";
/**
* Custom Jasmine matchers to make unit testing easier.
*/
module.exports = {
// compare two functions.
toBeTheSameFunctionAs: function(util, customEqualityTesters) {
let preProcess = function(func) {
return JSON.stringify(func.toString()).replace(/(\\t|\\n)/g,'');
};
return {
compare: function(actual, expected) {
return {
pass: (preProcess(actual) === preProcess(expected)),
message: 'The functions were not the same'
};
}
};
}
}
Which is then used in my test as follows:
"use strict";
let someExternalFunction = require('../../lib/someExternalFunction');
let thingBeingTested = require('../../lib/thingBeingTested');
let customMatchers = require('../support/customMatchers');
describe('myTests', function() {
beforeEach(function() {
jasmine.addMatchers(customMatchers);
let app = {
use: function() {}
};
spyOn(app, 'use');
thingBeingTested(app);
});
it('calls app.use with the correct function', function() {
expect(app.use.calls.count()).toBe(1);
expect(app.use.calls.argsFor(0)).toBeTheSameFunctionAs(someExternalFunction);
});
});
If you want to compare two objects but ignore their functions, you can use the methods _.isEqualWith together with _.isFunction from lodash as follows.
function ignoreFunctions(objValue, otherValue) {
if (_.isFunction(objValue) && _.isFunction(otherValue)) {
return true;
}
}
it('check object equality but ignore their functions', () => {
...
expect(_.isEqualWith(actualObject, expectedObject, ignoreFunctions)).toBeTrue();
});
How can I validate only certain attributes on a model? Currently I check if the attribute exists in the object passed into validate:
validate: function(attrs) {
// Number
if (attrs.minimum) {
if (isNaN(attrs.minimum)) {
return -1;
}
}
if (attrs.maximum) {
if (isNaN(attrs.maximum)) {
return -1;
}
}
}
but if I want to validate string value then:
if (attrs.mystring) {
// Do validation
}
would fail and the validation never takes place.
Backbone now supports the has property. So you can do something like that:
var Person = Backbone.Model.extend({
defaults: {
"name": "Kevin",
"age" : 26,
"job" : "web"
},
validate: function(attrs, options) {
for(k in attrs) {
if(!this.has(k)) {
return k + ' attribute is not exist';
}
}
}
});
var person = new Person;
person.on("invalid", function(model, error) {
console.log(error);
});
Im a little confused by your wording, but I think you want to check if its not an empty string first? and also work out the possibility that it is undefined..if so then this is what you'll want to do..
validate: function(attrs) {
// Number
if (attrs.minimum) {
if (isNaN(attrs.minimum)) {
return -1;
}
}
if (attrs.maximum) {
if (isNaN(attrs.maximum)) {
return -1;
}
}
if (typeof(attrs.mystring) != "undefined"){
if (!attrs.mystring){
return -1;
}
}
}
if you want to only validate one of your attributes, you should write your validate function to accommodate the options accordingly
validate: function(attrs, option) {
if (!option){
// Number
if (attrs.minimum) {
if (isNaN(attrs.minimum)) {
return -1;
}
}
if (attrs.maximum) {
if (isNaN(attrs.maximum)) {
return -1;
}
}
if (!attrs.mystring){
return -1;
}
}else{
switch(option){
case("string"):
if (!attrs.mystring){
return -1;
}
break;
case("number"):
// Number
if (attrs.minimum) {
if (isNaN(attrs.minimum)) {
return -1;
}
}
if (attrs.maximum) {
if (isNaN(attrs.maximum)) {
return -1;
}
}
break;
}
}
}
there are many ways to do this, this probably being the least efficient lol but using your example, it will do the job.
also, this isn't really a backbone.js problem per say...but general js