If table contains something then do something - cypress

How can I code: If table contains some text then do something.
I tried it with contains but that throws me error if table does not contains.
if(cy.get(tableCode).contains('td', value)){
cy.get(tableCode).contains('td', value).click()
}else{
cy.reload()
}
Thanks for your time.

The proper way to us jQuery :contains() would be
cy.get(tableCode).then($table => {
const $cell = $table.find('td:contains(value)')
if ($cell.length) {
$cell.click()
} else {
cy.reload()
}
})

You can use the Jquery length method to check if the element is present in the table or not -
cy.get('tableCode').then(($ele) => {
if ($ele.find('td').contains('value').length > 0) {
//Element found
cy.wrap($ele).find('td').contains('value').click()
}
else {
//Element not found
cy.reload()
}
})

Related

Cypress : XPATH - Do something if the element exists

I need to click on a button if the button exists. I am using the cypress xpath. Currently i am using below code but not working
cy.xpath('//button[text()="New"]')
.then(($button) => {
if ($button.is(':visible')) {
cy.log('visible')
cy.xpath('//button[text()="New"]').click();
} else {
//do something
}
})
In case if you want to click a button based on it existence, you can do like this:
cy.get('body').then(($body) => {
if ($body.find('button:contains("New")').length > 0) {
cy.log('visible')
cy.xpath('//button[text()="New"]').click()
} else {
//do something
}
})
In case if you want to check if the element is visible and then click on it.
cy.xpath('//button[text()="New"]').then(($button) => {
if ($button.is(':visible')) {
cy.log('visible')
cy.wrap($button).click()
} else {
//do something
}
})
XPath has a count() function that tells you if the element exists.
cy.xpath('count(//button[text()="New"])').then(count => { // check existence first
if (count) {
cy.xpath('//button[text()="New"]').then($button =>
if ($button.is(':visible')) {
cy.log('visible')
cy.wrap($button).click()
} else {
//do something
}
}
})
Splitting exists and visible checks like that will work if the DOM is stable.

How to change field size in Infor EAM?

How to change the size of fields in Infor EAM?
Anyone with experience with Infor EAM would be gladly appreciated.
You could do it using Extensible Framework. For example, following code will change width of work order and equipment description fields if you put it in EF of WSJOBS screen.
Ext.define(
'EAM.custom.external_WSJOBS', {
extend: 'EAM.custom.AbstractExtensibleFramework',
getSelectors: function () {
if( EAM.app.designerMode == false) {
return {
'[extensibleFramework] [tabName=HDR][isTabView=true]': {
afterlayout: function() {
try {
document.getElementsByName( 'description')[0].style.width = '700px';
document.getElementsByName( 'equipmentdesc')[0].style.width = '700px';
return true;
} catch( err) {
return true;
}
}
}
}
}
}
}
);

How to get input field name that value has changed [ Angular 6 ]

I tried reactive form valueChanges but valueChanges method doesn't return input field name which has changed.
I thought code like this. but I think this is not smart way. Because I have to compare every each input field. so I need more smart way.
// get init view data from local storage
this.localstorageService.getPlaceDetail().subscribe(data => {
this.initPlaceDetail = data;
// watch changed value
this.editPlaceForm.valueChanges.subscribe(chengedVal => {
if (chengedVal['ja_name'] !== this.initPlaceDetail.languages.ja.name.text) {
this.changedJA = true;
}
if (chengedVal['ja_romaji'] !== this.initPlaceDetail.languages.ja.name.romaji) {
this.changedJA = true;
}
// ...... I have to check all input fields??
});
});
I'm adding form controls from an array and something like this worked for me. Just reference the item you need instead of expecting the valueChanges observable to pass it to you.
myFields.forEach(item => {
const field = new FormControl("");
field.setValue(item.value);
field.valueChanges.subscribe(v => {
console.log(item.name + " is now " + v);
});
});
This is my way to get changed control in form.
I shared for whom concerned.
Method to get list control changed values
private getChangedProperties(form): any[] {
let changedProperties = [];
Object.keys(form.controls).forEach((name) => {
let currentControl = form.controls[name];
if (currentControl.dirty)
changedProperties.push({ name: name, value: currentControl.value });
});
return changedProperties;
}
If you only want to get latest changed control you can use
var changedProps = this.getChangedProperties(this.ngForm.form);
var latestChanged = changedProps.reduce((acc, item) => {
if (this.changedProps.find(c => c.name == item.name && c.value == item.value) == undefined) {
acc.push(item);
}
return acc;
}, []);
Instead of listening to whole form changes you can listen to value changes event for each form control as shown in below code:
this.myForm.get('ja_name').valueChanges.subscribe(val => {
this.formattedMessage = `My name is ${val}.`;
});

Correct way to get a count of matching elements in Nightwatch?

I'm trying to test if a todo app has the right number of elements.
The docs seem to deal almost exclusively with single elements, so I had to use the Selenium Protocol functions. Would this be the right way to test the count of matching selectors (in this case, checking for 2 li elements)?
client.elements('css selector','#todo-list li', function (result) {
client.assert.equal(result.value.length, 2);
});
This works in my test, but I wasn't sure if there were gotchas around using a callback for this. Also not sure why Nightwatch doesn't have any helper functions dealing with more than one element.
I found the following very elegant solution within a VueJS template. It shows how to add a custom assertion into Nightwatch that counts the number of elements returned by a selector. See http://nightwatchjs.org/guide#writing-custom-assertions for details of how to write custom assertions within Nightwatch.
Once installed, usage is as simple as:
browser.assert.elementCount('#todo-list li', 2)
The plugin:
// A custom Nightwatch assertion.
// the name of the method is the filename.
// can be used in tests like this:
//
// browser.assert.elementCount(selector, count)
//
// for how to write custom assertions see
// http://nightwatchjs.org/guide#writing-custom-assertions
exports.assertion = function (selector, count) {
this.message = 'Testing if element <' + selector + '> has count: ' + count;
this.expected = count;
this.pass = function (val) {
return val === this.expected;
}
this.value = function (res) {
return res.value;
}
this.command = function (cb) {
var self = this;
return this.api.execute(function (selector) {
return document.querySelectorAll(selector).length;
}, [selector], function (res) {
cb.call(self, res);
});
}
}
This code was added to vuejs-templates by yyx990803 in 2016. So full credit goes to yyx990803.
Just to reassure you I do a similar thing when trying to grab all matching elements, ex:
browser.elements("xpath","//ul[#name='timesList']/h6", function(result){
els = result.value;
var i = 0;
els.forEach(function(el, j, elz){
browser.elementIdText(el.ELEMENT, function(text) {
dates[i] = text.value;
i++;
});
});
});
Alternatively, if you want to be sure that n number of elements exist, you can use a combination of :nth-of-type/:nth-child selectors and nightwatch's expect.
For example, if you want to test if #foo has nine direct children:
function(browser) {
browser
.url('http://example.com')
.expect.element('#foo > *:nth-child(9)').to.be.present;
browser.end();
}
Or if #bar has three direct article children:
function(browser) {
browser
.url('http://example.com')
.expect.element('#bar > article:nth-of-type(3)').to.be.present;
browser.end();
}
You could use expect.elements(<selector>).count():
browser.expect.elements('div').count.to.equal(10);
browser.expect.elements('p').count.to.not.equal(1);
I adapted Chris K's answer to support XPath expressions by using the built-in method this.api.elements:
exports.assertion = function elementCount(selector, count) {
this.message = 'Testing if element <' + selector + '> has count: ' + count
this.expected = count
this.pass = function pass(val) {
return val === this.expected
}
this.value = function value(res) {
return res.value.length
}
this.command = function command(callback) {
return this.api.elements(this.client.locateStrategy, selector, callback)
}
}
For usage instructions and credits see his answer
And if you like a bit of TypeScript, here is an assertion that will confirm the element count:
import { NightwatchCallbackResult, NightwatchAssertion, NightwatchAPI } from "nightwatch";
module.exports.assertion = function (selector: string, count: number, description?: string) {
this.message = description || `Testing if element <${selector}> has count: ${count}`;
this.expected = count;
this.pass = (value: number) => value === this.expected;
this.value = (result: number) => result;
this.command = (callback: (result: number) => void): NightwatchAPI => {
const self: NightwatchAssertion = this;
return self.api.elements(this.client.locateStrategy, selector, (result: NightwatchCallbackResult) => {
callback(result.value.length);
});
}
}
Use like this:
browser.assert.elementCount('body', 1, 'There is only one body element');

Smart-Table - Select first row displayed (angularjs)

Is it possible to automatically select the first row when using smart-table. I have added the class st-selected conditionally using ng-class which highlights the row, but when I then select another row it does not deselect the first row.
I would be grateful of any help.
Thanks
I have just had a similar problem, but wanted to have a specified default selection, I solved the issue with allot of swearing and a directive.
(function(undefined) {
'use strict';
angular
.module('mymodule')
.directive('stDefaultSelection', function() {
return {
require: 'stTable',
restrict: 'A',
scope: {
selection: '=stDefaultSelection',
},
link: function link(scope, element, attrs, controller) {
scope.$watch('selection', function(newValue, oldValue) {
var selectionMode = 'single';
if (angular.isArray(newValue) && newValue.length > 1) {
selectionMode = 'multi';
}
if (angular.isArray(newValue)) {
newValue.forEach(function (row, index, array) {
controller.select(row, selectionMode);
});
} else {
controller.select(newValue, selectionMode);
}
});
}
};
});
})();
Then in your html:
<table st-table="myCtrl.data.records" st-safe-src="myCtrl.data.safeRecords" st-default-selection="myCtrl.defaultRecord">
Once the data has been set then set your default record and that may solve your problem.
You can use $watch operator and $filter operator to do the needful.
//fired when table rows are selected
$scope.$watch('displayedCollection', function (row) {
//get selected row
row.filter(function (r) {
if (r.isSelected) {
$scope.selectedId = r.id;
//getInfo(r.id);
}
else if (!$scope.rowCollection[0].isSelected) {
$scope.rowCollection[0].isSelected = true;
$scope.selectedId = $scope.rowCollection[0].id;
//getInfo($scope.rowCollection[0].id);
}
})
}, true);
This will select the selected row, and if no row is selected, it will by default select the row with index 0. (First Row)
You need to pass to attributes to your smart table:
<tr ng-repeat="row in rowCollection" st-select-row="row" st-select-mode="single">
You can make a css class to highlight the row:
.st-selected {
background-color: #ffd800;
}

Resources