Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f0e4a09
➖ chore: unignore `entry_types` and `permission_groups` models in Pri…
ByteKatana Jul 20, 2026
df6d103
♻️ refactor: migrate `entry_types` controller from MongoDB to Prisma
ByteKatana Jul 20, 2026
7126fb2
🩹 fix: update `created_at` and `updated_at` to fix TS2352 errors
ByteKatana Jul 20, 2026
b7f07a9
🔧 chore: update test configurations
ByteKatana Jul 20, 2026
f805500
♻️ refactor: export `PermissionGroup` and `EntryType` types directly …
ByteKatana Jul 20, 2026
e314086
:test_tube: test: replace MongoDB mocks with Prisma implementation in…
ByteKatana Jul 20, 2026
a7ac7d1
:test_tube: test: update tests for entry-type API routes with Prisma …
ByteKatana Jul 20, 2026
891a67c
🧪 test: migrate `entry.controller.test.ts` to use Prisma mocks instea…
ByteKatana Jul 20, 2026
12709bd
♻️ refactor: migrate `entry.controller.ts` from MongoDB to Prisma
ByteKatana Jul 20, 2026
92ccd39
:test_tube: test: update `entryTypeId` to be dynamically generated wi…
ByteKatana Jul 20, 2026
95fc711
➖ chore: unignore `entries` model in Prisma schema
ByteKatana Jul 20, 2026
3a7acab
🚚 chore: move prisma mocks to their standard Jest locations.
ByteKatana Jul 21, 2026
5fa0835
🚚 chore: move prisma mocks to their standard Jest locations.
ByteKatana Jul 21, 2026
12baccf
:test_tube: test: simplify Prisma mocking in test files
ByteKatana Jul 21, 2026
6d466df
:test_tube: test: replace MongoDB mocks with Prisma implementation in…
ByteKatana Jul 21, 2026
e8c589a
♻️ refactor: migrate `permission-group.controller.ts` from MongoDB to…
ByteKatana Jul 21, 2026
c151814
♻️ refactor: remove redundant comments in test mocks
ByteKatana Jul 21, 2026
f9f9ad6
♻️ refactor: add missing oauth field in prisma schema
ByteKatana Jul 21, 2026
94c5446
:test_tube: test: extend Prisma mocks with `user` model
ByteKatana Jul 22, 2026
36e07e1
♻️ refactor: migrate `user.controller.ts` from MongoDB to Prisma
ByteKatana Jul 22, 2026
07d1437
🧪 test: update `entries` API tests with Prisma mocks and enhanced req…
ByteKatana Jul 23, 2026
5edd973
🧪 test: update `permission-groups` API tests with Prisma mocks and en…
ByteKatana Jul 23, 2026
41a955a
🧪 test: update `users` API tests with Prisma mocks and enhanced reque…
ByteKatana Jul 23, 2026
26b1094
🧪 test: extend API builder mock with `users` mock data and filtering …
ByteKatana Jul 23, 2026
6d306d9
🧪 test: extend global setup with fetch API and related globals for tests
ByteKatana Jul 23, 2026
c971eb6
🧪 test: add unit tests for `permission-groups` server actions with Pr…
ByteKatana Jul 24, 2026
d8a2550
🧪 test: add unit tests for `stats` server actions with Prisma mocks
ByteKatana Jul 24, 2026
46b848a
🧪 test: add unit tests for `permission-groups` server actions with AP…
ByteKatana Jul 25, 2026
ebe5fb1
♻️ refactor: migrate `getPermissionGroups` action from MongoDB to Prisma
ByteKatana Jul 25, 2026
43a0472
♻️ refactor: migrate `updatePermissionGroups` action from MongoDB to …
ByteKatana Jul 25, 2026
d7e6381
♻️ refactor: migrate `getOverviewStats` action from MongoDB to Prisma
ByteKatana Jul 25, 2026
46e113d
♻️ refactor: add `created_at` field to `Entry` model in Prisma schema
ByteKatana Jul 25, 2026
9a67158
🛠️ chore: update tsconfig to refine test file exclusion pattern
ByteKatana Jul 25, 2026
df114ac
🧪 test: add unit tests for `auth` module with provider and callback m…
ByteKatana Jul 25, 2026
e86de49
🧪 test: add unit tests for `studio/settings` server actions with Pris…
ByteKatana Jul 25, 2026
b88675f
♻️ refactor: migrate all `studio/settings` server actions from MongoD…
ByteKatana Jul 25, 2026
3e35c6c
♻️ refactor: update `ApiKey` model with additional fields in Prisma s…
ByteKatana Jul 25, 2026
3502968
♻️ refactor: migrate `auth` module from MongoDB to Prisma
ByteKatana Jul 25, 2026
c97f81d
🧪 test: add unit tests for `auth` module's email verification and per…
ByteKatana Jul 25, 2026
40044e6
♻️ refactor: complete migration of `auth` module server actions from …
ByteKatana Jul 25, 2026
3320087
🧪 test: add Jest mocks for Prisma, Next.js cache, and server session …
ByteKatana Jul 25, 2026
071ac44
🧪 test: add unit tests for `api-key` and `api-builder` controllers, a…
ByteKatana Jul 25, 2026
e63ed23
♻️ refactor: migrate `api-key` and `api-builder` controllers from Mon…
ByteKatana Jul 25, 2026
ad76c02
♻️ refactor: replace manual MongoDB setup with Prisma migrations in `…
ByteKatana Jul 25, 2026
6ffbdfa
🧪 test: extend Prisma mocks with `findFirst`, `findMany`, and `delete…
ByteKatana Jul 25, 2026
ee9bdb7
🔥 chore: remove unused MongoDB connection file after Prisma migration
ByteKatana Jul 25, 2026
a032739
Merge branch 'main' into refactor/migrate-to-prisma
ByteKatana Jul 25, 2026
3112686
🧪 test: remove async modifier from Jest mock implementation that has …
ByteKatana Jul 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions __mocks__/controllers/api-builder.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
export const apiBuilderController = jest
.fn()
.mockImplementation((routeType: string, collectionName: string, findWhere: any, routeData: any) => {
return {
routeType,
collectionName,
findWhere,
routeData,
fetchData: jest.fn().mockImplementation((_findType?: string) => {
if (collectionName === "users") {
const mockUsers = [
{ id: "1", username: "mock_user", permission_group: "admin", email: "mock1@test.com" },
{ id: "2", username: "mock_user", permission_group: "admin", email: "mock2@test.com" },
{ id: "3", username: "mock_user", permission_group: "admin", email: "mock3@test.com" },
{ id: "4", username: "other_user", permission_group: "editor", email: "other1@test.com" },
{ id: "5", username: "root_user", permission_group: "root", email: "root@test.com" }
]

if (routeType === "index") {
return mockUsers
} else if (routeType === "single-param") {
if (findWhere === "permission_group") {
return mockUsers.filter((u) => u.permission_group === routeData)
} else if (findWhere === "username") {
return mockUsers.filter((u) => u.username === routeData)
}
return mockUsers
}
return []
}

const mockEntryTypes = [
{ id: "1", name: "Type 1", namespace: "test-entry-type", slug: "type-1" },
{ id: "2", name: "Type 2", namespace: "test-entry-type", slug: "type-2" },
{ id: "3", name: "Type 3", namespace: "newtest.newtest1", slug: "type-3" },
{ id: "4", name: "Type 4", namespace: "newtest.newtest1", slug: "type-4" },
{ id: "5", name: "Type 5", namespace: "other-namespace", slug: "type-5" }
]

if (routeType === "index") {
return mockEntryTypes
} else if (routeType === "single-param") {
if (routeData === "test-entry-type") {
return mockEntryTypes.filter((et) => et.namespace === "test-entry-type")
}
return mockEntryTypes
} else if (routeType === "multi-param") {
const ns = Array.isArray(routeData) ? routeData.join(".") : routeData
return mockEntryTypes.filter((et) => et.namespace === ns)
}
return []
})
}
})
3 changes: 3 additions & 0 deletions __mocks__/controllers/api-key.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const apiKeyController = jest.fn().mockImplementation(() => ({
findKey: jest.fn().mockResolvedValue([{ key: "valid-key" }])
}))
2 changes: 2 additions & 0 deletions __mocks__/lib/api/rate-limits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Mock rate limiting to be a direct pass-through to simplify route testing
export const withRateLimit = (handler: any) => handler
3 changes: 3 additions & 0 deletions __mocks__/lib/api/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Mock API key controller and utility checks
export const isSystemApiKey = jest.fn().mockImplementation((key: string) => key === "system-key")
export const isValidApiKey = jest.fn().mockImplementation((_keyData: any, key: string) => key === "valid-key")
3 changes: 3 additions & 0 deletions __mocks__/lib/check-permission-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Mock permission checking API helper to isolate controller validation
const checkPermissionApi = jest.fn()
export default checkPermissionApi
136 changes: 101 additions & 35 deletions __tests__/api/entries/entries.api.test.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,59 @@
/**
* @jest-environment node
*/
/* eslint-disable @typescript-eslint/no-require-imports */
import httpMocks from "node-mocks-http"
import { NextApiRequest, NextApiResponse } from "next"
import indexRouteHandler from "../../../pages/api/v1/entries/index"
import slugRouteHandler from "../../../pages/api/v1/entries/[slug]"
import paramRouteHandler from "../../../pages/api/v1/entries/[...param]"
import { Entry } from "../../../interfaces"
import indexRouteHandler from "@/pages/api/v1/entries/index"
import slugRouteHandler from "@/pages/api/v1/entries/[slug]"
import paramRouteHandler from "@/pages/api/v1/entries/[...param]"
import { Entry } from "@/interfaces"
import checkPermissionApi from "@/lib/check-permission-api"

