Skip to content

Commit

Permalink
test: all api (not backend) unit tests passing
Browse files Browse the repository at this point in the history
  • Loading branch information
Xunnamius committed Jul 4, 2021
1 parent c48a1c6 commit 48df0de
Show file tree
Hide file tree
Showing 15 changed files with 270 additions and 328 deletions.
2 changes: 1 addition & 1 deletion lib/next-use-redirection/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import * as React from 'react'
import { useRedirection } from 'next-use-redirection'
import { useUser } from 'universe/frontend/hooks'
import PasswordForm from 'components/password-form'
import { WithAuthed, User } from 'types/global';
import type { WithAuthed, User } from 'types/global';

const REDIRECT_ON_NOT_FIRST_LOGIN_LOCATION = '/dashboard';

Expand Down
3 changes: 1 addition & 2 deletions src/pages/api/v1/memes/[...meme_ids].ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
} else sendHttpOk(res, { memes });
} else {
// * PUT
// TODO: validation
await updateMemes({ meme_ids, data: {} });
await updateMemes({ meme_ids, data: req.body });
sendHttpOk(res);
}
},
Expand Down
3 changes: 2 additions & 1 deletion src/pages/api/v1/memes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
regexMatch: {}
})
});
} else
} // * POST
else
sendHttpOk(res, { meme: await createMeme({ creatorKey: key, data: req.body }) });
},
{ req, res, methods: ['GET', 'POST'], apiVersion: 1 }
Expand Down
1 change: 1 addition & 0 deletions src/pages/api/v1/memes/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
}

