Unexpected result when using Sinon onCall method - sinon

I am experiencing an unexpected result :"should get data and has multiple recordSets" test case. My intention is to have the "stub.getRefundItems" method call return one set of results on the first call and a second set of results on the second call. The test works as expected if there are no other tests that use that method. However when I add in the additional test "should get data and has 1 recordSet" I get a single result (LineItemsHasNextFalse) no matter what I do. I should also mention the stub gets injected via awilix as a singleton. Am I wiring the stub up incorrectly? Is it not possible to change the results using onCall after you have set the returns value?
let stub = {
getRefund: sandbox.stub(),
getRefunds: sandbox.stub(),
getRefundItems: sandbox.stub(),
getRefundTransactions: sandbox.stub()
};
var sandbox = require('sinon').createSandbox();
describe('#refunds', function() {
beforeEach(function () {
sandbox.spy(logger)
})
afterEach(function () {
// completely restore all fakes created through the sandbox
sandbox.restore();
})
context('getRefundItems', function() {
it('should get data and has 1 recordSet', test(async function() {
stub.getRefundItems.returns(LineItemsHasNextFalse)
let resp = await refunds.getRefundItems({"gid":"shjdjs"})
expect(resp).to.deep.equal(LineItemsHasNextFalse.data.refund.refundLineItems.edges)
}))
it('should get data and has multiple recordSets', test(async function() {
let correctResp = new Array()
correctResp.push(...LineItemsHasNextTrue.data.refund.refundLineItems.edges)
correctResp.push(...LineItemsHasNextFalse.data.refund.refundLineItems.edges)
stub.getRefundItems.onCall(0).returns(LineItemsHasNextTrue)
stub.getRefundItems.onCall(1).returns(LineItemsHasNextFalse)
let resp = await refunds.getRefundItems({"gid":"shjdjs"})
console.log(resp)
expect(resp).to.deep.equal(correctResp)
}))
})
})
async getRefundItems(msgObj)
{
let hasNext = false
let items = []
let count = 0
do
{
let response = await stub.getRefundItems(msgObj)
if(response.data.refund != null)
{
items.push(...response.data.refund.refundLineItems.edges)
if(response.data.refund.refundLineItems.pageInfo.hasNextPage)
{
let cursor = response.data.refund.refundLineItems.edges[0].cursor
msgObj.after = cursor
hasNext = true
}
else
{
hasNext=false
}
}
}
while(hasNext)
return items
}

Related

correct way to fire out a fail result in page reponse event listener in codeceptJS

I wrote a helper methods to add a network response listener over Puppeteer page instance. the code looks like this
let Helper = codecept_helper;
class CheckHelper extends Helper {
async listenRequest(listener)
{
const helper = this.helpers['Puppeteer'];
await helper.page.setRequestInterception(true);
helper.page.on("request",listener);
return helper._waitForAction();
}
async listenResponse(listener)
{
const helper = this.helpers['Puppeteer'];
helper.page.on("response",listener);
return helper._waitForAction();
}
}
module.exports = CheckHelper;
then in the test script
let self=this;
I.listenResponse((response)=>{
if(response.url().match(/github.*\.js/) && response.headers()['content-length']>1000) {
//codeceptjs.event.emit(codeceptjs.event.test.failed, self, 'js file is too big!');
//codeceptjs.recorder.throw('js file is too big!')
//codeceptjs.recorder.stop();
//throw new Error('js file is too big!')
}
})
I.amOnPage("https://www.github.com");
i first add response listener, then i goto "github", when some js file size is too big,i will throw out an error,in order too check content size is correctly.
however, even i throw error out (like the comments codes did), the main test flow just not stop, how do i do is the right way?
well,i found a solution later
i recorded all the page response into a custom object in the page instance.
later i wrote a help methods to check whole records.
//in helper.js
startRecordResponse() {
const helper = this.helpers['Puppeteer'];
helper.page.on("response", (res) => {
//record all response instance into savedResponse object inside page, we'll use it later
helper.page.savedResponse = helper.page.savedResponse || {};
helper.page.savedResponse[res.url()] = res;
});
return helper._waitForAction();
}
checkFileIsTooBig(filter, sizeLimit) {
const helper = this.helpers['Puppeteer'];
//use the data recorded in savedResponse object
Object.keys(helper.page.savedResponse).forEach((url) => {
var res = helper.page.savedResponse[url];
if (((filter instanceof RegExp && filter.test(url)) || (typeof filter == "string" && url.indexOf(filter) != -1)) && res.headers()['content-length'] > sizeLimit) {
throw new Error(`file ${url} is too big,${res.headers()['content-length']} > ${sizeLimit}`)
}
})
return helper._waitForAction();
}
then in test file
Before((I) => {
I.startRecordResponse();
I.amOnPage("https://www.github.com");
});
Scenario('github_test', (I) => {
//check a js file contain github is less than 100 bytes
I.checkFileIsTooBig(/github.*\.js/,100);
}
);

How to test the return value of a promise in a Cucumber test?

I'm trying to test the return value of a get request to a couchdb node.
I have a feature defined with the following Given clause:
Given A get request is made to the DB
which is implemented with the following step function:
var Profile = require('../UserProfile.js')
Given('A get request is made to the DB', function () {
var text = Profile.getDB('localhost:5984').then(data => {
console.log(data)
})
});
The above step references this model:
var axios = require('axios')
module.exports = {
getDB: function(url){
return axios.get(url).then(response => {
return response.data
})
}
};
I can't seem to log the result of the GET request when I perform it in the model and reference it in the step definition. When I do the GET request in the step definition, it works - but this isn't useful to me, I want to test the model. How do I get the resulting value?
Cucumber 2.0 supports Promises as returns, try with:
const Profile = require('../UserProfile')
const { defineSupportCode } = require('cucumber')
defineSupportCode(({ defineStep }) => {
defineStep('A get request is made to the DB', function () {
return Profile.getDB('http://localhost:5984').then(data => {
console.log(data)
})
})
})

