Promise with async function is not waiting to be fulfilled - javascript

I am struggling with the issue of Promise and async/await for last two days. I am trying to configure my protractor.conf.js that would get the browser name just at the starting of the suit and will join with the suit name. I have written jasmine allure reporter code in customized way so that I can get browser name in asynchronously and then use with the suit name. But nothing working properly. In the code I have tried, I get only suit name. Browser name in few seconds later. As a result I could not use that browser name in suit name. Here is my code in detail
Edited
var AllureReporter = function CustomJasmine2AllureReporter(userDefinedConfig, allureReporter) {
let browser = {
getCapabilities: function() {
return new Promise(resolve => {
setTimeout(() => {
resolve({
get: str => str
});
}, 2000);
});
}
};
var result;
let bName = (async () => {
try {
var result = (await browser.getCapabilities()).get('Browser Name');
return result;
} catch (err) {
return "Error or smth"
}
})();
this.suiteStarted = function(suite) {
this.allure.startSuite(suite.fullName + result);
console.log(suite.fullName + result);
};
// other methods like spec done,, spec description.
}
the index code from Allure that can be changed is
'use strict';
var assign = require('object-assign'),
Suite = require('./beans/suite'),
Test = require('./beans/test'),
Step = require('./beans/step'),
Attachment = require('./beans/attachment'),
util = require('./util'),
writer = require('./writer');
function Allure() {
this.suites = [];
this.options = {
targetDir: 'allure-results'
};
}
Allure.prototype.setOptions = function(options) {
assign(this.options, options);
};
Allure.prototype.getCurrentSuite = function() {
return this.suites[0];
};
Allure.prototype.startSuite = function(suiteName, timestamp) {
this.suites.unshift(new Suite(suiteName,timestamp));
};
module.exports = Allure;
and the Suit.js class
function Suite(name, timestamp) {
this.name = name;
this.start = timestamp || Date.now();
this.testcases = [];
}
Suite.prototype.end = function(timestamp) {
this.stop = timestamp || Date.now();
};
Suite.prototype.addTest = function(test) {
this.testcases.push(test);
};
Suite.prototype.toXML = function() {
var result = {
'#': {
'xmlns:ns2' : 'urn:model.allure.qatools.yandex.ru',
start: this.start
},
name: this.name,
title: this.name,
'test-cases': {
'test-case': this.testcases.map(function(testcase) {
return testcase.toXML();
})
}
};
if(this.stop) {
result['#'].stop = this.stop;
}
return result;
};
module.exports = Suite;
I am getting this output after edited the question.the result is undefined in the suit name
Executing 7 defined specs...
Test Suites & Specs:
Test for correct login undefined
1. Test for correct login
(node:9764) [DEP0005] DeprecationWarning: Buffer() is deprecated due to
security and usability issues. Please use the Buffer.alloc(),
Buffer.allocUnsafe(), or Buffer.from() methods instead.
√ Navigate to the login page (5520ms)
√ Click onto language button (406ms)
√ English Language is selected (417ms)
√ Correct user name is written into email field (609ms)
√ Correct password is written into password field (486ms)
√ Login button is clicked and home page is opened with Machine on left top
menu (5622ms)
√ Logout button is clicked and redirect to login page (4049ms)
7 specs, 0 failures
Finished in 17.127 seconds
I want to get browser name after the the line 'Test Suites & Specs:' and want to add the name with suit name.

The function where you want to use await should be async.
I have made a small example for you. hope it will help
//The function we want to use wait in should be async!
async function myFunction() {
//Using callback
thisTakeSomeTime().then((res) => console.log(res)); //Will fire when time out is done. but continue to the next line
//Using await
let a = await thisTakeSomeTime();
console.log(a);//will fire after waiting. a will be defined with the result.
}
function thisTakeSomeTime() {
return new Promise((res) => {
setTimeout(()=>{res("This is the result of the promise")}, 5000)
})
}
myFunction();

