Add proving machine refactor guardrail tests (#1584)

* Add proving machine refactor tests

* Clarify refactor guardrail test intent

* Add Socket.IO status handler wiring tests for proving store (#1586)

* Add status handler listener tests

* Fix failure status test payload

* Add hello ack uuid test (#1588)

* formatting

* format, agent feedback

* delete mock mock tests
This commit is contained in:
Justin Hernandez
2026-01-12 11:29:57 -08:00
committed by GitHub
parent d132633c20
commit 9f5171f21e
4 changed files with 856 additions and 0 deletions

View File

@@ -0,0 +1,252 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import type { SelfClient } from '../../../src';
import { useProvingStore } from '../../../src/proving/provingMachine';
import { useProtocolStore } from '../../../src/stores/protocolStore';
import { useSelfAppStore } from '../../../src/stores/selfAppStore';
import { actorMock } from '../actorMock';
vitest.mock('xstate', () => {
return {
createActor: vitest.fn(() => actorMock),
createMachine: vitest.fn(),
assign: vitest.fn(),
send: vitest.fn(),
spawn: vitest.fn(),
interpret: vitest.fn(),
fromPromise: vitest.fn(),
fromObservable: vitest.fn(),
fromEventObservable: vitest.fn(),
fromCallback: vitest.fn(),
fromTransition: vitest.fn(),
fromReducer: vitest.fn(),
fromRef: vitest.fn(),
};
});
vitest.mock('@selfxyz/common/utils/proving', async () => {
const actual = await vitest.importActual<typeof import('@selfxyz/common/utils/proving')>(
'@selfxyz/common/utils/proving',
);
return {
...actual,
getPayload: vitest.fn(() => ({ payload: true })),
encryptAES256GCM: vitest.fn(() => ({
nonce: [1],
cipher_text: [2],
auth_tag: [3],
})),
};
});
vitest.mock('@selfxyz/common/utils/circuits/registerInputs', async () => {
const actual = (await vitest.importActual('@selfxyz/common/utils/circuits/registerInputs')) as any;
return {
...actual,
generateTEEInputsRegister: vitest.fn(async () => ({
inputs: { reg: true },
circuitName: 'register_circuit',
endpointType: 'celo',
endpoint: 'https://register',
})),
generateTEEInputsDSC: vitest.fn(() => ({
inputs: { dsc: true },
circuitName: 'dsc_circuit',
endpointType: 'celo',
endpoint: 'https://dsc',
})),
generateTEEInputsDiscloseStateless: vitest.fn(() => ({
inputs: { disclose: true },
circuitName: 'disclose_circuit',
endpointType: 'https',
endpoint: 'https://disclose',
})),
};
});
describe('payload generator (refactor guardrail via _generatePayload)', () => {
const selfClient: SelfClient = {
trackEvent: vitest.fn(),
emit: vitest.fn(),
logProofEvent: vitest.fn(),
getPrivateKey: vitest.fn(),
getSelfAppState: () => useSelfAppStore.getState(),
getProvingState: () => useProvingStore.getState(),
getProtocolState: () => useProtocolStore.getState(),
} as unknown as SelfClient;
beforeEach(() => {
vitest.clearAllMocks();
useSelfAppStore.setState({
selfApp: {
chainID: 42220,
userId: '12345678-1234-1234-1234-123456789abc',
userDefinedData: '0x0',
selfDefinedData: '',
endpointType: 'https',
endpoint: 'https://endpoint',
scope: 'scope',
sessionId: '',
appName: '',
logoBase64: '',
header: '',
userIdType: 'uuid',
devMode: false,
disclosures: {},
version: 1,
deeplinkCallback: '',
},
});
});
it('builds a submit request payload with the encrypted payload', async () => {
useProvingStore.setState({
circuitType: 'register',
passportData: { documentCategory: 'passport', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
const payload = await useProvingStore.getState()._generatePayload(selfClient);
expect(payload).toEqual({
jsonrpc: '2.0',
method: 'openpassport_submit_request',
id: 2,
params: {
uuid: 'uuid-123',
nonce: [1],
cipher_text: [2],
auth_tag: [3],
},
});
});
it('throws when dsc is requested for aadhaar documents', async () => {
useProvingStore.setState({
circuitType: 'dsc',
passportData: { documentCategory: 'aadhaar', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
await expect(useProvingStore.getState()._generatePayload(selfClient)).rejects.toThrow(
'DSC circuit type is not supported for Aadhaar documents',
);
});
it('throws when disclose circuit is requested without a SelfApp', async () => {
useSelfAppStore.setState({ selfApp: null });
useProvingStore.setState({
circuitType: 'disclose',
passportData: { documentCategory: 'passport', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
await expect(useProvingStore.getState()._generatePayload(selfClient)).rejects.toThrow(
'SelfApp context not initialized',
);
});
it('throws on invalid circuit types', async () => {
useProvingStore.setState({
circuitType: 'invalid' as any,
passportData: { documentCategory: 'passport', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
await expect(useProvingStore.getState()._generatePayload(selfClient)).rejects.toThrow(
'Invalid circuit type:invalid',
);
});
it('uses register_id for id cards', async () => {
const { getPayload } = await import('@selfxyz/common/utils/proving');
useProvingStore.setState({
circuitType: 'register',
passportData: { documentCategory: 'id_card', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
await useProvingStore.getState()._generatePayload(selfClient);
expect(getPayload).toHaveBeenCalledWith(
{ reg: true },
'register_id',
'register_circuit',
'celo',
'https://register',
1,
expect.any(String),
'',
);
});
it('keeps dsc circuit type for passport documents', async () => {
const { getPayload } = await import('@selfxyz/common/utils/proving');
useProvingStore.setState({
circuitType: 'dsc',
passportData: { documentCategory: 'passport', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
await useProvingStore.getState()._generatePayload(selfClient);
expect(getPayload).toHaveBeenCalledWith(
{ dsc: true },
'dsc',
'dsc_circuit',
'celo',
'https://dsc',
1,
expect.any(String),
'',
);
});
it('always uses disclose for disclosure flows', async () => {
const { getPayload } = await import('@selfxyz/common/utils/proving');
useProvingStore.setState({
circuitType: 'disclose',
passportData: { documentCategory: 'passport', mock: false } as any,
secret: 'secret',
uuid: 'uuid-123',
sharedKey: Buffer.alloc(32, 1),
env: 'prod',
});
await useProvingStore.getState()._generatePayload(selfClient);
expect(getPayload).toHaveBeenCalledWith(
{ disclose: true },
'disclose',
'disclose_circuit',
'https',
'https://disclose',
1,
expect.any(String),
'',
);
});
});

View File

@@ -0,0 +1,172 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import { EventEmitter } from 'events';
import type { Socket } from 'socket.io-client';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useProvingStore } from '../../../src/proving/provingMachine';
import { actorMock } from '../actorMock';
vi.mock('socket.io-client');
vi.mock('../../../src/constants/analytics', () => ({
ProofEvents: {
SOCKETIO_CONN_STARTED: 'SOCKETIO_CONN_STARTED',
SOCKETIO_SUBSCRIBED: 'SOCKETIO_SUBSCRIBED',
SOCKETIO_STATUS_RECEIVED: 'SOCKETIO_STATUS_RECEIVED',
SOCKETIO_PROOF_FAILURE: 'SOCKETIO_PROOF_FAILURE',
SOCKETIO_PROOF_SUCCESS: 'SOCKETIO_PROOF_SUCCESS',
REGISTER_COMPLETED: 'REGISTER_COMPLETED',
},
PassportEvents: {},
}));
vi.mock('../../../src/proving/internal/logging', () => ({
logProofEvent: vi.fn(),
createProofContext: vi.fn(() => ({})),
}));
vi.mock('@selfxyz/common/utils/proving', () => ({
getWSDbRelayerUrl: vi.fn(() => 'ws://test-url'),
getPayload: vi.fn(),
encryptAES256GCM: vi.fn(),
clientKey: {},
clientPublicKeyHex: 'test-key',
ec: {},
}));
vi.mock('../../../src/documents/utils', () => ({
loadSelectedDocument: vi.fn(() =>
Promise.resolve({
data: { mockData: true },
version: '1.0.0',
}),
),
hasAnyValidRegisteredDocument: vi.fn(() => Promise.resolve(true)),
clearPassportData: vi.fn(),
markCurrentDocumentAsRegistered: vi.fn(),
reStorePassportDataWithRightCSCA: vi.fn(),
}));
vi.mock('../../../src/types/events', () => ({
SdkEvents: {
PASSPORT_DATA_NOT_FOUND: 'PASSPORT_DATA_NOT_FOUND',
},
}));
vi.mock('@selfxyz/common/utils', () => ({
getCircuitNameFromPassportData: vi.fn(() => 'register'),
getSolidityPackedUserContextData: vi.fn(() => '0x123'),
}));
vi.mock('@selfxyz/common/utils/attest', () => ({
getPublicKey: vi.fn(),
verifyAttestation: vi.fn(),
}));
vi.mock('@selfxyz/common/utils/circuits/registerInputs', () => ({
generateTEEInputsDSC: vi.fn(),
generateTEEInputsRegister: vi.fn(),
}));
vi.mock('@selfxyz/common/utils/passports/validate', () => ({
checkDocumentSupported: vi.fn(() => Promise.resolve(true)),
checkIfPassportDscIsInTree: vi.fn(() => Promise.resolve(true)),
isDocumentNullified: vi.fn(() => Promise.resolve(false)),
isUserRegistered: vi.fn(() => Promise.resolve(false)),
isUserRegisteredWithAlternativeCSCA: vi.fn(() => Promise.resolve(false)),
}));
vi.mock('xstate', () => ({
createActor: vi.fn(() => actorMock),
createMachine: vi.fn(() => ({})),
}));
describe('Socket.IO status handler wiring', () => {
const mockSelfClient = {
trackEvent: vi.fn(),
emit: vi.fn(),
getPrivateKey: vi.fn(() => Promise.resolve('mock-private-key')),
logProofEvent: vi.fn(),
getSelfAppState: () => ({
selfApp: {},
}),
getProtocolState: () => ({
isUserLoggedIn: true,
}),
getProvingState: () => useProvingStore.getState(),
} as any;
let mockSocket: EventEmitter & Partial<Socket>;
let socketIoMock: any;
beforeEach(async () => {
vi.clearAllMocks();
useProvingStore.setState({
socketConnection: null,
error_code: null,
reason: null,
circuitType: 'register',
} as any);
mockSocket = new EventEmitter() as EventEmitter & Partial<Socket>;
vi.spyOn(mockSocket as any, 'emit');
mockSocket.disconnect = vi.fn();
const socketIo = await import('socket.io-client');
socketIoMock = vi.mocked(socketIo.default || socketIo);
socketIoMock.mockReturnValue(mockSocket);
const store = useProvingStore.getState();
await store.init(mockSelfClient, 'register', true);
actorMock.send.mockClear();
});
it('applies success updates and emits PROVE_SUCCESS', async () => {
const store = useProvingStore.getState();
store._startSocketIOStatusListener('test-uuid', 'https', mockSelfClient);
await new Promise(resolve => setImmediate(resolve));
(mockSocket as any).emit('status', { status: 4 });
const finalState = useProvingStore.getState();
expect(finalState.socketConnection).toBe(null);
expect(actorMock.send).toHaveBeenCalledWith({ type: 'PROVE_SUCCESS' });
});
it('applies failure updates and emits PROVE_FAILURE', async () => {
const store = useProvingStore.getState();
store._startSocketIOStatusListener('test-uuid', 'https', mockSelfClient);
await new Promise(resolve => setImmediate(resolve));
(mockSocket as any).emit('status', {
status: 5,
error_code: 'E001',
reason: 'TEE failed',
});
const finalState = useProvingStore.getState();
expect(finalState.error_code).toBe('E001');
expect(finalState.reason).toBe('TEE failed');
expect(finalState.socketConnection).toBe(null);
expect(actorMock.send).toHaveBeenCalledWith({ type: 'PROVE_FAILURE' });
});
it('emits PROVE_ERROR without updating state for retryable errors', async () => {
const store = useProvingStore.getState();
store._startSocketIOStatusListener('test-uuid', 'https', mockSelfClient);
await new Promise(resolve => setImmediate(resolve));
(mockSocket as any).emit('status', '{"invalid": json}');
const finalState = useProvingStore.getState();
expect(finalState.socketConnection).toBe(mockSocket);
expect(finalState.error_code).toBe(null);
expect(finalState.reason).toBe(null);
expect(actorMock.send).toHaveBeenCalledWith({ type: 'PROVE_ERROR' });
});
});

View File

@@ -0,0 +1,227 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import type { SelfClient } from '../../../src';
import * as documentUtils from '../../../src/documents/utils';
import { useProvingStore } from '../../../src/proving/provingMachine';
import { useProtocolStore } from '../../../src/stores/protocolStore';
import { useSelfAppStore } from '../../../src/stores/selfAppStore';
import { actorMock } from '../actorMock';
vitest.mock('uuid', () => ({
v4: vitest.fn(() => 'uuid-123'),
}));
vitest.mock('xstate', () => {
return {
createActor: vitest.fn(() => actorMock),
createMachine: vitest.fn(),
assign: vitest.fn(),
send: vitest.fn(),
spawn: vitest.fn(),
interpret: vitest.fn(),
fromPromise: vitest.fn(),
fromObservable: vitest.fn(),
fromEventObservable: vitest.fn(),
fromCallback: vitest.fn(),
fromTransition: vitest.fn(),
fromReducer: vitest.fn(),
fromRef: vitest.fn(),
};
});
vitest.mock('@selfxyz/common/utils/attest', () => {
return {
validatePKIToken: vitest.fn(() => ({
userPubkey: Buffer.from('abcd', 'hex'),
serverPubkey: 'server-key',
imageHash: 'hash',
verified: true,
})),
checkPCR0Mapping: vitest.fn(async () => true),
};
});
vitest.mock('@selfxyz/common/utils/proving', async () => {
const actual = await vitest.importActual<typeof import('@selfxyz/common/utils/proving')>(
'@selfxyz/common/utils/proving',
);
return {
...actual,
clientPublicKeyHex: 'abcd',
clientKey: {
derive: vitest.fn(() => ({
toArray: () => Array(32).fill(7),
})),
},
ec: {
keyFromPublic: vitest.fn(() => ({
getPublic: vitest.fn(() => 'server-public'),
})),
},
};
});
describe('websocket handlers (refactor guardrail via proving store)', () => {
const selfClient: SelfClient = {
trackEvent: vitest.fn(),
emit: vitest.fn(),
logProofEvent: vitest.fn(),
getPrivateKey: vitest.fn().mockResolvedValue('secret'),
getSelfAppState: () => useSelfAppStore.getState(),
getProvingState: () => useProvingStore.getState(),
getProtocolState: () => useProtocolStore.getState(),
} as unknown as SelfClient;
let loadSelectedDocumentSpy: any;
beforeEach(() => {
vitest.clearAllMocks();
(globalThis as { __DEV__?: boolean }).__DEV__ = true;
useSelfAppStore.setState({ selfApp: null, sessionId: null, socket: null });
if (!loadSelectedDocumentSpy) {
loadSelectedDocumentSpy = vitest.spyOn(documentUtils, 'loadSelectedDocument');
}
loadSelectedDocumentSpy.mockResolvedValue({
data: {
documentCategory: 'passport',
mock: false,
dsc_parsed: { authorityKeyIdentifier: 'aki' },
} as any,
} as any);
});
it('does nothing when actor is missing or wsConnection is null', () => {
useProvingStore.setState({ wsConnection: null } as any);
useProvingStore.getState()._handleWsOpen(selfClient);
expect(actorMock.send).not.toHaveBeenCalled();
});
it('does nothing when wsConnection is null even if actor exists', async () => {
await useProvingStore.getState().init(selfClient, 'register');
actorMock.send.mockClear();
useProvingStore.setState({ wsConnection: null } as any);
useProvingStore.getState()._handleWsOpen(selfClient);
expect(actorMock.send).not.toHaveBeenCalled();
});
it('sends hello message and stores uuid on open', async () => {
const wsConnection = {
send: vitest.fn(),
} as unknown as WebSocket;
await useProvingStore.getState().init(selfClient, 'register');
useProvingStore.setState({ wsConnection });
useProvingStore.getState()._handleWsOpen(selfClient);
expect(useProvingStore.getState().uuid).toBe('uuid-123');
const [sentMessage] = (wsConnection.send as unknown as { mock: { calls: string[][] } }).mock.calls[0];
const parsedMessage = JSON.parse(sentMessage);
expect(parsedMessage).toMatchObject({
jsonrpc: '2.0',
method: 'openpassport_hello',
id: 1,
params: {
uuid: 'uuid-123',
user_pubkey: expect.any(Array),
},
});
});
it('handles attestation messages by deriving shared key and emitting CONNECT_SUCCESS', async () => {
const { clientPublicKeyHex } = await import('@selfxyz/common/utils/proving');
const { validatePKIToken } = await import('@selfxyz/common/utils/attest');
await useProvingStore.getState().init(selfClient, 'register');
useProvingStore.setState({ currentState: 'init_tee_connexion' } as any);
const event = { data: JSON.stringify({ result: { attestation: [1, 2, 3] } }) } as MessageEvent;
await useProvingStore.getState()._handleWebSocketMessage(event, selfClient);
expect(clientPublicKeyHex).toBe('abcd');
expect(validatePKIToken).toHaveBeenCalled();
expect(useProvingStore.getState().sharedKey).toEqual(Buffer.from(Array(32).fill(7)));
expect(actorMock.send).toHaveBeenCalledWith({ type: 'CONNECT_SUCCESS' });
});
it('starts socket listener on hello ack', async () => {
await useProvingStore.getState().init(selfClient, 'register');
const startListener = vitest.fn();
useProvingStore.setState({
endpointType: 'https',
uuid: 'uuid-123',
_startSocketIOStatusListener: startListener,
} as any);
const event = new MessageEvent('message', {
data: JSON.stringify({ id: 2, result: 'status-uuid' }),
});
await useProvingStore.getState()._handleWebSocketMessage(event, selfClient);
expect(startListener).toHaveBeenCalledWith('status-uuid', 'https', selfClient);
});
it('uses hello ack uuid when it differs from stored uuid', async () => {
await useProvingStore.getState().init(selfClient, 'register');
const startListener = vitest.fn();
useProvingStore.setState({
endpointType: 'https',
uuid: 'uuid-123',
_startSocketIOStatusListener: startListener,
} as any);
const event = new MessageEvent('message', {
data: JSON.stringify({ id: 2, result: 'uuid-456' }),
});
await useProvingStore.getState()._handleWebSocketMessage(event, selfClient);
expect(startListener).toHaveBeenCalledWith('uuid-456', 'https', selfClient);
});
it('emits PROVE_ERROR on websocket error payloads', async () => {
await useProvingStore.getState().init(selfClient, 'register');
const event = new MessageEvent('message', {
data: JSON.stringify({ error: 'bad' }),
});
await useProvingStore.getState()._handleWebSocketMessage(event, selfClient);
expect(actorMock.send).toHaveBeenCalledWith({ type: 'PROVE_ERROR' });
});
it.each([
{ state: 'init_tee_connexion', expected: 'PROVE_ERROR' },
{ state: 'proving', expected: 'PROVE_ERROR' },
{ state: 'listening_for_status', expected: 'PROVE_ERROR' },
])('emits $expected when websocket closes during $state', async ({ state, expected }) => {
await useProvingStore.getState().init(selfClient, 'register');
useProvingStore.setState({ currentState: state } as any);
const event = { code: 1000, reason: 'closed' } as CloseEvent;
useProvingStore.getState()._handleWsClose(event, selfClient);
expect(actorMock.send).toHaveBeenCalledWith({ type: expected });
});
it.each([
{ state: 'init_tee_connexion', expected: 'PROVE_ERROR' },
{ state: 'proving', expected: 'PROVE_ERROR' },
])('emits $expected when websocket errors during $state', async ({ state, expected }) => {
await useProvingStore.getState().init(selfClient, 'register');
useProvingStore.setState({ currentState: state } as any);
useProvingStore.getState()._handleWsError(new Event('error'), selfClient);
expect(actorMock.send).toHaveBeenCalledWith({ type: expected });
});
});

View File

@@ -0,0 +1,205 @@
// SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc.
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.
import type { SelfClient } from '../../../src';
import * as documentUtils from '../../../src/documents/utils';
import { useProvingStore } from '../../../src/proving/provingMachine';
import { useProtocolStore } from '../../../src/stores/protocolStore';
import { actorMock, emitState } from '../actorMock';
vitest.mock('xstate', () => {
return {
createActor: vitest.fn(() => actorMock),
createMachine: vitest.fn(),
assign: vitest.fn(),
send: vitest.fn(),
spawn: vitest.fn(),
interpret: vitest.fn(),
fromPromise: vitest.fn(),
fromObservable: vitest.fn(),
fromEventObservable: vitest.fn(),
fromCallback: vitest.fn(),
fromTransition: vitest.fn(),
fromReducer: vitest.fn(),
fromRef: vitest.fn(),
};
});
vitest.mock('@selfxyz/common/utils', async () => {
const actual = await vitest.importActual<typeof import('@selfxyz/common/utils')>('@selfxyz/common/utils');
return {
...actual,
getCircuitNameFromPassportData: vitest.fn(() => 'mock-circuit'),
};
});
describe('websocket URL resolution (refactor guardrail via initTeeConnection)', () => {
const wsSend = vitest.fn();
const wsAddEventListener = vitest.fn();
const wsMock = vitest.fn(() => ({
addEventListener: wsAddEventListener,
send: wsSend,
}));
let loadSelectedDocumentSpy: any;
const makeSelfClient = (): SelfClient =>
({
getPrivateKey: vitest.fn().mockResolvedValue('secret'),
trackEvent: vitest.fn(),
logProofEvent: vitest.fn(),
getProvingState: () => useProvingStore.getState(),
getProtocolState: () => useProtocolStore.getState(),
getSelfAppState: () => ({ selfApp: null }),
}) as unknown as SelfClient;
const setCircuitsMapping = (documentCategory: 'passport' | 'id_card' | 'aadhaar', mapping: any) => {
useProtocolStore.setState(state => ({
[documentCategory]: {
...state[documentCategory],
circuits_dns_mapping: mapping,
},
}));
};
beforeEach(() => {
vitest.restoreAllMocks();
vitest.clearAllMocks();
global.WebSocket = wsMock as unknown as typeof WebSocket;
loadSelectedDocumentSpy = vitest.spyOn(documentUtils, 'loadSelectedDocument');
});
it.each([
{
label: 'disclose passport -> DISCLOSE',
circuitType: 'disclose' as const,
documentCategory: 'passport' as const,
circuitName: 'disclose',
mappingKey: 'DISCLOSE',
},
{
label: 'disclose id_card -> DISCLOSE_ID',
circuitType: 'disclose' as const,
documentCategory: 'id_card' as const,
circuitName: 'disclose',
mappingKey: 'DISCLOSE_ID',
},
{
label: 'disclose aadhaar -> DISCLOSE_AADHAAR',
circuitType: 'disclose' as const,
documentCategory: 'aadhaar' as const,
circuitName: 'disclose_aadhaar',
mappingKey: 'DISCLOSE_AADHAAR',
},
{
label: 'register passport -> REGISTER',
circuitType: 'register' as const,
documentCategory: 'passport' as const,
circuitName: 'mock-circuit',
mappingKey: 'REGISTER',
},
{
label: 'register id_card -> REGISTER_ID',
circuitType: 'register' as const,
documentCategory: 'id_card' as const,
circuitName: 'mock-circuit',
mappingKey: 'REGISTER_ID',
},
{
label: 'register aadhaar -> REGISTER_AADHAAR',
circuitType: 'register' as const,
documentCategory: 'aadhaar' as const,
circuitName: 'mock-circuit',
mappingKey: 'REGISTER_AADHAAR',
},
{
label: 'dsc passport -> DSC',
circuitType: 'dsc' as const,
documentCategory: 'passport' as const,
circuitName: 'mock-circuit',
mappingKey: 'DSC',
},
{
label: 'dsc id_card -> DSC_ID',
circuitType: 'dsc' as const,
documentCategory: 'id_card' as const,
circuitName: 'mock-circuit',
mappingKey: 'DSC_ID',
},
])('$label resolves expected WebSocket URL', async ({ circuitType, documentCategory, circuitName, mappingKey }) => {
const selfClient = makeSelfClient();
const wsUrl = `wss://example/${mappingKey}`;
loadSelectedDocumentSpy.mockResolvedValue({
data: {
documentCategory,
mock: false,
dsc_parsed: { authorityKeyIdentifier: 'aki' },
} as any,
} as any);
setCircuitsMapping(documentCategory, {
[mappingKey]: {
[circuitName]: wsUrl,
},
});
await useProvingStore.getState().init(selfClient, circuitType);
const initPromise = useProvingStore.getState().initTeeConnection(selfClient);
emitState('ready_to_prove');
await initPromise;
expect(wsMock).toHaveBeenCalledWith(wsUrl);
});
it('throws when mapping is missing for the circuit', async () => {
const selfClient = makeSelfClient();
loadSelectedDocumentSpy.mockResolvedValue({
data: {
documentCategory: 'passport',
mock: false,
dsc_parsed: { authorityKeyIdentifier: 'aki' },
} as any,
} as any);
setCircuitsMapping('passport', {
REGISTER: {
other: 'wss://missing',
},
});
await useProvingStore.getState().init(selfClient, 'register');
await expect(useProvingStore.getState().initTeeConnection(selfClient)).rejects.toThrow(
'No WebSocket URL available for TEE connection',
);
});
it('throws for unsupported document categories', async () => {
const selfClient = makeSelfClient();
const invalidCategory = 'driver_license';
loadSelectedDocumentSpy.mockResolvedValue({
data: {
documentCategory: invalidCategory,
mock: false,
dsc_parsed: { authorityKeyIdentifier: 'aki' },
} as any,
} as any);
useProtocolStore.setState(state => ({
...(state as any),
[invalidCategory]: {
circuits_dns_mapping: {},
},
}));
await useProvingStore.getState().init(selfClient, 'disclose');
await expect(useProvingStore.getState().initTeeConnection(selfClient)).rejects.toThrow(
'Unsupported document category for disclose: driver_license',
);
});
});