I'm trying without success to set the value of a radio button with CasperJS.
Can somebody explain to me why the assertEval is failing on this test?
this.test.assertExist('input[name=main][value=yes]');
casper.thenEvaluate(function(term) {
document.querySelector('input[name=main][value=yes]').setAttribute('checked', true);
});
this.test.assertEval(function() {
return document.querySelector('input[name=main][value=yes]').getAttribute('checked') == "true";
}, 'Main was set to true');
To understand why this assert is failing, we need to understand that each call to casper.then defines a new navigation step, and casper.run executes each step in the order that they're defined. So the code within your casper.then block is an async callback.
If you annotate your code like this:
this.test.assertExists('input[name=main][value=yes]');
casper.then(function() {
this.echo('Select the radio button');
this.evaluate(function() {
document.querySelector('input[name=main][value=yes]').setAttribute('checked', true);
}
});
this.echo('Assert that the radio button is selected');
this.test.assertEval(function() {
return document.querySelector('input[name=main][value=yes]').getAttribute('checked') == "true";
}, 'Main was set to true');
You will notice that "Assert that the radio button is selected" gets printed before "Select the radio button". So there's your problem!
The Solution:
You may not need to use then if you're not performing any navigation steps. In that case, you can simply use evaluate instead of thenEvaluate. Or if you really need to use then, just put assertEval into the same casper.then block:
this.test.assertExists('input[name=main][value=yes]');
casper.then(function() {
this.evaluate(function(term) {
document.querySelector('input[name=main][value=yes]').setAttribute('checked', true);
});
this.test.assertEval(function() {
return document.querySelector('input[name=main][value=yes]').getAttribute('checked') == "true";
}, 'Main was set to true');
});
Related
My emit call is not getting called on my button click. I tried to run a debugger and step through it and it gets triggered but looks like it steps right through and skips it. I'm not sure what the issue is or why it's skipping.
Parent
<step-review #emitgetappdata="getAppData"></step-review>
getAppData: function(data=null) {
debugger
}
Step Review
<button #click="this.clickedButton()">Test</button>
clickedButton: function() {
console.log("reached here");
let data = {
text: "Foo",
}
this.$emit('emitgetappdata', data);
}
You can't use this on view
<button #click="clickedButton()">Test</button>
clickedButton() {
console.log("reached here");
let data = {
text: "Foo",
}
this.$emit('emitgetappdata', data);
}
and your component code to this a bit more clean.
<step-review #emitgetappdata="getAppData"></step-review>
getAppData(data=null) {
debugger
}
Edited after reading some docs :
https://v2.vuejs.org/v2/guide/instance.html#Data-and-Methods
I've got an action function for my popup and I need to access the feature attributes from the pop up within the action function. In the code below I'd like to access {SAWID} -- I dont see it in the event parameter sent to the function.
var ContactsAction = {
title: "Get Contacts",
id: "contacts-this",
};
var template = {
// autocasts as new PopupTemplate()
title: "{Name}",
content: "{SAWID}",
actions: [ContactsAction]
};
// Event handler that fires each time an action is clicked.
view.popup.on("trigger-action", lang.hitch(this, this.Contacts));
// Executes when GetContacts is clicked in pop ups
Contacts: function (event) {
if (event.action.id === "contacts-this") {
//grab SAWID
}
}
Thanks
Pete
I found something that works, although its probably not the best way to do it:
there is an innerText property on the even.target object that includes all the text in the pop up. If I parse the innerText property I can get what I need: If anyone knows of a cleaner way please let me know. Thanks
// Executes when GetContacts is clicked in pop ups
Contacts: function (event) {
if (event.action.id === "contacts-this") {
var str = event.target.innerText;
var start = str.indexOf("Close") + 6;//"Close" always precedes my SAWID
var end = str.indexOf("Zoom") - 1;//"Zoom" is always after my SAWID
var SAWID = str.substring(start, end);
alert(SAWID);
}
}
I'm trying to find a way to simulate a "change" event when doing E2E testing (with selenium or cypress) and slate.js
In our UI, when the user clicks on a word, we pop-up a modal (related to that word). I've been unable to make this happen as I can't get the change event to trigger
The Cypress input commands (e.g. cy.type() and cy.clear()) work by dispatching input and change events - in the case of cy.type(), one per character. This mimics the behavior of a real browser as a user types on their keyboard and is enough to trigger the behavior of most application JavaScript.
However, Slate relies almost exclusively on the beforeinput event (see here https://docs.slatejs.org/concepts/xx-migrating#beforeinput) which is a new browser technology and an event which the Cypress input commands don’t simulate. Hopefully the Cypress team will update their input commands to dispatch the beforeinput event, but until they do I’ve created a couple of simple custom commands which will trigger Slate’s input event listeners and make it respond.
// commands.js
Cypress.Commands.add('getEditor', (selector) => {
return cy.get(selector)
.click();
});
Cypress.Commands.add('typeInSlate', { prevSubject: true }, (subject, text) => {
return cy.wrap(subject)
.then(subject => {
subject[0].dispatchEvent(new InputEvent('beforeinput', { inputType: 'insertText', data: text }));
return subject;
})
});
Cypress.Commands.add('clearInSlate', { prevSubject: true }, (subject) => {
return cy.wrap(subject)
.then(subject => {
subject[0].dispatchEvent(new InputEvent('beforeinput', { inputType: 'deleteHardLineBackward' }))
return subject;
})
});
// slateEditor.spec.js
cy.getEditor('[data-testid=slateEditor1] [contenteditable]')
.typeInSlate('Some input text ');
cy.getEditor('[data-testid=slateEditor2] [contenteditable]')
.clearInSlate()
.typeInSlate('http://httpbin.org/status/409');
If you need to support other inputTypes, all of the inputTypes supported by Slate are listed in the source code for editable.tsx
Found a solution:
1) Add a ref to the Editor
<Editor
ref={this.editor}
/>
2) Add a document listener for a custom event
componentDidMount() {
document.addEventListener("Test_SelectWord", this.onTestSelectWord)
}
componentWillUnmount() {
document.removeEventListener("Test_SelectWord", this.onTestSelectWord)
}
3) Create a handler that creates a custom select event
onTestSelectWord(val: any) {
let slateEditor = val.detail.parentElement.parentElement.parentElement.parentElement
// Events are special, can't use spread or Object.keys
let selectEvent: any = {}
for (let key in val) {
if (key === 'currentTarget') {
selectEvent['currentTarget'] = slateEditor
}
else if (key === 'type') {
selectEvent['type'] = "select"
}
else {
selectEvent[key] = val[key]
}
}
// Make selection
let selection = window.getSelection();
let range = document.createRange();
range.selectNodeContents(val.detail);
selection.removeAllRanges();
selection.addRange(range)
// Fire select event
this.editor.current.onEvent("onSelect", selectEvent)
}
4) User the following in your test code:
arr = Array.from(document.querySelectorAll(".cl-token-node"))
text = arr.filter(element => element.children[0].innerText === "*WORD_YOU_ARE_SELECTING*")[0].children[0].children[0]
var event = new CustomEvent("Test_SelectWord", {detail: text})
document.dispatchEvent(event, text)
Cypress can explicitly trigger events: https://docs.cypress.io/api/commands/trigger.html#Syntax
This may work for you:
cy.get(#element).trigger("change")
I am trying to bind a MetroUI modal dialog to an angular controller property. This way I can show and hide the dialog using binding.
DIRECTIVE
appMod.directive('showDialog', ['$timeout', function ($timeout): ng.IDirective {
return {
restrict: 'A',
link: function (scope, element, attrs, ngModel) {
scope.$watch(attrs.showDialog, function (value) {
if (value) {
element.show();
}
else {
element.hide();
}
});
}
}
}]);
HTML:
<div class="padding20 dialog" id="dialog9"
data-role="dialog" data-close-button="true"
data-overlay="true" data-overlay-color="op-dark"
show-dialog="vm.isDialogVisible">
This way I can control opening the dialog by setting the vm.isDialogVisible Boolean on my controller.
Problem is that I am trying to update the vm.isDialogVisible attribute when the user closes the dialog (via the close button). Anyone has some ideas how to fix that?
It is always cool to find your own solution (took me a day :-)). I made a mistake to use the show / hide features of the element. I should have used the data attribute of the element. That way I am able to access the
onDialogClose
function, which enable me to update the scope. Below my solution
appMod.directive(showDialog, ['$timeout','$parse',function ($timeout, $parse){
return {
restrict: 'A',
scope:false,
link: function (scope, element, attrs) {
var e1 = theDialog.data('dialog');
$timeout(() => {
e1.options.onDialogClose = (dialog) => {
var model = $parse(attrs.showDialog);
model.assign(scope, false);
scope.$digest();
};
}, 0);
scope.$watch(attrs.showDialog, function (value) {
if (value) {
e1.open();
}
else {
e1.close();
}
});
}
}
}]);
I am trying to populate the dojox/form/checkedMultiSelect with a top option named: 'select all'.
One way to do this is to use declare function to change the '_addOptionItem' function.
The problem is that this '_addOptionItem' function is using a declared object named: 'formCheckedMultiSelectMenuItem' inside the 'CheckedMultiSelect' widget, AND gives an error with: 'formCheckedMultiSelectMenuItem is not defined'.
How to fix this?
My JS code:
declare_CheckedMultiSelect: function(formCheckedMultiSelectItem){
return declare(CheckedMultiSelect, {
startup: function() {
this.inherited(arguments);
setTimeout(lang.hitch(this, function() {
this.dropDownButton.set("label", this.label);
}));
},
_addOptionItem: function(item){
var item;
if(this.dropDown){
item = new formCheckedMultiSelectMenuItem({
option: option,
parent: this.dropDownMenu
});
c(item)
this.dropDownMenu.addChild(item);
}else{
item = new formCheckedMultiSelectItem({
option: option,
parent: this
});
this.wrapperDiv.appendChild(item.domNode);
}
this.onAfterAddOptionItem(item, option);
}
});
}
Here is working prototype of what you are trying to achieve http://jsfiddle.net/894af/750/ please feel free to ask any follow up question. it is done in different way, but what I simply did is:
1) when create the mutliselect get each check box after creating using
onAfterAddOptionItem
2) listen to the select all checkbox and then override the onclick fucntion and then change the selection of all the checkboxs, based on the selection of the checkbox.
if(option.value == "SA"){
on(item, "click", function(evt){
var optionsToSelect = checkedMultiSelect.getOptions();
for(var i = 0 ; i < optionsToSelect.length;i++){
if(optionsToSelect[i].value == "SA"){
if(optionsToSelect[i].selected){
checkedMultiSelect.set("value",optionsToSelect);
}else{
checkedMultiSelect.set("value",[]);
}
}
}
});
}