Skip to content

Commit 87b50da

Browse files
AtofStrykerdebrisapron
authored andcommitted
feat: update cognito login guide for realworld app (#4882)
* feat: update cognito login guide for realworld app * chore: update guide from comments in code review * properly close alert tag * Update content/guides/end-to-end-testing/amazon-cognito-authentication.md * chore: address comments from code review * fix linting
1 parent ddd2c02 commit 87b50da

File tree

3 files changed

+153
-10
lines changed

3 files changed

+153
-10
lines changed
21.6 MB
Binary file not shown.
11.8 MB
Binary file not shown.

content/guides/end-to-end-testing/amazon-cognito-authentication.md

Lines changed: 153 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ e2eSpecific: true
77

88
## <Icon name="graduation-cap"></Icon> What you'll learn
99

10+
- Log in to [Amazon Cognito](https://aws.amazon.com/cognito) through the UI with
11+
[`cy.origin()`](/api/commands/origin)
1012
- Programmatically authenticate with
1113
[Amazon Cognito](https://aws.amazon.com/cognito) via a custom Cypress command
1214
- Adapting your [Amazon Cognito](https://aws.amazon.com/cognito) application for
@@ -16,13 +18,17 @@ e2eSpecific: true
1618

1719
<Alert type="success">
1820

19-
<strong class="alert-header">Why authenticate programmatically?</strong>
21+
<strong class="alert-header">Authenticate by visiting a different domain with
22+
[`cy.origin()`](/api/commands/origin)</strong>
2023

2124
Typically, logging in a user within your app by authenticating via a third-party
22-
provider requires visiting login pages hosted on a different domain. Since each
23-
Cypress test is limited to visiting domains of the same origin, we can subvert
24-
visiting and testing third-party login pages by programmatically interacting
25-
with the third-party authentication API to login a user.
25+
provider requires visiting a login page hosted on a different domain. Before
26+
Cypress [v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress tests were
27+
limited to visiting domains of the same origin, making programmatic login the
28+
only option for authenticating users with a third-party API. As of Cypress
29+
[v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress tests are no longer
30+
limited to visiting domains of a single origin, meaning you can easily
31+
authenticate to federated AWS Cognito via the UI!
2632

2733
</Alert>
2834

@@ -36,7 +42,7 @@ mobile apps quickly and easily" and "scales to millions of users and supports
3642
sign-in with social identity providers, such as Facebook, Google, and Amazon,
3743
and enterprise identity providers via SAML 2.0."
3844

39-
## Programmatic Authentication with Amazon Cognito
45+
## Authentication with Amazon Cognito
4046

4147
The documentation for [Amazon Cognito](https://aws.amazon.com/cognito)
4248
recommends using the
@@ -157,8 +163,135 @@ const awsConfig = require('./aws-exports-es5.js')
157163

158164
## Custom Command for Amazon Cognito Authentication
159165

166+
There are two ways you can authenticate to AWS Cognito:
167+
168+
- [Login with `cy.origin()`](/guides/end-to-end-testing/amazon-cognito-authentication#Login-with-cy-origin)
169+
- [Programmatic Access](/guides/end-to-end-testing/amazon-cognito-authentication#Programmatic-Login)
170+
171+
### Login with [`cy.origin()`](/api/commands/origin)
172+
173+
Next, we'll write a custom command called `loginByCognito` to perform a login to
174+
[Amazon Cognito](https://aws.amazon.com/cognito). This command will use
175+
[`cy.origin()`](/api/commands/origin) to
176+
177+
1. navigate to the Cognito origin
178+
2. input user credentials
179+
3. sign in and redirect back to the
180+
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app)
181+
4. cache the results with [`cy.session()`](/api/commands/session)
182+
183+
```jsx
184+
// cypress/support/auth-provider-commands/cognito.ts
185+
// Amazon Cognito
186+
const loginToCognito = (username: string, password: string) => {
187+
Cypress.log({
188+
displayName: 'COGNITO LOGIN',
189+
message: [`🔐 Authenticating | ${username}`],
190+
autoEnd: false,
191+
})
192+
193+
cy.visit('/')
194+
cy.contains('Sign in with AWS', {
195+
includeShadowDom: true,
196+
}).click()
197+
198+
cy.origin(
199+
Cypress.env('cognito_domain'),
200+
{
201+
args: {
202+
username,
203+
password,
204+
},
205+
},
206+
({ username, password }) => {
207+
// Cognito log in page has some elements of the same id but are off screen.
208+
// We only want the visible elements to log in
209+
cy.get('input[name="username"]:visible').type(username)
210+
cy.get('input[name="password"]:visible').type(password, {
211+
// use log: false to prevent your password from showing in the Command Log
212+
log: false,
213+
})
214+
cy.get('input[name="signInSubmitButton"]:visible').click()
215+
}
216+
)
217+
218+
// give a few seconds for redirect to settle
219+
cy.wait(2000)
220+
221+
// verify we have made it passed the login screen
222+
cy.contains('Get Started').should('be.visible')
223+
}
224+
225+
// right now our custom command is light. More on this later!
226+
Cypress.Commands.add('loginByCognito', (username, password) => {
227+
return loginToCognito(username, password)
228+
})
229+
```
230+
231+
Now, we can use our `loginByCognito` command in the test. Below is our test to
232+
login as a user via [Amazon Cognito](https://aws.amazon.com/cognito), complete
233+
the onboarding process and logout.
234+
235+
<Alert type="success">
236+
237+
The
238+
[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/cognito.spec.ts)
239+
is in the
240+
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app).
241+
242+
</Alert>
243+
244+
```jsx
245+
describe('Cognito', function () {
246+
beforeEach(function () {
247+
// Seed database with test data
248+
cy.task('db:seed')
249+
250+
// login via Amazon Cognito via cy.origin()
251+
cy.loginByCognito(
252+
Cypress.env('cognito_username'),
253+
Cypress.env('cognito_password')
254+
)
255+
})
256+
257+
it('shows onboarding', function () {
258+
cy.contains('Get Started').should('be.visible')
259+
})
260+
})
261+
```
262+
263+
<DocsVideo src="/img/examples/aws-cognito-origin.mp4"></DocsVideo>
264+
265+
Lastly, we can refactor our login command to take advantage of
266+
[`cy.session()`](/api/commands/session) to store our logged in user so we don't
267+
have to reauthenticate with everything test.
268+
269+
```jsx
270+
// cypress/support/auth-provider-commands/cognito.ts
271+
// Amazon Cognito
272+
Cypress.Commands.add('loginByCognito', (username, password) => {
273+
cy.session(
274+
`cognito-${username}`,
275+
() => {
276+
return loginToCognito(username, password)
277+
},
278+
{
279+
validate() {
280+
cy.visit('/')
281+
// revalidate our session to make sure we are logged in
282+
cy.contains('Get Started').should('be.visible')
283+
},
284+
}
285+
)
286+
})
287+
```
288+
289+
<DocsVideo src="/img/examples/cognito-session-restore.mp4"></DocsVideo>
290+
291+
### Programmatic Login
292+
160293
Next, we'll write a command to perform a programmatic login into
161-
[Amazon Cognito](https://aws.amazon.com/cognito) and set items in localStorage
294+
[Amazon Cognito](https://aws.amazon.com/cognito) and set items in `localStorage`
162295
with the authenticated users details, which we will use in our application code
163296
to verify we are authenticated under test.
164297

@@ -255,7 +388,17 @@ describe('Cognito', function () {
255388
})
256389
```
257390

258-
## Adapting an Amazon Cognito App for Testing
391+
### Adapting an Amazon Cognito App for Testing
392+
393+
<Alert type="info">
394+
395+
<strong class="alert-header">Programmatic Login</strong>
396+
397+
Unlike programmatic login, authenticating with
398+
[`cy.origin()`](/api/commands/origin) does not require adapting the application
399+
to work. This step is only needed if implementing programmatic login.
400+
401+
</Alert>
259402

260403
The
261404
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app) is
@@ -267,7 +410,7 @@ The front end uses the
267410
The back end uses the [express-jwt](https://github.com/auth0/express-jwt) to
268411
validate JWTs from [Amazon Cognito](https://aws.amazon.com/cognito).
269412

270-
### Adapting the back end
413+
#### Adapting the back end
271414

272415
In order to validate API requests from the frontend, we install
273416
[express-jwt](https://github.com/auth0/express-jwt) and
@@ -312,7 +455,7 @@ if (process.env.REACT_APP_AWS_COGNITO) {
312455
// routes ...
313456
```
314457

315-
### Adapting the front end
458+
#### Adapting the front end
316459

317460
We need to update our front end React app to allow for authentication with
318461
[Amazon Cognito](https://aws.amazon.com/cognito) using the

0 commit comments

Comments
 (0)