[Sub apps] Gate add() on user activation

Apps should only be allowed to trigger sub-app-installation
on user activation, and only once (i.e. the activation should be consumed).

For testing, test_driver.bless provides the necessary user activation by adding a button and clicking it.

Bug: 1394390
Test: third_party/blink/tools/run_web_tests.py external/wpt/subapps
Change-Id: Ic49e8ad567aff668b325aeacbda6c903aabc56e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4111444
Commit-Queue: Philipp Weiß <phweiss@chromium.org>
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1085840}
diff --git a/subapps/add-error.tentative.https.html b/subapps/add-error.tentative.https.html
index 626c934..d049268 100644
--- a/subapps/add-error.tentative.https.html
+++ b/subapps/add-error.tentative.https.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
 <title>Sub Apps: Error cases for add()</title>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/subapps-helpers.js"></script>
@@ -52,11 +54,15 @@
   let install_options = {};
   install_options["install_url"] = wrong_origin_url;
   subapp[wrong_origin_url] = install_options;
-  await promise_rejects_dom(t, 'URLMismatchError', navigator.subApps.add(subapp));
+
+  await test_driver.bless("installing a subapp", async function () {
+    await promise_rejects_dom(t, 'URLMismatchError', navigator.subApps.add(subapp));
+  });
 }, 'Wrong origin URL argument.');
 
 promise_test(async t => {
   const same_origin_url = document.location.origin + '/sub-app';
+
   let add_call_params = {};
   let install_options = {};
   install_options["install_url"] = same_origin_url;
@@ -68,10 +74,22 @@
   let expected_results = {};
   expected_results[same_origin_url] = "expected-app-id-check-failed";
 
-  await subapps_add_expect_reject_with_result(t, add_call_params, mocked_response, expected_results);
+  await test_driver.bless("installing a subapp", async function () {
+    await subapps_add_expect_reject_with_result(t, add_call_params, mocked_response, expected_results);
+  });
 }, 'Service failed to add single sub-app.');
 
 promise_test(async t => {
+  const same_origin_url = document.location.origin + '/sub-app';
+
+  let subapp = {
+    [same_origin_url]: { install_url: same_origin_url }
+  };
+
+  await promise_rejects_dom(t, 'NotAllowedError', navigator.subApps.add(subapp));
+}, 'Missing user activation.');
+
+promise_test(async t => {
   let add_call_params = {};
 
   const url_1 = document.location.origin + '/sub-app-1';
@@ -92,7 +110,9 @@
   expected_results[url_1] = "expected-app-id-check-failed";
   expected_results[url_2] = "install-url-invalid";
 
-  await subapps_add_expect_reject_with_result(t, add_call_params, mocked_response, expected_results);
+  await test_driver.bless("installing a subapp", async function () {
+    await subapps_add_expect_reject_with_result(t, add_call_params, mocked_response, expected_results);
+  });
 }, 'Service failed to add two sub-apps.');
 
 promise_test(async t => {
@@ -116,6 +136,8 @@
   expected_results[url_1] = "success-new-install";
   expected_results[url_2] = "expected-app-id-check-failed";
 
-  await subapps_add_expect_reject_with_result(t, add_call_params, mocked_response, expected_results);
+  await test_driver.bless("installing a subapp", async function () {
+    await subapps_add_expect_reject_with_result(t, add_call_params, mocked_response, expected_results);
+  });
 }, 'Service added one sub-app failed to add another sub-app.');
 </script>
\ No newline at end of file
diff --git a/subapps/add-success.tentative.https.html b/subapps/add-success.tentative.https.html
index 1839b18..b2751ad 100644
--- a/subapps/add-success.tentative.https.html
+++ b/subapps/add-success.tentative.https.html
@@ -1,8 +1,11 @@
 <!DOCTYPE html>
 <title>Sub Apps: Valid calls for add()</title>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="resources/subapps-helpers.js"></script>
+
 <script>
 
 promise_test(async t => {
@@ -19,7 +22,9 @@
   let expected_results = {};
   expected_results[same_origin_url] = "success-new-install";
 
-  await subapps_add_expect_success_with_result(t, add_call_params, mocked_response, expected_results);
+  await test_driver.bless("installing a subapp", async function () {
+    await subapps_add_expect_success_with_result(t, add_call_params, mocked_response, expected_results);
+  });
 }, 'Add API call works with single sub app.');
 
 promise_test(async t => {
@@ -43,7 +48,10 @@
   expected_results[url_1] = "success-new-install";
   expected_results[url_2] = "success-new-install";
 
-  await subapps_add_expect_success_with_result(t, add_call_params, mocked_response, expected_results);
+
+  await test_driver.bless("installing a subapp", async function () {
+    await subapps_add_expect_success_with_result(t, add_call_params, mocked_response, expected_results);
+  });
 }, 'Add API call works with multiple sub apps.');
 
 </script>
\ No newline at end of file
diff --git a/subapps/resources/subapps-helpers.js b/subapps/resources/subapps-helpers.js
index 1d50c40..e923db0 100644
--- a/subapps/resources/subapps-helpers.js
+++ b/subapps/resources/subapps-helpers.js
@@ -90,9 +90,6 @@
 
   await createMockSubAppsService(Status.SUCCESS, mocked_response);
   await navigator.subApps.add(add_call_params)
-    .catch(e => {
-      assert_unreached("Should not have rejected.");
-    })
     .then(result => {
       for (const app_id in expected_results) {
         assert_own_property(result, app_id, "Return results are missing entry for subapp.")