mirror of
https://github.com/usatiuk/photos.git
synced 2025-10-28 15:27:49 +01:00
get users working
This commit is contained in:
@@ -40,6 +40,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"@typescript-eslint/require-await": "warn"
|
"@typescript-eslint/require-await": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-member-access": "off",
|
||||||
|
"@typescript-eslint/no-unsafe-assignment": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,13 @@
|
|||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strictFunctionTypes": true,
|
"strictFunctionTypes": true,
|
||||||
"strictNullChecks": true
|
"strictNullChecks": true,
|
||||||
|
"baseUrl": "./src",
|
||||||
|
"paths": {
|
||||||
|
"~*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.ts",
|
"./src/**/*.ts",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "mariadb",
|
"type": "mariadb",
|
||||||
"host": "db",
|
"host": "localhost",
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"username": "photos",
|
"username": "photos",
|
||||||
"password": "photos",
|
"password": "photos",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "mariadb",
|
"type": "mariadb",
|
||||||
"host": "dbtest",
|
"host": "localhost",
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"username": "photos",
|
"username": "photos",
|
||||||
"password": "photos",
|
"password": "photos",
|
||||||
|
|||||||
925
package-lock.json
generated
925
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@@ -3,41 +3,65 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start-frontend": "cd frontend && npm start",
|
"start-frontend": "cd frontend && npm start",
|
||||||
"ts-node-dev": "ts-node-dev ./src/server.ts",
|
"start": "ts-node -T -r tsconfig-paths/register src/server.ts",
|
||||||
|
"ts-node-dev": "ts-node-dev -r tsconfig-paths/register ./src/server.ts",
|
||||||
"dev": "cross-env NODE_ENV=development concurrently npm:ts-node-dev npm:start-frontend -c 'blue,green'",
|
"dev": "cross-env NODE_ENV=development concurrently npm:ts-node-dev npm:start-frontend -c 'blue,green'",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
"test": "cross-env NODE_ENV=test mocha --timeout 15000 -r ts-node/register -r tsconfig-paths/register 'src/tests/**/*.ts' ",
|
||||||
"lint": "eslint ./src/** --ext .js,.jsx,.ts,.tsx",
|
"lint": "eslint ./src/** --ext .js,.jsx,.ts,.tsx",
|
||||||
"lint-frontend": "cd frontend && npm run lint",
|
"lint-frontend": "cd frontend && npm run lint",
|
||||||
"lint-all": "npm run lint && npm run lint-frontend"
|
"lint-all": "npm run lint && npm run lint-frontend"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@koa/cors": "^3.1.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.4.0",
|
"@typescript-eslint/eslint-plugin": "^4.4.0",
|
||||||
"@typescript-eslint/parser": "^4.4.0",
|
"@typescript-eslint/parser": "^4.4.0",
|
||||||
"bcrypt": "^5.0.0",
|
"bcrypt": "^5.0.0",
|
||||||
|
"chai": "^4.2.0",
|
||||||
"concurrently": "^5.3.0",
|
"concurrently": "^5.3.0",
|
||||||
"cross-env": "^7.0.2",
|
"cross-env": "^7.0.2",
|
||||||
"eslint": "^7.10.0",
|
"eslint": "^7.10.0",
|
||||||
"eslint-config-prettier": "^6.12.0",
|
"eslint-config-prettier": "^6.12.0",
|
||||||
"eslint-import-resolver-typescript": "^2.3.0",
|
"eslint-import-resolver-typescript": "^2.3.0",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
|
"eslint-plugin-mocha": "^8.0.0",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"koa": "^2.13.0",
|
"koa": "^2.13.0",
|
||||||
|
"koa-body": "^4.2.0",
|
||||||
|
"koa-jwt": "^4.0.0",
|
||||||
|
"koa-logger": "^3.2.1",
|
||||||
|
"koa-router": "^9.4.0",
|
||||||
|
"koa-send": "^5.0.1",
|
||||||
|
"koa-sslify": "^4.0.3",
|
||||||
|
"koa-static": "^5.0.0",
|
||||||
|
"mocha": "^8.1.3",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
"prettier": "^2.1.2",
|
"prettier": "^2.1.2",
|
||||||
"prettier-eslint": "^11.0.0",
|
"prettier-eslint": "^11.0.0",
|
||||||
|
"supertest": "^5.0.0",
|
||||||
"ts-node": "^9.0.0",
|
"ts-node": "^9.0.0",
|
||||||
"ts-node-dev": "^1.0.0-pre.63",
|
"ts-node-dev": "^1.0.0-pre.63",
|
||||||
|
"tsconfig-paths": "^3.9.0",
|
||||||
"typeorm": "^0.2.28",
|
"typeorm": "^0.2.28",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcrypt": "^3.0.0",
|
"@types/bcrypt": "^3.0.0",
|
||||||
|
"@types/chai": "^4.2.13",
|
||||||
"@types/concurrently": "^5.2.1",
|
"@types/concurrently": "^5.2.1",
|
||||||
"@types/eslint": "^7.2.3",
|
"@types/eslint": "^7.2.3",
|
||||||
"@types/eslint-plugin-prettier": "^3.1.0",
|
"@types/eslint-plugin-prettier": "^3.1.0",
|
||||||
"@types/jsonwebtoken": "^8.5.0",
|
"@types/jsonwebtoken": "^8.5.0",
|
||||||
"@types/koa": "^2.11.4",
|
"@types/koa": "^2.11.4",
|
||||||
"@types/prettier": "^2.1.1"
|
"@types/koa-logger": "^3.1.1",
|
||||||
|
"@types/koa-router": "^7.4.1",
|
||||||
|
"@types/koa-send": "^4.1.2",
|
||||||
|
"@types/koa-sslify": "^4.0.1",
|
||||||
|
"@types/koa-static": "^4.0.1",
|
||||||
|
"@types/koa__cors": "^3.0.2",
|
||||||
|
"@types/mocha": "^8.0.3",
|
||||||
|
"@types/prettier": "^2.1.1",
|
||||||
|
"@types/supertest": "^2.0.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/app.ts
55
src/app.ts
@@ -1,7 +1,58 @@
|
|||||||
|
import "reflect-metadata";
|
||||||
|
|
||||||
|
import * as cors from "@koa/cors";
|
||||||
import * as Koa from "koa";
|
import * as Koa from "koa";
|
||||||
|
import * as bodyParser from "koa-body";
|
||||||
|
import * as jwt from "koa-jwt";
|
||||||
|
import * as logger from "koa-logger";
|
||||||
|
import * as send from "koa-send";
|
||||||
|
import sslify, { xForwardedProtoResolver } from "koa-sslify";
|
||||||
|
import * as serve from "koa-static";
|
||||||
|
|
||||||
|
import { config, EnvType } from "~config";
|
||||||
|
import { userRouter } from "~routes/users";
|
||||||
|
import { devRouter } from "~routes/dev";
|
||||||
|
|
||||||
export const app = new Koa();
|
export const app = new Koa();
|
||||||
|
|
||||||
app.use(async (ctx) => {
|
app.use(cors());
|
||||||
ctx.body = "hello!";
|
app.use(logger());
|
||||||
|
app.use(bodyParser());
|
||||||
|
if (config.env === EnvType.production) {
|
||||||
|
app.use(sslify({ resolver: xForwardedProtoResolver }));
|
||||||
|
}
|
||||||
|
app.use(
|
||||||
|
jwt({
|
||||||
|
secret: config.jwtSecret,
|
||||||
|
passthrough: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.use(async (ctx, next) => {
|
||||||
|
try {
|
||||||
|
await next();
|
||||||
|
const status = ctx.status || 404;
|
||||||
|
if (status === 404) {
|
||||||
|
await send(ctx, "frontend/dist/index.html");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
ctx.status = err.status || 500;
|
||||||
|
ctx.body = err.message;
|
||||||
|
ctx.app.emit("error", err, ctx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(serve("frontend/dist"));
|
||||||
|
|
||||||
|
app.use(userRouter.routes()).use(userRouter.allowedMethods());
|
||||||
|
|
||||||
|
if (config.env === EnvType.development) {
|
||||||
|
app.use(devRouter.routes()).use(devRouter.allowedMethods());
|
||||||
|
}
|
||||||
|
|
||||||
|
app.on("error", (err, ctx) => {
|
||||||
|
ctx.body = {
|
||||||
|
error: err.message,
|
||||||
|
data: false,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,5 +4,7 @@ import { Connection, createConnection } from "typeorm";
|
|||||||
import { config } from "./";
|
import { config } from "./";
|
||||||
|
|
||||||
export async function connect(): Promise<Connection> {
|
export async function connect(): Promise<Connection> {
|
||||||
return createConnection(config.dbConnectionOptions);
|
return config.dbConnectionOptions
|
||||||
|
? createConnection(config.dbConnectionOptions)
|
||||||
|
: createConnection();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,23 +15,39 @@ export interface IConfig {
|
|||||||
dbConnectionOptions: ConnectionOptions | null;
|
dbConnectionOptions: ConnectionOptions | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getJwtSecret(): string {
|
||||||
|
switch (process.env.NODE_ENV) {
|
||||||
|
case "production":
|
||||||
|
if (process.env.JWT_SECRET === undefined) {
|
||||||
|
console.log("JWT_SECRET is not set");
|
||||||
|
process.exit(1);
|
||||||
|
} else {
|
||||||
|
return process.env.JWT_SECRET;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "development":
|
||||||
|
return "DEVSECRET";
|
||||||
|
break;
|
||||||
|
case "test":
|
||||||
|
return "TESTSECRET";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("Unknown NODE_ENV");
|
||||||
|
process.exit(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const production: IConfig = {
|
const production: IConfig = {
|
||||||
env: EnvType.production,
|
env: EnvType.production,
|
||||||
port: process.env.PORT ? parseInt(process.env.PORT, 10) : 3000,
|
port: process.env.PORT ? parseInt(process.env.PORT, 10) : 3000,
|
||||||
jwtSecret: ((): string => {
|
jwtSecret: getJwtSecret(),
|
||||||
if (process.env.JWT_SECRET === undefined) {
|
|
||||||
console.log("JWT_SECRET is not set");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
return process.env.JWT_SECRET;
|
|
||||||
})(),
|
|
||||||
dbConnectionOptions: null,
|
dbConnectionOptions: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const development: IConfig = {
|
const development: IConfig = {
|
||||||
...production,
|
...production,
|
||||||
env: EnvType.development,
|
env: EnvType.development,
|
||||||
jwtSecret: "DEVSECRET",
|
|
||||||
dbConnectionOptions:
|
dbConnectionOptions:
|
||||||
process.env.NODE_ENV === "development"
|
process.env.NODE_ENV === "development"
|
||||||
? fs.existsSync("./ormconfig.dev.json")
|
? fs.existsSync("./ormconfig.dev.json")
|
||||||
@@ -45,7 +61,6 @@ const development: IConfig = {
|
|||||||
const test: IConfig = {
|
const test: IConfig = {
|
||||||
...production,
|
...production,
|
||||||
env: EnvType.test,
|
env: EnvType.test,
|
||||||
jwtSecret: "TESTSECRET",
|
|
||||||
dbConnectionOptions:
|
dbConnectionOptions:
|
||||||
process.env.NODE_ENV === "test"
|
process.env.NODE_ENV === "test"
|
||||||
? process.env.CI
|
? process.env.CI
|
||||||
|
|||||||
9
src/routes/dev.ts
Normal file
9
src/routes/dev.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import * as Router from "koa-router";
|
||||||
|
import { User } from "~entity/User";
|
||||||
|
|
||||||
|
export const devRouter = new Router();
|
||||||
|
|
||||||
|
devRouter.post("/dev/clean", async (ctx) => {
|
||||||
|
await User.remove(await User.find());
|
||||||
|
ctx.body = { success: true };
|
||||||
|
});
|
||||||
117
src/routes/users.ts
Normal file
117
src/routes/users.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import * as Router from "koa-router";
|
||||||
|
import { IUserJWT, User } from "~entity/User";
|
||||||
|
|
||||||
|
export const userRouter = new Router();
|
||||||
|
|
||||||
|
userRouter.get("/users/user", async (ctx) => {
|
||||||
|
if (!ctx.state.user) {
|
||||||
|
ctx.throw(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jwt = ctx.state.user as IUserJWT;
|
||||||
|
|
||||||
|
const user = await User.findOne(jwt.id);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
ctx.throw(401);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = { error: false, data: user.toAuthJSON() };
|
||||||
|
});
|
||||||
|
|
||||||
|
userRouter.post("/users/login", async (ctx) => {
|
||||||
|
const request = ctx.request;
|
||||||
|
|
||||||
|
if (!request.body) {
|
||||||
|
ctx.throw(400);
|
||||||
|
}
|
||||||
|
const { username, password } = request.body as {
|
||||||
|
username: string | undefined;
|
||||||
|
password: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!(username && password)) {
|
||||||
|
ctx.throw(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await User.findOne({ username });
|
||||||
|
if (!user || !(await user.verifyPassword(password))) {
|
||||||
|
ctx.throw(404, "User not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = { error: false, data: user.toAuthJSON() };
|
||||||
|
});
|
||||||
|
|
||||||
|
userRouter.post("/users/signup", async (ctx) => {
|
||||||
|
const request = ctx.request;
|
||||||
|
|
||||||
|
if (!request.body) {
|
||||||
|
ctx.throw(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { username, password, email } = request.body as {
|
||||||
|
username: string | undefined;
|
||||||
|
password: string | undefined;
|
||||||
|
email: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!(username && password && email)) {
|
||||||
|
ctx.throw(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = new User(username, email);
|
||||||
|
await user.setPassword(password);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await user.save();
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code === "ER_DUP_ENTRY") {
|
||||||
|
ctx.throw(400, "User already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = { error: false, data: user.toAuthJSON() };
|
||||||
|
});
|
||||||
|
|
||||||
|
userRouter.post("/users/edit", async (ctx) => {
|
||||||
|
if (!ctx.state.user) {
|
||||||
|
ctx.throw(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jwt = ctx.state.user as IUserJWT;
|
||||||
|
const user = await User.findOne(jwt.id);
|
||||||
|
const request = ctx.request;
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
ctx.throw(401);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request.body) {
|
||||||
|
ctx.throw(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { password } = request.body as {
|
||||||
|
password: string | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!password) {
|
||||||
|
ctx.throw(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.setPassword(password);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await user.save();
|
||||||
|
} catch (e) {
|
||||||
|
ctx.throw(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = { error: false, data: user.toAuthJSON() };
|
||||||
|
});
|
||||||
8
src/tests/.eslintrc.json
Normal file
8
src/tests/.eslintrc.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"mocha"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"plugin:mocha/recommended"
|
||||||
|
]
|
||||||
|
}
|
||||||
142
src/tests/integration/users.test.ts
Normal file
142
src/tests/integration/users.test.ts
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import { expect } from "chai";
|
||||||
|
import { connect } from "config/database";
|
||||||
|
import * as request from "supertest";
|
||||||
|
import { getConnection } from "typeorm";
|
||||||
|
import { app } from "~app";
|
||||||
|
import { IUserAuthJSON, User } from "~entity/User";
|
||||||
|
|
||||||
|
import { ISeed, seedDB } from "./util";
|
||||||
|
|
||||||
|
const callback = app.callback();
|
||||||
|
|
||||||
|
let seed: ISeed;
|
||||||
|
|
||||||
|
describe("users", function () {
|
||||||
|
before(async function () {
|
||||||
|
await connect();
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await getConnection().close();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
seed = await seedDB();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should get user", async function () {
|
||||||
|
const response = await request(callback)
|
||||||
|
.get("/users/user")
|
||||||
|
.set({
|
||||||
|
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
})
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
|
const { jwt: _, ...user } = response.body.data as IUserAuthJSON;
|
||||||
|
|
||||||
|
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should login user", async function () {
|
||||||
|
const response = await request(callback)
|
||||||
|
.post("/users/login")
|
||||||
|
.set({ "Content-Type": "application/json" })
|
||||||
|
.send({ username: "User1", password: "User1" })
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
|
const { jwt: _, ...user } = response.body.data as IUserAuthJSON;
|
||||||
|
|
||||||
|
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not login user with wrong password", async function () {
|
||||||
|
const response = await request(callback)
|
||||||
|
.post("/users/login")
|
||||||
|
.set({ "Content-Type": "application/json" })
|
||||||
|
.send({ username: "User1", password: "asdf" })
|
||||||
|
.expect(404);
|
||||||
|
|
||||||
|
expect(response.body.error).to.be.equal("User not found");
|
||||||
|
expect(response.body.data).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should signup user", async function () {
|
||||||
|
const response = await request(callback)
|
||||||
|
.post("/users/signup")
|
||||||
|
.set({ "Content-Type": "application/json" })
|
||||||
|
.send({
|
||||||
|
username: "NUser1",
|
||||||
|
password: "NUser1",
|
||||||
|
email: "nuser1@users.com",
|
||||||
|
})
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
|
const { jwt: _, ...user } = response.body.data as IUserAuthJSON;
|
||||||
|
|
||||||
|
const newUser = await User.findOneOrFail({ username: "NUser1" });
|
||||||
|
|
||||||
|
expect(user).to.deep.equal(newUser.toJSON());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not signup user with duplicate username", async function () {
|
||||||
|
const response = await request(callback)
|
||||||
|
.post("/users/signup")
|
||||||
|
.set({ "Content-Type": "application/json" })
|
||||||
|
.send({
|
||||||
|
username: "User1",
|
||||||
|
password: "NUser1",
|
||||||
|
email: "user1@users.com",
|
||||||
|
})
|
||||||
|
.expect(400);
|
||||||
|
|
||||||
|
expect(response.body.error).to.be.equal("User already exists");
|
||||||
|
expect(response.body.data).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should change user's password", async function () {
|
||||||
|
const response = await request(callback)
|
||||||
|
.post("/users/edit")
|
||||||
|
.set({
|
||||||
|
Authorization: `Bearer ${seed.user1.toJWT()}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
})
|
||||||
|
.send({
|
||||||
|
password: "User1NewPass",
|
||||||
|
})
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(response.body.error).to.be.false;
|
||||||
|
|
||||||
|
const loginResponse = await request(callback)
|
||||||
|
.post("/users/login")
|
||||||
|
.set({ "Content-Type": "application/json" })
|
||||||
|
.send({ username: "User1", password: "User1NewPass" })
|
||||||
|
.expect("Content-Type", /json/)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
expect(loginResponse.body.error).to.be.false;
|
||||||
|
|
||||||
|
const { jwt: _, ...user } = response.body.data as IUserAuthJSON;
|
||||||
|
expect(user).to.deep.equal(seed.user1.toJSON());
|
||||||
|
|
||||||
|
const badLoginResponse = await request(callback)
|
||||||
|
.post("/users/login")
|
||||||
|
.set({ "Content-Type": "application/json" })
|
||||||
|
.send({ username: "User1", password: "User1" })
|
||||||
|
.expect(404);
|
||||||
|
|
||||||
|
expect(badLoginResponse.body.error).to.be.equal("User not found");
|
||||||
|
expect(badLoginResponse.body.data).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
30
src/tests/integration/util.ts
Normal file
30
src/tests/integration/util.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { User } from "entity/User";
|
||||||
|
//import { Document } from "~entity/Document";
|
||||||
|
|
||||||
|
export interface ISeed {
|
||||||
|
user1: User;
|
||||||
|
user2: User;
|
||||||
|
// doc1: Document;
|
||||||
|
// doc2p: Document;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function seedDB(): Promise<ISeed> {
|
||||||
|
//await Document.remove(await Document.find());
|
||||||
|
await User.remove(await User.find());
|
||||||
|
|
||||||
|
const user1 = new User("User1", "user1@users.com");
|
||||||
|
await user1.setPassword("User1");
|
||||||
|
await user1.save();
|
||||||
|
|
||||||
|
const user2 = new User("User2", "user2@users.com");
|
||||||
|
await user2.setPassword("User2");
|
||||||
|
await user2.save();
|
||||||
|
|
||||||
|
//const doc1 = new Document(user1, "Doc1", "Doc1", false);
|
||||||
|
//const doc2p = new Document(user1, "Doc2", "Doc2", true);
|
||||||
|
|
||||||
|
//await doc1.save();
|
||||||
|
//await doc2p.save();
|
||||||
|
|
||||||
|
return { user1, user2 }; // doc1, doc2p };
|
||||||
|
}
|
||||||
4
src/types.ts
Normal file
4
src/types.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface IAPIResponse<T> {
|
||||||
|
data: T | null;
|
||||||
|
error: string | null;
|
||||||
|
}
|
||||||
@@ -12,10 +12,17 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"strictFunctionTypes": true,
|
"strictFunctionTypes": true,
|
||||||
"strictNullChecks": true
|
"strictNullChecks": true,
|
||||||
|
"baseUrl": "./src",
|
||||||
|
"paths": {
|
||||||
|
"~*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*.ts",
|
"./src/**/*.ts",
|
||||||
|
"./tests/**/*.ts",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"frontend"
|
"frontend"
|
||||||
|
|||||||
Reference in New Issue
Block a user