describe("/api/v1/entries/", () => {
afterEach(() => {
// Mock rate limiting to be a direct pass-through to simplify route testing
jest.mock("@/lib/api/rate-limits", () => require("@/__mocks__/lib/api/rate-limits"))

// Mock permission checking API helper to isolate controller validation
jest.mock("@/lib/check-permission-api", () => require("@/__mocks__/lib/check-permission-api"))

// Mock API key controller and utility checks
jest.mock("@/lib/api/utils", () => require("@/__mocks__/lib/api/utils"))

jest.mock("@/controllers/api-key.controller", () => require("@/__mocks__/controllers/api-key.controller"))

// Mock apiBuilderController to bypass MongoDB queries and return mock objects directly
jest.mock("@/controllers/api-builder.controller", () =>
require("@/__mocks__/controllers/api-builder.controller")
)

describe("/api/v1/entries", () => {
const mockCheckPermissionApi = checkPermissionApi as jest.Mock

beforeEach(() => {
jest.clearAllMocks()
})

it("GET / - should return all entries", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24"
apikey: "system-key"
}
})

const response = httpMocks.createResponse<NextApiResponse>()

await indexRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.message).not.toBe({ message: "You're not authorized!" })
expect(Array.isArray(data)).toBe(true)
expect(data.length).toBe(5)
})

it("GET / - should return 'You're not authorized' if there is no API key ", async () => {
it("GET / - should return 'You're not authorized' if there is no API key", async () => {
const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
Expand All @@ -37,143 +63,183 @@ describe("/api/v1/entries/", () => {
})

const response = httpMocks.createResponse<NextApiResponse>()

await indexRouteHandler(request, response)
const data = await response._getJSONData()
expect(response._getStatusCode()).toBe(200)

expect(response._getStatusCode()).toBe(401)
expect(data.message).toBe("You're not authorized!")
})

it("GET /first_X - should return first X entries", async () => {
it("GET /first_X - should return first X entries", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
apikey: "system-key",
slug: "first_3"
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await slugRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.message).not.toBe({ message: "You're not authorized!" })
expect(data.length).toBeLessThanOrEqual(3)
})

it("GET /last_X - should return last X entries", async () => {
it("GET /last_X - should return last X entries", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
apikey: "system-key",
slug: "last_3"
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await slugRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.message).not.toBe({ message: "You're not authorized!" })
expect(data.length).toBeLessThanOrEqual(3)
})

it("GET /random_X - should return random X entries", async () => {
it("GET /random_X - should return random X entries", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
apikey: "system-key",
slug: "random_3"
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await slugRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.message).not.toBe({ message: "You're not authorized!" })
expect(data.length).toBeLessThanOrEqual(3)
})

it("GET /api/v1/entries/:namespace - should return entries from a namespace", async () => {
it("GET /api/v1/entries/:namespace - should return entries from a namespace", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
apikey: "system-key",
slug: "test-entry-type"
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await slugRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
data.forEach((entry: Entry) => {
expect(entry.namespace).toEqual("test-entry-type")
})
})

it("GET /api/v1/entries/:namespace/first_X - should return first X entries from a namespace", async () => {
it("GET /api/v1/entries/:namespace-part-1/:namespace-part-2/ - should return entries from sub-namespace", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
param: ["test-entry-type", "first_3"]
apikey: "system-key",
param: ["newtest", "newtest1"]
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await paramRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
data.forEach((entry: Entry) => {
expect(entry.namespace).toEqual("newtest.newtest1")
})
})

it("GET /api/v1/entries/:namespace-part-1/:namespace-part-2/first_x - should return first X entries from sub-namespace", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "system-key",
param: ["newtest", "newtest1", "first_3"]
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await paramRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.length).toBeLessThanOrEqual(3)
data.forEach((entry: Entry) => {
expect(entry.namespace).toEqual("test-entry-type")
expect(entry.namespace).toEqual("newtest.newtest1")
})
})

it("GET /api/v1/entries/:namespace/last_X - should return last X entries from a namespace", async () => {
it("GET /api/v1/entries/:namespace-part-1/:namespace-part-2/last_x - should return last X entries from sub-namespace", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
param: ["test-entry-type", "last_3"]
apikey: "system-key",
param: ["newtest", "newtest1", "last_3"]
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await paramRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.length).toBeLessThanOrEqual(3)
data.forEach((entry: Entry) => {
expect(entry.namespace).toEqual("test-entry-type")
expect(entry.namespace).toEqual("newtest.newtest1")
})
})

it("GET /api/v1/entries/:namespace/random_X - should return random X entries from a namespace", async () => {
it("GET /api/v1/entries/:namespace-part-1/:namespace-part-2/random_x - should return random X entries from sub-namespace", async () => {
mockCheckPermissionApi.mockResolvedValue(true)

const request = httpMocks.createRequest<NextApiRequest>({
method: "GET",
url: "/api/v1/entries",
query: {
apikey: "dbbf764d6ce785adb15a184699867b24",
param: ["test-entry-type", "random_3"]
apikey: "system-key",
param: ["newtest", "newtest1", "random_3"]
}
})
const response = httpMocks.createResponse<NextApiResponse>()

await paramRouteHandler(request, response)
const data = await response._getJSONData()

expect(response._getStatusCode()).toBe(200)
expect(data.length).toBeLessThanOrEqual(3)
data.forEach((entry: Entry) => {
expect(entry.namespace).toEqual("test-entry-type")
expect(entry.namespace).toEqual("newtest.newtest1")
})
})
})
Loading
Loading