-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Update End-to-End Testing -> Auth0 Authentication docs for v12 #4895
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,25 +7,15 @@ e2eSpecific: true | |
|
||
## <Icon name="graduation-cap"></Icon> What you'll learn | ||
|
||
- Log in to [Auth0](https://auth0.com) through the UI with | ||
[`cy.origin()`](/api/commands/origin) | ||
- Programmatically authenticate with [Auth0](https://auth0.com) via a custom | ||
Cypress command | ||
- Adapting your [Auth0](https://auth0.com) application for programmatic | ||
- Adapt your [Auth0](https://auth0.com) application for programmatic | ||
authentication during testing | ||
|
||
</Alert> | ||
|
||
<Alert type="success"> | ||
|
||
<strong class="alert-header">Why authenticate programmatically?</strong> | ||
|
||
Typically, logging in a user within your app by authenticating via a third-party | ||
provider requires visiting login pages hosted on a different domain. Since each | ||
Cypress test is limited to visiting domains of the same origin, we can subvert | ||
visiting and testing third-party login pages by programmatically interacting | ||
with the third-party authentication API to login a user. | ||
|
||
</Alert> | ||
|
||
<Alert type="warning"> | ||
|
||
This guide is setup for testing against an [Auth0](https://auth0.com) Single | ||
|
@@ -36,6 +26,22 @@ for automated end-to-end testing. | |
|
||
</Alert> | ||
|
||
<Alert type="success"> | ||
|
||
<strong class="alert-header">Authenticate by visiting a different domain with | ||
[`cy.origin()`](/api/commands/origin)</strong> | ||
|
||
Typically, logging in a user within your app by authenticating via a third-party | ||
provider requires visiting a login page hosted on a different domain. Before | ||
Cypress [v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress tests were | ||
limited to visiting domains of the same origin, making programmatic login the | ||
only option for authenticating users with a third-party API. As of Cypress | ||
[v12.0.0](https://on.cypress.io/changelog#12-0-0), Cypress tests are no longer | ||
limited to visiting domains of a single origin, meaning you can easily | ||
authenticate with [Auth0](https://auth0.com) via the UI! | ||
|
||
</Alert> | ||
|
||
## Auth0 Application Setup | ||
|
||
To get started with Auth0, an application needs to be setup within the | ||
|
@@ -111,23 +117,151 @@ require('dotenv').config() | |
} | ||
``` | ||
|
||
Note that `auth0_client_secret` is only needed for | ||
[programmatic login](#Programmatic-Login). | ||
|
||
::: | ||
|
||
## Custom Command for Auth0 Authentication | ||
|
||
There are two ways you can authenticate to Auth0: | ||
|
||
- [Login with `cy.origin()`](#Login-with-cy-origin) | ||
- [Programmatic Login](#Programmatic-Login) | ||
|
||
### Login with [`cy.origin()`](/api/commands/origin) | ||
|
||
Next, we'll write a custom command called `loginToAuth0` to perform a login to | ||
[Auth0](https://auth0.com). This command will use | ||
[`cy.origin()`](/api/commands/origin) to | ||
|
||
1. Navigate to the Auth0 login | ||
2. Input user credentials | ||
3. Sign in and redirect back to the | ||
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app) | ||
4. Cache the results with [`cy.session()`](/api/commands/session) | ||
|
||
```js | ||
// cypress/support/auth-provider-commands/auth0.ts | ||
|
||
function loginViaAuth0Ui(username: string, password: string) { | ||
// App landing page redirects to Auth0. | ||
cy.visit('/') | ||
|
||
// Login on Auth0. | ||
cy.origin( | ||
debrisapron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Cypress.env('auth0_domain'), | ||
{ args: { username, password } }, | ||
({ username, password }) => { | ||
cy.get('input#username').type(username) | ||
cy.get('input#password').type(password, { log: false }) | ||
cy.contains('button[value=default]', 'Continue').click() | ||
} | ||
) | ||
|
||
// Ensure Auth0 has redirected us back to the RWA. | ||
cy.url().should('equal', 'http://localhost:3000/') | ||
} | ||
|
||
Cypress.Commands.add('loginToAuth0', (username: string, password: string) => { | ||
const log = Cypress.log({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want to add the logging into the function as well so its encapsulated in the session? |
||
displayName: 'AUTH0 LOGIN', | ||
message: [`🔐 Authenticating | ${username}`], | ||
// @ts-ignore | ||
autoEnd: false, | ||
}) | ||
log.snapshot('before') | ||
|
||
loginViaAuth0Ui(username, password) | ||
|
||
log.snapshot('after') | ||
log.end() | ||
}) | ||
``` | ||
|
||
Now, we can use our `loginToAuth0` command in the test. Below is our test to | ||
login as a user via Auth0 and run a basic sanity check. | ||
|
||
<Alert type="success"> | ||
|
||
The | ||
[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/auth0.spec.ts) | ||
is in the | ||
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app). | ||
|
||
</Alert> | ||
|
||
```js | ||
describe('Auth0', function () { | ||
beforeEach(function () { | ||
cy.task('db:seed') | ||
cy.intercept('POST', '/graphql').as('createBankAccount') | ||
cy.loginToAuth0( | ||
Cypress.env('auth0_username'), | ||
Cypress.env('auth0_password') | ||
) | ||
cy.visit('/') | ||
}) | ||
|
||
it('shows onboarding', function () { | ||
cy.contains('Get Started').should('be.visible') | ||
debrisapron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}) | ||
}) | ||
``` | ||
|
||
<DocsVideo src="/img/examples/auth0-origin.mp4"></DocsVideo> | ||
|
||
Lastly, we can refactor our login command to take advantage of | ||
[`cy.session()`](/api/commands/session) to store our logged in user so we don't | ||
have to reauthenticate before every test. | ||
|
||
```js | ||
Cypress.Commands.add('loginToAuth0', (username: string, password: string) => { | ||
const log = Cypress.log({ | ||
displayName: 'AUTH0 LOGIN', | ||
message: [`🔐 Authenticating | ${username}`], | ||
// @ts-ignore | ||
debrisapron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
autoEnd: false, | ||
}) | ||
log.snapshot('before') | ||
|
||
cy.session( | ||
`auth0-${username}`, | ||
() => { | ||
loginViaAuth0Ui(username, password) | ||
}, | ||
{ | ||
validate: () => { | ||
// Validate presence of access token in localStorage. | ||
cy.wrap(localStorage) | ||
.invoke('getItem', 'authAccessToken') | ||
.should('exist') | ||
}, | ||
} | ||
) | ||
|
||
log.snapshot('after') | ||
log.end() | ||
}) | ||
``` | ||
debrisapron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
debrisapron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<DocsVideo src="/img/examples/auth0-session-restore.mp4"></DocsVideo> | ||
|
||
### Programmatic Login | ||
|
||
Below is a command to programmatically login into [Auth0](https://auth0.com), | ||
using the | ||
[/oauth/token endpoint](https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint) | ||
debrisapron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
and set an item in localStorage with the authenticated users details, which we | ||
and set an item in `localStorage` with the authenticated users details, which we | ||
will use in our application code to verify we are authenticated under test. | ||
|
||
The `loginByAuth0Api` command will execute the following steps: | ||
|
||
1. Use the | ||
[/oauth/token endpoint](https://auth0.com/docs/protocols/protocol-oauth2#token-endpoint) | ||
to perform the programmatic login. | ||
2. Finally the `auth0Cypress` localStorage item is set with the `access token`, | ||
`id_token` and user profile. | ||
2. Finally the `auth0Cypress` `localStorage` item is set with the | ||
`access token`, `id_token` and user profile. | ||
|
||
```jsx | ||
// cypress/support/commands.js | ||
|
@@ -216,17 +350,6 @@ describe('Auth0', function () { | |
}) | ||
``` | ||
|
||
<Alert type="success"> | ||
|
||
<strong class="alert-header">Try it out</strong> | ||
|
||
The | ||
[runnable version of this test](https://github.com/cypress-io/cypress-realworld-app/blob/develop/cypress/tests/ui-auth-providers/auth0.spec.ts) | ||
is in the | ||
[Cypress Real World App](https://github.com/cypress-io/cypress-realworld-app). | ||
|
||
</Alert> | ||
|
||
## Adapting an Auth0 App for Testing | ||
|
||
<Alert type="info"> | ||
|
@@ -238,7 +361,11 @@ within Cypress tests. To use this practice it is assumed you are testing an app | |
appropriately built or adapted to use Auth0. | ||
|
||
The following sections provides guidance on building or adapting an app to use | ||
Auth0 authentication. | ||
Auth0 authentication. Please note that if you are | ||
[logging in with `cy.origin()`](#Login-with-cy-origin) and your app is already | ||
successfully integrated with Auth0, you do not need to make any further changes | ||
to your app and the remainder of this guide should be regarded as purely | ||
informational. | ||
|
||
</Alert> | ||
|
||
|
@@ -420,7 +547,7 @@ if (process.env.REACT_APP_AUTH0) { | |
|
||
An update to our | ||
[AppAuth0.tsx component](https://github.com/cypress-io/cypress-realworld-app/blob/develop/src/containers/AppAuth0.tsx) | ||
is needed to conditionally use the `auth0Cypress` localStorage item. | ||
is needed to conditionally use the `auth0Cypress` `localStorage` item. | ||
|
||
In the code below, we conditionally apply a `useEffect` block based on being | ||
under test with Cypress (using `window.Cypress`). | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.