Cucumber Data Table in (Nightwatch) javascript not working as expected - javascript

So the problem I'm getting is probably something so, so simple (probably), but it's infuriating my as to why it won't work.
What I'd like to do is click on an Edit button on a website, change a value, and Save it.
However, there are over 120 of these changes to be made, and thus over 120 edit clicks, etc.
Hence why I thought I'd use a Data Table.
And here is my subsequent test code;
const { client } = require('nightwatch-cucumber')
const { defineSupportCode } = require('cucumber')
const globals = require('../../config/globals.js')
var emailEntry = (`input[name='administrator[email]']`)
var passwordEntry = (`input[name='administrator[password]']`)
var existingGtmKey = ("GTM-123456")
var newGtmKey = ("GTM-654321")
var gtmKey = (`//div/input[#value='${existingGtmKey}']`)
var saveButton = (`input[type=submit][value='Save']`)
defineSupportCode(({ Given, Then, When }) => {
Given(/^I've logged into Winit cms$/, () => {
return client
.url('http://winit-stage.bauerpublishing.com/admin/sign_in')
.waitForElementVisible('body', 5000)
// Enter winit email address
.moveToElement(`form#new_administrator ${emailEntry}`, 1,1)
.click(`form#new_administrator ${emailEntry}`)
.setValue(`${emailEntry}`, "*****.*****#*****.co.uk")
// Enter winit password
.moveToElement(`form#new_administrator ${passwordEntry}`, 1,1)
.click(`form#new_administrator ${passwordEntry}`)
.setValue(`${passwordEntry}`, "******")
// Click on the 'Sign in' button
.click("form#new_administrator input[type=submit][value='Sign in']")
})
Then (/^I'm able to change the gtm tag for that site (.*?)$/,
(siteedit) => {
return client
// Click on the 'sites' link
.useXpath()
.click("//a[normalize-space(text())='Sites']")
// Click on Edit button
.click(siteedit)
.click(`${gtmKey}`)
.clearValue(`${gtmKey}`)
// Set new gtm key value
.setValue(`${gtmKey}`, `${newGtmKey}`)
// Click save
.useCss()
.click(`${saveButton}`)
})
})
I thought (wrongly!) this would be pretty straightforward, the script would log into my account, click the edit button, enter new value, press the save key, then do the same for the next website edit button.
It works for the first edit button in the Data table, but then the test fails, giving the following error;
So it looks as though it's running the whole script, and not just the Then part of the script.
But I don't understand why??
Any help would be greatly appreciated.
Many thanks.

Related

Intro.JS possible to check user input before proceed

So, i want to come out with the Javascript which forced user to input / select anything before going to next step, (like forced user to press button, input their name, etc). I am working on Django Framework with mix together with Javascript and HTML together.
Ignore the first part as I am trying to assign each function to the button so the button can do different tasks individually. But it wont work in the intro.js script.
Code snipper are below:
<script>
/*
var btn1=document.getElementById("button1");
var btn2=document.getElementById("button2");
var div=document.getElementById("InputName");
btn1.onclick=function(){
if (div.style.display !=="none") {
div.style.display="none";
} else {
div.style.display="block";
}
};
// this is the crucial part
btn2.onclick=function(){
var steps=[
{element:"#button1",intro:"A button", position:"right"},
{element:"#button2",intro:"This goes away sometimes"}
];
if (div.style.display==="none") {
steps.splice(1,1);
}
introJs().setOptions({
steps:steps
}).start();
} */
var steps=[
{element:"#InputName",intro:"Please fill your name", position:"right"},
{element:"#InputUsername",intro:"Please fill your username"},
{element:"#button1",intro:"Succesfully Filled, press register."}
];
introJs().setOptions({
steps:steps
}).start();

How to create a submit button in react-admin which changes appearance and behaviour depending on form data and validation

