docs: init cypress test e2e

Signed-off-by: jffarge <jf@dagger.io>
This commit is contained in:
jffarge 2021-07-02 11:23:12 +02:00
parent 795430024b
commit 868339e174
15 changed files with 1091 additions and 56 deletions

View File

@ -120,3 +120,34 @@ jobs:
- name: Universe Test - name: Universe Test
run: | run: |
make universe-test make universe-test
cypress-run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Cypress run
uses: cypress-io/github-action@v2
env:
REACT_APP_CLIENT_ID: 123
REACT_APP_CLIENT_SECRET: 123
REACT_APP_DAGGER_SITE_URI: https://dagger.io
REACT_APP_API_PROXY_ENABLE: false
REACT_APP_AMPLITUDE_ID: 123
with:
config: chromeWebSecurity=false
start: |
yarn start
yarn start:withAuth
working-directory: ./website
- uses: actions/upload-artifact@v1
if: failure()
with:
name: cypress-screenshots
path: website/cypress/screenshots
# Test run video was always captured, so this action uses "always()" condition
- uses: actions/upload-artifact@v1
if: always()
with:
name: cypress-videos
path: website/cypress/videos

9
website/.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"arrowParens": "always",
"bracketSpacing": false,
"jsxBracketSameLine": true,
"printWidth": 80,
"proseWrap": "never",
"singleQuote": true,
"trailingComma": "all"
}

4
website/cypress.json Normal file
View File

@ -0,0 +1,4 @@
{
"chromeWebSecurity": false,
"video": false
}

View File

@ -0,0 +1,4 @@
{
"message": "Bad credentials",
"documentation_url": "https://docs.github.com/rest"
}

View File

@ -0,0 +1,5 @@
{
"error":"bad_verification_code",
"error_description":"The code passed is incorrect or expired.",
"error_uri":"https://docs.github.com/apps/managing-oauth-apps/troubleshooting-oauth-app-access-token-request-errors/#bad-verification-code"
}

View File

@ -0,0 +1,53 @@
describe('Visit Docs website', function() {
it('Visit docs website without authentication', function() {
cy.visit('http://localhost:3000')
cy.get('[data-cy="cy-signin"]').should('not.exist')
}),
it('Visit docs website with authentication', function() {
cy.visit('http://localhost:3001')
cy.get('[data-cy="cy-signin"]').should('exist')
})
context('When user is authenticated', function() {
beforeEach(() => {
cy.setLocalStorage('user', "{\"permission\":true,\"login\":\"slumbering\"}")
cy.intercept('/t', 'success').as('logAmplitude')
cy.visit(('http://localhost:3001'))
})
it('Visit docs website with a valid authenticated user', function() {
cy.get('[data-cy=cy-doc-content]').should('exist')
})
it('log to amplitude when user visit another page', function() {
cy.get('[data-cy=cy-doc-content]').should('exist')
cy.get('.menu > :nth-child(2) > :nth-child(2) > .menu__link').click()
})
})
context('When user is not authorized', function() {
it('Redirect user after unsuccessful sign in', function() {
cy.intercept('**/login/oauth/access_token?code=jergub54545&client_id=123&client_secret=321', {fixture: 'bad_verification.code.json'})
cy.intercept('**/user', (req) => {
req.continue((res) => {
expect(res.statusCode).to.be.equal(401)
})
})
cy.visit('http://localhost:3001?code=jergub54545')
cy.get('[data-cy=cy-page-redirect]').should('exist')
// cy.wait(10000)
// cy.location().should((location) => {
// expect(location.host).to.eq('dagger.io')
// })
})
it('Visit docs website with a user not authorized', function() {
cy.setLocalStorage('user', "{\"permission\":false,\"login\":\"slumbering\"}")
cy.visit('http://localhost:3001')
cy.get('[data-cy=cy-page-redirect]').should('exist')
cy.intercept('/t', 'success')
})
})
})

