Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions modules/express/src/typedRoutes/api/v1/acceptShare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@ export const AcceptShareRequestBody = {
userPassword: optional(t.string),
/** New passphrase to encrypt the shared wallet's keys */
newWalletPassphrase: optional(t.string),
/** Optional encrypted private key to use instead of generating a new one */
/** Optional encrypted xprv to use instead of generating a new one */
overrideEncryptedXprv: optional(t.string),
};

/** Response from accepting a wallet share */
export const AcceptShareResponse = t.type({
/** Indicates whether the share state was changed by this operation */
changed: t.boolean,
/** Current state of the wallet share */
state: t.string,
});

/**
* Accept a Wallet Share
* Allows users to accept a wallet share invitation from another user.
Expand All @@ -34,7 +42,7 @@ export const PostAcceptShare = httpRoute({
}),
response: {
/** Successfully accepted wallet share */
200: t.UnknownRecord,
200: AcceptShareResponse,
/** Error response */
400: BitgoExpressError,
},
Expand Down
79 changes: 78 additions & 1 deletion modules/express/test/unit/typedRoutes/acceptShare.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as t from 'io-ts';
import {
AcceptShareRequestParams,
AcceptShareRequestBody,
AcceptShareResponse,
PostAcceptShare,
} from '../../../src/typedRoutes/api/v1/acceptShare';
import { assertDecode } from './common';
Expand Down Expand Up @@ -126,14 +127,79 @@ describe('AcceptShare codec tests', function () {
});
});

describe('AcceptShareResponse', function () {
it('should validate valid response with all fields', function () {
const validResponse = {
changed: true,
state: 'accepted',
};

const decoded = assertDecode(AcceptShareResponse, validResponse);
assert.strictEqual(decoded.changed, validResponse.changed);
assert.strictEqual(decoded.state, validResponse.state);
});

it('should validate response with changed=false', function () {
const validResponse = {
changed: false,
state: 'pending',
};

const decoded = assertDecode(AcceptShareResponse, validResponse);
assert.strictEqual(decoded.changed, false);
assert.strictEqual(decoded.state, 'pending');
});

it('should reject response without changed field', function () {
const invalidResponse = {
state: 'accepted',
};

assert.throws(() => {
assertDecode(AcceptShareResponse, invalidResponse);
});
});

it('should reject response without state field', function () {
const invalidResponse = {
changed: true,
};

assert.throws(() => {
assertDecode(AcceptShareResponse, invalidResponse);
});
});

it('should reject response with non-boolean changed field', function () {
const invalidResponse = {
changed: 'true',
state: 'accepted',
};

assert.throws(() => {
assertDecode(AcceptShareResponse, invalidResponse);
});
});

it('should reject response with non-string state field', function () {
const invalidResponse = {
changed: true,
state: 123,
};

assert.throws(() => {
assertDecode(AcceptShareResponse, invalidResponse);
});
});
});

describe('Supertest Integration Tests', function () {
const agent = setupAgent();
const shareId = 'share123456789abcdef';

const mockAcceptShareResponse = {
state: 'accepted',
changed: true,
walletId: 'wallet123',
};

afterEach(function () {
Expand Down Expand Up @@ -163,6 +229,11 @@ describe('AcceptShare codec tests', function () {
assert.strictEqual(result.status, 200);
assert.ok(result.body);

// Validate response structure
const decodedResponse = assertDecode(AcceptShareResponse, result.body);
assert.strictEqual(typeof decodedResponse.changed, 'boolean');
assert.strictEqual(typeof decodedResponse.state, 'string');

// Verify the method was called with correct params
sinon.assert.calledOnce(acceptShareStub);
const callArgs = acceptShareStub.firstCall.args[0];
Expand Down Expand Up @@ -191,6 +262,9 @@ describe('AcceptShare codec tests', function () {
assert.strictEqual(result.status, 200);
assert.ok(result.body);

// Validate response structure
assertDecode(AcceptShareResponse, result.body);

sinon.assert.calledOnce(acceptShareStub);
const callArgs = acceptShareStub.firstCall.args[0];
assert.strictEqual(callArgs.walletShareId, shareId);
Expand All @@ -217,6 +291,9 @@ describe('AcceptShare codec tests', function () {
assert.strictEqual(result.status, 200);
assert.ok(result.body);

// Validate response structure
assertDecode(AcceptShareResponse, result.body);

sinon.assert.calledOnce(acceptShareStub);
const callArgs = acceptShareStub.firstCall.args[0];
assert.strictEqual(callArgs.walletShareId, shareId);
Expand Down