@studious-lms/server 1.2.45 → 1.2.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +45 -0
- package/.env.test.example +37 -0
- package/README.md +34 -7
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +12110 -0
- package/coverage/coverage-final.json +44 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +221 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/server/index.html +116 -0
- package/coverage/server/src/exportType.ts.html +109 -0
- package/coverage/server/src/index.html +161 -0
- package/coverage/server/src/index.ts.html +1702 -0
- package/coverage/server/src/instrument.ts.html +130 -0
- package/coverage/server/src/lib/config/env.ts.html +448 -0
- package/coverage/server/src/lib/config/index.html +116 -0
- package/coverage/server/src/lib/fileUpload.ts.html +1138 -0
- package/coverage/server/src/lib/googleCloudStorage.ts.html +334 -0
- package/coverage/server/src/lib/index.html +206 -0
- package/coverage/server/src/lib/jsonConversion.ts.html +2323 -0
- package/coverage/server/src/lib/jsonStyles.ts.html +193 -0
- package/coverage/server/src/lib/notificationHandler.ts.html +193 -0
- package/coverage/server/src/lib/pusher.ts.html +121 -0
- package/coverage/server/src/lib/thumbnailGenerator.ts.html +592 -0
- package/coverage/server/src/middleware/auth.ts.html +646 -0
- package/coverage/server/src/middleware/index.html +146 -0
- package/coverage/server/src/middleware/logging.ts.html +244 -0
- package/coverage/server/src/middleware/security.ts.html +271 -0
- package/coverage/server/src/routers/_app.ts.html +232 -0
- package/coverage/server/src/routers/agenda.ts.html +319 -0
- package/coverage/server/src/routers/announcement.ts.html +3481 -0
- package/coverage/server/src/routers/assignment.ts.html +7633 -0
- package/coverage/server/src/routers/attendance.ts.html +1030 -0
- package/coverage/server/src/routers/auth.ts.html +1081 -0
- package/coverage/server/src/routers/class.ts.html +3535 -0
- package/coverage/server/src/routers/comment.ts.html +991 -0
- package/coverage/server/src/routers/conversation.ts.html +982 -0
- package/coverage/server/src/routers/event.ts.html +1609 -0
- package/coverage/server/src/routers/file.ts.html +1144 -0
- package/coverage/server/src/routers/folder.ts.html +2797 -0
- package/coverage/server/src/routers/index.html +386 -0
- package/coverage/server/src/routers/labChat.ts.html +3073 -0
- package/coverage/server/src/routers/marketing.ts.html +340 -0
- package/coverage/server/src/routers/message.ts.html +1912 -0
- package/coverage/server/src/routers/notifications.ts.html +364 -0
- package/coverage/server/src/routers/section.ts.html +1120 -0
- package/coverage/server/src/routers/user.ts.html +862 -0
- package/coverage/server/src/routers/worksheet.ts.html +1729 -0
- package/coverage/server/src/trpc.ts.html +397 -0
- package/coverage/server/src/types/index.html +116 -0
- package/coverage/server/src/types/trpc.ts.html +127 -0
- package/coverage/server/src/utils/aiUser.ts.html +280 -0
- package/coverage/server/src/utils/email.ts.html +121 -0
- package/coverage/server/src/utils/generateInviteCode.ts.html +106 -0
- package/coverage/server/src/utils/index.html +206 -0
- package/coverage/server/src/utils/inference.ts.html +709 -0
- package/coverage/server/src/utils/logger.ts.html +664 -0
- package/coverage/server/src/utils/prismaErrorHandler.ts.html +907 -0
- package/coverage/server/src/utils/prismaWrapper.ts.html +355 -0
- package/coverage/server/vitest.config.ts.html +196 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -52
- package/dist/index.js.map +1 -1
- package/dist/instrument.js +15 -8
- package/dist/instrument.js.map +1 -1
- package/dist/lib/config/env.d.ts +169 -0
- package/dist/lib/config/env.d.ts.map +1 -0
- package/dist/lib/config/env.js +115 -0
- package/dist/lib/config/env.js.map +1 -0
- package/dist/lib/fileUpload.d.ts.map +1 -1
- package/dist/lib/fileUpload.js +5 -4
- package/dist/lib/fileUpload.js.map +1 -1
- package/dist/lib/googleCloudStorage.d.ts.map +1 -1
- package/dist/lib/googleCloudStorage.js +7 -8
- package/dist/lib/googleCloudStorage.js.map +1 -1
- package/dist/lib/jsonConversion.d.ts.map +1 -1
- package/dist/lib/jsonConversion.js +14 -16
- package/dist/lib/jsonConversion.js.map +1 -1
- package/dist/lib/notificationHandler.d.ts +2 -2
- package/dist/lib/prisma.d.ts +2 -2
- package/dist/lib/prisma.d.ts.map +1 -1
- package/dist/lib/prisma.js +22 -3
- package/dist/lib/prisma.js.map +1 -1
- package/dist/lib/pusher.d.ts.map +1 -1
- package/dist/lib/pusher.js +8 -7
- package/dist/lib/pusher.js.map +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +7 -5
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/security.d.ts +5 -0
- package/dist/middleware/security.d.ts.map +1 -0
- package/dist/middleware/security.js +77 -0
- package/dist/middleware/security.js.map +1 -0
- package/dist/routers/_app.d.ts +368 -108
- package/dist/routers/_app.d.ts.map +1 -1
- package/dist/routers/_app.js +4 -2
- package/dist/routers/_app.js.map +1 -1
- package/dist/routers/agenda.d.ts.map +1 -1
- package/dist/routers/agenda.js +12 -9
- package/dist/routers/agenda.js.map +1 -1
- package/dist/routers/announcement.d.ts +8 -0
- package/dist/routers/announcement.d.ts.map +1 -1
- package/dist/routers/announcement.js +6 -4
- package/dist/routers/announcement.js.map +1 -1
- package/dist/routers/assignment.d.ts +17 -4
- package/dist/routers/assignment.d.ts.map +1 -1
- package/dist/routers/assignment.js +51 -19
- package/dist/routers/assignment.js.map +1 -1
- package/dist/routers/attendance.d.ts +1 -0
- package/dist/routers/attendance.d.ts.map +1 -1
- package/dist/routers/attendance.js +4 -4
- package/dist/routers/attendance.js.map +1 -1
- package/dist/routers/auth.d.ts +20 -0
- package/dist/routers/auth.d.ts.map +1 -1
- package/dist/routers/auth.js +132 -15
- package/dist/routers/auth.js.map +1 -1
- package/dist/routers/class.d.ts +10 -0
- package/dist/routers/class.d.ts.map +1 -1
- package/dist/routers/class.js +49 -5
- package/dist/routers/class.js.map +1 -1
- package/dist/routers/comment.d.ts +2 -0
- package/dist/routers/comment.d.ts.map +1 -1
- package/dist/routers/conversation.d.ts +2 -0
- package/dist/routers/conversation.d.ts.map +1 -1
- package/dist/routers/conversation.js +46 -31
- package/dist/routers/conversation.js.map +1 -1
- package/dist/routers/file.d.ts.map +1 -1
- package/dist/routers/file.js +30 -7
- package/dist/routers/file.js.map +1 -1
- package/dist/routers/labChat.d.ts +2 -0
- package/dist/routers/labChat.d.ts.map +1 -1
- package/dist/routers/labChat.js +5 -322
- package/dist/routers/labChat.js.map +1 -1
- package/dist/routers/marketing.d.ts +1 -1
- package/dist/routers/message.d.ts +1 -0
- package/dist/routers/message.d.ts.map +1 -1
- package/dist/routers/message.js +3 -2
- package/dist/routers/message.js.map +1 -1
- package/dist/routers/newtonChat.d.ts +55 -0
- package/dist/routers/newtonChat.d.ts.map +1 -0
- package/dist/routers/newtonChat.js +262 -0
- package/dist/routers/newtonChat.js.map +1 -0
- package/dist/routers/notifications.d.ts +4 -4
- package/dist/routers/section.d.ts +19 -4
- package/dist/routers/section.d.ts.map +1 -1
- package/dist/routers/section.js +26 -8
- package/dist/routers/section.js.map +1 -1
- package/dist/routers/user.d.ts.map +1 -1
- package/dist/routers/user.js +5 -4
- package/dist/routers/user.js.map +1 -1
- package/dist/routers/worksheet.d.ts +44 -41
- package/dist/routers/worksheet.d.ts.map +1 -1
- package/dist/routers/worksheet.js +25 -34
- package/dist/routers/worksheet.js.map +1 -1
- package/dist/seedDatabase.d.ts +1 -1
- package/dist/seedDatabase.js +275 -284
- package/dist/seedDatabase.js.map +1 -1
- package/dist/server/pipelines/aiLabChat.d.ts +21 -0
- package/dist/server/pipelines/aiLabChat.d.ts.map +1 -0
- package/dist/server/pipelines/aiLabChat.js +456 -0
- package/dist/server/pipelines/aiLabChat.js.map +1 -0
- package/dist/server/pipelines/aiNewtonChat.d.ts +30 -0
- package/dist/server/pipelines/aiNewtonChat.d.ts.map +1 -0
- package/dist/server/pipelines/aiNewtonChat.js +280 -0
- package/dist/server/pipelines/aiNewtonChat.js.map +1 -0
- package/dist/server/pipelines/gradeWorksheet.d.ts +15 -0
- package/dist/server/pipelines/gradeWorksheet.d.ts.map +1 -0
- package/dist/server/pipelines/gradeWorksheet.js +139 -0
- package/dist/server/pipelines/gradeWorksheet.js.map +1 -0
- package/dist/trpc.d.ts.map +1 -1
- package/dist/trpc.js +2 -2
- package/dist/trpc.js.map +1 -1
- package/dist/utils/email.d.ts +9 -1
- package/dist/utils/email.d.ts.map +1 -1
- package/dist/utils/email.js +20 -5
- package/dist/utils/email.js.map +1 -1
- package/dist/utils/inference.d.ts +5 -0
- package/dist/utils/inference.d.ts.map +1 -1
- package/dist/utils/inference.js +71 -7
- package/dist/utils/inference.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +3 -3
- package/dist/utils/logger.js.map +1 -1
- package/docker-compose.yml +14 -0
- package/package.json +13 -4
- package/prisma/schema.prisma +34 -5
- package/scripts/test-pre-push.ts +14 -0
- package/src/index.ts +98 -54
- package/src/instrument.ts +13 -6
- package/src/lib/config/env.ts +126 -0
- package/src/lib/fileUpload.ts +3 -2
- package/src/lib/googleCloudStorage.ts +6 -6
- package/src/lib/jsonConversion.ts +12 -14
- package/src/lib/prisma.ts +23 -2
- package/src/lib/pusher.ts +6 -5
- package/src/middleware/auth.ts +5 -3
- package/src/middleware/security.ts +80 -0
- package/src/routers/_app.ts +2 -0
- package/src/routers/agenda.ts +10 -7
- package/src/routers/announcement.ts +4 -2
- package/src/routers/assignment.ts +74 -41
- package/src/routers/attendance.ts +2 -2
- package/src/routers/auth.ts +143 -14
- package/src/routers/class.ts +52 -3
- package/src/routers/conversation.ts +49 -29
- package/src/routers/file.ts +29 -5
- package/src/routers/labChat.ts +3 -367
- package/src/routers/message.ts +1 -1
- package/src/routers/newtonChat.ts +299 -0
- package/src/routers/section.ts +26 -6
- package/src/routers/user.ts +3 -2
- package/src/routers/worksheet.ts +26 -38
- package/src/seedDatabase.ts +290 -283
- package/src/server/pipelines/aiLabChat.ts +507 -0
- package/src/server/pipelines/aiNewtonChat.ts +338 -0
- package/src/server/pipelines/gradeWorksheet.ts +151 -0
- package/src/trpc.ts +2 -0
- package/src/utils/email.ts +30 -3
- package/src/utils/inference.ts +85 -5
- package/src/utils/logger.ts +2 -1
- package/tests/announcement.test.ts +164 -0
- package/tests/assignment.test.ts +296 -0
- package/tests/attendance.test.ts +168 -0
- package/tests/auth.test.ts +33 -10
- package/tests/class.test.ts +34 -9
- package/tests/event.test.ts +228 -0
- package/tests/section.test.ts +216 -0
- package/tests/setup.ts +70 -16
- package/tests/user.test.ts +158 -0
- package/vitest.config.ts +26 -0
- package/API_SPECIFICATION.md +0 -1597
- package/BASE64_REMOVAL_SUMMARY.md +0 -164
- package/CHAT_API_SPEC.md +0 -579
- package/LAB_CHAT_API_SPEC.md +0 -518
- package/dist/routers/school.d.ts +0 -208
- package/dist/routers/school.d.ts.map +0 -1
- package/dist/routers/school.js +0 -483
package/tests/setup.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
import { resolve } from 'path';
|
|
2
4
|
import { prisma } from '../src/lib/prisma';
|
|
3
5
|
import { beforeAll, beforeEach, afterAll, afterEach } from 'vitest';
|
|
4
6
|
import { logger } from '../src/utils/logger';
|
|
@@ -7,26 +9,31 @@ import { createTRPCContext } from '../src/trpc';
|
|
|
7
9
|
import { Session } from '@prisma/client';
|
|
8
10
|
import { clearDatabase } from '../src/seedDatabase';
|
|
9
11
|
|
|
12
|
+
// Load test environment variables
|
|
13
|
+
config({ path: resolve(process.cwd(), '.env.test') });
|
|
14
|
+
|
|
10
15
|
const getCaller = async (token: string) => {
|
|
11
16
|
const ctx = await createTRPCContext({
|
|
12
17
|
req: { headers: {
|
|
13
|
-
authorization: `Bearer ${token}
|
|
14
|
-
'x-user': token,
|
|
18
|
+
authorization: token ? `Bearer ${token}` : undefined,
|
|
19
|
+
'x-user': token || undefined,
|
|
15
20
|
} } as any,
|
|
16
21
|
res: {} as any,
|
|
17
22
|
});
|
|
18
23
|
return appRouter.createCaller(ctx);
|
|
19
24
|
};
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
// Before the entire test suite runs
|
|
27
|
+
beforeAll(async () => {
|
|
28
|
+
try {
|
|
29
|
+
logger.info('DATABASE_URL: ' + process.env.DATABASE_URL);
|
|
24
30
|
await clearDatabase();
|
|
31
|
+
logger.info('Database cleared for tests');
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
// Create public caller (no auth) for registration
|
|
28
34
|
caller = await getCaller('');
|
|
29
35
|
|
|
36
|
+
// Register users
|
|
30
37
|
const user1 = await caller.auth.register({
|
|
31
38
|
username: 'testuser1',
|
|
32
39
|
email: 'test@test.com',
|
|
@@ -41,18 +48,37 @@ const getCaller = async (token: string) => {
|
|
|
41
48
|
confirmPassword: 'password_is_1234',
|
|
42
49
|
});
|
|
43
50
|
|
|
51
|
+
const user3 = await caller.auth.register({
|
|
52
|
+
username: 'testuser3',
|
|
53
|
+
email: 'test3@test.com',
|
|
54
|
+
password: 'password_is_1234',
|
|
55
|
+
confirmPassword: 'password_is_1234',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Get sessions created during registration
|
|
44
59
|
session1 = await prisma.session.findFirst({
|
|
45
60
|
where: {
|
|
46
61
|
userId: user1.user.id,
|
|
47
62
|
},
|
|
48
63
|
}) as Session;
|
|
49
64
|
|
|
50
|
-
session2 =
|
|
65
|
+
session2 = await prisma.session.findFirst({
|
|
51
66
|
where: {
|
|
52
67
|
userId: user2.user.id,
|
|
53
68
|
},
|
|
54
|
-
})
|
|
69
|
+
}) as Session;
|
|
70
|
+
|
|
71
|
+
session3 = await prisma.session.findFirst({
|
|
72
|
+
where: {
|
|
73
|
+
userId: user3.user.id,
|
|
74
|
+
},
|
|
75
|
+
}) as Session;
|
|
55
76
|
|
|
77
|
+
if (!session1 || !session2 || !session3) {
|
|
78
|
+
throw new Error('Failed to create sessions for test users');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Verify emails using session tokens
|
|
56
82
|
verification1 = await caller.auth.verify({
|
|
57
83
|
token: session1.id,
|
|
58
84
|
});
|
|
@@ -61,6 +87,11 @@ const getCaller = async (token: string) => {
|
|
|
61
87
|
token: session2.id,
|
|
62
88
|
});
|
|
63
89
|
|
|
90
|
+
verification3 = await caller.auth.verify({
|
|
91
|
+
token: session3.id,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Login to get fresh tokens
|
|
64
95
|
login1 = await caller.auth.login({
|
|
65
96
|
username: 'testuser1',
|
|
66
97
|
password: 'password_is_1234',
|
|
@@ -71,22 +102,45 @@ const getCaller = async (token: string) => {
|
|
|
71
102
|
password: 'password_is_1234',
|
|
72
103
|
});
|
|
73
104
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
105
|
+
login3 = await caller.auth.login({
|
|
106
|
+
username: 'testuser3',
|
|
107
|
+
password: 'password_is_1234',
|
|
108
|
+
});
|
|
77
109
|
|
|
110
|
+
if (!login1.token || !login2.token || !login3.token) {
|
|
111
|
+
throw new Error('Failed to get login tokens');
|
|
112
|
+
}
|
|
78
113
|
|
|
79
|
-
|
|
80
|
-
|
|
114
|
+
// Create authenticated callers
|
|
115
|
+
user1Caller = await getCaller(login1.token);
|
|
116
|
+
user2Caller = await getCaller(login2.token);
|
|
117
|
+
user3Caller = await getCaller(login3.token);
|
|
118
|
+
logger.info('Test setup completed successfully');
|
|
119
|
+
} catch (error) {
|
|
120
|
+
logger.error('Test setup failed', { error });
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// After all tests, close the DB
|
|
126
|
+
afterAll(async () => {
|
|
127
|
+
try {
|
|
81
128
|
await prisma.$disconnect();
|
|
82
|
-
})
|
|
129
|
+
} catch (error) {
|
|
130
|
+
logger.error('Error disconnecting from database', { error });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
83
133
|
|
|
84
134
|
export let user1Caller: ReturnType<typeof appRouter.createCaller>;
|
|
85
135
|
export let user2Caller: ReturnType<typeof appRouter.createCaller>;
|
|
136
|
+
export let user3Caller: ReturnType<typeof appRouter.createCaller>;
|
|
86
137
|
export let caller: ReturnType<typeof appRouter.createCaller>;
|
|
87
138
|
export let session1: Session;
|
|
88
139
|
export let session2: Session;
|
|
140
|
+
export let session3: Session;
|
|
89
141
|
export let verification1: any;
|
|
90
142
|
export let verification2: any;
|
|
143
|
+
export let verification3: any;
|
|
91
144
|
export let login1: any;
|
|
92
|
-
export let login2: any;
|
|
145
|
+
export let login2: any;
|
|
146
|
+
export let login3: any;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { test, expect, describe, beforeEach } from 'vitest';
|
|
2
|
+
import { user1Caller, user2Caller } from './setup';
|
|
3
|
+
import { createTRPCContext } from '../src/trpc';
|
|
4
|
+
import { appRouter } from '../src/routers/_app';
|
|
5
|
+
|
|
6
|
+
describe('User Router', () => {
|
|
7
|
+
describe('getProfile', () => {
|
|
8
|
+
test('should get user profile successfully', async () => {
|
|
9
|
+
const profile = await user1Caller.user.getProfile();
|
|
10
|
+
|
|
11
|
+
expect(profile).toBeDefined();
|
|
12
|
+
expect(profile.id).toBeDefined();
|
|
13
|
+
expect(profile.username).toBe('testuser1');
|
|
14
|
+
expect(profile.profile).toBeDefined();
|
|
15
|
+
expect(profile.profile.displayName).toBeNull();
|
|
16
|
+
expect(profile.profile.bio).toBeNull();
|
|
17
|
+
expect(profile.profile.location).toBeNull();
|
|
18
|
+
expect(profile.profile.website).toBeNull();
|
|
19
|
+
expect(profile.profile.profilePicture).toBeNull();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('should fail without authentication', async () => {
|
|
23
|
+
const invalidCaller = await createTRPCContext({
|
|
24
|
+
req: { headers: {} } as any,
|
|
25
|
+
res: {} as any,
|
|
26
|
+
});
|
|
27
|
+
const router = appRouter.createCaller(invalidCaller);
|
|
28
|
+
|
|
29
|
+
await expect(router.user.getProfile()).rejects.toThrow();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('updateProfile', () => {
|
|
34
|
+
test('should update profile with display name and bio', async () => {
|
|
35
|
+
const updated = await user1Caller.user.updateProfile({
|
|
36
|
+
profile: {
|
|
37
|
+
displayName: 'Test User One',
|
|
38
|
+
bio: 'This is a test bio',
|
|
39
|
+
location: 'Test City',
|
|
40
|
+
website: 'https://example.com',
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(updated).toBeDefined();
|
|
45
|
+
expect(updated.profile.displayName).toBe('Test User One');
|
|
46
|
+
expect(updated.profile.bio).toBe('This is a test bio');
|
|
47
|
+
expect(updated.profile.location).toBe('Test City');
|
|
48
|
+
expect(updated.profile.website).toBe('https://example.com');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('should update profile with partial data', async () => {
|
|
52
|
+
const updated = await user2Caller.user.updateProfile({
|
|
53
|
+
profile: {
|
|
54
|
+
displayName: 'Test User Two',
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(updated.profile.displayName).toBe('Test User Two');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('should update profile with DiceBear avatar', async () => {
|
|
62
|
+
const updated = await user1Caller.user.updateProfile({
|
|
63
|
+
dicebearAvatar: {
|
|
64
|
+
url: 'https://api.dicebear.com/7.x/avataaars/svg?seed=test',
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(updated.profile.profilePicture).toBe('https://api.dicebear.com/7.x/avataaars/svg?seed=test');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// test('should clear profile fields when set to null', async () => {
|
|
72
|
+
// // First set some values
|
|
73
|
+
// await user1Caller.user.updateProfile({
|
|
74
|
+
// profile: {
|
|
75
|
+
// displayName: 'Test Name',
|
|
76
|
+
// bio: 'Test Bio',
|
|
77
|
+
// },
|
|
78
|
+
// });
|
|
79
|
+
|
|
80
|
+
// // Then clear them
|
|
81
|
+
// const cleared = await user1Caller.user.updateProfile({
|
|
82
|
+
// profile: {
|
|
83
|
+
// displayName: null,
|
|
84
|
+
// bio: null,
|
|
85
|
+
// },
|
|
86
|
+
// });
|
|
87
|
+
|
|
88
|
+
// expect(cleared.profile.displayName).toBeNull();
|
|
89
|
+
// expect(cleared.profile.bio).toBeNull();
|
|
90
|
+
// });
|
|
91
|
+
|
|
92
|
+
test('should fail without authentication', async () => {
|
|
93
|
+
const invalidCaller = await createTRPCContext({
|
|
94
|
+
req: { headers: {} } as any,
|
|
95
|
+
res: {} as any,
|
|
96
|
+
});
|
|
97
|
+
const router = appRouter.createCaller(invalidCaller);
|
|
98
|
+
|
|
99
|
+
await expect(router.user.updateProfile({
|
|
100
|
+
profile: { displayName: 'Test' },
|
|
101
|
+
})).rejects.toThrow();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('getUploadUrl', () => {
|
|
106
|
+
test('should generate upload URL for valid image file', async () => {
|
|
107
|
+
const result = await user1Caller.user.getUploadUrl({
|
|
108
|
+
fileName: 'profile.jpg',
|
|
109
|
+
fileType: 'image/jpeg',
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(result).toBeDefined();
|
|
113
|
+
expect(result.uploadUrl).toBeDefined();
|
|
114
|
+
expect(result.filePath).toBeDefined();
|
|
115
|
+
expect(result.fileName).toBeDefined();
|
|
116
|
+
expect(result.filePath).toContain('users/');
|
|
117
|
+
expect(result.filePath).toContain('/profile/');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test('should generate upload URL for PNG file', async () => {
|
|
121
|
+
const result = await user1Caller.user.getUploadUrl({
|
|
122
|
+
fileName: 'avatar.png',
|
|
123
|
+
fileType: 'image/png',
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(result).toBeDefined();
|
|
127
|
+
expect(result.fileName).toContain('.png');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('should fail for invalid file type', async () => {
|
|
131
|
+
await expect(user1Caller.user.getUploadUrl({
|
|
132
|
+
fileName: 'document.pdf',
|
|
133
|
+
fileType: 'application/pdf',
|
|
134
|
+
})).rejects.toThrow();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('should fail for empty file name', async () => {
|
|
138
|
+
await expect(user1Caller.user.getUploadUrl({
|
|
139
|
+
fileName: '',
|
|
140
|
+
fileType: 'image/jpeg',
|
|
141
|
+
})).rejects.toThrow();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('should fail without authentication', async () => {
|
|
145
|
+
const invalidCaller = await createTRPCContext({
|
|
146
|
+
req: { headers: {} } as any,
|
|
147
|
+
res: {} as any,
|
|
148
|
+
});
|
|
149
|
+
const router = appRouter.createCaller(invalidCaller);
|
|
150
|
+
|
|
151
|
+
await expect(router.user.getUploadUrl({
|
|
152
|
+
fileName: 'test.jpg',
|
|
153
|
+
fileType: 'image/jpeg',
|
|
154
|
+
})).rejects.toThrow();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
package/vitest.config.ts
CHANGED
|
@@ -1,11 +1,37 @@
|
|
|
1
1
|
import { defineConfig } from 'vitest/config';
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
import { resolve } from 'path';
|
|
4
|
+
|
|
5
|
+
// Load test environment variables before anything else
|
|
6
|
+
config({ path: resolve(process.cwd(), '.env.test'), override: true });
|
|
2
7
|
|
|
3
8
|
export default defineConfig({
|
|
4
9
|
test: {
|
|
5
10
|
globals: true,
|
|
6
11
|
environment: 'node',
|
|
7
12
|
hookTimeout: 60000, // 60 seconds
|
|
13
|
+
testTimeout: 30000, // 30 seconds per test
|
|
8
14
|
include: ['tests/**/*.test.ts'],
|
|
9
15
|
setupFiles: ['./tests/setup.ts'], // run setup before tests
|
|
16
|
+
// Run tests sequentially to avoid database conflicts
|
|
17
|
+
// Can be changed to true once tests are fully isolated
|
|
18
|
+
sequence: {
|
|
19
|
+
concurrent: false,
|
|
20
|
+
},
|
|
21
|
+
coverage: {
|
|
22
|
+
exclude: [
|
|
23
|
+
"generated/**",
|
|
24
|
+
"prisma/**",
|
|
25
|
+
"scripts/**",
|
|
26
|
+
"src/lib/prisma.ts",
|
|
27
|
+
"src/seedDatabase.ts",
|
|
28
|
+
"src/socket/**",
|
|
29
|
+
"**/node_modules/**",
|
|
30
|
+
"**/dist/**",
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
env: {
|
|
34
|
+
NODE_ENV: 'test',
|
|
35
|
+
},
|
|
10
36
|
},
|
|
11
37
|
});
|