View File

@ -0,0 +1,22 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
/**
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@ -0,0 +1,26 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
import "cypress-localstorage-commands"

View File

@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

4
website/cypress/videos/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -5,7 +5,7 @@
"scripts": { "scripts": {
"docusaurus": "docusaurus", "docusaurus": "docusaurus",
"start": "OAUTH_ENABLE=false docusaurus start", "start": "OAUTH_ENABLE=false docusaurus start",
"start:withAuth": "OAUTH_ENABLE=true docusaurus start", "start:withAuth": "OAUTH_ENABLE=true docusaurus start --port=3001",
"build": "OAUTH_ENABLE=true docusaurus build", "build": "OAUTH_ENABLE=true docusaurus build",
"build:withoutAuth": "OAUTH_ENABLE=false docusaurus build", "build:withoutAuth": "OAUTH_ENABLE=false docusaurus build",
"swizzle": "docusaurus swizzle", "swizzle": "docusaurus swizzle",
@ -13,7 +13,9 @@
"clear": "docusaurus clear", "clear": "docusaurus clear",
"serve": "docusaurus serve", "serve": "docusaurus serve",
"write-translations": "docusaurus write-translations", "write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids" "write-heading-ids": "docusaurus write-heading-ids",
"start-server": "concurrently \"OAUTH_ENABLE=false yarn docusaurus start --port=3000 --no-open\" \"OAUTH_ENABLE=true yarn docusaurus start --port=3001 --no-open\"",
"ci": "start-server-and-test 'yarn start-server' '3000|3001' 'yarn run cypress run'"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-beta.2", "@docusaurus/core": "2.0.0-beta.2",
@ -42,5 +44,11 @@
"last 1 firefox version", "last 1 firefox version",
"last 1 safari version" "last 1 safari version"
] ]
},
"devDependencies": {
"concurrently": "^6.2.0",
"cypress": "^7.6.0",
"cypress-localstorage-commands": "^1.4.5",
"start-server-and-test": "^1.12.5"
} }
} }

View File

@ -4,10 +4,12 @@ import style from './DocPageAuthentication.module.css'
export default function DocAuthentication() { export default function DocAuthentication() {
return ( return (
<div className={style.container}> <div data-cy="cy-signin" className={style.container}>
<h1 className={style.h1}>Welcome on Dagger documentation</h1> <h1 className={style.h1}>Welcome on Dagger documentation</h1>
<p>Please Sign In to Github to get access to the doc</p> <p>Please Sign In to Github to get access to the doc</p>
<div data-cy="cy-btn-signin">
<GithubLoginButton className={style.btn__github} onClick={() => window.location.href = process.env.REACT_APP_GITHUB_AUTHORIZE_URI} /> <GithubLoginButton className={style.btn__github} onClick={() => window.location.href = process.env.REACT_APP_GITHUB_AUTHORIZE_URI} />
</div> </div>
</div>
) )
} }

View File

@ -11,7 +11,7 @@ export default function DocPageRedirect() {
}, []) }, [])
return ( return (
<div className={`container ${style.wrapper}`}> <div data-cy="cy-page-redirect" className={`container ${style.wrapper}`}>
<div className={`row ${style.row}`}> <div className={`row ${style.row}`}>
<div className="col col--4 col--offset-2"> <div className="col col--4 col--offset-2">
<h1 className={style.h1}>Oups!</h1> <h1 className={style.h1}>Oups!</h1>

View File

@ -13,15 +13,15 @@ import DocSidebar from '@theme/DocSidebar';
import MDXComponents from '@theme/MDXComponents'; import MDXComponents from '@theme/MDXComponents';
import NotFound from '@theme/NotFound'; import NotFound from '@theme/NotFound';
import IconArrow from '@theme/IconArrow'; import IconArrow from '@theme/IconArrow';
import { matchPath } from '@docusaurus/router'; import {matchPath} from '@docusaurus/router';
import { translate } from '@docusaurus/Translate'; import {translate} from '@docusaurus/Translate';
import clsx from 'clsx'; import clsx from 'clsx';
import styles from './styles.module.css'; import styles from './styles.module.css';
import { ThemeClassNames, docVersionSearchTag } from '@docusaurus/theme-common'; import {ThemeClassNames, docVersionSearchTag} from '@docusaurus/theme-common';
import DocPageCustom from '../../components/DocPageCustom' import DocPageCustom from '../../components/DocPageCustom';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
function getSidebar({ versionMetadata, currentDocRoute }) { function getSidebar({versionMetadata, currentDocRoute}) {
function addTrailingSlash(str) { function addTrailingSlash(str) {
return str.endsWith('/') ? str : `${str}/`; return str.endsWith('/') ? str : `${str}/`;
} }
@ -30,7 +30,7 @@ function getSidebar({ versionMetadata, currentDocRoute }) {
return str.endsWith('/') ? str.slice(0, -1) : str; return str.endsWith('/') ? str.slice(0, -1) : str;
} }
const { permalinkToSidebar, docsSidebars } = versionMetadata; // With/without trailingSlash, we should always be able to get the appropriate sidebar const {permalinkToSidebar, docsSidebars} = versionMetadata; // With/without trailingSlash, we should always be able to get the appropriate sidebar
// note: docs plugin permalinks currently never have trailing slashes // note: docs plugin permalinks currently never have trailing slashes
// trailingSlash is handled globally at the framework level, not plugin level // trailingSlash is handled globally at the framework level, not plugin level
@ -45,10 +45,10 @@ function getSidebar({ versionMetadata, currentDocRoute }) {
}; };
} }
function DocPageContent({ currentDocRoute, versionMetadata, children }) { function DocPageContent({currentDocRoute, versionMetadata, children}) {
const { siteConfig, isClient } = useDocusaurusContext(); const {siteConfig, isClient} = useDocusaurusContext();
const { pluginId, version } = versionMetadata; const {pluginId, version} = versionMetadata;
const { sidebarName, sidebar } = getSidebar({ const {sidebarName, sidebar} = getSidebar({
versionMetadata, versionMetadata,
currentDocRoute, currentDocRoute,
}); });
@ -149,7 +149,7 @@ function DocPageContent({ currentDocRoute, versionMetadata, children }) {
function DocPage(props) { function DocPage(props) {
const { const {
route: { routes: docRoutes }, route: {routes: docRoutes},
versionMetadata, versionMetadata,
location, location,
} = props; } = props;
@ -159,9 +159,12 @@ function DocPage(props) {
const userAgent = ExecutionEnvironment.canUseDOM ? navigator.userAgent : null; const userAgent = ExecutionEnvironment.canUseDOM ? navigator.userAgent : null;
// DocPage Swizzle // DocPage Swizzle
const [userAccessStatus, setUserAccessStatus] = useState((() => { const [userAccessStatus, setUserAccessStatus] = useState(
if (typeof window !== "undefined") return JSON.parse(window.localStorage.getItem('user')) (() => {
})()) if (typeof window !== 'undefined')
return JSON.parse(window.localStorage.getItem('user'));
})(),
);
useEffect(() => { useEffect(() => {
import('amplitude-js').then(amplitude => { import('amplitude-js').then(amplitude => {
@ -191,9 +194,11 @@ function DocPage(props) {
<DocPageContent <DocPageContent
currentDocRoute={currentDocRoute} currentDocRoute={currentDocRoute}
versionMetadata={versionMetadata}> versionMetadata={versionMetadata}>
<div data-cy="cy-doc-content">
{renderRoutes(docRoutes, { {renderRoutes(docRoutes, {
versionMetadata, versionMetadata,
})} })}
</div>
</DocPageContent> </DocPageContent>
); );
} }

File diff suppressed because it is too large Load Diff