Skip to content

Commit 26b9d2f

Browse files
committed
fix unti tests
1 parent de08345 commit 26b9d2f

File tree

3 files changed

+83
-73
lines changed

3 files changed

+83
-73
lines changed

src/sso/saml/controller.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,13 @@ export default class SamlController {
413413
* @param args - arguments to log
414414
*/
415415
private log(level: 'log' | 'warn' | 'error' | 'info' | 'success', ...args: unknown[]): void {
416+
/**
417+
* Disable logging in test environment
418+
*/
419+
if (process.env.NODE_ENV === 'test') {
420+
return;
421+
}
422+
416423
const colors = {
417424
log: Effect.ForegroundGreen,
418425
warn: Effect.ForegroundYellow,

test/sso/saml/controller.test.ts

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,16 @@ import { ContextFactories } from '../../../src/types/graphql';
66
import { WorkspaceSsoConfig } from '../../../src/sso/types';
77
import { WorkspaceDBScheme, UserDBScheme } from '@hawk.so/types';
88
import SamlService from '../../../src/sso/saml/service';
9-
import samlStore from '../../../src/sso/saml/store';
9+
import { MemorySamlStateStore } from '../../../src/sso/saml/store/memory.store';
1010
import * as mongo from '../../../src/mongo';
11+
import WorkspaceModel from '../../../src/models/workspace';
12+
import UserModel from '../../../src/models/user';
1113

1214
/**
1315
* Mock dependencies
1416
*/
1517
jest.mock('../../../src/sso/saml/service');
1618

17-
/**
18-
* Import models AFTER mongo setup to ensure databases.hawk is initialized
19-
* This must be done after beforeAll sets up connections
20-
*/
21-
import WorkspaceModel from '../../../src/models/workspace';
22-
import UserModel from '../../../src/models/user';
23-
2419
beforeAll(async () => {
2520
/**
2621
* Ensure MONGO_HAWK_DB_URL is set from MONGO_URL (set by @shelf/jest-mongodb)
@@ -55,6 +50,7 @@ describe('SamlController', () => {
5550
let mockSamlService: jest.Mocked<SamlService>;
5651
let mockReq: Partial<Request>;
5752
let mockRes: Partial<Response>;
53+
let samlStore: MemorySamlStateStore;
5854

5955
const testWorkspaceId = new ObjectId().toString();
6056
const testUserId = new ObjectId().toString();
@@ -140,6 +136,11 @@ describe('SamlController', () => {
140136
* Clear all mocks
141137
*/
142138
jest.clearAllMocks();
139+
140+
/**
141+
* Create fresh store instance for each test
142+
*/
143+
samlStore = new MemorySamlStateStore();
143144
samlStore.clear();
144145

145146
/**
@@ -182,9 +183,9 @@ describe('SamlController', () => {
182183
(SamlService as jest.Mock).mockImplementation(() => mockSamlService);
183184

184185
/**
185-
* Create controller
186+
* Create controller with store
186187
*/
187-
controller = new SamlController(mockFactories);
188+
controller = new SamlController(mockFactories, samlStore);
188189

189190
/**
190191
* Mock Express Request
@@ -264,7 +265,7 @@ describe('SamlController', () => {
264265
/**
265266
* Verify AuthnRequest ID was saved by checking it can be validated
266267
*/
267-
expect(samlStore.validateAndConsumeAuthnRequest(mockRequestId, testWorkspaceId)).toBe(true);
268+
expect(await samlStore.validateAndConsumeAuthnRequest(mockRequestId, testWorkspaceId)).toBe(true);
268269
});
269270

270271
it('should use default returnUrl when not provided', async () => {
@@ -292,7 +293,7 @@ describe('SamlController', () => {
292293
* Verify that default returnUrl was saved in RelayState
293294
* Default returnUrl is `/workspace/${workspaceId}`
294295
*/
295-
const relayState = samlStore.getRelayState(relayStateId!);
296+
const relayState = await samlStore.getRelayState(relayStateId!);
296297
expect(relayState).not.toBeNull();
297298
expect(relayState?.returnUrl).toBe(`/workspace/${testWorkspaceId}`);
298299
expect(relayState?.workspaceId).toBe(testWorkspaceId);
@@ -370,7 +371,7 @@ describe('SamlController', () => {
370371
* Setup test data
371372
*/
372373
const testReturnUrl = '/workspace/test';
373-
const expectedFrontendUrl = `${process.env.GARAGE_URL}${testReturnUrl}`;
374+
const expectedCallbackPath = `/login/sso/${testWorkspaceId}`;
374375

375376
mockWorkspacesFactory.findById.mockResolvedValue(workspace);
376377
mockUsersFactory.findBySamlIdentity.mockResolvedValue(user);
@@ -379,11 +380,11 @@ describe('SamlController', () => {
379380
/**
380381
* Setup samlStore to return valid state for tests
381382
*/
382-
samlStore.saveRelayState(testRelayStateId, {
383+
await samlStore.saveRelayState(testRelayStateId, {
383384
returnUrl: testReturnUrl,
384385
workspaceId: testWorkspaceId,
385386
});
386-
samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
387+
await samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
387388

388389
await controller.handleAcs(mockReq as Request, mockRes as Response);
389390

@@ -421,16 +422,18 @@ describe('SamlController', () => {
421422
expect(user.generateTokensPair).toHaveBeenCalled();
422423

423424
/**
424-
* Verify redirect to frontend with returnUrl from RelayState
425+
* Verify redirect to Garage SSO callback page with tokens and returnUrl
425426
* GARAGE_URL is set in beforeEach: 'https://garage.example.com'
426427
*/
427428
expect(mockRes.redirect).toHaveBeenCalledWith(
428-
expect.stringContaining(expectedFrontendUrl)
429+
expect.stringContaining(expectedCallbackPath)
429430
);
430431

431432
const redirectUrl = new URL((mockRes.redirect as jest.Mock).mock.calls[0][0]);
433+
expect(redirectUrl.pathname).toBe(expectedCallbackPath);
432434
expect(redirectUrl.searchParams.get('access_token')).toBe('test-access-token');
433435
expect(redirectUrl.searchParams.get('refresh_token')).toBe('test-refresh-token');
436+
expect(redirectUrl.searchParams.get('returnUrl')).toBe(testReturnUrl);
434437
});
435438

436439
it('should return 400 error when workspace is not found', async () => {
@@ -502,11 +505,11 @@ describe('SamlController', () => {
502505
/**
503506
* Setup samlStore with valid state
504507
*/
505-
samlStore.saveRelayState(testRelayStateId, {
508+
await samlStore.saveRelayState(testRelayStateId, {
506509
returnUrl: '/workspace/test',
507510
workspaceId: testWorkspaceId,
508511
});
509-
samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
512+
await samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
510513
(workspace.getMemberInfo as jest.Mock).mockResolvedValue(null);
511514

512515
await controller.handleAcs(mockReq as Request, mockRes as Response);
@@ -546,11 +549,11 @@ describe('SamlController', () => {
546549
/**
547550
* Setup samlStore with valid state
548551
*/
549-
samlStore.saveRelayState(testRelayStateId, {
552+
await samlStore.saveRelayState(testRelayStateId, {
550553
returnUrl: '/workspace/test',
551554
workspaceId: testWorkspaceId,
552555
});
553-
samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
556+
await samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
554557
(workspace.getMemberInfo as jest.Mock).mockResolvedValue(null);
555558

556559
await controller.handleAcs(mockReq as Request, mockRes as Response);
@@ -582,11 +585,11 @@ describe('SamlController', () => {
582585
/**
583586
* Setup samlStore with valid state
584587
*/
585-
samlStore.saveRelayState(testRelayStateId, {
588+
await samlStore.saveRelayState(testRelayStateId, {
586589
returnUrl: '/workspace/test',
587590
workspaceId: testWorkspaceId,
588591
});
589-
samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
592+
await samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
590593
(workspace.getMemberInfo as jest.Mock).mockResolvedValue({
591594
userEmail: testEmail,
592595
});
@@ -621,17 +624,23 @@ describe('SamlController', () => {
621624
/**
622625
* Setup samlStore with AuthnRequest but no RelayState
623626
*/
624-
samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
627+
await samlStore.saveAuthnRequest(testRequestId, testWorkspaceId);
625628

626629
await controller.handleAcs(mockReq as Request, mockRes as Response);
627630

628631
/**
629-
* Verify redirect uses default returnUrl
632+
* Verify redirect to Garage SSO callback page with default returnUrl
630633
*/
634+
const expectedCallbackPath = `/login/sso/${testWorkspaceId}`;
635+
const defaultReturnUrl = `/workspace/${testWorkspaceId}`;
636+
631637
expect(mockRes.redirect).toHaveBeenCalledWith(
632-
expect.stringContaining(`/workspace/${testWorkspaceId}`)
638+
expect.stringContaining(expectedCallbackPath)
633639
);
640+
641+
const redirectUrl = new URL((mockRes.redirect as jest.Mock).mock.calls[0][0]);
642+
expect(redirectUrl.pathname).toBe(expectedCallbackPath);
643+
expect(redirectUrl.searchParams.get('returnUrl')).toBe(defaultReturnUrl);
634644
});
635645
});
636646
});
637-

0 commit comments

Comments
 (0)