When I click the button with text 'Create' the text is replaced to 'Confirm?'
This is the HTML:
and the pageObject:
create() {
return cy.get('im-page.hydrated', { includeShadowDom: true })
.find('im-button', { includeShadowDom: true })
.eq(1)
.find('button', { includeShadowDom: true })
.click({ force: true })
}
confirmBtn() {
return cy.get('im-page.hydrated').find('im-button')
.eq(1)
.find('button.success.outline')
.contains('Confirm?')
}
Then when Cypress click on Confirm I got this error:
There's an issue logged doc.createTreeWalker is not a function #20813 but not yet resolved.
From the source code the doc part refers to the previous subject, i.e the element before the .find() which above is cy.get('im-page.hydrated').find('im-button').eq(1).
My guess is because the button changes on the Create click, something in that previous subject becomes invalid when you try to access the Confirm button.
A couple of ideas to try (just guesses at this stage)
// using jquery to avoid the treeWalker (used by the .find() command)
cy.get('im-page.hydrated im-button:eq(1) button.success.outline:contains(Confirm)')
// using an alias and "withinSubject" option to explicitly define `doc`
cy.get('im-page.hydrated im-button:eq(1)`).as('parent')
cy.get('#parent').then($parent => {
cy.get('button.success.outline:contains(Confirm)', { withinSubject: $parent })
You should turn on shadowDOM globally to avoid missing any parts that need it.
// cypress.json
{
...
"includeShadowDom": true
}
#3 - just do a simple search for "Confirm", since likely only one thing at a time needs confirming.
cy.contains('button.success.outline', 'Confirm')
Related
I updated my ionic3 to ionic4 and hyperlinks aren't working anymore. So I tried to set a new ClickEvent for them. Unfortunately the click event doesn't work. The content of my event is never reached even If I click some link. I don't get why it's not working.
ngAfterViewChecked() {
if (!this._element) return;
let arrUrls = this._element.nativeElement.querySelectorAll('a');
console.log("arrUrls.length:", arrUrls.length); // Reached and correct
console.log("arrUrls:", arrUrls); // Reached and correct
this.setEventListener(arrUrls);
}
private setEventListener(arrUrls)
{
arrUrls.forEach((objUrl) =>
{
console.log('5412212112121212'); // Reached
console.log(objUrl); // Reached and correct
// Listen for a click event on each hyperlink found
objUrl.addEventListener('click', (event) =>
{
//NOT REACHED
event.preventDefault();
alert('7213983728912798312231'); // Isn't reached
//this._link = event.target.href;
}, false);
});
}
You don't really need to get so detailed and write this all yourself.
Other people have already solved the problem such as the LinkifyJS project.
There is an angular compatible wrapper for it:
https://www.npmjs.com/package/ngx-linkifyjs
Which, once you have done the standard setup process you can use it as either a pipe:
<span [innerHTML]="'Linkify the following URL: https://github.com/anthonynahas/ngx-linkifyjs and share it <3' | linkify"></span>
Or as a service:
import {NgxLinkifyjsService, Link, LinkType, NgxLinkifyOptions} from 'ngx-linkifyjs';
constructor(public linkifyService: NgxLinkifyjsService) {
const options: NgxLinkifyOptions =
{
className: 'linkifiedYES',
target : {
url : '_self'
}
};
this.linkifyService.linkify('For help with GitHub.com, please email support#github.com');
// result 1 --> see below
this.linkifyService.linkify('For help with GitHub.com, please email support#github.com', options);
// result 2 --> see below
}
}
I am adding new textarea elements via AJAX, so I wrote the function assignRichText() below which adds CKEDITOR to any textarea.addckeditor, then removes the addckeditor class so it isn't added a second time later. This seems to work.
However, I am also calling the function updateRichText() below when doing AJAX saves, because otherwise my textarea elements are not updated (since I'm not submitting the form). In my console I see that the function is starting and ending, however the console.log('i='+i); never puts anything in my console. So my instances are not being picked up. Is there something wrong with my "for" statement?
function assignRichText(){
$('textarea.addckeditor').each(function(){
ClassicEditor
.create(document.querySelector('textarea.addckeditor'), {
toolbar: ['bold', 'italic']
})
.then(editor => {
console.log(editor);
})
.catch(error => {
console.error(error);
});
$(this).removeClass('addckeditor');
});
}
function updateRichText(){
console.log('start updateRichText');
for (var i in ClassicEditor.instances){
console.log('i='+i);
ClassicEditor.instances[i].updateElement();
}
console.log('end updateRichText');
}
I have been working with nightmare.js to run tests using mocha. This is my first time working with these framework/libraries. I am currently creating a test that loads a login page on a web app im working on and attempts to sign in. This is the code I am using as a reference
Source: https://segment.com/blog/ui-testing-with-nightmare/
describe('Login Page', function () {
describe('given bad data', () => {
it('should fail', done => {
nightmare
.goto('https://gethoodie.com/auth')
.on('page', (type, message) => {
if (type == 'alert') done()
})
.type('.login-email-input', 'notgonnawork')
.type('.login-password-input', 'invalid password')
.click('.login-submit')
.wait(2000)
.end()
.then()
.catch(done)
})
})
The main question I have about tis code is the .type and .click functions. Reading the nightmare api both of these functions work like so
.type(selector[, text])
Enters the text provided into the selector element. Empty or falsey values provided for text will clear the selector's value..type(selector[, text])
I have tried to implement this functionality using the code below
describe('/ (authentication)', () => {
it('should pass by logging into the system', done => {
// testing urls will be `http://localhost:port/path`
nightmare.goto('http://localhost:4000/login')
.on('page', (type, message) => {
if (type === 'alert') done()
})
.type('input[id="username"]', 'admin')
.type('input[id="password"]', 'toetagging')
.click('button[data-reactid=".0.0.1.3.0"]')
.wait(2000)
.end()
.then()
.catch(done)
})
})
My main question is, what exactly is the selector and how do I get it?
A selector is useful to match some node(s) in the DOM. Suppose, you have the following DOM:
<div class="login-submit">
<input id='input-login' type="text" class="fancy" name="login" />
</div>
To select the input box, you can use the following selectors, as you would with CSS:
input.fancy
.login-submit input
#input-login
input[name=login]
Let's say that with nightmare you wanted to type into the input box, you could use the following code:
nightmare.type('input[name=login]', 'superwoman')
Here 'input[name=login]' is a selector, and 'superwoman' is the text that you want nightmare to type inside the input line.
It's trivial to test if an element is clickable with Protractor, but I'm stuck scratching my head trying to figure out how to check if an element is not clickable.
I've attempted to wrap the click function in a try/catch so that when an error is thrown when trying to click it should catch it and let the test pass; however, this does not work.
Here is my code for the method that does the check:
return this.shouldSeeDisabledFunds()
.then(function() {
var clickable = true;
try {
fundsElem.first().click();
} catch (e) {
clickable = false;
console.log(clickable);
} finally {
console.log(clickable);
}
console.log(clickable);
// All the way through, clickable is still true, and the console log in the
// catch is not called. I believe this is because click is asynchronous.
})
;
I have found a solution that works for this. As click() returns a promise you can simply .then off of it and throw in the successful click handler and override the catch handler to do nothing which makes the test pass if the element is not clickable.
return this.shouldSeeDisabledFunds()
.then(function() {
fundsElem.first().click()
.then(
function() {
throw "Can click Funds element that should be disabled";
},
function() {}
)
;
})
;
Maybe not applicable in your case, but a better way to check if an element is clickable is checking if it is both visible and enabled: elem.isDisplayed() and elem.isEnabled(). This way you don't accidentally click on buttons when you're not supposed to.
Fyi, there will be a library coming to help with cases like this: https://github.com/angular/protractor/pull/1703
There are actually two methods to check it.
1) Using ExpectedConditions
var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to not be clickable.
browser.wait(EC.not(EC.elementToBeClickable($('#abc'))), 5000);
If found to be clickable, it will return error.
2) Using protractor's isEnabled, isDisplayed and isPresent
So as far as my understanding goes, you can create isNotClickable, which will return false only if element is present, displayed or enabled and true otherwise:
function isNotClickable(element) {
return element.isPresent().then((isPresent) => {
if (isPresent) {
return element.isDisplayed().then((isDisplayed) => {
if (isDisplayed) {
return !element.isEnabled();
}
return true;
});
}
return true;
});
}
To verify Clickable : element.isDisplayed().toBe(true)
Not Clickable : element.isDisplayed().toBe(false)
Worked for me.
If the user presses the down key while a custom popup is displayed, I would like this down event to be cancelled from the editor and handled manually.
However, if the popup is disactivated, the 'down' key should perform as usual.
For that, I wrote this:
editor.commands.addCommand({
name: 'nav_down.',
bindKey: {win: 'Down', mac: 'Down'},
exec: function(editor) {
if(myPopupIsOpen()) {
// Do whatever I want with the popup.
return false;
} else {
// just leave the key.
return true;
}
readOnly: true
});
Unfortunately, I can return false or true, the result is the same, it always capture the down event, which is annoying. How can I prevent that?
I already tried the following:
Add a key binding to the DOM. But after that, the interaction always happen (i.e. I cannot capture it).
Return false or true as suggested for common events but this does not work here.
EDIT
The solution from #a user works very well.
Instead of the above command, I wrote:
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
keyboardHandler = new HashHandler();
keyboardHandler.addCommand({
name: 'nav_down.',
bindKey: {win: 'Down', mac: 'Down'},
exec: function(editor) {
if(myPopupIsOpen()) {
// Do whatever I want with the popup.
return true; // CHANGE HERE ! true is when it capture it.
} else {
// just leave the key.
return false; // CHANGE HERE ! false is when I don't capture it.
}
readOnly: true
});
editor.keyBinding.addKeyboardHandler(keyboardHandler);
In the current version ace only keeps one command for each key so your addCommand call removes default binding for down.
You can add new keyboard handler similar to what autocompletion does https://github.com/ajaxorg/ace/blob/v1.1.3/lib/ace/autocomplete.js#L221
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
keyboardHandler = new HashHandler();
keyboardHandler.addCommand(/*add your command with return false*/)
editor.keyBinding.addKeyboardHandler(keyboardHandler);