Cypress next-auth mail authentication  
Tags: node, cypress
Published: 2020-10-11 12:04:01

Authentication with email could simplify the signup process and prevent password mistakes. In the topic, we will use [next-auth](https://next-auth.js.org/getting-started/example) default email authentication method and test the workflow via cypress.

For quick start: [repo](https://github.com/pcreem/cypressAuth) 

> point check before cypress testing, make sure you can get the following results

* after signup with an email, a notification on the webpage  
![homepage](https://dev-to-uploads.s3.amazonaws.com/i/a1cfuqzhu9lfh29457i6.png)
* an email notification in Mailtrap inbox
![Mailtrap inbox](https://dev-to-uploads.s3.amazonaws.com/i/001gq79lvzqnfjgvlppw.png)
* webpage turn to login state with httpOnly cookie
![login](https://dev-to-uploads.s3.amazonaws.com/i/belpwqjeu2rq19g9mwhx.png)

## cypress authentication work flow

#### Aim to solve the following test:
* send an email after a user signup
* check the email has been received
* make sure the email contains the link to the homepage
* click the link in email redirect to the homepage 
* make sure the page turn to login state
* keep user login after page refresh 

#### Setting up

* `npx yarn add cypress`
* _optional_ `npx yarn add faker`
* A user signup with an email `code .\cypress\integration\sample_spec.js`
```
const faker = require('faker');
const randomEmail = faker.internet.email().toLowerCase();

describe('Login Test', () => {

    it('Visits the test page', () => {
      cy.visit('http://localhost:3000')
      cy.contains('Sign in').click()
      cy.url().should('include', '/api/auth/signin')

      cy.get('#input-email-for-email-provider')
        .type(randomEmail)
        .should('have.value', randomEmail)
    
        cy.contains('Sign in with Email').click()
        cy.contains('Check your email')
        
    });

    it('should send an email containing a verification link', () => {
        const inboxUrl = Cypress.env('inboxUrl')
        const token  = Cypress.env('Api-Token')

        cy.getLastEmail().then(html => {
     
          const link = html.match(/href="([^"]*)/)[1]
          cy.expect(link).to.contains('/api/auth/callback/email')
          cy.visit(link);
          cy.contains(`Signed in as ${randomEmail}`)
          cy.reload()
          cy.contains(`Signed in as ${randomEmail}`)
          //delete all mail
          cy.request({
            method: 'PATCH',
            url: `${inboxUrl}/clean`,
            headers: {
                'Api-Token': token,
                }
            });
        });
      });
  })


```

* API interacts with Mailtrap to get last mail 
`code .\cypress\support\commands.js`
```
const inboxUrl = Cypress.env('inboxUrl')
const token  = Cypress.env('Api-Token')

Cypress.Commands.add('getLastEmail', () => {
    function requestEmail() {
      return cy
        .request({
          method: 'GET',
          url: `${inboxUrl}/messages`,
          headers: {
            'Api-Token': token,
          },
          json: true,
        })
        .then(({ body }) => {
   
          if (body) {
            
            let msgId = body[0].id
            cy.request({
            method: 'GET',
            url: `${inboxUrl}/messages/${msgId}/body.html`,
            headers: {
                'Api-Token': token,
            },
            json: true,
            }).then(({ body }) => { 
                if (body) { return body }
                 
                cy.wait(1000);  
                return requestEmail();
            })
          }
        });
    }
  
    return requestEmail();
  });

```
##### configuration 
* `code cypress.json`
* _there could have network problems during the test, use "retries" to retry the test will save your time, visit cypress page for [more info](https://docs.cypress.io/guides/guides/test-retries.html#Introduction)_
```
{
    "retries": 3 
}
```
* `code cypress.env.json`
```
{
    "inboxUrl":"Your Mailtrap Inbox url with inboxId",
    "Api-Token":"Your Mailtrap API token"
}
```
* `npx cypress open`
*  run sample_spec.js test

the result should like this
![cypress open](https://dev-to-uploads.s3.amazonaws.com/i/11y8jjbwgwhs8kcnj5yv.png)

make a automatical process
* `npx yarn add start-server-and-test`
* `npx start-server-and-test 'next dev' 3000 'cypress run'`
![cypress run](https://dev-to-uploads.s3.amazonaws.com/i/es2y7570m8qbfxt7mteg.png)