Can anyone please guide me on how can I send values using the labels of the field. I'm aware of the fact that one should not send values using labels as the labels changes but in my case it's not that case, i.e it's not gonna change.
I'm attaching the HTML Code screenshots of that label and the webpage screenshot as well. WebPage Screenshot and the HTML Code Screenshot.
The only code structure I can show is in this image.Code Structure
The codes which I have tried are as below,
The From Date and To Date is one set of code I tried. So, like first From and To Date variable is one way of implementation of code, second set is some other way of implementing the code and so on.
async selectDates(FromDate:string,ToDate:string){
console.log("$$$ From and To Date in selectDates function From: "+FromDate+" To: "+ToDate);
// var fromDate = "From Date";
// await browser.element(by.xpath("//label[. = '" + fromDate + "']/following-sibling::input"));
// await fromInput.sendKeys(FromDate);
// var toDate = "To Date";
// await browser.element(by.xpath("//label[. = '" + toDate + "']/following-sibling::input"));
// await toInput.sendKeys(ToDate);
// var TmpLabelName = "From Date";
// var TmpInput = await element(by.xpath("//label[contains(text(),'" + TmpLabelName + "')]/following-sibling::input"));
// await TmpInput.sendKeys(FromDate);
// var TmpLabelName2 = "To Date";
// var TmpInput2 = await element(by.xpath("//label[contains(text(),'" + TmpLabelName2 + "')]/following-sibling::input"));
// await TmpInput2.sendKeys(ToDate);
// var TmpLabelName = "From Date";
// var TmpInput = await element(by.xpath("//label[.,'" + TmpLabelName + "']/following-sibling::input"));
// await TmpInput.sendKeys(FromDate);
// var TmpLabelName2 = "To Date";
// var TmpInput2 = await element(by.xpath("//label[.,'" + TmpLabelName2 + "']/following-sibling::input"));
// await TmpInput2.sendKeys(ToDate);
// let FlabelName = "From Date";
// var Finput = await element(by.xpath("//label[. = '" + FlabelName + "']/following-sibling::input")).sendKeys(FromDate);
// let TlabelName = "To Date";
// var Tinput = await element(by.xpath("//label[. = '" + TlabelName + "']/following-sibling::input")).sendKeys(ToDate);
}
I have searched for many articles and other answers but neither of them gave the desired answer. can anyone please help me with this, It would be really helpful!!
Edits:
The Code structure (Sorry for identation issues)
function ele(label: string){
return element.all(by.css('td > label.fieldlabel')).filter((ele)=>{
return ele.getText().then((text: string) => {
return text === label;
});
}).get(0);
}
export class Reports extends ReportObjects {
async selectDates(FromDate:string,ToDate:string){
await browser.executeScript("arguments[0].value='" + FromDate + "';", ele('From Date'));
await browser.executeScript("arguments[0].value='" + ToDate + "';", ele('To Date'));
}
async generateReport(testDataRow:number){
let fromDate = excel.getColumnValue('FromDate',testDataRow).toString();
let toDate = excel.getColumnValue('ToDate',testDataRow).toString();
await this.selectDates(fromDate,toDate);
}
}
The Excel Screenshot From/To Date
PS: I cannot use ID because that is dynamic, it's changing for different scenarios
Even we not recommend to use XPATH, but in your case we need it.
cost ele = element(by.xpath('//label[text()="From Date"]/../../input'))
await ele.sendKeys(FromDate)
// if sendKeys() can't work, try as below
await browser.executeScript("arguments[0].value=arguments[1]", ele, FromDate);
Try below solution with java script executer
const FromDate= //your from date
function ele(label: string){
return element.all(by.css('td > label.feildlabel').filter((ele)=>{
return ele.getText().then((text: string) => {
return text === label;
});
}).get(0);
}
await browser.executeScript("arguments[0].value='" + FromDate + "';", ele('From Date'));
Refer https://www.protractortest.org/#/api?view=webdriver.WebDriver.prototype.executeScript
Related
I have created a Firebase function for my shopping app, where the function is triggered when an order is created and then it checks the quantity of each product in the order and update product quantity in the database. I need this to keep track of how many items is left of each product.
However, in case one of the products in the order has more quantity than what left (the quantity of the product in the database), I need a way for the function to return an error I can catch from my react native app so I can inform the user that the quantity he asked for is not available. I also need the function to stop the creating of the order doc in the database.
Here's the firebase function I wrote:
exports.countOrderProductChange = functions.firestore.document("/orders/{id}")
.onCreate((change, context) => {
const data = change.data();
const itemsList = data["itemsList"];
let error = "";
const newProductsSizes = {};
for (const item of itemsList) {
db.collection("products").doc(item.product.id).get().then((doc) => {
const product = doc.data();
let sizes = [];
if (item.product.id in newProductsSizes) {
sizes = newProductsSizes[item.product.id];
} else {
sizes = product.sizes;
}
const remaingSize = sizes.find((size) => (size.name == item.size));
const remaingSizeQty = remaingSize.qty;
if (remaingSizeQty < item.qty) {
if (remaingSizeQty == 0) {
error = "Sorry there's no more (" + item.size +
") size of the product: " + item.product.name;
} else {
error = "Sorry there's only "+ remaingSizeQty +
" of (" + item.size +
") size of the product: " + item.product.name;
}
functions.logger.log(error);
return error;
} else {
const sizeIndex = sizes.findIndex((obj) => (obj.name == item.size));
const newQty = remaingSizeQty - item.qty;
const newSizes = sizes;
newSizes[sizeIndex].qty = newQty;
newProductsSizes[item.product.id] = newSizes;
}
});
}
for (const productId in Object.keys(newProductsSizes)) {
if (Object.prototype.isPrototypeOf.call(newProductsSizes, productId)) {
db.collection("products").doc(productId).update({
sizes: newProductsSizes[productId],
});
}
}
});
As Doug Stevenson commented, your application is not able to directly run the onCreate function, as this type of function is a background function. As shown in the third point, these functions are called from the backend:
When the event provider generates an event that matches the function's conditions, the code is invoked.
You can check this related post for more reference, which also mentions listening to a document used to hold the status of the operation.
Another alternative would be to use a callable function. These functions allow you to handle errors on the client and are called directly within your app.
https://github.com/exceljs/exceljs
There is a problem in creating applications through electron and Exceljs.
I want to read the Excel file and show it to user in the html table. The problem is that it deals with xlsx files with a very large number of rows.
So I want to show the progress to the user as follows.
ex) 5/10000. (Read row / Total number of rows)
Also, if possible, I would like to return the data in the form of json or html whenever I read it. (If this is impossible, I'd like to indicate that it's loading until it's finished)
const filePath = "/Users/caglia/Documents/test.xlsx"
const ExcelJS = require('exceljs')
async function loadExcelFile(filePath) {
let start = new Date();
console.log('start :', Date.now())
const sheetData = []
const workbook = new ExcelJS.Workbook()
await workbook.xlsx.readFile(filePath)
const worksheet = workbook.worksheets[0] // first sheet
const options = {
includeEmpty: true
}
await worksheet.eachRow(options, (row, rowNum) => {
sheetData[rowNum] = []
//console.log('rowNum', rowNum)
row.eachCell(options, (cell, cellNum) => {
sheetData[rowNum][cellNum] = {
value: cell.value
}
})
})
let end = new Date();
console.log('finish ', Date.now(), 'timediff', end - start);
}
loadExcelFile(filePath)
I've created a bot which goes in Google Spreadsheet getting some datas before sending them by DM to 50 guild members into Discord.
However, due to high requests of datas, I've got an error message saying that I've exceeded the quota for group 'ReadGroup' and limit 'USER-100s'.
To avoid getting this error, I've created a buffer function however it still doesn't work, does anyone know how to avoid getting this limit error?
Here is the main code which is launched when I type a specific commande in Discord :
const client1 = new google.auth.JWT(keys.client_email, null, keys.private_key, ['https://www.googleapis.com/auth/spreadsheets']);
const client2 = new discord.Client();
.
.
.
let valeur1 = await liste(client1);
await sleep(100000);
console.log("End of first buffering time (100s)");
for (i = 0; i < valeur1.length; i++){
if (valeur1[i] != undefined){
try{
let valeur2 = await envoi(client1, valeur1[i]);
const user = client2.users.get(String(valeur1[i])) || await client2.fetchUser(String(valeur1[i]));
console.log("Ready to send to : " + user.id);
await user.send("The character you need to improve is : " + valeur2[0] + "\n 1. " + valeur2[1] + " = " + valeur2[2] + " >>> " + valeur2[3] + "\n 2. " + valeur2[4] + " = " + valeur2[5] + " >>> " + valeur2[6] + "\n 3. " + valeur2[7] + " = " + valeur2[8] + " >>> " + valeur2[9]);
console.log("Message sent for : " + user.id);
}
catch(err){
console.error(err);
console.log("Error detected for : " + valeur1[i]);
break;
}
}
}
Here is the first function called ("liste") which return the list of the 50 members id :
async function liste(client){
const gsapi = google.sheets({version:'v4',auth: client});
let data1 = new Array();
for (i = 0; i < 50; i++) {
const opt1 = {spreadsheetId: 'XXXXXX', range: 'Serveur!C' + (3+i)};
let data2 = await gsapi.spreadsheets.values.get(opt1);
data1.push(data2.data.values);
}
return data1;
}
And here is the second function called ("envoi") which is supposed to send the DM to the 50 different members of the guild :
async function envoi(client, id){
const gsapi = google.sheets({version:'v4',auth: client});
for (i = 0; i < 50; i++){
const opt1 = {spreadsheetId: 'XXXXXX', range: 'Discord!A' + (3+i)};
let data1 = await gsapi.spreadsheets.values.get(opt1);
if (parseInt(id) === parseInt(data1.data.values)){
const opt2 = {spreadsheetId: 'XXXXXX', range: 'Discord!C' + (3+i)};
let data2 = await gsapi.spreadsheets.values.get(opt2);
const opt3 = {spreadsheetId: 'XXXXXX', range: 'Discord!D' + (3+i)};
let data3 = await gsapi.spreadsheets.values.get(opt3);
.
.
.
const opt10 = {spreadsheetId: 'XXXXXX', range: 'Discord!K' + (3+i)};
let data10 = await gsapi.spreadsheets.values.get(opt10);
const opt11 = {spreadsheetId: 'XXXXXX', range: 'Discord!L' + (3+i)};
let data11 = await gsapi.spreadsheets.values.get(opt11);
var stats = [data2.data.values,data3.data.values,data4.data.values,data5.data.values,data6.data.values,data7.data.values,data8.data.values,data9.data.values,data10.data.values,data11.data.values];
await sleep(10000);
console.log("Extraction done for " + parseInt(id));
return stats;
}
}
console.log("Member not found");
return "erreur";
}
As a result, I would like to get all the members to get their DM. However after the 18th member, an error appear, even though I put some buffering time.
In the console.log, I get :
End of first buffering time (100s)
Extraction done for 408575708424699900
Ready to send to : 408575708424699925
Message sent for : 408575708424699925
.
.
.
Extraction done for 438420776652374000
Ready to send to : 438420776652374036
Message sent for : 438420776652374036
Error: Quota exceeded for quota group 'ReadGroup' and limit 'USER-100s' of service 'sheets.googleapis.com'
.
.
.
Error detected for : 493854774446391296
This is even more strange that the error concerns a member who already have received his DM (he is one the the first 10 members in the list)
Thanks to Tanaike, I updated my code using spreadsheets.values.batchGet() method. In that way instead of extraction values by values, I extracted a batch of values.
And then I made my formula. Now I don't have any issues anymore and even better, my script is way much quicker :)
Below is my code of cloud functions I am trying to copy the data from users node to challenge node
exports.copyChallengeDate = functions.database.ref(`Users/{pushId}/DateChallengeAccept`).onCreate((snapshot, context)=>{
var DateChallengeAccept = snapshot.val();
console.log('Challenge', context.params.pushId, DateChallengeAccept);
var challenge = DateChallengeAccept;
return admin.database().ref('Challenge/' + context.params.pushId).child('DateChallengeAccept').set(challenge);
});
But the thing is when I am trying to copy the date from user table to challenge node it's only occur in QS5h99YxS0ZGpT42fpUFvzOdpTi1
D uid same as of Users node. I want to copy it in both uid's(QS5h99YxS0ZGpT42fpUFvzOdpTi1, 7aH9Ag8414VzM0n7P6ur4LvcepI2)
D present in challenge node. I was stuck in it from last two days please help me out
Update following you remark that DateChallengeAccept is not initialized when you create the record. You should use another method, like onUpdate() (or onWrite()) and not onCreate(), as you do in your question. Do as follows:
exports.copyChallengeDate = functions.database.ref(`Users/{pushId}`).onUpdate((change, context) =>
const DateChallengeAccept = change.after.val().DateChallengeAccept;
if ( DateChallengeAccept === undefined) {
return false;
}
const referredBy = change.after.val().referredBy;
console.log('Challenge', context.params.pushId, DateChallengeAccept);
const dateChallengeAcceptObj = {
"DateChallengeAccept": DateChallengeAccept
};
let updates = {};
updates['Challenge/' + context.params.pushId + '/DateChallengeAccept'] = dateChallengeAcceptObj;
updates['Challenge/' + referredBy + '/DateChallengeAccept'] = dateChallengeAcceptObj;
return admin.database().ref().update(updates);
});
You need to get the referredId value in your Function, because it is this data item that holds the ID of the other user (i.e. 7aH9Ag8414VzM0n7P6ur4LvcepI2). So you have to trigger the event on the parent node, not at the DateChallengeAccept node.
Then you have to use the update() method to write simultaneously to two nodes, see the doc here: https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields
So you should do as follows:
exports.copyChallengeDate = functions.database.ref(`Users/{pushId}`).onCreate((snapshot, context)=>{
const DateChallengeAccept = snapshot.val().DateChallengeAccept;
if ( DateChallengeAccept === undefined) {
return false;
}
const referredBy = snapshot.val().referredBy;
console.log('Challenge', context.params.pushId, DateChallengeAccept);
const dateChallengeAcceptObj = {
"DateChallengeAccept": DateChallengeAccept
};
let updates = {};
updates['Challenge/' + context.params.pushId + '/DateChallengeAccept'] = dateChallengeAcceptObj;
updates['Challenge/' + referredBy + '/DateChallengeAccept'] = dateChallengeAcceptObj;
return admin.database().ref().update(updates);
});
Below is virtually all of the code for a node.js app that lets you get playlists for artists if you run the command simply followed by an artists name
simplay the Beatles
From the output in the terminal, I know that the code in the ._flush method (added to the prototype of UrlsForNamesTransform) is getting run but it's never explicitly called. UrlsForNamesTransform extends the Transform stream in node.js, which I mention because I've seen it in other code before where a function is running without explicitly getting called (at least that I can see). Is it something about Transform or what is happening to make the code in ._flush run?
This is the github repo for the code https://github.com/thlorenz/simplay
'use strict';
var urlschema = 'http://ws.audioscrobbler.com/2.0/?method=artist.getsimilar&artist={{artist}}&api_key={{apikey}}&format=json';
var hyperquest = require('hyperquest')
, table = require('text-table')
, colors = require('ansicolors')
, styles = require('ansistyles')
var stream = require('stream');
var util = require('util');
var Transform = stream.Transform;
util.inherits(UrlsForNamesTransform, Transform);
function UrlsForNamesTransform (opts) {
if (!(this instanceof UrlsForNamesTransform)) return new UrlsForNamesTransform(opts);
opts = opts || {};
Transform.call(this, opts);
this._writableState.decodeStrings = false;
this.artist = opts.artist;
this.json = '';
}
UrlsForNamesTransform.prototype._transform = function (chunk, encoding, cb) {
this.json += chunk.toString();
cb();
};
UrlsForNamesTransform.prototype._flush = function (cb) {
var records = [];
try {
var o = JSON.parse(this.json);
var artists = o.similarartists.artist;
if (!Array.isArray(artists)) {
this.push('Sorry, no records for "' + this.artist + '" where found, please correct your spelling and/or try another artist.');
return cb();
}
artists.forEach(function (node) {
var youtubeurl = 'http://www.youtube.com/results?search_query={{artist}},playlist'.replace('{{artist}}', node.name);
var rdiourl = 'http://www.rdio.com/search/{{artist}}/artists/'.replace('{{artist}}', node.name);
var lastfmurl = 'http://www.last.fm/music/{{artist}}'.replace('{{artist}}', node.name);
var lastfmRadioUrl = 'http://www.last.fm/listen/artist/{{artist}}'.replace('{{artist}}', node.name);
var urls = [
''
, colors.white(' youtube: ') + styles.underline(colors.brightBlue(encodeURI(youtubeurl)))
, colors.blue (' rdio: ') + styles.underline(colors.brightBlue(encodeURI(rdiourl)))
, colors.brightRed (' last.fm: ') + styles.underline(colors.brightBlue(encodeURI(lastfmurl)))
, colors.red (' last.fm radio: ') + styles.underline(colors.brightBlue(encodeURI(lastfmRadioUrl)))
, ''
, ''].join('\n');
records.push([ '\n' + colors.brightYellow(node.name), colors.cyan(node.match), urls ]);
})
this.push(table(records.reverse()));
cb();
} catch (err) {
cb(err);
}
}
var go = module.exports =
/**
* Retrieves similar artists for the given artist from last.fm using the apikey.
* Then it converts the information to display youtube.com, last.fm, rdio playlist/artist urls for each artist.
*
* #name simplay
* #function
* #param {String} artist the artist to find similar artists for
* #param {String} apikey the api key to be used with last.fm
* #return {ReadableStream} that will push the url information
*/
function simplay(artist, apikey) {
if (!artist) throw new Error('Please provid the artist that you like to get similar artist links for');
if (!apikey) throw new Error('Please set LASTFM_API env variable to your API key: http://www.last.fm/api/account/create');
var url = urlschema
.replace('{{artist}}', artist)
.replace('{{apikey}}', apikey);
return hyperquest(url)
.on('error', console.error)
.pipe(new UrlsForNamesTransform({ artist: artist }))
.on('error', console.error)
};
The important line is this one:
util.inherits(UrlsForNamesTransform, Transform);
What this means is that UrlsForNamesTransform is a subclass of Transform. There is very good documentation on subclassing Transform, which can be found on the node.js api site.
Essentially, a subclass of Transform must implement _transform and can implement _flush, but is expected to never call either of those functions. Methods in Transform will call them based on events on the incoming stream.