summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/file-system-access
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/file-system-access
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/file-system-access')
-rw-r--r--testing/web-platform/tests/file-system-access/META.yml1
-rw-r--r--testing/web-platform/tests/file-system-access/README.md2
-rw-r--r--testing/web-platform/tests/file-system-access/idlharness.https.any.js18
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-IndexedDB-manual.https.html13
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-getUniqueId-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-isSameEntry-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-BroadcastChannel-manual.https.html14
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-Error-manual.https.html16
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-frames-manual.https.html14
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-windows-manual.https.html14
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-workers-manual.https.html15
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-frames-manual.https.html14
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-windows-manual.https.html14
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-workers-manual.https.html15
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-remove-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getDirectoryHandle-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getFileHandle-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-iteration-manual.https.html11
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-move-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-partitioned-manual.https.tentative.html116
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-removeEntry-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-resolve-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-create-sync-access-handle-manual.https.tentative.html11
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-getFile-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-move-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-partitioned-manual.https.tentative.html125
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-piped-manual.https.html11
-rw-r--r--testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-write-manual.https.html10
-rw-r--r--testing/web-platform/tests/file-system-access/opaque-origin.https.window.js86
-rw-r--r--testing/web-platform/tests/file-system-access/resources/data/testfile.txt1
-rw-r--r--testing/web-platform/tests/file-system-access/resources/local-fs-test-helpers.js186
-rw-r--r--testing/web-platform/tests/file-system-access/resources/opaque-origin-sandbox.html39
-rw-r--r--testing/web-platform/tests/file-system-access/resources/test-helpers.js80
-rw-r--r--testing/web-platform/tests/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.js3
-rw-r--r--testing/web-platform/tests/file-system-access/script-tests/FileSystemDirectoryHandle-move.js256
-rw-r--r--testing/web-platform/tests/file-system-access/showDirectoryPicker-manual.https.html34
-rw-r--r--testing/web-platform/tests/file-system-access/showOpenFilePicker-manual.https.html42
-rw-r--r--testing/web-platform/tests/file-system-access/showPicker-errors.https.window.js142
-rw-r--r--testing/web-platform/tests/file-system-access/showSaveFilePicker-manual.https.html33
40 files changed, 1446 insertions, 0 deletions
diff --git a/testing/web-platform/tests/file-system-access/META.yml b/testing/web-platform/tests/file-system-access/META.yml
new file mode 100644
index 0000000000..b4eaf1a49c
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/META.yml
@@ -0,0 +1 @@
+spec: https://wicg.github.io/file-system-access/
diff --git a/testing/web-platform/tests/file-system-access/README.md b/testing/web-platform/tests/file-system-access/README.md
new file mode 100644
index 0000000000..b007264cea
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/README.md
@@ -0,0 +1,2 @@
+This directory contains tests for the
+[File System Access](https://wicg.github.io/file-system-access/) specification.
diff --git a/testing/web-platform/tests/file-system-access/idlharness.https.any.js b/testing/web-platform/tests/file-system-access/idlharness.https.any.js
new file mode 100644
index 0000000000..ca3e92061a
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/idlharness.https.any.js
@@ -0,0 +1,18 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+'use strict';
+
+idl_test(
+ ['file-system-access'],
+ ['fs', 'permissions', 'html', 'dom'],
+ idl_array => {
+ if (self.GLOBAL.isWindow()) {
+ idl_array.add_objects({
+ Window: ['window'],
+ // TODO: DataTransferItem
+ });
+ }
+ }
+);
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-IndexedDB-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-IndexedDB-manual.https.html
new file mode 100644
index 0000000000..f9a58d457f
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-IndexedDB-manual.https.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="/IndexedDB/resources/support-promises.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-IndexedDB.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-getUniqueId-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-getUniqueId-manual.https.html
new file mode 100644
index 0000000000..32fc5ea103
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-getUniqueId-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-getUniqueId.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-isSameEntry-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-isSameEntry-manual.https.html
new file mode 100644
index 0000000000..6587bdf506
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-isSameEntry-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-isSameEntry.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-BroadcastChannel-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-BroadcastChannel-manual.https.html
new file mode 100644
index 0000000000..3981372df0
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-BroadcastChannel-manual.https.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-BroadcastChannel.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-Error-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-Error-manual.https.html
new file mode 100644
index 0000000000..b872839f2a
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-Error-manual.https.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-Error.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-frames-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-frames-manual.https.html
new file mode 100644
index 0000000000..3ec98c86c0
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-frames-manual.https.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-MessagePort-frames.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-windows-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-windows-manual.https.html
new file mode 100644
index 0000000000..359f11cd17
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-windows-manual.https.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-MessagePort-windows.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-workers-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-workers-manual.https.html
new file mode 100644
index 0000000000..af0d616909
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-MessagePort-workers-manual.https.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-MessagePort-workers.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-frames-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-frames-manual.https.html
new file mode 100644
index 0000000000..1581a645a5
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-frames-manual.https.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-frames.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-windows-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-windows-manual.https.html
new file mode 100644
index 0000000000..21fd7cb274
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-windows-manual.https.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-windows.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-workers-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-workers-manual.https.html
new file mode 100644
index 0000000000..f30ecddd9a
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-postMessage-workers-manual.https.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name=timeout content=long>
+
+<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>
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="resources/messaging-blob-helpers.js"></script>
+<script src="resources/messaging-serialize-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-postMessage-workers.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-remove-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-remove-manual.https.html
new file mode 100644
index 0000000000..ef7edd3aa8
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemBaseHandle-remove-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemBaseHandle-remove.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getDirectoryHandle-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getDirectoryHandle-manual.https.html
new file mode 100644
index 0000000000..e403d225ea
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getDirectoryHandle-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemDirectoryHandle-getDirectoryHandle.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getFileHandle-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getFileHandle-manual.https.html
new file mode 100644
index 0000000000..1fa4e11699
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-getFileHandle-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemDirectoryHandle-getFileHandle.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-iteration-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-iteration-manual.https.html
new file mode 100644
index 0000000000..e8c293266c
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-iteration-manual.https.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="/common/gc.js"></script>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemDirectoryHandle-iteration.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-move-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-move-manual.https.html
new file mode 100644
index 0000000000..20c6ccfdeb
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-move-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="script-tests/FileSystemDirectoryHandle-move.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-partitioned-manual.https.tentative.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-partitioned-manual.https.tentative.html
new file mode 100644
index 0000000000..3422914e23
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-partitioned-manual.https.tentative.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<head>
+ <meta charset=utf-8>
+ <script src="/common/dispatcher/dispatcher.js"></script>
+ <script src="/common/get-host-info.sub.js"></script>
+ <script src="/common/utils.js"></script>
+ <script src="/html/cross-origin-embedder-policy/credentialless/resources/common.js"></script>
+ <script src="/html/anonymous-iframe/resources/common.js"></script>
+ <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>
+ <script src="resources/test-helpers.js"></script>
+ <script src="resources/local-fs-test-helpers.js"></script>
+</head>
+<body>
+<script>
+
+const setUpChildFrame = (done) => `
+ const importScript = ${importScript};
+ await importScript("/resources/testharness.js");
+ await importScript("/resources/testdriver.js");
+ await importScript("/resources/testdriver-vendor.js");
+ await importScript("/file-system-access/resources/local-fs-test-helpers.js");
+ await importScript("/file-system-access/resources/test-helpers.js");
+ await window.test_driver.bless(
+ 'show a file picker.<br />Please select an empty directory');
+ await send("${done}", "done");
+`;
+
+const createTestDir = (name) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ await dir.getDirectoryHandle("${name}", {create: true});
+ return send("${done}", "done");
+ });
+`;
+
+const removeTestDir = (name) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ await dir.removeEntry("${name}", {recursive: true});
+ return send("${done}", "done");
+ });
+`;
+
+const assertNumEntries = (numFiles) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ assert_equals(${numFiles}, await getDirectoryEntryCount(dir));
+ return send("${done}", "done");
+ });
+`;
+
+const assertNoAccess = (done) => `
+ try {
+ await self.showDirectoryPicker();
+ await send("${done}", "unexpected");
+ } catch (e) {
+ await send("${done}", "done");
+ }
+`;
+
+// To be resilient against tests not cleaning up properly, cleanup before
+// every test.
+function clearDirectories() {
+ const directory = await directory_promise;
+ for await (let entry of directory.values()) {
+ await directory.removeEntry(
+ entry.name, {recursive: entry.kind === 'directory'});
+ }
+}
+
+// The following tests make use of helper framed_test to define promise tests
+// that send assertion scripts to multiple executor subframes.
+
+framed_test(async (t, sendTo) => {
+ clearDirectories();
+ // Ensure we have directory picker access in all child contexts.
+ await sendTo(childContexts, setUpChildFrame);
+ await sendTo(sameSiteContexts, assertNumEntries(0));
+
+ // Create directory in anonymous same-site context.
+ await sendTo([FRAME_CONTEXT.anonymousFrameSameSite], createTestDir("test"));
+
+ // Assert we can see the directory from all same-site contexts.
+ await sendTo(sameSiteContexts, assertNumEntries(1));
+}, 'getDirectoryHandle can access handles across same-site contexts.');
+
+framed_test(async (t, sendTo) => {
+ clearDirectories();
+ // Ensure we have directory picker access in all child contexts.
+ await sendTo(childContexts, setUpChildFrame);
+ await sendTo(sameSiteContexts, assertNumEntries(0));
+
+ // Create a test directory in a third-party same-site context.
+ await sendTo([FRAME_CONTEXT.thirdPartySameSite], createTestDir("file"));
+ await sendTo([FRAME_CONTEXT.thirdPartySameSite], assertNumEntries(1));
+
+ // Remove directory from an anonymous same-site context.
+ await sendTo([FRAME_CONTEXT.anonymousFrameSameSite], removeTestDir("file"));
+ // Assert third-party same-site context can no longer access directory.
+ await sendTo([FRAME_CONTEXT.thirdPartySameSite], assertNumEntries(0));
+}, 'Directory handles can be removed from other same-site contexts.');
+
+framed_test(async (t, sendTo) => {
+ clearDirectories();
+ // Ensure we have directory picker access in all child contexts.
+ await sendTo(childContexts, setUpChildFrame);
+ // Assert that an error is raised when attempting to access
+ // getDirectoryHandle.
+ await sendTo(crossSiteContexts, assertNoAccess);
+}, 'Cross-site sub-frames can not access getDirectoryHandle.');
+
+// TODO(crbug.com/1322897): Add tests for ancestor bit frames.
+// TODO(crbug.com/1099413): Add tests for non-default buckets.
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-removeEntry-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-removeEntry-manual.https.html
new file mode 100644
index 0000000000..cf97b9d1bb
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-removeEntry-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemDirectoryHandle-removeEntry.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-resolve-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-resolve-manual.https.html
new file mode 100644
index 0000000000..25be22afaf
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemDirectoryHandle-resolve-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemDirectoryHandle-resolve.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-create-sync-access-handle-manual.https.tentative.html b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-create-sync-access-handle-manual.https.tentative.html
new file mode 100644
index 0000000000..0a67f5b26d
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-create-sync-access-handle-manual.https.tentative.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="resources/messaging-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemFileHandle-create-sync-access-handle.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-getFile-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-getFile-manual.https.html
new file mode 100644
index 0000000000..9583032b59
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-getFile-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemFileHandle-getFile.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-move-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-move-manual.https.html
new file mode 100644
index 0000000000..360b09c3b7
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-move-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemFileHandle-move.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-partitioned-manual.https.tentative.html b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-partitioned-manual.https.tentative.html
new file mode 100644
index 0000000000..0aefd9eca3
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemFileHandle-partitioned-manual.https.tentative.html
@@ -0,0 +1,125 @@
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<script src="/common/dispatcher/dispatcher.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/html/cross-origin-embedder-policy/credentialless/resources/common.js"></script>
+<script src="/html/anonymous-iframe/resources/common.js"></script>
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<body>
+<script>
+
+const setUpChildFrame = (done) => `
+ const importScript = ${importScript};
+ await importScript("/resources/testharness.js");
+ await importScript("/resources/testdriver.js");
+ await importScript("/resources/testdriver-vendor.js");
+ await importScript("/file-system-access/resources/local-fs-test-helpers.js");
+ await importScript("/file-system-access/resources/test-helpers.js");
+ await window.test_driver.bless(
+ 'show a file picker.<br />Please select an empty directory');
+ await send("${done}", "done");
+`;
+
+const createTestFile = (name, contents) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ const handle = await dir.getFileHandle("${name}", {create: true});
+ const writer = await handle.createWritable();
+ await writer.write(new Blob(["${contents}"]));
+ await writer.close();
+ return send("${done}", "done");
+ });
+`;
+
+const removeTestFile = (name) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ await dir.removeEntry("${name}");
+ return send("${done}", "done");
+ });
+`;
+
+const assertNumEntries = (numFiles) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ assert_equals(${numFiles}, await getDirectoryEntryCount(dir));
+ return send("${done}", "done");
+ });
+`;
+
+const assertFileContents = (file, contents) => (done) => `
+ self.showDirectoryPicker().then(async (dir) => {
+ const handle = await dir.getFileHandle("${file}");
+ assert_equals("${contents}", await getFileContents(handle));
+ return send("${done}", "done");
+ });
+`;
+
+const assertNoAccess = (done) => `
+ try {
+ await self.showDirectoryPicker();
+ await send("${done}", "unexpected");
+ } catch (e) {
+ await send("${done}", "done");
+ }
+`;
+
+// To be resilient against tests not cleaning up properly, cleanup before
+// every test.
+function clearDirectories() {
+ const directory = await directory_promise;
+ for await (let entry of directory.values()) {
+ await directory.removeEntry(
+ entry.name, {recursive: entry.kind === 'directory'});
+ }
+}
+
+// The following tests make use of helper framed_test to define promise tests
+// that send assertion scripts to multiple executor subframes.
+
+framed_test(async (t, sendTo) => {
+ clearDirectories();
+ // Ensure we have directory picker access in all child contexts.
+ await sendTo(childContexts, setUpChildFrame);
+ await sendTo(sameSiteContexts, assertNumEntries(0));
+
+ // Create file in first-party context.
+ await sendTo([FRAME_CONTEXT.firstParty], createTestFile("test.txt", "abc"));
+ // Assert file contents from all same-site contexts.
+ await sendTo(sameSiteContexts, assertNumEntries(1));
+ await sendTo(sameSiteContexts, assertFileContents("test.txt", "abc"));
+}, 'getFileHandle can access handles across same-site contexts.');
+
+framed_test(async (t, sendTo) => {
+ clearDirectories();
+ // Ensure we have directory picker access in all child frames.
+ await sendTo(childContexts, setUpChildFrame);
+ await sendTo(sameSiteContexts, assertNumEntries(0));
+
+ // Create file in third-party same-site context.
+ await sendTo([FRAME_CONTEXT.thirdPartySameSite], createTestFile("file", "b"));
+ await sendTo([FRAME_CONTEXT.thirdPartySameSite], assertNumEntries(1));
+
+ // Remove file from an anonymous same-site context.
+ await sendTo([FRAME_CONTEXT.anonymousFrameSameSite], removeTestFile("file"));
+ // Assert third-party same-site context can no longer access file.
+ await sendTo([FRAME_CONTEXT.thirdPartySameSite], assertNumEntries(0));
+}, 'File handles can be removed from other same-site contexts.');
+
+framed_test(async (t, sendTo) => {
+ clearDirectories();
+ // Ensure we have directory picker access in all child contexts.
+ await sendTo(childContexts, setUpChildFrame);
+ // Assert that an error is raised when attempting to access getFileHandle.
+ await sendTo(crossSiteContexts, assertNoAccess);
+}, 'Cross-site sub-frames cannot access getFileHandle.');
+
+// TODO(crbug.com/1322897): Add tests for ancestor bit frames.
+// TODO(crbug.com/1099413): Add tests for non-default buckets.
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-manual.https.html
new file mode 100644
index 0000000000..b9f28c5b08
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemWritableFileStream.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-piped-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-piped-manual.https.html
new file mode 100644
index 0000000000..645eddbb50
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-piped-manual.https.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../streams/resources/recording-streams.js"></script>
+<script src="../fs/script-tests/FileSystemWritableFileStream-piped.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-write-manual.https.html b/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-write-manual.https.html
new file mode 100644
index 0000000000..f1c4960ad3
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/local_FileSystemWritableFileStream-write-manual.https.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+<script src="resources/local-fs-test-helpers.js"></script>
+<script src="../fs/script-tests/FileSystemWritableFileStream-write.js"></script>
diff --git a/testing/web-platform/tests/file-system-access/opaque-origin.https.window.js b/testing/web-platform/tests/file-system-access/opaque-origin.https.window.js
new file mode 100644
index 0000000000..8f431a2406
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/opaque-origin.https.window.js
@@ -0,0 +1,86 @@
+'use strict';
+
+const kSandboxWindowUrl = 'resources/opaque-origin-sandbox.html';
+
+function add_iframe(test, src, sandbox) {
+ const iframe = document.createElement('iframe');
+ iframe.src = src;
+ if (sandbox !== undefined) {
+ iframe.sandbox = sandbox;
+ }
+ document.body.appendChild(iframe);
+ test.add_cleanup(() => {
+ iframe.remove();
+ });
+}
+
+// Creates a data URI iframe that uses postMessage() to provide its parent
+// with the test result. The iframe checks for the existence of
+// |property_name| on the window.
+async function verify_does_not_exist_in_data_uri_iframe(
+ test, property_name) {
+ const iframe_content =
+ '<script>' +
+ ' const is_property_name_defined = ' +
+ ` (self.${property_name} !== undefined);` +
+ ' parent.postMessage({is_property_name_defined}, "*")' +
+ '</script>';
+
+ const data_uri = `data:text/html,${encodeURIComponent(iframe_content)}`;
+ add_iframe(test, data_uri);
+
+ const event_watcher = new EventWatcher(test, self, 'message');
+ const message_event = await event_watcher.wait_for('message')
+
+ assert_false(message_event.data.is_property_name_defined,
+ `Data URI iframes must not define '${property_name}'.`);
+}
+
+// |kSandboxWindowUrl| sends two messages to this window. The first is the
+// result of showDirectoryPicker(). The second is the result of
+// navigator.storage.getDirectory(). For windows using sandbox='allow-scripts',
+// both results must produce rejected promises.
+async function verify_results_from_sandboxed_child_window(test) {
+ const event_watcher = new EventWatcher(test, self, 'message');
+
+ const first_message_event = await event_watcher.wait_for('message');
+ assert_equals(
+ first_message_event.data,
+ 'showDirectoryPicker(): REJECTED: SecurityError');
+
+ const second_message_event = await event_watcher.wait_for('message');
+ assert_equals(second_message_event.data,
+ 'navigator.storage.getDirectory(): REJECTED: SecurityError');
+}
+
+promise_test(async test => {
+ await verify_does_not_exist_in_data_uri_iframe(test, 'showDirectoryPicker');
+}, 'showDirectoryPicker() must be undefined for data URI iframes.');
+
+promise_test(async test => {
+ await verify_does_not_exist_in_data_uri_iframe(
+ test, 'FileSystemDirectoryHandle');
+}, 'FileSystemDirectoryHandle must be undefined for data URI iframes.');
+
+promise_test(
+ async test => {
+ add_iframe(test, kSandboxWindowUrl, /*sandbox=*/ 'allow-scripts');
+ await verify_results_from_sandboxed_child_window(test);
+ },
+ 'navigator.storage.getDirectory() and ' +
+ 'showDirectoryPicker() must reject in a sandboxed iframe.');
+
+promise_test(
+ async test => {
+ const child_window_url = kSandboxWindowUrl +
+ '?pipe=header(Content-Security-Policy, sandbox allow-scripts)';
+
+ const child_window = window.open(child_window_url);
+ test.add_cleanup(() => {
+ child_window.close();
+ });
+
+ await verify_results_from_sandboxed_child_window(test);
+ },
+ 'navigator.storage.getDirectory() and ' +
+ 'showDirectoryPicker() must reject in a sandboxed opened window.');
diff --git a/testing/web-platform/tests/file-system-access/resources/data/testfile.txt b/testing/web-platform/tests/file-system-access/resources/data/testfile.txt
new file mode 100644
index 0000000000..980a0d5f19
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/resources/data/testfile.txt
@@ -0,0 +1 @@
+Hello World!
diff --git a/testing/web-platform/tests/file-system-access/resources/local-fs-test-helpers.js b/testing/web-platform/tests/file-system-access/resources/local-fs-test-helpers.js
new file mode 100644
index 0000000000..4bb9793085
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/resources/local-fs-test-helpers.js
@@ -0,0 +1,186 @@
+// This file defines a directory_test() function that can be used to define
+// tests that require a FileSystemDirectoryHandle. The implementation of that
+// function in this file will ask the user to select an empty directory and uses
+// that directory.
+//
+// Another implementation of this function exists in
+// fs/resources/sandboxed-fs-test-helpers.js, where that version uses the
+// sandboxed file system instead.
+
+function getFileSystemType() {
+ return 'local';
+}
+
+const directory_promise = (async () => {
+ await new Promise(resolve => {
+ window.addEventListener('DOMContentLoaded', resolve);
+ });
+
+ // Small delay to give chrome's test automation a chance to actually install
+ // itself.
+ await new Promise(resolve => step_timeout(resolve, 100));
+
+ await window.test_driver.bless(
+ 'show a file picker.<br />Please select an empty directory');
+ const entries = await self.showDirectoryPicker();
+ assert_true(entries instanceof FileSystemHandle);
+ assert_true(entries instanceof FileSystemDirectoryHandle);
+ for await (const entry of entries) {
+ assert_unreached('Selected directory is not empty');
+ }
+ return entries;
+})();
+
+function directory_test(func, description) {
+ promise_test(async t => {
+ const directory = await directory_promise;
+ // To be resilient against tests not cleaning up properly, cleanup before
+ // every test.
+ for await (let entry of directory.values()) {
+ await directory.removeEntry(
+ entry.name, {recursive: entry.kind === 'directory'});
+ }
+ await func(t, directory);
+ }, description);
+}
+
+directory_test(async (t, dir) => {
+ assert_equals(await dir.queryPermission({mode: 'read'}), 'granted');
+}, 'User succesfully selected an empty directory.');
+
+directory_test(async (t, dir) => {
+ const status = await dir.queryPermission({mode: 'readwrite'});
+ if (status == 'granted')
+ return;
+
+ await window.test_driver.bless('ask for write permission');
+ assert_equals(await dir.requestPermission({mode: 'readwrite'}), 'granted');
+}, 'User granted write access.');
+
+const child_frame_js = (origin, frameFn, done) => `
+ const importScript = ${importScript};
+ await importScript("/html/cross-origin-embedder-policy/credentialless" +
+ "/resources/common.js");
+ await importScript("/html/anonymous-iframe/resources/common.js");
+ await importScript("/common/utils.js");
+ await send("${done}", ${frameFn}("${origin}"));
+`;
+
+/**
+ * Context identifiers for executor subframes of framed tests. Individual
+ * contexts (or convenience context lists below) can be used to send JavaScript
+ * for evaluation in each frame (see framed_test below).
+ *
+ * Note that within framed tests:
+ * - firstParty represents the top-level document.
+ * - thirdParty represents an embedded context (iframe).
+ * - ancestorBit contexts include a cross-site ancestor iframe.
+ * - anonymousFrame contexts are third-party anonymous iframe contexts.
+ */
+const FRAME_CONTEXT = {
+ firstParty: 0,
+ thirdPartySameSite: 1,
+ thirdPartySameSite_AncestorBit: 2,
+ thirdPartyCrossSite: 3,
+ anonymousFrameSameSite: 4,
+ anonymousFrameSameSite_AncestorBit: 5,
+ anonymousFrameCrossSite: 6,
+};
+
+// TODO(crbug.com/1322897): Add AncestorBit contexts.
+const sameSiteContexts = [
+ FRAME_CONTEXT.firstParty,
+ FRAME_CONTEXT.thirdPartySameSite,
+ FRAME_CONTEXT.anonymousFrameSameSite,
+];
+
+// TODO(crbug.com/1322897): Add AncestorBit contexts.
+const crossSiteContexts = [
+ FRAME_CONTEXT.thirdPartyCrossSite,
+ FRAME_CONTEXT.anonymousFrameCrossSite,
+];
+
+// TODO(crbug.com/1322897): Add AncestorBit contexts.
+const childContexts = [
+ FRAME_CONTEXT.thirdPartySameSite,
+ FRAME_CONTEXT.thirdPartyCrossSite,
+ FRAME_CONTEXT.anonymousFrameSameSite,
+ FRAME_CONTEXT.anonymousFrameCrossSite,
+];
+
+/**
+ * Creates a promise test with same- & cross-site executor subframes.
+ *
+ * In addition to the standard testing object, the provided func will be called
+ * with a sendTo function. sendTo expects:
+ * - contexts: an Iterable of FRAME_CONTEXT constants representing the
+ * frame(s) in which the provided script will be concurrently run.
+ * - js_gen: a function which should generate a script string when called
+ * with a string token. sendTo will wait until a "done" message
+ * is sent to this queue.
+ */
+function framed_test(func, description) {
+ const same_site_origin = get_host_info().HTTPS_ORIGIN;
+ const cross_site_origin = get_host_info().HTTPS_NOTSAMESITE_ORIGIN;
+ const frames = Object.values(FRAME_CONTEXT);
+
+ promise_test(async (t) => {
+ return new Promise(async (resolve, reject) => {
+ try {
+ // Set up handles to all third party frames.
+ const handles = [
+ null, // firstParty
+ newIframe(same_site_origin), // thirdPartySameSite
+ null, // thirdPartySameSite_AncestorBit
+ newIframe(cross_site_origin), // thirdPartyCrossSite
+ newAnonymousIframe(same_site_origin), // anonymousFrameSameSite
+ null, // anonymousFrameSameSite_AncestorBit
+ newAnonymousIframe(cross_site_origin), // anonymousFrameCrossSite
+ ];
+ // Set up nested SameSite frames for ancestor bit contexts.
+ const setUpQueue = token();
+ send(newIframe(cross_site_origin),
+ child_frame_js(same_site_origin, "newIframe", setUpQueue));
+ handles[FRAME_CONTEXT.thirdPartySameSite_AncestorBit] =
+ await receive(setUpQueue);
+ send(newAnonymousIframe(cross_site_origin),
+ child_frame_js(same_site_origin, "newAnonymousIframe", setUpQueue));
+ handles[FRAME_CONTEXT.anonymousFrameSameSite_AncestorBit] =
+ await receive(setUpQueue);
+
+ const sendTo = (contexts, js_generator) => {
+ // Send to all contexts in parallel to minimize timeout concerns.
+ return Promise.all(contexts.map(async (context) => {
+ const queue = token();
+ const js_string = js_generator(queue, context);
+ switch (context) {
+ case FRAME_CONTEXT.firstParty:
+ // Code is executed directly in this frame via eval() rather
+ // than in a new context to avoid differences in API access.
+ eval(`(async () => {${js_string}})()`);
+ break;
+ case FRAME_CONTEXT.thirdPartySameSite:
+ case FRAME_CONTEXT.thirdPartyCrossSite:
+ case FRAME_CONTEXT.anonymousFrameSameSite:
+ case FRAME_CONTEXT.anonymousFrameCrossSite:
+ case FRAME_CONTEXT.thirdPartySameSite_AncestorBit:
+ case FRAME_CONTEXT.anonymousFrameSameSite_AncestorBit:
+ send(handles[context], js_string);
+ break;
+ default:
+ reject(`Cannot execute in context: ${context}`);
+ }
+ if (await receive(queue) != "done") {
+ reject(`Script failed in frame ${context}: ${js_string}`);
+ }
+ }));
+ };
+
+ await func(t, sendTo);
+ } catch (e) {
+ reject(e);
+ }
+ resolve();
+ });
+ }, description);
+}
diff --git a/testing/web-platform/tests/file-system-access/resources/opaque-origin-sandbox.html b/testing/web-platform/tests/file-system-access/resources/opaque-origin-sandbox.html
new file mode 100644
index 0000000000..f489f889b3
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/resources/opaque-origin-sandbox.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<script>
+ 'use strict'
+
+ // Sends two messages to its creator:
+ // (1) The result of showDirectoryPicker().
+ // (2) The result of navigator.storage.getDirectory().
+
+ function post_message(data) {
+ if (window.parent !== null) {
+ window.parent.postMessage(data, { targetOrigin: '*' });
+ }
+ if (window.opener !== null) {
+ window.opener.postMessage(data, { targetOrigin: '*' });
+ }
+ }
+
+ try {
+ window.showDirectoryPicker()
+ .then(() => {
+ post_message('showDirectoryPicker(): FULFILLED');
+ }).catch(error => {
+ post_message(`showDirectoryPicker(): REJECTED: ${error.name}`);
+ });
+ } catch (error) {
+ post_message(`showDirectoryPicker(): EXCEPTION: ${error.name}`);
+ }
+
+ try {
+ navigator.storage.getDirectory()
+ .then(() => {
+ post_message('navigator.storage.getDirectory(): FULFILLED');
+ }).catch(error => {
+ post_message(`navigator.storage.getDirectory(): REJECTED: ${error.name}`);
+ });
+ } catch (error) {
+ post_message(`navigator.storage.getDirectory(): EXCEPTION: ${error.name}`);
+ }
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/file-system-access/resources/test-helpers.js b/testing/web-platform/tests/file-system-access/resources/test-helpers.js
new file mode 100644
index 0000000000..893cd19848
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/resources/test-helpers.js
@@ -0,0 +1,80 @@
+// A special path component meaning "this directory."
+const kCurrentDirectory = '.';
+
+// A special path component meaning "the parent directory."
+const kParentDirectory = '..';
+
+// Array of separators used to separate components in hierarchical paths.
+let kPathSeparators;
+if (navigator.userAgent.includes('Windows NT')) {
+ // Windows uses both '/' and '\' as path separators.
+ kPathSeparators = ['/', '\\'];
+} else {
+ kPathSeparators = ['/'];
+}
+
+async function getFileSize(handle) {
+ const file = await handle.getFile();
+ return file.size;
+}
+
+async function getFileContents(handle) {
+ const file = await handle.getFile();
+ return new Response(file).text();
+}
+
+async function getDirectoryEntryCount(handle) {
+ let result = 0;
+ for await (let entry of handle) {
+ result++;
+ }
+ return result;
+}
+
+async function getSortedDirectoryEntries(handle) {
+ let result = [];
+ for await (let entry of handle.values()) {
+ if (entry.kind === 'directory')
+ result.push(entry.name + '/');
+ else
+ result.push(entry.name);
+ }
+ result.sort();
+ return result;
+}
+
+async function createDirectory(test, name, parent) {
+ const new_dir_handle = await parent.getDirectoryHandle(name, {create: true});
+ test.add_cleanup(async () => {
+ try {
+ await parent.removeEntry(name, {recursive: true});
+ } catch (e) {
+ // Ignore any errors when removing directories, as tests might
+ // have already removed the directory.
+ }
+ });
+ return new_dir_handle;
+}
+
+async function createEmptyFile(test, name, parent) {
+ const handle = await parent.getFileHandle(name, {create: true});
+ test.add_cleanup(async () => {
+ try {
+ await parent.removeEntry(name);
+ } catch (e) {
+ // Ignore any errors when removing files, as tests might already remove
+ // the file.
+ }
+ });
+ // Make sure the file is empty.
+ assert_equals(await getFileSize(handle), 0);
+ return handle;
+}
+
+async function createFileWithContents(test, name, contents, parent) {
+ const handle = await createEmptyFile(test, name, parent);
+ const writer = await handle.createWritable();
+ await writer.write(new Blob([contents]));
+ await writer.close();
+ return handle;
+}
diff --git a/testing/web-platform/tests/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.js b/testing/web-platform/tests/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.js
new file mode 100644
index 0000000000..00578f1c8b
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/sandboxed_FileSystemDirectoryHandle-move.https.any.js
@@ -0,0 +1,3 @@
+// META: script=resources/test-helpers.js
+// META: script=../fs/resources/sandboxed-fs-test-helpers.js
+// META: script=script-tests/FileSystemDirectoryHandle-move.js
diff --git a/testing/web-platform/tests/file-system-access/script-tests/FileSystemDirectoryHandle-move.js b/testing/web-platform/tests/file-system-access/script-tests/FileSystemDirectoryHandle-move.js
new file mode 100644
index 0000000000..abdbc9ef2b
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/script-tests/FileSystemDirectoryHandle-move.js
@@ -0,0 +1,256 @@
+// META: script=resources/test-helpers.js
+
+'use strict';
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir-before', {create: true});
+ await dir.move('dir-after');
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move(name) to rename an empty directory');
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir-before', {create: true});
+ await promise_rejects_js(t, TypeError, dir.move(''));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir-before/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move("") to rename an empty directory fails');
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir-before', {create: true});
+ await createFileWithContents(t, 'file-in-dir', 'abc', dir);
+ await dir.move('dir-after');
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), ['file-in-dir']);
+}, 'move(name) to rename a non-empty directory');
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir-before', {create: true});
+ await dir.move(root, 'dir-after');
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move(dir, name) to rename an empty directory');
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir-before', {create: true});
+ await createFileWithContents(t, 'file-in-dir', 'abc', dir);
+ await dir.move(root, 'dir-after');
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir-after/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), ['file-in-dir']);
+}, 'move(dir, name) to rename a non-empty directory');
+
+directory_test(async (t, root) => {
+ const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
+ const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
+ const dir_in_dir =
+ await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
+ await dir_in_dir.move(dir_dest);
+
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
+ assert_array_equals(
+ await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir_in_dir), []);
+}, 'move(dir) to move an empty directory to a new directory');
+
+directory_test(async (t, root) => {
+ const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
+ const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
+ const dir_in_dir =
+ await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
+ await dir_in_dir.move(dir_dest, 'dir-in-dir');
+
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
+ assert_array_equals(
+ await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir_in_dir), []);
+}, 'move(dir, name) to move an empty directory to a new directory');
+
+directory_test(async (t, root) => {
+ const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
+ const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
+ const dir_in_dir =
+ await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
+ const file =
+ await createFileWithContents(t, 'file-in-dir', 'abc', dir_in_dir);
+ await dir_in_dir.move(dir_dest);
+
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
+ assert_array_equals(
+ await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
+ assert_array_equals(
+ await getSortedDirectoryEntries(dir_in_dir), ['file-in-dir']);
+ // `file` should be invalidated after moving directories.
+ await promise_rejects_dom(t, 'NotFoundError', getFileContents(file));
+}, 'move(dir) to move a non-empty directory to a new directory');
+
+directory_test(async (t, root) => {
+ const dir_src = await root.getDirectoryHandle('dir-src', {create: true});
+ const dir_dest = await root.getDirectoryHandle('dir-dest', {create: true});
+ const dir_in_dir =
+ await dir_src.getDirectoryHandle('dir-in-dir', {create: true});
+ const file =
+ await createFileWithContents(t, 'file-in-dir', 'abc', dir_in_dir);
+ await dir_in_dir.move(dir_dest, 'dir-in-dir');
+
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir-dest/', 'dir-src/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir_src), []);
+ assert_array_equals(
+ await getSortedDirectoryEntries(dir_dest), ['dir-in-dir/']);
+ assert_array_equals(
+ await getSortedDirectoryEntries(dir_in_dir), ['file-in-dir']);
+ // `file` should be invalidated after moving directories.
+ await promise_rejects_dom(t, 'NotFoundError', getFileContents(file));
+}, 'move(dir, name) to move a non-empty directory to a new directory');
+
+directory_test(async (t, root) => {
+ const dir1 = await root.getDirectoryHandle('dir1', {create: true});
+ const dir2 = await root.getDirectoryHandle('dir2', {create: true});
+ const handle = await createFileWithContents(t, 'file', 'foo', root);
+
+ await handle.move(dir1);
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir1), ['file']);
+ assert_array_equals(await getSortedDirectoryEntries(dir2), []);
+ assert_equals(await getFileContents(handle), 'foo');
+
+ await handle.move(dir2);
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir1), []);
+ assert_array_equals(await getSortedDirectoryEntries(dir2), ['file']);
+ assert_equals(await getFileContents(handle), 'foo');
+
+ await handle.move(root);
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir1/', 'dir2/', 'file']);
+ assert_array_equals(await getSortedDirectoryEntries(dir1), []);
+ assert_array_equals(await getSortedDirectoryEntries(dir2), []);
+ assert_equals(await getFileContents(handle), 'foo');
+}, 'move(dir) can be called multiple times');
+
+directory_test(async (t, root) => {
+ const dir1 = await root.getDirectoryHandle('dir1', {create: true});
+ const dir2 = await root.getDirectoryHandle('dir2', {create: true});
+ const handle = await createFileWithContents(t, 'file', 'foo', root);
+
+ await handle.move(dir1, 'file-1');
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir1), ['file-1']);
+ assert_array_equals(await getSortedDirectoryEntries(dir2), []);
+ assert_equals(await getFileContents(handle), 'foo');
+
+ await handle.move(dir2, 'file-2');
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir1/', 'dir2/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir1), []);
+ assert_array_equals(await getSortedDirectoryEntries(dir2), ['file-2']);
+ assert_equals(await getFileContents(handle), 'foo');
+
+ await handle.move(root, 'file-3');
+ assert_array_equals(
+ await getSortedDirectoryEntries(root), ['dir1/', 'dir2/', 'file-3']);
+ assert_array_equals(await getSortedDirectoryEntries(dir1), []);
+ assert_array_equals(await getSortedDirectoryEntries(dir2), []);
+ assert_equals(await getFileContents(handle), 'foo');
+}, 'move(dir, name) can be called multiple times');
+
+directory_test(async (t, root) => {
+ const handle = await createFileWithContents(t, 'file-before', 'foo', root);
+ const valid_name = '#$23423@352^*3243';
+ await handle.move(root, valid_name);
+
+ assert_array_equals(await getSortedDirectoryEntries(root), [valid_name]);
+ assert_equals(await getFileContents(handle), 'foo');
+ assert_equals(await getFileSize(handle), 3);
+
+ const contains_invalid_characters = '/file\\';
+ await promise_rejects_js(
+ t, TypeError, handle.move(root, contains_invalid_characters));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), [valid_name]);
+ assert_equals(await getFileContents(handle), 'foo');
+ assert_equals(await getFileSize(handle), 3);
+
+ const empty_name = '';
+ await promise_rejects_js(t, TypeError, handle.move(root, empty_name));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), [valid_name]);
+ assert_equals(await getFileContents(handle), 'foo');
+ assert_equals(await getFileSize(handle), 3);
+
+ const banned_name = '..';
+ await promise_rejects_js(t, TypeError, handle.move(root, banned_name));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), [valid_name]);
+ assert_equals(await getFileContents(handle), 'foo');
+ assert_equals(await getFileSize(handle), 3);
+}, 'move(dir, name) with a name with invalid characters should fail');
+
+directory_test(async (t, root) => {
+ const handle = await createFileWithContents(t, 'file-before', 'foo', root);
+ await promise_rejects_js(t, TypeError, handle.move(root, ''));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['file-before']);
+ assert_equals(await getFileContents(handle), 'foo');
+ assert_equals(await getFileSize(handle), 3);
+}, 'move(dir, "") should fail');
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir', {create: true});
+ await promise_rejects_dom(
+ t, 'InvalidModificationError', dir.move(dir));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move(dir, name) to move a directory within itself fails');
+
+directory_test(async (t, root) => {
+ const dir = await root.getDirectoryHandle('dir', {create: true});
+ await promise_rejects_dom(
+ t, 'InvalidModificationError', dir.move(dir, 'dir-fail'));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['dir/']);
+ assert_array_equals(await getSortedDirectoryEntries(dir), []);
+}, 'move(dir, name) to move a directory within itself and rename fails');
+
+directory_test(async (t, root) => {
+ const parent_dir =
+ await root.getDirectoryHandle('parent-dir', {create: true});
+ const child_dir =
+ await parent_dir.getDirectoryHandle('child-dir', {create: true});
+ await promise_rejects_dom(
+ t, 'InvalidModificationError', parent_dir.move(child_dir));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['parent-dir/']);
+ assert_array_equals(
+ await getSortedDirectoryEntries(parent_dir), ['child-dir/']);
+ assert_array_equals(await getSortedDirectoryEntries(child_dir), []);
+}, 'move(dir) to move a directory within a descendent fails');
+
+directory_test(async (t, root) => {
+ const parent_dir =
+ await root.getDirectoryHandle('parent-dir', {create: true});
+ const child_dir =
+ await parent_dir.getDirectoryHandle('child-dir', {create: true});
+ await promise_rejects_dom(
+ t, 'InvalidModificationError', parent_dir.move(child_dir, 'dir'));
+
+ assert_array_equals(await getSortedDirectoryEntries(root), ['parent-dir/']);
+ assert_array_equals(
+ await getSortedDirectoryEntries(parent_dir), ['child-dir/']);
+ assert_array_equals(await getSortedDirectoryEntries(child_dir), []);
+}, 'move(dir, name) to move a directory within a descendent fails');
diff --git a/testing/web-platform/tests/file-system-access/showDirectoryPicker-manual.https.html b/testing/web-platform/tests/file-system-access/showDirectoryPicker-manual.https.html
new file mode 100644
index 0000000000..d1abf93eaf
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/showDirectoryPicker-manual.https.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+
+<script>
+
+ promise_test(async t => {
+ await new Promise(resolve => {
+ window.addEventListener('DOMContentLoaded', resolve);
+ });
+ // Small delay to give chrome's test automation a chance to actually install
+ // itself.
+ await new Promise(resolve => step_timeout(resolve, 100));
+
+ await window.test_driver.bless(
+ 'show a directory picker.<br />Please select file-system-access/resources/data/');
+ const dir = await self.showDirectoryPicker();
+ assert_true(dir instanceof FileSystemHandle);
+ assert_true(dir instanceof FileSystemDirectoryHandle);
+ assert_equals(dir.kind, "directory");
+ assert_equals(dir.name, 'data');
+ assert_array_equals(await getSortedDirectoryEntries(dir), ['testfile.txt']);
+
+ promise_test(async t => {
+ assert_equals(await dir.queryPermission(), 'granted');
+ }, 'showDirectoryPicker returns correct permissions');
+ }, 'showDirectoryPicker works');
+
+</script>
diff --git a/testing/web-platform/tests/file-system-access/showOpenFilePicker-manual.https.html b/testing/web-platform/tests/file-system-access/showOpenFilePicker-manual.https.html
new file mode 100644
index 0000000000..2c8f29d7b6
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/showOpenFilePicker-manual.https.html
@@ -0,0 +1,42 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+
+<script>
+
+ promise_test(async t => {
+ await new Promise(resolve => {
+ window.addEventListener('DOMContentLoaded', resolve);
+ });
+ // Small delay to give chrome's test automation a chance to actually install
+ // itself.
+ await new Promise(resolve => step_timeout(resolve, 100));
+
+ await window.test_driver.bless(
+ 'show a file picker.<br />Please select file-system-access/resources/data/testfile.txt');
+ const files = await self.showOpenFilePicker({
+ multiple: false, types: [
+ { description: 'Text files', accept: { ' text/plain ': ['.txt'] } },
+ { description: 'Images', accept: { ' image/* ': ['.jpg', '.jpeg', '.png'] } },
+ ],
+ });
+ assert_true(Array.isArray(files));
+ assert_equals(files.length, 1);
+ assert_true(files[0] instanceof FileSystemHandle);
+ assert_true(files[0] instanceof FileSystemFileHandle);
+ assert_equals(files[0].kind, "file");
+ assert_equals(files[0].name, 'testfile.txt');
+ assert_equals(await (await files[0].getFile()).text(), 'Hello World!\n');
+
+ promise_test(async t => {
+ assert_equals(await files[0].queryPermission(), 'granted');
+ }, 'showOpenFilePicker returns correct permissions');
+ }, 'showOpenFilePicker works');
+
+</script>
+
diff --git a/testing/web-platform/tests/file-system-access/showPicker-errors.https.window.js b/testing/web-platform/tests/file-system-access/showPicker-errors.https.window.js
new file mode 100644
index 0000000000..ed66e1093b
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/showPicker-errors.https.window.js
@@ -0,0 +1,142 @@
+// META: script=resources/test-helpers.js
+
+promise_test(async t => {
+ await promise_rejects_dom(t, 'SecurityError', self.showOpenFilePicker());
+}, 'showOpenFilePicker: Showing a picker requires user activation.');
+
+promise_test(async t => {
+ await promise_rejects_dom(t, 'SecurityError', self.showSaveFilePicker());
+}, 'showSaveFilePicker: Showing a picker requires user activation.');
+
+promise_test(async t => {
+ await promise_rejects_dom(t, 'SecurityError', self.showDirectoryPicker());
+}, 'showDirectoryPicker: Showing a picker requires user activation.');
+
+// TODO(mek): Add tests for cross-origin iframes, opaque origins, etc.
+
+define_file_picker_error_tests('showOpenFilePicker');
+define_file_picker_error_tests('showSaveFilePicker');
+
+function define_file_picker_error_tests(showPickerMethod) {
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({excludeAcceptAllOption: true, types: []}));
+ }, showPickerMethod + ': File picker requires at least one accepted type.');
+
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({types: [{accept: {'': ['.foo']}}]}));
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({types: [{accept: {' ': ['.foo']}}]}));
+ }, showPickerMethod + ': MIME type can\'t be an empty string.');
+
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({types: [{accept: {'image': ['.foo']}}]}));
+ }, showPickerMethod + ': MIME type must have subtype.');
+
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({types: [{accept: {' /plain': ['.foo']}}]}));
+ }, showPickerMethod + ': MIME type can\'t have empty type.');
+
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({types: [{accept: {'image/ ': ['.foo']}}]}));
+ }, showPickerMethod + ': MIME type can\'t have empty subtype.');
+
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod](
+ {types: [{accept: {'text/plain;charset=utf8': ['.txt']}}]}));
+ }, showPickerMethod + ': MIME type can\'t have parameters.');
+
+ promise_test(async t => {
+ await promise_rejects_js(t, TypeError, self[showPickerMethod]({
+ types: [{accept: {'text>foo/plain': ['.txt']}}]
+ }));
+ }, showPickerMethod + ': MIME type can\'t have invalid characters in type.');
+
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod]({types: [{accept: {'text / plain': ['.txt']}}]}));
+ }, showPickerMethod + ': MIME type can\'t have whitespace in the middle.');
+
+ promise_test(
+ async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod](
+ {types: [{accept: {'text/plain>foo': ['.txt']}}]}));
+ },
+ showPickerMethod +
+ ': MIME type can\'t have invalid characters in subtype.');
+
+ promise_test(async t => {
+ await promise_rejects_js(t, TypeError, self[showPickerMethod]({
+ startIn: 'secrets',
+ }));
+ }, showPickerMethod + ': unknown well-known starting directory.');
+
+ promise_test(async t => {
+ await promise_rejects_js(t, TypeError, self[showPickerMethod]({
+ startIn: null,
+ }));
+ }, showPickerMethod + ': starting directory can\t be null.');
+
+ promise_test(async t => {
+ await promise_rejects_js(t, TypeError, self[showPickerMethod]({
+ id: "inv*l:d\\ chara<ters",
+ }));
+ }, showPickerMethod + ': starting directory ID contains invalid characters.');
+
+ promise_test(async t => {
+ await promise_rejects_js(t, TypeError, self[showPickerMethod]({
+ id: "id-length-cannot-exceed-32-characters",
+ }));
+ }, showPickerMethod + ': starting directory ID cannot exceed 32 characters.');
+
+ const invalid_extensions = {
+ '.extensiontoolong': 'extension length more than 16.',
+ '.txt.': 'extenstion ends with "."',
+ 'txt': 'extenstion does not start with "."',
+ '.$txt' : 'illegal character "$"',
+ '.t<xt': 'illegal character "<"',
+ '.t/xt': 'illegal character "\"',
+ '.\txt': 'illegal character "/"',
+ '.txt\\': 'illegal characters "\\"',
+ '.txt?': 'illegal character "?"',
+ '.txt*': 'illegal character "*"',
+ '.{txt': 'illegal character "{"',
+ '.}txt': 'illegal character "}"',
+ ' .txt': 'illegal whitespace at front of extension',
+ '. txt': 'illegal whitespace in extension',
+ '.txt ': 'illegal whitespace at end of extension',
+ '.\u202etxt\u202e' : 'illegal RTL character',
+ '.t\u00E6xt': 'non-ASCII character "æ"',
+ '.קום': 'non-ASCII character "קום"',
+ '.txt🙂': 'non-ASCII character "🙂"',
+ '.{txt}': 'illegal characters "{" and "}"',
+ }
+
+ for (const [extension, description] of Object.entries(invalid_extensions)) {
+ define_file_picker_extension_error_test(showPickerMethod, extension, description)
+ }
+}
+
+function define_file_picker_extension_error_test(showPickerMethod, extension, description) {
+ promise_test(async t => {
+ await promise_rejects_js(
+ t, TypeError,
+ self[showPickerMethod](
+ { types: [{ accept: { 'text/plain': ['.txt', extension] } }] }));
+ }, showPickerMethod + ': invalid extension "' + extension + '". ' + description + ".");
+} \ No newline at end of file
diff --git a/testing/web-platform/tests/file-system-access/showSaveFilePicker-manual.https.html b/testing/web-platform/tests/file-system-access/showSaveFilePicker-manual.https.html
new file mode 100644
index 0000000000..332a1a4273
--- /dev/null
+++ b/testing/web-platform/tests/file-system-access/showSaveFilePicker-manual.https.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<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>
+<script src="resources/test-helpers.js"></script>
+
+<script>
+
+ promise_test(async t => {
+ await window.test_driver.bless(
+ 'show a file picker.<br />Please make a copy of file-system-access/resources/data/testfile.txt in a writable directory and pick that file');
+ const file = await self.showSaveFilePicker({
+ multiple: false, types: [
+ { description: 'Text files', accept: { 'text/plain': ['.txt'] } },
+ ],
+ });
+ assert_true(file instanceof FileSystemHandle);
+ assert_true(file instanceof FileSystemFileHandle);
+ assert_equals(file.kind, "file");
+ assert_equals(file.name, 'testfile.txt');
+ assert_equals(await (await file.getFile()).text(), '',
+ 'showSaveFilePicker should clear contents of file');
+
+ promise_test(async t => {
+ assert_equals(await file.queryPermission(), 'granted');
+ assert_equals(await file.queryPermission({ mode: 'readwrite' }), 'granted');
+ }, 'showSaveFilePicker returns correct permissions');
+ }, 'showSaveFilePicker works');
+
+</script>