Skip to content

Commit

Permalink
Merge pull request #126 from zhumeisongsong/feature/refactor-auth-module
Browse files Browse the repository at this point in the history
refactor: ♻️ auth module
  • Loading branch information
zhumeisongsong authored Dec 17, 2024
2 parents 08948f7 + da14c23 commit 667b33f
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 130 deletions.
2 changes: 1 addition & 1 deletion libs/auth/application/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './lib/auth.service';
export * from './lib/use-cases/sign-in.use-case';
64 changes: 0 additions & 64 deletions libs/auth/application/src/lib/auth.service.spec.ts

This file was deleted.

70 changes: 70 additions & 0 deletions libs/auth/application/src/lib/use-cases/sign-in.use-case.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Test } from '@nestjs/testing';
import { JwtService } from '@nestjs/jwt';
import { UnauthorizedException } from '@nestjs/common';
import { AwsCognitoService } from '@shared/infrastructure-aws-cognito';
import { SignInUseCase } from './sign-in.use-case';

describe('SignInUseCase', () => {
let signInUseCase: SignInUseCase;
let awsCognitoService: AwsCognitoService;
let jwtService: JwtService;

beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [
SignInUseCase,
{
provide: AwsCognitoService,
useValue: {
signIn: jest.fn(),
},
},
{
provide: JwtService,
useValue: {
signAsync: jest.fn(),
},
},
],
}).compile();

signInUseCase = moduleRef.get<SignInUseCase>(SignInUseCase);
awsCognitoService = moduleRef.get<AwsCognitoService>(AwsCognitoService);
jwtService = moduleRef.get<JwtService>(JwtService);
});

