Skip to content

Commit ec87fd9

Browse files
authored
Merge pull request #60 from leepoeaik/develop
fix(collaboration-service): Fix failing tests and remove unused code
2 parents e19646f + 19c97a6 commit ec87fd9

File tree

6 files changed

+48
-48
lines changed

6 files changed

+48
-48
lines changed

collaboration-service/src/__tests__/codeServer.onBeforeConnect.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ jest.unstable_mockModule('../storage/db.js', () => ({
1212
getDocument: jest.fn(),
1313
upsertDocument: jest.fn(),
1414
checkUserVerified: jest.fn(),
15+
deleteRoom: jest.fn(),
1516
}));
1617

17-
let YjsServer: typeof import('../party/codeServer.js').default;
18+
let YjsServer: typeof import('../party/websocketServer.js').default;
1819

1920
class MockHeaders {
2021
private readonly store = new Map<string, string>();
@@ -41,7 +42,7 @@ const buildRequest = (url: string, headers: Record<string, string> = {}) =>
4142
}) as unknown as Request;
4243

4344
beforeAll(async () => {
44-
({default: YjsServer} = await import('../party/codeServer.js'));
45+
({default: YjsServer} = await import('../party/websocketServer.js'));
4546
});
4647

4748
describe('YjsServer.onBeforeConnect', () => {

collaboration-service/src/__tests__/codeServer.onConnect.test.ts

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
import {afterAll, beforeAll, beforeEach, describe, expect, it, jest} from '@jest/globals';
2+
import {Buffer} from 'node:buffer';
3+
import type * as Party from 'partykit/server';
24
import * as Y from 'yjs';
35

4-
const verifyTokenMock = jest.fn();
5-
const checkUserVerifiedMock = jest.fn();
6-
const getDocumentMock = jest.fn();
7-
const upsertDocumentMock = jest.fn();
8-
const partyOnConnectMock = jest.fn();
6+
const verifyTokenMock = jest.fn<() => Promise<{valid: boolean; payload?: any; error?: any}>>();
7+
const checkUserVerifiedMock = jest.fn<() => Promise<boolean>>();
8+
const getDocumentMock = jest.fn<() => Promise<{data: any; error: any}>>();
9+
const upsertDocumentMock = jest.fn<(roomId: string, content: Uint8Array) => Promise<{data: any; error: any}>>();
10+
const partyOnConnectMock = jest.fn<
11+
(
12+
connection: Party.Connection,
13+
room: Party.Room,
14+
options: {
15+
load: () => Promise<Y.Doc>;
16+
callback?: {handler: (doc: Y.Doc) => Promise<void>};
17+
}
18+
) => Promise<void>
19+
>();
920

1021
jest.unstable_mockModule('../utils/jwt.js', () => ({
1122
verifyToken: verifyTokenMock,
@@ -16,17 +27,19 @@ jest.unstable_mockModule('../storage/db.js', () => ({
1627
getDocument: getDocumentMock,
1728
upsertDocument: upsertDocumentMock,
1829
checkRoomExists: jest.fn(),
30+
deleteRoom: jest.fn(),
1931
}));
2032

2133
jest.unstable_mockModule('y-partykit', () => ({
2234
onConnect: partyOnConnectMock,
2335
}));
2436

25-
let YjsServer: typeof import('../party/codeServer.js').default;
37+
let YjsServer: typeof import('../party/websocketServer.js').default;
2638

2739
const createConnection = () =>
2840
({
2941
close: jest.fn(),
42+
addEventListener: jest.fn(),
3043
}) as unknown as Party.Connection;
3144

3245
const buildContext = (token?: string) =>
@@ -41,7 +54,7 @@ const buildContext = (token?: string) =>
4154
const room = {id: 'room-1'} as unknown as Party.Room;
4255

4356
beforeAll(async () => {
44-
({default: YjsServer} = await import('../party/codeServer.js'));
57+
({default: YjsServer} = await import('../party/websocketServer.js'));
4558
});
4659

4760
describe('YjsServer.onConnect', () => {
@@ -76,7 +89,7 @@ describe('YjsServer.onConnect', () => {
7689
const server = new YjsServer(room);
7790
const connection = createConnection();
7891

79-
verifyTokenMock.mockResolvedValue({valid: false, error: new Error('invalid token')} as any);
92+
verifyTokenMock.mockResolvedValue({valid: false, error: new Error('invalid token')});
8093

8194
await server.onConnect(connection, buildContext('token-1'));
8295

@@ -91,7 +104,7 @@ describe('YjsServer.onConnect', () => {
91104
verifyTokenMock.mockResolvedValue({
92105
valid: true,
93106
payload: {userId: 'user-1'},
94-
} as any);
107+
});
95108
checkUserVerifiedMock.mockResolvedValue(false);
96109

97110
await server.onConnect(connection, buildContext('token-1'));
@@ -110,10 +123,10 @@ describe('YjsServer.onConnect', () => {
110123
verifyTokenMock.mockResolvedValue({
111124
valid: true,
112125
payload: {userId: 'user-1'},
113-
} as any);
126+
});
114127
checkUserVerifiedMock.mockResolvedValue(true);
115-
getDocumentMock.mockResolvedValue({data: null, error: null} as any);
116-
upsertDocumentMock.mockResolvedValue({data: null, error: null} as any);
128+
getDocumentMock.mockResolvedValue({data: null, error: null});
129+
upsertDocumentMock.mockResolvedValue({data: null, error: null});
117130

118131
partyOnConnectMock.mockImplementation(async (_connection, _, options) => {
119132
const doc = await options.load();
@@ -138,13 +151,13 @@ describe('YjsServer.onConnect', () => {
138151
verifyTokenMock.mockResolvedValue({
139152
valid: true,
140153
payload: {userId: 'user-1'},
141-
} as any);
154+
});
142155
checkUserVerifiedMock.mockResolvedValue(true);
143156
getDocumentMock.mockResolvedValue({
144157
data: {document: Buffer.from(encoded).toString('base64')},
145158
error: null,
146-
} as any);
147-
upsertDocumentMock.mockResolvedValue({data: null, error: null} as any);
159+
});
160+
upsertDocumentMock.mockResolvedValue({data: null, error: null});
148161

149162
let loadedDoc: Y.Doc | null = null;
150163
partyOnConnectMock.mockImplementation(async (_connection, _, options) => {
@@ -153,7 +166,8 @@ describe('YjsServer.onConnect', () => {
153166

154167
await server.onConnect(connection, buildContext('token-1'));
155168

156-
expect(loadedDoc?.getText('codemirror').toString()).toBe('hello');
169+
expect(loadedDoc).not.toBeNull();
170+
expect(loadedDoc!.getText('codemirror').toString()).toBe('hello');
157171
});
158172

159173
it('closes the connection when loading the document fails', async () => {
@@ -163,20 +177,22 @@ describe('YjsServer.onConnect', () => {
163177
verifyTokenMock.mockResolvedValue({
164178
valid: true,
165179
payload: {userId: 'user-1'},
166-
} as any);
180+
});
167181
checkUserVerifiedMock.mockResolvedValue(true);
168182
getDocumentMock.mockResolvedValue({
169183
data: null,
170184
error: {message: 'database offline'},
171-
} as any);
185+
});
172186

173187
partyOnConnectMock.mockImplementation(async (_connection, _, options) => {
188+
// This will throw an error which should be caught by the outer try-catch
174189
await options.load();
175190
});
176191

177192
await server.onConnect(connection, buildContext('token-1'));
178193

179194
expect(connection.close).toHaveBeenCalledWith(4000, 'Internal server error');
195+
expect(partyOnConnectMock).toHaveBeenCalledTimes(1);
180196
});
181197
});
182198

collaboration-service/src/__tests__/yjsHelpers.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as Y from 'yjs';
22

3-
import {ensureSharedStructures, pruneChatHistory} from '../party/codeServer.js';
3+
import {ensureSharedStructures, pruneChatHistory} from '../party/websocketServer.js';
44

55
describe('Yjs helper utilities', () => {
66
it('initialises the required collaborative structures', () => {
@@ -11,7 +11,8 @@ describe('Yjs helper utilities', () => {
1111
expect(doc.getText('codemirror')).toBeInstanceOf(Y.Text);
1212
expect(doc.getMap<string>('config')).toBeInstanceOf(Y.Map);
1313
expect(doc.getArray('chat')).toBeInstanceOf(Y.Array);
14-
expect(doc.getMap('executionState')).toBeInstanceOf(Y.Map);
14+
expect(doc.getMap('execution')).toBeInstanceOf(Y.Map);
15+
expect(doc.getMap('submission')).toBeInstanceOf(Y.Map);
1516
});
1617

1718
it('prunes chat history that exceeds the chat limit', () => {

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,10 @@ services:
6565
environment:
6666
- NODE_ENV=development
6767
- VITE_NGROK_COLLAB_HOST=${VITE_NGROK_COLLAB_HOST}
68-
- VITE_HISTORY_SERVICE_URL=http://localhost:8085
68+
- VITE_HISTORY_SERVICE_URL=${VITE_HISTORY_SERVICE_URL}
6969
- VITE_QUESTION_SERVICE_URL=http://localhost:8083
7070
- VITE_USER_SERVICE_URL=http://localhost:8080
71-
- VITE_MATCHING_SERVICE_URL=http://localhost:8081
71+
- VITE_MATCHING_SERVICE_URL=${VITE_MATCHING_SERVICE_URL}
7272
volumes:
7373
- ./frontend:/app
7474
- /app/node_modules

frontend/src/collaboration/components/CollabEditor.tsx

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ export default function CollabEditor({
2626
provider: YPartyKitProvider;
2727
}) {
2828
// const {ytext, awareness, isReady, languageConfig, setSharedLanguage} = useCollabEditor({roomId});
29-
const [activeTab, setActiveTab] = useState('code');
3029
const {ytext, awareness, isReady, languageConfig, setSharedLanguage} = useCollabEditor({
3130
roomId,
3231
provider,
@@ -53,24 +52,10 @@ export default function CollabEditor({
5352
{/* Header with tabs and language selector */}
5453
<div className="flex items-center px-4 justify-between w-full border-b border-gray-200 py-2 flex-shrink-0">
5554
<div className="flex items-center space-x-4">
56-
<button
57-
onClick={() => setActiveTab('code')}
58-
className={`flex items-center space-x-2 px-3 py-2 rounded ${
59-
activeTab === 'code' ? 'bg-gray-100' : 'hover:bg-gray-50'
60-
}`}
61-
>
55+
<button className={`flex items-center space-x-2 px-3 py-2 rounded 'bg-gray-100'}`}>
6256
<Code size={16} />
6357
<span className="text-sm font-medium">Code</span>
6458
</button>
65-
<button
66-
onClick={() => setActiveTab('whiteboard')}
67-
className={`flex items-center space-x-2 px-3 py-2 rounded ${
68-
activeTab === 'whiteboard' ? 'bg-gray-100' : 'hover:bg-gray-50'
69-
}`}
70-
>
71-
<Image size={16} />
72-
<span className="text-sm font-medium">Whiteboard</span>
73-
</button>
7459
</div>
7560

7661
<div className="flex items-center space-x-2"></div>

frontend/src/collaboration/components/SubmissionPanel.tsx

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import useAuth from '@/hooks/useAuth';
1010
import * as Y from 'yjs';
1111

1212
// const HISTORY_SERVICE_URL = import.meta.env.VITE_HISTORY_SERVICE_URL || 'http://localhost:8085';
13-
const HISTORY_SERVICE_URL = 'http://localhost:8085';
14-
const MATCHING_SERVICE_URL = 'http://localhost:8081';
15-
const COLLAB_SERVICE_URL = 'http://localhost:8082';
13+
const HISTORY_SERVICE_URL = import.meta.env['VITE_HISTORY_SERVICE_URL'] || 'http://localhost:8085';
14+
const MATCHING_SERVICE_URL =
15+
import.meta.env['VITE_MATCHING_SERVICE_URL'] || 'http://localhost:8081';
16+
const COLLAB_SERVICE_URL =
17+
`http://${import.meta.env['VITE_NGROK_COLLAB_HOST']}` || 'http://localhost:8082';
1618

1719
export default function SubmissionPanel({
1820
isPenaltyOver,
@@ -311,11 +313,6 @@ export default function SubmissionPanel({
311313
<span>{isSubmitting ? 'Submitting...' : 'Submit Solution'}</span>
312314
</button>
313315

314-
<button className="w-full border border-gray-300 hover:bg-gray-50 py-3 rounded-lg font-semibold flex items-center justify-center space-x-2">
315-
<Eye size={18} />
316-
<span>View Solution</span>
317-
</button>
318-
319316
<button
320317
className="w-full bg-red-500 hover:bg-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed text-white py-3 rounded-lg font-semibold flex items-center justify-center space-x-2"
321318
disabled={isLeavingRoom}

0 commit comments

Comments
 (0)