Use case
This is a Cypress E2E test coded with JS and I'm trying to compare pre-production and production sitemap URL contents in order to find the differences. I have two data sets (fixture) one for production and the other for test env.
code snippet
let compareUrlsBetween = (prodSitemapUrls, testEnvSitemapUrls) => {
const pathFirstEnv = new Set(JSON.parse(prodSitemapUrls).map(url => (new URL(url)).pathname))
const pathSecondEnv = new Set(JSON.parse(testEnvSitemapUrls).map(url => (new URL(url)).pathname))
const diff = new Set(pathFirstEnv);
for (const path of pathSecondEnv) {
diff.delete(path);
}
return diff
}
// Check for differences
if (compareUrlsBetween.length > 0) {
let titi = typeof(compareUrlsBetween(prodSitemapUrls, testEnvSitemapUrls))
console.log(titi)
cy.log('text : ' , compareUrlsBetween (prodSitemapUrls, testEnvSitemapUrls)) // Returns null
//console.log(compareUrlsBetween(prodSitemapUrls, testEnvSitemapUrls))
//console.log('Production and test env sitemap urls are not ISO, ' + 'Here are the diffrences : ' , compareUrlsBetween (prodSitemapUrls, testEnvSitemapUrls))
//throw new Error()
} else {
expect(prodSitemapUrls).to.eq(testEnvSitemapUrls)
}
Test goal & the problem
Test goal is to fail the test in cas of diff between these two fixtures (.xml), throw a new error and show the diff as normal log (cy.log()). I've already tried multiple solutions like JSON.stringify(), data type convertion etc. but none of them solved my case.
Log I observe at this moment : logtext : , {}
PS : the other type of logs like console.log() or console.table() are working perfectly fine
Any help is much appreciated.
Solution
Convert the set into an array
cy.log('text : ' , [...compareUrlsBetween (prodSitemapUrls, testEnvSitemapUrls)])
Why?
I'm not 100% sure, but it seems like cy.log uses JSON.stringify underneath which causes sets to be converted to {}
Related
i am trying to make a CLIish server in node.js.
but I need a way to parse a string and run a function from an object.
what I mean is... I don't want to nest a million switch statements just to have the commands I need.
using 2 other StackOverflow answers, I got 1 part done. inputs.
now i just need to figure out how to figure ou where the command stops and the input begins.
example:
inputting do say user:Yimmee msg:"well hello" "something random":yes
I need to separate do say and the inputs.
this is what i started with, but I do not know how to finish it.
function command(command, usable){
//usable is the object holding the commands that can be used.
//here I set commandMain to the part of command that is the command
/*and where commandInput is too. and I'm not forcing you,
but is preferably to be converted to an object.*/
var commandSplit = [];
do{
var match = (/[^ "]+|"([^"]*)"/gim).exec(commandMain);
if(match != null){
commandSplit.push(match[1] ? match[1] : match[0]);
}
}while (match != null);
var reach = `usable`;
commandSplit.forEach((to, nu)=>{
if(nu === commandSplit.length - 1){
reach += `["_${to}"]`;
}else{
reach += `["${to}"]`;
}
});
console.log(reach);
try{
return eval(reach)(commandInputs);
}catch(error){
return false;
}
}
Note I gave up a little, there will be some ridiculous errors.
big fat edit::::::::::::::::::::::L:::::::
idk how in the world process.argv works, and looking in one of the answers, i know how to set it.
but i am using a live websocket for this.
Unless this is an exercise, I'd strongly recommend not to implement your own command and argument parser. Use one of the existing libraries. A quick web search for "node cli library" yields a lot of results, including comparisons.
The libraries range from tiny and simple like minimist, very popular ones like yargs or commander, to heavier ones like oclif.
I'd also recommend checking the Command-line utilities section of Sindre Sorhus' Awesome Node.js list.
What you are doing is passing options and arguments to a program. You can use process.argv to get these.
It's always good to have useful error messages and command line documentation. Hence, if you're distributing to users, a more robust library for this purpose is worth an extra dependency. Widely used is yargs, see their website at https://www.npmjs.com/package/yargs for some examples.
If you want to do it using the basic process.argv, here's a solution:
This is your command in a format most people are used to: node some.js --user Yimmee --msg "well hello" --random
And the implementation
let arguments = process.argv.slice(2); // this removes `node` and the filename from arguments list
console.log(arguments)
switch (arguments[0]) { // check that `say` is the first "command"
case 'say':
let options = process.argv.slice(3); // get the stuff after `say`
let optionsObject = {} // key-value representation
if (options.indexOf("--user") != -1) { // if it exists
optionsObject.user = options[options.indexOf("--user")+1]
}
else {
// you can throw an error here
}
if (options.indexOf("--msg") != -1) { // if it exists
optionsObject.msg = options[options.indexOf("--msg")+1]
}
if (options.indexOf("--random") != -1) { // if it exists
optionsObject.random = true
}
console.log(optionsObject) // you can use optionsObject for your program
break;
default:
console.log("Invalid command");
}
EDIT: If this is happening inside the code as a function call, you can adapt above code:
function test(argsString) {
let arguments = argsString.split(/ (?=(?:(?:[^"]*"){2})*[^"]*$)/); // split the string into an array at the spaces
// ^ regex from https://stackoverflow.com/questions/23582276/
console.log(arguments)
switch (arguments[0]) { // check that `say` is the first "command"
case 'say':
let options = arguments.slice(1); // get the stuff after `say`
let optionsObject = {} // key-value representation
if (options.indexOf("--user") != -1) { // if it exists
optionsObject.user = options[options.indexOf("--user") + 1]
}
else {
// you can throw an error here
}
if (options.indexOf("--msg") != -1) { // if it exists
optionsObject.msg = options[options.indexOf("--msg") + 1]
}
if (options.indexOf("--random") != -1) { // if it exists
optionsObject.random = true
}
console.log(optionsObject) // you can use optionsObject for your program
break;
default:
console.log("Invalid command");
}
}
I cant figure out why this is returning as an error.
item.Question.toUpperCase is not a function
I get this error in my expo application with react but no errors are thrown in the console
Error:
TypeError: item.Question.toUpperCase is not a function.
in item.Question.toUpperCase() item.Question.toUpperCase is undefined
I tried creating new variables as
var Question = item.Question.toUpperCase()
But that didn't seem to work so here is the full code
else if(item.Title == undefined){
const itemData = `${item.Question.toUpperCase()} ${item.answer.toUpperCase()} ${item.keyword.toUpperCase()}`;
const textData = search.toUpperCase();
return itemData.indexOf(textData) > -1;
item is an object in which Question is a string
Thank you
Edit:
So after some logging I found this area to be giving the error:
console.log(item.keyword,item.Title)
console.log(typeof item.Question, item.Question)
const itemData = `${item.Title.toUpperCase()} ${item.Question.toUpperCase()} ${item.answer.toUpperCase()} ${item.keyword.toUpperCase()}`;
const textData = search.toUpperCase();
console.log(typeof itemData,typeof textData)
when logging item.Question and the type I got number and NaN which is odd because from my database it should be pulling the string "this is a strng10"
All the other calls to the database seem to be working fine. They give the correct type for item.Question as String.
So I guess the problem I'm trying to solve is how the string is being converted to a number that is NaN?
This appears to work on my end. Are you certain you're passing the correct datatypes?
let item = {
Question: "test",
Title: undefined,
Answer: "thing",
Keyword: "wow"
}
if (item.Title === undefined) {
const itemData =
`${item.Question.toUpperCase()} ${item.Answer.toUpperCase()} ${item.Keyword.toUpperCase()}`
itemData
}
Console returns "TEST THING WOW"
So after logging all the way back to my call to the database I found an extra + before getting the question, removing that fixed the issue. So sorry for wasting all of your time.
The issuse was inside the object:
Question: + childData.Question
I want to replace a particular line using javascript with new content.
This is the file content,
SERVER=1055#localhost
GROUP_SERVERS=2325#localhost
LINE_IAM_INTERESTED=KTYUIERVW:2800
FILE_PATH="C:\Program Files\somefile\Shared Files\"
In this line, LINE_IAM_INTERESTED=KTYUIERVW:2800 .I want to replace KTYUIERVW with KJHTERDY and 2800 with 78945
I have shown what I tried using fs appendfilesync
fs.appendFileSync('file_name').toString().split('\n').forEach(function(line){
app.console.log("called append");
var sEntry = line.split("=");
if (sEntry.length == 2) {
if (sEntry[0] == "LINE_IAM_INTERESTED") {
app.console.log("found one!!!!");
}
}
});
you can try READ -> REPLACE -> WRITE flow:
fs.writeFileSync('file_name', fs.readFileSync('file_name').replace('KTYUIERVW:2800', 'KJHTERDY:78945'))
appendFile and appendFileSync are used for adding to the end of the file. Although you can do it as a one liner as shown in the other answer, I've kept the structure of your code the same. Here you want to read the data, modify it then re-write it. Using the block of code you have, you can modify it to use readFileSync and writeFileSync.
let newData = fs.readFileSync('file_name', 'utf-8').split('\n').map(line => {
let sEntry = line.split('=')
if (sEntry.length == 2) {
if (sEntry[0] == "LINE_IAM_INTERESTED") {
console.log("found one!!!!");
return sEntry[0] + '=' + 'KJHTERDY:78945'
}
}
return line
}).join('\n')
fs.writeFileSync('file_name', newData)
I've swapped the forEach for map which lets us change the array data by returning the desired value. The new array is then joined back together and written back to the file.
I've been observing some strange behaviour in a stored procedure in Azure Cosmos DB using javascript API (https://learn.microsoft.com/en-us/azure/cosmos-db/programming#javascript-language-integrated-query-api)
Assuming there is a document in the database with the body.id = '---' the procedure below correctly return that document. However, if I comment the line 'return found ' and uncomment the lines with 'if (1==1)' then the stored procedure returns an empty result. I tried changing it to if (found){return found;} else{return false;}' - same empty output. Also, same happens if I write 'found = found && (1==1);' after 'let found = c.body.id != null && c.body.id ==t;'
Is this a Javascript bug or me doing something wrong?
// SAMPLE STORED PROCEDURE
function sample() {
__.filter(c=>{
//return true;
let t = "---";
let found = c.body.id != null && c.body.id ==t;
return found; <---
//if (1==1){
// return found;
//}
}
, {pageSize: -1},
(a, b, c)=>{
__.response.setBody(b);
return;
});
}
I reproduce your issue on my side.
The following JavaScript constructs do not get optimized for Azure
Cosmos DB indices:
Control flow (for example, if, for, while) Function calls
Based on the statement in the doc, if is not recommanded to use in predicateFunction.
You could just filter documents by return expression(e.g. x.isMetadata === true);
i am new to javascript and i currently have an object printed to console when i use the following code:
clickEvents: {
click:function(target) {
console.log(target);
}
}
when i view console i can see the following object:
i am banging my head against a wall to write code that takes the object and prints it to a div using the .append() method. i am extermely new to working with javascript objects, and would appreciate any help trying to tease out an object and/or print the object data.
is events the object name? would i tease out the eventDate using something like events->eventDate?
I've made this over ~15 minutes so it's imperfect; there are types and edge cases surely unaccounted for and the design of the function could be better - not to mention that performing all of this as a giant string and then setting that as HTML is likely bad practice (I'm used to React now, ha!). Regardless, this will iterate over any array or object you pass to it and print it all in a big <ul> recursively.
const targetEl = document.querySelector('.js-target')
if (!targetEl) return
// Small helper functions
const isObj = data => typeof data === 'object' && !Array.isArray(data) && data !== null
const isArr = data => Array.isArray(data)
const dataToHTML = (data, noNode = false) => {
if (isObj(data)) {
const accumulator = Object.entries(data).reduce((acc, set) => acc + `<li><strong>${set[0]}</strong>: ${dataToHTML(set[1], true)}</li>`, '')
return `<ul>${accumulator}</ul>`
}
else if (isArr(data)) {
const accumulator = data.reduce((acc, item) => acc + dataToHTML(item), '')
return `<ul>${accumulator}</ul>`
}
else return noNode ? data : `<li>${data}</li>`
}
const logHTML = dataToHTML(exampleData)
targetEl.innerHTML = logHTML
Assuming that your data/variable is named exampleData.
Any questions pop them in the comments :-)
I'm not sure if you have a div that you want to append to already, but you would do something like this ->
document.getElementById("toBeAppendedTo").innerHTML = target.events[0].eventDate; where toBeAppendedTo is the id of the div you're trying to add this text to.
append() is a jquery function, not a javascript function.
That won't have any formatting and will just be the string value 07-28-2017 in a div.