Supply Test Data into Nightwatch - automation

I tried to supply test data to nightwatch but i don't know how. How to supply any dynamic test data to Nightwatch testing?
I don't want to hardcoded the value into the code. I want to supply it from file.
EDIT:
.setValue('selector', 'DEBBIE A/P EKU')

Since you mentioned it in one of your comments you want to read the values from a file, I recommend you doing it via pseudo-JSON (actually .js). Also a solution I applied in my company.
I have multiple json files which contain certain test data that I didn't want to have in the code. The basic structure of those looks like this:
module.exports = {
WHATEVER_IDENTIFIER_I_WANT: 'Some shiny value'
}
My Page Object contains a line like this:
const STATIC = require('path/to/static/file')
…
.setValue('selector', STATIC.WHATEVER_IDENTIFIER_I_WANT)
And yea, it is not highly sophisticated but it fulfils the purpose.
If you don't want to use module.exports and .js you can still use some node methods to load and parse a JSON. E.g.
fs.readFileSync / fs.readFile (to load the JSON file)
const file = fs.readFileSync('path/to/file')
JSON.parse() (to retrieve a JavaScript Object)
const STATIC = JSON.parse(file)
Hope this is useful for you :)

I've been through the same issue. At the moment my set up is like this:
Raw data are in the excel sheet. I use node.js to convert excel sheet into json file. Then use json data in nightwatch.
Here is the code to read the json file in nightwatch:
module.exports = {
tags: ['loginpage'],
// if not regular size logout button is not visible
'Login' : function (client) {
var credentials;
try{
credentials = require('./path/to/inputJsonData.json');
} catch(err) {
console.log(err);
console.log ('Couldn\'t load the inputJsonData file. Please ensure that ' +
'you have the inputJsonData.json in subfolder ./path/to ' +
'in the same folder as the tests');
process.exit();
}
Here is the code that use data from it:
client
.url(credentials.url)
.waitForElementVisible('body', 1000)
.assert.title('Sign In Home Page')
.login(credentials.username,credentials.password)
// some more steps here
.logout()
.end();
}
};
inputJsonData.json data
{
"url": "http://path/to/my/input/credentials/file",
"username": "yourUserName",
"password": "yourPassword"
}
My problem/question:
How to find the count of elements read into the json object from a file when the file has following format?:
[
{
....
},
{
....
},
.....
{
....
}
]
My failed attempt to get the number of elements: JSON.parse(company).count where company is another json read file like credentials in above code.
Answer: use standard javascript array property length company.length

