summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/web-share
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/web-share')
-rw-r--r--testing/web-platform/tests/web-share/META.yml5
-rw-r--r--testing/web-platform/tests/web-share/canShare-files.https.html40
-rw-r--r--testing/web-platform/tests/web-share/canShare-insecure.http.html16
-rw-r--r--testing/web-platform/tests/web-share/canShare.https.html159
-rw-r--r--testing/web-platform/tests/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html122
-rw-r--r--testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html27
-rw-r--r--testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html.headers1
-rw-r--r--testing/web-platform/tests/web-share/feature-policy-listed.html31
-rw-r--r--testing/web-platform/tests/web-share/idlharness.https.window.js17
-rw-r--r--testing/web-platform/tests/web-share/resources/blank.html2
-rw-r--r--testing/web-platform/tests/web-share/resources/manual-helper.js100
-rw-r--r--testing/web-platform/tests/web-share/resources/post-message.html35
-rw-r--r--testing/web-platform/tests/web-share/share-cancel-manual.https.html24
-rw-r--r--testing/web-platform/tests/web-share/share-consume-activation.https.html33
-rw-r--r--testing/web-platform/tests/web-share/share-empty.https.html54
-rw-r--r--testing/web-platform/tests/web-share/share-extra-argument-manual.https.html21
-rw-r--r--testing/web-platform/tests/web-share/share-extra-field-manual.https.html21
-rw-r--r--testing/web-platform/tests/web-share/share-files-manual.https.html30
-rw-r--r--testing/web-platform/tests/web-share/share-image-manual.tentative.https.html26
-rw-r--r--testing/web-platform/tests/web-share/share-non-string-manual.https.html23
-rw-r--r--testing/web-platform/tests/web-share/share-null-manual.https.html22
-rw-r--r--testing/web-platform/tests/web-share/share-securecontext.http.html17
-rw-r--r--testing/web-platform/tests/web-share/share-sharePromise-internal-slot.https.html38
-rw-r--r--testing/web-platform/tests/web-share/share-simple-manual.https.html28
-rw-r--r--testing/web-platform/tests/web-share/share-unicode-strings-manual.https.html25
-rw-r--r--testing/web-platform/tests/web-share/share-unicode-strings-nonutf8-manual.https.html27
-rw-r--r--testing/web-platform/tests/web-share/share-url-empty-manual.https.html18
-rw-r--r--testing/web-platform/tests/web-share/share-url-encoding-manual.https.html22
-rw-r--r--testing/web-platform/tests/web-share/share-url-invalid.https.html76
-rw-r--r--testing/web-platform/tests/web-share/share-url-noscheme-manual.https.html19
-rw-r--r--testing/web-platform/tests/web-share/share-url-pathonly-manual.https.html19
-rw-r--r--testing/web-platform/tests/web-share/share-url-relative-manual.https.html20
-rw-r--r--testing/web-platform/tests/web-share/share-without-user-gesture.https.html19
-rw-r--r--testing/web-platform/tests/web-share/test-fully-active.https.html77
34 files changed, 1214 insertions, 0 deletions
diff --git a/testing/web-platform/tests/web-share/META.yml b/testing/web-platform/tests/web-share/META.yml
new file mode 100644
index 0000000000..d2eccca6f4
--- /dev/null
+++ b/testing/web-platform/tests/web-share/META.yml
@@ -0,0 +1,5 @@
+spec: https://w3c.github.io/web-share/
+suggested_reviewers:
+ - ewilligers
+ - mgiuca
+ - marcoscaceres
diff --git a/testing/web-platform/tests/web-share/canShare-files.https.html b/testing/web-platform/tests/web-share/canShare-files.https.html
new file mode 100644
index 0000000000..2c2f2ff969
--- /dev/null
+++ b/testing/web-platform/tests/web-share/canShare-files.https.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: canShare with files</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+ const textFile = new File(['hello'], 'hello.txt', {type:'text/plain'});
+ const emptyFile = new File([''], 'empty');
+
+ test(() => {
+ assert_throws_js(TypeError, () => { navigator.canShare({files: textFile}) });
+ }, 'canShare with single file');
+
+ test(() => {
+ assert_equals(navigator.canShare({files: []}), false);
+ }, 'canShare with empty file list');
+
+ test(() => {
+ assert_equals(navigator.canShare({files: [emptyFile]}), true);
+ }, 'canShare with single file list');
+
+ test(() => {
+ assert_equals(navigator.canShare({files: [textFile, emptyFile]}), true);
+ }, 'canShare with file list');
+
+ test(() => {
+ assert_equals(navigator.canShare({files: [textFile, emptyFile, textFile]}), true);
+ }, 'canShare with repeated file');
+
+ test(() => {
+ assert_equals(navigator.canShare({url: 'https://example.com/', files: [textFile, emptyFile]}), true);
+ }, 'canShare with file list and url');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/canShare-insecure.http.html b/testing/web-platform/tests/web-share/canShare-insecure.http.html
new file mode 100644
index 0000000000..ce81c7c0c8
--- /dev/null
+++ b/testing/web-platform/tests/web-share/canShare-insecure.http.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: canShare from non-secure context</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ test(() => {
+ assert_false('canShare' in navigator, 'navigator has attribute \'canShare\'.');
+ }, 'navigator.canShare must be undefined in non-secure context');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/canShare.https.html b/testing/web-platform/tests/web-share/canShare.https.html
new file mode 100644
index 0000000000..f0aed9a244
--- /dev/null
+++ b/testing/web-platform/tests/web-share/canShare.https.html
@@ -0,0 +1,159 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: canShare method tests</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ test(() => {
+ assert_false(
+ navigator.canShare(),
+ "no arguments (uses default argument value, which is empty dictionary)"
+ );
+
+ assert_false(navigator.canShare({}), "empty dictionary not allowed");
+
+ assert_false(navigator.canShare(undefined), "empty dictionary not allowed");
+
+ assert_false(navigator.canShare(null), "empty dictionary not allowed");
+
+ assert_false(
+ navigator.canShare({ unused: "unexpected field" }),
+ "results in empty dictionary, which is not allowed"
+ );
+ }, "canShare() empty and default dictionary");
+
+ test(() => {
+ assert_true(navigator.canShare({ url: "http://a.b" }), "http URL is ok");
+
+ assert_true(navigator.canShare({ url: "https://a.b" }), "https URL is ok");
+
+ assert_false(
+ navigator.canShare({ url: "http://a.b:65536" }),
+ "URL is invalid"
+ );
+
+ assert_false(
+ navigator.canShare({ url: "data:the url" }),
+ "data URL is not allowed"
+ );
+
+ assert_false(
+ navigator.canShare({ url: "file:///usr/" }),
+ "file URL is not allowed"
+ );
+
+ assert_true(
+ navigator.canShare({
+ url: "https://a.b/path?query#fragment",
+ }),
+ "canShare with URL"
+ );
+
+ assert_true(
+ navigator.canShare({
+ url: {
+ toString() {
+ return "https://a.b/";
+ },
+ },
+ }),
+ "canShare URL as with object with stringifier"
+ );
+
+ assert_true(
+ navigator.canShare(
+ { url: "" },
+ "canShare with empty URL, which resolves as the doc's base URL"
+ )
+ );
+
+ assert_true(
+ navigator.canShare({
+ url: "//a.b/path?query#fragment",
+ }),
+ "canShare with URL having no scheme"
+ );
+
+ assert_true(
+ navigator.canShare({
+ url: "relative",
+ }),
+ "canShare relative URL, resolved against API base URL"
+ );
+ }, "canShare() url member");
+
+ test(() => {
+ assert_false(
+ navigator.canShare({ title: undefined }),
+ "canShare with attribute undefined is equivalent to omitting the attribute"
+ );
+
+ assert_true(navigator.canShare({ title: "subject" }), "canShare with title");
+
+ assert_true(navigator.canShare({ title: null }), "stringified null");
+ }, "canShare() title member");
+
+ test(() => {
+ assert_true(navigator.canShare({ text: "" }), "ok to share empty text");
+
+ assert_true(
+ navigator.canShare({ text: "some text 🤔" }),
+ "ok to share unicode"
+ );
+
+ assert_true(navigator.canShare({ text: 123 }), "number is stringified");
+ }, "canShare() text member");
+
+ test(() => {
+ const file = new File(["hello"], "file", { type: "text/plain" });
+ const file2 = new File([], "file2");
+
+ assert_false(navigator.canShare({ files: [] }), "empty list is not allowed");
+
+ assert_false(
+ navigator.canShare({
+ url: "https://a.b:800000",
+ files: [file, file2],
+ }),
+ "invalid URL invalidates the share"
+ );
+
+ assert_true(
+ navigator.canShare({ files: [file] }),
+ "single file is ok to share"
+ );
+
+ assert_true(
+ navigator.canShare({ files: [file, file2, file] }),
+ "repeated files is ok to share"
+ );
+
+ assert_true(
+ navigator.canShare({
+ files: [file, file2],
+ text: "some texts",
+ url: "https://example.com/",
+ }),
+ "is ok to share files, text, and url together"
+ );
+ }, "canShare() files member");
+
+ test(() => {
+ assert_true(
+ navigator.canShare({
+ title: "subject",
+ text: "body",
+ url: "https://a.b/",
+ files: [new File([], "file")],
+ unused: "unexpected field",
+ }),
+ "canShare with unexpected field"
+ );
+ }, "canShare() multiple members");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html b/testing/web-platform/tests/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html
new file mode 100644
index 0000000000..773da84c0c
--- /dev/null
+++ b/testing/web-platform/tests/web-share/disabled-by-permissions-policy-cross-origin.https.sub.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: is disabled by permissions policy cross-origin</title>
+ <link
+ rel="help"
+ href="https://w3c.github.io/web-share/#permissions-policy"
+ />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body></body>
+ <script>
+ const crossOrigin = "https://{{hosts[alt][]}}:{{ports[https][0]}}";
+ const sameOriginPath = "/web-share/resources/post-message.html";
+ const crossOriginSrc = `${crossOrigin}${sameOriginPath}`;
+ const shareData = {
+ title: "WebShare Test",
+ text: "This is a test of the Web Share API",
+ url: "https://example.com/",
+ };
+
+ function waitForMessage(message) {
+ return new Promise((resolve) => {
+ window.addEventListener("message", function listener(event) {
+ if (event.data.action !== message) return;
+ window.removeEventListener("message", listener);
+ resolve(event.data);
+ });
+ });
+ }
+
+ async function loadIframe(t, src, allowList) {
+ const iframe = document.createElement("iframe");
+ if (allowList !== undefined) iframe.allow = allowList;
+ t.add_cleanup(() => {
+ iframe.remove();
+ });
+ await new Promise((resolve) => {
+ iframe.src = src;
+ document.body.appendChild(iframe);
+ iframe.onload = resolve;
+ });
+ await waitForMessage("loaded");
+ return iframe;
+ }
+
+ promise_test(async (t) => {
+ assert_true("share" in navigator, "navigator.share is exposed");
+ const iframe = await loadIframe(t, crossOriginSrc);
+ const iframeWindow = iframe.contentWindow;
+ iframeWindow.postMessage({ action: "share", data: shareData }, "*");
+ const data = await waitForMessage("share");
+ assert_equals(data.result, "error");
+ assert_equals(data.error, "NotAllowedError");
+ }, "share() is disabled by default 'self' by permissions policy for cross-origin iframes");
+
+ promise_test(async (t) => {
+ assert_true("share" in navigator, "navigator.share is exposed");
+ const iframe = await loadIframe(t, crossOriginSrc, "web-share 'none'");
+ const iframeWindow = iframe.contentWindow;
+ iframeWindow.postMessage({ action: "share", data: shareData }, "*");
+ const data = await waitForMessage("share");
+ assert_equals(data.result, "error");
+ assert_equals(data.error, "NotAllowedError");
+ }, "share() is disabled explicitly by permissions policy for cross-origin iframe");
+
+ promise_test(async (t) => {
+ assert_true("share" in navigator, "navigator.share is exposed");
+ const iframe = await loadIframe(t, crossOriginSrc, "web-share 'self'");
+ const iframeWindow = iframe.contentWindow;
+ iframeWindow.postMessage({ action: "share", data: shareData }, "*");
+ const data = await waitForMessage("share");
+ assert_equals(data.result, "error");
+ assert_equals(data.error, "NotAllowedError");
+ }, "share() not allowed, as only allowed to share with self");
+
+ promise_test(async (t) => {
+ assert_true("canShare" in navigator, "navigator.canShare is exposed");
+ const iframe = await loadIframe(t, crossOriginSrc);
+ const iframeWindow = iframe.contentWindow;
+ iframeWindow.postMessage({ action: "canShare", data: shareData }, "*");
+ const data = await waitForMessage("canShare");
+ assert_equals(data.result, false, "Expected false, as it can't share.");
+ }, "canShare() not allowed to share by default permissions policy cross-origin");
+
+ promise_test(async (t) => {
+ assert_true("canShare" in navigator, "navigator.canShare is exposed");
+ const iframe = await loadIframe(
+ t,
+ crossOriginSrc,
+ `web-share ${crossOrigin}`
+ );
+ iframe.contentWindow.postMessage(
+ { action: "canShare", data: shareData },
+ "*"
+ );
+ const data = await waitForMessage("canShare");
+ assert_equals(
+ data.result,
+ true,
+ `Expected true, is it can now share on ${origin}.`
+ );
+ }, "canShare() is allowed by permissions policy to share cross-origin on a particular origin");
+
+ promise_test(async (t) => {
+ assert_true("canShare" in navigator, "navigator.canShare is exposed");
+ const iframe = await loadIframe(t, sameOriginPath, "web-share 'self'");
+ iframe.contentWindow.postMessage(
+ { action: "canShare", data: shareData },
+ "*"
+ );
+ const data = await waitForMessage("canShare");
+ assert_equals(
+ data.result,
+ true,
+ "Expected true, at it can share with self."
+ );
+ }, "canShare() with self");
+ </script>
+</html>
diff --git a/testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html b/testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html
new file mode 100644
index 0000000000..e9ea903965
--- /dev/null
+++ b/testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: Can be disabled by permissions policy</title>
+ <link rel="help" href="https://w3c.github.io/web-share/#permissions-policy">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <script>
+ promise_test(async (t) => {
+ await test_driver.bless("web share");
+ await promise_rejects_dom(t, "NotAllowedError", navigator.share({}));
+ }, "share() can be disabled by permissions policy");
+
+ test((t) => {
+ assert_false(
+ navigator.canShare({ text: "foo" }),
+ "not allowed to share"
+ );
+ }, "canShare() can be disabled by permissions policy");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html.headers b/testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html.headers
new file mode 100644
index 0000000000..83f5a343fa
--- /dev/null
+++ b/testing/web-platform/tests/web-share/disabled-by-permissions-policy.https.sub.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: web-share=()
diff --git a/testing/web-platform/tests/web-share/feature-policy-listed.html b/testing/web-platform/tests/web-share/feature-policy-listed.html
new file mode 100644
index 0000000000..127498dde1
--- /dev/null
+++ b/testing/web-platform/tests/web-share/feature-policy-listed.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: policy is listed</title>
+ <link rel="help" href="https://w3c.github.io/web-share/#permissions-policy">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ 'use strict';
+
+ test(() => {
+ assert_true(document.featurePolicy.allowsFeature('web-share'));
+ }, 'allowsFeature() returns true for web-share');
+
+ test(() => {
+ assert_true(document.featurePolicy.features().includes('web-share'));
+ }, 'features() includes web-share');
+
+ test(() => {
+ assert_true(document.featurePolicy.allowedFeatures().includes('web-share'));
+ }, 'allowedFeatures() includes web-share');
+
+ test(() => {
+ assert_equals(Array.from(document.featurePolicy.getAllowlistForFeature('web-share')).length, 1);
+ }, 'allowsFeature() returns a single entry for web-share');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/idlharness.https.window.js b/testing/web-platform/tests/web-share/idlharness.https.window.js
new file mode 100644
index 0000000000..fbe59864af
--- /dev/null
+++ b/testing/web-platform/tests/web-share/idlharness.https.window.js
@@ -0,0 +1,17 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+// https://w3c.github.io/web-share/
+
+'use strict';
+
+idl_test(
+ ['web-share'],
+ ['html'],
+ idl_array => {
+ idl_array.add_objects({
+ Navigator: ['navigator']
+ });
+ }
+);
diff --git a/testing/web-platform/tests/web-share/resources/blank.html b/testing/web-platform/tests/web-share/resources/blank.html
new file mode 100644
index 0000000000..84f43b333a
--- /dev/null
+++ b/testing/web-platform/tests/web-share/resources/blank.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
diff --git a/testing/web-platform/tests/web-share/resources/manual-helper.js b/testing/web-platform/tests/web-share/resources/manual-helper.js
new file mode 100644
index 0000000000..15bb17936e
--- /dev/null
+++ b/testing/web-platform/tests/web-share/resources/manual-helper.js
@@ -0,0 +1,100 @@
+// Internal function. Returns [instruction, list] DOM elements.
+function setupManualShareTestCommon() {
+ const div = document.createElement('div');
+ document.body.appendChild(div);
+
+ const instruction = document.createElement('div');
+ instruction.id = 'instruction';
+ div.appendChild(instruction);
+
+ const shareButton = document.createElement('input');
+ shareButton.id = 'share_button';
+ shareButton.value = 'Share button';
+ shareButton.type = 'button';
+ div.appendChild(shareButton);
+
+ let heading = document.createElement('h2');
+ heading.innerText = 'Instructions:';
+ instruction.appendChild(heading);
+ let list = document.createElement('ol');
+ instruction.appendChild(list);
+ let item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = 'Click the Share button.';
+
+ return [instruction, list];
+}
+
+// Sets up the page for running manual tests. Automatically creates the
+// instructions (based on the parameters) and the share button.
+function setupManualShareTest(expected_share_data) {
+ const {title, text, url, files} = expected_share_data;
+ let [instruction, list] = setupManualShareTestCommon();
+ let item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = 'Choose a valid share target.';
+
+ heading = document.createElement('h2');
+ heading.innerText = 'Pass the test iff the target app received:';
+ instruction.appendChild(heading);
+
+ list = document.createElement('ul');
+ instruction.appendChild(list);
+
+ item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = `title = "${title}"`;
+ item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = `text = "${text}"`;
+ item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = `url = "${url}"`;
+ if (files) {
+ item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = `files = ${files.length} file(s)`;
+ for (let file of files) {
+ const div = document.createElement('div');
+ if (file.type.startsWith('text/')) {
+ const reader = new FileReader();
+ reader.onload = () => {
+ div.textContent = reader.result;
+ };
+ reader.readAsText(file);
+ } else if (file.type.startsWith('image/')) {
+ const image = document.createElement('img');
+ image.src = URL.createObjectURL(file);
+ image.alt = file.name;
+ div.appendChild(image);
+ }
+ item.appendChild(div);
+ }
+ }
+}
+
+function setupManualShareTestRequiringCancellation() {
+ const [instruction, list] = setupManualShareTestCommon();
+ const item = document.createElement('li');
+ list.appendChild(item);
+ item.innerText = 'Cancel the share dialog.';
+}
+
+// Returns a promise. When the user clicks the button, calls
+// |click_handler| and resolves the promise with the result.
+function callWhenButtonClicked(click_handler) {
+ return new Promise((resolve, reject) => {
+ document.querySelector('#share_button').onclick = () => {
+ try {
+ const result = click_handler();
+ resolve(result);
+ } catch (e) {
+ reject(e);
+ }
+ };
+ });
+}
+
+function getAbsoluteUrl(url) {
+ return new URL(url, document.baseURI).toString();
+}
diff --git a/testing/web-platform/tests/web-share/resources/post-message.html b/testing/web-platform/tests/web-share/resources/post-message.html
new file mode 100644
index 0000000000..30134e2901
--- /dev/null
+++ b/testing/web-platform/tests/web-share/resources/post-message.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script>
+ window.addEventListener("message", async (event) => {
+ const {
+ data: { action, data },
+ } = event;
+ const response = {};
+ try {
+ switch (action) {
+ case "share":
+ await test_driver.bless("share");
+ await navigator.share(data);
+ response.result = "unreached";
+ break;
+ case "canShare":
+ response.result = navigator.canShare(data);
+ break;
+ }
+ } catch (error) {
+ response.result = "error";
+ response.error = error.name;
+ } finally {
+ event.source.postMessage({ ...response, action }, "*");
+ }
+ });
+
+ // send message to parent that we loaded
+ function sendLoadMessage() {
+ window.parent.postMessage({ action: "loaded" }, "*");
+ }
+</script>
+<body onload="sendLoadMessage()"></body>
diff --git a/testing/web-platform/tests/web-share/share-cancel-manual.https.html b/testing/web-platform/tests/web-share/share-cancel-manual.https.html
new file mode 100644
index 0000000000..e27d1975be
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-cancel-manual.https.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share cancelled by user</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ setupManualShareTestRequiringCancellation();
+
+ promise_test(t => {
+ return callWhenButtonClicked(() => promise_rejects_dom(
+ t, 'AbortError',
+ navigator.share({title: 'the title', text: 'the message',
+ url: 'https://example.com'})));
+ }, 'share with user cancellation');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-consume-activation.https.html b/testing/web-platform/tests/web-share/share-consume-activation.https.html
new file mode 100644
index 0000000000..301469f83d
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-consume-activation.https.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: consume user activation</title>
+ <link rel="help" href="https://w3c.github.io/web-share/#share-method">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <script>
+ promise_test(async t => {
+ // Not activated by user gesture, so not allowed!
+ await promise_rejects_dom(t, "NotAllowedError", navigator.share());
+
+ await test_driver.bless("web share");
+
+ // We have a gesture, but the URL is invalid - so TypeError!
+ await promise_rejects_js(
+ t,
+ TypeError,
+ navigator.share({ url: "http://example.com:65536" })
+ );
+
+ // The activation has been consumed, so calling share() again would require
+ // a new gesture.
+ await promise_rejects_dom(t, "NotAllowedError", navigator.share());
+ }, "Calling share consumes user activation");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-empty.https.html b/testing/web-platform/tests/web-share/share-empty.https.html
new file mode 100644
index 0000000000..0bca2f2960
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-empty.https.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: Share no known fields</title>
+ <link rel="help" href="https://w3c.github.io/web-share/#share-method">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <script>
+ promise_test(async t => {
+ await test_driver.bless("web share", () => {
+ return promise_rejects_js(t, TypeError, navigator.share());
+ });
+ }, "share with no arguments (same as empty dictionary)");
+
+ promise_test(async t => {
+ await test_driver.bless("web share", () => {
+ return promise_rejects_js(t, TypeError, navigator.share({}));
+ });
+ }, "share with an empty dictionary");
+
+ promise_test(async t => {
+ await test_driver.bless("web share", () => {
+ return promise_rejects_js(t, TypeError, navigator.share(undefined));
+ });
+ }, "share with a undefined argument (same as empty dictionary)");
+
+ promise_test(async t => {
+ await test_driver.bless("web share", () => {
+ return promise_rejects_js(t, TypeError, navigator.share(null));
+ });
+ }, "share with a null argument (same as empty dictionary)");
+
+ promise_test(async t => {
+ await test_driver.bless("web share", () => {
+ return promise_rejects_js(
+ t,
+ TypeError,
+ navigator.share({ unused: "unexpected field" })
+ );
+ });
+ }, "share with a dictionary containing only surplus fields");
+
+ promise_test(async t => {
+ await test_driver.bless("web share");
+ await promise_rejects_js(t, TypeError, navigator.share({ files: [] }));
+ }, "share with an empty files member")
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-extra-argument-manual.https.html b/testing/web-platform/tests/web-share/share-extra-argument-manual.https.html
new file mode 100644
index 0000000000..47ef7fa115
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-extra-argument-manual.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Surplus arguments ignored</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ setupManualShareTest(
+ {title: 'the title', text: 'the message', url: 'https://example.com'});
+ callWhenButtonClicked(() => navigator.share(
+ {title: 'the title', text: 'the message', url: 'https://example.com'},
+ 'more than required'));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-extra-field-manual.https.html b/testing/web-platform/tests/web-share/share-extra-field-manual.https.html
new file mode 100644
index 0000000000..8b479bb02b
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-extra-field-manual.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Surplus fields ignored</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ setupManualShareTest(
+ {title: 'the title', text: 'the message', url: 'https://example.com'});
+ callWhenButtonClicked(() => navigator.share(
+ {title: 'the title', text: 'the message', url: 'https://example.com',
+ unused: 'unexpected field'}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-files-manual.https.html b/testing/web-platform/tests/web-share/share-files-manual.https.html
new file mode 100644
index 0000000000..c3941bb406
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-files-manual.https.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share multiple files</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const options = {type: 'text/plain'};
+ const first = new File(['one'], 'first.txt', options);
+ const second = new File(['two'], 'second.txt', options);
+ const third = new File(['three'], 'third.txt', options);
+ const fourth = new File(['four'], 'fourth.txt', options);
+ const fifth = new File(['five'], 'fifth.txt', options);
+ const data = {
+ title: 'Counting to 5',
+ text: 'Here are the numbers',
+ url: 'https://example.com/',
+ files: [first, second, third, fourth, fifth]
+ };
+ setupManualShareTest(data);
+ callWhenButtonClicked(() => navigator.share(data));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-image-manual.tentative.https.html b/testing/web-platform/tests/web-share/share-image-manual.tentative.https.html
new file mode 100644
index 0000000000..48ea4c378c
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-image-manual.tentative.https.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share single image file</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const fileBits = [
+ '<svg xmlns="http://www.w3.org/2000/svg" width="80px" height="80px">',
+ '<circle cx="40" cy="40" r="28" fill="lime" />',
+ '</svg>'
+ ];
+ const fileName = 'circle.svg';
+ const options = {type: 'image/svg+xml'};
+ const file = new File(fileBits, fileName, options);
+ setupManualShareTest({title: '', text: '', url: '', files: [file]});
+ callWhenButtonClicked(() => navigator.share({files: [file]}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-non-string-manual.https.html b/testing/web-platform/tests/web-share/share-non-string-manual.https.html
new file mode 100644
index 0000000000..b70f8fc23d
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-non-string-manual.https.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share non-string types (test implicit conversion)</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ // Expect that each of the non-string values is converted into a string.
+ setupManualShareTest(
+ {title: 'true', text: 'the object', url: getAbsoluteUrl('384957')});
+
+ const objectWithToString = {toString() { return 'the object'; }};
+ callWhenButtonClicked(() => navigator.share(
+ {title: true, text: objectWithToString, url: 384957}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-null-manual.https.html b/testing/web-platform/tests/web-share/share-null-manual.https.html
new file mode 100644
index 0000000000..4c74225cbe
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-null-manual.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share null and undefined values</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ // Expect null to be converted into the string 'null'. On the other
+ // hand, undefined should be equivalent to omitting the attribute.
+ setupManualShareTest(
+ {title: 'null', text: '', url: getAbsoluteUrl('null')});
+ callWhenButtonClicked(() => navigator.share(
+ {title: null, text: undefined, url: null}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-securecontext.http.html b/testing/web-platform/tests/web-share/share-securecontext.http.html
new file mode 100644
index 0000000000..6344330c6b
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-securecontext.http.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share from non-secure context</title>
+ <link rel="help" href="https://w3c.github.io/web-share/#extensions-to-the-navigator-interface">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ test(() => {
+ assert_false('share' in navigator, 'navigator has attribute \'share\'.');
+ }, 'navigator.share must be undefined in non-secure context');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-sharePromise-internal-slot.https.html b/testing/web-platform/tests/web-share/share-sharePromise-internal-slot.https.html
new file mode 100644
index 0000000000..eb8bf7e4c7
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-sharePromise-internal-slot.https.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <link rel="help" href="https://github.com/w3c/web-share/pull/113" />
+ <title>WebShare Test: only one share at a time</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <button>
+ <script>
+ setup({ allow_uncaught_exception:true });
+ promise_test(async t => {
+ const button = document.querySelector("button");
+ const p = new Promise(r => {
+ button.onclick = () => {
+ const promises = [];
+ promises.push(
+ navigator.share({ title: "should be pending" }),
+ navigator.share({ title: "should reject" }),
+ navigator.share({ title: "should also reject" })
+ );
+ r(promises);
+ };
+ });
+ test_driver.click(button);
+ const [, promise2, promise3] = await p;
+ await Promise.all([
+ promise_rejects_dom(t, "InvalidStateError", promise2),
+ promise_rejects_dom(t, "InvalidStateError", promise3)
+ ]);
+ }, "Only allow one share call at a time, which is controlled by the [[sharePromise]] internal slot.");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-simple-manual.https.html b/testing/web-platform/tests/web-share/share-simple-manual.https.html
new file mode 100644
index 0000000000..d4a1f9b1c8
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-simple-manual.https.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Simple share</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const url = 'https://www.example.com/some/path?some_query#some_fragment';
+ const data = {title: 'the title', text: 'the message', url, files: []};
+ setupManualShareTest(data);
+ callWhenButtonClicked(() => navigator.share(data)).then(
+ result => {
+ // Check that promise resolved with undefined. This is guarded
+ // by an if statement because we do not want it to register as a
+ // test if it passes (since this is a manual test).
+ if (result !== undefined) {
+ assert_equals(result, undefined);
+ }
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-unicode-strings-manual.https.html b/testing/web-platform/tests/web-share/share-unicode-strings-manual.https.html
new file mode 100644
index 0000000000..8cdaa87de7
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-unicode-strings-manual.https.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share with non-ASCII Unicode strings</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ // Title is a string with BMP and non-BMP characters.
+ // Text contains invalid surrogates which should be converted into U+FFFD.
+ // URL contains non-ASCII characters in host and path.
+ const title = 'fáncy 写作 😱';
+ const url = 'https://测试.example.com/📄';
+ // Host is IDNA-encoded. Path is percent-encoded.
+ const url_ascii = 'https://xn--0zwm56d.example.com/%F0%9F%93%84';
+ setupManualShareTest({title, text: '\ufffdx', url: url_ascii});
+ callWhenButtonClicked(() => navigator.share({title, text: '\ud9a3x', url}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-unicode-strings-nonutf8-manual.https.html b/testing/web-platform/tests/web-share/share-unicode-strings-nonutf8-manual.https.html
new file mode 100644
index 0000000000..deabec3def
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-unicode-strings-nonutf8-manual.https.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="windows-1252">
+ <title>WebShare Test: Share with non-ASCII Unicode strings in a Latin-1-encoded page</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ assert_equals(document.characterSet, 'windows-1252');
+
+ // Exact same test as in share-unicode-strings-manual.html, with same
+ // expectations. This tests that the page's encoding (ISO-8859-1) is
+ // ignored and Unicode characters are always percent-encoded in UTF-8.
+ const title = 'f\xe1ncy \u5199\u4f5c \ud83d\ude31';
+ const url = 'https://\u6d4b\u8bd5.example.com/\ud83d\udcc4';
+ // Host is IDNA-encoded. Path is percent-encoded with UTF-8.
+ const url_ascii = 'https://xn--0zwm56d.example.com/%F0%9F%93%84';
+ setupManualShareTest({title, text: '\ufffdx', url: url_ascii});
+ callWhenButtonClicked(() => navigator.share({title, text: '\ud9a3x', url}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-url-empty-manual.https.html b/testing/web-platform/tests/web-share/share-url-empty-manual.https.html
new file mode 100644
index 0000000000..4038dab8cf
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-url-empty-manual.https.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share with empty URL</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ setupManualShareTest({title: '', text: '', url: document.baseURI});
+ callWhenButtonClicked(() => navigator.share({url: ''}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-url-encoding-manual.https.html b/testing/web-platform/tests/web-share/share-url-encoding-manual.https.html
new file mode 100644
index 0000000000..0f03b5a8b7
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-url-encoding-manual.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share URL with illegal characters (test percent encoding)</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const url = 'http://example.com/foo\\ab%63\r\n\t "<>`{}';
+ // Expect '\' to normalize to '/', "%63" to normalize to 'c', '\r\n\t'
+ // to be removed, and all the other illegal characters to be percent-escaped.
+ const url_encoded = 'http://example.com/foo/abc%20%22%3C%3E%60%7B%7D';
+ setupManualShareTest({title: '', text: '', url: url_encoded});
+ callWhenButtonClicked(() => navigator.share({url}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-url-invalid.https.html b/testing/web-platform/tests/web-share/share-url-invalid.https.html
new file mode 100644
index 0000000000..cb76458c24
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-url-invalid.https.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: Share with an invalid URL</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <script>
+ promise_test(async t => {
+ await test_driver.bless();
+ const promise = navigator.share({ url: "http://a.com:65536" });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects when URL is invalid");
+
+ promise_test(async t => {
+ await test_driver.bless();
+ const promise = navigator.share({ url: "file:///etc/passwd" });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects file:// URLs");
+
+ promise_test(async t => {
+ await test_driver.bless();
+ const promise = navigator.share({ url: "wss://a.com/" });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects wss: URLs");
+
+ promise_test(async t => {
+ await test_driver.bless();
+ const promise = navigator.share({ url: "about:config" });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects about: URLs");
+
+ promise_test(async t => {
+ await test_driver.bless();
+ const promise = navigator.share({ url: "chrome://about" });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects chrome: URLs");
+
+ promise_test(async t => {
+ await test_driver.bless();
+ const promise = navigator.share({ url: "javascript:window.alert('error')" });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects javascript: URLs");
+
+ promise_test(async t => {
+ await test_driver.bless();
+ const file = new File([], "text/plain");
+ const promise = navigator.share({ url: URL.createObjectURL(file) });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects blob: URLs");
+
+ promise_test(async t => {
+ const encoder = new TextEncoder();
+ const encoded = encoder.encode(
+ `<meta http-equiv="refresh" content="1;url=http://example.com/">`
+ );
+ const file = new File(encoded, "text/html");
+ const url = URL.createObjectURL(file);
+ const reader = new FileReader();
+ reader.readAsDataURL(file);
+ const dataURL = await new Promise(resolve => {
+ reader.addEventListener("load", () => {
+ resolve(reader.result);
+ });
+ });
+ await test_driver.bless();
+ const promise = navigator.share({ url: dataURL });
+ return promise_rejects_js(t, TypeError, promise);
+ }, "share() rejects data: URLs");
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-url-noscheme-manual.https.html b/testing/web-platform/tests/web-share/share-url-noscheme-manual.https.html
new file mode 100644
index 0000000000..e9d7eefeb7
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-url-noscheme-manual.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share with URL without a scheme</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const url = '//www.example.com/some/path?some_query#some_fragment';
+ setupManualShareTest({title: '', text: '', url: getAbsoluteUrl(url)});
+ callWhenButtonClicked(() => navigator.share({url}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-url-pathonly-manual.https.html b/testing/web-platform/tests/web-share/share-url-pathonly-manual.https.html
new file mode 100644
index 0000000000..0487bc8521
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-url-pathonly-manual.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share with absolute path-only URL</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const url = '/some/path?some_query#some_fragment';
+ setupManualShareTest({title: '', text: '', url: getAbsoluteUrl(url)});
+ callWhenButtonClicked(() => navigator.share({url}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-url-relative-manual.https.html b/testing/web-platform/tests/web-share/share-url-relative-manual.https.html
new file mode 100644
index 0000000000..bbea3860a5
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-url-relative-manual.https.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share with relative URL</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="resources/manual-helper.js"></script>
+ <base href="https://www.example.com/some/path.html">
+ </head>
+ <body>
+ <script>
+ setup({explicit_timeout: true});
+
+ const url = 'foo';
+ setupManualShareTest({title: '', text: '', url: getAbsoluteUrl(url)});
+ callWhenButtonClicked(() => navigator.share({url}));
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/share-without-user-gesture.https.html b/testing/web-platform/tests/web-share/share-without-user-gesture.https.html
new file mode 100644
index 0000000000..1b2a764dbe
--- /dev/null
+++ b/testing/web-platform/tests/web-share/share-without-user-gesture.https.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>WebShare Test: Share without user gesture error</title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <script>
+ promise_test(t => {
+ return promise_rejects_dom(
+ t, 'NotAllowedError',
+ navigator.share({title: 'the title', text: 'the message',
+ url: 'https://example.com'}));
+ }, 'share without a user gesture');
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/web-share/test-fully-active.https.html b/testing/web-platform/tests/web-share/test-fully-active.https.html
new file mode 100644
index 0000000000..46991d3370
--- /dev/null
+++ b/testing/web-platform/tests/web-share/test-fully-active.https.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>WebShare Test: consume user activation</title>
+ <link rel="help" href="https://github.com/w3c/web-share/pull/219" />
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ </head>
+ <body>
+ <script>
+ async function loadIframe() {
+ const iframe = document.createElement("iframe");
+ iframe.src = "./resources/blank.html";
+ document.body.appendChild(iframe);
+ await new Promise((resolve) => {
+ iframe.addEventListener("load", resolve);
+ });
+ return iframe;
+ }
+
+ promise_test(async (t) => {
+ const iframe = await loadIframe();
+ const { contentWindow } = iframe;
+ const { navigator, DOMException } = contentWindow;
+ const data = { text: "text" };
+ iframe.remove();
+ await promise_rejects_dom(
+ t,
+ "InvalidStateError",
+ DOMException,
+ navigator.share(data),
+ "Expected promise rejected with InvalidStateError from .share()"
+ );
+ }, "calling share() on non-fully active document returns a promise rejected with InvalidStateError");
+
+ promise_test(async (t) => {
+ const iframe = await loadIframe();
+ const { contentWindow } = iframe;
+ const { navigator, DOMException } = contentWindow;
+ const data = { text: "text" };
+
+ // Acquire transient activation, but make the iframe non-fully-active
+ await test_driver.bless(
+ "web share",
+ () => {
+ iframe.remove();
+ },
+ contentWindow
+ );
+
+ await promise_rejects_dom(
+ t,
+ "InvalidStateError",
+ DOMException,
+ navigator.share(data),
+ "Expected promise rejected with InvalidStateError from .share()"
+ );
+ }, "calling share() with transient activation on non-fully active document returns a promise rejected with InvalidStateError");
+
+ promise_test(async (t) => {
+ const iframe = await loadIframe();
+ const { contentWindow } = iframe;
+ const { navigator } = contentWindow;
+ const data = { text: "text" };
+
+ assert_true(navigator.canShare(data), "doc is fully active, so true");
+
+ iframe.remove();
+
+ assert_false(navigator.canShare(data), "not fully active, so false");
+ }, "calling canShare() on a non-fully active document returns false");
+ </script>
+ </body>
+</html>