Method call that fetches data. Can it be made reactive?

I want to get data from a number of queries on the same collection, and unfortunately this is not yet supported on meteor. That's why I tried to do something like this:
Common
Dep = new Deps.Dependency;
Server
Meteor.methods({
fetch: function(){
var results = Data.find(dataQuery).fetch();
var otherResults = Data.find(queryThatCannotBeCombinedWithPrevious).fetch();
return results.concat(otherResults);
},
save: function(data){
Data.insert(data);
Dep.changed();
}
update: function(data){
Data.update({_id: data._id}, data);
Dep.changed();
}
});
Client
Session.setDefault('combinedData', []);
Template.demo.data = function(){
Dep.depend();
Meteor.call('fetch',function(error, data){
Session.set('combinedData', data);
});
return Session.get('combinedData');
};
This doesn't work though, propably because the Dep variable on the client is different from the Dep on the server. Is there a way to make the method call reactive when the contents of the Data collection change?
Notes
I am currently using Meteor 0.8.1.1, which doesn't allow subscriptions that return multiple cursors of the same collection yet.
This requires a small hack and you're close. First, you need a client–only dependence, the server just passes a data returned from the method and doesn't share variables (also there's nothing on the server that requires deps). Second, you only want to fetch the actual variable once, otherwise you'll end up with an infinite loop.
Example implementation:
var value = null;
var valueInitialized = false;
var valueDep = new Deps.Dependency();
Template.demo.data = function() {
valueDep.depend();
if(!valueInitialized) {
valueInitialized = true;
Meteor.call('fetchData', function(err, result) {
value = result;
valueDep.changed();
});
}
return value;
};

Block meteor helper from returning when doing http request

I need to prevent my meteor helper from returning right away until either the timeout or data returns from my Meteor.http.get(url, ...) request. For example,
Meteor.templateName.helpers ({
testHelper: function()
{
var ss = "doesnt wait";
Meteor.http.get("http://api.somesite.com",
function (error, result) {
if(!error){
if(result.statusCode === 200) {
var respJson = JSON.parse(result.content);
console.log(respJson);
ss = "should have this value";
}
}
});
return ss;
}
})
Is Meteor.http not a blocking call, how can i make the helper method stop until the get request returns data. Do i need to move the get request to a Meteor.Method ?
On the client, you don't have the fiber module, as a result is not possible to make a synchronous call to a function.
One solution might be to use a Session because of it's reactivity. You just set a default value, and use it in your helper function
Session.setDefault('testHelper', {msg: 'wait'})
Meteor.templateName.helpers ({
testHelper: function() {
return Session.get('testHelper');
}
});
Then update this session every time you want:
Template.templateName.rendered = function () {
Meteor.http.get("http://api.somesite.com",
function (error, result) {
if(!error && result.statusCode === 200){
var respJson = JSON.parse(result.content);
Session.set('testHelper', respJson)
}
}
);
}
If you don't want to use a Session, you can implement your own reactivity mecanism using the Deps module. For instance in the Meteor.http.get callback you can set a Template.templateName attribute and invalidate a context object in order to rerun the helper function. But a Session is definitly more easy ;-)

Can't get result data with $http angularjs

I'm trying to use $http, but why it return null result?
angular.module('myApp')
.factory('sender', function($http) {
var newData = null;
$http.get('test.html')
.success(function(data) {
newData = data;
console.log(newData)
})
.error(function() {
newData = 'error';
});
console.log(newData)
return newData
})
Console say: http://screencast.com/t/vBGkl2sThBd4. Why my newData first is null and then is defined? How to do it correctly?
As YardenST said, $http is asynchronous so you need to make sure that all functions or display logic that are dependent on the data that is returned by your $http.get(), gets handle accordingly. One way to accomplish this is to make use of the "promise" that $http returns:
Plunkr Demo
var myApp = angular.module('myApp', []);
myApp.factory('AvengersService', function ($http) {
var AvengersService = {
getCast: function () {
// $http returns a 'promise'
return $http.get("avengers.json").then(function (response) {
return response.data;
});
}
};
return AvengersService;
});
myApp.controller('AvengersCtrl', function($scope, $http, $log, AvengersService) {
// Assign service to scope if you'd like to be able call it from your view also
$scope.avengers = AvengersService;
// Call the async method and then do stuff with what is returned inside the function
AvengersService.getCast().then(function (asyncCastData) {
$scope.avengers.cast = asyncCastData;
});
// We can also use $watch to keep an eye out for when $scope.avengers.cast gets populated
$scope.$watch('avengers.cast', function (cast) {
// When $scope.avengers.cast has data, then run these functions
if (angular.isDefined(cast)) {
$log.info("$scope.avengers.cast has data");
}
});
});
This JavaScript code is asynchronous.
console.log(newData)
return newData
Is executed before what inside success
newData = data;
console.log(newData)
So at first time, the newData is null (you set it to be null)
And when the http response is returned (inside the success), the newData gets its new value.
This is very common in Javascript, you should do all your work inside the success.

Resources