I am trying to assert visibility of the child elements in a parent element.
i am checking weather the divs inside c-cost-with label are visible.
Here is the HTML for it:
i am trying to fetch the elements based on the parent:
Given(/^I should see the following charge amounts and charge labels in offer:$/, (dataTable) => {
dataTable.rawTable.slice(1).forEach((row) => {
let [optionName, pricingPlanName, chargeAmount, ChargeLabel] = row;
let costWithLabelElement = costWithLabelUtil.getCostWithLabelElement(optionsCardCostListElement);
costWithLabelUtil.getCostWithLabelCostElementContainingText(chargeAmount, costWithLabelElement).should('be.visible');
costWithLabelUtil.getCostWithLabelLabelElementContainingText(ChargeLabel, costWithLabelElement).should('be.visible');
});
});
here is the code in costWithLabelUtil:
export function getCostWithLabelElement (ancestorElement = null) {
return ElementFinders.getElementFromAncestorIfProvided('.c-cost-with-label', ancestorElement);
}
export function getCostWithLabelMainElement (ancestorElement = null) {
return ElementFinders.getElementFromAncestorIfProvided('.c-cost-with-label__main', ancestorElement);
}
export function getCostWithLabelCostElement (ancestorElement = null) {
return ElementFinders.getElementFromAncestorIfProvided('.c-cost-with-label__cost', ancestorElement);
}
export function getCostWithLabelCostElementContainingText (text, ancestorElement = null) {
return ElementFinders.getElementContainingTextFromAncestorIfProvided('.c-cost-with-label__cost', text, ancestorElement);
}
export function getCostWithLabelLabelElement (ancestorElement = null) {
return ElementFinders.getElementFromAncestorIfProvided('.c-cost-with-label__label', ancestorElement);
}
export function getCostWithLabelLabelElementContainingText (text, ancestorElement = null) {
cy.log(ancestorElement);
return ElementFinders.getElementContainingTextFromAncestorIfProvided('.c-cost-with-label__label', text, ancestorElement);
}
Here is the Element Finder page:
export function getElementFromAncestorIfProvided (elementLocator, ancestorElement = null) {
if (ancestorElement) {
return ancestorElement.find(elementLocator);
}
return cy.get(elementLocator);
}
export function getElementContainingTextFromAncestorIfProvided (elementLocator, text, ancestorElement = null) {
if (ancestorElement) {
return ancestorElement.find(elementLocator).contains(text);
}
return cy.get(elementLocator).contains(text);
}
I am fetching the parent element first and then trying to fetch the childs and check there visibility.
when i execute the steps the first step is executed correctly but the second step is failing !!!
it is trying to fetch the element from '.c-cost-with-label__cost' even though in the function i am passing the parent element.
how to resolve this issue, how to perform assertions [check visibility] on different elements simultaneously
Related
I am trying to dynamically translate some text to be displayed when a user clicks on the translate button, but I can't get it to save my values outside of the Promise. I haven't worked much with Promises and every example only shows console.log, rather than saving values outside of the Promise. I don't really understand how they work. Here is (most of) the code I am trying to fix:
constructor(props) {
super(props);
this.state = {
dynamicTranslate: this.props.dynamicTranslate,
};
}
// I've tried this method as both sync and async (with await) but neither work
googleTranslate = (key) => {
const translator = TranslatorFactory.createTranslator();
// translate returns a Promise
return translator.translate(key, i18n.locale)
.then((response) => {return response});
}
renderText() {
// getting some values....
// this loops through all the feedback information
for (var i = 0; i < components_feedback.length; i++) {
let label = (some string);
let value = (some string);
// to do: call google translate call here if Boolean(this.state.dynamicTranslate)
if (Boolean(this.state.dynamicTranslate)) {
// I am ultimately trying to save the translation string from googleTranslate()
// in label/value so I can push it into feedbacks
label = this.googleTranslate(label);
value = this.googleTranslate(value);
}
feedbacks.push({label: label, value: value, type: comp.type})
}
return (
// some stuff
feedbacks.map((feedback, index)) => {
// some stuff
<Text>{feedback.label}</Text>
<Text>{feedback.value}</Text>
// some other stuff
});
);
}
render() {
return (
<View>{this.renderText()}</View>
);
}
One of the issues I'm running into is that label/value is a Promise if translation is on. If I try to make renderText() an async method, it is also turned into a Promise which render() can't handle. No idea where to go from here.
Solved this issue. Solution is to put the loop in an async function that (ideally) gets called on construction. This loop was edited to await the returns and push to local arrays of labels and values then saves those in state. You can compare the length of those arrays to the expected length (compare length of last array being used to be positive that it has finished) and that is how you can know if the Promises have returned. Paraphrased code:
constructor(props) {
this.state = {
translatedLabels = []
translatedValues = []
}
this.asyncFunction()
}
asyncFunction = () => {
labels = []
for loop
label = await promise
labels.push(label)
//same for values
end for
this.setState({translatedLabels: labels})
}
//later
renderText() {
if (this.state.translatedLabels.length === whatever) {
// do your stuff as you know the async function has finished
}
}
render() {
return (
{this.renderText()}
);
}
Using this reference, I had worked ag grid drop down.
Issue : once I selected a drop down value, then getvalue() returns value instead of name. Hence it shows the number on the column and it should be text.
If I change that to name, while saving, its bind to name . But here it should be value.
Required : getValue should return name & saving the array should contain value.
agInit(params: any): void {
this.params = params;
this.value = this.params.value;
this.name = this.params.name;
this.options = params.options;
}
getValue(): any {
return this.value;
}
ngAfterViewInit() {
window.setTimeout(() => {
this.input.element.nativeElement.focus();
})
}
stackbltiz here
here
How can I achieve this.
You don't have to create new cellRenderer and cellEditor for it, ag-grid provides inbuilt select for it. **
When you using objects (for dropdown\combobox) inside single cell - you have to implement value handlers: valueParser and valueFormatter:
Value parser: After editing cells in the grid you have the opportunity to parse the value before inserting it into your data. This is done using Value Parsers.
colDef.valueParser = (params) => {
return this.lookupKey(mapping, params.newValue);
}
Value formatter: Value formatters allow you to format values for display. This is useful when data is one type (e.g. numeric) but needs to be converted for human reading (e.g. putting in currency symbols and number formatting).
colDef.valueFormatter = (params) => {
return this.lookupValue(mapping, params.newValue);
}
*where mapping represents your object and inside each of those functions you are just extracting key or value.
Original solution:
lookupValue(mappings, key) {
return mappings[key];
}
lookupKey(mappings, name) {
var keys = Object.keys(mappings);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (mappings[key] === name) {
return key;
}
}
}
and here my little bit modified:
lookupValue(mappings, key:string) {
if(!mappings || !mappings.find(item => item.Id == key)) return null;
else
return mappings.find(item => item.Id == key).Value;
}
lookupKey(mappings, name) {
let key: any;
for (key in mappings) {
if (mappings.hasOwnProperty(key)) {
if (name === mappings[key]) {
return key.Id;
}
}
}
}
UPDATE
To populate dropdown you need yo use cellEditorParams:
colDef.cellEditor = 'selectCellEditor';
colDef.cellEditorParams = {
values: yourList,
},
** But in case when it could be required you still need to have both of renderers and store object inside, and then you would be able to choose what would be displayed on every stage.
I am passing data from parent to child. In the HTML, i can see the value of the Input() variable. However, on my TS file, when I try to do a conditional to check the value of Input() it is always an empty string. Here is my code for the child:
#Input() checkDbStatus = '';
ngOnInit() {
this.initForm();
this.dbStatusCheck();
}
// disables all controls in a form group
disableControl(group: FormGroup){
Object.keys(group.controls).forEach((key: string) => {
const abstractControl = group.get(key);
abstractControl.disable();
})
}
// disable form controls if dbStatus !== update
dbStatusCheck() {
if(this.checkDbStatus !== 'update') {
this.disableControl(this.demographicsSectionOne);
this.disableControl(this.demographicsSectionTwo);
this.disableControl(this.demographicsSectionThree);
this.disableControl(this.demographicsSectionFour);
this.disableControl(this.demographicsSectionFive);
}
}
I think you need to use the ngChange lifecycle.
https://angular.io/api/core/OnChanges
export class YourComponent implements OnChanges
ngOnChanges(changes: SimpleChanges) {
if (changes.checkDbStatus.currentValue !== changes.checkDbStatus.previousValue) {
this.doStatusCheck();
}
}
Try set and get input() function
https://angular.io/guide/component-interaction
_checkDbStatus: any;
#Input() set checkDbStatus(data: any) {
this._checkDbStatus = data;
this.dbStatusCheck(data)
}
get checkDbStatus(){return this._checkDbStatus }
Here is what I am trying to do:
I have two DataTables on the same page with different data. One is 'sell_orders' and the other is 'buy_orders'. I want to filter the data in each table separately based on checkboxes at the top of each table. So far I have gotten that to work using the following code:
$("#sell_vis_cit").change(function() {
var checked = this.checked;
var allowFilter = ['sell-orders'];
if (!checked) {
$.fn.dataTable.ext.search.push (
function(settings, data, dataIndex) {
// check if current table is part of the allow list
if ( $.inArray( settings.nTable.getAttribute('id'), allowFilter ) == -1 ) {
// if not table should be ignored
return true;
}
return $(sell_table.row(dataIndex).node()).attr('sell-data-sec') != 'x';
}
);
sell_table.draw();
} else {
$.fn.dataTable.ext.search.pop();
sell_table.draw();
}
});
$("#buy_vis_cit").change(function() {
var checked = this.checked;
var allowFilter = ['buy-orders'];
if (!checked) {
$.fn.dataTable.ext.search.push (
function(settings, data, dataIndex) {
// check if current table is part of the allow list
if ( $.inArray( settings.nTable.getAttribute('id'), allowFilter ) == -1 ) {
// if not table should be ignored
return true;
}
return $(buy_table.row(dataIndex).node()).attr('buy-data-sec') != 'x';
}
);
buy_table.draw();
} else {
$.fn.dataTable.ext.search.pop();
buy_table.draw();
}
});
The problem I am having is when it comes time to remove the filter. If filters have been applied to each table, the removal of the filter using the pop() function becomes unreliable because there is no way to verify that it is removing the filter from the right table.
So my question is: is there a way to verify that pop() is running on the right table like I did with push()? Alternatively, is there a better way to achieve my goal?
Why push() and pop() in the first place? It seems to me you have some static filters which is turned on and off by checkboxes. You could declare a filter once globally and do the "math" inside the filter :
$.fn.dataTable.ext.search.push(function(settings, data, dataIndex) {
if ((settings.sTableId == 'sell-orders' && $("#sell_vis_cit").is(':checked')) ||
(settings.sTableId == 'buy-orders' && $("#buy_vis_cit").is(':checked'))) {
//filter code
} else {
return true
}
})
and then simply activate the filters in the click handlers :
$("#sell_vis_cit, #buy_vis_cit").change(function() {
buy_table.draw();
sell_table.draw();
})
I have a custom data grid element simplified like this:
export class DataGrid {
#bindable data;
dataChanged(newValue, oldValue) {
console.log("Sensing new data...", newValue);
}
}
It's instantiated like this:
<data-grid data.bind="records"></data-grid>
"Sensing new data..." and the array of records is displayed in the console when the data grid appears. However, when I delete a record from the array of objects, the dataChanged() function is not triggered.
let index = this.records.findIndex((r) => { return r.acc_id === this.record.acc_id; });
if (index > -1) {
console.log("Deleting element..." + index, this.records);
this.records.splice(index, 1);
}
I get "Deleting element..." in the console but not "Sensing new data...".
Any ideas why dataChanged() is not firing when I splice out a record?
You can not observe an Array for mutations like that. You have to use a collectionObserver instead. Right now, your dataChanged() would only fire if you overwrite the data value (ie data = [1, 2, 3] which overwrites it with a new array).
Example how to use the collectionObserver from the BindingEngine class, for your usecase:
import { BindingEngine } from 'aurelia-framework';
export class DataGrid {
static inject = [BindingEngine];
#bindable data;
constructor(bindingEngine) {
this._bindingEngine = bindingEngine;
}
attached() {
this._dataObserveSubscription = this._bindingEngine
.collectionObserver(this.data)
.subscribe(splices => this.dataArrayChanged(splices));
}
detached() {
// clean up this observer when the associated view is removed
this._dataObserveSubscription.dispose();
}
dataArrayChanged(splices) {
console.log('Array mutated', splices);
}
}