@@ -7,22 +7,23 @@ e2eSpecific: true
7
7
8
8
## <Icon name =" graduation-cap " ></Icon > What you'll learn
9
9
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
14
15
15
16
</Alert >
16
17
17
18
<Alert type =" success " >
18
19
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 >
20
22
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.
26
27
27
28
</Alert >
28
29
@@ -36,7 +37,7 @@ mobile apps quickly and easily" and "scales to millions of users and supports
36
37
sign-in with social identity providers, such as Facebook, Google, and Amazon,
37
38
and enterprise identity providers via SAML 2.0."
38
39
39
- ## Programmatic Authentication with Amazon Cognito
40
+ ## Authentication with Amazon Cognito
40
41
41
42
The documentation for [ Amazon Cognito] ( https://aws.amazon.com/cognito )
42
43
recommends using the
@@ -157,6 +158,169 @@ const awsConfig = require('./aws-exports-es5.js')
157
158
158
159
## Custom Command for Amazon Cognito Authentication
159
160
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
+
160
324
Next, we'll write a command to perform a programmatic login into
161
325
[ Amazon Cognito] ( https://aws.amazon.com/cognito ) and set items in localStorage
162
326
with the authenticated users details, which we will use in our application code
@@ -255,7 +419,7 @@ describe('Cognito', function () {
255
419
})
256
420
```
257
421
258
- ## Adapting an Amazon Cognito App for Testing
422
+ #### Adapting an Amazon Cognito App for Testing
259
423
260
424
The
261
425
[ Cypress Real World App] ( https://github.com/cypress-io/cypress-realworld-app ) is
@@ -267,7 +431,7 @@ The front end uses the
267
431
The back end uses the [ express-jwt] ( https://github.com/auth0/express-jwt ) to
268
432
validate JWTs from [ Amazon Cognito] ( https://aws.amazon.com/cognito ) .
269
433
270
- ### Adapting the back end
434
+ #### Adapting the back end
271
435
272
436
In order to validate API requests from the frontend, we install
273
437
[ express-jwt] ( https://github.com/auth0/express-jwt ) and
@@ -312,7 +476,7 @@ if (process.env.REACT_APP_AWS_COGNITO) {
312
476
// routes ...
313
477
```
314
478
315
- ### Adapting the front end
479
+ #### Adapting the front end
316
480
317
481
We need to update our front end React app to allow for authentication with
318
482
[ Amazon Cognito] ( https://aws.amazon.com/cognito ) using the
0 commit comments