I am using the following code to take screenshots (in after each) when a test fails in Protractor:
function failScreenshot() {
var fs = require('fs');
var spec = jasmine.getEnv().currentSpec;
var specName = spec.description.split(' ').join('_');
if (spec.results().passed()) {
return;
} else {
browser.takeScreenshot().then(
function(png) {
var stream = fs.createWriteStream('screenshots/' + specName + '.png');
stream.write(new Buffer(png, 'base64'));
stream.end();
});
}
}
When I am running the tests locally, the screenshot works just as expected. When running the tests via Jenkins, the tests will stop at the first fail and the screenshot is not created. Also, the folders and paths are correct, I have checked them over and over again. My Jenkins version is 1532.1
Any ideeas on how could I solve this issue?
After further documentation I have found the answer. It was a problem with the path. It seems like NODE JS does not read the path as I thought.
The ./ returns the current directory, except in the require() function. When using require(), it reads ./ to the directory of the file in which it was called (obviously, the mistake was here). __dirname is always the directory of the file in which is used.
The code to be used for my path is the following:
__dirname + '/screenshots/' + specName + '.png'
You can also take the screenshots in jenkins by using the mocha-proshot reporter.
It is a npm package which can be downloaded easily and is very easy to setup.
Related
I want to read a symlink, and get the details of the link itself, not the contents of the linked file. How do I do that in Node, in a cross-platform way?
I can detect symlinks easily using lstat, no problem. Once I know the path of the file, and that it is a symlink though, how can I read it? fs.readFile always reads the target file, or throws an error for reading a directory for links to directories.
There is a fs.constants.O_SYMLINK constant, which in theory solves this on OSX, but it seems to be undefined on both Ubuntu & Windows 10.
If you have determined that the file is a symlink try this:
fs.readlink("./mysimlink", function (err, linkString) {
// .. do some error handling here ..
console.log(linkString)
});
Confirmed as working on Linux.
You could then use fs.realpath() to turn it into a full path. Be aware though that linkString can be just a filename or relative path as well as a fully qualified path so you may have to get fs.realpath() for the symlink, determine its directory part and prefix it to linkString before using fs.realpath() on it.
I've just faced the same issue: sometimes fs.readlink returns a relative path, sometimes it returns an absolute path.
(proper error handling not implemented to keep things simple)
const fs = require('fs');
const pathPckg = require('path');
async function getTarLinkOfSymLink(path){
return new Promise((resolve, reject)=>{
fs.readlink(path, (err, tarPath)=>{
if(err){
console.log(err.message);
return resolve('');
}
const baseSrcPath = pathPckg.dirname(path);
return resolve( pathPckg.resolve(baseSrcPath, tarPath) );
});
});
}
// usage:
const path = '/example/symbolic/link/path';
const tarPath = await getTarLinkOfSymLink(path);
The code works if the symbolic link is either a file or a directory/folder - tested on Linux
I want to know how I can verify if a file was downloaded using Selenium Webdriver after I click the download button.
Your question doesn't say whether you want to confirm it locally or remotely(like browserstack) . If it is remotely then my answer will be "NO" as you can see that the file is getting downloaded but you can not access the folder. So you wont be able to assert that the file has been downloaded.
If you want to achieve this locally(in Chrome) then the answer is "YES", you can do it something like this:
In wdio.conf.js(To know where it is getting downloaded)
var path = require('path');
const pathToDownload = path.resolve('chromeDownloads');
// chromeDownloads above is the name of the folder in the root directory
exports.config = {
capabilities: [{
maxInstances: 1,
browserName: 'chrome',
os: 'Windows',
chromeOptions: {
args: [
'user-data-dir=./chrome/user-data',
],
prefs: {
"download.default_directory": pathToDownload,
}
}
}],
And your spec file(To check if the file is downloaded or not ?)
const fsExtra = require('fs-extra');
const pathToChromeDownloads = './chromeDownloads';
describe('User can download and verify a file', () =>{
before(() => {
// Clean up the chromeDownloads folder and create a fresh one
fsExtra.removeSync(pathToChromeDownloads);
fsExtra.mkdirsSync(pathToChromeDownloads);
});
it('Download the file', () =>{
// Code to download
});
it('Verify the file is downloaded', () =>{
// Code to verify
// Get the name of file and assert it with the expected name
});
});
more about fs-extra : https://www.npmjs.com/package/fs-extra
Hope this helps.
TL;DR: Unless your web-app has some kind of visual/GUI trigger once the download finishes (some text, an image/icon-font, push-notification, etc.), then the answer is a resounding NO.
Webdriver can't go outside the scope of your browser, but your underlying framework can. Especially if you're using NodeJS. :)
Off the top of my head I can think of a few ways I've been able to do this in the past. Choose as applicable:
1. Verify if the file has been downloaded using Node's File System (aka fs)
Since you're running WebdriverIO, under a NodeJS environment, then you can make use its powerful lib tool-suite. I would use fs.exists, or fs.existsSync to verify if the file is in the expected folder.
If you want to be diligent, then also use fs.statSync in conjunction with fs.exists & poll the file until it has the expected size (e.g.: > 2560 bytes)
There are multiple examples online that can help you put together such a script. Use the fs documentation, but other resources as well. Lastly, you can add said script inside your it/describe statement (I remember your were using Mocha).
2. Use child_process's exec command to launch third-party scripts
Though this method requires more work to setup, I find it more relevant on the long run.
!!! Caution: Apart from launching the script, you need to write a script in a third-party framework.
Using an AutoIT script;
Using a Sikuli script;
Using a TestComplete (not linking it, I don't like it that much), or [insert GUI verification script here] script;
Note: All the above frameworks can generate an .exe file that you can trigger from your WebdriverIO test-cases in order to check if your file has been downloaded, or not.
Steps to take:
create one of the stand-alone scripts like mentioned above;
place the script's .exe file inside your project in a known folder;
use child_process.exec to launch the script and assert its result after it finishes its execution;
Example:
exec = require('child_process').exec;
// Make sure you also remove the .exe from scriptName
var yourScript = pathToScript + scriptName;
var child = exec(yourScript);
child.on('close', function (code, signal) {
if (code!==0) {
callback.fail(online.online[module][code]);
} else {
callback();
}
});
Finally: I'm sure there are other ways to do it. But, your main take-away from such a vague question should be: YES, you can verify if the file has been downloaded if you absolutely must, expecially if this test-case is CRITICAL to your regression-run.
I am new to Browserify and trying the following:
I created a node server and trying to get a package called 'openbci' running on the browser.
so I have the following file structure:
Myapp
-...
-public
--app.js
--index.html
--openBCI.js
--...
--javascript
---openBCI
----bundle.js
---...
-node_modules
--openbci
---openBCIBoard.js
--browserify
--...
my app.js file sets the server to serve the public folder
// app.js
var express = require('express');
var app = express();
app.use(express.static('public'));
app.listen(myPort);
then I created the following openBCI.js
// openBCI.js
var OpenBCIBoard = require('openbci').OpenBCIBoard;
exports.OpenBCIBoard = OpenBCIBoard;
and finally launched the browserify command:
$ browserify public/openBCI.js > public/javascript/openBCI/bundle.js
but once called in my index.html file, I got an Uncaught TypeError: exists is not a function at Function.getRoot:
exports.getRoot = function getRoot (file) {
var dir = dirname(file)
, prev
while (true) {
if (dir === '.') {
// Avoids an infinite loop in rare cases, like the REPL
dir = process.cwd()
}
**if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {**
// Found the 'package.json' file or 'node_modules' dir; we're done
return dir
}
if (prev === dir) {
// Got to the top
throw new Error('Could not find module root given file: "' + file
+ '". Do you have a `package.json` file? ')
}
// Try the parent dir next
prev = dir
dir = join(dir, '..')
}
}
It appears that it could not find the original path for the module.
Could you please tell me what is to change? Or if I understood at all how browserify works ? :)
I notice a few things that seem strange about the code.
exists is undefined in JavaScript or node. It appears to be an alias of fs.exists - is that right?
If so, fs.exists is deprecated. Per the documentation, you can achieve the same effect with fs.stat or fs.access. Note however that you should either supply a callback (preferable) or use the Sync version of these methods.
If you are trying to use file system tools in the browser you are going to run into problems because you are attempting to access the server's file system from the browser. There is a plugin, browserify-fs, that gives you an equivalent to fs in the browser. However, this seems to access the browser's local IndexedDB, not the storage on your server.
I would suggest running code that relies on server-side files on the server, rather than in the browser.
I'm currently trying to search for a few files in a specific folder on Windows using node and grunt.
I have a grunt task that has a function to read a dir with JSON files, but the problem is that when I run the task, the code to read the file doesn't do anything, everything else on that grunt task runs perfect, but that. I'm not sure if the reference for the path is correct, but I'm also using path.normalize() and it does not throws any error.
This is snippet of the code:
..// Some other code
var fs = require('fs'),
path = require("path");
grunt.registerTask('separate', function() {
var filePath = path.normalize("C:\Users\jbernhardt\Desktop\testkeeper\jenkinsReports");
fs.readdir(filePath, function(err, filenames) {
//This log doesn't show as it the function is not running
grunt.log.writeln("Testing");
if (err) {
grunt.log.writeln("Error");
return;
}
filenames.forEach(function(filename){
grunt.log.writeln("Testing");
});
});
...//Some more code below for the same task
}
Does anyone has an idea why this snippet of the code is being skipped when I run the task? I could probably be missing some basic stuffs. Thanks!
Try readdirSync and check if your function still not working. I guess your process is finished before the callback.
You can simply use the __dirname object to get the path where the current script is running:
..// Some other code
var fs = require('fs'),
path = require("path");
grunt.registerTask('separate', function() {
fs.readdir(__dirname, function(err, filenames) {
//This log doesn't show as it the function is not running
grunt.log.writeln("Testing");
if (err) {
grunt.log.writeln("Error");
return;
}
filenames.forEach(function(filename){
grunt.log.writeln("Testing");
});
});
...//Some more code below for the same task
}
You can find more info here.
you need change your path
var filePath = path.normalize("C:\\Users\\jbernhardt\\Desktop\\testkeeper\\jenkinsReports");
Also To achieve consistent results when working with Windows file paths on any operating system, use path.win32:
path.win32.basename('C:\\Users\\jbernhardt\\Desktop\\testkeeper\\jenkinsReports"');
You can read about https://nodejs.org/api/path.html#path_windows_vs_posix
The slash in path are being escaped.
"C:\\Users\\jbernhardt\\Desktop\\testkeeper\\jenkinsReports"
should solve your issue.
Is there a way in a Node.js Jake build to wait until a certain file has been copied, and advance to do some operation only after the destination file can be found? I think this question pretty much comes down to "is there a way to copy files synchronously in Node.js/Jake?" (Perhaps something else than writing something from scratch, using the combination of fs.readSync and fs.writeSync.)
Background:
I'm developing a web app that is run on Node.js (with Express) during development, but will be deployed on a Java server in production. (We use Jade and Stylus in the client and Express enables us to run the app without generating all the HTML files etc. and deploying it after every change.)
I use Jake for making the build, i.e. generating HTML files from Jade files and CSS from Stylus files etc. Now I'm also trying to concatenate all of the app's JavaScript files into one minimized file and change all the HTML files to use that instead of all the separate JS files that are used in "raw" form during development.
However, I now have a problem with that last step. My idea was to copy all of my Jade files into a temporary directory for the deployment build and replace the reference (in a Jade file used as a header on all HTML pages) to a list of all separate JS files to the one that has just been generated by concatenating and minimizing the whole bunch. But as I first copy all of the Jade files to another location (which happens asynchronously) and try to edit one of the files, opening the file always fails since the copy operation hasn't really finished yet.
This is what I have now (in a simplified form) in my jakefile:
var fs = require('fs');
var fse = require('fs-extra');
var path = require('path');
var glob = require('glob');
var Snockets = require('snockets');
var snockets = new Snockets();
// generating the minimized JS file
snockets.getConcatenation(baseDir + '/scripts/all.js', { minify: true }, function(err, allJs) {
if (err) {
throw err;
}
fs.writeFileSync(generatedJsFileName, allJs);
});
// copying all the Jade files to a temp dir
glob.sync('**/*.*', {
cwd : srcDir
}).forEach(function(file) {
var loadPath = srcDir + '/' + file;
var savePath = targetDir + '/' + file;
fse.mkdirsSync(path.dirname(savePath));
fse.copy(loadPath, savePath);
});
// trying to read one of the copied files (which fails, since the file cannot be found yet)
fs.readFile(targetDir + '/views/includes/head.jade', 'utf8', function(err, data) {
...
});
This might be a stupid question, and a stupid way to try to solve the problem in the first place. So, also suggestions for a better approach are very welcome.
Update:
I also tried using Parseq, putting each operation (creating the JS file, copying the Jade files, reading one file) in its own function, but even that gives me the same error. If I run the script several times without deleting the target directory of the copy operation in between, the file can be found. So e.g. the path is correct and the problem really seems to be about timing.
I didn't really find an answer to the main question so I don't know if this helps anyone else facing the same problem. But I did find a way to get around the problem.
I ended using the same original Jade files for the two different conversions, but in the second conversion I use a custom js function to change the script tag reference to point to the minified file.
I.e.
var data = jade.compile(str, { filename: file, pretty: true })({
css: function(path) {
return '<link rel="stylesheet" href="/styles/' + path + '.css" />';
},
js: function(path) {
var name = '<script src="/scripts/';
if (path == 'all') {
name += generatedJsFileName;
}
else {
name += path + '.js';
}
name += '"></script>';
return name;
}
});
It might not be the prettiest workaround but it works.