Skip to content

Commit dbd35c4

Browse files
committed
feat: update cognito login guide for realworld app
1 parent 4b6a45f commit dbd35c4

File tree

3 files changed

+178
-14
lines changed

3 files changed

+178
-14
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: 178 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,23 @@ e2eSpecific: true
77

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

10-
- Programmatically authenticate with
11-
[Amazon Cognito](https://aws.amazon.com/cognito) via a custom Cypress command
12-
- Adapting your [Amazon Cognito](https://aws.amazon.com/cognito) application for
13-
programmatic authentication during testing
10+
- Authenticate with [`cy.origin()`](/api/commands/origin) or programmatically
11+
(legacy) to [Amazon Cognito](https://aws.amazon.com/cognito) via a custom
12+
Cypress command
13+
- If needed, adapting your [Amazon Cognito](https://aws.amazon.com/cognito)
14+
application for programmatic authentication during testing
1415

1516
</Alert>
1617

1718
<Alert type="success">
1819

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

21-
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.
23+
Programmatic authentication for Cognito is now considered a legacy
24+
recommendation. As of Cypress [v12.0.0](https://on.cypress.io/changelog#12-0-0),
25+
you can easily authenticate to federated AWS Cognito as Cypress tests are no
26+
longer limited to visiting domains of a single origin.
2627

2728
</Alert>
2829

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

39-
## Programmatic Authentication with Amazon Cognito
40+
## Authentication with Amazon Cognito
4041

4142
The documentation for [Amazon Cognito](https://aws.amazon.com/cognito)
4243
recommends using the
@@ -157,6 +158,169 @@ const awsConfig = require('./aws-exports-es5.js')
157158

158159
## Custom Command for Amazon Cognito Authentication
159160

161+
There are two ways you can authenticate to AWS Cognito
162+
163+
- [Login with cy.origin()](/guides/end-to-end-testing/amazon-cognito-authentication#Login-with-cy-origin)
164+
- [Legacy Programmatic Access](/guides/end-to-end-testing/amazon-cognito-authentication#Programmatic-Login-Legacy)
165+
166+
### Login with [`cy.origin()`](/api/commands/origin)
167+
168+
Next, we'll write a command to perform a login to
169+
[Amazon Cognito](https://aws.amazon.com/cognito) using
170+
[`cy.origin()`](/api/commands/origin) to navigate to the cognito origin,
171+
inputting a user credentials, and signing in via OAuth to redirect back to our
172+
application, and caching the results with
173+
[`cy.session()`](/api/commands/session).
174+
175+
In this `loginByCognito` command, we redirect to the cognito login screen by
176+
authenticating with `Sign in with AWS`. We then enter our user credentials and
177+
sign in, which redirects us back to the realworld app.
178+
179+
```jsx
180+
// cypress/support/auth-provider-commands/cognito.ts
181+
182+
/// Amazon Cognito
183+
Cypress.Commands.add('loginByCognito', (username, password) => {
184+
Cypress.log({
185+
displayName: 'COGNITO LOGIN',
186+
message: [`🔐 Authenticating | ${username}`],
187+
// @ts-ignore
188+
autoEnd: false,
189+
})
190+
191+
cy.visit('/')
192+
cy.contains('Sign in with AWS', {
193+
includeShadowDom: true,
194+
}).click()
195+
196+
cy.origin(
197+
Cypress.env('cognito_domain'),
198+
{
199+
args: {
200+
username,
201+
password,
202+
},
203+
},
204+
({ username, password }) => {
205+
// cognito log in page has some elements of the same id but are off screen. we only want the visible elements to log in
206+
cy.get('input[name="username"]:visible').type(username)
207+
cy.get('input[name="password"]:visible').type(password, {
208+
log: false,
209+
})
210+
cy.get('input[name="signInSubmitButton"]:visible').click()
211+
}
212+
)
213+
214+
// give a few seconds for redirect to settle
215+
// eslint-disable-next-line cypress/no-unnecessary-waiting
216+
cy.wait(2000)
217+
218+
// verify we have made it passed the login screen
219+
cy.contains('Get Started').should('be.visible')
220+
})
221+
```
222+
223+
Secondly, we can use our `loginByCognito` command in the test. Below is our test
224+
to login as a user via [Amazon Cognito](https://aws.amazon.com/cognito),
225+
complete the onboarding process and logout.
226+
227+
<Alert type="success">
228+
229+
The
230+
[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/cognito.spec.ts)
231+
is in the
232+
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app).
233+
234+
</Alert>
235+
236+
```jsx
237+
describe('Cognito', function () {
238+
beforeEach(function () {
239+
// Seed database with test data
240+
cy.task('db:seed')
241+
242+
// login via Amazon Cognito via cy.origin()
243+
cy.loginByCognito(
244+
Cypress.env('cognito_username'),
245+
Cypress.env('cognito_password')
246+
)
247+
})
248+
249+
it('shows onboarding', function () {
250+
cy.contains('Get Started').should('be.visible')
251+
})
252+
})
253+
```
254+
255+
<DocsVideo src="/img/examples/aws-cognito-origin.mp4"></DocsVideo>
256+
257+
Lastly, we can refactor our login command to take advantage of
258+
[`cy.session()`](/api/commands/session) to store our logged in user so we don't
259+
have to reauthenticate with everything test.
260+
261+
```jsx
262+
// Amazon Cognito
263+
Cypress.Commands.add('loginByCognito', (username, password) => {
264+
cy.session(
265+
`cognito-${username}`,
266+
() => {
267+
Cypress.log({
268+
displayName: 'COGNITO LOGIN',
269+
message: [`🔐 Authenticating | ${username}`],
270+
// @ts-ignore
271+
autoEnd: false,
272+
})
273+
274+
cy.visit('/')
275+
cy.contains('Sign in with AWS', {
276+
includeShadowDom: true,
277+
}).click()
278+
279+
cy.origin(
280+
Cypress.env('cognito_domain'),
281+
{
282+
args: {
283+
username,
284+
password,
285+
},
286+
},
287+
({ username, password }) => {
288+
// cognito log in page has some elements of the same id but are off screen. we only want the visible elements to log in
289+
cy.get('input[name="username"]:visible').type(username)
290+
cy.get('input[name="password"]:visible').type(password, {
291+
log: false,
292+
})
293+
cy.get('input[name="signInSubmitButton"]:visible').click()
294+
}
295+
)
296+
297+
// give a few seconds for redirect to settle
298+
// eslint-disable-next-line cypress/no-unnecessary-waiting
299+
cy.wait(2000)
300+
301+
// verify we have made it passed the login screen
302+
cy.contains('Get Started').should('be.visible')
303+
},
304+
{
305+
validate() {
306+
cy.visit('/')
307+
// revalidate our session to make sure we are logged in
308+
cy.contains('Get Started').should('be.visible')
309+
},
310+
}
311+
)
312+
})
313+
```
314+
315+
<DocsVideo src="/img/examples/cognito-session-restore.mp4"></DocsVideo>
316+
317+
Unlike programmatic login, authenticating with
318+
[`cy.origin()`](/api/commands/origin) does not require adapting the application
319+
to work. It simply works without intervention exactly how your users would
320+
consume the application!
321+
322+
### Programmatic Login (Legacy)
323+
160324
Next, we'll write a command to perform a programmatic login into
161325
[Amazon Cognito](https://aws.amazon.com/cognito) and set items in localStorage
162326
with the authenticated users details, which we will use in our application code
@@ -255,7 +419,7 @@ describe('Cognito', function () {
255419
})
256420
```
257421

258-
## Adapting an Amazon Cognito App for Testing
422+
#### Adapting an Amazon Cognito App for Testing
259423

260424
The
261425
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app) is
@@ -267,7 +431,7 @@ The front end uses the
267431
The back end uses the [express-jwt](https://github.com/auth0/express-jwt) to
268432
validate JWTs from [Amazon Cognito](https://aws.amazon.com/cognito).
269433

270-
### Adapting the back end
434+
#### Adapting the back end
271435

272436
In order to validate API requests from the frontend, we install
273437
[express-jwt](https://github.com/auth0/express-jwt) and
@@ -312,7 +476,7 @@ if (process.env.REACT_APP_AWS_COGNITO) {
312476
// routes ...
313477
```
314478

315-
### Adapting the front end
479+
#### Adapting the front end
316480

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

0 commit comments

Comments
 (0)