In a complex tabbed form in react-admin I need to have two submit buttons, one is the regular save button and one for altering the "status" field (advancing one workflow step) and saving the form.
The save butten should only become active if all required fields are filled by the user.
The other button changes its text depending on a "status" field in the record which contains the current workflow step, and is only active when the form validation for the current workflow step passes.
So either I need a dynamic button or several buttons which show and hide depending on the "status" field.
I think the dynamic button would be the more elegant solution.
Below you see the code I currently have, it is more or less copied from the react-admin documentation. I need to add a custom save button as well, but it is just a subset, easy to do when the AdvanceWorkflowButton works at the end.
const AdvanceWorkflowButton= ({ handleSubmitWithRedirect, ...props }) => {
const [create] = useCreate('posts');
const redirectTo = useRedirect();
const notify = useNotify();
const { basePath, redirect } = props;
const form = useForm();
// I need to set the label dynamically ... how?
// I also need sth like:
// if (validationSucceeds()) enable=true
const handleClick = useCallback(() => {
// here I need to check the current content of the "status" field.... how?
form.change('status', { "id": 2, "name": "Vorbereitung begonnen" });
handleSubmitWithRedirect('list');
}, [form]);
return <SaveButton {...props} handleSubmitWithRedirect={handleClick} />;
};
const CustomToolbar = props => (
<Toolbar {...props} >
<SaveButton
label="Speichern"
redirect="list"
submitOnEnter={true}
variant="text"
/>
<AdvanceWorkflowButton />
</Toolbar>
);
I had the exact same trouble.
Needed a button to save the form without validation, and another to save and change status with validation in place.
The code above helped me get to the answer, here are my configuration of the components necessary to achieve the desired outcome.
Set a new truthy value up in the form data as follows when the user clicks the save and next. Check the new property ('goNextStep' in our example) on the server to move the process forward.
<SaveButton
label="Save and next step"
handleSubmitWithRedirect={() => {
form.change('goNextStep', 1); // or true
props.handleSubmitWithRedirect('list');
}}
</SaveButton>
<SaveButton
label="Save only"
handleSubmitWithRedirect={() => {
form.change('validateCustom', 0); // or false
props.handleSubmitWithRedirect('list');
}}
/>
Use the validate prop on react-admin form. I could not make it work with field level validations. I had to remove every field level validation props, and implement all those in validateFunction.
Altough, you could still use the validators in your custom validation function.
const validateFunction = (values) =>{
// using our previously set custom value, which tells us which button the user clicked
let shouldValidate = values.goNextStep === 1;
// return undefined if you dont want any validation error
if (!shouldValidate) return undefined;
let errors = {};
// use built in validations something like this
var someTextFieldErrorText = required()(values.someTextField, values);
if (someTextFieldErrorText) {
errors.someTextFieldErrorText = someTextFieldErrorText;
}
// OR write plain simple validation yourself
if(!values.someTextField) {
errors.someTextField = 'Invalid property!';
}
return Object.keys(errors) ? errors : undefined;
}
Than set up tabbed form to use the previous function for validation.
<TabbedForm
validate={validateFunction}
>
...
</TabbedForm
React-admin version: 3.10.1

How to know/capture the Detail Grid ID of the specific detail grid you are in? (ag-grid javascript)

