Merge pull request #402 from spotify/eide/hack-cypress

Add e2e tests for App with Cypress
This commit is contained in:
Marcus Eide
2020-03-30 08:56:54 +02:00
committed by GitHub
11 changed files with 619 additions and 67 deletions
+5
View File
@@ -0,0 +1,5 @@
{
"baseUrl": "http://localhost:3000",
"fixturesFolder": false,
"pluginsFile": false
}
+12
View File
@@ -0,0 +1,12 @@
{
"plugins": ["cypress"],
"extends": ["plugin:cypress/recommended"],
"rules": {
"jest/expect-expect": [
"error",
{
"assertFunctionNames": ["expect", "cy.contains"]
}
]
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
describe('App', () => {
it('should render the welcome page', () => {
cy.visit('/');
cy.contains('Welcome to Backstage');
cy.contains('Getting Started');
cy.contains('Quick Links');
cy.contains('APIs');
});
it('should display support info when clicking the button', () => {
cy.visit('/');
cy.findByTestId('support-button').click({ force: true });
cy.contains('#backstage');
});
it('should display error message when triggering it', () => {
cy.visit('/');
cy.findByTestId('error-button').click({ force: true });
cy.contains('Error: Oh no!');
cy.findByTestId('error-button-close').click({ force: true });
});
it('should be able to login and logout', () => {
const name = 'test-name';
Cypress.on('window:before:load', win => {
win.fetch = cy.stub().resolves({
status: 200,
json: () => ({ username: 'test name', token: 'token', name }),
});
});
cy.visit('/');
cy.get('a[href="/login"]').click({ force: true });
cy.url().should('include', '/login');
cy.contains('Welcome, guest!');
cy.contains('Username')
.get('input[name=github-username-tf]')
.type(name, { force: true });
cy.contains('Token')
.get('input[name=github-auth-tf]')
.type('password', { force: true });
cy.findByTestId('github-auth-button').click({ force: true });
cy.contains(`Welcome, ${name}!`);
cy.contains('Logout').click({ force: true });
cy.contains('Welcome, guest!');
});
});
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import '@testing-library/cypress/add-commands';
+13 -2
View File
@@ -28,7 +28,11 @@
"start": "backstage-cli app:serve",
"build": "backstage-cli app:build",
"test": "backstage-cli test",
"lint": "backstage-cli lint"
"test:e2e": "start-server-and-test start http://localhost:3000 cy:dev",
"test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run",
"lint": "backstage-cli lint",
"cy:dev": "cypress open",
"cy:run": "cypress run"
},
"browserslist": {
"production": [
@@ -42,5 +46,12 @@
"last 1 safari version"
]
},
"license": "Apache-2.0"
"license": "Apache-2.0",
"devDependencies": {
"@testing-library/cypress": "^6.0.0",
"@types/jquery": "^3.3.34",
"cypress": "^4.2.0",
"eslint-plugin-cypress": "^2.10.3",
"start-server-and-test": "^1.10.11"
}
}
@@ -16,7 +16,8 @@
import React, { FC, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Snackbar } from '@material-ui/core';
import { Snackbar, IconButton } from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import { Alert } from '@material-ui/lab';
import { ErrorApi, ErrorContext } from '@backstage/core';
@@ -73,7 +74,19 @@ const ErrorDisplay: FC<Props> = ({ forwarder }) => {
message={firstError.toString()}
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
>
<Alert onClose={handleClose} severity="error">
<Alert
action={
<IconButton
color="inherit"
size="small"
onClick={handleClose}
data-testid="error-button-close"
>
<CloseIcon />
</IconButton>
}
severity="error"
>
{firstError.toString()}
</Alert>
</Snackbar>
@@ -27,7 +27,7 @@ import {
TextField,
List,
ListItem,
Link
Link,
} from '@material-ui/core';
import InfoCard from '../../../layout/InfoCard/InfoCard';
@@ -37,7 +37,9 @@ enum AuthType {
const LoginPage: FC<{}> = () => {
const [githubUsername, setGithubUsername] = useState(String);
const [githubPersonalAuthToken, setGithubPersonalAuthToken] = useState(String);
const [githubPersonalAuthToken, setGithubPersonalAuthToken] = useState(
String,
);
const [loginDetails, setLoginDetails] = useState(Object);
const saveGithubInfo = (info: {}) => {
@@ -70,11 +72,11 @@ const LoginPage: FC<{}> = () => {
'Content-Type': 'application/x-www-form-urlencoded',
}),
})
.then((response) => {
.then(response => {
if (response.status === 200) return response.json();
throw Error(`${response.status} ${response.statusText}`);
})
.then((data) => {
.then(data => {
const info = {
username: username,
token: token,
@@ -158,6 +160,7 @@ const LoginPage: FC<{}> = () => {
</ListItem>
<ListItem>
<Button
data-testid="github-auth-button"
variant="outlined"
color="primary"
onClick={() => authenticate(AuthType.GitHub)}
@@ -174,4 +177,4 @@ const LoginPage: FC<{}> = () => {
);
};
export default LoginPage;
export default LoginPage;
@@ -78,7 +78,11 @@ const SupportButton: FC<Props> = ({
return (
<Fragment>
<Button color="primary" onClick={onClickHandler}>
<Button
data-testid="support-button"
color="primary"
onClick={onClickHandler}
>
<HelpIcon className={classes.leftIcon} />
Support
</Button>
+1 -1
View File
@@ -94,7 +94,7 @@ export const SidebarItem: FC<SidebarItemProps> = ({
onClick={onClick}
underline="none"
>
<div className={classes.iconContainer}>
<div data-testid="login-button" className={classes.iconContainer}>
<Icon fontSize="small" />
</div>
<Typography variant="subtitle1" className={classes.label}>