Skip to content

Commit

Permalink
add more tests, fix logic
Browse files Browse the repository at this point in the history
  • Loading branch information
hmalik88 committed Sep 13, 2024
1 parent 082292e commit 870f5de
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 17 deletions.
35 changes: 30 additions & 5 deletions packages/snaps-utils/src/ui.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,20 @@ describe('validateLink', () => {
expect(fn).not.toHaveBeenCalled();
});

it('throws an error if the snap being navigated to is not installed', () => {
const fn = jest.fn().mockReturnValue(false);

expect(() =>
validateLink(
'metamask://snap/npm:@metamask/examplesnap/home',
fn,
jest.fn().mockReturnValue(false),
),
).toThrow('The snap being navigated to is not installed.');

expect(fn).not.toHaveBeenCalled();
});

it('throws an error for an invalid URL', () => {
const fn = jest.fn().mockReturnValue(false);

Expand Down Expand Up @@ -658,29 +672,39 @@ describe('validateTextLinks', () => {

it('throws an error if an invalid link is found in text', () => {
expect(() =>
validateTextLinks('[test](http://foo.bar)', () => false),
validateTextLinks('[test](http://foo.bar)', () => false, jest.fn()),
).toThrow(
'Invalid URL: Protocol must be one of: https:, mailto:, metamask:.',
);

expect(() =>
validateTextLinks('[[test]](http://foo.bar)', () => false),
validateTextLinks('[[test]](http://foo.bar)', () => false, jest.fn()),
).toThrow(
'Invalid URL: Protocol must be one of: https:, mailto:, metamask:.',
);

expect(() => validateTextLinks('<http://foo.bar>', () => false)).toThrow(
expect(() =>
validateTextLinks('<http://foo.bar>', () => false, jest.fn()),
).toThrow(
'Invalid URL: Protocol must be one of: https:, mailto:, metamask:.',
);

expect(() =>
validateTextLinks('[test](http://foo.bar "foo bar baz")', () => false),
validateTextLinks(
'[test](http://foo.bar "foo bar baz")',
() => false,
jest.fn(),
),
).toThrow(
'Invalid URL: Protocol must be one of: https:, mailto:, metamask:.',
);

expect(() =>
validateTextLinks('[foo][1]\n\n[1]: http://foo.bar', () => false),
validateTextLinks(
'[foo][1]\n\n[1]: http://foo.bar',
() => false,
jest.fn(),
),
).toThrow(
'Invalid URL: Protocol must be one of: https:, mailto:, metamask:.',
);
Expand All @@ -689,6 +713,7 @@ describe('validateTextLinks', () => {
validateTextLinks(
`[foo][1]\n\n[1]: http://foo.bar "foo bar baz"`,
() => false,
jest.fn(),
),
).toThrow(
'Invalid URL: Protocol must be one of: https:, mailto:, metamask:.',
Expand Down
34 changes: 33 additions & 1 deletion packages/snaps-utils/src/url.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { parseMetaMaskUrl } from './url';
import { isMetaMaskUrl, METAMASK_URL_REGEX, parseMetaMaskUrl } from './url';

describe('METAMASK_URL_REGEX', () => {
it('will throw for non-metamask urls', () => {
expect('random:foobar'.match(METAMASK_URL_REGEX)).toBeNull();
});
});

describe('parseMetaMaskUrl', () => {
it('can parse a valid url with the client authority', () => {
Expand Down Expand Up @@ -28,6 +34,16 @@ describe('parseMetaMaskUrl', () => {
});
});

it('can parse a valid url with a local snap', () => {
expect(
parseMetaMaskUrl('metamask://snap/local:http://localhost:8080/home'),
).toStrictEqual({
authority: 'snap',
path: '/home',
snapId: 'local:http://localhost:8080',
});
});

it('will throw on an invalid scheme', () => {
expect(() => parseMetaMaskUrl('metmask://client/')).toThrow(
'Invalid MetaMask url.',
Expand All @@ -53,3 +69,19 @@ describe('parseMetaMaskUrl', () => {
);
});
});

describe('isMetaMaskUrl', () => {
it.each(['https://www.google.com', 'metamask://foo/'])(
'will return false for non-metamask urls',
(url) => {
expect(isMetaMaskUrl(url)).toBe(false);
},
);

it.each(['metamask://snap/home', 'metamask://client/'])(
'will not throw for valid metamask urls',
(url) => {
expect(isMetaMaskUrl(url)).toBe(true);
},
);
});
33 changes: 22 additions & 11 deletions packages/snaps-utils/src/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,40 @@ export function parseMetaMaskUrl(url: MetaMaskUrl): {
};
} else if (authority === 'snap') {
const strippedPath = stripSnapPrefix(path.slice(1));
const location = path.slice(1).startsWith('npm:') ? 'npm:' : 'local:';
const isNameSpaced = strippedPath.startsWith('@');
const pathTokens = strippedPath.split('/');
const lastPathToken = `/${pathTokens[pathTokens.length - 1]}`;
const partialSnapId = isNameSpaced
? `${pathTokens[0]}/${pathTokens[1]}`
: pathTokens[0];
const location = path.slice(1).startsWith('npm:') ? 'npm:' : 'local:';
let partialSnapId;
if (location === 'local:') {
partialSnapId = `http://${pathTokens[2]}`;
assert(
pathTokens.length === 4 && SnapPaths.includes(lastPathToken),
'Invalid snap path.',
);
} else {
partialSnapId = isNameSpaced
? `${pathTokens[0]}/${pathTokens[1]}`
: pathTokens[0];
assert(
isNameSpaced
? pathTokens.length === 3 && SnapPaths.includes(lastPathToken)
: pathTokens.length === 2 && SnapPaths.includes(lastPathToken),
'Invalid snap path.',
);
}
const snapId = `${location}${partialSnapId}`;
assertIsValidSnapId(snapId);
assert(
isNameSpaced
? pathTokens.length === 3 && SnapPaths.includes(lastPathToken)
: pathTokens.length === 2 && SnapPaths.includes(lastPathToken),
'Invalid snap path.',
);

return {
authority,
snapId,
path: lastPathToken,
};
}

// You don't ever actually reach this line, TS doesn't know that no other authority will make it past
// the regex statement
/* istanbul ignore next */
throw new Error('Invalid authority');
}

Expand Down

0 comments on commit 870f5de

Please sign in to comment.