diff options
author | Matthew Miller <matthew@millerti.me> | 2022-06-20 12:44:39 -0700 |
---|---|---|
committer | Matthew Miller <matthew@millerti.me> | 2022-06-20 12:44:39 -0700 |
commit | aa5b2e8f97e8948dff05c6444bf2262dcb43cbcf (patch) | |
tree | 57ed6c31279b850ce9cf2cca556cee26a79e86c6 /packages/browser/src/methods/startAuthentication.test.ts | |
parent | 803f96ca81fa113a23aa8243dfa438f2f778daa9 (diff) |
Add tests for conditional UI support
Diffstat (limited to 'packages/browser/src/methods/startAuthentication.test.ts')
-rw-r--r-- | packages/browser/src/methods/startAuthentication.test.ts | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/packages/browser/src/methods/startAuthentication.test.ts b/packages/browser/src/methods/startAuthentication.test.ts index 89a0938..6f1b87b 100644 --- a/packages/browser/src/methods/startAuthentication.test.ts +++ b/packages/browser/src/methods/startAuthentication.test.ts @@ -6,6 +6,7 @@ import { } from '@simplewebauthn/typescript-types'; import { browserSupportsWebauthn } from '../helpers/browserSupportsWebauthn'; +import { browserSupportsWebAuthnAutofill } from '../helpers/browserSupportsWebAuthnAutofill'; import utf8StringToBuffer from '../helpers/utf8StringToBuffer'; import bufferToBase64URLString from '../helpers/bufferToBase64URLString'; import { WebAuthnError } from '../helpers/structs'; @@ -15,9 +16,11 @@ import { webauthnAbortService } from '../helpers/webAuthnAbortService'; import { startAuthentication } from './startAuthentication'; jest.mock('../helpers/browserSupportsWebauthn'); +jest.mock('../helpers/browserSupportsWebAuthnAutofill'); const mockNavigatorGet = window.navigator.credentials.get as jest.Mock; const mockSupportsWebauthn = browserSupportsWebauthn as jest.Mock; +const mockSupportsAutofill = browserSupportsWebAuthnAutofill as jest.Mock; const mockAuthenticatorData = 'mockAuthenticatorData'; const mockClientDataJSON = 'mockClientDataJSON'; @@ -56,11 +59,13 @@ beforeEach(() => { }); mockSupportsWebauthn.mockReturnValue(true); + mockSupportsAutofill.mockResolvedValue(true); }); afterEach(() => { mockNavigatorGet.mockReset(); mockSupportsWebauthn.mockReset(); + mockSupportsAutofill.mockReset(); }); test('should convert options before passing to navigator.credentials.get(...)', async () => { @@ -231,6 +236,57 @@ test('should cancel an existing call when executed again', async () => { expect(abortSpy).toHaveBeenCalledTimes(1); }); +test('should set up autofill a.k.a. Conditional UI', async () => { + const opts: PublicKeyCredentialRequestOptionsJSON = { + ...goodOpts1, + allowCredentials: [ + { + ...goodOpts1.allowCredentials![0], + transports: ["cable"], + }, + ] + }; + document.body.innerHTML = ` + <form> + <label for="username">Username</label> + <input type="text" name="username" autocomplete="username webauthn" /> + <button type="submit">Submit</button> + </form> + `; + + await startAuthentication(opts, true); + + // The most important bit + expect(mockNavigatorGet.mock.calls[0][0].mediation).toEqual('conditional'); + // The latest version of https://github.com/w3c/webauthn/pull/1576 says allowCredentials should + // be an "empty list", as opposed to being undefined + expect(mockNavigatorGet.mock.calls[0][0].publicKey.allowCredentials).toBeDefined(); + expect(mockNavigatorGet.mock.calls[0][0].publicKey.allowCredentials.length).toEqual(0); +}); + +test('should throw error if autofill not supported', async () => { + mockSupportsAutofill.mockResolvedValue(false); + + const rejected = await expect(startAuthentication(goodOpts1, true)).rejects; + rejected.toThrow(Error); + rejected.toThrow(/does not support webauthn autofill/i); +}); + +test('should throw error if no acceptable <input> is found', async () => { + // <input> is missing "webauthn" from the autocomplete attribute + document.body.innerHTML = ` + <form> + <label for="username">Username</label> + <input type="text" name="username" autocomplete="username" /> + <button type="submit">Submit</button> + </form> + `; + + const rejected = await expect(startAuthentication(goodOpts1, true)).rejects; + rejected.toThrow(Error); + rejected.toThrow(/no <input>/i); +}); + describe('WebAuthnError', () => { describe('AbortError', () => { const AbortError = generateCustomError('AbortError'); |