Commit 80527764 authored by Ayu Ishii's avatar Ayu Ishii Committed by Commit Bot

WebOTP: Re-Add WPT from SMS Receiver API

This change re-adds wpt tests[1] from the former API iteration,
SMS Receiver API, to the new OTP Credential API version.
They were once deleted here[2], when cleaning up the previous
API interface.

[1]https://chromium.googlesource.com/chromium/src/+/26d14ef58e85c3826d4ca5cc0607efc49300b993/third_party/blink/web_tests/external/wpt/sms/interceptor.https.html
[2]https://chromium-review.googlesource.com/c/chromium/src/+/2097041

Change-Id: Ic1755c0a6fab4764bd3b0ab06c688f1cd4001d3a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2121466
Commit-Queue: Ayu Ishii <ayui@chromium.org>
Reviewed-by: default avatarVictor Costan <pwnall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#754258}
parent 52b12fca
<!DOCTYPE html>
<link rel="help" href="https://github.com/WICG/WebOTP">
<title>Tests OTPCredential</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./support/otpcredential-helper.js"></script>
<script>
'use strict';
promise_test(async t => {
await expect(receive).andReturn(async () => {
return {status: Status.kSuccess, otp: "ABC"};
});
let cred = await navigator.credentials.get({otp: {transport: ["sms"]}});
assert_equals(cred.code, "ABC");
}, 'Basic usage');
promise_test(async t => {
await expect(receive).andReturn(async () => {
return {status: Status.kSuccess, otp: "ABC"};
});
await expect(receive).andReturn(async () => {
return {status: Status.kSuccess, otp: "ABC2"};
});
let sms1 = navigator.credentials.get({otp: {transport: ["sms"]}});
let sms2 = navigator.credentials.get({otp: {transport: ["sms"]}});
let cred2= await sms2;
let cred1 = await sms1;
assert_equals(cred1.code, "ABC");
assert_equals(cred2.code, "ABC2");
}, 'Handle multiple requests in different order.');
promise_test(async t => {
await expect(receive).andReturn(async () => {
return {status: Status.kCancelled};
});
await expect(receive).andReturn(async () => {
return {status: Status.kSuccess, otp: "success"};
});
let cancelled_sms = navigator.credentials.get({otp: {transport: ["sms"]}});
let successful_sms = navigator.credentials.get({otp: {transport: ["sms"]}});
let successful_cred = await successful_sms;
assert_equals(successful_cred.code, "success");
try {
await cancelled_sms;
assert_unreached('Expected AbortError to be thrown.');
} catch (error) {
assert_equals(error.name, "AbortError");
}
}, 'Handle multiple requests with success and error.');
promise_test(async t => {
await expect(receive).andReturn(async () => {
return {status: Status.kCancelled};
});
await promise_rejects_dom(t, 'AbortError', navigator.credentials.get(
{otp: {transport: ["sms"]}}));
}, 'Deal with cancelled requests');
promise_test(async t => {
const controller = new AbortController();
const signal = controller.signal;
controller.abort();
await promise_rejects_dom(t, 'AbortError', navigator.credentials.get(
{otp: {transport: ["sms"]}, signal: signal}));
}, 'Should abort request');
</script>
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<div id=log>
<script>
'use strict';
const host = get_host_info();
const remoteBaseURL =
host.HTTPS_REMOTE_ORIGIN +
window.location.pathname.replace(/\/[^\/]*$/, '/');
const localBaseURL =
host.HTTPS_ORIGIN +
window.location.pathname.replace(/\/[^\/]*$/, '/');
promise_test(async t => {
const messageWatcher = new EventWatcher(t, window, "message");
var iframe = document.createElement("iframe");
iframe.src = localBaseURL + "support/otpcredential-iframe.html";
document.body.appendChild(iframe);
const message = await messageWatcher.wait_for("message");
assert_equals(message.data.result, "Pass");
assert_equals(message.data.code, "ABC123");
}, "Test OTPCredential enabled in same origin iframes");
promise_test(async t => {
const messageWatcher = new EventWatcher(t, window, "message");
var iframe = document.createElement("iframe");
iframe.src = remoteBaseURL + "support/otpcredential-iframe.html"
document.body.appendChild(iframe);
const message = await messageWatcher.wait_for("message");
assert_equals(message.data.result, "Fail");
assert_equals(message.data.errorType, "NotAllowedError");
}, "Test OTPCredential disabled in cross origin iframes");
</script>
# CredentialManagement Testing
## OTPCredential Testing
In this test suite `otpcredential-helper.js` is a testing framework that enables
engines to test OTPCredential by intercepting the connection between the browser
and the underlying operating system and mock its behavior.
Usage:
1. Include `<script src="./support/otpcredential-helper.js"></script>` in your
test
2. Set expectations
```
await expect(receive).andReturn(() => {
// mock behavior
})
```
3. Call `navigator.credentials.get({otp: {transport: ["sms"]}})`
4. Verify results
The mocking API is browser agnostic and is designed such that other engines
could implement it too.
Here are the symbols that are exposed to tests that need to be implemented
per engine:
- function receive(): the main/only function that can be mocked
- function expect(): the main/only function that enables us to mock it
- enum State {kSuccess, kTimeout}: allows you to mock success/failures
'use strict';
// These tests rely on the User Agent providing an implementation of
// the sms retriever.
//
// In Chromium-based browsers this implementation is provided by a polyfill
// in order to reduce the amount of test-only code shipped to users. To enable
// these tests the browser must be run with these options:
// // --enable-blink-features=MojoJS,MojoJSTest
async function loadChromiumResources() {
if (!window.MojoInterfaceInterceptor) {
// Do nothing on non-Chromium-based browsers or when the Mojo bindings are
// not present in the global namespace.
return;
}
const resources = [
'/gen/layout_test_data/mojo/public/js/mojo_bindings_lite.js',
'/gen/mojo/public/mojom/base/time.mojom-lite.js',
'/gen/third_party/blink/public/mojom/sms/sms_receiver.mojom-lite.js',
'/resources/chromium/mock-sms-receiver.js',
];
await Promise.all(resources.map(path => {
const script = document.createElement('script');
script.src = path;
script.async = false;
const promise = new Promise((resolve, reject) => {
script.onload = resolve;
script.onerror = reject;
});
document.head.appendChild(script);
return promise;
}));
Status.kSuccess = blink.mojom.SmsStatus.kSuccess;
Status.kTimeout = blink.mojom.SmsStatus.kTimeout;
Status.kCancelled = blink.mojom.SmsStatus.kCancelled;
};
const Status = {};
async function create_sms_provider() {
if (typeof SmsProvider === 'undefined') {
await loadChromiumResources();
}
if (typeof SmsProvider == 'undefined') {
throw new Error('Mojo testing interface is not available.');
}
return new SmsProvider();
}
function receive() {
throw new Error("expected to be overriden by tests");
}
function expect(call) {
return {
async andReturn(callback) {
const mock = await create_sms_provider();
mock.pushReturnValuesForTesting(call.name, callback);
}
}
}
<!doctype html>
<script src="./otpcredential-helper.js"></script>
<script>
'use strict';
// Loading otpcredential-iframe.html in the test will make an OTPCredentials
// call on load, and trigger a postMessage upon completion.
//
// message {
// string result: "Pass" | "Fail"
// string code: credentials.code
// string errorType: error.name
// }
// Intercept successful calls and return mocked value.
(async function() {
await expect(receive).andReturn(() => {
return Promise.resolve({
status: Status.kSuccess,
otp: "ABC123",
});
});
}());
window.onload = async () => {
try {
const credentials =
await navigator.credentials.get({otp: {transport: ["sms"]}});
window.parent.postMessage({result: "Pass", code: credentials.code}, '*');
} catch (error) {
window.parent.postMessage({result: "Fail", errorType: error.name}, '*');
}
}
</script>
...@@ -689,7 +689,7 @@ WEB-PLATFORM.TEST:web-bundle/resources/wbn/*.wbn ...@@ -689,7 +689,7 @@ WEB-PLATFORM.TEST:web-bundle/resources/wbn/*.wbn
# https://github.com/web-platform-tests/wpt/issues/16455 # https://github.com/web-platform-tests/wpt/issues/16455
# Please consult with ecosystem-infra@chromium.org before adding more. # Please consult with ecosystem-infra@chromium.org before adding more.
MISSING DEPENDENCY: idle-detection/interceptor.https.html MISSING DEPENDENCY: idle-detection/interceptor.https.html
MISSING DEPENDENCY: sms/resources/helper.js MISSING DEPENDENCY: credential-management/support/otpcredential-helper.js
MISSING DEPENDENCY: web-nfc/resources/nfc-helpers.js MISSING DEPENDENCY: web-nfc/resources/nfc-helpers.js
MISSING DEPENDENCY: shape-detection/resources/shapedetection-helpers.js MISSING DEPENDENCY: shape-detection/resources/shapedetection-helpers.js
MISSING DEPENDENCY: webxr/resources/webxr_util.js MISSING DEPENDENCY: webxr/resources/webxr_util.js
......
'use strict';
const SmsProvider = (() => {
class MockSmsReceiver {
constructor() {
this.mojoReceiver_ = new blink.mojom.SmsReceiverReceiver(this);
this.interceptor_ =
new MojoInterfaceInterceptor(blink.mojom.SmsReceiver.$interfaceName);
this.interceptor_.oninterfacerequest = (e) => {
this.mojoReceiver_.$.bindHandle(e.handle);
}
this.interceptor_.start();
this.returnValues_ = {};
}
async receive() {
let call = this.returnValues_.receive ?
this.returnValues_.receive.shift() : null;
if (!call)
return;
return call();
}
async abort() {};
pushReturnValuesForTesting(callName, value) {
this.returnValues_[callName] = this.returnValues_[callName] || [];
this.returnValues_[callName].push(value);
return this;
}
}
const mockSmsReceiver = new MockSmsReceiver();
class SmsProviderChromium {
constructor() {
Object.freeze(this); // Make it immutable.
}
pushReturnValuesForTesting(callName, callback) {
mockSmsReceiver.pushReturnValuesForTesting(callName, callback);
}
}
return SmsProviderChromium;
})();
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment