From 4c4e6d26103eee5d34e2d5069824ae9dfd06a4a7 Mon Sep 17 00:00:00 2001 From: manish Date: Wed, 25 Sep 2024 16:54:35 +0530 Subject: [PATCH 1/2] test : account module --- src/modules/account/account.ts | 58 ++++++++++++++++++++++- test/account.test.ts | 87 +++++++++++++++++++++++++++++++++- test/stubs/common.stub.ts | 3 ++ 3 files changed, 146 insertions(+), 2 deletions(-) diff --git a/src/modules/account/account.ts b/src/modules/account/account.ts index 660c635..fe3d112 100644 --- a/src/modules/account/account.ts +++ b/src/modules/account/account.ts @@ -1,13 +1,48 @@ import { MediaType } from 'openapi-typescript-helpers'; -import { OpenAPIClient, MyAccountResponse } from '../../common/types'; +import { + OpenAPIClient, + MyAccountResponse, + AccountCreateRequest, +} from '../../common/types'; import { paths } from '../../api'; import { GTWError } from '../../helpers/custom-error'; +import { CryptoService } from '../../services/crypto-service'; export class Account { private client: OpenAPIClient; + private cryptoService: CryptoService; constructor(client: OpenAPIClient) { this.client = client; + this.cryptoService = new CryptoService(); + } + + /** + * The `createAccount` function in TypeScript asynchronously creates a new account by verifying a + * message, sending a POST request to an endpoint, and returning a token upon success. + * @param {AccountCreateRequest} - The `createAccount` function takes in an `AccountCreateRequest` + * object with the following parameters: + * @returns The `createAccount` function returns a token from the `data` object after successfully + * verifying the message signature and creating an account with the provided username and wallet + * address. + */ + async createAccount({ + message, + signature, + username, + wallet_address, + }: AccountCreateRequest) { + await this.cryptoService.verifyMessage(signature, message, wallet_address); + + const { data, error, response } = await this.client.POST('/accounts', { + body: { message, signature, username, wallet_address }, + }); + + if (error) { + throw new GTWError(error, response); + } + + return data.token; } /** @@ -26,4 +61,25 @@ export class Account { return data; } + + /** + * The function `updateAccount` asynchronously updates the profile picture and username of the current + * account using a PATCH request. + * @param - The `updateAccount` function takes in an object with two properties: `profile_picture` and + * `username`, both of type string. These values are used to update the user's account information by + * making a PATCH request to the `/accounts/me` endpoint with the provided data. If there is an error + * @returns The `updateAccount` function is returning the `data` object after making a PATCH request to + * update the account information (profile picture and username). + */ + async updateAccount(profile_picture?: string, username?: string) { + const { data, error, response } = await this.client.PATCH('/accounts/me', { + body: { profile_picture, username }, + }); + + if (error) { + throw new GTWError(error, response); + } + + return data; + } } diff --git a/test/account.test.ts b/test/account.test.ts index d9d43f3..c575507 100644 --- a/test/account.test.ts +++ b/test/account.test.ts @@ -4,7 +4,15 @@ import { paths } from '../src/api'; import { GTWError } from '../src/helpers/custom-error'; import { Account } from '../src/modules/account/account'; import { MediaType } from 'openapi-typescript-helpers'; -import { mockClient, mockGet } from './stubs/common.stub'; +import { + authDetails, + errorMessage, + mockClient, + mockGet, + mockPatch, + mockPost, + successMessage, +} from './stubs/common.stub'; import { routes } from '../src/common/routes'; describe('Account', () => { @@ -16,6 +24,32 @@ describe('Account', () => { ); }); + describe('create Account ', () => { + it('should return with new account with given credentials', async () => { + mockPost.mockResolvedValue(successMessage({ data: { token: 'test' } })); + + const result = await account.createAccount( + authDetails({ username: 'testuser' }), + ); + + expect(result).toBeDefined(); + expect(mockPost).toHaveBeenCalledWith(routes.CreateAccount, { + body: authDetails({ username: 'testuser' }), + }); + }); + + it('should return error when creating account', async () => { + mockPost.mockResolvedValue(errorMessage()); + + await expect( + account.createAccount(authDetails({ username: 'testuser' })), + ).rejects.toThrow(GTWError); + expect(mockPost).toHaveBeenCalledWith(routes.CreateAccount, { + body: authDetails({ username: 'testuser' }), + }); + }); + }); + describe('getAccountInfo', () => { it('should return account info when API call is successful', async () => { const mockData: MyAccountResponse = { did: '123', username: 'Test User' }; @@ -44,4 +78,55 @@ describe('Account', () => { expect(mockClient.GET).toHaveBeenCalledWith(routes.GetMyAccount); }); }); + + describe('update Account', () => { + it('should return account with updated attributes', async () => { + const mockData = { + created_at: '2024-09-25T12:34:56Z', + did: 'did:example:123456789abcdefghi', + profile_picture: 'https://example.com/profile-picture.png', + storage_size: 1024, + updated_at: '2024-09-25T13:34:56Z', + username: 'new_username', + username_updated_at: '2024-09-25T12:35:56Z', + wallet_address: '0x123456789abcdefghi', + }; + + mockPatch.mockResolvedValue({ + data: mockData, + response: {}, + error: null, + }); + + const result = await account.updateAccount( + 'https://example.com/profile-picture.png', + ); + + expect(result).toEqual(mockData); + expect(mockClient.PATCH).toHaveBeenCalledWith(routes.UpdateAccount, { + body: { + profile_picture: 'https://example.com/profile-picture.png', + username: undefined, + }, + }); + }); + + it('should throw GTWError when API call fails', async () => { + const mockResponse = { status: 401 } as Response; + + mockPatch.mockResolvedValue({ + data: null, + response: mockResponse, + error: { error: 'Unauthorized' }, + }); + + await expect(account.updateAccount()).rejects.toThrow(GTWError); + expect(mockClient.PATCH).toHaveBeenCalledWith(routes.UpdateAccount, { + body: { + profile_picture: 'https://example.com/profile-picture.png', + username: undefined, + }, + }); + }); + }); }); diff --git a/test/stubs/common.stub.ts b/test/stubs/common.stub.ts index 48b8244..e155110 100644 --- a/test/stubs/common.stub.ts +++ b/test/stubs/common.stub.ts @@ -62,11 +62,13 @@ export const linksStub = (overrideLinkStub?: HelperLinks) => ({ export let mockGet: jest.Mock; export let mockPost: jest.Mock; +export let mockPatch: jest.Mock; export let mockPut: jest.Mock; export let mockDelete: jest.Mock; mockGet = jest.fn(); mockPost = jest.fn(); +mockPatch = jest.fn(); mockPut = jest.fn(); mockDelete = jest.fn(); @@ -74,5 +76,6 @@ export let mockClient: OpenAPIClient = { GET: mockGet, POST: mockPost, PUT: mockPut, + PATCH: mockPatch, DELETE: mockDelete, } as any as OpenAPIClient; From 76289e88c34241a5f14a04995d635ddb2300fe6c Mon Sep 17 00:00:00 2001 From: manish Date: Wed, 25 Sep 2024 17:04:21 +0530 Subject: [PATCH 2/2] fix: typescript issue --- test/account.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/account.test.ts b/test/account.test.ts index c575507..89eefa0 100644 --- a/test/account.test.ts +++ b/test/account.test.ts @@ -52,7 +52,10 @@ describe('Account', () => { describe('getAccountInfo', () => { it('should return account info when API call is successful', async () => { - const mockData: MyAccountResponse = { did: '123', username: 'Test User' }; + const mockData = { + did: '123', + username: 'Test User', + } as MyAccountResponse; mockGet.mockResolvedValue({ data: mockData, response: {},