Add some mocha/chai tests
This commit is contained in:
@@ -3,7 +3,8 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"browser": false,
|
"browser": false,
|
||||||
"es6": true
|
"es6": true,
|
||||||
|
"mocha": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2018
|
"ecmaVersion": 2018
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ const login = async (req, res, next) => {
|
|||||||
try {
|
try {
|
||||||
user = await users.getByEmail(req.body.email);
|
user = await users.getByEmail(req.body.email);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
|
||||||
return next(error, null);
|
return next(error, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"aws-sdk": "^2.792.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
@@ -12,13 +13,17 @@
|
|||||||
"shortid": "^2.2.15"
|
"shortid": "^2.2.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"chai": "^4.2.0",
|
||||||
|
"chai-http": "^4.3.0",
|
||||||
"eslint": "^7.12.1",
|
"eslint": "^7.12.1",
|
||||||
"eslint-config-prettier": "^6.15.0",
|
"eslint-config-prettier": "^6.15.0",
|
||||||
|
"faker": "^5.1.0",
|
||||||
|
"mocha": "^8.2.1",
|
||||||
"prettier": "^2.1.2"
|
"prettier": "^2.1.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"pretest": "eslint --ignore-path ../.gitignore .",
|
"pretest": "eslint --ignore-path ../.gitignore .",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "mocha",
|
||||||
"format": "prettier --write \"**/*.{js,json,md,yml}\""
|
"format": "prettier --write \"**/*.{js,json,md,yml}\""
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
|
|||||||
@@ -15,11 +15,12 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"gatsby": "^2.25.3",
|
"gatsby": "^2.25.3",
|
||||||
"react": "^16.12.0",
|
|
||||||
"react-dom": "^16.12.0",
|
|
||||||
"react-router-dom": "^5.1.2",
|
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"moment": "^2.24.0"
|
"moment": "^2.24.0",
|
||||||
|
"react": "^16.12.0",
|
||||||
|
"react-bootstrap": "^1.4.0",
|
||||||
|
"react-dom": "^16.12.0",
|
||||||
|
"react-router-dom": "^5.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^7.12.1",
|
"eslint": "^7.12.1",
|
||||||
|
|||||||
@@ -1,284 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import { Link } from "gatsby";
|
|
||||||
import styles from "./Auth.module.css";
|
|
||||||
import { userRegister, userLogin, userGet, saveSession } from "../../utils";
|
|
||||||
|
|
||||||
class Auth extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
const pathName = window.location.pathname.replace("/", "");
|
|
||||||
|
|
||||||
this.state = {};
|
|
||||||
this.state.state = pathName;
|
|
||||||
this.state.loading = true;
|
|
||||||
this.state.error = null;
|
|
||||||
this.state.formEmail = "";
|
|
||||||
this.state.formPassword = "";
|
|
||||||
|
|
||||||
// Bindings
|
|
||||||
this.handleFormInput = this.handleFormInput.bind(this);
|
|
||||||
this.handleFormSubmit = this.handleFormSubmit.bind(this);
|
|
||||||
this.handleFormTypeChange = this.handleFormTypeChange.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Component did mount
|
|
||||||
*/
|
|
||||||
componentDidMount() {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Clear query params
|
|
||||||
const url = document.location.href;
|
|
||||||
window.history.pushState({}, "", url.split("?")[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles a form change
|
|
||||||
*/
|
|
||||||
handleFormTypeChange(type) {
|
|
||||||
this.setState({ state: type }, () => {
|
|
||||||
this.props.history.push(`/${type}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle text changes within form fields
|
|
||||||
*/
|
|
||||||
handleFormInput(field, value) {
|
|
||||||
value = value.trim();
|
|
||||||
|
|
||||||
const nextState = {};
|
|
||||||
nextState[field] = value;
|
|
||||||
|
|
||||||
this.setState(Object.assign(this.state, nextState));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles form submission
|
|
||||||
* @param {object} evt
|
|
||||||
*/
|
|
||||||
async handleFormSubmit(evt) {
|
|
||||||
evt.preventDefault();
|
|
||||||
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
// Validate email
|
|
||||||
if (!this.state.formEmail) {
|
|
||||||
return this.setState({
|
|
||||||
loading: false,
|
|
||||||
formError: "email is required",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate password
|
|
||||||
if (!this.state.formPassword) {
|
|
||||||
return this.setState({
|
|
||||||
loading: false,
|
|
||||||
formError: "password is required",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let token;
|
|
||||||
try {
|
|
||||||
if (this.state.state === "register") {
|
|
||||||
token = await userRegister(
|
|
||||||
this.state.formEmail,
|
|
||||||
this.state.formPassword
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
token = await userLogin(
|
|
||||||
this.state.formEmail,
|
|
||||||
this.state.formPassword
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
if (error.message) {
|
|
||||||
this.setState({
|
|
||||||
formError: error.message,
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
formError:
|
|
||||||
"Sorry, something unknown went wrong. Please try again.",
|
|
||||||
loading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch user record and set session in cookie
|
|
||||||
let user = await userGet(token.token);
|
|
||||||
user = user.user;
|
|
||||||
saveSession(user.id, user.email, token.token);
|
|
||||||
|
|
||||||
window.location.replace("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className={`${styles.container} animateFadeIn`}>
|
|
||||||
<div className={styles.containerInner}>
|
|
||||||
{/* Logo */}
|
|
||||||
|
|
||||||
<Link to="/" className={`${styles.logo}`}>
|
|
||||||
<img
|
|
||||||
draggable="false"
|
|
||||||
src={"./fullstack-app-title.png"}
|
|
||||||
alt="serverless-fullstack-application"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
|
|
||||||
{/* Loading */}
|
|
||||||
|
|
||||||
{this.state.loading && <div>loading, man!</div>}
|
|
||||||
|
|
||||||
{/* Registration Form */}
|
|
||||||
|
|
||||||
{!this.state.loading && (
|
|
||||||
<div className={styles.formType}>
|
|
||||||
<div
|
|
||||||
className={`${styles.formTypeRegister}
|
|
||||||
${
|
|
||||||
this.state.state === "register" ? styles.formTypeActive : ""
|
|
||||||
}`}
|
|
||||||
onClick={(e) => {
|
|
||||||
this.handleFormTypeChange("register");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Register
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`${styles.formTypeSignIn}
|
|
||||||
${this.state.state === "login" ? styles.formTypeActive : ""}`}
|
|
||||||
onClick={(e) => {
|
|
||||||
this.handleFormTypeChange("login");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Sign-In
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{this.state.state === "register" && !this.state.loading && (
|
|
||||||
<div className={styles.containerRegister}>
|
|
||||||
<form
|
|
||||||
className={styles.form}
|
|
||||||
onSubmit={this.handleFormSubmit}
|
|
||||||
>
|
|
||||||
<div className={styles.formField}>
|
|
||||||
<label className={styles.formLabel}>
|
|
||||||
email
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="yours@example.com"
|
|
||||||
className={styles.formInput}
|
|
||||||
value={this.state.formEmail}
|
|
||||||
onChange={(e) => {
|
|
||||||
this.handleFormInput(
|
|
||||||
"formEmail",
|
|
||||||
e.target.value
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formField}>
|
|
||||||
<label className={styles.formLabel}>
|
|
||||||
password
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
placeholder="your password"
|
|
||||||
className={styles.formInput}
|
|
||||||
value={this.state.formPassword}
|
|
||||||
onChange={(e) => {
|
|
||||||
this.handleFormInput(
|
|
||||||
"formPassword",
|
|
||||||
e.target.value
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.state.formError && (
|
|
||||||
<div className={styles.formError}>
|
|
||||||
{this.state.formError}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<input
|
|
||||||
className={`buttonPrimaryLarge ${styles.formButton}`}
|
|
||||||
type="submit"
|
|
||||||
value="Register"
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{this.state.state === "login" && !this.state.loading && (
|
|
||||||
<div className={styles.containerSignIn}>
|
|
||||||
<form
|
|
||||||
className={styles.form}
|
|
||||||
onSubmit={this.handleFormSubmit}
|
|
||||||
>
|
|
||||||
<div className={styles.formField}>
|
|
||||||
<label className={styles.formLabel}>
|
|
||||||
email
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="yours@example.com"
|
|
||||||
className={styles.formInput}
|
|
||||||
value={this.state.formEmail}
|
|
||||||
onChange={(e) => {
|
|
||||||
this.handleFormInput(
|
|
||||||
"formEmail",
|
|
||||||
e.target.value
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.formField}>
|
|
||||||
<label className={styles.formLabel}>
|
|
||||||
password
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
placeholder="your password"
|
|
||||||
className={styles.formInput}
|
|
||||||
value={this.state.formPassword}
|
|
||||||
onChange={(e) => {
|
|
||||||
this.handleFormInput(
|
|
||||||
"formPassword",
|
|
||||||
e.target.value
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.state.formError && (
|
|
||||||
<div className={styles.formError}>
|
|
||||||
{this.state.formError}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<input
|
|
||||||
className={`buttonPrimaryLarge ${styles.formButton}`}
|
|
||||||
type="submit"
|
|
||||||
value="Sign In"
|
|
||||||
/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Auth;
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import React, { Component } from "react";
|
|
||||||
import { withRouter } from "react-router-dom";
|
|
||||||
import styles from "./Dashboard.module.css";
|
|
||||||
import { getSession, deleteSession } from "../../utils";
|
|
||||||
|
|
||||||
class Dashboard extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {};
|
|
||||||
|
|
||||||
// Bindings
|
|
||||||
this.logout = this.logout.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
|
||||||
const userSession = getSession();
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
session: userSession,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Log user out by clearing cookie and redirecting
|
|
||||||
*/
|
|
||||||
logout() {
|
|
||||||
deleteSession();
|
|
||||||
this.props.history.push(`/`);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className={`${styles.container} animateFadeIn`}>
|
|
||||||
<div className={styles.containerInner}>
|
|
||||||
{/* Navigation */}
|
|
||||||
|
|
||||||
<div className={styles.navigationContainer}>
|
|
||||||
<div className={`link`}>
|
|
||||||
{this.state.session
|
|
||||||
? this.state.session.userEmail
|
|
||||||
: ""}
|
|
||||||
</div>
|
|
||||||
<div className={`link`} onClick={this.logout}>
|
|
||||||
logout
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Content */}
|
|
||||||
|
|
||||||
<div className={`${styles.contentContainer}`}>
|
|
||||||
<div className={`${styles.artwork} animateFlicker`}>
|
|
||||||
<img
|
|
||||||
draggable="false"
|
|
||||||
src={"./fullstack-app-artwork.png"}
|
|
||||||
alt="serverless-fullstack-application"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={`${styles.welcomeMessage}`}>
|
|
||||||
Welcome to your serverless fullstack dashboard...
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withRouter(Dashboard);
|
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Auth from "../components/Auth/Auth";
|
import { Container, Row, Col } from "react-bootstrap";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Container>
|
||||||
|
<Row>
|
||||||
|
<Col>
|
||||||
<p>Hello world!</p>
|
<p>Hello world!</p>
|
||||||
<Auth />
|
</Col>
|
||||||
</div>
|
</Row>
|
||||||
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user