describe('execute', () => {
const email = '[email protected]';
const password = 'password123';
const mockAccessToken = 'mock.access.token';

it('should successfully sign in and return access token', async () => {
jest.spyOn(awsCognitoService, 'signIn').mockResolvedValue(undefined);
jest.spyOn(jwtService, 'signAsync').mockResolvedValue(mockAccessToken);

const result = await signInUseCase.execute(email, password);

expect(awsCognitoService.signIn).toHaveBeenCalledWith(email, password);
expect(jwtService.signAsync).toHaveBeenCalledWith({ email });
expect(result).toEqual({ accessToken: mockAccessToken });
});

it('should throw UnauthorizedException when AWS Cognito sign in fails', async () => {
const error = new Error('Invalid credentials');
jest.spyOn(awsCognitoService, 'signIn').mockRejectedValue(error);

await expect(signInUseCase.execute(email, password)).rejects.toThrow(
UnauthorizedException,
);
});

it('should throw UnauthorizedException when JWT signing fails', async () => {
jest.spyOn(awsCognitoService, 'signIn').mockResolvedValue(undefined);
jest.spyOn(jwtService, 'signAsync').mockRejectedValue(new Error());

await expect(signInUseCase.execute(email, password)).rejects.toThrow(
UnauthorizedException,
);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import { Injectable, Logger, UnauthorizedException } from '@nestjs/common';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { AwsCognitoService } from '@shared/infrastructure-aws-cognito';

// Implement the authentication logic
@Injectable()
export class AuthService {
private readonly logger = new Logger(AuthService.name);
export class SignInUseCase {
constructor(
private awsCognitoService: AwsCognitoService,
private jwtService: JwtService,
) {}

// Retrieving a user and verifying the password
async signIn(
async execute(
email: string,
pass: string,
): Promise<{
accessToken: string;
}> {
// try {
// await this.awsCognitoService.signIn(email, pass);
// } catch (error) {
// this.logger.error('SignIn error:', error);
// throw new UnauthorizedException(error); // TODO: return error code
// }
try {
await this.awsCognitoService.signIn(email, pass);
} catch (error) {
throw new UnauthorizedException(error); // TODO: return error code
}

try {
const accessToken = await this.jwtService.signAsync({
Expand All @@ -35,7 +32,6 @@ export class AuthService {
accessToken,
};
} catch (error) {
this.logger.error('SignIn error:', error);
throw new UnauthorizedException('Invalid credentials'); // TODO: return error code
}
}
Expand Down
6 changes: 3 additions & 3 deletions libs/auth/interface-adapters/src/lib/auth.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AuthService } from '@auth/application';
import { SignInUseCase } from '@auth/application';
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
Expand All @@ -7,7 +7,7 @@ import { AwsCognitoService } from '@shared/infrastructure-aws-cognito';
import { AuthResolver } from './resolver/auth.resolver';

@Module({
providers: [AuthResolver, AuthService, AwsCognitoService],
providers: [AuthResolver, SignInUseCase, AwsCognitoService],
imports: [
JwtModule.registerAsync({
imports: [ConfigModule],
Expand All @@ -22,6 +22,6 @@ import { AuthResolver } from './resolver/auth.resolver';
},
}),
],
exports: [AuthService],
exports: [],
})
export class AuthModule {}
61 changes: 41 additions & 20 deletions libs/auth/interface-adapters/src/lib/resolver/auth.resolver.spec.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,71 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from '@auth/application';
import { SignInUseCase } from '@auth/application';
import { UnauthorizedException } from '@nestjs/common';

import { AuthResolver } from './auth.resolver';
import { SignInInputDto } from '../dto/sign-in-input.dto';

describe('AuthResolver', () => {
let resolver: AuthResolver;
let authService: AuthService;
let signInUseCase: SignInUseCase;

const mockSignInUseCase = {
execute: jest.fn(),
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
AuthResolver,
{
provide: AuthService,
useValue: {
signIn: jest.fn(),
},
provide: SignInUseCase,
useValue: mockSignInUseCase,
},
],
}).compile();

resolver = module.get<AuthResolver>(AuthResolver);
authService = module.get<AuthService>(AuthService);
signInUseCase = module.get<SignInUseCase>(SignInUseCase);
});

it('should be defined', () => {
expect(resolver).toBeDefined();
afterEach(() => {
jest.clearAllMocks();
});

describe('signIn', () => {
it('should call authService.signIn with correct parameters', async () => {
const signInInput: SignInInputDto = {
email: '[email protected]',
password: 'password123',
};
const expectedResult = { accessToken: 'testToken' };

jest.spyOn(authService, 'signIn').mockResolvedValue(expectedResult);
const signInInput: SignInInputDto = {
email: '[email protected]',
password: 'password123',
};

const mockResponse = {
accessToken: 'mock-access-token',
};

it('should successfully sign in a user', async () => {
mockSignInUseCase.execute.mockResolvedValue(mockResponse);

const result = await resolver.signIn(signInInput);

expect(authService.signIn).toHaveBeenCalledWith(
expect(result).toEqual(mockResponse);
expect(signInUseCase.execute).toHaveBeenCalledWith(
signInInput.email,
signInInput.password,
);
});

it('should throw UnauthorizedException when sign in fails', async () => {
mockSignInUseCase.execute.mockRejectedValue(
new UnauthorizedException('Invalid credentials'),
);

await expect(resolver.signIn(signInInput)).rejects.toThrow(
UnauthorizedException,
);
expect(signInUseCase.execute).toHaveBeenCalledWith(
signInInput.email,
signInInput.password
signInInput.password,
);
expect(result).toEqual(expectedResult);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AuthService } from '@auth/application';
import { SignInUseCase } from '@auth/application';
import { Resolver, Mutation, Args, Field, ObjectType } from '@nestjs/graphql';

import { SignInInputDto } from '../dto/sign-in-input.dto';
Expand All @@ -12,13 +12,13 @@ export class Response {
// Expose the authentication endpoints
@Resolver()
export class AuthResolver {
constructor(private authService: AuthService) {}
constructor(private signInUseCase: SignInUseCase) {}

@Mutation(() => Response)
async signIn(
@Args({ name: 'signInInput', type: () => SignInInputDto })
signInInput: SignInInputDto,
): Promise<Response> {
return this.authService.signIn(signInInput.email, signInInput.password);
return this.signInUseCase.execute(signInInput.email, signInInput.password);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Injectable, Logger } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { awsConfig } from '@shared/config';
import * as AWS from 'aws-sdk';

@Injectable()
export class AwsCognitoService {
private readonly logger = new Logger(AwsCognitoService.name);
// private readonly configService: ConfigService;
private cognito: AWS.CognitoIdentityServiceProvider;

Expand Down Expand Up @@ -35,12 +33,7 @@ export class AwsCognitoService {
],
};

try {
return await this.cognito.signUp(params).promise();
} catch (error) {
this.logger.error('signUp', error);
throw error;
}
return await this.cognito.signUp(params).promise();
}

async signIn(
Expand All @@ -57,12 +50,7 @@ export class AwsCognitoService {
},
};

try {
return await this.cognito.initiateAuth(params).promise();
} catch (error) {
this.logger.error('signIn', error);
throw error;
}
return await this.cognito.initiateAuth(params).promise();
}

async refreshToken(
Expand All @@ -77,12 +65,7 @@ export class AwsCognitoService {
},
};

try {
return await this.cognito.initiateAuth(params).promise();
} catch (error) {
this.logger.error('refreshToken', error);
throw error;
}
return await this.cognito.initiateAuth(params).promise();
}

async confirmSignUp(email: string, confirmationCode: string): Promise<void> {
Expand All @@ -93,11 +76,6 @@ export class AwsCognitoService {
ConfirmationCode: confirmationCode,
};

try {
await this.cognito.confirmSignUp(params).promise();
} catch (error) {
this.logger.error('confirmSignUp', error);
throw error;
}
await this.cognito.confirmSignUp(params).promise();
}
}

0 comments on commit 667b33f

Please sign in to comment.