diff --git a/packages/snaps-utils/coverage.json b/packages/snaps-utils/coverage.json index 7e74294584..76e026e3eb 100644 --- a/packages/snaps-utils/coverage.json +++ b/packages/snaps-utils/coverage.json @@ -1,6 +1,6 @@ { "branches": 99.74, - "functions": 98.91, + "functions": 98.92, "lines": 99.45, - "statements": 96.3 + "statements": 96.31 } diff --git a/packages/snaps-utils/src/snaps.test.ts b/packages/snaps-utils/src/snaps.test.ts index 20e642c690..17ceec4d31 100644 --- a/packages/snaps-utils/src/snaps.test.ts +++ b/packages/snaps-utils/src/snaps.test.ts @@ -14,9 +14,37 @@ import { assertIsValidSnapId, verifyRequestedSnapPermissions, stripSnapPrefix, + isSnapId, } from './snaps'; +import { MOCK_SNAP_ID } from './test-utils'; import { uri, WALLET_SNAP_PERMISSION_KEY } from './types'; +describe('isSnapId', () => { + it.each(['npm:@metamask/test-snap-bip44', 'local:http://localhost:8000'])( + 'returns `true` for "%s"', + (value) => { + expect(isSnapId(value)).toBe(true); + }, + ); + + it.each([ + undefined, + {}, + null, + true, + 2, + 'foo:bar', + ' local:http://localhost:8000', + 'local:http://localhost:8000 ', + 'local:http://localhost:8000\n', + 'local:http://localhost:8000\r', + 'local:😎', + 'local:␡', + ])('returns `false` for "%s"', (value) => { + expect(isSnapId(value)).toBe(false); + }); +}); + describe('assertIsValidSnapId', () => { it.each([undefined, {}, null, true, 2])( 'throws for non-strings (#%#)', @@ -239,7 +267,7 @@ describe('isSnapPermitted', () => { { type: 'snapIds', value: { - foo: {}, + [MOCK_SNAP_ID]: {}, }, }, ], @@ -273,9 +301,9 @@ describe('isSnapPermitted', () => { }, }; - expect(isSnapPermitted(validPermissions, 'foo')).toBe(true); - expect(isSnapPermitted(invalidPermissions1, 'foo')).toBe(false); - expect(isSnapPermitted(invalidPermissions2, 'foo')).toBe(false); + expect(isSnapPermitted(validPermissions, MOCK_SNAP_ID)).toBe(true); + expect(isSnapPermitted(invalidPermissions1, MOCK_SNAP_ID)).toBe(false); + expect(isSnapPermitted(invalidPermissions2, MOCK_SNAP_ID)).toBe(false); }); describe('verifyRequestedSnapPermissions', () => { diff --git a/packages/snaps-utils/src/snaps.ts b/packages/snaps-utils/src/snaps.ts index f3fe08967f..6ccd71fb97 100644 --- a/packages/snaps-utils/src/snaps.ts +++ b/packages/snaps-utils/src/snaps.ts @@ -7,6 +7,7 @@ import type { BlockReason } from '@metamask/snaps-registry'; import type { SnapId, Snap as TruncatedSnap } from '@metamask/snaps-sdk'; import type { Struct } from '@metamask/superstruct'; import { + is, empty, enums, intersection, @@ -311,6 +312,17 @@ export function stripSnapPrefix(snapId: string): string { return snapId.replace(getSnapPrefix(snapId), ''); } +/** + * Check if the given value is a valid snap ID. This function is a type guard, + * and will narrow the type of the value to `SnapId` if it returns `true`. + * + * @param value - The value to check. + * @returns `true` if the value is a valid snap ID, and `false` otherwise. + */ +export function isSnapId(value: unknown): value is SnapId { + return is(value, SnapIdStruct); +} + /** * Assert that the given value is a valid snap ID. *