-
Notifications
You must be signed in to change notification settings - Fork 1
Add Jest Test Infrastructure and Comprehensive Tests for User #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Shengle-Dai
wants to merge
3
commits into
main
Choose a base branch
from
setup-backend-test
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| module.exports = { | ||
| preset: "ts-jest", | ||
| testEnvironment: "node", | ||
| roots: ["<rootDir>/src"], | ||
| testMatch: ["**/__tests__/**/*.test.ts"], | ||
| moduleFileExtensions: ["ts", "js", "json"], | ||
| collectCoverageFrom: [ | ||
| "src/**/*.ts", | ||
| "!src/**/*.d.ts", | ||
| "!src/**/index.ts", | ||
| "!src/server.ts", | ||
| ], | ||
| setupFilesAfterEnv: ["<rootDir>/src/__tests__/setup.ts"], | ||
| moduleNameMapper: { | ||
| "^common$": "<rootDir>/../common/dist/index.js", | ||
| }, | ||
| transform: { | ||
| "^.+\\.ts$": [ | ||
| "ts-jest", | ||
| { | ||
| tsconfig: { | ||
| module: "commonjs", | ||
| esModuleInterop: true, | ||
| }, | ||
| }, | ||
| ], | ||
| }, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| import { User, Order, Organization } from "@prisma/client"; | ||
|
|
||
| /** | ||
| * Test data factory functions | ||
| * | ||
| * These functions create mock data objects that match Prisma's generated types. | ||
| * Use these in tests to create consistent, valid test data. | ||
| */ | ||
|
|
||
| /** | ||
| * Create a mock User object | ||
| * | ||
| * @param overrides - Optional properties to override default values | ||
| * @returns A User object with test data | ||
| * | ||
| * @example | ||
| * const user = createMockUser({ name: 'John Doe' }); | ||
| */ | ||
| export const createMockUser = (overrides?: Partial<User>): User => ({ | ||
| id: "123e4567-e89b-12d3-a456-426614174000", | ||
| email: "test@example.com", | ||
| name: "Test User", | ||
| venmoUsername: null, | ||
| createdAt: new Date("2024-01-01T00:00:00.000Z"), | ||
| ...overrides, | ||
| }); | ||
|
|
||
| /** | ||
| * Create multiple mock User objects | ||
| * | ||
| * @param count - Number of users to create | ||
| * @returns An array of User objects | ||
| * | ||
| * @example | ||
| * const users = createMockUsers(3); | ||
| */ | ||
| export const createMockUsers = (count: number): User[] => { | ||
| return Array.from({ length: count }, (_, i) => | ||
| createMockUser({ | ||
| id: `123e4567-e89b-12d3-a456-42661417400${i}`, | ||
| email: `test${i}@example.com`, | ||
| name: `Test User ${i}`, | ||
| }) | ||
| ); | ||
| }; | ||
|
|
||
| /** | ||
| * Create a mock Organization object | ||
| * | ||
| * @param overrides - Optional properties to override default values | ||
| * @returns An Organization object with test data | ||
| * | ||
| * @example | ||
| * const org = createMockOrganization({ name: 'My Org' }); | ||
| */ | ||
| export const createMockOrganization = ( | ||
| overrides?: Partial<Organization> | ||
| ): Organization => ({ | ||
| id: "223e4567-e89b-12d3-a456-426614174000", | ||
| name: "Test Organization", | ||
| description: "A test organization", | ||
| authorized: true, | ||
| logoUrl: "https://example.com/logo.png", | ||
| websiteUrl: "https://example.com", | ||
| instagramUsername: "testorg", | ||
| createdAt: new Date("2024-01-01T00:00:00.000Z"), | ||
| ...overrides, | ||
| }); | ||
|
|
||
| /** | ||
| * Create a mock Order object | ||
| * | ||
| * @param overrides - Optional properties to override default values | ||
| * @returns An Order object with test data | ||
| * | ||
| * @example | ||
| * const order = createMockOrder({ paymentStatus: 'CONFIRMED' }); | ||
| */ | ||
| export const createMockOrder = (overrides?: Partial<Order>): Order => ({ | ||
| id: "323e4567-e89b-12d3-a456-426614174000", | ||
| paymentMethod: "VENMO" as const, | ||
| paymentStatus: "PENDING" as const, | ||
| pickedUp: false, | ||
| buyerId: "123e4567-e89b-12d3-a456-426614174000", | ||
| fundraiserId: "423e4567-e89b-12d3-a456-426614174000", | ||
| createdAt: new Date("2024-01-01T00:00:00.000Z"), | ||
| updatedAt: new Date("2024-01-01T00:00:00.000Z"), | ||
| ...overrides, | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| /** | ||
| * Test utilities and mocks | ||
| * | ||
| * This is the main entry point for all test utilities. | ||
| * Import from this file in your tests for a clean, consistent interface. | ||
| * | ||
| * @example | ||
| * import { prismaMock, createMockUser, mockResponse } from '../../__tests__'; | ||
| */ | ||
|
|
||
| // Re-export everything from setup | ||
| export * from "./setup"; | ||
|
|
||
| // Additional test utilities can be added here as needed |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| /** | ||
| * Express.js test utilities | ||
| * | ||
| * Provides mock implementations of Express request, response, and next function | ||
| * for use in handler and middleware tests. | ||
| */ | ||
|
|
||
| /** | ||
| * Create a mock Express request object | ||
| * | ||
| * @param overrides - Optional properties to override default request values | ||
| * @returns A mock request object with common properties | ||
| * | ||
| * @example | ||
| * const req = mockRequest({ params: { id: '123' }, body: { name: 'Test' } }); | ||
| */ | ||
| export const mockRequest = <T = any>(overrides?: Partial<T>): T => | ||
| ({ | ||
| params: {}, | ||
| query: {}, | ||
| body: {}, | ||
| headers: {}, | ||
| ...overrides, | ||
| } as T); | ||
|
|
||
| /** | ||
| * Create a mock Express response object | ||
| * | ||
| * @returns A mock response object with chainable methods | ||
| * | ||
| * @example | ||
| * const res = mockResponse(); | ||
| * await handler(req, res); | ||
| * expect(res.status).toHaveBeenCalledWith(200); | ||
| */ | ||
| export const mockResponse = () => { | ||
| const res: any = { | ||
| locals: {}, | ||
| }; | ||
| res.status = jest.fn().mockReturnValue(res); | ||
| res.json = jest.fn().mockReturnValue(res); | ||
| res.send = jest.fn().mockReturnValue(res); | ||
| return res; | ||
| }; | ||
|
|
||
| /** | ||
| * Create a mock Express next function | ||
| * | ||
| * @returns A jest mock function for the next callback | ||
| * | ||
| * @example | ||
| * const next = mockNext(); | ||
| * await middleware(req, res, next); | ||
| * expect(next).toHaveBeenCalled(); | ||
| */ | ||
| export const mockNext = () => jest.fn(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { PrismaClient } from "@prisma/client"; | ||
| import { mockDeep, mockReset, DeepMockProxy } from "jest-mock-extended"; | ||
|
|
||
| /** | ||
| * Mocked Prisma Client for testing | ||
| * | ||
| * This provides a fully mocked Prisma client that can be used in tests | ||
| * without requiring an actual database connection. | ||
| */ | ||
| export const prismaMock = | ||
| mockDeep<PrismaClient>() as unknown as DeepMockProxy<PrismaClient>; | ||
|
|
||
| /** | ||
| * Mock the Prisma utility module | ||
| * | ||
| * This ensures that any imports of '../utils/prisma' will receive the mocked client | ||
| */ | ||
| jest.mock("../../utils/prisma", () => ({ | ||
| __esModule: true, | ||
| prisma: prismaMock, | ||
| })); | ||
|
|
||
| /** | ||
| * Reset Prisma mock before each test | ||
| */ | ||
| export const resetPrismaMock = () => { | ||
| mockReset(prismaMock); | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| /** | ||
| * Mocked Supabase Auth for testing | ||
| * | ||
| * This provides a mocked Supabase authentication client that can be | ||
| * configured on a per-test basis. | ||
| */ | ||
|
|
||
| export const mockSupabaseAuth = { | ||
| getUser: jest.fn().mockResolvedValue({ data: { user: null }, error: null }), | ||
| }; | ||
|
|
||
| const mockSupabaseClient = { | ||
| auth: mockSupabaseAuth, | ||
| }; | ||
|
|
||
| /** | ||
| * Mock the Supabase SDK | ||
| * | ||
| * This ensures that any calls to createClient() will return our mocked client | ||
| */ | ||
| jest.mock("@supabase/supabase-js", () => ({ | ||
| createClient: jest.fn(() => mockSupabaseClient), | ||
| })); | ||
|
|
||
| /** | ||
| * Reset Supabase mock to default state (no authenticated user) | ||
| */ | ||
| export const resetSupabaseMock = () => { | ||
| mockSupabaseAuth.getUser.mockResolvedValue({ | ||
| data: { user: null }, | ||
| error: null, | ||
| }); | ||
| }; | ||
|
|
||
| /** | ||
| * Helper to create a mock Supabase user object | ||
| */ | ||
| export const createMockSupabaseUser = ( | ||
| userId: string = "123e4567-e89b-12d3-a456-426614174000" | ||
| ) => ({ | ||
| id: userId, | ||
| email: "test@example.com", | ||
| aud: "authenticated", | ||
| role: "authenticated", | ||
| app_metadata: {}, | ||
| user_metadata: {}, | ||
| created_at: "2024-01-01T00:00:00.000Z", | ||
| updated_at: "2024-01-01T00:00:00.000Z", | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /** | ||
| * Global test setup | ||
| * | ||
| * This file is automatically loaded by Jest before each test suite. | ||
| * It configures all necessary mocks and resets them between tests. | ||
| */ | ||
|
|
||
| // Import and configure mocks | ||
| import "./mocks/prisma.mock"; | ||
| import "./mocks/supabase.mock"; | ||
|
|
||
| // Re-export mocks for use in tests | ||
| export { prismaMock, resetPrismaMock } from "./mocks/prisma.mock"; | ||
| export { | ||
| mockSupabaseAuth, | ||
| resetSupabaseMock, | ||
| createMockSupabaseUser, | ||
| } from "./mocks/supabase.mock"; | ||
| export { mockRequest, mockResponse, mockNext } from "./mocks/express.mock"; | ||
|
|
||
| // Re-export fixtures for use in tests | ||
| export { | ||
| createMockUser, | ||
| createMockUsers, | ||
| createMockOrganization, | ||
| createMockOrder, | ||
| } from "./fixtures"; | ||
|
|
||
| // Import reset functions | ||
| import { resetPrismaMock } from "./mocks/prisma.mock"; | ||
| import { resetSupabaseMock } from "./mocks/supabase.mock"; | ||
|
|
||
| /** | ||
| * Reset all mocks before each test | ||
| */ | ||
| beforeEach(() => { | ||
| resetPrismaMock(); | ||
| resetSupabaseMock(); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work on the pr! this will be really useful for us. Just had one comment to add:
In a few tests there is:
but the
supabase.auth.getUser()and default mock return both data and error:You could make the overrides always include error: null or add a small helper func like
setAuthenticatedUser()that sets the full shape for consistency. That’ll help us avoid tests breaking if auth logic ever checkserror.