if (match && regexMatch) {
// * GET
sendHttpOk(res, {
memes: await searchMemes({
after,
Expand Down
18 changes: 10 additions & 8 deletions src/pages/api/v1/users/[user_id]/friends/[friend_id].ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import { wrapHandler } from 'universe/backend/middleware';
import { addFriend, isUserAFriend, removePackmate } from 'universe/backend';
import { addUserAsFriend, isUserAFriend, removeUserAsFriend } from 'universe/backend';
import { sendHttpNotFound, sendHttpOk } from 'multiverse/next-respond';
import { ValidationError } from 'universe/backend/error';
import { ObjectId } from 'mongodb';

import type { NextApiResponse, NextApiRequest } from 'next';
import type { FriendId, UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';

export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
let packmate_id: ObjectId | undefined = undefined;
let user_id: ObjectId | undefined = undefined;
let friend_id: FriendId | undefined = undefined;
let user_id: UserId | undefined = undefined;

try {
packmate_id = new ObjectId(req.query.packmate_id.toString());
friend_id = new ObjectId(req.query.friend_id.toString());
} catch {
throw new ValidationError(
`invalid packmate_id "${req.query.packmate_id.toString()}"`
`invalid friend_id "${req.query.friend_id.toString()}"`
);
}

Expand All @@ -30,14 +31,15 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
}

if (req.method == 'GET') {
(await isUserAFriend({ packmate_id, user_id }))
(await isUserAFriend({ friend_id, user_id }))
? sendHttpOk(res)
: sendHttpNotFound(res);
} else if (req.method == 'DELETE') {
await removePackmate({ packmate_id, user_id });
await removeUserAsFriend({ friend_id, user_id });
sendHttpOk(res);
} else {
await addFriend({ packmate_id, user_id });
// * PUT
await addUserAsFriend({ friend_id, user_id });
sendHttpOk(res);
}
},
Expand Down
10 changes: 6 additions & 4 deletions src/pages/api/v1/users/[user_id]/friends/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import { getRequestsOfType } from 'universe/backend';
import { getUserFriendsUserIds } from 'universe/backend';
import { sendHttpOk } from 'multiverse/next-respond';
import { wrapHandler } from 'universe/backend/middleware';
import { ValidationError } from 'universe/backend/error';
import { ObjectId } from 'mongodb';

import type { NextApiResponse, NextApiRequest } from 'next';
import type { UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';

export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
let after: ObjectId | null | undefined = undefined;
let user_id: ObjectId | undefined = undefined;
let after: UserId | null | undefined = undefined;
let user_id: UserId | undefined = undefined;

try {
after = req.query.after ? new ObjectId(req.query.after.toString()) : null;
Expand All @@ -27,8 +28,9 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
}

// * GET
sendHttpOk(res, {
users: await getRequestsOfType({ user_id, after })
users: await getUserFriendsUserIds({ user_id, after })
});
},
{
Expand Down
18 changes: 13 additions & 5 deletions src/pages/api/v1/users/[user_id]/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,38 @@ import { getUser, deleteUser, updateUser } from 'universe/backend';
import { sendHttpOk } from 'multiverse/next-respond';
import { wrapHandler } from 'universe/backend/middleware';
import { ObjectId } from 'mongodb';
import { GuruMeditationError, ValidationError } from 'universe/backend/error';

import type { NextApiResponse, NextApiRequest } from 'next';
import { ValidationError } from 'universe/backend/error';
import type { UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';

export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
let user_id: ObjectId | undefined = undefined;
const param = req.query.user_id;
let user_id: UserId | undefined = undefined;
let username: string | undefined = undefined;

try {
user_id = new ObjectId(req.query.user_id.toString());
user_id = new ObjectId(param.toString());
} catch {
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
if (req.method != 'GET' || typeof param != 'string' || !param.length)
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
else username = param;
}

if (req.method == 'GET') {
sendHttpOk(res, { user: await getUser({ user_id }) });
sendHttpOk(res, { user: await getUser(user_id ? { user_id } : { username }) });
} else if (!user_id) {
throw new GuruMeditationError('sanity check failed: user_id is missing');
} else if (req.method == 'DELETE') {
await deleteUser({ user_id });
sendHttpOk(res);
} else {
// * PUT
await updateUser({ user_id, data: req.body });
sendHttpOk(res);
}
Expand Down
1 change: 1 addition & 0 deletions src/pages/api/v1/users/[user_id]/liked/[meme_id].ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
}

// * GET
if (user_id !== undefined) {
(await isMemeLiked({ meme_id, user_id }))
? sendHttpOk(res)
Expand Down
6 changes: 4 additions & 2 deletions src/pages/api/v1/users/[user_id]/liked/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import { ValidationError } from 'universe/backend/error';
import { ObjectId } from 'mongodb';

import type { NextApiResponse, NextApiRequest } from 'next';
import type { MemeId, UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';

export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
let after: ObjectId | null | undefined = undefined;
let user_id: ObjectId | undefined = undefined;
let after: MemeId | null | undefined = undefined;
let user_id: UserId | undefined = undefined;

try {
after = req.query.after ? new ObjectId(req.query.after.toString()) : null;
Expand All @@ -27,6 +28,7 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
}

// * GET
sendHttpOk(res, { memes: await getUserLikedMemeIds({ user_id, after }) });
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import { wrapHandler } from 'universe/backend/middleware';
import { addFriendRequest, isUserFollowing, unfollowUser } from 'universe/backend';
import {
addFriendRequest,
isFriendRequestOfType,
removeFriendRequest
} from 'universe/backend';
import { sendHttpNotFound, sendHttpOk } from 'multiverse/next-respond';
import { ValidationError } from 'universe/backend/error';
import { ObjectId } from 'mongodb';

import type { NextApiResponse, NextApiRequest } from 'next';
import type { FriendRequestType, UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';

export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
let followed_id: ObjectId | undefined = undefined;
let user_id: ObjectId | undefined = undefined;
let target_id: UserId | undefined = undefined;
let user_id: UserId | undefined = undefined;
let request_type: FriendRequestType | undefined = undefined;

try {
followed_id = new ObjectId(req.query.followed_id.toString());
target_id = new ObjectId(req.query.target_id.toString());
} catch {
throw new ValidationError(
`invalid user_id "${req.query.followed_id.toString()}"`
`invalid target_id "${req.query.target_id.toString()}"`
);
}

Expand All @@ -29,15 +35,24 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
}

if (!['incoming', 'outgoing'].includes(req.query.request_type.toString())) {
throw new ValidationError(
`invalid request_type "${req.query.request_type.toString()}", expected "incoming" or "outgoing"`
);
}

request_type = req.query.request_type as FriendRequestType;

if (req.method == 'GET') {
(await isUserFollowing({ followed_id, user_id }))
(await isFriendRequestOfType({ target_id, request_type, user_id }))
? sendHttpOk(res)
: sendHttpNotFound(res);
} else if (req.method == 'DELETE') {
await unfollowUser({ followed_id, user_id });
await removeFriendRequest({ target_id, request_type, user_id });
sendHttpOk(res);
} else {
await addFriendRequest({ followed_id, user_id });
// * PUT
await addFriendRequest({ target_id, request_type, user_id });
sendHttpOk(res);
}
},
Expand Down
20 changes: 15 additions & 5 deletions src/pages/api/v1/users/[user_id]/requests/[request_type]/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { getUserFriendsUserIds } from 'universe/backend';
import { getFriendRequestsOfType } from 'universe/backend';
import { sendHttpOk } from 'multiverse/next-respond';
import { wrapHandler } from 'universe/backend/middleware';
import { ValidationError } from 'universe/backend/error';
import { ObjectId } from 'mongodb';

import type { NextApiResponse, NextApiRequest } from 'next';
import type { FriendRequestType, UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';

export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
let after: ObjectId | null | undefined = undefined;
let user_id: ObjectId | undefined = undefined;
const includeIndirect = req.query.includeIndirect !== undefined;
let after: UserId | null | undefined = undefined;
let user_id: UserId | undefined = undefined;
let request_type: FriendRequestType | undefined = undefined;

try {
after = req.query.after ? new ObjectId(req.query.after.toString()) : null;
Expand All @@ -28,8 +29,17 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
throw new ValidationError(`invalid user_id "${req.query.user_id.toString()}"`);
}

if (!['incoming', 'outgoing'].includes(req.query.request_type.toString())) {
throw new ValidationError(
`invalid request_type "${req.query.request_type.toString()}", expected "incoming" or "outgoing"`
);
}

request_type = req.query.request_type as FriendRequestType;

// * GET
sendHttpOk(res, {
users: await getUserFriendsUserIds({ user_id, includeIndirect, after })
users: await getFriendRequestsOfType({ user_id, request_type, after })
});
},
{
Expand Down
7 changes: 5 additions & 2 deletions src/pages/api/v1/users/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ValidationError } from 'universe/backend/error';
import { ObjectId } from 'mongodb';

import type { NextApiResponse, NextApiRequest } from 'next';
import type { UserId } from 'types/global';

// ? This is a NextJS special "config" export
export { defaultConfig as config } from 'universe/backend/middleware';
Expand All @@ -13,7 +14,7 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {
await wrapHandler(
async ({ req, res }) => {
const key = req.headers.key?.toString() || '';
let after: ObjectId | null | undefined = undefined;
let after: UserId | null | undefined = undefined;

try {
after = req.query.after ? new ObjectId(req.query.after.toString()) : null;
Expand All @@ -23,7 +24,9 @@ export default async function (req: NextApiRequest, res: NextApiResponse) {

if (req.method == 'GET') {
sendHttpOk(res, { users: await getAllUsers({ after }) });
} else sendHttpOk(res, { user: await createUser({ key, data: req.body }) });
// * POST
} else
sendHttpOk(res, { user: await createUser({ creatorKey: key, data: req.body }) });
},
{ req, res, methods: ['GET', 'POST'], apiVersion: 1 }
);
Expand Down
3 changes: 3 additions & 0 deletions test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import EndpointBarks, { config as ConfigBarks } from 'universe/pages/api/v1/bark
import EndpointUsers, { config as ConfigUsers } from 'universe/pages/api/v1/users';
import EndpointInfo, { config as ConfigInfo } from 'universe/pages/api/v1/info';

// TODO: make this into a generalized package of some sort... call it:
// TODO: @xunnamius/fable

import EndpointBarksIds, {
config as ConfigBarksIds
} from 'universe/pages/api/v1/barks/[...meme_ids]';
Expand Down
6 changes: 2 additions & 4 deletions test/unit-api-memes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
DUMMY_KEY as KEY,
createMeme,
getMemes,
updateMemes,
getMemeLikesUserIds,
isMemeLiked,
searchMemes
Expand Down Expand Up @@ -43,7 +42,6 @@ jest.mock('universe/backend/middleware');

const mockedCreateMeme = asMockedFunction(createMeme);
const mockedGetMemes = asMockedFunction(getMemes);
const mockedUpdateMemes = asMockedFunction(updateMemes);
const mockedGetMemeLikesUserIds = asMockedFunction(getMemeLikesUserIds);
const mockedIsMemeLiked = asMockedFunction(isMemeLiked);
const mockedSearchMemes = asMockedFunction(searchMemes);
Expand Down Expand Up @@ -228,7 +226,7 @@ describe('api/v1/memes', () => {
});

describe('/:meme_id1/:meme_id2/.../:meme_idN [PUT]', () => {
it('accepts multiple meme_ids, ignoring not found and duplicates', async () => {
it('accepts multiple meme_ids', async () => {
expect.hasAssertions();

const items = [
Expand Down Expand Up @@ -388,7 +386,7 @@ describe('api/v1/memes', () => {
});
});

it('errors if the user has not liked the meme', async () => {
it('404s if the user has not liked the meme', async () => {
expect.hasAssertions();

mockedIsMemeLiked.mockReturnValue(Promise.resolve(false));
Expand Down
Loading

0 comments on commit 48df0de

Please sign in to comment.