Cypress can test anything that runs in a browser.
This will be a series of articles about cypress from basic to advanced (maybe). If there is something you do not understand, error, do not hesitate to comment.
Login problem
Perhaps one of the first tests that was the hardest was the login screen test.
This screen test is very prone to miss cases since we have to check the correctness of a lot of input from the user. Furthermore, almost every function of a given system always requires user authentication. Therefore, having to perform login in function test files is a prerequisite. So if we write this non-optimal processing, it will slow down functionality testing significantly.
So you can follow these tips.
Completely test the login function in a single run
Since this has always been a very important function in systems, let’s test it out with realism. The most realistic here is to make the most of the user. So when you want to fully test the login or signup function, then test by interacting with the UI (login using UI) exactly the same as the user. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="token function">describe</span> <span class="token punctuation">(</span> <span class="token string">'The Login Page'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">beforeEach</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// reset and seed the database prior to every test</span> cy <span class="token punctuation">.</span> <span class="token function">exec</span> <span class="token punctuation">(</span> <span class="token string">'npm run db:reset && npm run db:seed'</span> <span class="token punctuation">)</span> <span class="token comment">// seed a user in the DB that we can control from our tests</span> <span class="token comment">// assuming it generates a random password for us</span> cy <span class="token punctuation">.</span> <span class="token function">request</span> <span class="token punctuation">(</span> <span class="token string">'POST'</span> <span class="token punctuation">,</span> <span class="token string">'/test/seed/user'</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> username <span class="token operator">:</span> <span class="token string">'jane.lane'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">its</span> <span class="token punctuation">(</span> <span class="token string">'body'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">as</span> <span class="token punctuation">(</span> <span class="token string">'currentUser'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token function">it</span> <span class="token punctuation">(</span> <span class="token string">'sets auth cookie when logging in via form submission'</span> <span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// destructuring assignment of the this.currentUser object</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> username <span class="token punctuation">,</span> password <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> currentUser cy <span class="token punctuation">.</span> <span class="token function">visit</span> <span class="token punctuation">(</span> <span class="token string">'/login'</span> <span class="token punctuation">)</span> cy <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'input[name=username]'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">type</span> <span class="token punctuation">(</span> username <span class="token punctuation">)</span> <span class="token comment">// {enter} causes the form to submit</span> cy <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'input[name=password]'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">type</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> password <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">{enter}</span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token comment">// we should be redirected to /dashboard</span> cy <span class="token punctuation">.</span> <span class="token function">url</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">should</span> <span class="token punctuation">(</span> <span class="token string">'include'</span> <span class="token punctuation">,</span> <span class="token string">'/dashboard'</span> <span class="token punctuation">)</span> <span class="token comment">// our auth cookie should be present</span> cy <span class="token punctuation">.</span> <span class="token function">getCookie</span> <span class="token punctuation">(</span> <span class="token string">'your-session-cookie'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">should</span> <span class="token punctuation">(</span> <span class="token string">'exist'</span> <span class="token punctuation">)</span> <span class="token comment">// UI should reflect this user being logged in</span> cy <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'h1'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">should</span> <span class="token punctuation">(</span> <span class="token string">'contain'</span> <span class="token punctuation">,</span> <span class="token string">'jane.lane'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
beforeEach()
: contains the handles that will always be run before starting the test. Similar to afterEach()
cy.exec()
: run system commands, terminal
We see that in the test case there will be the corresponding actions entering the data in the username and password fields. It is easy to see that we are describing the same action the user does.
From there we can write all test cases to fully test this functionality, for example test cases like:
- Invalid username / password
- The account has been locked or deleted
- …
Cypress will have test strategies for common, and popular functions here .
Skip testing on the UI in certain cases
If a function needs to be logged in, then we run the login process again and test, and then test that function, which is considered not optimal and unnecessary. We need to minimize the authentication process because we have tested it completely before. One of the simplest ways here is to avoid doing login operations on the UI, and instead use the API.
Therefore, please note the following 2 things .
When you are writing tests for a particular function, you should test it on the UI.
But when you test a certain function of the system that depends on the state from the above function, you cannot use the UI to set this state.
Let’s see the example login via API using cy.request()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | <span class="token function">describe</span> <span class="token punctuation">(</span> <span class="token string">'The Dashboard Page'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">beforeEach</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// reset and seed the database prior to every test</span> cy <span class="token punctuation">.</span> <span class="token function">exec</span> <span class="token punctuation">(</span> <span class="token string">'npm run db:reset && npm run db:seed'</span> <span class="token punctuation">)</span> <span class="token comment">// seed a user in the DB that we can control from our tests</span> <span class="token comment">// assuming it generates a random password for us</span> cy <span class="token punctuation">.</span> <span class="token function">request</span> <span class="token punctuation">(</span> <span class="token string">'POST'</span> <span class="token punctuation">,</span> <span class="token string">'/test/seed/user'</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> username <span class="token operator">:</span> <span class="token string">'jane.lane'</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">its</span> <span class="token punctuation">(</span> <span class="token string">'body'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">as</span> <span class="token punctuation">(</span> <span class="token string">'currentUser'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token function">it</span> <span class="token punctuation">(</span> <span class="token string">'logs in programmatically without using the UI'</span> <span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// destructuring assignment of the this.currentUser object</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> username <span class="token punctuation">,</span> password <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> currentUser <span class="token comment">// programmatically log us in without needing the UI</span> cy <span class="token punctuation">.</span> <span class="token function">request</span> <span class="token punctuation">(</span> <span class="token string">'POST'</span> <span class="token punctuation">,</span> <span class="token string">'/login'</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> username <span class="token punctuation">,</span> password <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token comment">// now that we're logged in, we can visit</span> <span class="token comment">// any kind of restricted route!</span> cy <span class="token punctuation">.</span> <span class="token function">visit</span> <span class="token punctuation">(</span> <span class="token string">'/dashboard'</span> <span class="token punctuation">)</span> <span class="token comment">// our auth cookie should be present</span> cy <span class="token punctuation">.</span> <span class="token function">getCookie</span> <span class="token punctuation">(</span> <span class="token string">'your-session-cookie'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">should</span> <span class="token punctuation">(</span> <span class="token string">'exist'</span> <span class="token punctuation">)</span> <span class="token comment">// UI should reflect this user being logged in</span> cy <span class="token punctuation">.</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token string">'h1'</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">should</span> <span class="token punctuation">(</span> <span class="token string">'contain'</span> <span class="token punctuation">,</span> <span class="token string">'jane.lane'</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
Obviously we save time on login manipulation and testing as it is only the prerequisite of the main function we need to test. Then, just login through the API and operate, test on the main function you need.
Explore more
- Recipes – built-in test strategies for common functions.
- Best Practices – these are hands-on exercises with essential test writing tips.