mirror of
https://github.com/CompassConnections/Compass.git
synced 2025-12-23 22:18:43 -05:00
Add backend API unit tests (#21)
* setting up test structure * . * added playwright config file, deleted original playwright folder and moved "some.test" file * continued test structure setup * Updating test folder structure * Added database seeding script and backend testing folder structure * removed the database test * Replaced db seeding script * Updated userInformation.ts to use values from choices.tsx * merge prep * removing extra unit test, moving api test to correct folder * Pushing to get help with sql Unit test * Updating get-profiles unit tests * Added more unit tests * . * Added more unit tests * Added getSupabaseToken unit test * . * excluding supabase token test so ci can pass * . * Seperated the seedDatabase func into its own file so it can be accessed seperatly * Fixed failing test * . * . * Fix tests * Fix lint * Clean --------- Co-authored-by: MartinBraquet <martin.braquet@gmail.com>
This commit is contained in:
committed by
GitHub
parent
f323034eed
commit
ab612a3eca
32
.vscode/launch.json
vendored
Normal file
32
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Jest Tests",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"runtimeArgs": [
|
||||
"--inspect-brk",
|
||||
"${workspaceRoot}/node_modules/.bin/jest",
|
||||
"--runInBand"
|
||||
],
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen"
|
||||
}
|
||||
// {
|
||||
// "type": "node",
|
||||
// "request": "launch",
|
||||
// "name": "Launch Program",
|
||||
// "skipFiles": [
|
||||
// "<node_internals>/**"
|
||||
// ],
|
||||
// "program": "${workspaceFolder}/backend/api/tests/unit/get-profiles.unit.test.ts",
|
||||
// "outFiles": [
|
||||
// "${workspaceFolder}/**/*.js"
|
||||
// ]
|
||||
// }
|
||||
]
|
||||
}
|
||||
@@ -13,7 +13,7 @@ module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
project: ['./tsconfig.json', './tsconfig.test.json'],
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/ban-types': [
|
||||
|
||||
@@ -168,3 +168,6 @@ docker rmi -f $(docker images -aq)
|
||||
### Documentation
|
||||
|
||||
The API doc is available at https://api.compassmeet.com. It's dynamically prepared in [app.ts](src/app.ts).
|
||||
|
||||
### Todo (Tests)
|
||||
- [ ] Finish get-supabase-token unit test when endpoint is implemented
|
||||
@@ -10,26 +10,26 @@ export type profileQueryType = {
|
||||
after?: string | undefined,
|
||||
// Search and filter parameters
|
||||
name?: string | undefined,
|
||||
genders?: String[] | undefined,
|
||||
education_levels?: String[] | undefined,
|
||||
pref_gender?: String[] | undefined,
|
||||
genders?: string[] | undefined,
|
||||
education_levels?: string[] | undefined,
|
||||
pref_gender?: string[] | undefined,
|
||||
pref_age_min?: number | undefined,
|
||||
pref_age_max?: number | undefined,
|
||||
drinks_min?: number | undefined,
|
||||
drinks_max?: number | undefined,
|
||||
pref_relation_styles?: String[] | undefined,
|
||||
pref_romantic_styles?: String[] | undefined,
|
||||
diet?: String[] | undefined,
|
||||
political_beliefs?: String[] | undefined,
|
||||
mbti?: String[] | undefined,
|
||||
relationship_status?: String[] | undefined,
|
||||
languages?: String[] | undefined,
|
||||
religion?: String[] | undefined,
|
||||
pref_relation_styles?: string[] | undefined,
|
||||
pref_romantic_styles?: string[] | undefined,
|
||||
diet?: string[] | undefined,
|
||||
political_beliefs?: string[] | undefined,
|
||||
mbti?: string[] | undefined,
|
||||
relationship_status?: string[] | undefined,
|
||||
languages?: string[] | undefined,
|
||||
religion?: string[] | undefined,
|
||||
wants_kids_strength?: number | undefined,
|
||||
has_kids?: number | undefined,
|
||||
is_smoker?: boolean | undefined,
|
||||
shortBio?: boolean | undefined,
|
||||
geodbCityIds?: String[] | undefined,
|
||||
geodbCityIds?: string[] | undefined,
|
||||
lat?: number | undefined,
|
||||
lon?: number | undefined,
|
||||
radius?: number | undefined,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { toUserAPIResponse } from 'common/api/user-types'
|
||||
import { convertUser, displayUserColumns } from 'common/supabase/users'
|
||||
import { convertUser } from 'common/supabase/users'
|
||||
import { createSupabaseDirectClient } from 'shared/supabase/init'
|
||||
import { APIError } from 'common/api/utils'
|
||||
import { removeNullOrUndefinedProps } from 'common/util/object'
|
||||
|
||||
export const getUser = async (props: { id: string } | { username: string }) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
|
||||
@@ -52,7 +52,7 @@ export const report: APIHandler<'report'> = async (body, auth) => {
|
||||
console.error('Failed to get reported user for report', userError)
|
||||
return
|
||||
}
|
||||
let message: string = `
|
||||
const message: string = `
|
||||
🚨 **New Report** 🚨
|
||||
**Type:** ${contentType}
|
||||
**Content ID:** ${contentId}
|
||||
|
||||
115
backend/api/tests/unit/ban-user.unit.test.ts
Normal file
115
backend/api/tests/unit/ban-user.unit.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
jest.mock('shared/supabase/init')
|
||||
jest.mock('shared/helpers/auth')
|
||||
jest.mock('common/envs/constants')
|
||||
jest.mock('shared/supabase/users')
|
||||
jest.mock('shared/analytics')
|
||||
jest.mock('shared/utils')
|
||||
|
||||
import { banUser } from "api/ban-user";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import { throwErrorIfNotMod } from "shared/helpers/auth";
|
||||
import * as constants from "common/envs/constants";
|
||||
import * as supabaseUsers from "shared/supabase/users";
|
||||
import * as sharedAnalytics from "shared/analytics";
|
||||
import { } from "shared/helpers/auth";
|
||||
import { APIError, AuthedUser } from "api/helpers/endpoint"
|
||||
|
||||
|
||||
describe('banUser', () => {
|
||||
const mockPg = {} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('ban a user successfully', async () => {
|
||||
const mockUser = {
|
||||
userId: '123',
|
||||
unban: false
|
||||
};
|
||||
const mockAuth = {uid: '321'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(constants.isAdminId as jest.Mock).mockReturnValue(false);
|
||||
|
||||
await banUser(mockUser, mockAuth, mockReq);
|
||||
|
||||
expect(throwErrorIfNotMod).toBeCalledWith(mockAuth.uid);
|
||||
expect(constants.isAdminId).toBeCalledWith(mockUser.userId);
|
||||
expect(sharedAnalytics.trackPublicEvent)
|
||||
.toBeCalledWith(mockAuth.uid, 'ban user', {userId: mockUser.userId});
|
||||
expect(supabaseUsers.updateUser)
|
||||
.toBeCalledWith(mockPg, mockUser.userId, {isBannedFromPosting: true});
|
||||
});
|
||||
|
||||
it('unban a user successfully', async () => {
|
||||
const mockUser = {
|
||||
userId: '123',
|
||||
unban: true
|
||||
};
|
||||
const mockAuth = {uid: '321'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(constants.isAdminId as jest.Mock).mockReturnValue(false);
|
||||
|
||||
await banUser(mockUser, mockAuth, mockReq);
|
||||
|
||||
expect(throwErrorIfNotMod).toBeCalledWith(mockAuth.uid);
|
||||
expect(constants.isAdminId).toBeCalledWith(mockUser.userId);
|
||||
expect(sharedAnalytics.trackPublicEvent)
|
||||
.toBeCalledWith(mockAuth.uid, 'ban user', {userId: mockUser.userId});
|
||||
expect(supabaseUsers.updateUser)
|
||||
.toBeCalledWith(mockPg, mockUser.userId, {isBannedFromPosting: false});
|
||||
});
|
||||
|
||||
it('throw and error if the ban requester is not a mod or admin', async () => {
|
||||
const mockUser = {
|
||||
userId: '123',
|
||||
unban: false
|
||||
};
|
||||
const mockAuth = {uid: '321'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(throwErrorIfNotMod as jest.Mock).mockRejectedValue(
|
||||
new APIError(
|
||||
403,
|
||||
`User ${mockAuth.uid} must be an admin or trusted to perform this action.`
|
||||
)
|
||||
);
|
||||
|
||||
await expect(banUser(mockUser, mockAuth, mockReq))
|
||||
.rejects
|
||||
.toThrowError(`User ${mockAuth.uid} must be an admin or trusted to perform this action.`);
|
||||
expect(throwErrorIfNotMod).toBeCalledWith(mockAuth.uid);
|
||||
expect(sharedAnalytics.trackPublicEvent).toBeCalledTimes(0);
|
||||
expect(supabaseUsers.updateUser).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it('throw an error if the ban target is an admin', async () => {
|
||||
const mockUser = {
|
||||
userId: '123',
|
||||
unban: false
|
||||
};
|
||||
const mockAuth = {uid: '321'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(constants.isAdminId as jest.Mock).mockReturnValue(true);
|
||||
|
||||
await expect(banUser(mockUser, mockAuth, mockReq))
|
||||
.rejects
|
||||
.toThrowError('Cannot ban admin');
|
||||
expect(throwErrorIfNotMod).toBeCalledWith(mockAuth.uid);
|
||||
expect(constants.isAdminId).toBeCalledWith(mockUser.userId);
|
||||
expect(sharedAnalytics.trackPublicEvent).toBeCalledTimes(0);
|
||||
expect(supabaseUsers.updateUser).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
119
backend/api/tests/unit/block-user.unit.test.ts
Normal file
119
backend/api/tests/unit/block-user.unit.test.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
jest.mock('shared/supabase/init')
|
||||
jest.mock('shared/supabase/users')
|
||||
jest.mock('shared/supabase/utils')
|
||||
|
||||
import * as blockUserModule from "api/block-user";
|
||||
import { AuthedUser } from "api/helpers/endpoint";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import * as supabaseUsers from "shared/supabase/users";
|
||||
import * as supabaseUtils from "shared/supabase/utils";
|
||||
|
||||
describe('blockUser', () => {
|
||||
let mockPg: any;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
mockPg = {
|
||||
tx: jest.fn(async (cb) => {
|
||||
const mockTx = {};
|
||||
await cb(mockTx);
|
||||
}),
|
||||
};
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg)
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('block the user successfully', async () => {
|
||||
const mockParams = { id: '123' }
|
||||
const mockAuth = {uid: '321'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(supabaseUsers.updatePrivateUser as jest.Mock).mockResolvedValue(null);
|
||||
|
||||
await blockUserModule.blockUser(mockParams, mockAuth, mockReq)
|
||||
|
||||
expect(mockPg.tx).toHaveBeenCalledTimes(1)
|
||||
|
||||
expect(supabaseUsers.updatePrivateUser)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
mockAuth.uid,
|
||||
{ blockedByUserIds: supabaseUtils.FieldVal.arrayConcat(mockParams.id)}
|
||||
);
|
||||
expect(supabaseUsers.updatePrivateUser)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
mockParams.id,
|
||||
{ blockedByUserIds: supabaseUtils.FieldVal.arrayConcat(mockAuth.uid)}
|
||||
);
|
||||
});
|
||||
|
||||
it('throw an error if the user tries to block themselves', async () => {
|
||||
const mockParams = { id: '123' }
|
||||
const mockAuth = {uid: '123'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
expect(blockUserModule.blockUser(mockParams, mockAuth, mockReq))
|
||||
.rejects
|
||||
.toThrowError('You cannot block yourself')
|
||||
|
||||
expect(mockPg.tx).toHaveBeenCalledTimes(0)
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('unblockUser', () => {
|
||||
let mockPg: any;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
mockPg = {
|
||||
tx: jest.fn(async (cb) => {
|
||||
const mockTx = {};
|
||||
await cb(mockTx);
|
||||
}),
|
||||
};
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg)
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('block the user successfully', async () => {
|
||||
const mockParams = { id: '123' }
|
||||
const mockAuth = {uid: '321'} as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(supabaseUsers.updatePrivateUser as jest.Mock).mockResolvedValue(null);
|
||||
|
||||
await blockUserModule.unblockUser(mockParams, mockAuth, mockReq)
|
||||
|
||||
expect(mockPg.tx).toHaveBeenCalledTimes(1)
|
||||
|
||||
expect(supabaseUsers.updatePrivateUser)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
mockAuth.uid,
|
||||
{ blockedByUserIds: supabaseUtils.FieldVal.arrayConcat(mockParams.id)}
|
||||
);
|
||||
expect(supabaseUsers.updatePrivateUser)
|
||||
.toHaveBeenCalledWith(
|
||||
expect.any(Object),
|
||||
mockParams.id,
|
||||
{ blockedByUserIds: supabaseUtils.FieldVal.arrayConcat(mockAuth.uid)}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
32
backend/api/tests/unit/compatible-profiles.unit.test.ts
Normal file
32
backend/api/tests/unit/compatible-profiles.unit.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import {getCompatibleProfiles} from "api/compatible-profiles";
|
||||
|
||||
jest.mock('shared/supabase/init')
|
||||
|
||||
describe('getCompatibleProfiles', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
const mockPg = {
|
||||
none: jest.fn().mockResolvedValue(null),
|
||||
one: jest.fn().mockResolvedValue(null),
|
||||
oneOrNone: jest.fn().mockResolvedValue(null),
|
||||
any: jest.fn().mockResolvedValue([]),
|
||||
map: jest.fn().mockResolvedValue([["abc", {score: 0.69}]]),
|
||||
} as any;
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('successfully get compatible profiles when supplied with a valid user Id', async () => {
|
||||
const results = await getCompatibleProfiles("123");
|
||||
expect(results.status).toEqual('success');
|
||||
expect(results.profileCompatibilityScores).toEqual({"abc": {score: 0.69}});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
114
backend/api/tests/unit/contact.unit.test.ts
Normal file
114
backend/api/tests/unit/contact.unit.test.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
jest.mock('common/discord/core');
|
||||
jest.mock('shared/supabase/utils');
|
||||
jest.mock('shared/supabase/init');
|
||||
jest.mock('common/util/try-catch');
|
||||
|
||||
import { contact } from "api/contact";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import * as supabaseUtils from "shared/supabase/utils";
|
||||
import { tryCatch } from "common/util/try-catch";
|
||||
import { sendDiscordMessage } from "common/discord/core";
|
||||
import { AuthedUser } from "api/helpers/endpoint";
|
||||
|
||||
describe('contact', () => {
|
||||
let mockPg: any;
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
mockPg = {
|
||||
oneOrNone: jest.fn(),
|
||||
};
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('send a discord message to the user', async () => {
|
||||
const mockProps = {
|
||||
content: {
|
||||
type: 'doc',
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Error test message'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
userId: '123'
|
||||
};
|
||||
const mockAuth = { uid: '321' } as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
const mockDbUser = { name: 'Humphrey Mocker' };
|
||||
const mockReturnData = {} as any;
|
||||
|
||||
(tryCatch as jest.Mock).mockResolvedValue({ data: mockReturnData, error: null });
|
||||
(mockPg.oneOrNone as jest.Mock).mockResolvedValue(mockDbUser);
|
||||
(sendDiscordMessage as jest.Mock).mockResolvedValue(null);
|
||||
|
||||
const results = await contact(mockProps, mockAuth, mockReq);
|
||||
expect(supabaseUtils.insert).toBeCalledTimes(1)
|
||||
expect(supabaseUtils.insert).toBeCalledWith(
|
||||
mockPg,
|
||||
'contact',
|
||||
{
|
||||
user_id: mockProps.userId,
|
||||
content: JSON.stringify(mockProps.content)
|
||||
}
|
||||
);
|
||||
expect(results.success).toBe(true);
|
||||
await results.continue();
|
||||
expect(sendDiscordMessage).toBeCalledWith(
|
||||
expect.stringContaining(`New message from ${mockDbUser.name}`),
|
||||
'contact'
|
||||
)
|
||||
expect(sendDiscordMessage).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('throw an error if the inser function fails', async () => {
|
||||
const mockProps = {
|
||||
content: {
|
||||
type: 'doc',
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Error test message'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
userId: '123'
|
||||
};
|
||||
const mockAuth = { uid: '321' } as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
(tryCatch as jest.Mock).mockResolvedValue({ data: null, error: Error });
|
||||
|
||||
expect(contact(mockProps, mockAuth, mockReq))
|
||||
.rejects
|
||||
.toThrowError('Failed to submit contact message');
|
||||
expect(supabaseUtils.insert).toBeCalledTimes(1)
|
||||
expect(supabaseUtils.insert).toBeCalledWith(
|
||||
mockPg,
|
||||
'contact',
|
||||
{
|
||||
user_id: mockProps.userId,
|
||||
content: JSON.stringify(mockProps.content)
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
47
backend/api/tests/unit/create-bookmarked-search.unit.test.ts
Normal file
47
backend/api/tests/unit/create-bookmarked-search.unit.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
jest.mock('shared/supabase/init');
|
||||
|
||||
import { createBookmarkedSearch } from "api/create-bookmarked-search";
|
||||
import { AuthedUser } from "api/helpers/endpoint";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
|
||||
describe('createBookmarkedSearch', () => {
|
||||
let mockPg: any;
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
mockPg = {
|
||||
one: jest.fn(),
|
||||
};
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('insert a bookmarked search into the database', async () => {
|
||||
const mockProps = {
|
||||
search_filters: 'mock_search_filters',
|
||||
location: 'mock_location',
|
||||
search_name: 'mock_search_name'
|
||||
};
|
||||
const mockAuth = { uid: '321' } as AuthedUser;
|
||||
const mockReq = {} as any;
|
||||
|
||||
await createBookmarkedSearch(mockProps, mockAuth, mockReq)
|
||||
expect(mockPg.one).toBeCalledTimes(1)
|
||||
expect(mockPg.one).toHaveBeenCalledWith(
|
||||
expect.stringContaining('INSERT INTO bookmarked_searches'),
|
||||
[
|
||||
mockAuth.uid,
|
||||
mockProps.search_filters,
|
||||
mockProps.location,
|
||||
mockProps.search_name
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
56
backend/api/tests/unit/create-comment.unit.test.ts
Normal file
56
backend/api/tests/unit/create-comment.unit.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
jest.mock('shared/supabase/init');
|
||||
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import { AuthedUser } from "api/helpers/endpoint";
|
||||
|
||||
describe('createComment', () => {
|
||||
let mockPg: any;
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
|
||||
mockPg = {
|
||||
one: jest.fn()
|
||||
};
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('successfully create a comment with information provided', async () => {
|
||||
const mockUserId = {userId: '123'}
|
||||
const mockOnUser = {id: '123'}
|
||||
const mockCreator = {
|
||||
id: '123',
|
||||
name: 'Mock Creator',
|
||||
username: 'mock.creator.username',
|
||||
avatarUrl: 'mock.creator.avatarurl'
|
||||
}
|
||||
const mockContent = {
|
||||
content: {
|
||||
type: 'doc',
|
||||
content: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'This is the comment text'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
userId: '123'
|
||||
};
|
||||
const mockAuth = { uid: '321' } as AuthedUser;
|
||||
const mockReplyToCommentId = {} as any;
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
333
backend/api/tests/unit/get-profiles.unit.test.ts
Normal file
333
backend/api/tests/unit/get-profiles.unit.test.ts
Normal file
@@ -0,0 +1,333 @@
|
||||
import * as profilesModule from "api/get-profiles";
|
||||
import { Profile } from "common/profiles/profile";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
|
||||
describe('getProfiles', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should fetch the user profiles', () => {
|
||||
it('successfully', async ()=> {
|
||||
const mockProfiles = [
|
||||
{
|
||||
diet: ['Jonathon Hammon'],
|
||||
has_kids: 0
|
||||
},
|
||||
{
|
||||
diet: ['Joseph Hammon'],
|
||||
has_kids: 1
|
||||
},
|
||||
{
|
||||
diet: ['Jolene Hammon'],
|
||||
has_kids: 2,
|
||||
}
|
||||
] as Profile [];
|
||||
|
||||
jest.spyOn(profilesModule, 'loadProfiles').mockResolvedValue({profiles: mockProfiles, count: 3});
|
||||
|
||||
const props = {
|
||||
limit: 2,
|
||||
orderBy: "last_online_time" as const,
|
||||
};
|
||||
const mockReq = {} as any;
|
||||
const results = await profilesModule.getProfiles(props, mockReq, mockReq);
|
||||
|
||||
if('continue' in results) {
|
||||
throw new Error('Expected direct response')
|
||||
};
|
||||
|
||||
expect(results.status).toEqual('success');
|
||||
expect(results.profiles).toEqual(mockProfiles);
|
||||
expect(results.profiles[0]).toEqual(mockProfiles[0]);
|
||||
expect(profilesModule.loadProfiles).toHaveBeenCalledWith(props);
|
||||
expect(profilesModule.loadProfiles).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('unsuccessfully', async () => {
|
||||
jest.spyOn(profilesModule, 'loadProfiles').mockRejectedValue(null);
|
||||
|
||||
const props = {
|
||||
limit: 2,
|
||||
orderBy: "last_online_time" as const,
|
||||
};
|
||||
const mockReq = {} as any;
|
||||
const results = await profilesModule.getProfiles(props, mockReq, mockReq);
|
||||
|
||||
if('continue' in results) {
|
||||
throw new Error('Expected direct response')
|
||||
};
|
||||
|
||||
expect(results.status).toEqual('fail');
|
||||
expect(results.profiles).toEqual([]);
|
||||
expect(profilesModule.loadProfiles).toHaveBeenCalledWith(props);
|
||||
expect(profilesModule.loadProfiles).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadProfiles', () => {
|
||||
let mockPg: any;
|
||||
|
||||
describe('should call pg.map with an SQL query', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockPg = {
|
||||
map: jest.fn().mockResolvedValue([]),
|
||||
one: jest.fn().mockResolvedValue(1),
|
||||
};
|
||||
|
||||
jest.spyOn(supabaseInit, 'createSupabaseDirectClient')
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('successfully', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
limit: 10,
|
||||
name: 'John',
|
||||
is_smoker: true,
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain('select');
|
||||
expect(query).toContain('from profiles');
|
||||
expect(query).toContain('where');
|
||||
expect(query).toContain('limit 10');
|
||||
expect(query).toContain(`John`);
|
||||
expect(query).toContain(`is_smoker`);
|
||||
expect(query).not.toContain(`gender`);
|
||||
expect(query).not.toContain(`education_level`);
|
||||
expect(query).not.toContain(`pref_gender`);
|
||||
expect(query).not.toContain(`age`);
|
||||
expect(query).not.toContain(`drinks_per_month`);
|
||||
expect(query).not.toContain(`pref_relation_styles`);
|
||||
expect(query).not.toContain(`pref_romantic_styles`);
|
||||
expect(query).not.toContain(`diet`);
|
||||
expect(query).not.toContain(`political_beliefs`);
|
||||
expect(query).not.toContain(`religion`);
|
||||
expect(query).not.toContain(`has_kids`);
|
||||
});
|
||||
|
||||
it('that contains a gender filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
genders: ['Electrical_gender'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`gender`);
|
||||
expect(query).toContain(`Electrical_gender`);
|
||||
});
|
||||
|
||||
it('that contains a education level filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
education_levels: ['High School'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`education_level`);
|
||||
expect(query).toContain(`High School`);
|
||||
});
|
||||
|
||||
it('that contains a prefer gender filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
pref_gender: ['female'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
console.log(query);
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`pref_gender`);
|
||||
expect(query).toContain(`female`);
|
||||
});
|
||||
|
||||
it('that contains a minimum age filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
pref_age_min: 20,
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`age`);
|
||||
expect(query).toContain(`>= 20`);
|
||||
});
|
||||
|
||||
it('that contains a maximum age filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
pref_age_max: 40,
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`age`);
|
||||
expect(query).toContain(`<= 40`);
|
||||
});
|
||||
|
||||
it('that contains a minimum drinks per month filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
drinks_min: 4,
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`drinks_per_month`);
|
||||
expect(query).toContain('4');
|
||||
});
|
||||
|
||||
it('that contains a maximum drinks per month filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
drinks_max: 20,
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`drinks_per_month`);
|
||||
expect(query).toContain('20');
|
||||
});
|
||||
|
||||
it('that contains a relationship style filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
pref_relation_styles: ['Chill and relaxing'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`pref_relation_styles`);
|
||||
expect(query).toContain('Chill and relaxing');
|
||||
});
|
||||
|
||||
it('that contains a romantic style filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
pref_romantic_styles: ['Sexy'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`pref_romantic_styles`);
|
||||
expect(query).toContain('Sexy');
|
||||
});
|
||||
|
||||
it('that contains a diet filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
diet: ['Glutton'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`diet`);
|
||||
expect(query).toContain('Glutton');
|
||||
});
|
||||
|
||||
it('that contains a political beliefs filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
political_beliefs: ['For the people'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`political_beliefs`);
|
||||
expect(query).toContain('For the people');
|
||||
});
|
||||
|
||||
it('that contains a religion filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
religion: ['The blood god'],
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`religion`);
|
||||
expect(query).toContain('The blood god');
|
||||
});
|
||||
|
||||
it('that contains a has kids filter', async () => {
|
||||
await profilesModule.loadProfiles({
|
||||
has_kids: 3,
|
||||
});
|
||||
|
||||
const [query, values, cb] = mockPg.map.mock.calls[0]
|
||||
|
||||
expect(mockPg.map.mock.calls).toHaveLength(1)
|
||||
expect(query).toContain(`has_kids`);
|
||||
expect(query).toContain('> 0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
mockPg = {
|
||||
map: jest.fn(),
|
||||
one: jest.fn().mockResolvedValue(1),
|
||||
};
|
||||
|
||||
jest.spyOn(supabaseInit, 'createSupabaseDirectClient')
|
||||
.mockReturnValue(mockPg)
|
||||
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('return profiles from the database', async () => {
|
||||
const mockProfiles = [
|
||||
{
|
||||
diet: ['Jonathon Hammon'],
|
||||
is_smoker: true,
|
||||
has_kids: 0
|
||||
},
|
||||
{
|
||||
diet: ['Joseph Hammon'],
|
||||
is_smoker: false,
|
||||
has_kids: 1
|
||||
},
|
||||
{
|
||||
diet: ['Jolene Hammon'],
|
||||
is_smoker: true,
|
||||
has_kids: 2,
|
||||
}
|
||||
] as Profile [];
|
||||
|
||||
mockPg.map.mockResolvedValue(mockProfiles);
|
||||
const props = {} as any;
|
||||
const results = await profilesModule.loadProfiles(props);
|
||||
|
||||
expect(results).toEqual({profiles: mockProfiles, count: 1});
|
||||
});
|
||||
|
||||
it('throw an error if there is no compatability', async () => {
|
||||
const props = {
|
||||
orderBy: 'compatibility_score'
|
||||
}
|
||||
expect(profilesModule.loadProfiles(props))
|
||||
.rejects
|
||||
.toThrowError('Incompatible with user ID')
|
||||
});
|
||||
})
|
||||
})
|
||||
49
backend/api/tests/unit/get-supabase-token.unit.test.ts
Normal file
49
backend/api/tests/unit/get-supabase-token.unit.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
jest.mock('jsonwebtoken');
|
||||
|
||||
|
||||
describe.skip('getSupabaseToken', () => {
|
||||
// const originalSupabaseJwtSecret = process.env.SUPABASE_JWT_SECRET
|
||||
// const originalInstanceId = constants.ENV_CONFIG.supabaseInstanceId
|
||||
// const originalProjectId = constants.ENV_CONFIG.firebaseConfig.projectId
|
||||
|
||||
// describe('should', () => {
|
||||
// beforeEach(() => {
|
||||
// jest.resetAllMocks();
|
||||
|
||||
// process.env.SUPABASE_JWT_SECRET = 'test-jwt-secret-123';
|
||||
// constants.ENV_CONFIG.supabaseInstanceId = 'test-instance-id';
|
||||
// constants.ENV_CONFIG.firebaseConfig.projectId = 'test-project-id';
|
||||
|
||||
// (jsonWebtokenModules.sign as jest.Mock).mockReturnValue('fake-jwt-token-abc123');
|
||||
// });
|
||||
|
||||
// afterEach(() => {
|
||||
// if (originalSupabaseJwtSecret === undefined) {
|
||||
// delete process.env.SUPABASE_JWT_SECRET;
|
||||
// } else {
|
||||
// process.env.SUPABASE_JWT_SECRET = originalSupabaseJwtSecret;
|
||||
// }
|
||||
// constants.ENV_CONFIG.supabaseInstanceId = originalInstanceId;
|
||||
// constants.ENV_CONFIG.firebaseConfig.projectId = originalProjectId;
|
||||
|
||||
// jest.restoreAllMocks();
|
||||
// });
|
||||
|
||||
// it('successfully generate a JTW token with correct parameters', async () => {
|
||||
// const mockParams = {} as any;
|
||||
// const mockAuth = {uid: '321'} as AuthedUser;
|
||||
// const result = await getSupabaseToken(mockParams, mockAuth, mockParams)
|
||||
|
||||
// expect(result).toEqual({
|
||||
// jwt: 'fake-jwt-token-abc123'
|
||||
// })
|
||||
// })
|
||||
// });
|
||||
});
|
||||
|
||||
describe('getCompatibleProfiles', () => {
|
||||
it('skip', async () => {
|
||||
console.log('This needs tests');
|
||||
|
||||
})
|
||||
})
|
||||
@@ -1,12 +1,15 @@
|
||||
jest.mock("shared/supabase/init");
|
||||
|
||||
import { getUser } from "api/get-user";
|
||||
import { createSupabaseDirectClient } from "shared/supabase/init";
|
||||
import { toUserAPIResponse } from "common/api/user-types";
|
||||
import { convertUser } from "common/supabase/users";
|
||||
import { APIError } from "common/src/api/utils";
|
||||
import { APIError } from "common/api/utils";
|
||||
|
||||
|
||||
jest.spyOn(require("common/supabase/users"), 'convertUser')
|
||||
jest.spyOn(require("common/api/user-types"), 'toUserAPIResponse')
|
||||
|
||||
jest.mock("shared/supabase/init");
|
||||
jest.mock("common/supabase/users");
|
||||
jest.mock("common/api/utils");
|
||||
describe('getUser', () =>{
|
||||
let mockPg: any;
|
||||
|
||||
@@ -19,41 +22,142 @@ describe('getUser', () =>{
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should fetch user successfully by id', async () => {
|
||||
const mockDbUser = {
|
||||
created_time: '2025-11-11T16:42:05.188Z',
|
||||
data: { link: {}, avatarUrl: "", isBannedFromPosting: false },
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
name_username_vector: "'buckridg':2,4 'franklin':1,3",
|
||||
username: 'Franky_Buck'
|
||||
};
|
||||
const mockConvertedUser = {
|
||||
created_time: new Date(),
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
name_username_vector: "'buckridg':2,4 'franklin':1,3",
|
||||
username: 'Franky_Buck'
|
||||
describe('when fetching by id', () => {
|
||||
it('should fetch user successfully by id', async () => {
|
||||
const mockDbUser = {
|
||||
created_time: '2025-11-11T16:42:05.188Z',
|
||||
data: { link: {}, avatarUrl: "", isBannedFromPosting: false },
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
name_username_vector: "'buckridg':2,4 'franklin':1,3",
|
||||
username: 'Franky_Buck'
|
||||
};
|
||||
const mockConvertedUser = {
|
||||
created_time: new Date(),
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
name_username_vector: "'buckridg':2,4 'franklin':1,3",
|
||||
username: 'Franky_Buck'
|
||||
|
||||
};
|
||||
const mockApiResponse = {
|
||||
created_time: '2025-11-11T16:42:05.188Z',
|
||||
data: { link: {}, avatarUrl: "", isBannedFromPosting: false },
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
username: 'Franky_Buck'
|
||||
};
|
||||
|
||||
mockPg.oneOrNone.mockImplementation((query: string, values: any[], cb: (value: any) => any) => {
|
||||
const result = cb(mockDbUser);
|
||||
return Promise.resolve(result);
|
||||
});
|
||||
|
||||
(convertUser as jest.Mock).mockReturnValue(mockConvertedUser);
|
||||
( toUserAPIResponse as jest.Mock).mockReturnValue(mockApiResponse);
|
||||
|
||||
const result = await getUser({id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP'})
|
||||
|
||||
expect(mockPg.oneOrNone).toHaveBeenCalledWith(
|
||||
expect.stringContaining('where id = $1'),
|
||||
['feUaIfcxVmJZHJOVVfawLTTPgZiP'],
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
expect(convertUser).toHaveBeenCalledWith(mockDbUser);
|
||||
expect(toUserAPIResponse).toHaveBeenCalledWith(mockConvertedUser);
|
||||
|
||||
expect(result).toEqual(mockApiResponse);
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
const mockApiResponse = {
|
||||
created_time: '2025-11-11T16:42:05.188Z',
|
||||
data: { link: {}, avatarUrl: "", isBannedFromPosting: false },
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
username: 'Franky_Buck'
|
||||
};
|
||||
it('should throw 404 when user is not found by id', async () => {
|
||||
mockPg.oneOrNone.mockImplementation((query: string, values: any[], cb: (value: any) => any) => {
|
||||
return Promise.resolve(null);
|
||||
});
|
||||
|
||||
// mockPg.oneOrNone.mockImplementation((query: any, params: any, callback: any) => {
|
||||
// return Promise.resolve(callback(mockDbUser))
|
||||
// })
|
||||
|
||||
// (convertUser as jest.Mock).mockReturnValue(mockConvertedUser);
|
||||
// ( toUserAPIResponse as jest.Mock).mockReturnValue(mockApiResponse);
|
||||
|
||||
// const result = await getUser({id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP'})
|
||||
|
||||
// console.log(result);
|
||||
(convertUser as jest.Mock).mockReturnValue(null)
|
||||
|
||||
try {
|
||||
await getUser({id: '3333'});
|
||||
fail('Should have thrown');
|
||||
} catch (error) {
|
||||
const apiError = error as APIError;
|
||||
expect(apiError.code).toBe(404)
|
||||
expect(apiError.message).toBe('User not found')
|
||||
expect(apiError.details).toBeUndefined()
|
||||
expect(apiError.name).toBe('APIError')
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('when fetching by username', () => {
|
||||
it('should fetch user successfully by username', async () => {
|
||||
const mockDbUser = {
|
||||
created_time: '2025-11-11T16:42:05.188Z',
|
||||
data: { link: {}, avatarUrl: "", isBannedFromPosting: false },
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
name_username_vector: "'buckridg':2,4 'franklin':1,3",
|
||||
username: 'Franky_Buck'
|
||||
};
|
||||
const mockConvertedUser = {
|
||||
created_time: new Date(),
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
name_username_vector: "'buckridg':2,4 'franklin':1,3",
|
||||
username: 'Franky_Buck'
|
||||
|
||||
};
|
||||
const mockApiResponse = {
|
||||
created_time: '2025-11-11T16:42:05.188Z',
|
||||
data: { link: {}, avatarUrl: "", isBannedFromPosting: false },
|
||||
id: 'feUaIfcxVmJZHJOVVfawLTTPgZiP',
|
||||
name: 'Franklin Buckridge',
|
||||
username: 'Franky_Buck'
|
||||
};
|
||||
|
||||
mockPg.oneOrNone.mockImplementation((query: string, values: any[], cb: (value: any) => any) => {
|
||||
const result = cb(mockDbUser);
|
||||
return Promise.resolve(result);
|
||||
});
|
||||
|
||||
(convertUser as jest.Mock).mockReturnValue(mockConvertedUser);
|
||||
(toUserAPIResponse as jest.Mock).mockReturnValue(mockApiResponse);
|
||||
|
||||
const result = await getUser({username: 'Franky_Buck'})
|
||||
|
||||
expect(mockPg.oneOrNone).toHaveBeenCalledWith(
|
||||
expect.stringContaining('where username = $1'),
|
||||
['Franky_Buck'],
|
||||
expect.any(Function)
|
||||
);
|
||||
|
||||
expect(convertUser).toHaveBeenCalledWith(mockDbUser);
|
||||
expect(toUserAPIResponse).toHaveBeenCalledWith(mockConvertedUser);
|
||||
|
||||
expect(result).toEqual(mockApiResponse);
|
||||
|
||||
});
|
||||
|
||||
it('should throw 404 when user is not found by id', async () => {
|
||||
mockPg.oneOrNone.mockImplementation((query: string, values: any[], cb: (value: any) => any) => {
|
||||
return Promise.resolve(null);
|
||||
});
|
||||
|
||||
(convertUser as jest.Mock).mockReturnValue(null)
|
||||
|
||||
try {
|
||||
await getUser({username: '3333'});
|
||||
fail('Should have thrown');
|
||||
} catch (error) {
|
||||
const apiError = error as APIError;
|
||||
expect(apiError.code).toBe(404)
|
||||
expect(apiError.message).toBe('User not found')
|
||||
expect(apiError.details).toBeUndefined()
|
||||
expect(apiError.name).toBe('APIError')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
34
backend/api/tests/unit/set-last-online-time.unit.test.ts
Normal file
34
backend/api/tests/unit/set-last-online-time.unit.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
jest.mock('shared/supabase/init');
|
||||
|
||||
import * as setLastTimeOnlineModule from "api/set-last-online-time";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
|
||||
describe('Should', () => {
|
||||
let mockPg: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockPg = {
|
||||
none: jest.fn(),
|
||||
};
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('change the users last online time', async () => {
|
||||
const mockProfile = {user_id: 'Jonathon'};
|
||||
|
||||
await setLastTimeOnlineModule.setLastOnlineTimeUser(mockProfile.user_id);
|
||||
|
||||
expect(mockPg.none).toBeCalledTimes(1);
|
||||
|
||||
const [query, userId] = mockPg.none.mock.calls[0];
|
||||
|
||||
expect(userId).toContain(mockProfile.user_id);
|
||||
expect(query).toContain("VALUES ($1, now())")
|
||||
expect(query).toContain("ON CONFLICT (user_id)")
|
||||
expect(query).toContain("DO UPDATE")
|
||||
expect(query).toContain("user_activity.last_online_time < now() - interval '1 minute'")
|
||||
});
|
||||
})
|
||||
86
backend/api/tests/unit/update-profile.unit.test.ts
Normal file
86
backend/api/tests/unit/update-profile.unit.test.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
jest.mock("shared/supabase/init");
|
||||
jest.mock("shared/supabase/utils");
|
||||
|
||||
import { AuthedUser } from "api/helpers/endpoint";
|
||||
import { updateProfile } from "api/update-profile";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import * as supabaseUtils from "shared/supabase/utils";
|
||||
|
||||
describe('updateProfiles', () => {
|
||||
let mockPg: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockPg = {
|
||||
oneOrNone: jest.fn(),
|
||||
};
|
||||
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
describe('should', () => {
|
||||
it('update an existing profile when provided the user id', async () => {
|
||||
const mockUserProfile = {
|
||||
user_id: '234',
|
||||
diet: 'Nothing',
|
||||
gender: 'female',
|
||||
is_smoker: true,
|
||||
}
|
||||
const mockUpdateMade = {
|
||||
gender: 'male'
|
||||
}
|
||||
const mockUpdatedProfile = {
|
||||
user_id: '234',
|
||||
diet: 'Nothing',
|
||||
gender: 'male',
|
||||
is_smoker: true,
|
||||
}
|
||||
const mockParams = {} as any;
|
||||
const mockAuth = {
|
||||
uid: '234'
|
||||
}
|
||||
|
||||
mockPg.oneOrNone.mockResolvedValue(mockUserProfile);
|
||||
(supabaseUtils.update as jest.Mock).mockResolvedValue(mockUpdatedProfile);
|
||||
|
||||
const result = await updateProfile(
|
||||
mockUpdateMade,
|
||||
mockAuth as AuthedUser,
|
||||
mockParams
|
||||
);
|
||||
|
||||
expect(mockPg.oneOrNone.mock.calls.length).toBe(1);
|
||||
expect(mockPg.oneOrNone.mock.calls[0][1]).toEqual([mockAuth.uid]);
|
||||
expect(result).toEqual(mockUpdatedProfile);
|
||||
});
|
||||
|
||||
it('throw an error if a profile is not found', async () => {
|
||||
mockPg.oneOrNone.mockResolvedValue(null);
|
||||
expect(updateProfile({} as any, {} as any, {} as any,))
|
||||
.rejects
|
||||
.toThrowError('Profile not found');
|
||||
});
|
||||
|
||||
it('throw an error if unable to update the profile', async () => {
|
||||
const mockUserProfile = {
|
||||
user_id: '234',
|
||||
diet: 'Nothing',
|
||||
gender: 'female',
|
||||
is_smoker: true,
|
||||
}
|
||||
const data = null;
|
||||
const error = true;
|
||||
const mockError = {
|
||||
data,
|
||||
error
|
||||
}
|
||||
mockPg.oneOrNone.mockResolvedValue(mockUserProfile);
|
||||
(supabaseUtils.update as jest.Mock).mockRejectedValue(mockError);
|
||||
expect(updateProfile({} as any, {} as any, {} as any,))
|
||||
.rejects
|
||||
.toThrowError('Error updating profile');
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.json'],
|
||||
project: ['./tsconfig.json', './tsconfig.test.json'],
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/ban-types': [
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import {SupabaseDirectClient} from 'shared/supabase/init'
|
||||
import {Row as RowFor} from 'common/supabase/utils'
|
||||
import {createSupabaseDirectClient, SupabaseDirectClient} from 'shared/supabase/init'
|
||||
import {getCompatibilityScore, hasAnsweredQuestions} from 'common/profiles/compatibility-score'
|
||||
import {getCompatibilityAnswers, getGenderCompatibleProfiles, getProfile} from "shared/profiles/supabase"
|
||||
import {
|
||||
getAnswersForUser,
|
||||
getCompatibilityAnswers,
|
||||
getGenderCompatibleProfiles,
|
||||
getProfile
|
||||
} from "shared/profiles/supabase"
|
||||
import {groupBy} from "lodash"
|
||||
import {hrtime} from "node:process"
|
||||
|
||||
type AnswerRow = RowFor<'compatibility_answers'>
|
||||
|
||||
// Canonicalize pair ordering (user_id_1 < user_id_2 lexicographically)
|
||||
function canonicalPair(a: string, b: string) {
|
||||
return a < b ? [a, b] as const : [b, a] as const
|
||||
@@ -14,15 +16,16 @@ function canonicalPair(a: string, b: string) {
|
||||
|
||||
export async function recomputeCompatibilityScoresForUser(
|
||||
userId: string,
|
||||
pg: SupabaseDirectClient,
|
||||
client?: SupabaseDirectClient,
|
||||
) {
|
||||
const pg = client ?? createSupabaseDirectClient()
|
||||
const startTs = hrtime.bigint()
|
||||
|
||||
const profile = await getProfile(userId)
|
||||
if (!profile) throw new Error(`Profile not found for user ${userId}`)
|
||||
|
||||
// Load all answers for the target user
|
||||
const answersSelf = await pg.manyOrNone<AnswerRow>(
|
||||
'select * from compatibility_answers where creator_id = $1',
|
||||
[userId]
|
||||
)
|
||||
const answersSelf = await getAnswersForUser(userId);
|
||||
|
||||
// If the user has no answered questions, set the score to null
|
||||
if (!hasAnsweredQuestions(answersSelf)) {
|
||||
@@ -35,10 +38,7 @@ export async function recomputeCompatibilityScoresForUser(
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const profile = await getProfile(userId, pg)
|
||||
if (!profile) throw new Error(`Profile not found for user ${userId}`)
|
||||
let profiles = await getGenderCompatibleProfiles(profile)
|
||||
const profiles = await getGenderCompatibleProfiles(profile)
|
||||
const otherUserIds = profiles.map((l) => l.user_id)
|
||||
const profileAnswers = await getCompatibilityAnswers([userId, ...otherUserIds])
|
||||
const answersByUser = groupBy(profileAnswers, 'creator_id')
|
||||
@@ -96,4 +96,6 @@ export async function recomputeCompatibilityScoresForUser(
|
||||
|
||||
const dt = Number(hrtime.bigint() - startTs) / 1e9
|
||||
console.log(`Done recomputing compatibility scores for user ${userId} (${dt.toFixed(1)}s).`)
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export const createProfileLikeNotification = async (like: Row<'profile_likes'>)
|
||||
const pg = createSupabaseDirectClient()
|
||||
|
||||
const targetPrivateUser = await getPrivateUser(target_id)
|
||||
const profile = await getProfile(creator_id, pg)
|
||||
const profile = await getProfile(creator_id)
|
||||
|
||||
if (!targetPrivateUser || !profile) return
|
||||
|
||||
@@ -49,7 +49,7 @@ export const createProfileShipNotification = async (
|
||||
const creator = await getUser(creator_id)
|
||||
const targetPrivateUser = await getPrivateUser(recipientId)
|
||||
const pg = createSupabaseDirectClient()
|
||||
const profile = await getProfile(otherTargetId, pg)
|
||||
const profile = await getProfile(otherTargetId)
|
||||
|
||||
if (!creator || !targetPrivateUser || !profile) {
|
||||
console.error('Could not load user object', {
|
||||
|
||||
@@ -2,7 +2,7 @@ import {areGenderCompatible} from 'common/profiles/compatibility-util'
|
||||
import {type Profile, type ProfileRow} from 'common/profiles/profile'
|
||||
import {type User} from 'common/user'
|
||||
import {Row} from 'common/supabase/utils'
|
||||
import {createSupabaseDirectClient, SupabaseDirectClient} from 'shared/supabase/init'
|
||||
import {createSupabaseDirectClient} from 'shared/supabase/init'
|
||||
|
||||
export type ProfileAndUserRow = ProfileRow & {
|
||||
name: string
|
||||
@@ -26,8 +26,8 @@ export function convertRow(row: ProfileAndUserRow | undefined): Profile | null {
|
||||
|
||||
const PROFILE_COLS = 'profiles.*, name, username, users.data as user'
|
||||
|
||||
export const getProfile = async (userId: string, client?: SupabaseDirectClient) => {
|
||||
const pg = client ?? createSupabaseDirectClient()
|
||||
export const getProfile = async (userId: string) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
return await pg.oneOrNone(
|
||||
`
|
||||
select ${PROFILE_COLS}
|
||||
@@ -122,3 +122,14 @@ export const getCompatibilityAnswers = async (userIds: string[]) => {
|
||||
[userIds]
|
||||
)
|
||||
}
|
||||
|
||||
type AnswerRow = Row<'compatibility_answers'>
|
||||
|
||||
export async function getAnswersForUser(userId: string) {
|
||||
const pg = createSupabaseDirectClient()
|
||||
const answersSelf = await pg.manyOrNone<AnswerRow>(
|
||||
'select * from compatibility_answers where creator_id = $1',
|
||||
[userId]
|
||||
)
|
||||
return answersSelf
|
||||
}
|
||||
|
||||
140
backend/shared/tests/unit/compute-score.unit.test.ts
Normal file
140
backend/shared/tests/unit/compute-score.unit.test.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import {recomputeCompatibilityScoresForUser} from "api/compatibility/compute-scores";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import * as profilesSupabaseModules from "shared/profiles/supabase";
|
||||
import * as compatibilityScoreModules from "common/profiles/compatibility-score";
|
||||
import {Profile} from "common/profiles/profile";
|
||||
|
||||
jest.mock('shared/profiles/supabase')
|
||||
jest.mock('shared/supabase/init')
|
||||
jest.mock('common/profiles/compatibility-score')
|
||||
|
||||
|
||||
describe('recomputeCompatibilityScoresForUser', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
const mockPg = {
|
||||
none: jest.fn().mockResolvedValue(null),
|
||||
one: jest.fn().mockResolvedValue(null),
|
||||
oneOrNone: jest.fn().mockResolvedValue(null),
|
||||
any: jest.fn().mockResolvedValue([]),
|
||||
} as any;
|
||||
(supabaseInit.createSupabaseDirectClient as jest.Mock)
|
||||
.mockReturnValue(mockPg);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('should', () => {
|
||||
it('successfully get compute score when supplied with a valid user Id', async () => {
|
||||
const mockUser = {userId: "123"};
|
||||
const mockUserProfile = {
|
||||
id: 1,
|
||||
user_id: '123',
|
||||
user: {
|
||||
username: "Mockuser.getProfile"
|
||||
},
|
||||
created_time: "10:30",
|
||||
explanation: "mockExplanation3",
|
||||
importance: 3,
|
||||
};
|
||||
const mockGenderCompatibleProfiles = [
|
||||
{
|
||||
age: 20,
|
||||
user_id: "1",
|
||||
company: 'Mock Texan Roadhouse',
|
||||
drinks_per_month: 3,
|
||||
city: 'Mockingdale'
|
||||
},
|
||||
{
|
||||
age: 23,
|
||||
user_id: "2",
|
||||
company: 'Chicken fried goose',
|
||||
drinks_per_month: 2,
|
||||
city: 'Mockingdale'
|
||||
},
|
||||
{
|
||||
age: 40,
|
||||
user_id: "3",
|
||||
company: 'World Peace',
|
||||
drinks_per_month: 10,
|
||||
city: 'Velvet Suite'
|
||||
},
|
||||
] as Partial<Profile> [];
|
||||
const mockProfileCompatibilityAnswers = [
|
||||
{
|
||||
created_time: "10:30",
|
||||
creator_id: "3",
|
||||
explanation: "mockExplanation3",
|
||||
id: 3,
|
||||
importance: 3
|
||||
},
|
||||
{
|
||||
created_time: "10:20",
|
||||
creator_id: "2",
|
||||
explanation: "mockExplanation2",
|
||||
id: 2,
|
||||
importance: 2
|
||||
},
|
||||
{
|
||||
created_time: "10:10",
|
||||
creator_id: "1",
|
||||
explanation: "mockExplanation",
|
||||
id: 1,
|
||||
importance: 1
|
||||
},
|
||||
];
|
||||
const mockCompatibilityScore = {
|
||||
score: 4,
|
||||
confidence: "low"
|
||||
};
|
||||
const mockAnswersForUser = [{
|
||||
created_time: "",
|
||||
creator_id: mockUser.userId,
|
||||
explanation: "",
|
||||
id: 1,
|
||||
importance: 1,
|
||||
multiple_choice: 0,
|
||||
pref_choices: [0, 1],
|
||||
question_id: 1,
|
||||
}];
|
||||
|
||||
(profilesSupabaseModules.getProfile as jest.Mock)
|
||||
.mockResolvedValue(mockUserProfile);
|
||||
(profilesSupabaseModules.getGenderCompatibleProfiles as jest.Mock)
|
||||
.mockResolvedValue(mockGenderCompatibleProfiles);
|
||||
(profilesSupabaseModules.getCompatibilityAnswers as jest.Mock)
|
||||
.mockResolvedValue(mockProfileCompatibilityAnswers);
|
||||
(profilesSupabaseModules.getAnswersForUser as jest.Mock)
|
||||
.mockResolvedValue(mockAnswersForUser);
|
||||
(compatibilityScoreModules.getCompatibilityScore as jest.Mock)
|
||||
.mockReturnValue(mockCompatibilityScore);
|
||||
(compatibilityScoreModules.hasAnsweredQuestions as jest.Mock)
|
||||
.mockReturnValue(true);
|
||||
|
||||
const results = await recomputeCompatibilityScoresForUser(mockUser.userId);
|
||||
expect(profilesSupabaseModules.getProfile).toBeCalledWith(mockUser.userId);
|
||||
expect(profilesSupabaseModules.getProfile).toBeCalledTimes(1);
|
||||
expect(profilesSupabaseModules.getGenderCompatibleProfiles).toBeCalledWith(mockUserProfile);
|
||||
expect(profilesSupabaseModules.getGenderCompatibleProfiles).toBeCalledTimes(1);
|
||||
expect(compatibilityScoreModules.getCompatibilityScore).toBeCalledTimes(mockGenderCompatibleProfiles.length)
|
||||
// expect(results.profile).toEqual(mockUserProfile);
|
||||
// expect(results.compatibleProfiles).toContain(mockGenderCompatibleProfiles[0]);
|
||||
expect(results?.[0][0]).toEqual("1");
|
||||
expect(results?.[0][1]).toEqual("123");
|
||||
expect(results?.[0][2]).toBeCloseTo(mockCompatibilityScore.score, 2);
|
||||
});
|
||||
|
||||
it('throw an error if there is no profile matching the user Id', async () => {
|
||||
const mockUser = {userId: "123"};
|
||||
|
||||
expect(recomputeCompatibilityScoresForUser(mockUser.userId))
|
||||
.rejects
|
||||
.toThrowError('Profile not found');
|
||||
expect(profilesSupabaseModules.getProfile).toBeCalledWith(mockUser.userId);
|
||||
expect(profilesSupabaseModules.getProfile).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -2,107 +2,11 @@
|
||||
// export ENVIRONMENT=DEV && ./scripts/build_api.sh && npx tsx ./scripts/userCreation.ts
|
||||
|
||||
import {createSupabaseDirectClient} from "../backend/shared/lib/supabase/init";
|
||||
import {insert} from "../backend/shared/lib/supabase/utils";
|
||||
import {PrivateUser} from "../common/lib/user";
|
||||
import {getDefaultNotificationPreferences} from "../common/lib/user-notification-preferences";
|
||||
import {randomString} from "../common/lib/util/random";
|
||||
import UserAccountInformation from "../tests/e2e/backend/utils/userInformation";
|
||||
import { seedDatabase } from "../tests/e2e/utils/seedDatabase";
|
||||
|
||||
type ProfileType = 'basic' | 'medium' | 'full'
|
||||
|
||||
/**
|
||||
* Function used to populate the database with profiles.
|
||||
*
|
||||
* @param pg - Supabase client used to access the database.
|
||||
* @param userInfo - Class object containing information to create a user account generated by `fakerjs`.
|
||||
* @param profileType - Optional param used to signify how much information is used in the account generation.
|
||||
*/
|
||||
async function seedDatabase (pg: any, userInfo: UserAccountInformation, profileType?: string) {
|
||||
|
||||
const userId = userInfo.user_id
|
||||
const deviceToken = randomString()
|
||||
const bio = {
|
||||
"type": "doc",
|
||||
"content": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"content": [
|
||||
{
|
||||
"text": userInfo.bio,
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
const basicProfile = {
|
||||
user_id: userId,
|
||||
bio_length: userInfo.bio.length,
|
||||
bio: bio,
|
||||
age: userInfo.age,
|
||||
born_in_location: userInfo.born_in_location,
|
||||
company: userInfo.company,
|
||||
}
|
||||
|
||||
const mediumProfile = {
|
||||
...basicProfile,
|
||||
drinks_per_month: userInfo.drinks_per_month,
|
||||
diet: [userInfo.randomElement(userInfo.diet)],
|
||||
education_level: userInfo.randomElement(userInfo.education_level),
|
||||
ethnicity: [userInfo.randomElement(userInfo.ethnicity)],
|
||||
gender: userInfo.randomElement(userInfo.gender),
|
||||
height_in_inches: userInfo.height_in_inches,
|
||||
pref_gender: [userInfo.randomElement(userInfo.pref_gender)],
|
||||
pref_age_min: userInfo.pref_age.min,
|
||||
pref_age_max: userInfo.pref_age.max,
|
||||
}
|
||||
|
||||
const fullProfile = {
|
||||
...mediumProfile,
|
||||
occupation_title: userInfo.occupation_title,
|
||||
political_beliefs: [userInfo.randomElement(userInfo.political_beliefs)],
|
||||
pref_relation_styles: [userInfo.randomElement(userInfo.pref_relation_styles)],
|
||||
religion: [userInfo.randomElement(userInfo.religion)],
|
||||
}
|
||||
|
||||
const profileData = profileType === 'basic' ? basicProfile
|
||||
: profileType === 'medium' ? mediumProfile
|
||||
: fullProfile
|
||||
|
||||
const user = {
|
||||
// avatarUrl,
|
||||
isBannedFromPosting: false,
|
||||
link: {},
|
||||
}
|
||||
|
||||
const privateUser: PrivateUser = {
|
||||
id: userId,
|
||||
email: userInfo.email,
|
||||
initialIpAddress: userInfo.ip,
|
||||
initialDeviceToken: deviceToken,
|
||||
notificationPreferences: getDefaultNotificationPreferences(),
|
||||
blockedUserIds: [],
|
||||
blockedByUserIds: [],
|
||||
}
|
||||
|
||||
await pg.tx(async (tx:any) => {
|
||||
|
||||
await insert(tx, 'users', {
|
||||
id: userId,
|
||||
name: userInfo.name,
|
||||
username: userInfo.name,
|
||||
data: user,
|
||||
})
|
||||
|
||||
await insert(tx, 'private_users', {
|
||||
id: userId,
|
||||
data: privateUser,
|
||||
})
|
||||
|
||||
await insert(tx, 'profiles', profileData )
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
(async () => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
|
||||
99
tests/e2e/utils/seedDatabase.ts
Normal file
99
tests/e2e/utils/seedDatabase.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import {insert} from "../../../backend/shared/lib/supabase/utils";
|
||||
import {PrivateUser} from "../../../common/lib/user";
|
||||
import {getDefaultNotificationPreferences} from "../../../common/lib/user-notification-preferences";
|
||||
import {randomString} from "../../../common/lib/util/random";
|
||||
import UserAccountInformation from "../backend/utils/userInformation";
|
||||
|
||||
/**
|
||||
* Function used to populate the database with profiles.
|
||||
*
|
||||
* @param pg - Supabase client used to access the database.
|
||||
* @param userInfo - Class object containing information to create a user account generated by `fakerjs`.
|
||||
* @param profileType - Optional param used to signify how much information is used in the account generation.
|
||||
*/
|
||||
export async function seedDatabase (pg: any, userInfo: UserAccountInformation, profileType?: string) {
|
||||
|
||||
const userId = userInfo.user_id
|
||||
const deviceToken = randomString()
|
||||
const bio = {
|
||||
"type": "doc",
|
||||
"content": [
|
||||
{
|
||||
"type": "paragraph",
|
||||
"content": [
|
||||
{
|
||||
"text": userInfo.bio,
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
const basicProfile = {
|
||||
user_id: userId,
|
||||
bio_length: userInfo.bio.length,
|
||||
bio: bio,
|
||||
age: userInfo.age,
|
||||
born_in_location: userInfo.born_in_location,
|
||||
company: userInfo.company,
|
||||
}
|
||||
|
||||
const mediumProfile = {
|
||||
...basicProfile,
|
||||
drinks_per_month: userInfo.drinks_per_month,
|
||||
diet: [userInfo.randomElement(userInfo.diet)],
|
||||
education_level: userInfo.randomElement(userInfo.education_level),
|
||||
ethnicity: [userInfo.randomElement(userInfo.ethnicity)],
|
||||
gender: userInfo.randomElement(userInfo.gender),
|
||||
height_in_inches: userInfo.height_in_inches,
|
||||
pref_gender: [userInfo.randomElement(userInfo.pref_gender)],
|
||||
pref_age_min: userInfo.pref_age.min,
|
||||
pref_age_max: userInfo.pref_age.max,
|
||||
}
|
||||
|
||||
const fullProfile = {
|
||||
...mediumProfile,
|
||||
occupation_title: userInfo.occupation_title,
|
||||
political_beliefs: [userInfo.randomElement(userInfo.political_beliefs)],
|
||||
pref_relation_styles: [userInfo.randomElement(userInfo.pref_relation_styles)],
|
||||
religion: [userInfo.randomElement(userInfo.religion)],
|
||||
}
|
||||
|
||||
const profileData = profileType === 'basic' ? basicProfile
|
||||
: profileType === 'medium' ? mediumProfile
|
||||
: fullProfile
|
||||
|
||||
const user = {
|
||||
// avatarUrl,
|
||||
isBannedFromPosting: false,
|
||||
link: {},
|
||||
}
|
||||
|
||||
const privateUser: PrivateUser = {
|
||||
id: userId,
|
||||
email: userInfo.email,
|
||||
initialIpAddress: userInfo.ip,
|
||||
initialDeviceToken: deviceToken,
|
||||
notificationPreferences: getDefaultNotificationPreferences(),
|
||||
blockedUserIds: [],
|
||||
blockedByUserIds: [],
|
||||
}
|
||||
|
||||
await pg.tx(async (tx:any) => {
|
||||
|
||||
await insert(tx, 'users', {
|
||||
id: userId,
|
||||
name: userInfo.name,
|
||||
username: userInfo.name,
|
||||
data: user,
|
||||
})
|
||||
|
||||
await insert(tx, 'private_users', {
|
||||
id: userId,
|
||||
data: privateUser,
|
||||
})
|
||||
|
||||
await insert(tx, 'profiles', profileData )
|
||||
|
||||
})
|
||||
};
|
||||
Reference in New Issue
Block a user