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

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.

Related

Add test description in report

Is there a way to add custom text in testcafe reports?
I would like to add a short description in the reports, so when somebody else checks it to be able to understand what the test does (especially when the test is passed, only the test name appears in the report and I cannot write too much text in the name of the test,it makes no sense). The problem is that I have different functions checking some menus and only 1 test scenario. I would like to add a text to know which functions were called.
console.log('custom text') will write the text only in the console
this.write('custom text') used inside a async function gives an error.
class goThroughAllMenus{
constructor(){
}
async f_CheckHomeMenus() {
//Description: This function is going through all submenus under Home page
// and checks that the pages are 'up and running'.
this.write(`Running test for Home menu`)
await t
//Hjem
.click(StartPage.HomeMenus.menuHome)
.expect(StartPage.StartPage.StartSubMenu.exists).ok()
}
}
There is no built-in capability to pass custom data to the reporter. You can ping the already existing issue in the TestCafe repo. However, if you just want to send common information about the whole test block, you can use meta and create a custom reporter to show this information.
//reporter.js
export default function () {
return {
async reportTaskStart (startTime, userAgents, testCount) {
},
async reportFixtureStart (name, path, meta) {
},
async reportTestStart (name, meta) {
},
async reportTestDone (name, testRunInfo, meta) {
this.write(meta );
},
async reportTaskDone (endTime, passed, warnings, result) {
}
};
}
Also, you can create a fork of any existing reporter and enhance one.

ckeditor5 - custom container element - recursion error on paste

I'm trying to create a CKEditor5 custom element plugin - mainly for custom format/styles -- nested divs etc. Managed to be able to inject/format the elements, and I can type in them. But if I try to copy and paste text into a custom element I get a too much recursion error.
MyWidget plugin:
export default class MyWidgetPlugin extends Plugin {
init() {
const editor = this.editor;
editor.model.schema.register('my-widget', {
inheritAllFrom: '$root',
isLimit: true,
});
editor.conversion.elementToElement({ model: 'my-widget', view: 'my-widget' });
editor.commands.add('myWidget', new MyWidgetCommand(editor));
}
}
MyWidget command:
class MyWidgetCommand extends Command {
execute() {
const editor = this.editor;
const block = first(this.editor.model.document.selection.getSelectedBlocks());
this.editor.model.change(writer => {
const myWidget = writer.createElement('my-widget')
writer.insert ( myWidget, block, 'after');
writer.appendElement( 'paragraph', myWidget );
});
}
}
Inserting a widget injects this into the editor:
<my-widget>
<p></p>
</my-widget>
And I can type fine, but I can't paste. I'm guessing I got the schema wrong... have played around with quite a few different options.. but to no avail.
I didn't check it but I think that the issue is here:
editor.model.schema.register('my-widget', {
inheritAllFrom: '$root',
isLimit: true,
});
This schema rule says that <my-widget> will allow e.g. a <paragraph> inside it. But it doesn't say anything about where <my-widget> may be used. That's because $root is not allowed in any other element (cause it's a root :)).
I think that the following should work fine:
editor.model.schema.register('my-widget', {
inheritAllFrom: '$root',
allowIn: '$root',
isLimit: true,
});
Alternatively, a more generic solution should work too:
editor.model.schema.register('my-widget', {
inheritAllFrom: '$root',
allowWhere: '$block',
isLimit: true,
});
Still, the editor should not crash with an infinite loop, so I reported https://github.com/ckeditor/ckeditor5-engine/issues/1441.

element not updated when data changes

I have a vaadin-checkbox:
<vaadin-checkbox id=[[item.id]] disabled="true" checked="[[item.checked]]">[[item.description]]</vaadin-checkbox>
I defined my properties:
static get properties() {
return {
items: {
type: Array,
notify: true,
value: function() {
return [];
}
}
};
}
When I now change the data by pressing some button:
_selectItem(event) {
const item = event.model.item;
if (item.checked === true) {
this.$.grid.deselectItem(item);
} else {
this.$.grid.selectItem(item);
}
item.checked = !item.checked;
}
The state of the checkbox is still checked="true". Why isnt the checkbox getting updated? The same thing when I change the description of the item:
_selectItem(event) {
event.model.item.description = 'test';
}
The test description is never appearing. The checkbox is never getting updated.
The reason why the checkbox does not get updated by the button click handler is in the Polymer 2 data system. Polymer does not detect the change and does not update the template accordingly.
In order to make the change in a way that Polymer would detect it you have two options:
Use this.set(`items.${event.model.index}.checked`, !item.checked) if you can reliably assume that the index used by dom-repeat always matches that elements's index in the items array (it is not the case if you use sorting or filtering features of dom-repeat). See an example here https://jsfiddle.net/vlukashov/epd0dn2j/
If you do not know the index of the updated item in the items array, you can also use the Polymer.MutableData mixin and notify Polymer that something has changed inside the items array without specifying the index of the changed item. This is done by calling this.notifyPath('items') after making a change. However, this requires that your element extends the Polymer.MutableData mixin, and that dom-repeat has the mutable-data attribute set. See an example here: https://jsfiddle.net/vlukashov/epd0dn2j/24/
More information on this in the Polymer 2 docs.

Supply Test Data into Nightwatch

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

Dynamic SASS variables from a server side language

I have a database table that contains a list of colour variables (example HEX colour code). My styles are compiled using Gulp and SASS.
When my Django app creates/updates a row in the database i need to build a new stylesheet based on the colours.
Somehow i need to get the colours from my server side app into a build process.
Record with colours added -> Gulp runs -> New colour variables are used within the stylesheet generation.
Any ideas how this could be done?
Thanks,
I solved this problem in a less than ideal way..
There is a module called gulp-preprocess which take a context array and replaces vars before the sass process runs..
For example:
SASS File
$body-background: '/* #echo body-background */';
body {
background: $body-background;
}
GULP
var data = {
'1': {
'body-background': '#f00',
},
'2': {
'body-background': '#ffffff',
}
}
gulp.task('scss', function () {
for (var partner_id in data) {
if (!data.hasOwnProperty(partner_id)) continue;
var partner_data = data[partner_id]
gulp.src('./static/scss/*.scss')
.pipe($.sourcemaps.init())
.pipe($.preprocess({context: partner_data}))
.pipe($.sass({
errLogToConsole: true,
style: 'compact'
})
.on('error', function (err) {
console.log('Error:', err);
this.emit('end');
}))
.pipe($.autoprefixer({cascade: false}))
.pipe($.cssnano())
.pipe($.sourcemaps.write('./maps'))
.pipe(gulp.dest('./static/css/'+ partner_id))
}
});
I came across this service https://www.grooveui.com, that lets you create multiple themes from your SASS files.
The only catch is you have to host your SASS files with them. Then you can create new themes and set variable values. I guess they are using database to store variables and generating multiple SASS files.
Could be worth a try.