UNPKG

@bsv/wallet-toolbox

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

305 lines 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const listCertificates_1 = require("../../../src/storage/methods/listCertificates"); jest.mock('../../../src/storage/StorageProvider'); describe('listCertificates', () => { let mockStorage; let auth; // This is a valid, minimal set of arguments for listCertificates let vargs; let originator; // Helper so we can easily mock the transaction call const mockTransaction = async (callback) => { // We simulate the transaction by simply calling back immediately // with an empty object as trx token. return callback({}); }; beforeEach(() => { // Create a fresh mock of the storage mockStorage = { // We only need to mock the methods that are actually used by listCertificates transaction: jest.fn().mockImplementation(mockTransaction), findCertificates: jest.fn(), findCertificateFields: jest.fn(), countCertificates: jest.fn() }; // Auth with a valid user ID auth = { identityKey: 'myIdentityKey', userId: 123 }; // Minimal valid vargs with default limit=10, offset=0, no partial filter vargs = { partial: undefined, certifiers: [], types: [], limit: 10, offset: 0, privileged: false }; // By default we set it to undefined originator = undefined; }); afterEach(() => { jest.clearAllMocks(); }); test('should return an empty result when no certificates are found', async () => { // Setup mocks mockStorage.findCertificates.mockResolvedValueOnce([]); // no certs returned // Execute const result = await (0, listCertificates_1.listCertificates)(mockStorage, auth, vargs, originator); // Verify expect(mockStorage.transaction).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificates).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificateFields).not.toHaveBeenCalled(); expect(mockStorage.countCertificates).not.toHaveBeenCalled(); // no need to call if 0 < limit expect(result).toEqual({ totalCertificates: 0, certificates: [] }); }); test('should return exactly the number of certificates if they are fewer than the limit', async () => { // Suppose we have 2 certificates const fakeCerts = [ { certificateId: 1, userId: 123, type: 'base64Type1', serialNumber: 'serial1', certifier: 'abcdef01', subject: '12345678', verifier: undefined, revocationOutpoint: 'abcd1234.0', signature: 'deadbeef01', isDeleted: false, created_at: new Date(), updated_at: new Date() }, { certificateId: 2, userId: 123, type: 'base64Type2', serialNumber: 'serial2', certifier: 'abcdef02', subject: '23456789', verifier: undefined, revocationOutpoint: 'abcd5678.1', signature: 'deadbeef02', isDeleted: false, created_at: new Date(), updated_at: new Date() } ]; // Suppose each cert has some fields const fakeFieldsForCert1 = [ { certificateId: 1, userId: 123, fieldName: 'field1', fieldValue: 'value1', masterKey: 'mkey1', created_at: new Date(), updated_at: new Date() } ]; const fakeFieldsForCert2 = [ { certificateId: 2, userId: 123, fieldName: 'fieldA', fieldValue: 'valueA', masterKey: 'mkeyA', created_at: new Date(), updated_at: new Date() } ]; mockStorage.findCertificates.mockResolvedValueOnce(fakeCerts); // Make sure we return correct fields for each certificate mockStorage.findCertificateFields.mockImplementation(async (args) => { var _a, _b; if (((_a = args.partial) === null || _a === void 0 ? void 0 : _a.certificateId) === 1) return fakeFieldsForCert1; if (((_b = args.partial) === null || _b === void 0 ? void 0 : _b.certificateId) === 2) return fakeFieldsForCert2; return []; }); // The returned certs are length=2, which is < limit(10). So we do not call countCertificates // Setup a spied or mocked value just in case mockStorage.countCertificates.mockResolvedValueOnce(10); // Execute const result = await (0, listCertificates_1.listCertificates)(mockStorage, auth, vargs); // Verify expect(mockStorage.transaction).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificates).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificateFields).toHaveBeenCalledTimes(2); expect(mockStorage.countCertificates).not.toHaveBeenCalled(); // Because 2 < 10 expect(result.certificates.length).toBe(2); expect(result.totalCertificates).toBe(2); // Ensure the fields are included expect(result.certificates[0]).toEqual({ type: 'base64Type1', subject: '12345678', serialNumber: 'serial1', certifier: 'abcdef01', revocationOutpoint: 'abcd1234.0', signature: 'deadbeef01', verifier: undefined, fields: { field1: 'value1' }, keyring: { field1: 'mkey1' } }); expect(result.certificates[1]).toEqual({ type: 'base64Type2', subject: '23456789', serialNumber: 'serial2', certifier: 'abcdef02', revocationOutpoint: 'abcd5678.1', signature: 'deadbeef02', verifier: undefined, fields: { fieldA: 'valueA' }, keyring: { fieldA: 'mkeyA' } }); }); test('should call countCertificates when the returned certificates length is equal to limit', async () => { // We want exactly 'limit' items returned, so the function calls countCertificates vargs.limit = 2; // set limit to 2 const fakeCerts = [ { certificateId: 11, userId: 123, type: 'base64Type', serialNumber: 'sn', certifier: 'abcdef01', subject: 'deadbeef01', verifier: undefined, revocationOutpoint: '0000.0', signature: 'abcdabcd', isDeleted: false, created_at: new Date(), updated_at: new Date() }, { certificateId: 22, userId: 123, type: 'base64Type', serialNumber: 'sn2', certifier: 'abcdef02', subject: 'deadbeef02', verifier: undefined, revocationOutpoint: '0001.0', signature: 'ef01ef01', isDeleted: false, created_at: new Date(), updated_at: new Date() } ]; // Suppose each cert has no fields mockStorage.findCertificateFields.mockResolvedValue([]); // We return exactly 2 certs, which is == limit mockStorage.findCertificates.mockResolvedValueOnce(fakeCerts); // So the code should call countCertificates mockStorage.countCertificates.mockResolvedValueOnce(25); // Execute const result = await (0, listCertificates_1.listCertificates)(mockStorage, auth, vargs); // Verify expect(mockStorage.findCertificates).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificateFields).toHaveBeenCalledTimes(2); expect(mockStorage.countCertificates).toHaveBeenCalledTimes(1); // We expect totalCertificates = 25 from countCertificates expect(result.totalCertificates).toBe(25); expect(result.certificates.length).toBe(2); }); test('should handle transaction failure by throwing an error', async () => { // If the transaction or the underlying findCertificates call fails, we rethrow const error = new Error('Database error'); mockStorage.transaction.mockRejectedValueOnce(error); await expect((0, listCertificates_1.listCertificates)(mockStorage, auth, vargs)).rejects.toThrow('Database error'); // Verify mocks expect(mockStorage.transaction).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificates).not.toHaveBeenCalled(); expect(mockStorage.findCertificateFields).not.toHaveBeenCalled(); expect(mockStorage.countCertificates).not.toHaveBeenCalled(); }); test('should handle scenario userId is undefined', async () => { // Although typically userId is required, let's see what happens // If userId is undefined, partial: { userId: undefined, isDeleted: false } is used // The storage call might or might not blow up. We'll test that the code still calls the transaction // We rely on the underlying findCertificates to throw or return an empty array. auth.userId = undefined; mockStorage.findCertificates.mockResolvedValueOnce([]); const result = await (0, listCertificates_1.listCertificates)(mockStorage, auth, vargs); expect(result).toEqual({ totalCertificates: 0, certificates: [] }); // We see a normal call expect(mockStorage.transaction).toHaveBeenCalledTimes(1); expect(mockStorage.findCertificates).toHaveBeenCalledTimes(1); // The partial would have userId: undefined const arg0 = mockStorage.findCertificates.mock.calls[0][0]; expect(arg0.partial).toEqual({ userId: undefined, isDeleted: false }); }); test('if returned certificate count is bigger than limit, still only returns limit items but sets total using countCertificates', async () => { // For completeness, if the storage findCertificates method returns exactly "limit" items, // we do a count. But let's pretend it can return exactly limit or a bit more (some storages might do that incorrectly). // We'll only test the scenario that triggers the "else" path. Already tested an =limit scenario above, // but let's confirm the coverage if the function doesn't rely on partial storage returning partial results. vargs.limit = 2; const cA = { certificateId: 100, userId: 123, type: 'zzz', serialNumber: 'snA', certifier: 'cA', subject: 'sA', verifier: undefined, revocationOutpoint: 'nope.0', signature: 'sigA', isDeleted: false, created_at: new Date(), updated_at: new Date() }; const cB = { certificateId: 101, userId: 123, type: 'yyy', serialNumber: 'snB', certifier: 'cB', subject: 'sB', verifier: undefined, revocationOutpoint: 'nope.1', signature: 'sigB', isDeleted: false, created_at: new Date(), updated_at: new Date() }; const cC = { certificateId: 102, userId: 123, type: 'xxx', serialNumber: 'snC', certifier: 'cC', subject: 'sC', verifier: undefined, revocationOutpoint: 'nope.2', signature: 'sigC', isDeleted: false, created_at: new Date(), updated_at: new Date() }; // Suppose the storage returned 3 items even though we only want 2. // The code uses them all in memory, but sees length=3 which is > limit=2 // The line checks if (r.certificates.length < paged.limit). That is false, so it calls countCertificates. mockStorage.findCertificates.mockResolvedValueOnce([cA, cB, cC]); // Fields are none mockStorage.findCertificateFields.mockResolvedValue([]); // We want to see it call countCertificates mockStorage.countCertificates.mockResolvedValueOnce(999); const result = await (0, listCertificates_1.listCertificates)(mockStorage, auth, vargs); expect(result.certificates.length).toBe(3); expect(result.totalCertificates).toBe(999); // from countCertificates }); }); //# sourceMappingURL=listCertificates.test.js.map