From 3142487dd25bf3fb36f0c979fe5232830b60a6a7 Mon Sep 17 00:00:00 2001
From: Berend Sliedrecht <berend@animo.id>
Date: Thu, 18 Jan 2024 15:37:24 +0100
Subject: [PATCH] test(ssi): include unit test for credential functionality

Signed-off-by: Berend Sliedrecht <berend@animo.id>
---
 apps/ssi-abstraction/jest.config.js           |   1 +
 .../anoncredsCredentials.controller.spec.ts   | 138 ++++++++-----
 .../anoncredsCredentials.controller.ts        |  24 +++
 .../test/anoncredsCredentials.e2e-spec.ts     | 191 ++++++++++++++++--
 4 files changed, 282 insertions(+), 72 deletions(-)

diff --git a/apps/ssi-abstraction/jest.config.js b/apps/ssi-abstraction/jest.config.js
index 5ece9fc..b8e668f 100644
--- a/apps/ssi-abstraction/jest.config.js
+++ b/apps/ssi-abstraction/jest.config.js
@@ -17,6 +17,7 @@ export default {
       },
     ],
   },
+  testPathIgnorePatterns: ['<rootDir>/dist'],
   extensionsToTreatAsEsm: ['.ts'],
   moduleNameMapper: {
     // ESM modules require `.js` extension to be specified, but Jest doesn't work with them
diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/__tests__/anoncredsCredentials.controller.spec.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/__tests__/anoncredsCredentials.controller.spec.ts
index 4652f57..89c6c84 100644
--- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/__tests__/anoncredsCredentials.controller.spec.ts
+++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/__tests__/anoncredsCredentials.controller.spec.ts
@@ -24,75 +24,101 @@ describe('AnonCredsCredentialsController', () => {
     credentialsController = moduleRef.get(AnonCredsCredentialsController);
   });
 
-  describe('get all', () => {
-    it('should get all the credential records of the agent', async () => {
-      const result: Array<CredentialExchangeRecord> = [];
-      jest.spyOn(credentialsService, 'getAll').mockResolvedValue(result);
+  it('get all', async () => {
+    const result: Array<CredentialExchangeRecord> = [];
+    jest.spyOn(credentialsService, 'getAll').mockResolvedValue(result);
 
-      const event = await credentialsController.getAll({
-        tenantId: 'some-id',
-      });
+    const event = await credentialsController.getAll({
+      tenantId: 'some-id',
+    });
+
+    expect(event.data).toStrictEqual(result);
+  });
 
-      expect(event.data).toStrictEqual(result);
+  it('get all offers', async () => {
+    const result: Array<CredentialExchangeRecord> = [];
+    jest.spyOn(credentialsService, 'getAllOffers').mockResolvedValue(result);
+
+    const event = await credentialsController.getAllOffers({
+      tenantId: 'some-id',
     });
+
+    expect(event.data).toStrictEqual(result);
   });
 
-  describe('get by id', () => {
-    it('should get a credential record by id', async () => {
-      const result: CredentialExchangeRecord | null = null;
-      jest.spyOn(credentialsService, 'getById').mockResolvedValue(result);
+  it('get all requests', async () => {
+    const result: Array<CredentialExchangeRecord> = [];
+    jest.spyOn(credentialsService, 'getAllRequests').mockResolvedValue(result);
 
-      const event = await credentialsController.getById({
-        tenantId: 'some-id',
-        credentialRecordId: 'some-id',
-      });
+    const event = await credentialsController.getAllRequests({
+      tenantId: 'some-id',
+    });
+
+    expect(event.data).toStrictEqual(result);
+  });
 
-      expect(event.data).toStrictEqual(result);
+  it('get by id', async () => {
+    const result: CredentialExchangeRecord | null = null;
+    jest.spyOn(credentialsService, 'getById').mockResolvedValue(result);
+
+    const event = await credentialsController.getById({
+      tenantId: 'some-id',
+      credentialRecordId: 'some-id',
     });
+
+    expect(event.data).toStrictEqual(result);
   });
 
-  describe('offer', () => {
-    it('should offer a credential', async () => {
-      const result: CredentialExchangeRecord = new CredentialExchangeRecord({
-        state: CredentialState.Done,
-        threadId: 'some-id',
-        protocolVersion: 'v2',
-      });
-      jest.spyOn(credentialsService, 'offer').mockResolvedValue(result);
-
-      const event = await credentialsController.offer({
-        tenantId: 'some-id',
-        connectionId: 'some-id',
-        credentialDefinitionId: 'some-id',
-        attributes: [
-          { name: 'Name', value: 'Berend', mimeType: 'application/text' },
-          { name: 'Age', value: '25' },
-        ],
-      });
-
-      expect(event.data).toStrictEqual(result);
+  it('delete by id', async () => {
+    const result = {};
+    jest.spyOn(credentialsService, 'deleteById').mockResolvedValue(result);
+
+    const event = await credentialsController.deleteById({
+      tenantId: 'some-id',
+      credentialRecordId: 'some-id-that-does-not-exist',
     });
+
+    expect(event.data).toStrictEqual(result);
   });
 
-  describe('offer to self', () => {
-    it('should offer a credential to self', async () => {
-      const result: CredentialExchangeRecord = new CredentialExchangeRecord({
-        state: CredentialState.Done,
-        threadId: 'some-id',
-        protocolVersion: 'v2',
-      });
-      jest.spyOn(credentialsService, 'offerToSelf').mockResolvedValue(result);
-
-      const event = await credentialsController.offerToSelf({
-        tenantId: 'some-id',
-        credentialDefinitionId: 'some-id',
-        attributes: [
-          { name: 'Name', value: 'Berend', mimeType: 'application/text' },
-          { name: 'Age', value: '25' },
-        ],
-      });
-
-      expect(event.data).toStrictEqual(result);
+  it('offer', async () => {
+    const result: CredentialExchangeRecord = new CredentialExchangeRecord({
+      state: CredentialState.Done,
+      threadId: 'some-id',
+      protocolVersion: 'v2',
+    });
+    jest.spyOn(credentialsService, 'offer').mockResolvedValue(result);
+
+    const event = await credentialsController.offer({
+      tenantId: 'some-id',
+      connectionId: 'some-id',
+      credentialDefinitionId: 'some-id',
+      attributes: [
+        { name: 'Name', value: 'Berend', mimeType: 'application/text' },
+        { name: 'Age', value: '25' },
+      ],
     });
+
+    expect(event.data).toStrictEqual(result);
+  });
+
+  it('offer to self', async () => {
+    const result: CredentialExchangeRecord = new CredentialExchangeRecord({
+      state: CredentialState.Done,
+      threadId: 'some-id',
+      protocolVersion: 'v2',
+    });
+    jest.spyOn(credentialsService, 'offerToSelf').mockResolvedValue(result);
+
+    const event = await credentialsController.offerToSelf({
+      tenantId: 'some-id',
+      credentialDefinitionId: 'some-id',
+      attributes: [
+        { name: 'Name', value: 'Berend', mimeType: 'application/text' },
+        { name: 'Age', value: '25' },
+      ],
+    });
+
+    expect(event.data).toStrictEqual(result);
   });
 });
diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts
index c0caea3..a434e59 100644
--- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts
+++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts
@@ -15,6 +15,10 @@ import {
   EventAnonCredsCredentialRequestGetAllInput,
   EventAnonCredsCredentialsDeleteById,
   EventAnonCredsCredentialsDeleteByIdInput,
+  EventAnonCredsCredentialOfferGetById,
+  EventAnonCredsCredentialOfferGetByIdInput,
+  EventAnonCredsCredentialRequestGetById,
+  EventAnonCredsCredentialRequestGetByIdInput,
 } from '@ocm/shared';
 
 import { AnonCredsCredentialsService } from './anoncredsCredentials.service.js';
@@ -63,6 +67,26 @@ export class AnonCredsCredentialsController {
     );
   }
 
+  @MessagePattern(EventAnonCredsCredentialOfferGetById.token)
+  public async getOfferById(
+    options: EventAnonCredsCredentialOfferGetByIdInput,
+  ): Promise<EventAnonCredsCredentialOfferGetById> {
+    return new EventAnonCredsCredentialOfferGetById(
+      await this.credentialsService.getOfferById(options),
+      options.tenantId,
+    );
+  }
+
+  @MessagePattern(EventAnonCredsCredentialRequestGetById.token)
+  public async getRequestById(
+    options: EventAnonCredsCredentialRequestGetByIdInput,
+  ): Promise<EventAnonCredsCredentialRequestGetById> {
+    return new EventAnonCredsCredentialRequestGetById(
+      await this.credentialsService.getRequestById(options),
+      options.tenantId,
+    );
+  }
+
   @MessagePattern(EventAnonCredsCredentialsDeleteById.token)
   public async deleteById(
     options: EventAnonCredsCredentialsDeleteByIdInput,
diff --git a/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts b/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
index 12250e6..f63159f 100644
--- a/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
+++ b/apps/ssi-abstraction/test/anoncredsCredentials.e2e-spec.ts
@@ -1,17 +1,31 @@
 import type { INestApplication } from '@nestjs/common';
 import type { ClientProxy } from '@nestjs/microservices';
 import type {
-  EventDidcommAnonCredsCredentialsGetAllInput,
-  EventDidcommAnonCredsCredentialsGetByIdInput,
+  EventAnonCredsCredentialRequestGetAllInput,
+  EventAnonCredsCredentialsGetAllInput,
+  EventAnonCredsCredentialsGetByIdInput,
   EventDidcommAnonCredsCredentialsOfferToSelfInput,
+  EventAnonCredsCredentialOfferGetAllInput,
+  EventAnonCredsCredentialOfferGetByIdInput,
+  EventAnonCredsCredentialRequestGetByIdInput,
+  EventAnonCredsCredentialsDeleteByIdInput,
 } from '@ocm/shared';
 
-import { AutoAcceptCredential } from '@aries-framework/core';
+import {
+  AutoAcceptCredential,
+  CredentialExchangeRecord,
+} from '@aries-framework/core';
 import { ClientsModule, Transport } from '@nestjs/microservices';
 import { Test } from '@nestjs/testing';
 import {
-  EventDidcommAnonCredsCredentialsGetAll,
-  EventDidcommAnonCredsCredentialsGetById,
+  EventAnonCredsCredentialsDeleteById,
+  EventAnonCredsCredentialOfferGetAll,
+  EventAnonCredsCredentialOfferGetById,
+  EventAnonCredsCredentialRequestGetAll,
+  EventAnonCredsCredentialRequestGetById,
+  EventAnonCredsCredentialsGetAll,
+  EventAnonCredsCredentialsGetById,
+  EventAnonCredsProofsDeleteById,
   EventDidcommAnonCredsCredentialsOfferToSelf,
 } from '@ocm/shared';
 import { firstValueFrom } from 'rxjs';
@@ -104,29 +118,81 @@ describe('Credentials', () => {
     client.close();
   });
 
-  it(EventDidcommAnonCredsCredentialsGetAll.token, async () => {
+  it(EventAnonCredsCredentialsGetAll.token, async () => {
+    const response$ = client.send<
+      EventAnonCredsCredentialsGetAll,
+      EventAnonCredsCredentialsGetAllInput
+    >(EventAnonCredsCredentialsGetAll.token, { tenantId });
+    const response = await firstValueFrom(response$);
+    const eventInstance = EventAnonCredsCredentialsGetAll.fromEvent(response);
+
+    expect(eventInstance.instance).toEqual(expect.arrayContaining([]));
+  });
+
+  it(EventAnonCredsCredentialOfferGetAll.token, async () => {
     const response$ = client.send<
-      EventDidcommAnonCredsCredentialsGetAll,
-      EventDidcommAnonCredsCredentialsGetAllInput
-    >(EventDidcommAnonCredsCredentialsGetAll.token, { tenantId });
+      EventAnonCredsCredentialOfferGetAll,
+      EventAnonCredsCredentialOfferGetAllInput
+    >(EventAnonCredsCredentialOfferGetAll.token, { tenantId });
     const response = await firstValueFrom(response$);
     const eventInstance =
-      EventDidcommAnonCredsCredentialsGetAll.fromEvent(response);
+      EventAnonCredsCredentialOfferGetAll.fromEvent(response);
 
     expect(eventInstance.instance).toEqual(expect.arrayContaining([]));
   });
 
-  it(EventDidcommAnonCredsCredentialsGetById.token, async () => {
+  it(EventAnonCredsCredentialOfferGetById.token, async () => {
     const response$ = client.send<
-      EventDidcommAnonCredsCredentialsGetById,
-      EventDidcommAnonCredsCredentialsGetByIdInput
-    >(EventDidcommAnonCredsCredentialsGetById.token, {
+      EventAnonCredsCredentialOfferGetById,
+      EventAnonCredsCredentialOfferGetByIdInput
+    >(EventAnonCredsCredentialOfferGetById.token, {
       tenantId,
-      credentialRecordId: 'some-id',
+      credentialOfferId: 'some-id-that-does-not-exist',
+    });
+    const response = await firstValueFrom(response$);
+    const eventInstance =
+      EventAnonCredsCredentialOfferGetById.fromEvent(response);
+
+    expect(eventInstance.instance).toBeNull();
+  });
+
+  it(EventAnonCredsCredentialRequestGetAll.token, async () => {
+    const response$ = client.send<
+      EventAnonCredsCredentialRequestGetAll,
+      EventAnonCredsCredentialRequestGetAllInput
+    >(EventAnonCredsCredentialRequestGetAll.token, { tenantId });
+    const response = await firstValueFrom(response$);
+    const eventInstance =
+      EventAnonCredsCredentialRequestGetAll.fromEvent(response);
+
+    expect(eventInstance.instance).toEqual(expect.arrayContaining([]));
+  });
+
+  it(EventAnonCredsCredentialRequestGetById.token, async () => {
+    const response$ = client.send<
+      EventAnonCredsCredentialRequestGetById,
+      EventAnonCredsCredentialRequestGetByIdInput
+    >(EventAnonCredsCredentialRequestGetById.token, {
+      tenantId,
+      credentialRequestId: 'some-id-that-does-not-exist',
     });
     const response = await firstValueFrom(response$);
     const eventInstance =
-      EventDidcommAnonCredsCredentialsGetById.fromEvent(response);
+      EventAnonCredsCredentialRequestGetById.fromEvent(response);
+
+    expect(eventInstance.instance).toBeNull();
+  });
+
+  it(EventAnonCredsCredentialsGetById.token, async () => {
+    const response$ = client.send<
+      EventAnonCredsCredentialsGetById,
+      EventAnonCredsCredentialsGetByIdInput
+    >(EventAnonCredsCredentialsGetById.token, {
+      tenantId,
+      credentialRecordId: 'some-id',
+    });
+    const response = await firstValueFrom(response$);
+    const eventInstance = EventAnonCredsCredentialsGetById.fromEvent(response);
 
     expect(eventInstance.instance).toEqual(null);
   });
@@ -154,4 +220,97 @@ describe('Credentials', () => {
       autoAcceptCredential: AutoAcceptCredential.Always,
     });
   });
+
+  it(EventAnonCredsProofsDeleteById.token, async () => {
+    let credentialExchangeRecord: CredentialExchangeRecord | undefined =
+      undefined;
+
+    // GET ALL
+    {
+      const response$ = client.send<
+        EventAnonCredsCredentialsGetAll,
+        EventAnonCredsCredentialsGetAllInput
+      >(EventAnonCredsCredentialsGetAll.token, { tenantId });
+      const response = await firstValueFrom(response$);
+      const eventInstance = EventAnonCredsCredentialsGetAll.fromEvent(response);
+
+      expect(eventInstance.instance).toEqual(expect.arrayContaining([]));
+    }
+
+    // Offer a credential
+
+    {
+      const attributes = [
+        { name: 'Name', value: 'Berend' },
+        { name: 'Age', value: '25' },
+      ];
+
+      const response$ = client.send<
+        EventDidcommAnonCredsCredentialsOfferToSelf,
+        EventDidcommAnonCredsCredentialsOfferToSelfInput
+      >(EventDidcommAnonCredsCredentialsOfferToSelf.token, {
+        tenantId,
+        credentialDefinitionId,
+        attributes,
+      });
+
+      const response = await firstValueFrom(response$);
+      const eventInstance =
+        EventDidcommAnonCredsCredentialsOfferToSelf.fromEvent(response);
+
+      expect(eventInstance.instance).toMatchObject({
+        autoAcceptCredential: AutoAcceptCredential.Always,
+      });
+
+      credentialExchangeRecord = eventInstance.instance;
+    }
+
+    // GET THE CREDENTIAL BY ID
+    {
+      const response$ = client.send<
+        EventAnonCredsCredentialsGetById,
+        EventAnonCredsCredentialsGetByIdInput
+      >(EventAnonCredsCredentialsGetById.token, {
+        tenantId,
+        credentialRecordId: credentialExchangeRecord.id,
+      });
+      const response = await firstValueFrom(response$);
+      const eventInstance =
+        EventAnonCredsCredentialsGetById.fromEvent(response);
+
+      expect(eventInstance.instance).toBeInstanceOf(CredentialExchangeRecord);
+    }
+
+    // DELETE THE CREDENTIAL
+    {
+      const response$ = client.send<
+        EventAnonCredsCredentialsDeleteById,
+        EventAnonCredsCredentialsDeleteByIdInput
+      >(EventAnonCredsCredentialsDeleteById.token, {
+        tenantId,
+        credentialRecordId: credentialExchangeRecord.id,
+      });
+      const response = await firstValueFrom(response$);
+      const eventInstance =
+        EventAnonCredsCredentialsDeleteById.fromEvent(response);
+
+      expect(eventInstance).toMatchObject({});
+    }
+
+    // GET THE CREDENTIAL BY ID
+    {
+      const response$ = client.send<
+        EventAnonCredsCredentialsGetById,
+        EventAnonCredsCredentialsGetByIdInput
+      >(EventAnonCredsCredentialsGetById.token, {
+        tenantId,
+        credentialRecordId: credentialExchangeRecord.id,
+      });
+      const response = await firstValueFrom(response$);
+      const eventInstance =
+        EventAnonCredsCredentialsGetById.fromEvent(response);
+
+      expect(eventInstance.instance).toBeNull();
+    }
+  });
 });
-- 
GitLab