chromium/third_party/blink/web_tests/editing/pasteboard/data-transfer-items.html

<!doctype html>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../assert_selection.js"></script>
<script>
const t = async_test('DataTransferItems test');
let pendingCallbackCount = 0;

function removeStyle(text) {
  return text.replace(/ style=".*"/, '');
}

function checkItem(which, items, index, expectedData, expectedType) {
  assert_equals(items[index].kind, 'string',
      `${which}: items[${index}].kind`);
  assert_equals(items[index].type, expectedType,
      `${which}: items[${index}].type`);
  items[index].getAsString(actualData => {
      t.step(() =>
        assert_equals(removeStyle(actualData), expectedData,
            `${which}: items[${index}].getAsString()`));
      --pendingCallbackCount;
      if (pendingCallbackCount > 0)
          return;
      t.done();
  });
}

t.step(() => {
    assert_not_equals(window.internals, undefined,
      'This test requires window.internals to access clipboard');

    assert_selection(
      '<div contenteditable>^xyz|</div>',
      selection => {
        const editor = selection.document.querySelector('div');

        let savedDataTransferItems;
        let savedDataTransferItem;

        editor.addEventListener('copy', event => {
          const items = event.clipboardData.items;
          // Replace exiting clipboard data.
          items.add('abc', 'text/plain');
          items.add('<b>def</b>', 'text/html');

          assert_equals(items.length, 2, 'copy: items.length');
          assert_equals(items[3], undefined, 'copy: items[3]');
          checkItem('copy', items, 0, 'abc', 'text/plain');
          checkItem('copy', items, 1, '<b>def</b>', 'text/html');

          // Check that an exception is properly raised when attempting to
          // add a duplicate string type.
          assert_throws_dom('NotSupportedError', selection.window.DOMException,
              () => items.add('Moo', 'text/plain'),
              'Adding another text/plain data');
        });

        editor.addEventListener('paste', event => {
          const items = event.clipboardData.items;

          // Cache references to make sure they are not  accessible
          // outside the event handler.
          savedDataTransferItems = items;
          savedDataTransferItem = items[0];

          // Checking that a read-only DataTransferItems cannot be
          // mutated...
          items.add('new', 'text/plain');

          assert_equals(items.length, 2, 'paste: items.length');
          assert_equals(items[3], undefined, 'paste: items[3]');
          checkItem('paste', items, 0, 'abc', 'text/plain');
          checkItem('paste', items, 1, '<b>def</b>', 'text/html');
        });

        selection.document.execCommand('copy');
        selection.document.execCommand('paste');
        assert_equals(savedDataTransferItems.length, 0,
            'savedDataTransferItems.length');

        savedDataTransferItems.add('Security?', 'text/foo');
        assert_equals(savedDataTransferItems.length, 0,
            'savedDataTransferItems.length after add()');

        assert_equals(savedDataTransferItems[0], undefined,
            'savedDataTransferItems[0]');

        assert_equals(typeof(savedDataTransferItem), 'object',
            'savedDataTransferItem');
      },
      '<div contenteditable>xyz|</div>',
      {description: 'DataTransferItem(s) API at copy and paste time',
       removeSampleIfSucceeded: false});
});
</script>