Related

JS - How to retrieve variable after IndexedDB transaction.oncomplete() executes?

My problem is simple, but incredibly frustrating as I'm now on my second week of trying to figure this out and on the verge of giving up. I would like to retrieve my 'notesObject' variable outside my getAllNotes() function when after the transaction.oncomplete() listener executes.
(function() {
// check for IndexedDB support
if (!window.indexedDB) {
console.log(`Your browser doesn't support IndexedDB`);
return;
}
// open the CRM database with the version 1
let request = indexedDB.open('Notes', 1);
// create the Contacts object store and indexes
request.onupgradeneeded = (event) => {
let db = event.target.result;
// create the Notes object store ('table')
let store = db.createObjectStore('Notes', {
autoIncrement: true
});
// create an index on the sections property.
let index = store.createIndex('Sections', 'sections', {
unique: true
});
}
function insertData() {
let myDB = indexedDB.open('Notes');
myDB.onsuccess = (event) => {
// myDB.transaction('Notes', 'readwrite')
event.target.result.transaction('Notes', 'readwrite')
.objectStore('Notes')
.put({
sections: "New Note",
pages: "New page",
lastSelectedPage: ""
});
console.log("insert successful");
}
myDB.onerror = (event) => {
console.log('Error in NotesDB - insertData(): ' + event.target.errorCode);
}
myDB.oncomplete = (event) => {
myDB.close();
console.log('closed');
}
}
insertData()
function getAllNotes() {
let myDB = indexedDB.open('Notes');
let notesObject = [];
myDB.onsuccess = (event) => {
let dbObjectStore = event.target.result
.transaction("Notes", "readwrite").objectStore("Notes");
dbObjectStore.openCursor().onsuccess = (e) => {
let cursor = e.target.result;
if (cursor) {
let primaryKey = cursor.key;
let section = cursor.value.sections;
notesObject.push({
primaryKey,
section
})
cursor.continue();
}
}
dbObjectStore.transaction.onerror = (event) => {
console.log('Error in NotesDB - getAllData() tranaction: ' + event.target.errorCode);
}
dbObjectStore.transaction.oncomplete = (event) => {
return notesObject;
console.log(notesObject)
}
}
}
let notes = getAllNotes()
console.log("Getting Notes sucessful: " + notes)
})()
I've tried setting global variables, but nothing seems to work. I am a complete noob and honestly, I'm completely lost on how to retrieve the notesObject variable outside my getAllNotes() function. The results I get are 'undefined'. Any help would be greatly appreciated.
This is effectively a duplicate of Indexeddb: return value after openrequest.onsuccess
The operations getAllNotes() kicks off are asynchronous (they will run in the background and take time to complete), whereas your final console.log() call is run synchronously, immediately after getAllNotes(). The operations haven't completed at the time that is run, so there's nothing to log.
If you search SO for "indexeddb asynchronous" you'll find plenty of questions and answers about this topic.

Wait for all Firebase data query requests before executing code

