I'm using Cypress with Mocha Junit to do e2e testing for React in Chrome. The default behavior is for it to have one single output for results each time it runs my tests, and it overwrites the file every time. I'd like to have it keep these files in like a log.
The config is in a JSON file that looks like this:
}
"projectId": "XXXXXX",
"reporter": "junit",
"reporterOptions": {
"mochaFile": "./cypress/results/my-test-output.xml",
"toConsole": true
}
}
I'd like to do something like
var date = new Date();
"mochaFile": "./cypress/results/my-test-output${date}.xml",
Obviously this isn't valid JSON. How can I rig this up to make it generate something unique each time?
From the docs,
Results XML filename can contain [hash]
Also, if you check the junit reporter source, you can see how is doing it:
...
this.writeXmlToDisk(xml, this._options.mochaFile);
...
MochaJUnitReporter.prototype.writeXmlToDisk = function(xml, filePath){
if (filePath) {
if (filePath.indexOf('[hash]') !== -1) {
filePath = filePath.replace('[hash]', md5(xml));
} ...
So, you could just have:
"mochaFile": "./cypress/results/my-test-output[hash].xml"
Nothing to do here. As you can see all you need to do is wrap your JSON in backticks. Except that I'd suggest you use Date.now() instead of new Date().
let date = Date.now();
let json = `{
"projectId": "XXXXXX",
"reporter": "junit",
"reporterOptions": {
"mochaFile": "./cypress/results/my-test-output-${date}.xml",
"toConsole": true
}
}`
let parsedJson = JSON.parse(json)
console.log(parsedJson.reporterOptions.mochaFile)
Compared to a hash this even has the advantage of historization.
Related
When using chrome's chrome.i18n API, the chrome.i18n.getMessage method retrieves only one message at a time.
const buttonText = chrome.i18n.getMessage('buttonText');
What I want is to update the popup UI when the popup opens with the localized contents of message.json file. Doing so requires me to know the message names used. Is there a method/technique similar to getMessage for retrieving all the contents of the message.json file at once?
Right now, I can only keep all the message names somewhere and retrieve each localized message individually like:
const messages = ["buttonText", "buttonTitle"];
messages.forEach((message) => {
const messageText = chrome.i18n.getMessage(message);
// Update UI
});
To get the "messages.json" file you would have to use "fetch" and access the URL of the file with the "chrome.runtime" API and the "getURL" method.
fetch(chrome.runtime.getURL(`_locales/en/messages.json`))
The only thing is that in this way you have to specify the language yourself and verify it, that's how I did it:
let lang = 'en';
if (["es"].includes(chrome.i18n.getUILanguage().split('-')[0])) {
lang = chrome.i18n.getUILanguage().split('-')[0];
}
fetch(chrome.runtime.getURL(`_locales/${lang}/popup_content.json`))
Detecting the language of the browser and verifying if it exists in my extension apart from the default language, in this case English, if it does not exist in the array it is not modified and remains by default.
My "_locales" directory:
_locales -> en -> messages.json
_locales -> es -> messages.json
Finally, to iterate the result of "messages.json", as it is an object, I found these ways:
for (let key in obj) {
console.log(obj[key]);
}
Object.keys(obj).forEach(key => {
console.log(obj[key]);
});
Both ways iterate and return the keys of the given object. more info: Working with objects.
Final code: this will return each value of the "message" key of each object within the main object of the json.
let lang = 'en';
if (["es"].includes(chrome.i18n.getUILanguage().split('-')[0])) {
lang = chrome.i18n.getUILanguage().split('-')[0];
}
fetch(chrome.runtime.getURL(`_locales/${lang}/messages.json`)).then(res=> {
res.json().then(json=> {
Object.keys(json).forEach(key => {
console.log(json[key].message);
});
});
});
The file "_locales -> en -> messages.json":
{
"appName": {
"message": "Name of my extension"
},
"appDesc": {
"message": "Awesome extension."
}
}
The result in the console will be something like:
Name of my extension
Awesome extension.
Sorry if the wording is not correct or I am very repetitive, I had to use the translator.
Here is my situation:
I have a simple Schema that has an object called commands which I originally set to {}.
commands:{}
When I went to add a document to the database, I looped through a file of commands and added them to the object by doing command["command"] = "blah blah";. The way I did that is as follows (The code I work is quite old):
Guild.findOne({guildId:serverId}).then(x=>{
x.commands = {};
for(let command of Object.values(commandInfo)){
if(!command.name) continue;
const getSubs = ()=>{
const subArray = {};
if(!command.subCommands) return;
for(let subs of Object.values(command.subCommands)){
subArray[subs.name] = {
access:subs.access,
disabled:subs.disabled
}
}
x.commands[command.name].subCommands = subArray;
}
x.commands[command.name] = {
access:command.access,
bounded:command.bounded,
disabled:command.disabled,
}
getSubs();
}
console.log("Success!");
x.save();
});
The commands contain the following (I'll use two commands for my example):
work:{
access:"All",
bounded:"A Channel",
disabled:false
},
profile:{
access:"All",
bounded:"Another Channel",
disabled:false,
subCommands:{
bio:{
access:"All",
disabled:true
}
register:{
access:"All",
disabled:false
}
}
Fastforwarding to now, I made a config file that is supposed to edit these commands. The code I wrote works perfectly fine; however, Mongoose is unable to save any of the command's changes. Everything else in my Schema works in the config file except anything related to commands.
I know what the problem. Mongoose can't find the command in the Schema and gets confused somehow. And I know I could fix it by adding all of the commands and their properties to the Schema. The only problem with that is it's tedious and is not a clean solution to me adding any new commands. Plus, I have all of the information for the commands in a separate file, so I don't want to rewrite what I already wrote.
My question is: is there a workaround to my problem? I tried setting commands to Schema.Types.Mixed, but that didn't fix it. I also searched all around for something similar but could not find anything.
Here is the full Schema as requested:
const {Schema, model} = require("mongoose");
const settings = require("../utils/settings");
const guildSchema = Schema({
guildId:String,
symbols:{
prefix:{type:String, default:";"},
currency:{type:String, default:"$"}
},
channels:{
casinoChannels:Array,
fineChannels:Array
},
commands:Schema.Types.Mixed,
hierarchy:[{
name:String,
role:{type:String, default:""},
members:Array
}],
users:[{
userId:String,
cash:Number,
bank:Number,
items:[{
name:String,
amount:Number
}],
timers:{
work:String,
crime:String,
hack:String,
steal:String,
daily:String,
weekly:String,
marry:String,
divorce:String,
idea:String,
report:String,
quiz:String
},
fine:{
fineId:String,
description:String,
report:String,
pay:Number
},
used:String
}],
});
guildSchema.virtual("addUser").set(function(id){
const user = {
userId:id,
cash:settings.cash,
bank:settings.bank
};
this.users.push(user);
return user;
});
module.exports = model("Servers", guildSchema);
Use findOneAndUpdateto update the existing document in the collection.
let the object that you want to update in "commands" in mongodb be in x variable.
Guild.findOneAndUpdate({guildId : serverId},{commands : x));
The object which you have stored in x variable will directly be updated/replaced with this new data when a match is found.
UPDATE TO NOT COMPLETELY REPLACE EXISTING OBJECT
let guild = Guild.findOne({guildId : serverId});
if(guild){
// guild.commands here will have the existing object.
// Modify it as required and then use findOneAndUpdate again
}
The solution is quite simple. I took it from this site: https://mongoosejs.com/docs/2.7.x/docs/schematypes.html
To give credit:
Since it is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect/save
those changes. To "tell" Mongoose that the value of a Mixed type has
changed, call the .markModified(path) method of the document passing
the path to the Mixed type you just changed.
So, whenever I update the commands (aka whenever I change the access, bounded, or disabled variables), I would use the mark modified method on the command function. My code is:
guildSchema.virtual("saveCommands").set(function(name){
if(["access", "bounded", "disabled"].includes(name)) this.markModified('commands');
});
The .json file is like
"person":{"_info":{"name":"john","age":17}}
In my node, if i run console.log(person.body); it prints out fine, but if I try console.log(person._info.body); or console.log(person._info); it returns undefined.
So is there a way that I can print out the ._info?
Thanks
May be your json isn't valid, this code is working :
var obj = {
"person": {
"_info": {
"name":"john",
"age":17
}
}
};
console.log(obj.person._info);
Hello guys I'm kinda new to js and protractor and I just found out it can't create and modify files, so the question I want to ask is:
Is it possible to manually write test cases logic fails to a text file for example:
I know the code is not correct but you will get the idea i know about jasmine-reporters and with xml file output but it just prints console errors i want one that is custom liek the one below
describe('File output test', function() {
it('should have a title', function() {
browser.ignoreSynchronization=true;
browser.get('https://www.google.com');
});
it('Tests output file',function(){
var searchText = $('#lst-ib');
searchText.sendKeys('Testt')
searchText.sendKeys(protractor.Key.ENTER);
browser.sleep(3000);
if(browser.getTitle() != 'Test')
{
var txtFile = "C:\Users\y\Desktop\test.txt";
var file = new File(txtFile);
var url = browser.getCurrentUrl();
file.open("w");
file.writeln("Error at " + url);
file.close();
}
});
});
conf file pretty basic:
exports.config = {
framework: 'jasmine',
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['spec.js']
}
So I simply want to check for the given title at the moment and if it is different from the expected one i want to save the url in an output file so when the test ends i can check afterwards where exactly did something i didnt want happened. I hope I am not talking nonsense
Protractor runs in Node.js environment. So everything, that Node.js has, is available to you. Such as "fs" module. So you can manually save file every time, or (as a better option), write custom Jasmine reporter. Your reporter would expose some variable or function in global namespace to register custom errors and write them into a file after test execution.
Nevermind i found the answer to my question here is my sample code i used to test it
var fs = require('fs-extra')
var file = 'C:/Users/y/Desktop/test/New folder/output.txt'
var counter = 1;
describe('File output test', function() {
it('should have a title', function() {
browser.ignoreSynchronization=true;
browser.get('https://www.facebook.com');
});
it('Tests output file',function(){
email = 'dame#hotmail.com';
pass = 'test123'
var enterMail = $('#email');
enterMail.sendKeys(email);
var enterPass = $('#pass');
enterPass.sendKeys(pass);
enterPass.sendKeys(protractor.Key.ENTER);
browser.sleep(3000);
if(browser.getTitle() != 'Facebook'){
fs.appendFile(file,counter +'. ' + 'Error at login using: ('+email +') as email and ('+pass+') as password.' + "\n" , function (err) {
console.log(err) // => null
})
counter+=1;
}
});
});
I found a module fs-extra which allowed to create and edit some files or documents and i managed to create and write my manual output in a file here is the link to fs-extra https://github.com/jprichardson/node-fs-extra#mkdirsdir-callback in case someone needs it cheers
I am using fs.createReadStream() to read files, and then pipe them to the response.
I want to add a small Javascript function when I'm serving HTML files.
The only way I can think of is to read the file into a string, append the text to the string, and then stream the string to the response, but I think there could be a better/faster way to do this.
Is there a way for me to append the text to the file on the go?
After #Matthew Bakaitis's suggestion to use through and after reading for a while about it and checking the issues on github, I found through's developer recommending through2
for a case similar to mine.
Better implementation using finish callback
let str_to_append="Whatever you want to append"
let through_opts = { "decodeStrings": false, "encoding": "utf8" }
let chunk_handler = function (chunk, enc, next) {
next(null, chunk)
}
let finish_handler = function (done) {
this.push(str_to_append)
done()
}
let through_stream = through2.ctor(through_opts, chunk_handler, finish_handler)
Old Implementation
This is how I implemented the solution:
var through2 = require("through2");
var jsfn="<script>function JSfn(){ return "this is a js fn";}</script>";
var flag=0;
fileStream.pipe(
through2( {"decodeStrings" : false, "encoding": "utf8"},function(chunk, enc) {
if(flag===0) {
var tempChunk=chunk;
chunk=jsfn;
chunk+=tempChunk;
flag=1;
}
this.push(chunk);
})
).pipe(res);
The option decodeStrings must be set to false so that the chunk of data is a string and not a buffer. This is related to the transform function of the stream api, not to through2.
More info on transform