'use strict'; // This script depends on the following script: // /file-system-access/resources/test-helpers.js // /service-workers/service-worker/resources/test-helpers.sub.js // Define the URL constants used for each type of message target, including // iframes and workers. const kDocumentMessageTarget = 'resources/message-target.html'; const kSharedWorkerMessageTarget = 'resources/message-target-shared-worker.js'; const kServiceWorkerMessageTarget = 'resources/message-target-service-worker.js'; const kDedicatedWorkerMessageTarget = 'resources/message-target-dedicated-worker.js'; function create_dedicated_worker(test, url) { const dedicated_worker = new Worker(url); test.add_cleanup(() => { dedicated_worker.terminate(); }); return dedicated_worker; } async function create_service_worker(test, script_url, scope) { const registration = await service_worker_unregister_and_register( test, script_url, scope); test.add_cleanup(() => { return registration.unregister(); }); return registration; } // Creates an iframe and waits to receive a message from the iframe. // Valid |options| include src, srcdoc and sandbox, which mirror the // corresponding iframe element properties. async function add_iframe(test, options) { const iframe = document.createElement('iframe'); if (options.sandbox !== undefined) { iframe.sandbox = options.sandbox; } if (options.src !== undefined) { iframe.src = options.src; } if (options.srcdoc !== undefined) { iframe.srcdoc = options.srcdoc; } document.body.appendChild(iframe); test.add_cleanup(() => { iframe.remove(); }); await wait_for_loaded_message(self); return iframe; } // Creates a child window using window.open() and waits to receive a message // from the child window. async function open_window(test, url) { const child_window = window.open(url); test.add_cleanup(() => { child_window.close(); }); await wait_for_loaded_message(self); return child_window; } // Wait until |receiver| gets a message event with the data set to 'LOADED'. // The postMessage() tests use messaging instead of the loaded event because // cross-origin child windows from window.open() do not dispatch the loaded // event to the parent window. async function wait_for_loaded_message(receiver) { const message_promise = new Promise((resolve, reject) => { receiver.addEventListener('message', message_event => { if (message_event.data === 'LOADED') { resolve(); } else { reject('The message target must receive a "LOADED" message response.'); } }); }); await message_promise; } // Sets up a new message channel. Sends one port to |target| and then returns // the other port. function create_message_channel(target, target_origin) { const message_channel = new MessageChannel(); const message_data = { type: 'receive-message-port', message_port: message_channel.port2 }; target.postMessage( message_data, { transfer: [message_channel.port2], targetOrigin: target_origin }); message_channel.port1.start(); return message_channel.port1; } // Creates a variety of different FileSystemFileHandles for testing. async function create_file_system_handles(test, root) { // Create some files to use with postMessage(). const empty_file = await createEmptyFile(test, 'empty-file', root); const first_file = await createFileWithContents( test, 'first-file-with-contents', 'first-text-content', root); const second_file = await createFileWithContents( test, 'second-file-with-contents', 'second-text-content', root); // Create an empty directory to use with postMessage(). const empty_directory = await createDirectory(test, 'empty-directory', root); // Create a directory containing both files and subdirectories to use // with postMessage(). const directory_with_files = await createDirectory(test, 'directory-with-files', root); await createFileWithContents(test, 'first-file-in-directory', 'first-directory-text-content', directory_with_files); await createFileWithContents(test, 'second-file-in-directory', 'second-directory-text-content', directory_with_files); const subdirectory = await createDirectory(test, 'subdirectory', directory_with_files); await createFileWithContents(test, 'first-file-in-subdirectory', 'first-subdirectory-text-content', subdirectory); return [ empty_file, first_file, second_file, // Include the same FileSystemFileHandle twice. second_file, empty_directory, // Include the Same FileSystemDirectoryHandle object twice. empty_directory, directory_with_files ]; } // Tests sending an array of FileSystemHandles to |target| with postMessage(). // The array includes both FileSystemFileHandles and FileSystemDirectoryHandles. // After receiving the message, |target| accesses all cloned handles by // serializing the properties of each handle to a JavaScript object. // // |target| then responds with the resulting array of serialized handles. The // response also includes the array of cloned handles, which creates more // clones. After receiving the response, this test runner verifies that both // the serialized handles and the cloned handles contain the expected properties. async function do_post_message_test( test, root_dir, receiver, target, target_origin) { // Create and send the handles to |target|. const handles = await create_file_system_handles(test, root_dir, target, target_origin); target.postMessage( { type: 'receive-file-system-handles', cloned_handles: handles }, { targetOrigin: target_origin }); // Wait for |target| to respond with results. const event_watcher = new EventWatcher(test, receiver, 'message'); const message_event = await event_watcher.wait_for('message'); const response = message_event.data; assert_equals(response.type, 'receive-serialized-file-system-handles', 'The test runner must receive a "serialized-file-system-handles" ' + `message response. Actual response: ${response}`); // Verify the results. const expected_serialized_handles = await serialize_handles(handles); assert_equals_serialized_handles( response.serialized_handles, expected_serialized_handles); await assert_equals_cloned_handles(response.cloned_handles, handles); } // Runs the same test as do_post_message_test(), but uses a MessagePort. // This test starts by establishing a message channel between the test runner // and |target|. Afterwards, the test sends FileSystemHandles through the // message port channel. async function do_message_port_test(test, root_dir, target, target_origin) { const message_port = create_message_channel(target, target_origin); await do_post_message_test( test, root_dir, /*receiver=*/ message_port, /*target=*/ message_port); }