Cypress - Aliases : Cannot read properties of undefined (reading 'todoItem') - cypress

I'm using Cypress and I have an error when I try to access to "todoItem" text in the "expect(this.todoItem).to.eq('New Todo')" line.
Any ideas on how to access the "todoItem" text?
beforeEach(() => {
cy.get(".new-todo").type("New Todo {Enter}");
cy.get(".todo-list>li:nth-child(1)").invoke("text").as("todoItem");
});
it("gets added todo item", () => {
expect(this.todoItem).to.eq("New Todo");
});

If you want to reference a Cypress alias using this, you need to use a regular function instead of an arrow function.
it('gets added todo item', function () {
expect(this.todoItem).to.eq('New Todo');
});
You can also reference the alias by using cy.get(). This may be advantageous in situations where you want the alias to be used asynchronously in the Cypress command chain.
it('gets added todo item', () => {
cy.get('#todoItem').should('equal', 'New Todo');
});

Related

How to wait for the api call to finish and then check if element present using cypress?

i am new to cypress and i am trying to check if the element exists on a page once the api call is finished.
i do a http post to url 'things/thing1' and once this api finishes i want to check if span element is present on page.
i have tried something like below.
const setUp = () => {
cy.apiPatchSomethings(something1)
.then(() => {
cy.reload();
});
}
describe('Suite name', () => {
before(() => {
setUp();
});
it('test case', () => {
cy.contains('span');
}
});
the above code doesnt work. even before span element is seen on page it checks for span element.
if i use cy.wait(10000) like below it works
it('test case', () => {
cy.wait(10000);
cy.contains('span');
});
but i dont want to use cy.wait. is there some other way to solve this. could someone help me with this. thanks.
Cypress command cy.contains() when called with a single argument is looking for content,
Syntax
cy.contains(content)
cy.contains(content, options)
cy.contains(selector, content)
cy.contains(selector, content, options)
but I'm guessing you are looking for a span element, so use
cy.get('span')
or
cy.contains('span', 'my-content-in-span')
Assuming that's not the problem, just some arbitrary sample code...
Your can modify the setup function to return a promise, in order to wait for the reload.
const setUp = () => {
return cy.apiPatchSomethings(something1) // need a return here
.then(() => {
return new Cypress.Promise(resolve => { // inner return also
cy.reload()
resolve(true) // resolve will signal reload is finished
})
});
}
Because setup() is invoked inside before() Cypress will wait for the promise to resolve before proceeding.
Please don't add extra waits or timeouts, which is too often suggested. This will only lead to flaky tests.
Note if you don't mind ditching the setup() function, it becomes a lot simpler
describe('Suite name', () => {
before(() => {
cy.apiPatchSomethings(something1)
.then(() => cy.reload() ); // all commands here will be completed
// before the tests start
});
it('test case', () => {
cy.contains('span', 'my-content-in-span');
}
});
1.You can wait for span to be visible. The default timeout that cypress provides is 4 seconds.
cy.contains('span').should('be.visible')
2.If you want to give a custom timeout(eg. 10 sec) specific to this command, you can use:
cy.contains('span', { timeout: 10000 }).should('be.visible')
3.If you want to increase the timeout globally you mention this in your cypress.json file:
"defaultCommandTimeout": 10000
and, then just use:
cy.contains('span').should('be.visible')
Now, all your commands will have a default timeout for 10 seconds.

Cypress custom command wont return value

I have a function that I want to add as a command so i can reuse it.
Its on cypress/support/commands.js:
Cypress.Commands.add("generatePassword", () => {
return 'randomstring';
}
);
Then on my test I want to use it as:
it("Visits page", () => {
const password = generatePassword();
cy.log({password})
// Here it logs this:
//{password: {chainerid: chainer146, firstcall: false}}
});
Any idea on how to get the actual value? Now i get this:
{chainerid: chainer146, firstcall: false}
Thanks.
Basically cypress works in promise chain and you're returning the promise chainerid from your custom command. You have to chain it to use in next statement. Use something like below.
it("Visits page", () => {
return cy.generatePassword().then(pwd => {
cy.log(pwd);
});
});

Error message when using aliases with cypressIO

I get the following error message when using: "TypeError: Cannot read property 'text' of undefined"
I´ve done exactly as they do in the documentation: https://docs.cypress.io/guides/core-concepts/variables-and-aliases.html#Aliases
Can anyone see what i´m doing wrong?
beforeEach(() => {
cy.visit('http://localhost:4200/');
loginPage.login();
timeFilter.button.click();
cy.get('#title').invoke('text').as('text');
});
it('should show text', () => {
console.log(this.text);
});
Read the cypress documentation and the problem i did was using arrow functions and i did not access the alias in a closure using a .then(). As soon as i did this, it worked:
cy.get('#title').invoke('text').as('text');
it('should show text', () => {
cy.get('#main').then(function () {
console.log(this.text);
});
});
OR use function() instead of () => on the it() callback
cy.get('#title').invoke('text').as('text');
it('should show text', function() {
console.log(this.text);
});
Text has always been a pain in cypress. This could be one of a few things:
1) Sometimes this.alias doesn't work, try using:
cy.get('#text').then(text => console.log(text));
2) If the text is contained in an element below #title, you will have to get that specific element. For example, #title might be a div, which contains an h1 element inside of it, so in that case you would need to use #title > h1 as your selector. Post your HTML and I'll be able to tell if that's the case
3) invoke('text') almost never works, I'm not sure why. I find this works much more often cy.get('#title').then($el => el.text())

