Skip to content

Commit

Permalink
Merge branch 'develop' into backend-dep-update
Browse files Browse the repository at this point in the history
  • Loading branch information
elipe17 authored Dec 16, 2024
2 parents 0e612cc + ae340de commit bcd7bd7
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 88 deletions.
44 changes: 0 additions & 44 deletions .github/workflows/build-backend.yml

This file was deleted.

44 changes: 0 additions & 44 deletions .github/workflows/build-frontend.yml

This file was deleted.

8 changes: 8 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,14 @@ tasks:
- docker compose -f docker-compose.local.yml up tdp-frontend-test -d
- docker compose -f docker-compose.local.yml exec tdp-frontend-test sh -c "npm run test:cov"

cypress:
desc: Run cypress tests
dir: tdrs-frontend
cmds:
- docker-compose -f docker-compose.local.yml up --build tdp-frontend-test -d
- npm run test:e2e


frontend-lint:
desc: Run eslint in the frontend container
dir: tdrs-frontend
Expand Down
138 changes: 138 additions & 0 deletions docs/Technical-Documentation/tech-memos/cypress-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Cypress E2E

**Audience**: TDP Software Engineers <br>
**Subject**: Cypress Refactor <br>
**Date**: October 16th, 2024 <br>

## Summary
Digging into our pipeline failures associated in ticket #3141, it was found that our cypress authentication was not persisting for the admin user within a single routine that also used the STT user. Further investigation showed our cypress code is not easily extensible and has not only issues with CSRF compliance but scenario-specific authentication as opposed to abstracted and compartmented sessions. While splitting the scenario and/or using `cypress.wait()` might temporarily solve one problem, we have uncovered technical debt requiring refactoring of this code.

### Background
Debugging the failures within the pipeline had 3 recurring issues:
1. Referer not found as in [this post](https://github.com/cypress-io/cypress/issues/16975)
2. `adminApiRequest` failed to update status, resulting in next step failure.
3. Errors regarding Django's 'csrf_middleware_token`.

By addressing authentication in a standard way and storing all session cookies and tokens, we should be able to resolve these 3 issues.

## Out of Scope
* Any changes to frontend ReactJS and Nginx apps
* Significant changes to backend authentication
* New Cypress workflows beyond our end-to-end test against deployed develop branch

## Method/Design

### Abstracted Gherkin Steps
Presently, many of the defined Javascript functions for a given Gherkin step are bespoke or single-use instead of abstracted and should be adapted. Additionally, it was found that sessions were lingering between Gherkin scenarios as we did not have generic `setup` and `teardown` implementations ahead of these. Sufficient utilization of abstraction within the scenarios which are now doing setup/teardown between scenarios and proper session management should result in a cleaner Cypress execution and make future additions simpler.

Before:
```
Scenario: A new user is put in the pending state
Given The admin logs in
And '[email protected]' is in begin state
When '[email protected]' visits the home page
And '[email protected]' logs in
Then '[email protected]' requests access
And The admin sets the approval status of '[email protected]' to 'Pending'
Then '[email protected]' sees the request still submitted
```

There are specific functions for each of the Gherkin Steps and they might rely on the setup steps such as "user is in begin state" which could be handled if we utilized Cypress setup steps:

After:
```
Scenario: A new user is put in the pending state
Given '[email protected]' logs in
And '[email protected]' requests access
When The admin sets the approval status of '[email protected]' to 'Pending'
Then '[email protected]' sees the request still submitted
```

Setup/Teardown hook psuedo-code:
```JavaScript
describe('E2E User Approval Flow', ()=> {
beforeEach(() => {
cy.AdminLogsIn(kwargs)
cy.UserIsInBeginState(user)
}))

afterEach(() => {
cy.get(@testTeardownId).then(id => {
cy.resetUser(user)
cy.resetFilesUploaded(user)
})
}
})

When('The admin sets the approval status of {string} to {string}',
(username, status) => {
// proceed with your test steps
}
```
- [Cypress Teardown Hook Blog Post](https://medium.com/@joydeep56053/how-to-implement-test-teardown-hook-in-cypress-671fc9667e07)
### Abstracted utility authentication functions
Our current Cypress implementation has Gherkin scenarios `accounts.feature` which relies on definitions in `accounts.js`, `common-steps.js`, and finally `commands.js` which handle authentication in different ways for different scenarios (e.g., `login()`, `adminLogin()`, and `adminApiRequest()`)
These current functions do not handle the new django `crsf_middleware_token` which may be required for smooth operation. We will move to a standardized authentication function with wrappers which will make the Gherkin scenarios uniform in their approach to authentication and session management.
### Session Management
These new implementations will need to leverage newer Cypress commands `session` and `intercept` for managing our two-user scenarios.
```Javascript
const login = (name) => {
cy.session(name, () => {
cy.request({
method: 'POST',
url: '/login',
body: { name, password: 's3cr3t' },
}).then(({ body }) => {
window.localStorage.setItem('authToken', body.token)
})
})
}

it('should transfer money between users', () => {
login('user')
cy.visit('/transfer')
cy.get('#amount').type('100.00')
cy.get('#send-money').click()

login('other-user')
cy.visit('/account_balance')
cy.get('#balance').should('eq', '100.00')
})
```
[Session Documentation](https://docs.cypress.io/api/commands/session#Switching-sessions-inside-tests)
```Javascript
// spying
cy.intercept('/users/**')
cy.intercept('GET', '/users*')
cy.intercept({
method: 'GET',
url: '/users*',
hostname: 'localhost',
})

// spying and response stubbing
cy.intercept('POST', '/users*', {
statusCode: 201,
body: {
name: 'Peter Pan',
},
})

// spying, dynamic stubbing, request modification, etc.
cy.intercept('/users*', { hostname: 'localhost' }, (req) => {
/* do something with request and/or response */
})
```
[Intercept Documentation](https://docs.cypress.io/api/commands/intercept)
## Affected Systems
Existing Django CypressAuth class, django middleware, and existing Nginx implementation.
## Use and Test cases to consider
Test E2E Deployment pipelines and future Cypress integration tests.

0 comments on commit bcd7bd7

Please sign in to comment.