I'd like to verify the text content of a pseudo-element. The promise returned from using ptor.executeScript("window.getComputedStyle(jQuery('.my-class')[0], ':after').content").then(function(data){
console.log(arguments) // {'0':null}
});
I've also tried dropping that in the expectation, but I'd guess that fails for the same reason.
Since the CSS Declaration for this is pointing at one of the element's attributes anyway, should I just try to read that attribute?
executeScript will waits for you to return a value - so you'll need to do:
ptor.executeScript("return window.getComputedStyle(jQuery('.my-class')[0], ':after').content")
.then(function(data){ console.log(arguments)});
As an updated answer based up the one from our good friend Julie aka "Protractor Wizard."
I didn't have jQuery available to get my pseduo-element so I did this...
describe('#swPopover Component', () => {
it('should show the popover message when hovered', () => {
browser.actions().mouseMove(objectsPage.popover).perform();
browser.executeScript('return window.getComputedStyle(document.querySelector(".sw-popover"), ":after").content')
.then(data => expect(data).toBe('"I am the popover text"'));
});
});
Related
I am currently new to cypress and wants to test that Forgot Password should be below Login button in Facebook page? Is there a way to do that?
Is there a way to test relative positioning of elements in cypress?
I think you can use jQuery .position()
cy.get('#element1')
.then($el => $el.position().top) // get 1st top value
.then(top1 => {
cy.get('#element2')
.then($el => $el.position().top) // get 2nd top value
.then(top2 => {
expect(top1).to.be.gt(top2)
})
})
Notes
Cypress use jQuery to find elements. Chaining .then($el => ... exposes the jQuery object containing the element, so now you can apply other jQuery functions that are not part of the Cypress commands.
In fact, any other Javascript functions you want.
You can also make reusable functions
const getTop = ($el) = $el.position().top;
cy.get('#element1').then(getTop)
.then(top1 => {
cy.get('#element2').then(getTop)
.then(top2 => {
expect(top1).to.be.gt(top2)
})
})
You can use the cypress method next() to determine the element next to Log in button like this. next() gets the immediately following sibling of each DOM element within a set of DOM elements.
cy.get('div[type="submit"]').next().should('have.text', 'Forgot password?')
I am trying to test the login functionalities using cypress, but for some reason I am unable to access the input text-box.
It shows Timed out retrying after 4000ms: Expected to find element: runner container, but never found it.
describe("User authentication", () => {
beforeEach(() => {
cy.visit("https://lmflf.com");
});
it("it takes to the correct page", () => {
cy.get('[data-field=password]')
});
});
I could see a shadow DOM in your webpage and in that case you have to use .shadow()(Cypress Docs). Your code would look something like:
cy.get('view-login').shadow().find('input[data-field="username"]').type('username', {force: true})
cy.get('view-login').shadow().find('input[data-field="password"]').type('password', {force: true})
cy.get('view-login').shadow().find('input[value="personal"]').click()
cy.get('view-login').shadow().find('.ViewLogin__button').click()
So I am having a very frustrating issue.
I am trying to grab a HTML element with React/JS which exists only in a library, not in my code so I can't use useRef or anything like that.
If I do this:
useEffect(() => {
const handleContainer = document.getElementsByClassName('handle-container');
console.log({ handleContainer: handleContainer[0] });
}, [document]);
It prints: { handleContainer: undefined }
But with this:
useEffect(() => {
const handleContainer = document.getElementsByClassName('handle-container');
console.log({ handleContainer });
}, [document]);
It prints this:
I am trying to disable the right click event on that element.
Like this:
document.getElementsByClassName('handle-container')?.[0]?.setAttribute('oncontextmenu', 'return false;');
But I am failing.
Any ideas?
Any ideas?
This most likely because the console is displaying the current state of the HTMLCollection being referenced using console.log({ handleContainer }); over the snapshot of the first element (which may not exist yet) which is happening when you perform console.log({ handleContainer: handleContainer[0] });...
Could you try adding a timeout like below and seeing what happens? This will hopefully give enough time for the library and DOM to load up and make it queryable at effect function run...
useEffect(() => {
setTimeout(() => {
const handleContainer = document.getElementsByClassName('handle-container');
console.log({ handleContainer: handleContainer[0] });
}, 1000);
}, [document]);
If this shows the expected element, then it would indicate that when the effect is called without a timer the class element that needs to be referenced using { handleContainer: handleContainer[0] } does not yet exist but because the console is displaying a reference of the HTMLCollection object using { handleContainer } it would would still display it in the console as it is not dereferencing it from the children array.
Refs: MDN - HTMLCollection
I'm trying to obtain the text from a element in protractor, and after doing something with the text, i want to click on the same element. This is what i have
HTML:
<span class="span-user" id="spanuser"> {{user?.login}}</span>
Protractor test:
describe('Login OK with correct pass', () => {
it('should login successfully with admin account', () => {
// logging
username.clear();
username.sendKeys('admin');
password.clear();
password.sendKeys('admin');
element(by.css('button[type=submit]')).click();
// check if the username <span> has the current login username
const expect2 = /admin/;
const spanuser = element(by.css('span#spanuser'));
spanuser.getText().then((value) => {
console.log('inside');
console.log(value ? value : 'no value');
expect(value).toMatch(expect2);
});
// then i try to click on the same span, to do some stuff
spanuser.click().then(() => {
console.log('It has been pressed!');
});
});
});
The first part works just fine, it gets the test and it passes the expect, but when i try to do the click() function on the span, i get the following error:
Failed: Timed out waiting for asynchronous Angular tasks to finish after 5 seconds. This may be because the current page is not an Angular application. Please see the FAQ for moredetails: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
While waiting for element with locator - Locator: By(css selector,
span#spanuser)
What have i tried:
browser.waitForAngular() before spanuser.click()
browser.wait(10000) before spanuser.click()
also i have a waitForAngular() in the beforeAll function.
Does anyone has a idea on this? It doesn't really make any sense to me, why wouldn't find the same element that has already found before?
Thanks a lot!
add browser.waitForAngularEnabled('false') in onPrepare of protractor conf.js
onPrepare: function() {
browser.waitForAngularEnabled('false')
// if you set this in onPrepare(), it will be a global setting, will
// effect all script, so you no need to set it in other place.
}
use the jasmin defaulttimeoutinterval in config instead of manual sleep
jasmineNodeOpts: {
defaultTimeoutInterval: 250000
},
allScriptsTimeout: 180000
I'm using cypress to write some tests against an html site..
The following selects me correctly a single tr elements from a table on my HTML site.
The site contents looks like this:
<tr data-recordid="theId">
<td...><div ..>Text 1</div></td>
<td...><div ..>Text 2</div></td>
<td...><div ..>Text 3</div></td>
</tr>
The following test script snippet selects me correctly the single <tr..> part.
cy.get('tr[data-recordid="theId"]').contains('Text')
Now I want to select the text within the <div>..</div> tags..The first thing I have tried to chain a single call for the first <div>..</div> tag like this:
cy.get('tr[data-recordid="theId"]').get('div').contains('Text')
which does not work as I expected. The get() calls a chained jQuery calls (Based on the Docs of cypress). So it looks like I misunderstand how things work in JQuery.
What I'm expecting is how I can check all div elements like this (Not working):
cy.get('tr[data-recordid="theId"]')..SomeHowMagic
.get('td[alt="xyz"]".get('div').contains('Text 1')
.get('td...').get('div').contains('Text 2')
.get('td...').get('div').contains('Text 3')
Any idea how to get forward a step? Missing any information just make a comment.
Let's clarify a few things:
1) If you are just wanting to ASSERT that the div's contain the given text then this is the best possible and most precise way to do this:
cy.get('tr[data-recordid="theId"]').should(($tr) => {
const $divs = $tr.find('div') // find all the divs
expect($divs.eq(0)).to.contain('Text 1')
expect($divs.eq(1)).to.contain('Text 2')
expect($divs.eq(2)).to.contain('Text 2')
})
I can't tell if things need to be this specific. If you only want to ensure that the $tr contains text you could simplify it down to be:
cy.get('tr[data-recordid="theId"]').should(($tr) => {
expect($tr).to.contain('Text 1')
expect($tr).to.contain('Text 2')
expect($tr).to.contain('Text 2')
})
Why do it this way?
Using a .should() function will not change the subject. Your $tr will continue to be the subject going forward.
Cypress will wait until all of the assertions in the .should() callback pass, and continually retry until they do. That guarantees you the state of multiple elements is correct before proceeding.
2) However if you just care that Cypress finds the text and you don't mind the subject being changed you could do this:
cy.get('tr[data-recordid="theId"]').within(() => {
cy.contains('Text 1') // changes the subject to the <div>
cy.contains('Text 2') // changes the subject to the <div>
cy.contains('Text 3') // changes the subject to the <div>
})
This is different than the first example because instead of an explicit assertion you are simply changing the subject to whatever element the text is found in. Cypress's default assertion on cy.contains() is to retry so ultimately the behavior is the same, except you are additionally changing the subject.
If even this is too complicated you could also just do this:
cy.get('tr[data-recordid="theId"] div').contains('Text 1')
cy.get('tr[data-recordid="theId"] div').contains('Text 2')
cy.get('tr[data-recordid="theId"] div').contains('Text 3')
Your original question was also using chained cy.get() which does not drill into subjects. For that to happen use .find()
cy.get('a').get('span') // each cy.get() queries from the root
cy.get('a').find('span') // the .find() queries from the <a>
One final note: you suggested solution does not work. cy.get() does not accept a callback function, and if you look at your Command Log you will not see those 3 cy.contains from ever being invoked. In other words, they are not running. That's why its passing.
So after more experimenting I found a solution:
cy.get('tr[data-recordid="TheId"]>td> div', function() {
cy.contains('Text 1').end()
cy.contains('Text 2').end()
cy.contains('Text 3').end()
})
If someone else has a better solution please post it here.