From aa5b2e8f97e8948dff05c6444bf2262dcb43cbcf Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Mon, 20 Jun 2022 12:44:39 -0700 Subject: Add tests for conditional UI support --- .../__mocks__/browserSupportsWebAuthnAutofill.ts | 2 + .../src/methods/startAuthentication.test.ts | 56 ++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 packages/browser/src/helpers/__mocks__/browserSupportsWebAuthnAutofill.ts (limited to 'packages/browser/src') diff --git a/packages/browser/src/helpers/__mocks__/browserSupportsWebAuthnAutofill.ts b/packages/browser/src/helpers/__mocks__/browserSupportsWebAuthnAutofill.ts new file mode 100644 index 0000000..311b635 --- /dev/null +++ b/packages/browser/src/helpers/__mocks__/browserSupportsWebAuthnAutofill.ts @@ -0,0 +1,2 @@ +// We just need a simple mock so we can control whether this returns `true` or `false` +export const browserSupportsWebAuthnAutofill = jest.fn(); 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 = ` +
+ + + +
+ `; + + 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 is found', async () => { + // is missing "webauthn" from the autocomplete attribute + document.body.innerHTML = ` +
+ + + +
+ `; + + const rejected = await expect(startAuthentication(goodOpts1, true)).rejects; + rejected.toThrow(Error); + rejected.toThrow(/no /i); +}); + describe('WebAuthnError', () => { describe('AbortError', () => { const AbortError = generateCustomError('AbortError'); -- cgit v1.2.3