I just got into Cypress testing and tried to integrate it into a Project but got kind of stumped with testing a form on a site.
What should I be testing on the form ?
My Goal is to make sure that you can't submit the form without entering all fields that are absolutely neccessary and that the information that is provided is "correct".
So my instinct was to write a test like that
it('Submit Form without selecting Gender, Gender shows an Error')
Another test would be then
it('Submit Form without selecting Gender, Gender shows an Error, selecting Gender removes Error')
Would this be a "good" approach ? Is there a "better" one ?
First of all, understand how those frontend validations work. Are they JavaScript validations? Or HTML validations? If HTML, you can check required attribute on elements you need.
How many inputs does the form have? You might be typing a lot of similar test code, therefore I'd go for a data driven approach:
const testData = require('../fixtures/formData.json');
[
{
name: "name",
selector: "#name",
type: "input",
},
{
name: "gender",
selector: "#gender",
type: "checkbox",
},
].forEach(field => {
it(`Cannot send form without ${field}`, () => {
// fill in the form
// e.g. you can prepare a custom command for that
cy
.fillInForm(testData);
// delete one field
if (field.type === 'checkbox') {
cy
.get(field.selector)
.uncheck();
} else {
cy
.get(field.selector)
.clear();
}
// try to submit it
cy
.get('#submitBtn')
.click();
// check it has not been submitted
});
})
Than you can just edit or add data and the test code remains the same, no more typing.
Related
I'm using commitMode="Immediate" and I'm trying to disable my save button when any input is invalid.
What is the recommended approach to achieve this?
I understand that I can just set a variable when using "manual" mode from my component, but I can't find any event that represents a change in validity of preferably the complete Raddataform (otherwise of a single property) when using Immediate validation.
You can do this by listening for validation events and then updating your model.
From this example, add the propertyValidated listener:
<RadDataForm #propertyValidated="onPropertyValidated" ...></RadDataForm>
Then change your state:
methods: {
onPropertyValidated({ object, propertyName, entityProperty }) {
this.$refs.button.enabled = !entityProperty.isValid;
}
}
You will probably want to keep track of all validations in this case, or you could use the complete dataform.hasValidationErrors().
This is the NS-Vue solution, but totally applicable in Angular.
Add a #propertyValidated="onValidateForm" event listener that triggers on each validation. Then you can use hasValidationErrors() on the form to see if the form is valid. The only trick is that is has to be wrapped in a setTimeout(), like so:
onValidateForm(event) {
setTimeout(() => {
this.validated = !event.object.hasValidationErrors();
console.log("form valid: " + this.validated);
}, 100);
}
For a complete solution, see this playground.
I am using x-editable for in-line editing inside my web app. I would like to pass additional parameters to server, which I would like to read from data- attributes on trigger element. Here is my editable element:
Value
I would like to pass data-param attribute, but I don't know how to access trigger element. I tried via $(this).data('param'), but I get null... My full editable code:
$.fn.editable.defaults.mode = 'inline';
$('.editable').editable({
params: { param: $(this).data('param') }
});
Calling $('.editable').data('param') doesn't come into account since I have many .editable elements present.
Thanks
I figured it out. I'm answering in case somebody needs to know:
$('.editable').editable({
params: function(params) {
// add additional params from data-attributes of trigger element
params.param1 = $(this).editable().data('param');
params.param2 = $(this).editable().data('nextparam');
return params;
}
)
I'm implementing a simple (at least ,that was the goal) Kendo UI grid that displays two columns: one holding a checkbox, bound to a boolean, and one holding a display name for the item. The checkbox column has a simple template, and the change() event of the checkbox is handled so that the model in the datasource gets updated. I have verified this, and it works.
The data source has been configured for batch, and defines a transport for read and update. Both call a function that perform the ajax call. As I said before, the read function is handled as expected. However, the update function defined on the transport is not. The sync() on the datasource is triggered with a simple button whose click event is hooked to a function that calls datasource.sync() (or grid.saveChanges()).
transport: {
read: function(options) {
return loadStuff(options);
},
update: function (options) {
return updateStuff(options);
}
}
When debugging in the Kendo UI code, it looks like the models attribute on the ModelSet is always empty, and therefore the sync() decides that there's nothing to sync. Anyone got a clue what is happening here?
UPDATE:
Looks like something may be wrong when handling the checkbox check / uncheck. Apparently I should use something like
$('#divGrid').on('click', '.chkbx', function() {
var checked = $(this).is(':checked');
var grid = $('#divGrid').data().kendoGrid;
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("Selected", checked);
});
Unfortunately, it looks like the set() method is not defined on the data item. When debugging, it only contains the data, and no Model object having the set() method.
UPDATE 2:
Tried wrapping the data returned from the ajax call in a model defined with Model.define(). That seems to solve the issue of the model not being dirty, as the _modified property on the model returns true. However, the models array in the ModelSet remains empty. Is this a bug in Kendo UI, or am I going the wrong way?
You don't actually need to bind to click event on the checkboxes.
I´ve posted an example on using it in JSFiddle where you can see it running. This example displays in a grid two columns: first text (tick) and second boolean rendered as a checkbox (selected); the update is batch (so, it's pretty close to what you have).
Questions to keep in mind are:
For displaying the checkbox while not in edit mode, you should define a template, something like this. You might realize that the checkbox is in disabled state by default since you want to edit it as other fields (selecting the cell first). This also guarantees that the model is correctly updated:
{
field : "selected",
title : "Selected",
template: "<input type='checkbox' name='selected' #= selected ? 'checked' : '' # disabled/>"
}
Define in the model that this field is boolean:
schema : {
id : "id",
model: {
fields: {
symbol : { type: "string" },
selected: { type: "boolean" }
}
}
},
Define the transport.update function, something like:
transport: {
read : function (operation) {
// Your function for reading
},
update: function (operation) {
// Display modified data in an alert
alert("update" + JSON.stringify(operation.data.models, null, 4));
// Invoke updating function
// that should ends with an operation.success(the_new_data)
// In this example just say ok
operation.success(operation.data.models)
}
}
EDIT: If you want to be able to modify the checkbox state without having to enter in edit mode first, you should:
Remove the disabled from the template:
{
field : "selected",
title : "Selected",
template : "<input type='checkbox' name='selected' #= selected ? 'checked' : '' #/>"
},
Then bind the click event on checkboxes to the following handler function:
$("#stocks_tbl").on("click", "input:checkbox", function(ev) {
var dataItem = grid.dataItem($(this).closest('tr'));
dataItem.set("selected", this.checked);
});
Where #stocks_tbl is the id of the div that contains the grid. You might see it running here.
NOTE: It's important the on with the three parameters for making it live
I have the formwizard plugin integrated with an 8-step form; The problem is, whenever I'm trying to edit information and then jump to an specific step in the form so basically jumping ignoring previous steps, all steps that were not shown (cuz I jumped them) are not sent!!! :( so losing all data already populated into those fields.
For example,
$("#demoForm").formwizard("show","Step4");
This will trigger Step4, but if I am at Step1 and havent seen Step2 and Step3, and jump right into Step4.. then the plugin ignores those Step2 and 3 so when my processing script will process empty data. I would like to know how to notify the plugin that there are steps that were now shown in order to submit those values.
Note: I'm not using Ajax for this.
This is where the settings are:
$("#demoForm").formwizard({
formPluginEnabled: false,
validationEnabled : true,
disableUIStyles : true,
textNext: "Siguiente",
textBack: "Anterior",
textSubmit: "Guardar",
focusFirstInput : true
},
{
messages: { email: "Invalid email"}
},
{
// form plugin settings
}
);
Jumping to an specific step like this...
$('#gotostep').change(function(){
if($(this).val() != '')
{
$("#demoForm").formwizard("show",$(this).val());
return false;
}
});
..same thing happens if I try to force a submit changes on any steps using: $("#demoForm").submit(); :/
Thanks in advanced!
Frank
I guess it should suffice to enable all disabled input elements in the form when the form is submitted? Do this e.g. by hooking up a callback to the forms submit event like this:
$(function(){
var form = $("#demoForm");
form.submit(function(){
form.find(":input:disabled").removeAttr("disabled");
})})
Hope this helps.
I'm using jqGrid 4.2 with the filterToolbar, which works great. I'd like to add some type of custom search to query (server-side) fields that are not part of the colModel.
Prior to 4.0 I would have used filterGrid along the lines of this:
$('#keyword').jqGrid('filterGrid', '#ticket-grid',
{
gridModel: false,
filterModel: [
{ label: 'Keyword', name: 'keyword', stype: 'text'},
{ label: 'Inclued Closed?',name : 'includeClosed', stype: 'checkbox'}
]
});
I understand that this is no longer supported, and an stype: 'checkbox' doesn't work anyway.
How do I do this with the new search module/mechanism?
If I understand you correct you have already on the page, for example above the grid, some controls (text input, selects, chechboxes) which allow the user to define additional criteria of the results which the user want see in the grid. In the case you can use postData with methods (functions) in the way described in the old answer.
If any kind of grid refreshing: request to filter the data from the searching toolbar, changing of the page or the page size, changing of sorting and so on will always follow to the Ajax request to the server. In the case the properties from postData option of jqGrid will be added like other standard parameters (sidx, sord, page, ...). If one from the properties of the postData is defined as function (if a method of postData) then the function will be called to construct the parameter which will be sent to the server. So the current information from you custom searching controls (text input, selects, chechboxes) will be send to the server. In the way you need only use the parameters on the backend to filter the results.
So you have to define fields yourself. For example the text input with id="keyword-input" and checkbos with id="includeClosed" and then use postData in about the following form:
$('#keyword').jqGrid(
// ... other jqGrid options
postData: {
keyword: function () { return $('#keyword-input').val(); },
includeClosed: function () { return $('#includeClosed')is(':checked'); },
}
});