I am trying to fetch data from different collections in my cloud Firestore database in advance before I process them and apply them to batch, I created two async functions, one to capture the data and another to execute certain code only after all data is collected, I didn't want the code executing and creating errors before the data is fetched when i try to access the matchesObject after the async function to collect data is finished, it keeps saying "it cannot access a property matchStatus of undefined", i thought took care of that with async and await? could anyone shed some light as to why it is undefined one moment
axios.request(options).then(function(response) {
console.log('Total matches count :' + response.data.matches.length);
const data = response.data;
var matchesSnapshot;
var marketsSnapshot;
var tradesSnapshot;
var betsSnapshot;
matchesObject = {};
marketsObject = {};
tradesObject = {};
betsObject = {};
start();
async function checkDatabase() {
matchesSnapshot = await db.collection('matches').get();
matchesSnapshot.forEach(doc => {
matchesObject[doc.id] = doc.data();
console.log('matches object: ' + doc.id.toString())
});
marketsSnapshot = await db.collection('markets').get();
marketsSnapshot.forEach(doc2 => {
marketsObject[doc2.id] = doc2.data();
console.log('markets object: ' + doc2.id.toString())
});
tradesSnapshot = await db.collection('trades').get();
tradesSnapshot.forEach(doc3 => {
tradesObject[doc3.id] = doc3.data();
console.log('trades object: ' + doc3.id.toString())
});
betsSnapshot = await db.collection('bets').get();
betsSnapshot.forEach(doc4 => {
betsObject[doc4.id] = doc4.data();
console.log('bets object: ' + doc4.id.toString())
});
}
async function start() {
await checkDatabase();
// this is the part which is undefined, it keeps saying it cant access property matchStatus of undefined
console.log('here is matches object ' + matchesObject['302283']['matchStatus']);
if (Object.keys(matchesObject).length != 0) {
for (let bets of Object.keys(betsObject)) {
if (matchesObject[betsObject[bets]['tradeMatchId']]['matchStatus'] == 'IN_PLAY' && betsObject[bets]['matched'] == false) {
var sfRef = db.collection('users').doc(betsObject[bets]['user']);
batch11.set(sfRef, {
accountBalance: admin.firestore.FieldValue + parseFloat(betsObject[bets]['stake']),
}, {
merge: true
});
var sfRef = db.collection('bets').doc(bets);
batch12.set(sfRef, {
tradeCancelled: true,
}, {
merge: true
});
}
}
}
});
There are too many smaller issues in the current code to try to debug them one-by-one, so this refactor introduces various tests against your data. It currently won't make any changes to your database and is meant to be a replacement for your start() function.
One of the main differences against your current code is that it doesn't unnecessarily download 4 collections worth of documents (two of them aren't even used in the code you've included).
Steps
First, it will get all the bet documents that have matched == false. From these documents, it will check if they have any syntax errors and report them to the console. For each valid bet document, the ID of it's linked match document will be grabbed so we can then fetch all the match documents we actually need. Then we queue up the changes to the user's balance and the bet's document. Finally we report about any changes to be done and commit them (once you uncomment the line).
Code
Note: fetchDocumentById() is defined in this gist. Its a helper function to allow someCollectionRef.where(FieldPath.documentId(), 'in', arrayOfIds) to take more than 10 IDs at once.
async function applyBalanceChanges() {
const betsCollectionRef = db.collection('bets');
const matchesCollectionRef = db.collection('matches');
const usersCollectionRef = db.collection('users');
const betDataMap = {}; // Record<string, BetData>
await betsCollectionRef
.where('matched', '==', false)
.get()
.then((betsSnapshot) => {
betsSnapshot.forEach(betDoc => {
betDataMap[betDoc.id] = betDoc.data();
});
});
const matchDataMap = {}; // Record<string, MatchData | undefined>
// betIdList contains all IDs that will be processed
const betIdList = Object.keys(betDataMap).filter(betId => {
const betData = betDataMap[betId];
if (!betData) {
console.log(`WARN: Skipped Bet #${betId} because it was falsy (actual value: ${betData})`);
return false;
}
const matchId = betData.tradeMatchId;
if (!matchId) {
console.log(`WARN: Skipped Bet #${betId} because it had a falsy match ID (actual value: ${matchId})`);
return false;
}
if (!betData.user) {
console.log(`WARN: Skipped Bet #${betId} because it had a falsy user ID (actual value: ${userId})`);
return false;
}
const stakeAsNumber = Number(betData.stake); // not using parseFloat as it's too lax
if (isNaN(stakeAsNumber)) {
console.log(`WARN: Skipped Bet #${betId} because it had an invalid stake value (original NaN value: ${betData.stake})`);
return false;
}
matchDataMap[matchId] = undefined; // using undefined because its the result of `doc.data()` when the document doesn't exist
return true;
});
await fetchDocumentsById(
matchesCollectionRef,
Object.keys(matchIdMap),
(matchDoc) => matchDataMap[matchDoc.id] = matchDoc.data()
);
const batch = db.batch();
const queuedUpdates = 0;
betIdList.forEach(betId => {
const betData = betDataMap[betId];
const matchData = matchDataMap[betData.tradeMatchId];
if (matchData === undefined) {
console.log(`WARN: Skipped /bets/${betId}, because it's linked match doesn't exist!`);
continue;
}
if (matchData.matchStatus !== 'IN_PLAY') {
console.log(`INFO: Skipped /bets/${betId}, because it's linked match status is not "IN_PLAY" (actual value: ${matchData.matchStatus})`);
continue;
}
const betRef = betsCollectionRef.doc(betId);
const betUserRef = usersCollectionRef.doc(betData.user);
batch.update(betUserRef, { accountBalance: admin.firestore.FieldValue.increment(Number(betData.stake)) });
batch.update(betRef, { tradeCancelled: true });
queuedUpdates += 2; // for logging
});
console.log(`INFO: Batch currently has ${queuedUpdates} queued`);
// only uncomment when you are ready to make changes
// batch.commit();
}
Usage:
axios.request(options)
.then(function(response) {
const data = response.data;
console.log('INFO: Total matches count from API:' + data.matches.length);
return applyBalanceChanges();
}

Node.Js doesn't execute anonymous functions?? -aws lambda -alexa skill

I'm currently working on a Alexa Skill for my Smart Home.
I created a Lambda function and want to make a http request to a server. but it wont execute any of my anon. functions.
A lambda code example:
/* This code has been generated from your interaction model by skillinator.io
/* eslint-disable func-names */
/* eslint quote-props: ["error", "consistent"]*/
// There are three sections, Text Strings, Skill Code, and Helper Function(s).
// You can copy and paste the contents as the code for a new Lambda function, using the alexa-skill-kit-sdk-factskill template.
// This code includes helper functions for compatibility with versions of the SDK prior to 1.0.9, which includes the dialog directives.
// 1. Text strings =====================================================================================================
// Modify these strings and messages to change the behavior of your Lambda function
const request = require("request");
let speechOutput;
let reprompt;
let welcomeOutput = "Hallo xyz!";
let welcomeReprompt = "xy";
// 2. Skill Code =======================================================================================================
"use strict";
const Alexa = require('alexa-sdk');
const APP_ID = "my id"; // TODO replace with your app ID (OPTIONAL).
speechOutput = '';
const handlers = {
'LaunchRequest': function () {
this.emit(':ask', welcomeOutput, welcomeReprompt);
},
'AMAZON.HelpIntent': function () {
speechOutput = 'Placeholder response for AMAZON.HelpIntent.';
reprompt = '';
this.emit(':ask', speechOutput, reprompt);
},
'AMAZON.CancelIntent': function () {
speechOutput = 'Placeholder response for AMAZON.CancelIntent';
this.emit(':tell', speechOutput);
},
'AMAZON.StopIntent': function () {
speechOutput = 'Placeholder response for AMAZON.StopIntent.';
this.emit(':tell', speechOutput);
},
'SessionEndedRequest': function () {
speechOutput = '';
//this.emit(':saveState', true);//uncomment to save attributes to db on session end
this.emit(':tell', speechOutput);
},
'LichtIntent': function () {
//delegate to Alexa to collect all the required slot values
let filledSlots = delegateSlotCollection.call(this);
speechOutput = '';
//any intent slot variables are listed here for convenience
let zimmerSlotRaw = this.event.request.intent.slots.zimmer.value;
console.log(zimmerSlotRaw);
let zimmerSlot = resolveCanonical(this.event.request.intent.slots.zimmer);
console.log(zimmerSlot);
let was_lichtSlotRaw = this.event.request.intent.slots.was_licht.value;
console.log(was_lichtSlotRaw);
let was_lichtSlot = resolveCanonical(this.event.request.intent.slots.was_licht);
console.log(was_lichtSlot);
//THIS IS THE PART WHERE I NEED HELP!!
MakeRequest(function(data){
console.log("asddd");
speechOutput = "This is a place holder response for the intent named LichtIntent, which includes dialogs. This intent has 2 slots, which are zimmer, and was_licht. Anything else?";
var speechOutput = data;
this.emit(':ask', speechOutput, speechOutput);
});
console.log("asdww");
//DOWN TO HERE!!
},
'StromIntent': function () {
//delegate to Alexa to collect all the required slot values
let filledSlots = delegateSlotCollection.call(this);
speechOutput = '';
//any intent slot variables are listed here for convenience
let geraet_stromSlotRaw = this.event.request.intent.slots.geraet_strom.value;
console.log(geraet_stromSlotRaw);
let geraet_stromSlot = resolveCanonical(this.event.request.intent.slots.geraet_strom);
console.log(geraet_stromSlot);
let wasSlotRaw = this.event.request.intent.slots.was.value;
console.log(wasSlotRaw);
let wasSlot = resolveCanonical(this.event.request.intent.slots.was);
console.log(wasSlot);
//Your custom intent handling goes here
speechOutput = "This is a place holder response for the intent named StromIntent, which includes dialogs. This intent has 2 slots, which are geraet_strom, and was. Anything else?";
this.emit(':ask', speechOutput, speechOutput);
},
'FrageIntent': function () {
//delegate to Alexa to collect all the required slot values
let filledSlots = delegateSlotCollection.call(this);
speechOutput = '';
//any intent slot variables are listed here for convenience
let geraetSlotRaw = this.event.request.intent.slots.geraet.value;
console.log(geraetSlotRaw);
let geraetSlot = resolveCanonical(this.event.request.intent.slots.geraet);
console.log(geraetSlot);
let was_frageSlotRaw = this.event.request.intent.slots.was_frage.value;
console.log(was_frageSlotRaw);
let was_frageSlot = resolveCanonical(this.event.request.intent.slots.was_frage);
console.log(was_frageSlot);
//Your custom intent handling goes here
speechOutput = "This is a place holder response for the intent named FrageIntent, which includes dialogs. This intent has 2 slots, which are geraet, and was_frage. Anything else?";
this.emit(':ask', speechOutput, speechOutput);
},
'TuerIntent': function () {
//delegate to Alexa to collect all the required slot values
let filledSlots = delegateSlotCollection.call(this);
speechOutput = '';
//any intent slot variables are listed here for convenience
let zeitSlotRaw = this.event.request.intent.slots.zeit.value;
console.log(zeitSlotRaw);
let zeitSlot = resolveCanonical(this.event.request.intent.slots.zeit);
console.log(zeitSlot);
//Your custom intent handling goes here
speechOutput = "This is a place holder response for the intent named TuerIntent, which includes dialogs. This intent has one slot, which is zeit. Anything else?";
this.emit(':ask', speechOutput, speechOutput);
},
'Unhandled': function () {
speechOutput = "The skill didn't quite understand what you wanted. Do you want to try something else?";
this.emit(':ask', speechOutput, speechOutput);
}
};
exports.handler = (event, context) => {
const alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
// To enable string internationalization (i18n) features, set a resources object.
//alexa.resources = languageStrings;
alexa.registerHandlers(handlers);
//alexa.dynamoDBTableName = 'DYNAMODB_TABLE_NAME'; //uncomment this line to save attributes to DB
alexa.execute();
};
// END of Intent Handlers {} ========================================================================================
// 3. Helper Function =================================================================================================
//THESE ARE MY HELPER FUNCTIONS
function url(){
console.log("asd");
return " my server ip";
}
function MakeRequest(callback){
console.log("hallo!");
request.get(url(), function(error, response, body){
console.log("****************************************");
console.log(response);
console.log("****************************************");
console.log(error);
console.log("****************************************");
console.log(body);
console.log("****************************************");
callback("erfolg!");
});
console.log("hffggh");
}
//DOWN TO HERE!!
function resolveCanonical(slot){
//this function looks at the entity resolution part of request and returns the slot value if a synonyms is provided
let canonical;
try{
canonical = slot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
}catch(err){
console.log(err.message);
canonical = slot.value;
};
return canonical;
};
function delegateSlotCollection(){
console.log("in delegateSlotCollection");
console.log("current dialogState: "+this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
console.log("in Beginning");
let updatedIntent= null;
// updatedIntent=this.event.request.intent;
//optionally pre-fill slots: update the intent object with slot values for which
//you have defaults, then return Dialog.Delegate with this updated intent
// in the updatedIntent property
//this.emit(":delegate", updatedIntent); //uncomment this is using ASK SDK 1.0.9 or newer
//this code is necessary if using ASK SDK versions prior to 1.0.9
if(this.isOverridden()) {
return;
}
this.handler.response = buildSpeechletResponse({
sessionAttributes: this.attributes,
directives: getDialogDirectives('Dialog.Delegate', updatedIntent, null),
shouldEndSession: false
});
this.emit(':responseReady', updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
// return a Dialog.Delegate directive with no updatedIntent property.
//this.emit(":delegate"); //uncomment this is using ASK SDK 1.0.9 or newer
//this code necessary is using ASK SDK versions prior to 1.0.9
if(this.isOverridden()) {
return;
}
this.handler.response = buildSpeechletResponse({
sessionAttributes: this.attributes,
directives: getDialogDirectives('Dialog.Delegate', null, null),
shouldEndSession: false
});
this.emit(':responseReady');
} else {
console.log("in completed");
console.log("returning: "+ JSON.stringify(this.event.request.intent));
// Dialog is now complete and all required slots should be filled,
// so call your normal intent handler.
return this.event.request.intent;
}
}
function randomPhrase(array) {
// the argument is an array [] of words or phrases
let i = 0;
i = Math.floor(Math.random() * array.length);
return(array[i]);
}
function isSlotValid(request, slotName){
let slot = request.intent.slots[slotName];
//console.log("request = "+JSON.stringify(request)); //uncomment if you want to see the request
let slotValue;
//if we have a slot, get the text and store it into speechOutput
if (slot && slot.value) {
//we have a value in the slot
slotValue = slot.value.toLowerCase();
return slotValue;
} else {
//we didn't get a value in the slot.
return false;
}
}
//These functions are here to allow dialog directives to work with SDK versions prior to 1.0.9
//will be removed once Lambda templates are updated with the latest SDK
function createSpeechObject(optionsParam) {
if (optionsParam && optionsParam.type === 'SSML') {
return {
type: optionsParam.type,
ssml: optionsParam['speech']
};
} else {
return {
type: optionsParam.type || 'PlainText',
text: optionsParam['speech'] || optionsParam
};
}
}
function buildSpeechletResponse(options) {
let alexaResponse = {
shouldEndSession: options.shouldEndSession
};
if (options.output) {
alexaResponse.outputSpeech = createSpeechObject(options.output);
}
if (options.reprompt) {
alexaResponse.reprompt = {
outputSpeech: createSpeechObject(options.reprompt)
};
}
if (options.directives) {
alexaResponse.directives = options.directives;
}
if (options.cardTitle && options.cardContent) {
alexaResponse.card = {
type: 'Simple',
title: options.cardTitle,
content: options.cardContent
};
if(options.cardImage && (options.cardImage.smallImageUrl || options.cardImage.largeImageUrl)) {
alexaResponse.card.type = 'Standard';
alexaResponse.card['image'] = {};
delete alexaResponse.card.content;
alexaResponse.card.text = options.cardContent;
if(options.cardImage.smallImageUrl) {
alexaResponse.card.image['smallImageUrl'] = options.cardImage.smallImageUrl;
}
if(options.cardImage.largeImageUrl) {
alexaResponse.card.image['largeImageUrl'] = options.cardImage.largeImageUrl;
}
}
} else if (options.cardType === 'LinkAccount') {
alexaResponse.card = {
type: 'LinkAccount'
};
} else if (options.cardType === 'AskForPermissionsConsent') {
alexaResponse.card = {
type: 'AskForPermissionsConsent',
permissions: options.permissions
};
}
let returnResult = {
version: '1.0',
response: alexaResponse
};
if (options.sessionAttributes) {
returnResult.sessionAttributes = options.sessionAttributes;
}
return returnResult;
}
function getDialogDirectives(dialogType, updatedIntent, slotName) {
let directive = {
type: dialogType
};
if (dialogType === 'Dialog.ElicitSlot') {
directive.slotToElicit = slotName;
} else if (dialogType === 'Dialog.ConfirmSlot') {
directive.slotToConfirm = slotName;
}
if (updatedIntent) {
directive.updatedIntent = updatedIntent;
}
return [directive];
}
I use the "request" module for my http-request, I think you all know this module.
When I test my function, it gives me NO runtime error!
but the anonymous functions from the MakeRequest call and the request.get call wont execute, and I don't know why.
For Example the console output:
Hallo!,
Asd (very funny.. it gets the params for the request.get.. the bug has to be between the second param(the anon function itself?) in the call and the start of the anon function),
hffggh,
asdww
-the console.logs in the anon. functions doesn't show.
I maybe undestand why the MakeRequest funct. doesn't run -> because the callback from it never came. But why does the request.get not work?? I pasted the necessary parts (the MakeRequest and the helper functions) in a normal node projekt, and it worked!!? -facepalm.... im nearly crying..
My Goal: I want to receive a response from the server.. - thats all. But it just wont go into the function where I can access the response object(s).
(Scroll down to the helper functions)
Please help me out guys, I could really hit my head against the wall.
Reguards

How to correctly use Jasmine spies to mock transactions

I am trying to mock the behaviour from my transaction module in my account_spec. I am finding it difficult. Once, I make a deposit from my account, I have to mock the behaviour for the transaction but I am finding it very hard. My test is currently returning 'Transaction' is not undefined
EDIT:
I have an account module:
function Account(statement = new Statement, transaction = new Transaction){
this._statement = statement
this._transaction = transaction
}
Account.prototype.deposit = function(amount) {
this._transaction.deposit(amount)
this._statement.storeHistory(amount, this._balance, "Deposit")
}
Account.prototype.withdraw = function(amount) {
this._transaction.withdraw(amount)
this._statement.storeHistory(amount, this._balance, "Withdraw")
}
Account.prototype.balance = function() {
return this._balance
}
module.exports = Account;
I have a transaction module:
function Transaction(){
this._balance = 0
}
Transaction.prototype.balance = function() {
return this.balance
}
Transaction.prototype.deposit = function(amount) {
this._balance += amount
}
Transaction.prototype.withdraw = function(amount) {
this._balance -= amount
}
module.exports = Transaction;
My Statement:
function Statement(){
this._logs = []
}
Statement.prototype.seeStatement = function() {
return this._logs
}
Statement.prototype.storeHistory = function(amount, balance, type) {
this._logs.push({amount: amount, balance: balance, type: type})
}
module.exports = Statement;
My Account Spec:
'use strict';
describe('Account',function(){
var account;
beforeEach(function(){
statement = new Statement
var transactionSpy = jasmine.createSpyObj('transaction',['balance','withdraw','deposit']);
account = new Account(statement, transactionSpy);
});
it('is able for a user to deposit', function(){
account.deposit(40)
// expect(account.balance()).toEqual(40)
});
it('is able for a user to withdraw', function() {
account.deposit(40)
account.withdraw(20)
// expect(account.balance()).toEqual(20)
});
it('is able for a user to check their balance', function() {
account.deposit(20)
expect(transaction.balance()).toEqual(20)
});
});
Actually I see typo here, or maybe code is incomplete:
describe('Account', function() {
var account;
var transaction;
var statement = {}; //or some mock object
beforeEach(function() {
var spy = jasmine.createSpyObj('transaction',['returnBalance','withdraw','deposit']);
account = new Account(transaction, statement)
});
it("is able to deposit money", function() {
account.deposit(40)
expect(transaction.returnBalance).toEqual(40)
});
});
The code written by Alexander is correct except one note. You need to pass spy to Account constructor. The name transaction you pass to jasmine.createSpyObj is just a name that will be used in error messages. you can omit it (in this case it will be unknown)
beforeEach(function() {
var transactionSpy = jasmine.createSpyObj('transaction',['returnBalance','withdraw','deposit']);
account = new Account(transactionSpy, statement)
});

Waiting for multiple async operations in Nightwatch.js

I am attempting to test multiple sites for section headers being in the correct order. Of course everything is asynchronous in Nightwatch, including getting text from an element. The following code leads to the timeout never being called.
client.url(`www.oneofmyrealestatesites.com`);
client.waitForElementPresent("body", 5000);
var _ = require("underscore");
// This is the order I expect things to be in
var expected = ["Homes For Sale", "New Homes", "Apartments & Rentals"];
client.elements("css selector", ".listings .module-title .label", function (data) {
var listings = [];
data.value.forEach(function (element) {
client.elementIdText(element.ELEMENT, function (result) {
listings.push(result.value);
})
})
setTimeout(function () {
// Some of the sites have extra sections
var diff = _.intersection(listings, expected);
client.assert.ok(listings == diff);
}, 5000);
});
It would appear that no matter how much delay I give, listings is ALWAYS empty. If I console.log listings as it's being pushed to, it is getting populated, so that's not the issue. client.pause is always ignored as well.
Is there a way to make sure that listings is populated before asserting the diff?
I'm using async library for such cases https://github.com/caolan/async
Docs: https://github.com/caolan/async/blob/v1.5.2/README.md
var async = require("async");
/*use each, eachSeries or eachLimit - check docs for differences */
async.eachSeries(data.value, function (element, cb) {
client.elementIdText(element.ELEMENT, function (result) {
listings.push(result.value);
// this job is done
cb();
});
}, function() {
// Some of the sites have extra sections
var diff = _.intersection(listings, expected);
client.assert.ok(listings == diff);
});
setTimeout can only be called from .execute or .executeAsync because its actual javascript. The function below was only working until I used .executeAsync
Hope this works for you.
Cheers, Rody
LoopQuestionsLogSymptom: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium, false);
this.api.executeAsync(function() {
let checkQuestion = function() {
// GET THE ELEMENTS
let nextButton = document.querySelectorAll('.next-button');
let answers = document.getElementsByClassName('flex-row');
let blueButton = document.querySelector('.blue-inverse-button');
let doneButton = document.querySelector('#doneButton');
let monitor = document.querySelector('.monitor');
//CHECK THE TYPES OF QUESTIONS AND CLICK THE RIGHT BUTTONS
if (!blueButton) {
answers[0].click();
nextButton[0].click()
} else if(blueButton){
blueButton.click();
}
setTimeout(() => {
if(!doneButton) {
console.log('Answering another question!');
checkQuestion();
}
if(doneButton){
doneButton.click();
}
else if(monitor) {
console.log("Exiting?")
.assert(monitor);
return this;
}
}, 2000);
};
// Initiating the check question function
return checkQuestion();
},[], function(){
console.log('Done?')
});
this.waitForElementVisible('.monitor', constants.timeout.medium);
this.assert.elementPresent('.monitor');
this.assert.urlEquals('https://member-portal.env-dev4.vivantehealth.org/progress');
return this;
},

Categories

Resources