@@ -7,6 +7,8 @@ e2eSpecific: true
7
7
8
8
## <Icon name =" graduation-cap " ></Icon > What you'll learn
9
9
10
+ - Log in to [ Amazon Cognito] ( https://aws.amazon.com/cognito ) through the UI with
11
+ [ ` cy.origin() ` ] ( /api/commands/origin )
10
12
- Programmatically authenticate with
11
13
[ Amazon Cognito] ( https://aws.amazon.com/cognito ) via a custom Cypress command
12
14
- Adapting your [ Amazon Cognito] ( https://aws.amazon.com/cognito ) application for
@@ -16,13 +18,17 @@ e2eSpecific: true
16
18
17
19
<Alert type =" success " >
18
20
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 >
20
23
21
24
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!
26
32
27
33
</Alert >
28
34
@@ -36,7 +42,7 @@ mobile apps quickly and easily" and "scales to millions of users and supports
36
42
sign-in with social identity providers, such as Facebook, Google, and Amazon,
37
43
and enterprise identity providers via SAML 2.0."
38
44
39
- ## Programmatic Authentication with Amazon Cognito
45
+ ## Authentication with Amazon Cognito
40
46
41
47
The documentation for [ Amazon Cognito] ( https://aws.amazon.com/cognito )
42
48
recommends using the
@@ -157,8 +163,135 @@ const awsConfig = require('./aws-exports-es5.js')
157
163
158
164
## Custom Command for Amazon Cognito Authentication
159
165
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
+
160
293
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 `
162
295
with the authenticated users details, which we will use in our application code
163
296
to verify we are authenticated under test.
164
297
@@ -255,7 +388,17 @@ describe('Cognito', function () {
255
388
})
256
389
```
257
390
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 >
259
402
260
403
The
261
404
[ Cypress Real World App] ( https://github.com/cypress-io/cypress-realworld-app ) is
@@ -267,7 +410,7 @@ The front end uses the
267
410
The back end uses the [ express-jwt] ( https://github.com/auth0/express-jwt ) to
268
411
validate JWTs from [ Amazon Cognito] ( https://aws.amazon.com/cognito ) .
269
412
270
- ### Adapting the back end
413
+ #### Adapting the back end
271
414
272
415
In order to validate API requests from the frontend, we install
273
416
[ express-jwt] ( https://github.com/auth0/express-jwt ) and
@@ -312,7 +455,7 @@ if (process.env.REACT_APP_AWS_COGNITO) {
312
455
// routes ...
313
456
```
314
457
315
- ### Adapting the front end
458
+ #### Adapting the front end
316
459
317
460
We need to update our front end React app to allow for authentication with
318
461
[ Amazon Cognito] ( https://aws.amazon.com/cognito ) using the
0 commit comments