TheBayOr answered the question concisely regarding the use of files. Just to add that if you don't literally mean a non 'code' file but simply using a different location to store the values then the most common approach is using globals.
You can place an array of values in either your nightwatch.json...
"test_settings" : {
"default" : {
"selenium_port" : 4444,
"selenium_host" : "localhost",
"silent": true,
"globals" : {
"VARIABLE_1" : "i'm a variable",
"VARIABLE_2" : "i'm a variable too"
},
"desiredCapabilities": {
"browserName": "chrome",
"javascriptEnabled": true,
"acceptSslCerts": true
}
},
"other_environment" : {
"globals" : {
"VARIABLE_1" : "i'm a different variable",
"VARIABLE_2" : "i'm a different variable too"
You can use them in tests with something like....
.url(browser.globals.VARIABLE_1)
Notice in the above you can have sets of globals under different environments. This has the advantage of meaning you can have multiple sets and use the one you want by running nightwatch -e 'my desired environment'.
Similarly this can be achieved by putting your array of data in a globals file e.g. globals.js and referencing it in your 'globals.path'.
If you want to get really into it you can even store your variables in global.js then use the 'fs' library to write the values to a file, then have your tests read from there. I'd recommend a new question if thats what you intend.
Hopefully that adds something :)

In my case I just created a function which read variables , data ,etc
more details here: https://stackoverflow.com/a/64616920/3957754

Related

Use i18n with data fetched from Wordpress RestAPI

I'm stuck since a while on this problem now and I'm struggling to find answers or peoples that have experienced the same problem.
Also, I'm not a native English speaker and I'm new to programming, so sorry if it's not clear / if my approch is dumb as f
I decided to turn the Wordpress of my company to headless (on Nuxt). Everything was pretty fine until I tried to internationalized the app. The best solution (I think) to manage this task is to use nuxt-i18n, a tool to properly translate the app (strings, paths etc). But this solution seems to not be very compatible with data fetched from the Rest API.
For now I'm trying to passing the data from single page like that :
<script>
import SwitchL from '~/components/LanguageInput.vue'
export default {
components: {
SwitchL,
},
data() {
return {
fetchRestFr: null,
fetchRestEn: null,
i18nData: null,
}
},
i18n: {
messages: {
// help
}
},
methods: {
fetchSomeData() {
// Get page data in French
let fetchRestFr = this.$axios.$get(`https://www.company-site.com/wp-json/wp/v2/pages?include=42&lang=fr`);
// Get page data in English
let fetchRestEn = this.$axios.$get(`https://www.company-site.com/wp-json/wp/v2/pages?include=42&lang=en`);
// Assign data to null variables
this.fetchRestFr = fetchRestFr[0]
this.fetchRestEn = fetchRestEn[0]
// Build the i18n object
this.dataToI18n();
},
dataToI18n() {
if (this.fetchRestFr && this.fetchRestEn) {
let fr = this.fetchRestFr
let en = this.fetchRestEn
let data = {
messages: {
fr,
en
}
}
this.i18nData = data
}
},
},
created() {
this.fetchSomeData();
},
}
</script>
An other approch was to use the tag outside the template section like so :
<i18n>
// Inject the data generated from a function
{
"en": {
"data": "here"
},
"fr": {
"data": "ici"
}
}
</i18n>
But I don't find any solution to dynamically inject JSON here.
Last solution is to make things to preper way, by creating JSON file for i18n to referencing, but I think It will be pretty hard for me to do this, and to manage this on long term.
If you have advice, thoughts on this I will be very grateful !
You do usually use some JSON files directly. They will be stored into /locales/fr.json with something like this
{
"here": "ici"
}
Then, you'll access it into your template with
<template>
<p>{{ $t('here') }}</p>
</template>
And it will handle the fr/en switch by the several ways available (manual switch, checking browser's locale, URL's path, cookie etc).
You can check nuxt-i18n's documentation for this and get a proper simple setup quickly here: https://i18n.nuxtjs.org/
Usually, you won't need to use the i18n tag anymore but if you still need to, you can do as explained here: https://i18n.nuxtjs.org/per-component-translations

How to write Testcafe selector('Withoutvalue').withText('Valid Text')?

I am facing a scenario where the element tag name and attribute is changing from env to env, but the text content alone is unique.
Therefore I am not able to define any value for Selector('could not define anything here').
How could I write a path to locate the element ?
I don't see a direct solution for this, but a workaround that could solve your issue. You could have an object that holds environments specific data for you and which helps you for specific cases as the one that you seem to be confronted with. In this object, you could also store environment specific Selectors. This could, written in TypeScript, look as follows:
import { Selector } from "testcafe";
interface EnvironmentData {
envName: string;
myVariableSelector: Selector;
}
// Set up a list that contains environment specific data objects
const CONFIGS: EnvironmentData[] = [
{
envName: "MyEnv1",
myVariableSelector: Selector("my css selector 1").withText("my text 1")
},
{
envName: "MyEnv2",
myVariableSelector: Selector("my css selector 2").withText("my text 2")
},
{
envName: "MyEnv3",
myVariableSelector: Selector("my css selector 3").withText("my text 3")
}
]
// Assuming that you're CI for instance sets a environment variable ENVIRONMENT_NAME to
// any of the specific environments MyEnv1, MyEnv2 or MyEnv3
function getConfigForEnvironment(envDataSets: EnvironmentData[]): EnvironmentData {
const envData = envDataSets.find((c) => c.envName === process.env.ENVIRONMENT_NAME);
if (envData === undefined) {
console.error(`No suitable data for environment '${process.env.ENVIRONMENT_NAME}' found!`);
process.exit(1);
}
return envData;
}
// Determine the right object before the tests start
const envData = getConfigForEnvironment(CONFIGS);
fixture`My awesome tests`.page("myTestUrl");
test("My test", async (t) => {
// Make use of the object that holds the data for the desired environment
await t.expect(envData.myVariableSelector.exists).ok("Should be fine for any environment!");
});
I did it in a simpler way using the or operator (,)
i,e I wrote the selector with Selector('div,span').withText('Value')
The attribute div and span are changing with environment so I used , to pass both and it worked.

createjs loadManifest, it should be loading files in manifest, correct?

If I understand the docs correctly… 
window.queue = new createjs.LoadQueue(true, null, true);
queue.loadManifest({src: manifest, type: "manifest"}, true);
should be loading the files that are located in the json file, correct? Not seeing any requests in inspector, only getting the results array in console. Do I have to loop over results array and do the loadFile manually?
JSON is formatted correctly in a {src:"",id:"",type:"createjs.Types.IMAGE"} structure.
Any help is appreciated.
Adding more code:
function to pass in manifest url
function loadImages(manifest) {
window.queue = new createjs.LoadQueue(true, null, true);
queue.loadManifest({src: manifest, type: "manifest"}, true);
queue.on("fileload", this.handleFileLoaded);
queue.on("progress", function(event) {
console.log("progress " + event.progress);
});
queue.on("fileprogress", function(event) {
console.log("file progress " + event.progress);
});
queue.on("error", function(event) {
console.log("file error");
});
queue.on("complete", function(event) {
console.log("queue complete");
console.log(event);
});
queue.load();
return queue;
}
handleFileLoaded event is just dumping event to console at this point.
Manifest with two examples
{
"path":"https://images.unsplash.com/",
"type":"manifest",
"manifest": [
{
"src":"photo-1542838454-d4dce2a7cfde?fit=crop&w=500&q=60",
"id":"stair_boy",
"type":"createjs.Types.IMAGE"
},
{
"src":"photo-1549948558-1c6406684186?fit=crop&w=500&q=60",
"id":"night_bridge",
"type":"createjs.Types.IMAGE"
}
]}
I get access to the manifest array in the fileload event, I can manually load the images from there, but that seems counterintuitive to the whole point of using the PreloadJS. Seems like on page load, Preload should load the manifest, recognize 'type'… loop through files and in network inspector I should see the web requests for the images.
The types in your manifest are incorrect. You are passing in a string value of "createjs.Types.IMAGE". This is not equal to "image", nor is it the equivalent of the JavaScript createjs.Types.IMAGE, since it is interpretted as a string.
Instead use the string value "image"
{
"path":"https://images.unsplash.com/",
"type":"manifest",
"manifest": [
{
"src":"photo-1542838454-d4dce2a7cfde?fit=crop&w=500&q=60",
"id":"stair_boy",
"type":"image"
},
{
"src":"photo-1549948558-1c6406684186?fit=crop&w=500&q=60",
"id":"night_bridge",
"type":"image"
}
]}
Edit: The type property is only required when there is not a recognizable image extension, such as this case.
From the docs:
The loadManifest call supports four types of manifests:
A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property, which defines the list of files to load, and can optionally contain a "path" property, which will be prepended to each file in the list.
An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load, and can optionally contain a "path" property, which will be prepended to each file in the list.
An object which contains a "manifest" property, which defines the list of files to load, and can optionally contain a "path" property, which will be prepended to each file in the list.
An Array of files to load.
Your example uses the first approach. If something is not working, then feel free to post more code.
You could always throw some more events on your queue to see what is happening, such as "fileststart", "fileload", and "error". You should get at least one event when the first manifest starts loading.
Cheers.

how do we read a csv file and display the same in dojo?

i want to write a dojo code where upon a button click i want to read a .csv file and display the .csv file in a datagrid using Dojo. Can anyone please help me with this?
Your best try is to retrieve the data using the dojo/request/xhr module, with it you can retrieve an external CSV file. For example:
require(["dojo/request/xhr"], function(xhr) {
xhr.get("myfile.csv", {
handleAs: "text"
}).then(function(data) {
// Use data
});
});
Well, now you have the data as a string in your data parameter, what you now need to do is parse that string. The easiest way is to split your string on each enter, for example:
var lines = data.split(/\r?\n/);
The \r is optional (depends on the system you're using), but now you have each line seperated in an array element in lines. The next step is to retrieve each seperate value, for example by doing:
require(["dojo/_base/array"], function(array) {
/** Rest of code */
array.forEach(lines, function(line) {
var cells = line.split(',');
});
});
Then you have your data splitted by each comma. The next step is that you have to change it to a format that the dojox/grid/DataGrid can read. This means that you will probably convert the first line of your CSV content to your headers (if they contain headers) and the rest of the data to objects (in stead of arrays of strings).
You can get the first line with:
var headers = lines[0].split(',');
And the rest of the data with:
var otherData = lines.splice(1);
Now you should carefully read the documentation #MiBrock gave you, and with it you can transform the simple array of strings to the correct format.
The headers should become an array of objects like this:
[{ name: "display name", field: "field name" }, { /** other objects */ }]
I did that by doing:
array.map(headers, function(header) {
return {
field: header,
name: header
};
});
This will actually convert [ "a", "b" ] to:
[{ field: "a", name: "a" }, { field: "b", name: "b" }]
Now you need to convert all other lines to objects containing a field with name a and a field with name b, you can do that using:
array.map(otherData, function(line) {
var cells = line.split(','), obj = {};
array.forEach(cells, function(cell, idx) {
obj[headers[idx]] = cell;
});
return obj:
});
This will actually retrieve the fieldname by retrieving the corresponding header value and output it as a single object.
Now you can put it in a grid, look at #MiBrock's answer for more details about how to do that. The final result would look a bit like this JSFiddle.
Note: Next time you encounter a problem you can't solve, handle the parts you actually can solve first and then ask a question about the other parts. I mean, it's hard to believe that you can actually not solve any of this by yourself. You should try and learn it by yourself first.
The dojo-smore project includes a CSV object store that loads data from CSV into an in-memory store which can then be used with any component that supports object stores, like dgrid. You shouldn’t try to do it yourself, like Dimitri M suggested, and you shouldn’t use the dojox grids, which are deprecated.
You can use dojox.data.CsvStore to read a CSV store and use it in a data grid.
Have a look here : http://dojotoolkit.org/reference-guide/1.8/dojox/grid/index.html#dojox-grid-index
and here: http://dojotoolkit.org/documentation/tutorials/1.9/populating_datagrid/
This should help you to start with your Programming.
If you need further help, show us what you have tried to solve the Problem by posting your code and we'll be glad to help you.
Regards, Miriam

how to get pjscrape to print out current url in a file?

I am using pjscrape to scrape content from dynamic pages generated by a site. Please see code below.
I cant figure out what I need to do to get it to print out the url of the scraped page in the json variables dumped to a file. I have tried various ways of doing it - including document.url etc ( see lines 3-6 that are commented out in code below ). However I cant figure out how to get the urlFound variable to get the right value. Of course, the answer might be dead simple but its eluding me. Any other way of doing this? Help!
var scraper = function() {
return {
//urlFound:$(window.location.href),
//urlFound: $(this).window.location.href,
//urlFound: _pjs.toFullUrl($(this).attr('href')),
//urlFound: _pjs.toFullUrl($(this).URL),
// Heck - how to print out the url being scraped???
name: $('h1').text(),
marin: _pjs.getText($("script:contains('marin')"))
}
};
pjs.config({
// options: 'stdout', 'file' (set in config.logFile) or 'none'
log: 'stdout',
// options: 'json' or 'csv'
format: 'json',
// options: 'stdout' or 'file' (set in config.outFile)
writer: 'file',
outFile: 'scrape_output.json'
});
pjs.addSuite({
url: 'http://www.mophie.com/index.html',
moreUrls: function() {
return _pjs.getAnchorUrls('li a');
},
scraper: scraper
});
Don't need jquery for your selector on window.location.href. Not sure how to get access to the internal url of pjscraper, but changing your code to this works:
var scraper = function() {
return {
urlFound: window.location.href,
name: $('h1').text(),
marin: _pjs.getText($("script:contains('marin')"))
}
};
Or you can just use document.URL...save that as a variable and then write it to a file using How to read and write into file using JavaScript