otpcredential-helper.js (3601B)
1 // These tests rely on the User Agent providing an implementation of 2 // MockWebOTPService. 3 // 4 // In Chromium-based browsers this implementation is provided by a polyfill 5 // in order to reduce the amount of test-only code shipped to users. To enable 6 // these tests the browser must be run with these options: 7 // // --enable-blink-features=MojoJS,MojoJSTest 8 9 import {isChromiumBased} from '/resources/test-only-api.m.js'; 10 11 /** 12 * This enumeration is used by WebOTP WPTs to control mock backend behavior. 13 * See MockWebOTPService below. 14 */ 15 export const Status = { 16 SUCCESS: 0, 17 UNHANDLED_REQUEST: 1, 18 CANCELLED: 2, 19 ABORTED: 3, 20 }; 21 22 /** 23 * A interface which must be implemented by browsers to support WebOTP WPTs. 24 */ 25 export class MockWebOTPService { 26 /** 27 * Accepts a function to be invoked in response to the next OTP request 28 * received by the mock. The (optionally async) function, when executed, must 29 * return an object with a `status` field holding one of the `Status` values 30 * defined above, and -- if successful -- an `otp` field containing a 31 * simulated OTP string. 32 * 33 * Tests will call this method directly to inject specific response behavior 34 * into the browser-specific mock implementation. 35 */ 36 async handleNextOTPRequest(responseFunc) {} 37 } 38 39 /** 40 * Returns a Promise resolving to a browser-specific MockWebOTPService subclass 41 * instance if one is available. 42 */ 43 async function createBrowserSpecificMockImpl() { 44 if (isChromiumBased) { 45 return await createChromiumMockImpl(); 46 } 47 throw new Error('Unsupported browser.'); 48 } 49 50 const asyncMock = createBrowserSpecificMockImpl(); 51 52 export function expectOTPRequest() { 53 return { 54 async andReturn(callback) { 55 const mock = await asyncMock; 56 mock.handleNextOTPRequest(callback); 57 } 58 } 59 } 60 61 /** 62 * Instantiates a Chromium-specific subclass of MockWebOTPService. 63 */ 64 async function createChromiumMockImpl() { 65 const {SmsStatus, WebOTPService, WebOTPServiceReceiver} = await import( 66 '/gen/third_party/blink/public/mojom/sms/webotp_service.mojom.m.js'); 67 const MockWebOTPServiceChromium = class extends MockWebOTPService { 68 constructor() { 69 super(); 70 this.mojoReceiver_ = new WebOTPServiceReceiver(this); 71 this.interceptor_ = 72 new MojoInterfaceInterceptor(WebOTPService.$interfaceName); 73 this.interceptor_.oninterfacerequest = (e) => { 74 this.mojoReceiver_.$.bindHandle(e.handle); 75 }; 76 this.interceptor_.start(); 77 this.requestHandlers_ = []; 78 Object.freeze(this); 79 } 80 81 handleNextOTPRequest(responseFunc) { 82 this.requestHandlers_.push(responseFunc); 83 } 84 85 async receive() { 86 if (this.requestHandlers_.length == 0) { 87 throw new Error('Mock received unexpected OTP request.'); 88 } 89 90 const responseFunc = this.requestHandlers_.shift(); 91 const response = await responseFunc(); 92 switch (response.status) { 93 case Status.SUCCESS: 94 if (typeof response.otp != 'string') { 95 throw new Error('Mock success results require an OTP string.'); 96 } 97 return {status: SmsStatus.kSuccess, otp: response.otp}; 98 case Status.UNHANDLED_REQUEST: 99 return {status: SmsStatus.kUnhandledRequest}; 100 case Status.CANCELLED: 101 return {status: SmsStatus.kCancelled}; 102 case Status.ABORTED: 103 return {status: SmsStatus.kAborted}; 104 default: 105 throw new Error( 106 `Mock result contains unknown status: ${response.status}`); 107 } 108 } 109 110 async abort() {} 111 }; 112 return new MockWebOTPServiceChromium(); 113 }