I'm new with Cypress and I'm trying to implement some easy tests using an already existing webpage. I'm a little bit confused about the result, because I call invoke() twice: the first time to check the initial value (0%), and the second one to set a new value and check the change, but it doesn't work, and it tells me that it cannot find the attribute I'm searching for. The code is the following:
describe('My first test', function(){
beforeEach(() => {
cy.visit("https://www.wikiwand.com/en/IPv4")
})
it('test1', function() {
const opt = cy.get("#main_menu > li").eq(3).click()
const sty = opt.get(".noUi-origin").first()
sty.invoke("attr", "style").should("include", "left: 0%;")
sty.invoke("attr", "style", "left: 100%;").should("have.attr", "style", "left: 100%;")
})
})
I simply take the personalize button on the menu bar, and I want to change the value serif or sans. There is a problem with the order of the two invoke()? The error is:
*Timed out retrying after 4000ms: cy.invoke() errored because the property: attr does not exist on your subject.
cy.invoke() waited for the specified property attr to exist, but it never did.
If you do not expect the property attr to exist, then add an assertion such as:
cy.wrap({ foo: 'bar' }).its('quux').should('not.exist')*
on
sty.invoke("attr", "style", "left: 100%;").should("have.attr", "style", "left: 100%;")
Has someone an idea about it?
CodePudding user response:
Cypress commands run in a "chain", with the current "subject" being passed from one command to the next.
Although you think you are saving a reference to the element in const sty = ...
, actually you are saving a pointer to the internal Cypress subject.
When you do sty.invoke("attr", "style")
, you have now changed the subject to that style attribute, not the element.
So when you try to sty.invoke("attr", "style")
again, sty
no longer has an attr
method, hence the error.
More conventional way is not to store command results.
Just re-query
const opt = cy.get("#main_menu > li").eq(3).click()
cy.get(".noUi-origin").first()
.invoke("attr", "style")
.should("include", "left: 0%;")
cy.get(".noUi-origin").first()
.invoke("attr", "style", "left: 100%;")
.should("have.attr", "style", "left: 100%;")
Or use an assertion that does not change the subject
const opt = cy.get("#main_menu > li").eq(3).click()
cy.get(".noUi-origin").first()
.should("have.css", "left", "0px") // keeps the same subject
.invoke("attr", "style", "left: 100%;")
.should("have.attr", "style", "left: 100%;")
CodePudding user response:
So the Font slider when it is Serif the style is left: 0%;
and when you drag the slider to Sans the style is left: 100%;
. So your test should look like this:
cy.visit("https://www.wikiwand.com/en/IPv4");
cy.get("#main_menu > li").eq(3).click();
cy.get(".noUi-origin")
.first()
.invoke("attr", "style")
.should("include", "left: 0%;");
cy.get('[ng-click="$root.fontStyleHandler(1, true)"]').click(); //Drags the slider from Serif to Sans
cy.get(".noUi-origin")
.first()
.invoke("attr", "style")
.should("include", "left: 100%;");
Or, if you don't want to use the slider then you have to first remove the style attribute and then add the style attribute with value left: 100%;
, in that case your test should look like:
cy.visit("https://www.wikiwand.com/en/IPv4")
cy.get("#main_menu > li").eq(3).click()
cy.get(".noUi-origin")
.first()
.invoke("attr", "style")
.should("include", "left: 0%;")
cy.get(".noUi-origin").first().invoke("removeAttr", "style")
cy.get(".noUi-origin").first().invoke("attr", "style", "left: 100%;")
cy.get(".noUi-origin")
.first()
.invoke("attr", "style")
.should("include", "left: 100%;")