3

I would like to have some testcase to compare tolPage text value is the same as curPage text value like following. but it does not work, how should i pass element text from cypress chain to local variable

class Menu{ tolPage() { return cy .get(selectors.pagination.totalPageCount) .invoke('text') .then((text) => { return text.toString(); }); } curPage() { return cy .get(selectors.pagination.currentPageCount) .invoke('text') .then((text) => { return text.toString(); }); } } describe('check two function should be eq') { const menu = new Menu(); it('Verified "', () => { let text = menu.curPage(); # menu.tolPage().should('be.eq', text)); # menu.tolPage().should('be.eq', menu.curPage()); }); } 

1 Answer 1

4

You should read the part of the documentation that handles the async behaviour of cypress: https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Commands-Are-Asynchronous

So you can not assign menu.curPage() to a variable and expect that this variable contains the text.

So this will fail. testVar is still null when the expect line is reached:

it("test", () =>{ let testVar = null; cy.get("body").then(() => { testVar = 5; }) expect(testVar).to.eq(5) }) 

Instead you can write it this way (depends on what and how you want to test):

it("test", () =>{ let testVar = null; cy.get("body").then(() => { testVar = 5; }) cy.get("body").should(() => { expect(testVar).to.eq(5) }) }) 

so based on your code, your solution might look similar to this:

 describe('check two function should be eq') { const menu = new Menu(); it('Verified "', () => { menu.curPage().then(cPText => { menu.tolPage().then(tPText => { expect(cPText).to.eq(tPText); }) }); }); 

This nesting of commands can be annoying if you must check more than two text values. To make your life easier, you can do this:

describe("test", () => { beforeEach(() => { cy.visit("https://cypress.io") }) it("test", () => { getCaption(); getSubCaption(); // attention: function() syntax is required to keep `this` context cy.get("body").should(function() { expect(this.caption.indexOf("testing") > -1).to.eq(this.subcaption.indexOf("testing") > -1) }); }) }) function getCaption() { return cy.get(".Hero-TagLine.mt-0").invoke("text").as("caption"); } function getSubCaption() { return cy.get(".Hero-ByLine.mb-0").invoke("text").as("subcaption"); } 

I have added an own example so I was able to provide you a runnable and working example. But you can adjust it to fit your code easily. What happens:

  • cy.get().invoke("text").as("alias") does the same as in your code, except that it stores the textcontent in an alias. Cypress also creates a new instance variable for every alias, so you are able to access it through this.caption.
    • Using this approach you can easily store 10 and more text elements and then access them in a flat hierarchy
    • But be aware of the function () syntax. You can not use the phat arrow syntax because then your this context is wrong
    • also you can take advantage of the repeat functionality of the should command. It will retry your callback until no assert fails or until the timeout is reached
    • this works in Typescript, too. But of course, Typescript does not know the properties this.caption and this.subcaption. So you will have to cast this to any before or adjust the type definitions

Btw: I saw that you make this: cy.get().invoke("text").then(t => t.toString()) in order to fix the types in TS. You can avoid this by using a own type definition:

declare global { namespace Cypress { interface Chainable { invoke(fn: "text"): Cypress.Chainable<string>; } } } 

This can be removed after https://github.com/cypress-io/cypress/issues/4022 is merged.

Sign up to request clarification or add additional context in comments.

4 Comments

This is the typical Cypress answer to people asking about getting and storing values. It answers something else than what the question is about. Say you have an e2e test that wants to check persistance of data over several pages. How does assertions and chaining inside then() help with that? When you need to store a value, then at som later point compare that value to a value on another page? That's an important point of end-to-end- testing, and it seems that people simply doesn't understand it. If all your tests set up data and do all the assertions at onece, it works. But that's not enough.
@Hfrav i am not sure if I understand your problem. You want save values across several test suites? Within one suite the approach above should do what you want. If not, please give me a little example with pseudo code so I can better understand.
No point. I found out that it's simply not possible to do the following in Cypress: Open a page, get a value from the page, store that value in a variable, open a new page and compare an element on that page with the stored value (element from other page). This is just one more argument that Cypress is more a "unit test tool for developers" than a full-fledged e2e-testing tool. To get around this, the only solution is to have hard-coded test data, and everyone who knows anything about testing knows that that is very often not desirable.
@Hfrav at least as of November, 2022 (cypress version 10.8.0), the situation you described is well covered by this answer. In my particular case, I'm storing a DOM element's text in a variable using as (doing something like cy.dataCy("row-0-name").invoke("text").as("name0")). Then I run a cy.visit(...) (which refreshes the page), and then I can correctly read name0 using cy.get("@name0").then((name0) => {...}).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.