Skip to content

Commit

Permalink
[SDK-1569] Sample app with E2E tests (#31)
Browse files Browse the repository at this point in the history
* Vanilla CRA with react-router-dom

* move into const to look neater

* Turn off codecov comments in PRs

* package-lock overides parent

* Can't use ci without a package-lock
  • Loading branch information
adamjmcgrath authored Jun 10, 2020
1 parent f2f6e8a commit d678291
Show file tree
Hide file tree
Showing 34 changed files with 2,507 additions and 12 deletions.
11 changes: 7 additions & 4 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ version: 2.1
jobs:
build:
docker:
- image: cypress/browsers:node12.13.0-chrome80-ff74
- image: circleci/node:12.9.1-browsers
steps:
- checkout
- restore_cache:
keys:
- dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
key: dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "examples/cra-react-router/package.json" }}-{{ checksum "examples/users-api/package-lock.json" }}
- run: npm ci
- run: npm run install:examples
- save_cache:
key: dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}
key: dependencies-{{ .Branch }}-{{ checksum "package-lock.json" }}-{{ checksum "examples/cra-react-router/package.json" }}-{{ checksum "examples/users-api/package-lock.json" }}
paths:
- ~/.npm
- ~/.cache
- run: npm run build
- run: npm test
# TODO: remove when facebook/create-react-app#8845 is shipped
- run: sed -i '/process.env.CI/ s/isInteractive [|]*//' examples/cra-react-router/node_modules/react-scripts/scripts/start.js
- run: npm run test:integration
- run: npm run codecov
- store_test_results:
path: test-results
Expand Down
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module.exports = {
rules: {
'@typescript-eslint/camelcase': 'off',
},
ignorePatterns: ['examples/**'],
overrides: [
{
files: ['*.js'],
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,6 @@ dist

.idea
test-results

cypress/screenshots
cypress/videos
1 change: 1 addition & 0 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export default withAuthenticationRequired(Profile);
```js
// use-api.js
import { useEffect, useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react';

export const useApi = (url, options = {}) => {
const { getAccessTokenSilently } = useAuth0();
Expand Down
1 change: 1 addition & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
comment: false
9 changes: 9 additions & 0 deletions cypress.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"baseUrl": "http://localhost:3000",
"chromeWebSecurity": false,
"viewportWidth": 1000,
"viewportHeight": 1000,
"fixturesFolder": false,
"pluginsFile": false,
"supportFile": false
}
39 changes: 39 additions & 0 deletions cypress/integration/smoke.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const loginToAuth0 = (): void => {
cy.get('.auth0-lock-input-username .auth0-lock-input')
.clear()
.type('[email protected]');
cy.get('.auth0-lock-input-password .auth0-lock-input').clear().type('1234');
cy.get('.auth0-lock-submit').click();
};

describe('Smoke tests', () => {
it('do basic login and show user', () => {
cy.visit('/');
cy.get('#login').should('exist');
cy.get('#login').click();

loginToAuth0();

cy.get('#hello').contains(`Hello, ${Cypress.env('USER_EMAIL')}!`);
cy.get('#logout').click();
cy.get('#login').should('exist');
});

it('should protect a route and return to path after login', () => {
cy.visit('/users');

loginToAuth0();

cy.url().should('include', '/users');
cy.get('#logout').click();
});

it('should access an api', () => {
cy.visit('/users');

loginToAuth0();

cy.get('table').contains('[email protected]');
cy.get('#logout').click();
});
});
10 changes: 10 additions & 0 deletions cypress/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"strict": true,
"baseUrl": "../node_modules",
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}
28 changes: 28 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# @auth0/auth0-react Examples

To run the examples:

- Follow the steps to configure an Auth0 Single-Page Application (SPA) in https://auth0.com/docs/quickstart/spa/react/01-login#configure-auth0
- Follow the steps to create an API in https://auth0.com/docs/quickstart/spa/react/02-calling-an-api#create-an-api
- Add a permission to your API of `read:users` following the steps in https://auth0.com/docs/dashboard/guides/apis/add-permissions-apis
- Add a `.env` file to `./examples/cra-react-router/.env` With the `domain` and `clientId` of the application and `audience` (your API identifier)

```dotenv
REACT_APP_DOMAIN=your_domain
REACT_APP_CLIENT_ID=your_client_id
REACT_APP_AUDIENCE=your_audience
SKIP_PREFLIGHT_CHECK=true # To workaround issues with nesting create-react-app in another package
```

- Add a `.env` file to `./examples/users-api/.env` With the `domain` and `audience` (your API identifier)

```dotenv
DOMAIN=your_domain
AUDIENCE=your_audience
```

- Start the api and the web application by running the 2 start commands (from the project root)

```bash
$ npm run start:api && npm run start:cra
```
5 changes: 5 additions & 0 deletions examples/cra-react-router/.env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
SKIP_PREFLIGHT_CHECK=true
REACT_APP_DOMAIN=your-tenant.auth0.com
REACT_APP_CLIENT_ID=yourclientid
REACT_APP_AUDIENCE=https://api.example.com/users
REACT_APP_API_PORT=3001
26 changes: 26 additions & 0 deletions examples/cra-react-router/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Intentionally removing package lock because it has problems when using local file resolutions
package-lock.json
29 changes: 29 additions & 0 deletions examples/cra-react-router/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

## Available Scripts

In the project directory, you can run:

### `npm start`

Runs the app in the development mode.<br />
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.

The page will reload if you make edits.<br />
You will also see any lint errors in the console.

### `npm run build`

Builds the app for production to the `build` folder.<br />
It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.<br />
Your app is ready to be deployed!

See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.

## Learn More

You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).

To learn React, check out the [React documentation](https://reactjs.org/).
42 changes: 42 additions & 0 deletions examples/cra-react-router/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "cra-react-router",
"version": "0.1.0",
"private": true,
"dependencies": {
"@auth0/auth0-react": "file:../..",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/history": "^4.7.6",
"@types/jest": "^24.9.1",
"@types/node": "^12.12.43",
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"@types/react-router-dom": "^5.1.5",
"history": "^4.10.1",
"react": "file:../../node_modules/react",
"react-dom": "file:../../node_modules/react-dom",
"react-router-dom": "^5.2.0",
"react-scripts": "^3.4.1",
"typescript": "^3.7.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Binary file added examples/cra-react-router/public/favicon.ico
Binary file not shown.
24 changes: 24 additions & 0 deletions examples/cra-react-router/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Web site created using create-react-app"
/>

<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
crossorigin="anonymous"
/>
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
5 changes: 5 additions & 0 deletions examples/cra-react-router/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.spinner-border {
top: 50%;
position: fixed;
margin-top: -1rem;
}
33 changes: 33 additions & 0 deletions examples/cra-react-router/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { createBrowserHistory } from 'history';
import { Route, Router, Switch } from 'react-router-dom';
import './App.css';
import { ProtectedRoute } from './ProtectedRoute';
import { Nav } from './Nav';
import { Error } from './Error';
import { Loading } from './Loading';
import { Users } from './Users';

export const history = createBrowserHistory();

function App() {
const { isLoading, error } = useAuth0();

if (isLoading) {
return <Loading />;
}

return (
<Router history={history}>
<Nav />
{error && <Error message={error.message} />}
<Switch>
<Route path="/" exact />
<ProtectedRoute path="/users" component={Users} />
</Switch>
</Router>
);
}

export default App;
9 changes: 9 additions & 0 deletions examples/cra-react-router/src/Error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';

export function Error({ message }: { message: string }) {
return (
<div className="alert alert-danger" role="alert">
Oops... {message}
</div>
);
}
11 changes: 11 additions & 0 deletions examples/cra-react-router/src/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';

export function Loading() {
return (
<div className="text-center">
<div className="spinner-border" role="status">
<span className="sr-only">Loading...</span>
</div>
</div>
);
}
58 changes: 58 additions & 0 deletions examples/cra-react-router/src/Nav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useEffect, useState } from 'react';
import { useHistory, Link } from 'react-router-dom';
import { useAuth0 } from '@auth0/auth0-react';

export function Nav() {
const { isAuthenticated, user, loginWithRedirect, logout } = useAuth0();
const history = useHistory();
const [pathname, setPathname] = useState(() => history.location.pathname);

useEffect(() => {
return history.listen(({ pathname }) => setPathname(pathname));
}, [history]);

return (
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<span className="navbar-brand">@auth0/auth0-react</span>
<div className="collapse navbar-collapse">
<div className="navbar-nav">
<Link
to="/"
className={`nav-item nav-link${pathname === '/' ? ' active' : ''}`}
>
Home
</Link>
<Link
to="/users"
className={`nav-item nav-link${
pathname === '/users' ? ' active' : ''
}`}
>
Users
</Link>
</div>
</div>

{isAuthenticated ? (
<div>
<span id="hello">Hello, {user.name}!</span>{' '}
<button
className="btn btn-outline-secondary"
id="logout"
onClick={() => logout()}
>
logout
</button>
</div>
) : (
<button
className="btn btn-outline-success"
id="login"
onClick={() => loginWithRedirect()}
>
login
</button>
)}
</nav>
);
}
Loading

0 comments on commit d678291

Please sign in to comment.