From 549e53901e33503d787cbfb4e36b1bd28aa505e6 Mon Sep 17 00:00:00 2001 From: Siddharth9890 Date: Wed, 8 May 2024 15:28:00 +0530 Subject: [PATCH] feat(user): finished user class methods and tests --- __mocks__/v3/user.mock.ts | 28 +++++++++ scripts/compress.js | 17 +++++- scripts/compress.sh | 4 +- src/GatewayV3.ts | 3 + src/v3/auth/auth.ts | 24 +++++++- src/v3/pda/pda.ts | 23 ++++++-- src/v3/user/user.ts | 117 +++++++++++++++++++++++++++++++++++++ test/stubs/v3/user.stub.ts | 43 ++++++++++++++ test/v3/auth.test.ts | 3 +- test/v3/pda.test.ts | 6 +- test/v3/user.test.ts | 103 ++++++++++++++++++++++++++++++++ tsconfig.json | 7 +-- 12 files changed, 352 insertions(+), 26 deletions(-) create mode 100644 __mocks__/v3/user.mock.ts create mode 100644 src/v3/user/user.ts create mode 100644 test/stubs/v3/user.stub.ts create mode 100644 test/v3/user.test.ts diff --git a/__mocks__/v3/user.mock.ts b/__mocks__/v3/user.mock.ts new file mode 100644 index 0000000..9315e7c --- /dev/null +++ b/__mocks__/v3/user.mock.ts @@ -0,0 +1,28 @@ +import { User } from '../../src/v3/user/user'; +import { activitiesStub, userStub } from '../../test/stubs/v3/user.stub'; + +export const UserMockService = (user: User) => ({ + meMock: jest.spyOn(user.sdk, 'me_query').mockResolvedValue({ + me: userStub(), + }), + getSingleUserMock: jest.spyOn(user.sdk, 'user_query').mockResolvedValue({ + user: userStub(), + }), + myPDACountMock: jest.spyOn(user.sdk, 'myPDACount_query').mockResolvedValue({ + myPDACount: 10, + }), + myPDAsMock: jest.spyOn(user.sdk, 'myPDAs_query').mockResolvedValue({ + myPDAs: userStub().issuedPDAs, + }), + myDataModelsCountMock: jest + .spyOn(user.sdk, 'dataModelsCount_query') + .mockResolvedValue({ + dataModelsCount: 10, + }), + myActivitiesCountMock: jest + .spyOn(user.sdk, 'myActivitiesCount_query') + .mockResolvedValue({ myActivitiesCount: 10 }), + myActivitiesMock: jest + .spyOn(user.sdk, 'myActivities_query') + .mockResolvedValue({ myActivities: activitiesStub() }), +}); diff --git a/scripts/compress.js b/scripts/compress.js index 62ad4af..fbd817b 100644 --- a/scripts/compress.js +++ b/scripts/compress.js @@ -26,10 +26,21 @@ function processFile(inputFile, outputFile) { } const filesToProcess = [ - { input: 'dist/gatewaySdk/index.d.ts', output: 'dist/gatewaySdk/index.d.ts' }, { - input: 'dist/gatewaySdk/sources/GatewaySDK/types.d.ts', - output: 'dist/gatewaySdk/sources/GatewaySDK/types.d.ts', + input: 'dist/gatewaySdk/sources/GatewayV2/index.d.ts', + output: 'dist/gatewaySdk/sources/GatewayV2/index.d.ts', + }, + { + input: 'dist/gatewaySdk/sources/GatewayV2/types.d.ts', + output: 'dist/gatewaySdk/sources/GatewayV2/types.d.ts', + }, + { + input: 'dist/gatewaySdk/sources/GatewayV3/index.d.ts', + output: 'dist/gatewaySdk/sources/GatewayV3/index.d.ts', + }, + { + input: 'dist/gatewaySdk/sources/GatewayV3/types.d.ts', + output: 'dist/gatewaySdk/sources/GatewayV3/types.d.ts', }, ]; diff --git a/scripts/compress.sh b/scripts/compress.sh index d578ce9..ec8cb0e 100755 --- a/scripts/compress.sh +++ b/scripts/compress.sh @@ -1,8 +1,6 @@ #!/bin/sh - - -files="dist/gatewaySdk/index.js dist/src/auth/auth.js dist/src/data-model/data-model.js dist/src/dataRequestsTemplate/dataRequestsTemplate.js dist/src/organization/organization.js dist/src/pda/pda.js dist/src/proof/proof.js dist/src/request/request.js dist/src/user/user.js" +files="dist/gatewaySdk/sources/*.js dist/gatewaySdk/src/*.js" for file in $files; do uglifyjs "$file" -o "$file" diff --git a/src/GatewayV3.ts b/src/GatewayV3.ts index 20c9262..227ed84 100644 --- a/src/GatewayV3.ts +++ b/src/GatewayV3.ts @@ -5,9 +5,11 @@ import { clientTimingWrapper, parameterChecker, } from './utils/helper'; +import { PDA } from './v3/pda/pda'; export class GatewayV3 { private sdk: Sdk; + private pda: PDA; constructor({ apiKey, @@ -29,5 +31,6 @@ export class GatewayV3 { }); this.sdk = getSdk(client, logging ? clientTimingWrapper : undefined); + this.pda = new PDA(this.sdk); } } diff --git a/src/v3/auth/auth.ts b/src/v3/auth/auth.ts index 62fb4fb..f2fcf98 100644 --- a/src/v3/auth/auth.ts +++ b/src/v3/auth/auth.ts @@ -83,7 +83,13 @@ export class Auth { signingCipher?: SignCipherEnum; }) { try { - isWalletAddressValid(signingKey, Chain.EVM); + let chain: Chain; + if (signingCipher === undefined) { + chain = Chain.EVM; + } else if (signingCipher === SignCipherEnum.ED25519) { + chain = Chain.SOL; + } else chain = Chain.EVM; + isWalletAddressValid(signingKey, chain); isStringValid(signature); return ( await this.sdk.createUser_mutation({ @@ -105,7 +111,13 @@ export class Auth { */ async generateNonce(wallet: string, cipher?: SignCipherEnum) { try { - isWalletAddressValid(wallet, Chain.EVM); + let chain: Chain; + if (cipher === undefined) { + chain = Chain.EVM; + } else if (cipher === SignCipherEnum.ED25519) { + chain = Chain.SOL; + } else chain = Chain.EVM; + isWalletAddressValid(wallet, chain); return await this.sdk.generateNonce_mutation({ input: { wallet, cipher }, }); @@ -121,7 +133,13 @@ export class Auth { */ async refreshToken(input: SignedWalletNonceInput) { try { - isWalletAddressValid(input.signingKey, Chain.EVM); + let chain: Chain; + if (input.cipher === undefined) { + chain = Chain.EVM; + } else if (input.cipher === SignCipherEnum.ED25519) { + chain = Chain.SOL; + } else chain = Chain.EVM; + isWalletAddressValid(input.signingKey, chain); isStringValid(input.signature); return (await this.sdk.refreshToken_mutation({ input })).refreshToken; } catch (error) { diff --git a/src/v3/pda/pda.ts b/src/v3/pda/pda.ts index 229f290..fbf1c61 100644 --- a/src/v3/pda/pda.ts +++ b/src/v3/pda/pda.ts @@ -8,7 +8,7 @@ import { Sdk, UpdatePDAInput, } from '../../../gatewaySdk/sources/GatewayV3'; -import { Chain } from '../../types'; +import { Chain, SignCipherEnum } from '../../types'; import { errorHandler } from '../../utils/errorHandler'; import { isUUIDValid, @@ -16,9 +16,8 @@ import { validateObjectProperties, } from '../../utils/validators'; -// ask about helper functions like json encoder -// about validating singature -// about wallet type +// secp256k1=evm by default +// Ed25519=solana export class PDA { public sdk: Sdk; @@ -111,8 +110,14 @@ export class PDA { */ async changePDAStatus(input: UpdatePDAStatusInput) { try { + let chain: Chain; + if (input.signingCipher === undefined) { + chain = Chain.EVM; + } else if (input.signingCipher === SignCipherEnum.ED25519) { + chain = Chain.SOL; + } else chain = Chain.EVM; validateObjectProperties(input.data); - isWalletAddressValid(input.signingKey, Chain.EVM); + isWalletAddressValid(input.signingKey, chain); return await this.sdk.changePDAStatus_mutation({ input }); } catch (error) { throw new Error(errorHandler(error)); @@ -127,8 +132,14 @@ export class PDA { */ async createPDA(pdaInput: CreatePDAInput) { try { + let chain: Chain; + if (pdaInput.signingCipher === undefined) { + chain = Chain.EVM; + } else if (pdaInput.signingCipher === SignCipherEnum.ED25519) { + chain = Chain.SOL; + } else chain = Chain.EVM; validateObjectProperties(pdaInput.data); - isWalletAddressValid(pdaInput.signingKey, Chain.EVM); + isWalletAddressValid(pdaInput.signingKey, chain); return await this.sdk.createPDA_mutation({ input: pdaInput }); } catch (error) { throw new Error(errorHandler(error)); diff --git a/src/v3/user/user.ts b/src/v3/user/user.ts new file mode 100644 index 0000000..b2cca65 --- /dev/null +++ b/src/v3/user/user.ts @@ -0,0 +1,117 @@ +import { UserIdentifierTypeV3 } from '../../types'; +import { errorHandler } from '../../utils/errorHandler'; +import { isStringValid } from '../../utils/validators'; +import { + FilterDataModelInput, + myActivities_queryQueryVariables, + myActivitiesCount_queryQueryVariables, + myPDACount_queryQueryVariables, + myPDAs_queryQueryVariables, + Sdk, +} from '../../../gatewaySdk/sources/GatewayV3'; + +export class User { + public sdk: Sdk; + + constructor(sdk: Sdk) { + this.sdk = sdk; + } + + /** + * The function `me` makes an asynchronous call to `me_query` and returns the result, or throws an + * error if something goes wrong. + * @returns a Promise that resolves to me. + */ + async me() { + try { + return await this.sdk.me_query(); + } catch (error) { + throw new Error(errorHandler(error)); + } + } + + /** + * The function takes a user identifier type and value as input, queries the user using the SDK, and + * returns the result. + * @param - - `type`: The type of user identifier. It can be one of the following values: + * @returns The `user` function is returning the result of the `user_query` method call from the `sdk` + * object. + */ + async getSingleUser({ + type, + value, + }: { + type: UserIdentifierTypeV3; + value: string; + }) { + try { + isStringValid(value); + return await this.sdk.user_query({ input: { type, value } }); + } catch (error) { + throw new Error(errorHandler(error)); + } + } + + /** + * The function `myPDACount` is an asynchronous function that returns the count of a user's PDA + * based on an optional filter. + * @param {FilterPDAInput} [filter] - The `filter` parameter is an optional input that allows you to + * specify criteria for filtering the PDAs before counting them. It is + * of type `FilterPDAInput`. + * @returns a Promise that resolves to a number. + */ + async myPDACount(filter?: myPDACount_queryQueryVariables) { + try { + return (await this.sdk.myPDACount_query(filter)).myPDACount; + } catch (error) { + throw new Error(errorHandler(error)); + } + } + + /** + * The function `myPDAs` is an asynchronous function that takes in a `myPDAs_queryQueryVariables` object and returns a + * promise that resolves to a `myPDAs_queryQuery` object. + * @param {myPDAs_queryQueryVariables} - - `filter`: An object that contains filter criteria for the query. + * @returns a Promise that resolves to a value of type `myPDAs_queryQuery`. + */ + async myPDAs(variables?: myPDAs_queryQueryVariables) { + try { + return await this.sdk.myPDAs_query(variables); + } catch (error) { + throw new Error(errorHandler(error)); + } + } + + /** + * The function `myDataModelsCount` is an asynchronous function that retrieves the count of data + * models based on an optional filter and returns the count. + * @param {FilterDataModelInput} [filter] - The `filter` parameter is an optional input that allows + * you to specify conditions to filter the data models. It is of type `FilterDataModelInput`. You can + * use this parameter to define criteria such as filtering by a specific field value or applying + * logical operators like AND and OR to combine multiple conditions. + * @returns the count of data models that match the provided filter. + */ + async myDataModelsCount(filter?: FilterDataModelInput) { + try { + return (await this.sdk.dataModelsCount_query({ filter })).dataModelsCount; + } catch (error) { + throw new Error(errorHandler(error)); + } + } + + async myActivities(filter?: myActivities_queryQueryVariables) { + try { + return await this.sdk.myActivities_query(filter); + } catch (error) { + throw new Error(errorHandler(error)); + } + } + + async myActivitiesCount(filter?: myActivitiesCount_queryQueryVariables) { + try { + return (await this.sdk.myActivitiesCount_query(filter)).myActivitiesCount; + } catch (error) { + throw new Error(errorHandler(error)); + } + } +} diff --git a/test/stubs/v3/user.stub.ts b/test/stubs/v3/user.stub.ts new file mode 100644 index 0000000..5d06280 --- /dev/null +++ b/test/stubs/v3/user.stub.ts @@ -0,0 +1,43 @@ +import { Activity, User } from '../../../gatewaySdk/sources/GatewayV3'; + +export const userStub = (overrideUser?: Partial): User => ({ + id: 'f47ac10b-58cc-4372-a567-0e02b2c3d479', + createdAt: new Date('2021-01-01T12:00:00Z'), + updatedAt: new Date('2021-01-01T12:00:00Z'), + username: 'test01', + isCompleted: true, + issuedPDAs: [], + receivedPDAs: [], + receivedProofs: [], + recipientDataRequests: [], + verifierDataRequests: [], + roles: [], + did: 'did:gatewayid:abc123', + encryptionKey: '', + usernameLastUpdated: new Date('2021-01-01T12:00:00Z'), + ...overrideUser, +}); + +export const activitiesStub = (): Activity[] => { + return [ + { + action: 'PDA_ISSUANCE', + createdAt: '2024-01-09T13:09:29.020Z', + id: '659d4589abb2c024ff2ef8e5', + updatedAt: '2024-01-09T13:09:29.020Z', + metadata: { + creator: '', + dataModel: '', + issuer: '', + dataModels: [''], + organization: '', + owner: '', + pda: '', + proof: '', + requestTemplate: '', + signedBy: '', + status: '', + }, + }, + ]; +}; diff --git a/test/v3/auth.test.ts b/test/v3/auth.test.ts index d2ef0e6..aeb02cc 100644 --- a/test/v3/auth.test.ts +++ b/test/v3/auth.test.ts @@ -1,10 +1,9 @@ import { GraphQLClient } from 'graphql-request'; import { getSdk } from '../../gatewaySdk/sources/GatewayV3'; -import { Auth } from '../../src/v3/auth/auth'; import { AuthMockService } from '../../__mocks__/v3/auth.mock'; import { authStub } from '../stubs/v3/auth.stub'; -import { SignCipherEnum } from '../../src/types'; +import { Auth } from '../../src/v3/auth/auth'; let auth: Auth; diff --git a/test/v3/pda.test.ts b/test/v3/pda.test.ts index 0f18b89..d668130 100644 --- a/test/v3/pda.test.ts +++ b/test/v3/pda.test.ts @@ -5,6 +5,7 @@ import { PDA } from '../../src/v3/pda/pda'; import { getSdk } from '../../gatewaySdk/sources/GatewayV3'; import { pdaBodyData, pdaCreateStub, pdaStub } from '../stubs/v3/pda.stub'; import { PDAMockService } from '../../__mocks__/v3/pda.mock'; +import { authStub } from '../stubs/v3/auth.stub'; let pda: PDA; @@ -134,9 +135,8 @@ describe('PDA SERVICE TESTING', () => { const { updatePDA } = await pda.updatePDA({ data: pdaBodyData({ id: pdaStub().id }), - did: 'did:gatewayid:abc123', - signature: - '0x9ddccd4e4f97187334ec2ed980906c7adad096bd892a393243158c3acb6cf6d1', + did: authStub().did, + signature: authStub().signature, }); expect(updatePDA.id).toBe(pdaStub().id); diff --git a/test/v3/user.test.ts b/test/v3/user.test.ts new file mode 100644 index 0000000..1120e4e --- /dev/null +++ b/test/v3/user.test.ts @@ -0,0 +1,103 @@ +import { GraphQLClient } from 'graphql-request'; +import { getSdk } from '../../gatewaySdk/sources/GatewayV3'; +import { User } from '../../src/v3/user/user'; +import { userStub } from '../stubs/v3/user.stub'; +import { UserMockService } from '../../__mocks__/v3/user.mock'; +import { UserIdentifierType, UserIdentifierTypeV3 } from '../../src/types'; + +let user: User; + +beforeAll(() => { + user = new User(getSdk(new GraphQLClient(''))); +}); + +afterAll(() => { + jest.clearAllMocks(); +}); + +describe('USER SERVICE TESTING', () => { + it('me', async () => { + const { meMock } = UserMockService(user); + + const { me } = await user.me(); + + expect(me.did).toEqual(userStub().did); + + expect(meMock).toHaveBeenCalled(); + }); + + it('single user', async () => { + const { getSingleUserMock } = UserMockService(user); + + const res = await user.getSingleUser({ + type: UserIdentifierTypeV3.USER_ID, + value: userStub().id, + }); + + expect(res.user?.did).toEqual(userStub().did); + + expect(getSingleUserMock).toHaveBeenCalled(); + }); + + it('single user to throw error', async () => { + const { getSingleUserMock } = UserMockService(user); + + expect( + async () => + await user.getSingleUser({ + type: UserIdentifierTypeV3.USER_DID, + value: userStub({ did: '' }).did, + }), + ).rejects.toThrow(''); + + expect(getSingleUserMock).toHaveBeenCalled(); + }); + + it('my pdas count', async () => { + const { myPDACountMock } = UserMockService(user); + + const count = await user.myPDACount(); + + expect(count).toBeGreaterThanOrEqual(0); + expect(myPDACountMock).toHaveBeenCalled(); + }); + + it('my pdas', async () => { + const { myPDAsMock } = UserMockService(user); + + const { myPDAs } = await user.myPDAs({ + skip: 0, + take: 10, + }); + + expect(myPDAs.length).toBeGreaterThanOrEqual(0); + expect(myPDAsMock).toHaveBeenCalled(); + }); + + it('my data models count', async () => { + const { myDataModelsCountMock } = UserMockService(user); + + const count = await user.myDataModelsCount(); + + expect(count).toBeGreaterThanOrEqual(0); + expect(myDataModelsCountMock).toHaveBeenCalled(); + }); + + it('my activities count', async () => { + const { myActivitiesCountMock } = UserMockService(user); + + const count = await user.myActivitiesCount(); + + expect(count).toBeGreaterThanOrEqual(0); + expect(myActivitiesCountMock).toHaveBeenCalled(); + }); + + it('my activities', async () => { + const { myActivitiesMock } = UserMockService(user); + + const { myActivities } = await user.myActivities(); + + expect(myActivities.length).toBeGreaterThanOrEqual(0); + expect(myActivitiesMock).toHaveBeenCalled(); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index d2b25f8..2a34ad2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,11 +11,6 @@ "allowJs": true, "typeRoots": ["./typings", "./node_modules/@types/"], "outDir": "./dist/", - "declaration": true, - "paths": { - "@/*": ["./src/*"], - "@gatewaySdk/*": ["./gatewaySdk/sources/*"] - }, - "allowSyntheticDefaultImports": true + "declaration": true, } }