Skip to content
Draft
8 changes: 8 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
"next",
"prettier"
],
"overrides": [
{
"files": ["__tests__/**/*"],
"env": {
"jest": true
}
}
],
"plugins": ["@typescript-eslint", "prettier", "unicorn", "lit-a11y"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
Expand Down
33 changes: 33 additions & 0 deletions __tests__/api.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { NextRequest } from 'next/server';
import testCases from './api_test_cases';

describe('API Routes', () => {
afterAll(async () => {
const client = (global as any).__MONGO_CLIENT__;
await client.close();
});

test.each(testCases)(
'$name',
async ({
method,
path,
handler,
params,
body,
expectedPayload,
expectedStatus,
}) => {
const req = new NextRequest(`http://localhost:3000${path}`, {
method,
body,
});

const res = await handler(req, params);

expect(res.status).toBe(expectedStatus);
const data = await res.json();
expect(data).toEqual(expectedPayload);
}
);
});
72 changes: 72 additions & 0 deletions __tests__/api_test_cases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { NextRequest, NextResponse } from 'next/server';
import { GET as getMedia } from '../app/(api)/api/media/[id]/get';

type TestCase = {
name: string;
method: string;
path: string;
handler: (
req: NextRequest,
{ params }: any
) => Promise<
| NextResponse<{ ok: boolean; body: any }>
| NextResponse<{ ok: boolean; error: string }>
>;
params: any;
body: any;
expectedPayload: any;
expectedStatus: number;
};

const testCases: TestCase[] = [
{
name: 'GET /api/media/[id]',
method: 'GET',
path: '/api/media',
handler: getMedia,
params: { params: { id: '66922047aab73406a4292de4' } },
body: null,
expectedPayload: {
ok: true,
body: {
_id: '66922047aab73406a4292de4',
media_type: 'occaecati',
name: 'ut',
alt_text: 'Pauci veritas damno totus thermae carcer aperio.',
media_url: 'https://wretched-disconnection.org',
preview_url: 'https://hilarious-transformation.biz/',
date_added: '2023-12-20T14:52:58.552Z',
},
},
expectedStatus: 200,
},
{
name: 'GET /api/media/[id]',
method: 'GET',
path: '/api/media',
handler: getMedia,
params: { params: { id: '111111111111111111111111' } },
body: null,
expectedPayload: {
ok: false,
error: 'Item with id: 111111111111111111111111 not found.',
},
expectedStatus: 404,
},
{
name: 'GET /api/media/[id]',
method: 'GET',
path: '/api/media',
handler: getMedia,
params: { params: { id: 'not_a_real_id' } },
body: null,
expectedPayload: {
ok: false,
error:
'input must be a 24 character hex string, 12 byte Uint8Array, or an integer',
},
expectedStatus: 400,
},
];

export default testCases;
55 changes: 55 additions & 0 deletions __tests__/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import '@testing-library/jest-dom';
import { MongoClient } from 'mongodb';

let client;
let db;

beforeAll(async () => {
client = await MongoClient.connect((global as any).__MONGO_URI__, {
useNewUrlParser: true,
useUnifiedTopology: true,
} as any);
db = await client.db();

// Make the client available globally
(global as any).__MONGO_CLIENT__ = client;

await db.createCollection('media', {
validator: {
$jsonSchema: {
bsonType: 'object',
title: 'Media Object Validation',
properties: {
_id: {
bsonType: 'objectId',
description: '_id must be an ObjectId',
},
media_type: {
bsonType: 'string',
description: 'Media Type must be a string',
},
name: {
bsonType: 'string',
description: 'Name must be a string',
},
alt_text: {
bsonType: 'string',
description: 'Alternative text must be a string',
},
media_url: {
bsonType: 'string',
description: 'Media url must be a string',
},
preview_url: {
bsonType: 'string',
description: 'Preview url must be a string',
},
date_added: {
type: Date,
default: Date.now,
},
},
},
},
});
});
8 changes: 8 additions & 0 deletions __tests__/teardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = async () => {
// Access the client that was stored globally
const client = (global as any).__MONGO_CLIENT__;
if (client) {
await client.close();
console.log('MongoDB connection closed');
}
};
13 changes: 11 additions & 2 deletions app/(api)/_datalib/media/createMediaItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,26 @@ import { NextResponse } from 'next/server';
import { ObjectId } from 'mongodb';

import { getDatabase } from '../../_utils/mongodb/mongoClient.mjs';
import { HttpError, NoContentError } from '../../_utils/response/Errors';
import {
BadRequestError,
HttpError,
NoContentError,
} from '../../_utils/response/Errors';
import parseAndReplace from '@utils/request/parseAndReplace';
import Media from '@typeDefs/Media';

export default async function createMediaItem(data: object) {
try {
const parsedData = await parseAndReplace(data);
const parsedData: Media = await parseAndReplace(data);

if (!data || Object.keys(parsedData).length === 0) {
throw new NoContentError();
}

if (parsedData.media_type === 'video' && !parsedData.preview_url) {
throw new BadRequestError('Bad Request: Videos must contain preview_url');
}

const db = await getDatabase();
const creationStatus = await db.collection('media').insertOne(parsedData);

Expand Down
61 changes: 0 additions & 61 deletions app/(api)/_migrations/examples/add-delete-field-sample.js

This file was deleted.

56 changes: 0 additions & 56 deletions app/(api)/_migrations/examples/rename-field-sample.js

This file was deleted.

7 changes: 2 additions & 5 deletions app/(api)/_schema/Media.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const Media = {
const media = {
bsonType: 'object',
title: 'Media Object Validation',
properties: {
Expand All @@ -25,9 +25,6 @@ const Media = {
preview_url: {
bsonType: 'string',
description: 'Preview url must be a string',
required: function () {
return this.media_type === 'video'; // Preview URL required only for videos
},
},
date_added: {
type: Date,
Expand All @@ -36,4 +33,4 @@ const Media = {
},
};

export default Media;
export default media;
21 changes: 0 additions & 21 deletions app/(api)/_schema/Pokemon.mjs

This file was deleted.

Loading