How do I refactor this Cypress fixtures code? - javascript

I need help refactoring this Cypress code
let stripe;
let bookService;
let images;
let moreDetails;
let checkoutDetails;
let wait;
before(() => {
cy.visit('/');
cy.fixture('stripe').then((data) => {
stripe = data;
});
cy.fixture('bookService').then((data) => {
bookService = data;
});
cy.fixture('images').then((data) => {
images = data;
});
cy.fixture('moreDetails').then((data) => {
moreDetails = data;
});
cy.fixture('wait').then((data) => {
wait = data;
});
});
I have tried
stripe = cy.fixture('stripe')
but it's returning an object { specWindow: ..., chainerId: ...}

It's ok to import fixtures at the to of the spec. You can use require() to refactor the fixtures in the way you suggest,
let stripe = require('./cypress/fixtures/stripe.json')
let bookService = require('./cypress/fixtures/bookService.json')
let images = require('./cypress/fixtures/images.json')
let moreDetails = require('./cypress/fixtures/moreDetails.json')
let wait = require('./cypress/fixtures/wait.json')
before(() => {
cy.visit('/');
});

Related

Testing a void async method in Angular, the spec is not waiting for the async calls to complete, which is making the test always fail

I have a method called loadIssues() in an Angular component called BurndownComponent that is void and inserts values into an array. This method uses some async methods from a service and from the component itself. After running those asyncs it fills in the array.
I want to write test code for loadIssues(), but I do not know how to make the test wait for the array to be filled. Because loadIssues is void I cannot use async await. I also tried using a setTimeout but it ran asynchronously and did not wait for the execution of loadIssues().
Does anyone have an idea on how I could write such a test?
The relevant codes are below:
loadIssues():
loadIssues(): void {
this.selectedMilestone = this.milestone;
this.issues = [];
console.log(this.selectedMilestone.reviewDate);
this.gitlabService.getIssues(this.selectedMilestone?.title).then(issues => {
let allIssues = issues.filter(i => [RequirementLabel.StoryTask, RequirementLabel.Task, RequirementLabel.Story].includes(i.requirement));
this.getIssueEvents(allIssues).then(issues => {
allIssues = issues;
console.log('allIssues ', allIssues.length);
// issues could be moved out of the milestone towards the end of it
// we consider a limit of 3 days before the review meeting date
if (new Date().getTime() >= this.selectedMilestone.reviewDate.getTime() - (3 * MILLISECONDS_PER_DAY)) {
this.getMilestoneRolledIssues().then(rolledIssues => {
const issuesIds = allIssues.map(i => i.id);
console.log(issuesIds);
allIssues = allIssues.concat(...rolledIssues.filter(i => !issuesIds.includes(i.id))); // removes duplicated issues
this.gitlabService.getDiscussions(allIssues).then(discussions => {
allIssues.forEach((issue, index) => issue.discussions = discussions[index]);
this.issues = allIssues;
});
});
}
else {
this.gitlabService.getDiscussions(allIssues).then(discussions => {
allIssues.forEach((issue, index) => issue.discussions = discussions[index]);
this.issues = allIssues;
});
}
});
});
Test attempt (BurndownComponent.spec.ts):
describe('BurndownComponent', () => {
let component: BurndownComponent;
let fixture: ComponentFixture<BurndownComponent>;
const data: object = jsonData;
let httpMock: object;
let stubGitLabService: GitlabService;
beforeEach(async () => {
httpMock = {
'get': (url, headers): Observable<object[]> => {
const endpoint = 'https://git.tecgraf.puc-rio.br/api/v4/';
const discussions = data['discussions-test'][0]['discussions']
.map(d => Discussion.getDiscussion(d));
const urlDiscussions = [
`${endpoint}projects/1710/issues/120/discussions`,
`${endpoint}projects/1710/issues/97/discussions`,
`${endpoint}projects/1210/issues/920/discussions`
];
if(urlDiscussions.includes(url)) {
return new Observable(subscriber => discussions[urlDiscussions.indexOf(url)]);
}
return new Observable(subscriber => null);
}
}
stubGitLabService = new GitlabService(<any> httpMock);
await TestBed.configureTestingModule({
declarations: [ BurndownComponent ],
providers: [
{ provide: GitlabService, useValue: stubGitLabService }
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(BurndownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('loads all issues - loadIssues()', async () => {
const milestoneData = Milestone.getMilestone(data['milestone-test'][0]);
const milestoneEventsData = data['all-milestone-events'][0]['events']
.map(me => MilestoneEvent.getMilestoneEvent(me));
const labelEventsData = data['label-events-burndown-component-test'][0]['events']
.map(le => LabelEvent.getLabelEvent(le));
const issues = data['issues-test-passed-milestone']
.map(i => Issue.getIssue(i));
const discussions = data['discussions-test'][0]['discussions']
.map(d => Discussion.getDiscussion(d));
issues.forEach((issue, index) => {
issue.labelEvents = labelEventsData.map(le => LabelEvent.copy(le));
issue.milestoneEvents = milestoneEventsData.map(me => MilestoneEvent.copy(me));
});
component.milestone = milestoneData;
stubGitLabService['getDiscussions'] = (issues: Issue[]): Promise<Discussion[][]> => {
return new Promise<Discussion[][]>(resolve => resolve(discussions))
};
const spyMilestoneRolledIssues = spyOn(component, 'getMilestoneRolledIssues')
.and
.returnValue(Promise.resolve(issues));
const spyIssueEvents = spyOn(component, 'getIssueEvents')
.and
.returnValue(Promise.resolve(issues));
const getDiscussionsSpy = spyOn(stubGitLabService, 'getDiscussions')
.and
.returnValue(new Promise(
resolve => {
console.log('discussions');
resolve(discussions)
}
));
await component.loadIssues();
expect(component.issues.length).toBe(3);
expect(spyMilestoneRolledIssues).toHaveBeenCalled();
expect(getDiscussionsSpy).toHaveBeenCalled();
});
You are awaiting loadIssues but it is not an async function. You can address this by returning the Promise returned by then which will complete at an appropriate time.
loadIssues() { // remove explicit void return type
this.selectedMilestone = this.milestone;
this.issues = [];
console.log(this.selectedMilestone.reviewDate);
// return the promise
return this.gitlabService.getIssues(this.selectedMilestone?.title).then(issues => {
...

Promise.all() stops working before finishing

I've a very simple script that gets me some info by mapping over an array of around 150 records and the code seems to work fine with smaller number of records but everytime I run it with this 150 records it just stops working and doesn't continue and I think it might be a Promise.all problem.
any idea?
code:
const request = require('request');
const axios = require('axios');
const cheerio = require('cheerio');
const fs = require('fs').promises;
let champions = [];
const getChampData = async hrefs => {
const requests = hrefs.map(async ({ href }) => {
try {
const html = await axios.get(href);
const $ = cheerio.load(html.data);
const champName = $('.style__Title-sc-14gxj1e-3 span').text();
let skins = [];
$('.style__CarouselItemText-sc-1tlyqoa-16').each((_, el) => {
const skinName = $(el).text();
skins.push(skinName);
});
const champion = {
champName,
skins
};
console.log(champion);
return champion;
} catch (err) {
console.error(err);
}
});
const results = await Promise.all(requests);
await fs.writeFile('json/champions-skins.json', JSON.stringify(results));
return results;
};
edit #1:
I used a package called p-map with it and now everything works just fine!
const axios = require('axios');
const pMap = require('p-map');
const cheerio = require('cheerio');
const fs = require('fs').promises;
const getChampData = async hrefs => {
// const champions = JSON.parse(await fs.readFile('json/champions.json'));
try {
let champsList = await pMap(hrefs, async ({ href }) => {
const { data } = await axios(href);
const $ = cheerio.load(data);
const champName = $('.style__Title-sc-14gxj1e-3 span').text();
let skins = [];
$('.style__CarouselItemText-sc-1tlyqoa-16').each((_, el) => {
const skinName = $(el).text();
skins.push(skinName);
});
const champion = {
champName,
skins
};
console.log(champion);
return champion;
});
await fs.writeFile(
'champions-with-skins-list.json',
JSON.stringify(champsList)
);
} catch (err) {
console.error(err.message);
}
};
On Error return is missing. Look like issue with some url to fetch.
const getChampData = async hrefs => {
const requests = hrefs.map(async ({ href }) => {
try {
const html = await axios.get(href);
// rest of the code
} catch (err) {
console.error(err);
return []
}
});
const results = await Promise.all(requests);
await fs.writeFile("json/champions-skins.json", JSON.stringify(results));
return results;
};

convert multiple objects into an array of objects

I have created a function where i have passed an object as an argument and there are multiple objects which is passed on one by one and the output is an object but it comes as an individual object which is fine because I have written the code in that way now i wanted to store the objects into an array so it becomes an array of objects.and store for all objects
here is the tried code which gives single object example
const {db} = require('./constant')
const momentTz = require("moment-timezone");
const { getAuth } = require("./constant");
const officeStatus = async officeActivity => {
let output = {};
const maileventQuerySnapshot = await db
.collection("MailEvents")
.where("office", "==", officeActivity.office)
.where("event", "==", "delivered")
.limit(1).get();
output["office"] = officeActivity.office;
output["First Contact"] = officeActivity.attachment["First Contact"].value;
output["Second Contact"] = officeActivity.attachment["Second Contact"].value;
output["Office Creation Date"] = momentTz
.tz(officeActivity.timestamp, officeActivity.attachment.Timezone.value)
.format("DD MMM YYYY");
output["Reports Sent"] = maileventQuerySnapshot.docs.length ? true:false
const officeSubcollectionSnapshot = await db
.collection(`Offices/${officeActivity.officeId}/Addendum`)
.where("date","==",parseInt( momentTz(new Date()).subtract(1, "days").format("DD")))
.where('month', '==', parseInt( momentTz(new Date()).subtract(1, 'days').format("MM"))-1)
.where('year', '==',parseInt( momentTz(new Date()).subtract(1, "days").format("YYYY")))
.orderBy("user").orderBy('timestamp')
.get();
output['Number of unique Checkin Yesterday'] =
officeSubcollectionSnapshot.docs.length;
const activitiesRefSnapshot = await db
.collection("Activities")
.where("office", "==", officeActivity.office)
.where("template", "==", "subscription")
.where("attachment.Template.value", "==", "check-in")
.get();
const phoneNumberArray = [];
activitiesRefSnapshot.forEach(doc => {
phoneNumberArray.push(doc.data().attachment["Phone Number"].value);
});
const userRecord = await Promise.all(phoneNumberArray.map(getAuth));
output["Number of checkin Subscription Auth"] = userRecord.filter(
doc => doc !== undefined
).length;
output["Number of Checkin Subscription No Auth"] = userRecord.filter(
doc => doc === undefined
).length;
return { output};
};
module.exports = { officeStatus };
and the other file where i have queried the office and passed objects as an argument
const {admin,db} = require('./constant');
const { officeStatus } = require("./officeStatus");
let execute = async () => {
try {
let office = await db.collection("Offices").where("status", "==", "PENDING").get();
office.forEach(doc => {
officeStatus(doc.data())
.then(e => {
console.log(JSON.stringify(e.output));
})
.catch(error => {
console.log(error);
});
});
return;
} catch (error) {
console.log(error);
}
return;
};
execute();
admin.apps[0].delete();
I have get output in this way
{}
{}
{}....
and I wanted the output in this way
[{},{},{}]
The promise inside forEach is not correct. It wouldn't give you expected results. You shouldn't use that as it is not supported. You should consider using for..of or Promise.all. In your case I would suggest to use Promise.all as you need result in array.
Promise.all(office.docs.map(doc => {
return officeStatus(doc.data())
.then(e => {
return e.output;
})
.catch(error => {
console.log(error);
});
}))
.then(res => console.log(res));
Try doing that :
// and the other file where i have queried the office and passed objects as an argument
const {admin,db} = require('./constant');
const { officeStatus } = require("./officeStatus");
let execute = async () => {
try {
let office = await db.collection("Offices").where("status", "==", "PENDING").get();
let arr = new Array();
office.forEach(doc => {
officeStatus(doc.data())
.then(e => {
arr.push(e)
})
.catch(error => {
console.log(error);
});
});
console.log(arr)
return;
} catch (error) {
console.log(error);
}
return;
};
execute();
admin.apps[0].delete();
I just created an array where we push e when we did officeStatus. Then, at the end of the code, we log arr ; the declared array.
const {admin,db} = require('./constant');
const { officeStatus } = require("./officeStatus");
let execute = async () => {
let office = await db.collection("Offices").where("status", "==", "PENDING").get()
const arrayofObject = await Promise.all(office.docs.map(doc => {
return officeStatus(doc.data())
.then(e => {
// console.log(JSON.stringify(e.output));
return e.output;
})
.catch(error => {
console.log(error);
});
}))
console.log(arrayofObject)
return;
};
execute();
admin.apps[0].delete();

React.js, print something after all getDownloadURL functions completes

i am trying to get all the URL from Firebase.I need to print something after all the getDownloadURL completes. I have tried to add .then(function()){}after the storageRef.listAll(), however it does not work. Can someone help me? Thank you so much!
getAllURL = product => {
// Get all the images from the firebase
var storage = firebase.storage();
var that = this;
const storageRef = storage.ref(`image/${product}`)
storageRef.listAll().then(function(result) {
result.items.forEach(function(imageRef) {
imageRef.getDownloadURL().then(function(url) {
let a = 'a'
that.state.temp3.push(a)
console.log("789")
}).catch(function(error) {});
console.log("123")
})
console.log("456")
})
}
I declared a variable called promises and assigned all of the promises to it. After that, I used Promise.all to wait for all of the promises to resolve.
getAllURL = product => {
// Get all the images from the firebase
var storage = firebase.storage();
var that = this;
const storageRef = storage.ref(`image/${product}`);
storageRef.listAll().then(function(result) {
const promises = result.items.map(function(imageRef) {
return imageRef
.getDownloadURL()
.then(function(url) {
let a = "a";
that.state.temp3.push(a);
console.log("789");
})
.catch(function(error) {});
});
Promise.all(promises)
.then((results) => console.log('Promises resolved', results))
});
};

proper usage of async and await in JS?

import Firebase from './Firebase'
import videoManager from './videoManage';
async function getAllDatabaseLocations() {
await let ref = Firebase.database().ref("locations")
var user_locations = [];
ref.on("value", function (snapshot) {
snapshot.forEach(function (datas) {
const data = datas.val();
vid_manage = new videoManager(data.videourl);
vid_ref = vid_manage.getLocationVideoUrl();
vid_ref.getDownloadURL().then(function (url) {
videourl = url;
}).catch(function (error) {
});
let lokation = data.lokation;
let videourl = data.videourl;
let openinghours = data.openinghours;
let links = data.links;
let Lokationer = {
lokation: lokation,
videoUrl: videourl,
openingshours: openinghours,
links: links
};
console.log("Location objects are: ", Lokationer);
user_locations.push(Lokationer);
// location_obj.push(Lokationer);
});
});
return user_locations;
}
export default getAllDatabaseLocations;
This method always returns an empty array, even if the console inside the loop prints as i expected? How to use async and await property so as to return an array with all Lokationer objects inside on it.
You'll need to return a new promise because of the asynchronous ref.on("value") callback.
function getAllDatabaseLocations() {
return new Promise(resolve => {
ref.on("value", function (snapshot) {
...
// when done filling the array
resolve(user_locations);
});
});
}
const userLocations = await getAllDatabaseLocations(); // user_locations

Categories