chromium/third_party/blink/web_tests/http/tests/devtools/console/console-viewport-selection.js

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {TestRunner} from 'test_runner';
import {ConsoleTestRunner} from 'console_test_runner';

import * as Platform from 'devtools/core/platform/platform.js';
import * as Console from 'devtools/panels/console/console.js';

(async function() {
  TestRunner.addResult(`Tests that console viewport handles selection properly.\n`);
  await TestRunner.showPanel('console');
  await TestRunner.evaluateInPagePromise(`
      function populateConsoleWithMessages(count)
      {
          for (var i = 0; i < count - 1; ++i)
              console.log("Message #" + i);
          console.log("hello %cworld", "color: blue");
      }
      //# sourceURL=console-viewport-selection.js
    `);

  ConsoleTestRunner.fixConsoleViewportDimensions(600, 200);
  var consoleView = Console.ConsoleView.ConsoleView.instance();
  var viewport = consoleView.viewport;
  const minimumViewportMessagesCount = 10;
  const messagesCount = 150;
  const middleMessage = messagesCount / 2;
  var viewportMessagesCount;

  var testSuite = [
    async function testSelectionSingleLineText(next) {
      viewport.invalidate();
      viewport.forceScrollItemToBeFirst(0);
      viewportMessagesCount = viewport.lastVisibleIndex() - viewport.firstVisibleIndex() + 1;
      await selectMessages(middleMessage, 2, middleMessage, 7);
      dumpSelectionText();
      next();
    },

    async function testReversedSelectionSingleLineText(next) {
      await selectMessages(middleMessage, 7, middleMessage, 2);
      dumpSelectionText();
      next();
    },

    async function testSelectionMultiLineText(next) {
      await selectMessages(middleMessage - 1, 4, middleMessage + 1, 7);
      dumpSelectionText();
      next();
    },

    async function testSimpleVisibleSelection(next) {
      await selectMessages(middleMessage - 3, 6, middleMessage + 2, 6);
      dumpSelectionModel();
      next();
    },

    function testHalfScrollSelectionUp(next) {
      viewport.forceScrollItemToBeFirst(middleMessage);
      dumpSelectionModel();
      next();
    },

    function testHalfScrollSelectionDown(next) {
      viewport.forceScrollItemToBeLast(middleMessage);
      dumpSelectionModel();
      next();
    },

    function testScrollSelectionAwayUp(next) {
      viewport.forceScrollItemToBeFirst(0);
      dumpSelectionModel();
      next();
    },

    function testScrollSelectionAwayDown(next) {
      consoleView.immediatelyScrollToBottom();
      viewport.refresh();
      dumpSelectionModel();
      next();
    },

    async function testShiftClickSelectionOver(next) {
      await emulateShiftClickOnMessage(minimumViewportMessagesCount);
      dumpSelectionModel();
      next();
    },

    async function testShiftClickSelectionBelow(next) {
      await emulateShiftClickOnMessage(messagesCount - minimumViewportMessagesCount);
      dumpSelectionModel();
      next();
    },

    function testRemoveSelection(next) {
      var selection = window.getSelection();
      selection.removeAllRanges();
      dumpSelectionModel();
      next();
    },

    async function testReversedVisibleSelection(next) {
      await selectMessages(middleMessage + 1, 6, middleMessage - 4, 6);
      dumpSelectionModel();
      next();
    },

    async function testShiftClickReversedSelectionOver(next) {
      await emulateShiftClickOnMessage(minimumViewportMessagesCount);
      dumpSelectionModel();
      next();
    },

    async function testShiftClickReversedSelectionBelow(next) {
      await emulateShiftClickOnMessage(messagesCount - minimumViewportMessagesCount);
      dumpSelectionModel();
      next();
    },

    function testZeroOffsetSelection(next) {
      viewport.forceScrollItemToBeLast(messagesCount - 1);
      var lastMessageElement = viewport.renderedElementAt(messagesCount - 1);
      // there is a blue-colored "world" span in last message.
      var blueSpan = lastMessageElement;
      while (blueSpan.nodeName !== 'SPAN' || blueSpan.textContent !== 'world')
        blueSpan = blueSpan.traverseNextNode();

      window.getSelection().setBaseAndExtent(blueSpan, 0, blueSpan, blueSpan.childNodes.length);
      TestRunner.addResult('Selected text: ' + viewport.selectedText());
      next();
    },

    function testSelectAll(next) {
      viewport.forceScrollItemToBeFirst(0);

      // Set some initial selection in console.
      var base = consoleView.itemElement(messagesCount - 2).element();
      var extent = consoleView.itemElement(messagesCount - 1).element();
      window.getSelection().setBaseAndExtent(base, 0, extent, 0);

      // Try to select all messages.
      document.execCommand('selectAll');

      var text = viewport.selectedText();
      var count = text ? text.split('\n').length : 0;
      TestRunner.addResult(
          count === messagesCount ? 'Selected all ' + count + ' messages.' :
                                    'Selected ' + count + ' messages instead of ' + messagesCount);
      next();
    },

    function testSelectWithNonTextNodeContainer(next) {
      viewport.forceScrollItemToBeFirst(0);

      var nonTextNodeBase = consoleView.itemElement(1).element();
      var nonTextNodeExtent = consoleView.itemElement(2).element();
      var textNodeBase = consoleView.itemElement(1).element().traverseNextTextNode();
      var textNodeExtent = consoleView.itemElement(2).element().traverseNextTextNode();

      window.getSelection().setBaseAndExtent(nonTextNodeBase, 0, nonTextNodeExtent, 0);
      TestRunner.addResult('Selected text: ' + viewport.selectedText());

      window.getSelection().setBaseAndExtent(textNodeBase, 0, nonTextNodeExtent, 0);
      TestRunner.addResult('Selected text: ' + viewport.selectedText());

      window.getSelection().setBaseAndExtent(nonTextNodeBase, 0, textNodeExtent, 0);
      TestRunner.addResult('Selected text: ' + viewport.selectedText());

      next();
    }
  ];

  var awaitingMessagesCount = messagesCount;
  function messageAdded() {
    if (!--awaitingMessagesCount)
      TestRunner.runTestSuite(testSuite);
  }

  ConsoleTestRunner.addConsoleSniffer(messageAdded, true);
  TestRunner.evaluateInPage(Platform.StringUtilities.sprintf('populateConsoleWithMessages(%d)', messagesCount));

  function dumpSelectionModelElement(model) {
    if (!model)
      return 'null';
    return Platform.StringUtilities.sprintf('{item: %d, offset: %d}', model.item, model.offset);
  }

  function dumpSelectionModel() {
    viewport.refresh();
    var text = Platform.StringUtilities.sprintf(
        'anchor = %s, head = %s', dumpSelectionModelElement(viewport.anchorSelection),
        dumpSelectionModelElement(viewport.headSelection));
    TestRunner.addResult(text);
  }

  function dumpSelectionText() {
    viewport.refresh();
    var text = viewport.selectedText();
    TestRunner.addResult('Selected text:<<<EOL\n' + text + '\nEOL');
  }

  async function emulateShiftClickOnMessage(messageIndex) {
    viewport.refresh();
    var selection = window.getSelection();
    if (!selection || !selection.rangeCount) {
      TestRunner.addResult('FAILURE: There\'s no selection');
      return;
    }
    viewport.forceScrollItemToBeFirst(Math.max(messageIndex - minimumViewportMessagesCount / 2, 0));
    var element = consoleView.itemElement(messageIndex).element();
    // Console messages contain live locations.
    await TestRunner.waitForPendingLiveLocationUpdates();
    selection.setBaseAndExtent(selection.anchorNode, selection.anchorOffset, element, 0);
    viewport.refresh();
  }

  async function selectMessages(fromMessage, fromTextOffset, toMessage, toTextOffset) {
    if (Math.abs(toMessage - fromMessage) > minimumViewportMessagesCount) {
      TestRunner.addResult(Platform.StringUtilities.sprintf(
          'FAILURE: Cannot select more than %d messages (requested to select from %d to %d',
          minimumViewportMessagesCount, fromMessage, toMessage));
      TestRunner.completeTest();
      return;
    }
    viewport.forceScrollItemToBeFirst(Math.min(fromMessage, toMessage));

    await ConsoleTestRunner.selectConsoleMessages(fromMessage, fromTextOffset, toMessage, toTextOffset);
    viewport.refresh();
  }
})();