React Redux thunk - Chaining dispatches

Currently i'm building an application that is heavily dependant on API calls. The api calls are done within Redux actions with Thunk middleware like so:
export const brand_fetchAll = () => {
return dispatch => {
fetch(apiURL+'brand')
.then(response => {return response.json();})
.then(content => {
dispatch({
type: 'BRAND_STORE_ALL',
content
})
})
.catch(error => console.log(error))
}}
In my component, i'm first fetching the data through separate actions. After that i'm opening up an editor:
// A component method
editModeOn(){
// Fetch data
this.props.dispatch(campaign_fetchAll());
this.props.dispatch(brand_fetchAll());
// Open editor
this.props.dispatch(page_editModeOn());
}
Right now the editor opens before the api calls have completed, so no data is being shown. It's possible to chain the dispatches within the actions, but i want to keep the modularity, so i don't have to create hundreds of custom API calls. Ideally what i want is to chain them using something like promises:
// A component method
editModeOn(){
this.props.dispatch(campaign_fetchAll().then(brand_fetchAll()).then(page_editModeOn());
}
Unfortunately i didn't yet get that to work. I hope someone can help me out. If you need more information i'm happy to hand it over. Better ideas are also very welcome :)
Thanks in advance!
Would a callback function be an option for you?
So update your code to be;
export const brand_fetchAll = (callback) => {
return dispatch => {
fetch(apiURL+'brand')
.then(response => {return response.json();})
.then(content => {
dispatch({
type: 'BRAND_STORE_ALL',
content
});
callback();
})
.catch(error => console.log(error))
}}
// A component method
editModeOn(){
// Fetch data
this.props.dispatch(campaign_fetchAll());
this.props.dispatch(brand_fetchAll(() => {
// Open editor
this.props.dispatch(page_editModeOn());
}));
}
You are chaining the callback onto the end of the api call success, however, you are not tightly coupling what it is as you are passing this in depending on the usage.

access the output of get in then block

how to access the element that is yielded from .get().contains() in .then() function
My code is not entering the Then block. where am i doing wrong ?
cy.get(".c-header-listItem").contains("My Account").should(($link) => {
expect(localStorage.read("CD-SessionId")).to.be.not.null;`enter code here`
}).then(($link) => {
$link.click();
});
I got the login from Cypress documentation https://docs.cypress.io/api/commands/should.html#Subjects
.should(elem => {}) behaves exactly as .then(elem => {}), except that the function passed to the should will retry until it doesn't throw any exceptions. With that in mind, the following code should work:
cy.get(".c-header-listItem").contains("My Account").should(($link) => {
expect(localStorage.read("CD-SessionId")).to.be.not.null;
// Notice I have to wrap this to perform a Cypress
// click on it. $link is a native DOM object.
cy.wrap($link).click();
});
This would also work, but the separation isn't necessary.
cy.get(".c-header-listItem").contains("My Account").should(($link) => {
expect(localStorage.read("CD-SessionId")).to.be.not.null;
});
cy.get(".c-header-listItem").contains("My Account").click();

Resources