I have a Master-Detail ag-grid. One column has checkboxes, (checkboxSelection: true). The details grid have a custom status panel with a button. When the user clicks the button in any specific Detail grid, I don't know how to get the SelectedRows from just that one specific detail grid.
The problem is they might leave multiple details displayed/open, and then looping over each Detail Grid will include results from all open grids. I'm trying to isolate to just the grid where the user clicked the button.
I tried looping through all displayed/open detail grids to get the Detail grid ID. But I don't see any info in this that shows me which one they clicked the button in.
I tried in the button component to see if, in the params, there is anything referencing the detailgrid ID that the button is in, but I did not see anything there either.
This is the button component:
function ClickableStatusBarComponent() {}
ClickableStatusBarComponent.prototype.init = function(params)
{
this.params = params;
this.eGui = document.createElement('div');
this.eGui.className = 'ag-name-value';
this.eButton = document.createElement('button');
this.buttonListener = this.onButtonClicked.bind(this);
this.eButton.addEventListener("click", this.buttonListener);
this.eButton.innerHTML = 'Cancel Selected Records <em class="fas fa-check" aria-hidden="true"></em>';
console.log(this.params);
this.eGui.appendChild(this.eButton);
};
ClickableStatusBarComponent.prototype.getGui = function()
{
return this.eGui;
};
ClickableStatusBarComponent.prototype.destroy = function()
{
this.eButton.removeEventListener("click", this.buttonListener);
};
ClickableStatusBarComponent.prototype.onButtonClicked = function()
{
getSelectedRows();
};
Here is the code to loop through and find all open detail grids:
function getSelectedRows()
{
this.gridOptions.api.forEachDetailGridInfo(function(detailGridApi) {
console.log(detailGridApi.id);
});
I was able to work this out, so thought I'd post my answer in case others have the same issue. I'm not sure I took the best approach, but it's seemingly working as I need.
First, I also tried using a custom detail cell renderer, as per the documentation, but ultimately had the same issue. I was able to retrieve the DetailGridID in the detail onGridReady function--but couldn't figure out how to use that variable elsewhere.
So I went back to the code posted above, and when the button was clicked, I do a jquery .closest to find the nearest div with a row-id attribute (which represents the the DetailgridID), then I use that specific ID to get the rows selected in just that detail grid.
Updated button click code:
ClickableStatusBarComponent.prototype.onButtonClicked = function()
{
getSelectedRows(this);
};
Updated getSelectedRow function:
function getSelectedRows(clickedBtn)
{
var detailGridID = $(clickedBtn.eButton).closest('div[row-id]').attr('row-id');
var detailGridInfo = gridOptions.api.getDetailGridInfo(detailGridID);
const selectedNodes = detailGridInfo.api.getSelectedNodes()
const selectedData = selectedNodes.map( function(node) { return node.data })
const selectedDataStringPresentation = selectedData.map( function(node) {return node.UniqueID}).join(', ')
console.log(selectedDataStringPresentation);
}

Using part of Text to control redirect using Protractor

In our project, there are different urls assigned to different categories of product. If the product category is Cat1, click on edit button should take the user to the Cat1 page, and Cat2 should take the user to Cat2 page. However these categories are in a dynamic table so we can not use a fix reference for the edit buttons, and I am trying to make it dynamic. Below is my code snippet:
it('should take the user to appropriate page', function () {
expect(globalVariables.Edit_Button_1.isDisplayed());
// get rows
var row_1 = globalVariables.tableData_Dashboard.all(by.tagName("tr")).get(1);
// get cell values
var cells = row_1.all(by.tagName("td"));
var Cetegory = cells.get(3).getText().then(function (GL) {
// console.log(GL)
return GL;
});
globalVariables.Edit_Button_1.click();
browser.wait(EC.invisibilityOf(globalVariables.Edit_Button_1), 25000, 'Edit button is not disappearing yet');
if (Cetegory.endsWith('Cat1')){
expect(browser.getCurrentUrl()).toEndWith("Cat1");
}
else {
expect(browser.getCurrentUrl()).toEndWith("Cat2")
}
The tests fails with the log " Failed: Cetegories.endsWith is not a function ..
How can this be fixed?
Cetegory is a promise, not a string. Thus it does has function endsWith. You need to consume the promise eventual value in then() as following.
Cetegory.then(function(_Cetegory){
if (_Cetegory.endsWith('Cat1')){
expect(browser.getCurrentUrl()).toEndWith("Cat1");
}
else {
expect(browser.getCurrentUrl()).toEndWith("Cat2")
}
})

How to Retrieve Specific Data in Firebase Using Table Cells?

I'm kinda new to Javascript so please don't bite. I wrote simple function that displays my Firebase users in table, I'm using Jquery to create this, so far my code looks like that:
userRef.on("child_added", snap => {
var username = snap.child("name").child("name").val();
var surname = snap.child("name").child("surname").val();
$("#user_table").append("<tr><td>"+ username +"</td></tr>")
});
now i want to display each users data by clicking on his nickname in table, im doing it like that :
$("#user_table").on('click', 'td', function() {
userRef.on("child_added", snap =>{
cosValue = snap.child("cos").child("cos").val();
alert(cosValue);
})
});
and it displays all of my users data.. not this specific one that i clicked on, how can i solve that ? :)
userRef.on("child_added", snap => {
var username = snap.child("name").child("name").val();
var surname = snap.child("name").child("surname").val();
var cosValue = snap.child("cos").child("cos").val();
$("#user_table").append("<tr onClick=\"displayCos(" + cosValue + ")\"><td>"+ username +"</td></tr>")
});
function displayCos(cos) {
alert(cos); //or any other action, e.g. open a PopUp window, display it in another div or table, etc.
}
You don't need the second .on("child_added",...
Also, you may do that with an onClick listener, instead of coding that inline in the tr tag (see https://www.w3schools.com/js/js_htmldom_eventlistener.asp).

Categories