mirror of
https://github.com/mosip/inji-wallet.git
synced 2026-01-09 21:48:04 -05:00
INJIMOB-3246 Code coverage for Inji-Wallet repo increase above 5% (#2108)
* INJIMOB-3246 Code coverage for Inji-Wallet repo increase above 5% Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> * INJIMOB-3246: added snapshot tests and coverage increased to +4% Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> * removed duplicated lines Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> * Added updateCredentialInformation tests Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> * added code rabbit changes Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> * removed platform-specific tests without mocking Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> * standardize mocks in VcItemContainerProfileImage tests Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com> --------- Signed-off-by: Kaushik Gupta <kausgpt97@gmail.com>
This commit is contained in:
405
shared/Utils.test.ts
Normal file
405
shared/Utils.test.ts
Normal file
@@ -0,0 +1,405 @@
|
||||
import {
|
||||
getVCsOrderedByPinStatus,
|
||||
VCShareFlowType,
|
||||
VCItemContainerFlowType,
|
||||
CameraPosition,
|
||||
isMosipVC,
|
||||
parseJSON,
|
||||
isNetworkError,
|
||||
UUID,
|
||||
formatTextWithGivenLimit,
|
||||
DEEPLINK_FLOWS,
|
||||
base64ToByteArray,
|
||||
createCacheObject,
|
||||
isCacheExpired,
|
||||
getVerifierKey,
|
||||
} from './Utils';
|
||||
import {VCMetadata} from './VCMetadata';
|
||||
|
||||
describe('getVCsOrderedByPinStatus', () => {
|
||||
it('should be defined', () => {
|
||||
expect(getVCsOrderedByPinStatus).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return pinned VCs first', () => {
|
||||
const vcMetadatas = [
|
||||
new VCMetadata({id: '1', isPinned: false}),
|
||||
new VCMetadata({id: '2', isPinned: true}),
|
||||
new VCMetadata({id: '3', isPinned: false}),
|
||||
new VCMetadata({id: '4', isPinned: true}),
|
||||
];
|
||||
|
||||
const result = getVCsOrderedByPinStatus(vcMetadatas);
|
||||
|
||||
expect(result[0].isPinned).toBe(true);
|
||||
expect(result[1].isPinned).toBe(true);
|
||||
expect(result[2].isPinned).toBe(false);
|
||||
expect(result[3].isPinned).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle empty array', () => {
|
||||
const result = getVCsOrderedByPinStatus([]);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle all pinned VCs', () => {
|
||||
const vcMetadatas = [
|
||||
new VCMetadata({id: '1', isPinned: true}),
|
||||
new VCMetadata({id: '2', isPinned: true}),
|
||||
];
|
||||
|
||||
const result = getVCsOrderedByPinStatus(vcMetadatas);
|
||||
expect(result.every(vc => vc.isPinned)).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle all unpinned VCs', () => {
|
||||
const vcMetadatas = [
|
||||
new VCMetadata({id: '1', isPinned: false}),
|
||||
new VCMetadata({id: '2', isPinned: false}),
|
||||
];
|
||||
|
||||
const result = getVCsOrderedByPinStatus(vcMetadatas);
|
||||
expect(result.every(vc => !vc.isPinned)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('VCShareFlowType enum', () => {
|
||||
it('should have SIMPLE_SHARE defined', () => {
|
||||
expect(VCShareFlowType.SIMPLE_SHARE).toBe('simple share');
|
||||
});
|
||||
|
||||
it('should have MINI_VIEW_SHARE defined', () => {
|
||||
expect(VCShareFlowType.MINI_VIEW_SHARE).toBe('mini view share');
|
||||
});
|
||||
|
||||
it('should have MINI_VIEW_SHARE_WITH_SELFIE defined', () => {
|
||||
expect(VCShareFlowType.MINI_VIEW_SHARE_WITH_SELFIE).toBe(
|
||||
'mini view share with selfie',
|
||||
);
|
||||
});
|
||||
|
||||
it('should have MINI_VIEW_QR_LOGIN defined', () => {
|
||||
expect(VCShareFlowType.MINI_VIEW_QR_LOGIN).toBe('mini view qr login');
|
||||
});
|
||||
|
||||
it('should have OPENID4VP defined', () => {
|
||||
expect(VCShareFlowType.OPENID4VP).toBe('OpenID4VP');
|
||||
});
|
||||
|
||||
it('should have MINI_VIEW_SHARE_OPENID4VP defined', () => {
|
||||
expect(VCShareFlowType.MINI_VIEW_SHARE_OPENID4VP).toBe(
|
||||
'OpenID4VP share from mini view',
|
||||
);
|
||||
});
|
||||
|
||||
it('should have MINI_VIEW_SHARE_WITH_SELFIE_OPENID4VP defined', () => {
|
||||
expect(VCShareFlowType.MINI_VIEW_SHARE_WITH_SELFIE_OPENID4VP).toBe(
|
||||
'OpenID4VP share with selfie from mini view',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('VCItemContainerFlowType enum', () => {
|
||||
it('should have QR_LOGIN defined', () => {
|
||||
expect(VCItemContainerFlowType.QR_LOGIN).toBe('qr login');
|
||||
});
|
||||
|
||||
it('should have VC_SHARE defined', () => {
|
||||
expect(VCItemContainerFlowType.VC_SHARE).toBe('vc share');
|
||||
});
|
||||
|
||||
it('should have VP_SHARE defined', () => {
|
||||
expect(VCItemContainerFlowType.VP_SHARE).toBe('vp share');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CameraPosition enum', () => {
|
||||
it('should have FRONT defined', () => {
|
||||
expect(CameraPosition.FRONT).toBe('front');
|
||||
});
|
||||
|
||||
it('should have BACK defined', () => {
|
||||
expect(CameraPosition.BACK).toBe('back');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isMosipVC', () => {
|
||||
it('should be defined', () => {
|
||||
expect(isMosipVC).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return true for Mosip issuer', () => {
|
||||
const result = isMosipVC('Mosip');
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for MosipOtp issuer', () => {
|
||||
const result = isMosipVC('MosipOtp');
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for other issuers', () => {
|
||||
expect(isMosipVC('SomeOtherIssuer')).toBe(false);
|
||||
expect(isMosipVC('')).toBe(false);
|
||||
expect(isMosipVC('mosip')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseJSON', () => {
|
||||
it('should be defined', () => {
|
||||
expect(parseJSON).toBeDefined();
|
||||
});
|
||||
|
||||
it('should parse valid JSON string', () => {
|
||||
const jsonStr = '{"key": "value"}';
|
||||
const result = parseJSON(jsonStr);
|
||||
expect(result).toEqual({key: 'value'});
|
||||
});
|
||||
|
||||
it('should handle object input', () => {
|
||||
const obj = {key: 'value'};
|
||||
const result = parseJSON(obj);
|
||||
expect(result).toEqual({key: 'value'});
|
||||
});
|
||||
|
||||
it('should handle invalid JSON gracefully', () => {
|
||||
const invalidJson = '{invalid json}';
|
||||
const result = parseJSON(invalidJson);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle nested objects', () => {
|
||||
const jsonStr = '{"key": {"nested": "value"}}';
|
||||
const result = parseJSON(jsonStr);
|
||||
expect(result.key.nested).toBe('value');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isNetworkError', () => {
|
||||
it('should be defined', () => {
|
||||
expect(isNetworkError).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return true for network request failed error', () => {
|
||||
const error = 'Network request failed';
|
||||
expect(isNetworkError(error)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for other errors', () => {
|
||||
expect(isNetworkError('Some other error')).toBe(false);
|
||||
expect(isNetworkError('')).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle partial matches', () => {
|
||||
const error = 'Error: Network request failed - timeout';
|
||||
expect(isNetworkError(error)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UUID', () => {
|
||||
it('should be defined', () => {
|
||||
expect(UUID).toBeDefined();
|
||||
});
|
||||
|
||||
it('should generate a valid UUID', () => {
|
||||
const uuid = UUID.generate();
|
||||
expect(uuid).toBeDefined();
|
||||
expect(typeof uuid).toBe('string');
|
||||
expect(uuid.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should generate unique UUIDs', () => {
|
||||
const uuid1 = UUID.generate();
|
||||
const uuid2 = UUID.generate();
|
||||
expect(uuid1).not.toBe(uuid2);
|
||||
});
|
||||
|
||||
it('should match UUID format', () => {
|
||||
const uuid = UUID.generate();
|
||||
const uuidRegex =
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
expect(uuidRegex.test(uuid)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatTextWithGivenLimit', () => {
|
||||
it('should be defined', () => {
|
||||
expect(formatTextWithGivenLimit).toBeDefined();
|
||||
});
|
||||
|
||||
it('should truncate text longer than limit', () => {
|
||||
const text = 'This is a very long text';
|
||||
const result = formatTextWithGivenLimit(text, 10);
|
||||
expect(result).toBe('This is a ...');
|
||||
});
|
||||
|
||||
it('should return text as is if shorter than limit', () => {
|
||||
const text = 'Short text';
|
||||
const result = formatTextWithGivenLimit(text, 15);
|
||||
expect(result).toBe('Short text');
|
||||
});
|
||||
|
||||
it('should use default limit of 15 if not provided', () => {
|
||||
const text = 'This is a longer text than 15 characters';
|
||||
const result = formatTextWithGivenLimit(text);
|
||||
expect(result).toBe('This is a longe...');
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
const result = formatTextWithGivenLimit('', 10);
|
||||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
it('should handle exact limit length', () => {
|
||||
const text = 'Exactly 10';
|
||||
const result = formatTextWithGivenLimit(text, 10);
|
||||
expect(result).toBe('Exactly 10');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DEEPLINK_FLOWS enum', () => {
|
||||
it('should have QR_LOGIN defined', () => {
|
||||
expect(DEEPLINK_FLOWS.QR_LOGIN).toBe('qrLoginFlow');
|
||||
});
|
||||
|
||||
it('should have OVP defined', () => {
|
||||
expect(DEEPLINK_FLOWS.OVP).toBe('ovpFlow');
|
||||
});
|
||||
});
|
||||
|
||||
describe('base64ToByteArray', () => {
|
||||
it('should be defined', () => {
|
||||
expect(base64ToByteArray).toBeDefined();
|
||||
});
|
||||
|
||||
it('should convert base64 string to byte array', () => {
|
||||
const base64 = 'SGVsbG8gV29ybGQ='; // "Hello World"
|
||||
const result = base64ToByteArray(base64);
|
||||
expect(result).toBeInstanceOf(Uint8Array);
|
||||
expect(result.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should handle base64url encoding', () => {
|
||||
const base64url = 'SGVsbG8gV29ybGQ'; // without padding
|
||||
const result = base64ToByteArray(base64url);
|
||||
expect(result).toBeInstanceOf(Uint8Array);
|
||||
});
|
||||
|
||||
it('should throw error for invalid base64', () => {
|
||||
expect(() => {
|
||||
base64ToByteArray('!!!invalid base64!!!');
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should handle strings with whitespace', () => {
|
||||
const base64 = ' SGVsbG8gV29ybGQ= ';
|
||||
const result = base64ToByteArray(base64);
|
||||
expect(result).toBeInstanceOf(Uint8Array);
|
||||
});
|
||||
|
||||
it('should handle URL-safe base64 characters', () => {
|
||||
const base64 = 'SGVsbG8tV29ybGQ_'; // with - and _
|
||||
const result = base64ToByteArray(base64);
|
||||
expect(result).toBeInstanceOf(Uint8Array);
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
const result = base64ToByteArray('');
|
||||
expect(result).toBeInstanceOf(Uint8Array);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createCacheObject', () => {
|
||||
it('should create cache object with response and timestamp', () => {
|
||||
const response = {data: 'test data'};
|
||||
const result = createCacheObject(response);
|
||||
|
||||
expect(result).toHaveProperty('response');
|
||||
expect(result).toHaveProperty('cachedTime');
|
||||
expect(result.response).toBe(response);
|
||||
expect(typeof result.cachedTime).toBe('number');
|
||||
});
|
||||
|
||||
it('should use current timestamp', () => {
|
||||
const before = Date.now();
|
||||
const result = createCacheObject({});
|
||||
const after = Date.now();
|
||||
|
||||
expect(result.cachedTime).toBeGreaterThanOrEqual(before);
|
||||
expect(result.cachedTime).toBeLessThanOrEqual(after);
|
||||
});
|
||||
|
||||
it('should handle null response', () => {
|
||||
const result = createCacheObject(null);
|
||||
expect(result.response).toBeNull();
|
||||
expect(result.cachedTime).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle complex objects', () => {
|
||||
const complexResponse = {
|
||||
data: [1, 2, 3],
|
||||
metadata: {key: 'value'},
|
||||
nested: {deep: {value: true}},
|
||||
};
|
||||
const result = createCacheObject(complexResponse);
|
||||
expect(result.response).toBe(complexResponse);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCacheExpired', () => {
|
||||
it('should return false for recent timestamp', () => {
|
||||
const recentTimestamp = Date.now() - 1000; // 1 second ago
|
||||
expect(isCacheExpired(recentTimestamp)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for old timestamp', () => {
|
||||
const oldTimestamp = Date.now() - (60 * 60 * 1000 + 1000); // Over 1 hour ago
|
||||
expect(isCacheExpired(oldTimestamp)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for current timestamp', () => {
|
||||
const currentTimestamp = Date.now();
|
||||
expect(isCacheExpired(currentTimestamp)).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle edge case at exact TTL boundary', () => {
|
||||
const boundaryTimestamp = Date.now() - 60 * 60 * 1000; // Exactly 1 hour ago
|
||||
const result = isCacheExpired(boundaryTimestamp);
|
||||
expect(typeof result).toBe('boolean');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVerifierKey', () => {
|
||||
it('should create verifier key with prefix', () => {
|
||||
const verifier = 'example.com';
|
||||
const result = getVerifierKey(verifier);
|
||||
expect(result).toBe('trusted_verifier_example.com');
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
const result = getVerifierKey('');
|
||||
expect(result).toBe('trusted_verifier_');
|
||||
});
|
||||
|
||||
it('should preserve verifier name exactly', () => {
|
||||
const verifier = 'TestVerifier123';
|
||||
const result = getVerifierKey(verifier);
|
||||
expect(result).toBe('trusted_verifier_TestVerifier123');
|
||||
});
|
||||
|
||||
it('should handle special characters', () => {
|
||||
const verifier = 'verifier-with-dashes_and_underscores';
|
||||
const result = getVerifierKey(verifier);
|
||||
expect(result).toBe(
|
||||
'trusted_verifier_verifier-with-dashes_and_underscores',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canonicalize', () => {
|
||||
it('should be defined', async () => {
|
||||
const {canonicalize} = await import('./Utils');
|
||||
expect(canonicalize).toBeDefined();
|
||||
});
|
||||
});
|
||||
37
shared/VCFormat.test.ts
Normal file
37
shared/VCFormat.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import {VCFormat} from './VCFormat';
|
||||
|
||||
describe('VCFormat', () => {
|
||||
it('should have ldp_vc format', () => {
|
||||
expect(VCFormat.ldp_vc).toBe('ldp_vc');
|
||||
});
|
||||
|
||||
it('should have mso_mdoc format', () => {
|
||||
expect(VCFormat.mso_mdoc).toBe('mso_mdoc');
|
||||
});
|
||||
|
||||
it('should have vc_sd_jwt format', () => {
|
||||
expect(VCFormat.vc_sd_jwt).toBe('vc+sd-jwt');
|
||||
});
|
||||
|
||||
it('should have dc_sd_jwt format', () => {
|
||||
expect(VCFormat.dc_sd_jwt).toBe('dc+sd-jwt');
|
||||
});
|
||||
|
||||
it('should have exactly 4 formats', () => {
|
||||
const formatCount = Object.keys(VCFormat).length;
|
||||
expect(formatCount).toBe(4);
|
||||
});
|
||||
|
||||
it('should allow access via enum key', () => {
|
||||
expect(VCFormat['ldp_vc']).toBe('ldp_vc');
|
||||
expect(VCFormat['mso_mdoc']).toBe('mso_mdoc');
|
||||
expect(VCFormat['vc_sd_jwt']).toBe('vc+sd-jwt');
|
||||
expect(VCFormat['dc_sd_jwt']).toBe('dc+sd-jwt');
|
||||
});
|
||||
|
||||
it('should have all unique values', () => {
|
||||
const values = Object.values(VCFormat);
|
||||
const uniqueValues = new Set(values);
|
||||
expect(uniqueValues.size).toBe(values.length);
|
||||
});
|
||||
});
|
||||
499
shared/VCMetadata.test.ts
Normal file
499
shared/VCMetadata.test.ts
Normal file
@@ -0,0 +1,499 @@
|
||||
import {VCMetadata, parseMetadatas, getVCMetadata} from './VCMetadata';
|
||||
import {VCFormat} from './VCFormat';
|
||||
import {UUID} from './Utils';
|
||||
|
||||
describe('VCMetadata', () => {
|
||||
describe('constructor', () => {
|
||||
it('should create instance with default values', () => {
|
||||
const metadata = new VCMetadata();
|
||||
|
||||
expect(metadata.idType).toBe('');
|
||||
expect(metadata.requestId).toBe('');
|
||||
expect(metadata.isPinned).toBe(false);
|
||||
expect(metadata.id).toBe('');
|
||||
expect(metadata.issuer).toBe('');
|
||||
expect(metadata.protocol).toBe('');
|
||||
expect(metadata.timestamp).toBe('');
|
||||
expect(metadata.isVerified).toBe(false);
|
||||
expect(metadata.mosipIndividualId).toBe('');
|
||||
expect(metadata.format).toBe('');
|
||||
expect(metadata.isExpired).toBe(false);
|
||||
});
|
||||
|
||||
it('should create instance with provided values', () => {
|
||||
const metadata = new VCMetadata({
|
||||
idType: 'UIN',
|
||||
requestId: 'req123',
|
||||
isPinned: true,
|
||||
id: 'id123',
|
||||
issuer: 'TestIssuer',
|
||||
protocol: 'OpenId4VCI',
|
||||
timestamp: '2024-01-01',
|
||||
isVerified: true,
|
||||
mosipIndividualId: 'mosip123',
|
||||
format: 'ldp_vc',
|
||||
downloadKeyType: 'ED25519',
|
||||
isExpired: false,
|
||||
credentialType: 'NationalID',
|
||||
issuerHost: 'https://test.com',
|
||||
});
|
||||
|
||||
expect(metadata.idType).toBe('UIN');
|
||||
expect(metadata.requestId).toBe('req123');
|
||||
expect(metadata.isPinned).toBe(true);
|
||||
expect(metadata.id).toBe('id123');
|
||||
expect(metadata.issuer).toBe('TestIssuer');
|
||||
expect(metadata.protocol).toBe('OpenId4VCI');
|
||||
expect(metadata.timestamp).toBe('2024-01-01');
|
||||
expect(metadata.isVerified).toBe(true);
|
||||
expect(metadata.mosipIndividualId).toBe('mosip123');
|
||||
expect(metadata.format).toBe('ldp_vc');
|
||||
expect(metadata.downloadKeyType).toBe('ED25519');
|
||||
expect(metadata.isExpired).toBe(false);
|
||||
expect(metadata.credentialType).toBe('NationalID');
|
||||
expect(metadata.issuerHost).toBe('https://test.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromVC', () => {
|
||||
it('should create VCMetadata from VC object', () => {
|
||||
const vc = {
|
||||
idType: 'VID',
|
||||
requestId: 'req456',
|
||||
id: 'vc123',
|
||||
issuer: 'Issuer1',
|
||||
format: VCFormat.ldp_vc,
|
||||
};
|
||||
|
||||
const metadata = VCMetadata.fromVC(vc);
|
||||
|
||||
expect(metadata.idType).toBe('VID');
|
||||
expect(metadata.requestId).toBe('req456');
|
||||
expect(metadata.id).toBe('vc123');
|
||||
expect(metadata.issuer).toBe('Issuer1');
|
||||
expect(metadata.format).toBe(VCFormat.ldp_vc);
|
||||
});
|
||||
|
||||
it('should use default format if not provided', () => {
|
||||
const vc = {id: 'vc123'};
|
||||
const metadata = VCMetadata.fromVC(vc);
|
||||
|
||||
expect(metadata.format).toBe(VCFormat.ldp_vc);
|
||||
});
|
||||
|
||||
it('should handle isPinned default value', () => {
|
||||
const vc = {id: 'vc123'};
|
||||
const metadata = VCMetadata.fromVC(vc);
|
||||
|
||||
expect(metadata.isPinned).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fromVcMetadataString', () => {
|
||||
it('should parse JSON string to VCMetadata', () => {
|
||||
const jsonStr = JSON.stringify({
|
||||
id: 'vc123',
|
||||
issuer: 'TestIssuer',
|
||||
format: 'ldp_vc',
|
||||
});
|
||||
|
||||
const metadata = VCMetadata.fromVcMetadataString(jsonStr);
|
||||
|
||||
expect(metadata.id).toBe('vc123');
|
||||
expect(metadata.issuer).toBe('TestIssuer');
|
||||
expect(metadata.format).toBe('ldp_vc');
|
||||
});
|
||||
|
||||
it('should handle object input', () => {
|
||||
const obj = {
|
||||
id: 'vc456',
|
||||
issuer: 'AnotherIssuer',
|
||||
};
|
||||
|
||||
const metadata = VCMetadata.fromVcMetadataString(obj);
|
||||
|
||||
expect(metadata.id).toBe('vc456');
|
||||
expect(metadata.issuer).toBe('AnotherIssuer');
|
||||
});
|
||||
|
||||
it('should return empty VCMetadata on parse error', () => {
|
||||
const invalidJson = '{invalid json}';
|
||||
const metadata = VCMetadata.fromVcMetadataString(invalidJson);
|
||||
|
||||
expect(metadata).toBeInstanceOf(VCMetadata);
|
||||
expect(metadata.id).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isVCKey', () => {
|
||||
it('should return true for valid VC key', () => {
|
||||
expect(VCMetadata.isVCKey('VC_1234567890_abc123')).toBe(true);
|
||||
expect(VCMetadata.isVCKey('VC_timestamp_id')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for invalid VC key', () => {
|
||||
expect(VCMetadata.isVCKey('INVALID_KEY')).toBe(false);
|
||||
expect(VCMetadata.isVCKey('VC')).toBe(false);
|
||||
expect(VCMetadata.isVCKey('')).toBe(false);
|
||||
expect(VCMetadata.isVCKey('VC_')).toBe(false);
|
||||
});
|
||||
|
||||
it('should handle keys with special characters properly', () => {
|
||||
expect(VCMetadata.isVCKey('VC_123_abc-def')).toBe(true);
|
||||
expect(VCMetadata.isVCKey('VC_123_abc_def')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isFromOpenId4VCI', () => {
|
||||
it('should return true when protocol is OpenId4VCI', () => {
|
||||
const metadata = new VCMetadata({protocol: 'OpenId4VCI'});
|
||||
expect(metadata.isFromOpenId4VCI()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when protocol is not OpenId4VCI', () => {
|
||||
const metadata = new VCMetadata({protocol: 'OtherProtocol'});
|
||||
expect(metadata.isFromOpenId4VCI()).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when protocol is empty', () => {
|
||||
const metadata = new VCMetadata();
|
||||
expect(metadata.isFromOpenId4VCI()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVcKey', () => {
|
||||
it('should generate VC key with timestamp', () => {
|
||||
const metadata = new VCMetadata({
|
||||
timestamp: '1234567890',
|
||||
id: 'abc123',
|
||||
});
|
||||
|
||||
expect(metadata.getVcKey()).toBe('VC_1234567890_abc123');
|
||||
});
|
||||
|
||||
it('should generate VC key without timestamp', () => {
|
||||
const metadata = new VCMetadata({
|
||||
timestamp: '',
|
||||
id: 'xyz789',
|
||||
});
|
||||
|
||||
expect(metadata.getVcKey()).toBe('VC_xyz789');
|
||||
});
|
||||
|
||||
it('should match the VC key regex pattern', () => {
|
||||
const metadata = new VCMetadata({
|
||||
timestamp: '1234567890',
|
||||
id: 'test-id_123',
|
||||
});
|
||||
|
||||
const key = metadata.getVcKey();
|
||||
expect(VCMetadata.isVCKey(key)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('equals', () => {
|
||||
it('should return true for equal VCMetadata instances', () => {
|
||||
const metadata1 = new VCMetadata({
|
||||
timestamp: '1234567890',
|
||||
id: 'abc123',
|
||||
});
|
||||
const metadata2 = new VCMetadata({
|
||||
timestamp: '1234567890',
|
||||
id: 'abc123',
|
||||
});
|
||||
|
||||
expect(metadata1.equals(metadata2)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for different VCMetadata instances', () => {
|
||||
const metadata1 = new VCMetadata({
|
||||
timestamp: '1234567890',
|
||||
id: 'abc123',
|
||||
});
|
||||
const metadata2 = new VCMetadata({
|
||||
timestamp: '0987654321',
|
||||
id: 'xyz789',
|
||||
});
|
||||
|
||||
expect(metadata1.equals(metadata2)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when comparing instance with itself', () => {
|
||||
const metadata = new VCMetadata({
|
||||
timestamp: '1234567890',
|
||||
id: 'abc123',
|
||||
});
|
||||
|
||||
expect(metadata.equals(metadata)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('vcKeyRegExp', () => {
|
||||
it('should be defined as a RegExp', () => {
|
||||
expect(VCMetadata.vcKeyRegExp).toBeInstanceOf(RegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseMetadatas', () => {
|
||||
it('should be defined', () => {
|
||||
expect(parseMetadatas).toBeDefined();
|
||||
});
|
||||
|
||||
it('should parse array of metadata objects', () => {
|
||||
const metadataObjects = [
|
||||
{id: 'vc1', issuer: 'Issuer1'},
|
||||
{id: 'vc2', issuer: 'Issuer2'},
|
||||
{id: 'vc3', issuer: 'Issuer3'},
|
||||
];
|
||||
|
||||
const result = parseMetadatas(metadataObjects);
|
||||
|
||||
expect(result).toHaveLength(3);
|
||||
expect(result[0]).toBeInstanceOf(VCMetadata);
|
||||
expect(result[0].id).toBe('vc1');
|
||||
expect(result[1].id).toBe('vc2');
|
||||
expect(result[2].id).toBe('vc3');
|
||||
});
|
||||
|
||||
it('should handle empty array', () => {
|
||||
const result = parseMetadatas([]);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should create VCMetadata instances for each object', () => {
|
||||
const metadataObjects = [
|
||||
{id: 'test1', format: 'ldp_vc', isPinned: true},
|
||||
{id: 'test2', format: 'mso_mdoc', isPinned: false},
|
||||
];
|
||||
|
||||
const result = parseMetadatas(metadataObjects);
|
||||
|
||||
expect(result[0].id).toBe('test1');
|
||||
expect(result[0].format).toBe('ldp_vc');
|
||||
expect(result[0].isPinned).toBe(true);
|
||||
|
||||
expect(result[1].id).toBe('test2');
|
||||
expect(result[1].format).toBe('mso_mdoc');
|
||||
expect(result[1].isPinned).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVCMetadata', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(UUID, 'generate').mockReturnValue('test-uuid-12345');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should create VCMetadata with generated credential ID', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://issuer.example.com',
|
||||
issuer_id: 'TestIssuer',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '1234567890',
|
||||
vcMetadata: {
|
||||
isVerified: false,
|
||||
isExpired: false,
|
||||
},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {
|
||||
format: VCFormat.ldp_vc,
|
||||
},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'ED25519');
|
||||
|
||||
expect(result.requestId).toContain('test-uuid-12345');
|
||||
expect(result.requestId).toContain('issuer');
|
||||
expect(result.issuer).toBe('TestIssuer');
|
||||
expect(result.protocol).toBe('OpenId4VCI');
|
||||
expect(result.timestamp).toBe('1234567890');
|
||||
expect(result.downloadKeyType).toBe('ED25519');
|
||||
expect(result.format).toBe(VCFormat.ldp_vc);
|
||||
});
|
||||
|
||||
it('should handle credential_issuer when credential_issuer_host is not available', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer: 'https://backup.example.com',
|
||||
issuer_id: 'BackupIssuer',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {
|
||||
format: VCFormat.mso_mdoc,
|
||||
},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'RSA');
|
||||
|
||||
expect(result.issuer).toBe('BackupIssuer');
|
||||
expect(result.issuerHost).toBe('https://backup.example.com');
|
||||
expect(result.format).toBe(VCFormat.mso_mdoc);
|
||||
});
|
||||
|
||||
it('should use credential_issuer as fallback for issuer_id', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://issuer.test.com',
|
||||
credential_issuer: 'FallbackIssuer',
|
||||
protocol: 'OIDC',
|
||||
},
|
||||
timestamp: '9876543210',
|
||||
vcMetadata: {
|
||||
isVerified: true,
|
||||
isExpired: false,
|
||||
},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {
|
||||
format: VCFormat.vc_sd_jwt,
|
||||
},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'ECDSA');
|
||||
|
||||
expect(result.issuer).toBe('FallbackIssuer');
|
||||
expect(result.isVerified).toBe(true);
|
||||
expect(result.downloadKeyType).toBe('ECDSA');
|
||||
});
|
||||
|
||||
it('should extract issuer name from URL', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://subdomain.example.org',
|
||||
issuer_id: 'ExampleOrg',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {format: VCFormat.ldp_vc},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'ED25519');
|
||||
|
||||
expect(result.requestId).toContain('subdomain');
|
||||
});
|
||||
|
||||
it('should handle invalid URL gracefully', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'not-a-valid-url',
|
||||
issuer_id: 'TestIssuer',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {format: VCFormat.ldp_vc},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'ED25519');
|
||||
|
||||
expect(result.requestId).toContain('not-a-valid-url');
|
||||
expect(result.issuerHost).toBe('not-a-valid-url');
|
||||
});
|
||||
|
||||
it('should handle Mosip VC with UIN', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://mosip.example.com',
|
||||
issuer_id: 'Mosip',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: {
|
||||
credential: {
|
||||
credentialSubject: {
|
||||
UIN: '1234567890',
|
||||
},
|
||||
},
|
||||
},
|
||||
credentialWrapper: {format: VCFormat.ldp_vc},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'ED25519');
|
||||
|
||||
expect(result.mosipIndividualId).toBe('1234567890');
|
||||
});
|
||||
|
||||
it('should handle Mosip VC with VID', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://mosip.example.com',
|
||||
issuer_id: 'Mosip',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: {
|
||||
credential: {
|
||||
credentialSubject: {
|
||||
VID: '9876543210',
|
||||
},
|
||||
},
|
||||
},
|
||||
credentialWrapper: {format: VCFormat.ldp_vc},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'ED25519');
|
||||
|
||||
expect(result.mosipIndividualId).toBe('9876543210');
|
||||
});
|
||||
|
||||
it('should set credential type when provided', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://issuer.example.com',
|
||||
issuer_id: 'TestIssuer',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '1234567890',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {format: VCFormat.mso_mdoc},
|
||||
selectedCredentialType: 'org.iso.18013.5.1.mDL',
|
||||
};
|
||||
|
||||
const result = getVCMetadata(mockContext, 'RSA');
|
||||
|
||||
expect(result.credentialType).toBeDefined();
|
||||
expect(result.format).toBe(VCFormat.mso_mdoc);
|
||||
});
|
||||
|
||||
it('should handle different key types', () => {
|
||||
const mockContext: any = {
|
||||
selectedIssuer: {
|
||||
credential_issuer_host: 'https://issuer.example.com',
|
||||
issuer_id: 'TestIssuer',
|
||||
protocol: 'OpenId4VCI',
|
||||
},
|
||||
timestamp: '',
|
||||
vcMetadata: {},
|
||||
verifiableCredential: null,
|
||||
credentialWrapper: {format: VCFormat.vc_sd_jwt},
|
||||
selectedCredentialType: null,
|
||||
};
|
||||
|
||||
const resultRSA = getVCMetadata(mockContext, 'RS256');
|
||||
expect(resultRSA.downloadKeyType).toBe('RS256');
|
||||
|
||||
const resultEC = getVCMetadata(mockContext, 'ES256');
|
||||
expect(resultEC.downloadKeyType).toBe('ES256');
|
||||
});
|
||||
});
|
||||
216
shared/api.test.ts
Normal file
216
shared/api.test.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import {API_URLS} from './api';
|
||||
|
||||
describe('API_URLS configuration', () => {
|
||||
describe('trustedVerifiersList', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.trustedVerifiersList.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.trustedVerifiersList.buildURL()).toBe(
|
||||
'/v1/mimoto/verifiers',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('issuersList', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.issuersList.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.issuersList.buildURL()).toBe('/v1/mimoto/issuers');
|
||||
});
|
||||
});
|
||||
|
||||
describe('issuerConfig', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.issuerConfig.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL with issuer id', () => {
|
||||
expect(API_URLS.issuerConfig.buildURL('test-issuer')).toBe(
|
||||
'/v1/mimoto/issuers/test-issuer',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('issuerWellknownConfig', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.issuerWellknownConfig.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL with credential issuer', () => {
|
||||
expect(
|
||||
API_URLS.issuerWellknownConfig.buildURL('https://example.com'),
|
||||
).toBe('https://example.com/.well-known/openid-credential-issuer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('authorizationServerMetadataConfig', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.authorizationServerMetadataConfig.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL with authorization server URL', () => {
|
||||
expect(
|
||||
API_URLS.authorizationServerMetadataConfig.buildURL(
|
||||
'https://auth.example.com',
|
||||
),
|
||||
).toBe('https://auth.example.com/.well-known/oauth-authorization-server');
|
||||
});
|
||||
});
|
||||
|
||||
describe('allProperties', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.allProperties.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.allProperties.buildURL()).toBe(
|
||||
'/v1/mimoto/allProperties',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getIndividualId', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.getIndividualId.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.getIndividualId.buildURL()).toBe(
|
||||
'/v1/mimoto/aid/get-individual-id',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reqIndividualOTP', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.reqIndividualOTP.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.reqIndividualOTP.buildURL()).toBe(
|
||||
'/v1/mimoto/req/individualId/otp',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('walletBinding', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.walletBinding.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.walletBinding.buildURL()).toBe(
|
||||
'/v1/mimoto/wallet-binding',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bindingOtp', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.bindingOtp.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.bindingOtp.buildURL()).toBe('/v1/mimoto/binding-otp');
|
||||
});
|
||||
});
|
||||
|
||||
describe('requestOtp', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.requestOtp.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.requestOtp.buildURL()).toBe('/v1/mimoto/req/otp');
|
||||
});
|
||||
});
|
||||
|
||||
describe('credentialRequest', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.credentialRequest.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.credentialRequest.buildURL()).toBe(
|
||||
'/v1/mimoto/credentialshare/request',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credentialStatus', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.credentialStatus.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL with id', () => {
|
||||
expect(API_URLS.credentialStatus.buildURL('request-123')).toBe(
|
||||
'/v1/mimoto/credentialshare/request/status/request-123',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('credentialDownload', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.credentialDownload.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.credentialDownload.buildURL()).toBe(
|
||||
'/v1/mimoto/credentialshare/download',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('linkTransaction', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.linkTransaction.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.linkTransaction.buildURL()).toBe(
|
||||
'/v1/esignet/linked-authorization/v2/link-transaction',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('authenticate', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.authenticate.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.authenticate.buildURL()).toBe(
|
||||
'/v1/esignet/linked-authorization/v2/authenticate',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sendConsent', () => {
|
||||
it('should have POST method', () => {
|
||||
expect(API_URLS.sendConsent.method).toBe('POST');
|
||||
});
|
||||
|
||||
it('should build correct URL', () => {
|
||||
expect(API_URLS.sendConsent.buildURL()).toBe(
|
||||
'/v1/esignet/linked-authorization/v2/consent',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('googleAccountProfileInfo', () => {
|
||||
it('should have GET method', () => {
|
||||
expect(API_URLS.googleAccountProfileInfo.method).toBe('GET');
|
||||
});
|
||||
|
||||
it('should build correct URL with access token', () => {
|
||||
const accessToken = 'test-token-123';
|
||||
expect(API_URLS.googleAccountProfileInfo.buildURL(accessToken)).toBe(
|
||||
`https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=${accessToken}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,3 @@
|
||||
import {useState} from 'react';
|
||||
import testIDProps, {
|
||||
bytesToMB,
|
||||
faceMatchConfig,
|
||||
@@ -12,8 +11,20 @@ import testIDProps, {
|
||||
logState,
|
||||
removeWhiteSpace,
|
||||
sleep,
|
||||
getRandomInt,
|
||||
getMosipIdentifier,
|
||||
isTranslationKeyFound,
|
||||
getAccountType,
|
||||
BYTES_IN_MEGABYTE,
|
||||
} from './commonUtil';
|
||||
import {argon2iConfig} from './constants';
|
||||
import {
|
||||
argon2iConfig,
|
||||
GOOGLE_DRIVE_NAME,
|
||||
ICLOUD_DRIVE_NAME,
|
||||
GMAIL,
|
||||
APPLE,
|
||||
} from './constants';
|
||||
import {CredentialSubject} from '../machines/VerifiableCredential/VCMetaMachine/vc.d';
|
||||
|
||||
describe('hashData', () => {
|
||||
it('should expose a function', () => {
|
||||
@@ -74,6 +85,27 @@ describe('removeWhiteSpace', () => {
|
||||
const response = removeWhiteSpace('React Native Unit Testing');
|
||||
expect(response).toBe('ReactNativeUnitTesting');
|
||||
});
|
||||
|
||||
it('should handle empty string', () => {
|
||||
expect(removeWhiteSpace('')).toBe('');
|
||||
});
|
||||
|
||||
it('should handle string with only spaces', () => {
|
||||
expect(removeWhiteSpace(' ')).toBe('');
|
||||
});
|
||||
|
||||
it('should handle string with tabs and newlines', () => {
|
||||
expect(removeWhiteSpace('Hello\tWorld\n')).toBe('HelloWorld');
|
||||
});
|
||||
|
||||
it('should handle string with multiple types of whitespace', () => {
|
||||
expect(removeWhiteSpace(' Test \t String \n ')).toBe('TestString');
|
||||
});
|
||||
|
||||
it('should remove all whitespace from string', () => {
|
||||
const result = removeWhiteSpace('Hello World Test');
|
||||
expect(result).toBe('HelloWorldTest');
|
||||
});
|
||||
});
|
||||
|
||||
describe('logState', () => {
|
||||
@@ -97,17 +129,27 @@ describe('getMaskedText', () => {
|
||||
const maskedTxt = getMaskedText(id);
|
||||
expect(maskedTxt).toBe('******7890');
|
||||
});
|
||||
});
|
||||
|
||||
describe('faceMatchConfig', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(faceMatchConfig).toBeDefined();
|
||||
it('should handle exactly 4 characters', () => {
|
||||
expect(getMaskedText('1234')).toBe('1234');
|
||||
});
|
||||
|
||||
// it('faceMatchConfig should return expected output', () => {
|
||||
// // const retValue = faceMatchConfig(resp);
|
||||
// expect(false).toBeTruthy();
|
||||
// });
|
||||
it('should handle long strings', () => {
|
||||
const longString = '12345678901234567890';
|
||||
const masked = getMaskedText(longString);
|
||||
expect(masked.endsWith('7890')).toBe(true);
|
||||
expect(masked.length).toBe(longString.length);
|
||||
});
|
||||
|
||||
it('should handle short strings', () => {
|
||||
const result = getMaskedText('ABCDEF');
|
||||
expect(result).toBe('**CDEF');
|
||||
});
|
||||
|
||||
it('should handle exactly 4 characters (ABCD)', () => {
|
||||
const result = getMaskedText('ABCD');
|
||||
expect(result).toBe('ABCD');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBackupFileName', () => {
|
||||
@@ -116,26 +158,19 @@ describe('getBackupFileName', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('bytesToMB', () => {
|
||||
it('bytesToMB returns a string', () => {
|
||||
expect(bytesToMB(0)).toBe('0');
|
||||
});
|
||||
|
||||
it('10^6 bytes is 1MB', () => {
|
||||
expect(bytesToMB(1e6)).toBe('1.000');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDriveName', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(getDriveName).toBeDefined();
|
||||
});
|
||||
|
||||
it('getDriveName should return Google Drive on Android', () => {
|
||||
expect(getDriveName()).toBe('Google Drive');
|
||||
it('should return a string', () => {
|
||||
const result = getDriveName();
|
||||
expect(typeof result).toBe('string');
|
||||
});
|
||||
it('getDriveName should return Google Drive on Android', () => {
|
||||
expect(getDriveName()).toBe('Google Drive');
|
||||
|
||||
it('should return Google Drive for Android or iCloud for iOS', () => {
|
||||
const result = getDriveName();
|
||||
expect([GOOGLE_DRIVE_NAME, ICLOUD_DRIVE_NAME]).toContain(result);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -149,6 +184,19 @@ describe('sleep : The promise resolves after a certain time', () => {
|
||||
const promise = sleep(time);
|
||||
expect(promise).toBeInstanceOf(Promise);
|
||||
});
|
||||
|
||||
it('should delay for specified milliseconds', async () => {
|
||||
const start = Date.now();
|
||||
await sleep(100);
|
||||
const end = Date.now();
|
||||
const elapsed = end - start;
|
||||
expect(elapsed).toBeGreaterThanOrEqual(90); // Allow small margin
|
||||
});
|
||||
|
||||
it('should resolve after timeout', async () => {
|
||||
const promise = sleep(50);
|
||||
await expect(promise).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getScreenHeight', () => {
|
||||
@@ -160,4 +208,240 @@ describe('getScreenHeight', () => {
|
||||
const height = getScreenHeight();
|
||||
expect(typeof height).toBe('object');
|
||||
});
|
||||
|
||||
it('should return a value', () => {
|
||||
const height = getScreenHeight();
|
||||
expect(height).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getRandomInt', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(getRandomInt).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return a number within the specified range', () => {
|
||||
const min = 1;
|
||||
const max = 10;
|
||||
const result = getRandomInt(min, max);
|
||||
expect(result).toBeGreaterThanOrEqual(min);
|
||||
expect(result).toBeLessThanOrEqual(max);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return min when min and max are equal', () => {
|
||||
const value = 5;
|
||||
const result = getRandomInt(value, value);
|
||||
expect(result).toBe(value);
|
||||
});
|
||||
|
||||
it('should handle negative ranges', () => {
|
||||
const result = getRandomInt(-10, -1);
|
||||
expect(result).toBeGreaterThanOrEqual(-10);
|
||||
expect(result).toBeLessThanOrEqual(-1);
|
||||
});
|
||||
|
||||
it('should handle larger ranges', () => {
|
||||
const result = getRandomInt(100, 200);
|
||||
expect(result).toBeGreaterThanOrEqual(100);
|
||||
expect(result).toBeLessThanOrEqual(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMosipIdentifier', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(getMosipIdentifier).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return UIN when UIN is present', () => {
|
||||
const credentialSubject = {
|
||||
UIN: '123456789',
|
||||
VID: '987654321',
|
||||
} as Partial<CredentialSubject>;
|
||||
const result = getMosipIdentifier(credentialSubject as CredentialSubject);
|
||||
expect(result).toBe('123456789');
|
||||
});
|
||||
|
||||
it('should return VID when UIN is not present', () => {
|
||||
const credentialSubject = {VID: '987654321'} as Partial<CredentialSubject>;
|
||||
const result = getMosipIdentifier(credentialSubject as CredentialSubject);
|
||||
expect(result).toBe('987654321');
|
||||
});
|
||||
|
||||
it('should return undefined when neither UIN nor VID is present', () => {
|
||||
const credentialSubject = {} as Partial<CredentialSubject>;
|
||||
const result = getMosipIdentifier(credentialSubject as CredentialSubject);
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should prioritize UIN over VID', () => {
|
||||
const credSubject = {
|
||||
UIN: '1111111111',
|
||||
VID: '2222222222',
|
||||
} as CredentialSubject;
|
||||
expect(getMosipIdentifier(credSubject)).toBe('1111111111');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isTranslationKeyFound', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(isTranslationKeyFound).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return true when translation key is found', () => {
|
||||
const mockT = jest.fn(() => 'Translated text');
|
||||
const result = isTranslationKeyFound('someKey', mockT);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when translation key is not found', () => {
|
||||
const mockT = jest.fn((key: string) => key);
|
||||
const result = isTranslationKeyFound('someKey', mockT);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when key is translated', () => {
|
||||
const mockT = () => 'Translated value';
|
||||
expect(isTranslationKeyFound('any.key', mockT)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when translation key not found', () => {
|
||||
const mockT = (key: string) => key; // returns same key
|
||||
expect(isTranslationKeyFound('some.unknown.key', mockT)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true for errors.notFound key when translation is found', () => {
|
||||
const mockT = (key: string) => {
|
||||
if (key === 'errors.notFound') return 'Error Not Found';
|
||||
return key;
|
||||
};
|
||||
expect(isTranslationKeyFound('errors.notFound', mockT)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getAccountType', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(getAccountType).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return a string', () => {
|
||||
const result = getAccountType();
|
||||
expect(typeof result).toBe('string');
|
||||
});
|
||||
|
||||
it('should return Gmail for Android or Apple for iOS', () => {
|
||||
const result = getAccountType();
|
||||
expect([GMAIL, APPLE]).toContain(result);
|
||||
});
|
||||
});
|
||||
|
||||
describe('faceMatchConfig', () => {
|
||||
it('should expose a function', () => {
|
||||
expect(faceMatchConfig).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return a valid configuration object', () => {
|
||||
const config = faceMatchConfig();
|
||||
expect(config).toBeDefined();
|
||||
expect(config.withFace).toBeDefined();
|
||||
expect(config.withFace.encoder).toBeDefined();
|
||||
expect(config.withFace.matcher).toBeDefined();
|
||||
expect(config.withFace.encoder.tfModel).toBeDefined();
|
||||
expect(config.withFace.matcher.threshold).toBe(1);
|
||||
});
|
||||
|
||||
it('should return config with correct structure', () => {
|
||||
const config = faceMatchConfig();
|
||||
expect(config).toHaveProperty('withFace');
|
||||
expect(config.withFace).toHaveProperty('encoder');
|
||||
expect(config.withFace).toHaveProperty('matcher');
|
||||
expect(config.withFace.encoder.tfModel).toHaveProperty('path');
|
||||
expect(config.withFace.encoder.tfModel).toHaveProperty('modelChecksum');
|
||||
expect(config.withFace.matcher.threshold).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('BYTES_IN_MEGABYTE', () => {
|
||||
it('should be defined', () => {
|
||||
expect(BYTES_IN_MEGABYTE).toBeDefined();
|
||||
});
|
||||
|
||||
it('should equal 1,000,000', () => {
|
||||
expect(BYTES_IN_MEGABYTE).toBe(1000000);
|
||||
});
|
||||
|
||||
it('should be 1000 * 1000', () => {
|
||||
expect(BYTES_IN_MEGABYTE).toBe(1000 * 1000);
|
||||
});
|
||||
|
||||
it('should be a number', () => {
|
||||
expect(typeof BYTES_IN_MEGABYTE).toBe('number');
|
||||
});
|
||||
|
||||
it('should be positive', () => {
|
||||
expect(BYTES_IN_MEGABYTE).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bytesToMB', () => {
|
||||
it('bytesToMB returns a string', () => {
|
||||
expect(bytesToMB(0)).toBe('0');
|
||||
});
|
||||
|
||||
it('10^6 bytes is 1MB', () => {
|
||||
expect(bytesToMB(1e6)).toBe('1.000');
|
||||
});
|
||||
|
||||
it('should return "0" for negative bytes', () => {
|
||||
expect(bytesToMB(-100)).toBe('0');
|
||||
});
|
||||
|
||||
it('should convert 1,000,000 bytes to "1.000" MB', () => {
|
||||
expect(bytesToMB(1000000)).toBe('1.000');
|
||||
});
|
||||
|
||||
it('should convert 2,500,000 bytes to "2.500" MB', () => {
|
||||
expect(bytesToMB(2500000)).toBe('2.500');
|
||||
});
|
||||
|
||||
it('should convert 500,000 bytes to "0.500" MB', () => {
|
||||
expect(bytesToMB(500000)).toBe('0.500');
|
||||
});
|
||||
|
||||
it('should handle large byte values', () => {
|
||||
expect(bytesToMB(10000000)).toBe('10.000');
|
||||
});
|
||||
|
||||
it('should handle small byte values', () => {
|
||||
expect(bytesToMB(1000)).toBe('0.001');
|
||||
});
|
||||
|
||||
it('should return three decimal places', () => {
|
||||
const result = bytesToMB(1234567);
|
||||
expect(result).toMatch(/^\d+\.\d{3}$/);
|
||||
});
|
||||
|
||||
it('should handle fractional megabytes', () => {
|
||||
expect(bytesToMB(1234567)).toBe('1.235');
|
||||
});
|
||||
|
||||
it('should handle very small values', () => {
|
||||
expect(bytesToMB(100)).toBe('0.000');
|
||||
});
|
||||
|
||||
it('should handle exactly one byte', () => {
|
||||
expect(bytesToMB(1)).toBe('0.000');
|
||||
});
|
||||
|
||||
it('should convert bytes to megabytes', () => {
|
||||
const bytes = BYTES_IN_MEGABYTE * 5; // 5 MB
|
||||
const result = bytesToMB(bytes);
|
||||
expect(result).toBe('5.000');
|
||||
});
|
||||
|
||||
it('should handle fractional megabytes with BYTES_IN_MEGABYTE constant', () => {
|
||||
const bytes = BYTES_IN_MEGABYTE * 2.5;
|
||||
const result = bytesToMB(bytes);
|
||||
expect(result).toBe('2.500');
|
||||
});
|
||||
});
|
||||
|
||||
37
shared/cryptoutil/KeyTypes.test.ts
Normal file
37
shared/cryptoutil/KeyTypes.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import {KeyTypes} from './KeyTypes';
|
||||
|
||||
describe('KeyTypes', () => {
|
||||
it('should have RS256 key type', () => {
|
||||
expect(KeyTypes.RS256).toBe('RS256');
|
||||
});
|
||||
|
||||
it('should have ES256 key type', () => {
|
||||
expect(KeyTypes.ES256).toBe('ES256');
|
||||
});
|
||||
|
||||
it('should have ES256K key type', () => {
|
||||
expect(KeyTypes.ES256K).toBe('ES256K');
|
||||
});
|
||||
|
||||
it('should have ED25519 key type', () => {
|
||||
expect(KeyTypes.ED25519).toBe('Ed25519');
|
||||
});
|
||||
|
||||
it('should have exactly 4 key types', () => {
|
||||
const keyTypeCount = Object.keys(KeyTypes).length;
|
||||
expect(keyTypeCount).toBe(4);
|
||||
});
|
||||
|
||||
it('should allow access via enum key', () => {
|
||||
expect(KeyTypes['RS256']).toBe('RS256');
|
||||
expect(KeyTypes['ES256']).toBe('ES256');
|
||||
expect(KeyTypes['ES256K']).toBe('ES256K');
|
||||
expect(KeyTypes['ED25519']).toBe('Ed25519');
|
||||
});
|
||||
|
||||
it('should have all unique values', () => {
|
||||
const values = Object.values(KeyTypes);
|
||||
const uniqueValues = new Set(values);
|
||||
expect(uniqueValues.size).toBe(values.length);
|
||||
});
|
||||
});
|
||||
31
shared/error/BiometricCancellationError.test.ts
Normal file
31
shared/error/BiometricCancellationError.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {BiometricCancellationError} from './BiometricCancellationError';
|
||||
|
||||
describe('BiometricCancellationError', () => {
|
||||
it('should create an error instance with the correct message', () => {
|
||||
const errorMessage = 'User cancelled biometric authentication';
|
||||
const error = new BiometricCancellationError(errorMessage);
|
||||
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
expect(error).toBeInstanceOf(BiometricCancellationError);
|
||||
expect(error.message).toBe(errorMessage);
|
||||
});
|
||||
|
||||
it('should have the correct error name', () => {
|
||||
const error = new BiometricCancellationError('Test error');
|
||||
|
||||
expect(error.name).toBe('BiometricCancellationError');
|
||||
});
|
||||
|
||||
it('should maintain the error stack trace', () => {
|
||||
const error = new BiometricCancellationError('Stack trace test');
|
||||
|
||||
expect(error.stack).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle empty message', () => {
|
||||
const error = new BiometricCancellationError('');
|
||||
|
||||
expect(error.message).toBe('');
|
||||
expect(error.name).toBe('BiometricCancellationError');
|
||||
});
|
||||
});
|
||||
38
shared/error/UnsupportedVCFormat.test.ts
Normal file
38
shared/error/UnsupportedVCFormat.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import {UnsupportedVcFormat} from './UnsupportedVCFormat';
|
||||
|
||||
describe('UnsupportedVcFormat', () => {
|
||||
it('should create an error instance with the correct format message', () => {
|
||||
const format = 'jwt_vc_json';
|
||||
const error = new UnsupportedVcFormat(format);
|
||||
|
||||
expect(error).toBeInstanceOf(Error);
|
||||
expect(error).toBeInstanceOf(UnsupportedVcFormat);
|
||||
expect(error.message).toBe(format);
|
||||
});
|
||||
|
||||
it('should have the correct error name', () => {
|
||||
const error = new UnsupportedVcFormat('ldp_vc');
|
||||
|
||||
expect(error.name).toBe('UnsupportedVcFormat');
|
||||
});
|
||||
|
||||
it('should maintain the error stack trace', () => {
|
||||
const error = new UnsupportedVcFormat('custom_format');
|
||||
|
||||
expect(error.stack).toBeDefined();
|
||||
});
|
||||
|
||||
it('should handle empty format string', () => {
|
||||
const error = new UnsupportedVcFormat('');
|
||||
|
||||
expect(error.message).toBe('');
|
||||
expect(error.name).toBe('UnsupportedVcFormat');
|
||||
});
|
||||
|
||||
it('should handle complex format strings', () => {
|
||||
const format = 'application/vc+sd-jwt';
|
||||
const error = new UnsupportedVcFormat(format);
|
||||
|
||||
expect(error.message).toBe(format);
|
||||
});
|
||||
});
|
||||
73
shared/javascript.test.ts
Normal file
73
shared/javascript.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import {groupBy} from './javascript';
|
||||
|
||||
describe('javascript utils', () => {
|
||||
describe('groupBy', () => {
|
||||
it('should group elements based on predicate', () => {
|
||||
const array = [1, 2, 3, 4, 5, 6];
|
||||
const predicate = (num: number) => num % 2 === 0;
|
||||
|
||||
const [trueElements, falseElements] = groupBy(array, predicate);
|
||||
|
||||
expect(trueElements).toEqual([2, 4, 6]);
|
||||
expect(falseElements).toEqual([1, 3, 5]);
|
||||
});
|
||||
|
||||
it('should return empty arrays for empty input', () => {
|
||||
const array: number[] = [];
|
||||
const predicate = (num: number) => num > 0;
|
||||
|
||||
const [trueElements, falseElements] = groupBy(array, predicate);
|
||||
|
||||
expect(trueElements).toEqual([]);
|
||||
expect(falseElements).toEqual([]);
|
||||
});
|
||||
|
||||
it('should put all elements in true group when predicate always returns true', () => {
|
||||
const array = ['a', 'b', 'c'];
|
||||
const predicate = () => true;
|
||||
|
||||
const [trueElements, falseElements] = groupBy(array, predicate);
|
||||
|
||||
expect(trueElements).toEqual(['a', 'b', 'c']);
|
||||
expect(falseElements).toEqual([]);
|
||||
});
|
||||
|
||||
it('should put all elements in false group when predicate always returns false', () => {
|
||||
const array = ['a', 'b', 'c'];
|
||||
const predicate = () => false;
|
||||
|
||||
const [trueElements, falseElements] = groupBy(array, predicate);
|
||||
|
||||
expect(trueElements).toEqual([]);
|
||||
expect(falseElements).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should handle complex objects', () => {
|
||||
const array = [
|
||||
{name: 'John', age: 30},
|
||||
{name: 'Jane', age: 25},
|
||||
{name: 'Bob', age: 35},
|
||||
];
|
||||
const predicate = (person: {name: string; age: number}) =>
|
||||
person.age >= 30;
|
||||
|
||||
const [trueElements, falseElements] = groupBy(array, predicate);
|
||||
|
||||
expect(trueElements).toEqual([
|
||||
{name: 'John', age: 30},
|
||||
{name: 'Bob', age: 35},
|
||||
]);
|
||||
expect(falseElements).toEqual([{name: 'Jane', age: 25}]);
|
||||
});
|
||||
|
||||
it('should handle undefined array', () => {
|
||||
const array = undefined as any;
|
||||
const predicate = (num: number) => num > 0;
|
||||
|
||||
const [trueElements, falseElements] = groupBy(array, predicate);
|
||||
|
||||
expect(trueElements).toEqual([]);
|
||||
expect(falseElements).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
407
shared/openId4VCI/Utils.test.ts
Normal file
407
shared/openId4VCI/Utils.test.ts
Normal file
@@ -0,0 +1,407 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {
|
||||
Protocols,
|
||||
Issuers,
|
||||
isActivationNeeded,
|
||||
ACTIVATION_NEEDED,
|
||||
Issuers_Key_Ref,
|
||||
getDisplayObjectForCurrentLanguage,
|
||||
removeBottomSectionFields,
|
||||
getMatchingCredentialIssuerMetadata,
|
||||
selectCredentialRequestKey,
|
||||
updateCredentialInformation,
|
||||
} from './Utils';
|
||||
import {VCFormat} from '../VCFormat';
|
||||
|
||||
// Mock VCProcessor
|
||||
jest.mock('../../components/VC/common/VCProcessor', () => ({
|
||||
VCProcessor: {
|
||||
processForRendering: jest.fn().mockResolvedValue({
|
||||
processedData: 'mocked-processed-credential',
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('openId4VCI Utils', () => {
|
||||
describe('Protocols', () => {
|
||||
it('should have OpenId4VCI protocol defined', () => {
|
||||
expect(Protocols.OpenId4VCI).toBe('OpenId4VCI');
|
||||
});
|
||||
|
||||
it('should have OTP protocol defined', () => {
|
||||
expect(Protocols.OTP).toBe('OTP');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Issuers', () => {
|
||||
it('should have MosipOtp issuer defined', () => {
|
||||
expect(Issuers.MosipOtp).toBe('MosipOtp');
|
||||
});
|
||||
|
||||
it('should have Mosip issuer defined', () => {
|
||||
expect(Issuers.Mosip).toBe('Mosip');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ACTIVATION_NEEDED', () => {
|
||||
it('should contain Mosip', () => {
|
||||
expect(ACTIVATION_NEEDED).toContain(Issuers.Mosip);
|
||||
});
|
||||
|
||||
it('should contain MosipOtp', () => {
|
||||
expect(ACTIVATION_NEEDED).toContain(Issuers.MosipOtp);
|
||||
});
|
||||
|
||||
it('should have exactly 2 issuers', () => {
|
||||
expect(ACTIVATION_NEEDED).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isActivationNeeded', () => {
|
||||
it('should return true for Mosip issuer', () => {
|
||||
expect(isActivationNeeded('Mosip')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for MosipOtp issuer', () => {
|
||||
expect(isActivationNeeded('MosipOtp')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for other issuers', () => {
|
||||
expect(isActivationNeeded('SomeOtherIssuer')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for empty string', () => {
|
||||
expect(isActivationNeeded('')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for undefined', () => {
|
||||
expect(isActivationNeeded(undefined as any)).toBe(false);
|
||||
});
|
||||
|
||||
it('should be case sensitive', () => {
|
||||
expect(isActivationNeeded('mosip')).toBe(false);
|
||||
expect(isActivationNeeded('MOSIP')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Issuers_Key_Ref', () => {
|
||||
it('should have correct key reference', () => {
|
||||
expect(Issuers_Key_Ref).toBe('OpenId4VCI_KeyPair');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDisplayObjectForCurrentLanguage', () => {
|
||||
it('should return display object for current language', () => {
|
||||
const display = [
|
||||
{language: 'en', name: 'English Name', logo: 'en-logo.png'},
|
||||
{language: 'hi', name: 'Hindi Name', logo: 'hi-logo.png'},
|
||||
] as any;
|
||||
|
||||
const result = getDisplayObjectForCurrentLanguage(display);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.name).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return first display object when language not found', () => {
|
||||
const display = [
|
||||
{language: 'fr', name: 'French Name', logo: 'fr-logo.png'},
|
||||
{language: 'de', name: 'German Name', logo: 'de-logo.png'},
|
||||
] as any;
|
||||
|
||||
const result = getDisplayObjectForCurrentLanguage(display);
|
||||
expect(result).toBeDefined();
|
||||
expect(result.name).toBe('French Name');
|
||||
});
|
||||
|
||||
it('should return empty object when display array is empty', () => {
|
||||
const result = getDisplayObjectForCurrentLanguage([]);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('should return empty object when display is null', () => {
|
||||
const result = getDisplayObjectForCurrentLanguage(null as any);
|
||||
expect(result).toEqual({});
|
||||
});
|
||||
|
||||
it('should handle locale key instead of language key', () => {
|
||||
const display = [
|
||||
{locale: 'en-US', name: 'English Name', logo: 'en-logo.png'},
|
||||
{locale: 'hi-IN', name: 'Hindi Name', logo: 'hi-logo.png'},
|
||||
] as any;
|
||||
|
||||
const result = getDisplayObjectForCurrentLanguage(display);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
|
||||
it('should fallback to en-US when current language not found', () => {
|
||||
const display = [
|
||||
{language: 'fr', name: 'French Name'},
|
||||
{language: 'en-US', name: 'English US Name'},
|
||||
] as any;
|
||||
|
||||
const result = getDisplayObjectForCurrentLanguage(display);
|
||||
expect(result.name).toBe('English US Name');
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeBottomSectionFields', () => {
|
||||
it('should remove bottom section fields for SD-JWT format', () => {
|
||||
const fields = ['name', 'age', 'photo', 'signature', 'address'];
|
||||
const result = removeBottomSectionFields(fields, VCFormat.vc_sd_jwt);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove bottom section fields for DC-SD-JWT format', () => {
|
||||
const fields = ['name', 'age', 'photo', 'signature'];
|
||||
const result = removeBottomSectionFields(fields, VCFormat.dc_sd_jwt);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
});
|
||||
|
||||
it('should remove address field for LDP format', () => {
|
||||
const fields = ['name', 'age', 'address', 'photo'];
|
||||
const result = removeBottomSectionFields(fields, VCFormat.ldp_vc);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result).not.toContain('address');
|
||||
});
|
||||
|
||||
it('should handle empty fields array', () => {
|
||||
const result = removeBottomSectionFields([], VCFormat.ldp_vc);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMatchingCredentialIssuerMetadata', () => {
|
||||
it('should return matching credential configuration', () => {
|
||||
const wellknown = {
|
||||
credential_configurations_supported: {
|
||||
MOSIPVerifiableCredential: {
|
||||
format: 'ldp_vc',
|
||||
order: ['name', 'age'],
|
||||
},
|
||||
AnotherCredential: {
|
||||
format: 'jwt_vc',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = getMatchingCredentialIssuerMetadata(
|
||||
wellknown,
|
||||
'MOSIPVerifiableCredential',
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.format).toBe('ldp_vc');
|
||||
expect(result.order).toEqual(['name', 'age']);
|
||||
});
|
||||
|
||||
it('should throw error when credential type not found', () => {
|
||||
const wellknown = {
|
||||
credential_configurations_supported: {
|
||||
SomeCredential: {format: 'ldp_vc'},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
getMatchingCredentialIssuerMetadata(wellknown, 'NonExistentCredential');
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should handle multiple credential configurations', () => {
|
||||
const wellknown = {
|
||||
credential_configurations_supported: {
|
||||
Credential1: {format: 'ldp_vc'},
|
||||
Credential2: {format: 'jwt_vc'},
|
||||
Credential3: {format: 'mso_mdoc'},
|
||||
},
|
||||
};
|
||||
|
||||
const result = getMatchingCredentialIssuerMetadata(
|
||||
wellknown,
|
||||
'Credential2',
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.format).toBe('jwt_vc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('selectCredentialRequestKey', () => {
|
||||
it('should select first supported key type', () => {
|
||||
const proofSigningAlgos = ['RS256', 'ES256'];
|
||||
const keyOrder = {'0': 'RS256', '1': 'ES256', '2': 'Ed25519'};
|
||||
|
||||
const result = selectCredentialRequestKey(proofSigningAlgos, keyOrder);
|
||||
expect(result).toBe('RS256');
|
||||
});
|
||||
|
||||
it('should return first key when no match found', () => {
|
||||
const proofSigningAlgos = ['UNKNOWN_ALGO'];
|
||||
const keyOrder = {'0': 'RS256', '1': 'ES256'};
|
||||
|
||||
const result = selectCredentialRequestKey(proofSigningAlgos, keyOrder);
|
||||
expect(result).toBe('RS256');
|
||||
});
|
||||
|
||||
it('should handle empty proofSigningAlgos', () => {
|
||||
const keyOrder = {'0': 'RS256', '1': 'ES256'};
|
||||
|
||||
const result = selectCredentialRequestKey([], keyOrder);
|
||||
expect(result).toBe('RS256');
|
||||
});
|
||||
|
||||
it('should select matching key from middle of order', () => {
|
||||
const proofSigningAlgos = ['ES256'];
|
||||
const keyOrder = {'0': 'RS256', '1': 'ES256', '2': 'Ed25519'};
|
||||
|
||||
const result = selectCredentialRequestKey(proofSigningAlgos, keyOrder);
|
||||
expect(result).toBe('ES256');
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateCredentialInformation', () => {
|
||||
it('should update credential information for MSO_MDOC format', async () => {
|
||||
const mockContext = {
|
||||
selectedCredentialType: {
|
||||
id: 'TestCredential',
|
||||
format: VCFormat.mso_mdoc,
|
||||
},
|
||||
selectedIssuer: {
|
||||
display: [{language: 'en', logo: 'test-logo.png'}],
|
||||
},
|
||||
vcMetadata: {
|
||||
id: 'test-id',
|
||||
},
|
||||
};
|
||||
|
||||
const mockCredential = {
|
||||
credential: 'test-credential-data',
|
||||
} as any;
|
||||
|
||||
const result = await updateCredentialInformation(
|
||||
mockContext,
|
||||
mockCredential,
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.format).toBe(VCFormat.mso_mdoc);
|
||||
expect(result.verifiableCredential).toBeDefined();
|
||||
expect(result.verifiableCredential.credentialConfigurationId).toBe(
|
||||
'TestCredential',
|
||||
);
|
||||
expect(result.generatedOn).toBeInstanceOf(Date);
|
||||
});
|
||||
|
||||
it('should update credential information for SD-JWT format', async () => {
|
||||
const mockContext = {
|
||||
selectedCredentialType: {
|
||||
id: 'SDJWTCredential',
|
||||
format: VCFormat.vc_sd_jwt,
|
||||
},
|
||||
selectedIssuer: {
|
||||
display: [{language: 'en', logo: 'sd-jwt-logo.png'}],
|
||||
},
|
||||
vcMetadata: {
|
||||
id: 'sd-jwt-id',
|
||||
},
|
||||
};
|
||||
|
||||
const mockCredential = {
|
||||
credential: 'sd-jwt-credential-data',
|
||||
} as any;
|
||||
|
||||
const result = await updateCredentialInformation(
|
||||
mockContext,
|
||||
mockCredential,
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.format).toBe(VCFormat.vc_sd_jwt);
|
||||
expect(result.vcMetadata.format).toBe(VCFormat.vc_sd_jwt);
|
||||
});
|
||||
|
||||
it('should update credential information for DC-SD-JWT format', async () => {
|
||||
const mockContext = {
|
||||
selectedCredentialType: {
|
||||
id: 'DCSDJWTCredential',
|
||||
format: VCFormat.dc_sd_jwt,
|
||||
},
|
||||
selectedIssuer: {
|
||||
display: [{language: 'en', logo: 'dc-logo.png'}],
|
||||
},
|
||||
vcMetadata: {
|
||||
id: 'dc-jwt-id',
|
||||
},
|
||||
};
|
||||
|
||||
const mockCredential = {
|
||||
credential: 'dc-sd-jwt-credential-data',
|
||||
} as any;
|
||||
|
||||
const result = await updateCredentialInformation(
|
||||
mockContext,
|
||||
mockCredential,
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.format).toBe(VCFormat.dc_sd_jwt);
|
||||
});
|
||||
|
||||
it('should handle credential without logo in display', async () => {
|
||||
const mockContext = {
|
||||
selectedCredentialType: {
|
||||
id: 'NoLogoCredential',
|
||||
format: VCFormat.ldp_vc,
|
||||
},
|
||||
selectedIssuer: {
|
||||
display: [{language: 'en'}],
|
||||
},
|
||||
vcMetadata: {},
|
||||
};
|
||||
|
||||
const mockCredential = {
|
||||
credential: 'no-logo-credential',
|
||||
} as any;
|
||||
|
||||
const result = await updateCredentialInformation(
|
||||
mockContext,
|
||||
mockCredential,
|
||||
);
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.verifiableCredential.issuerLogo).toBe('');
|
||||
});
|
||||
|
||||
it('should include vcMetadata with format', async () => {
|
||||
const mockContext = {
|
||||
selectedCredentialType: {
|
||||
id: 'MetadataTest',
|
||||
format: VCFormat.ldp_vc,
|
||||
},
|
||||
selectedIssuer: {
|
||||
display: [],
|
||||
},
|
||||
vcMetadata: {
|
||||
id: 'metadata-id',
|
||||
},
|
||||
};
|
||||
|
||||
const mockCredential = {
|
||||
credential: 'metadata-test',
|
||||
} as any;
|
||||
|
||||
const result = await updateCredentialInformation(
|
||||
mockContext,
|
||||
mockCredential,
|
||||
);
|
||||
|
||||
expect(result.vcMetadata).toBeDefined();
|
||||
expect(result.vcMetadata.format).toBe(VCFormat.ldp_vc);
|
||||
expect(result.vcMetadata.id).toBe('metadata-id');
|
||||
});
|
||||
});
|
||||
});
|
||||
97
shared/sharing/imageUtils.test.ts
Normal file
97
shared/sharing/imageUtils.test.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {shareImageToAllSupportedApps} from './imageUtils';
|
||||
import RNShare from 'react-native-share';
|
||||
|
||||
jest.mock('react-native-share', () => ({
|
||||
open: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('imageUtils', () => {
|
||||
describe('shareImageToAllSupportedApps', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should return true when sharing is successful', async () => {
|
||||
const mockShareOptions = {
|
||||
url: 'file://path/to/image.jpg',
|
||||
type: 'image/jpeg',
|
||||
};
|
||||
|
||||
(RNShare.open as jest.Mock).mockResolvedValue({success: true});
|
||||
|
||||
const result = await shareImageToAllSupportedApps(mockShareOptions);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(RNShare.open).toHaveBeenCalledWith(mockShareOptions);
|
||||
});
|
||||
|
||||
it('should return false when sharing fails', async () => {
|
||||
const mockShareOptions = {
|
||||
url: 'file://path/to/image.jpg',
|
||||
type: 'image/jpeg',
|
||||
};
|
||||
|
||||
(RNShare.open as jest.Mock).mockResolvedValue({success: false});
|
||||
|
||||
const result = await shareImageToAllSupportedApps(mockShareOptions);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when an exception occurs', async () => {
|
||||
const mockShareOptions = {
|
||||
url: 'file://path/to/image.jpg',
|
||||
type: 'image/jpeg',
|
||||
};
|
||||
|
||||
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
||||
(RNShare.open as jest.Mock).mockRejectedValue(new Error('Share failed'));
|
||||
|
||||
const result = await shareImageToAllSupportedApps(mockShareOptions);
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||
'Exception while sharing image::',
|
||||
expect.any(Error),
|
||||
);
|
||||
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should handle different share options', async () => {
|
||||
const mockShareOptions = {
|
||||
url: 'file://path/to/qr-code.png',
|
||||
type: 'image/png',
|
||||
title: 'Share QR Code',
|
||||
};
|
||||
|
||||
(RNShare.open as jest.Mock).mockResolvedValue({success: true});
|
||||
|
||||
const result = await shareImageToAllSupportedApps(mockShareOptions);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(RNShare.open).toHaveBeenCalledWith(mockShareOptions);
|
||||
});
|
||||
|
||||
it('should handle user dismissing share dialog', async () => {
|
||||
const mockShareOptions = {
|
||||
url: 'file://path/to/image.jpg',
|
||||
};
|
||||
|
||||
(RNShare.open as jest.Mock).mockRejectedValue({
|
||||
message: 'User did not share',
|
||||
});
|
||||
|
||||
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
||||
const result = await shareImageToAllSupportedApps(mockShareOptions);
|
||||
|
||||
expect(result).toBe(false);
|
||||
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||
'Exception while sharing image::',
|
||||
expect.objectContaining({message: 'User did not share'}),
|
||||
);
|
||||
consoleErrorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user