chromium/chrome/test/data/webui/chromeos/diagnostics/touchscreen_tester_test.ts

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

import 'chrome://diagnostics/touchscreen_tester.js';
import 'chrome://webui-test/chromeos/mojo_webui_test_support.js';

import {DialogType, SCREEN_MAX_LENGTH, TouchEventType, TouchscreenTesterElement} from 'chrome://diagnostics/touchscreen_tester.js';
import {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js';
import {assert} from 'chrome://resources/js/assert.js';
import {assertDeepEquals, assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chromeos/chai_assert.js';
import {MockController} from 'chrome://webui-test/mock_controller.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

suite('touchscreenTesterTestSuite', function() {
  let touchscreenTesterElement: TouchscreenTesterElement|null = null;

  setup(() => {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
  });

  teardown(() => {
    touchscreenTesterElement?.remove();
    touchscreenTesterElement = null;
  });


  function initializeTouchscreenTester(): Promise<void> {
    touchscreenTesterElement = document.createElement('touchscreen-tester');
    assert(touchscreenTesterElement);
    document.body.appendChild(touchscreenTesterElement);

    return flushTasks();
  }

  /**
   * openTester is a helper function for some boilerplate code. It opens the
   * intro dialog, clicks the start testing button and makes sure canvas dialog
   * is open. The function then returns the canvas dialog.
   */
  async function openTester(): Promise<CrDialogElement> {
    assert(touchscreenTesterElement);
    const introDialog = touchscreenTesterElement.getDialog(DialogType.INTRO);
    introDialog.showModal();
    await flushTasks();
    assertTrue(introDialog.open);

    const getStartedButton =
    strictQuery('cr-button', introDialog, CrButtonElement);
    getStartedButton.click();
    await flushTasks();
    assertFalse(introDialog.open);

    const canvasDialog = touchscreenTesterElement.getDialog(DialogType.CANVAS);
    assertTrue(canvasDialog.open);

    return canvasDialog;
  }

  test('OpenIntroDialog', async () => {
    await initializeTouchscreenTester();
    assert(touchscreenTesterElement);
    const introDialog = touchscreenTesterElement.getDialog(DialogType.INTRO);
    introDialog.showModal();
    await flushTasks();
    assertTrue(introDialog.open);
  });

  test('OpenCanvasDialog', async () => {
    await initializeTouchscreenTester();
    const canvasDialog = await openTester();

    const canvas = canvasDialog.querySelector('canvas');
    assert(canvas);
    assertEquals(canvas.width, SCREEN_MAX_LENGTH);
    assertEquals(canvas.height, SCREEN_MAX_LENGTH);
  });

  test('OnDrawStart', async () => {
    await initializeTouchscreenTester();
    assert(touchscreenTesterElement);
    await openTester();

    // Mock drawTrailMark and drawTrail function.
    const drawingProvider = touchscreenTesterElement.getDrawingProvider();
    const mockController = new MockController();
    const mockDrawTrailMark =
        mockController.createFunctionMock(drawingProvider, 'drawTrailMark');
    const mockDrawTrail =
        mockController.createFunctionMock(drawingProvider, 'drawTrail');

    const expectedTouches = new Map();
    const mockTouchEvents = [
      {
        id: 1,
        point: {x: 100, y: 150},
        pressure: 50,
      },
      {
        id: 2,
        point: {x: 500, y: 550},
        pressure: 30,
      },
    ];

    for (const {id, point, pressure} of mockTouchEvents) {
      // Add expected function call signature.
      mockDrawTrailMark.addExpectation(point.x, point.y);
      mockDrawTrail.addExpectation(
          point.x - 1, point.y, point.x, point.y, pressure);
      expectedTouches.set(id, point);
      touchscreenTesterElement.onDrawStart(id, point, pressure);

      assertDeepEquals(expectedTouches, touchscreenTesterElement.getTouches());
      mockController.verifyMocks();
    }
  });

  test('OnDraw', async () => {
    await initializeTouchscreenTester();
    assert(touchscreenTesterElement);
    await openTester();

    // Mock drawTrailMark and drawTrail function.
    const drawingProvider = touchscreenTesterElement.getDrawingProvider();
    const mockController = new MockController();
    const mockDrawTrail =
        mockController.createFunctionMock(drawingProvider, 'drawTrail');

    const expectedTouches = new Map();
    const mockTouchEvents = [
      {
        type: TouchEventType.START,
        id: 1,
        point: {x: 100, y: 150},
        pressure: 40,
      },
      {
        type: TouchEventType.MOVE,
        id: 1,
        point: {x: 110, y: 160},
        pressure: 30,
      },
    ];

    for (const {type, id, point, pressure} of mockTouchEvents) {
      if (type === TouchEventType.START) {
        mockDrawTrail.addExpectation(
            point.x - 1, point.y, point.x, point.y, pressure);
        touchscreenTesterElement.onDrawStart(id, point, pressure);
      } else if (type === TouchEventType.MOVE) {
        const previousPt = expectedTouches.get(id);
        mockDrawTrail.addExpectation(
            previousPt.x, previousPt.y, point.x, point.y, pressure);
        touchscreenTesterElement.onDraw(id, point, pressure);
      }

      expectedTouches.set(id, point);
      assertDeepEquals(expectedTouches, touchscreenTesterElement.getTouches());
      mockController.verifyMocks();
    }
  });

  test('OnDrawEnd', async () => {
    await initializeTouchscreenTester();
    assert(touchscreenTesterElement);
    await openTester();

    // Mock drawTrailMark and drawTrail function.
    const drawingProvider = touchscreenTesterElement.getDrawingProvider();
    const mockController = new MockController();
    const mockDrawTrailMark =
        mockController.createFunctionMock(drawingProvider, 'drawTrailMark');
    const mockDrawTrail =
        mockController.createFunctionMock(drawingProvider, 'drawTrail');

    const expectedTouches = new Map();
    const mockTouchEvents = [
      {
        type: TouchEventType.START,
        id: 1,
        point: {x: 100, y: 150},
        pressure: 40,
      },
      {
        type: TouchEventType.MOVE,
        id: 1,
        point: {x: 110, y: 160},
        pressure: 30,
      },
      {
        type: TouchEventType.END,
        id: 1,
        point: {x: 110, y: 160},
        pressure: 30,
      },
    ];

    for (const {type, id, point, pressure} of mockTouchEvents) {
      if (type === TouchEventType.START) {
        mockDrawTrailMark.addExpectation(point.x, point.y);
        mockDrawTrail.addExpectation(
            point.x - 1, point.y, point.x, point.y, pressure);
        touchscreenTesterElement.onDrawStart(id, point, pressure);
        expectedTouches.set(id, point);
      } else if (type === TouchEventType.MOVE) {
        const previousPt = expectedTouches.get(id);
        mockDrawTrail.addExpectation(
            previousPt.x, previousPt.y, point.x, point.y, pressure);
        touchscreenTesterElement.onDraw(id, point, pressure);
        expectedTouches.set(id, point);
      } else if (type === TouchEventType.END) {
        mockDrawTrailMark.addExpectation(point.x, point.y);
        touchscreenTesterElement.onDrawEnd(id, point);
        expectedTouches.delete(id);
      }

      assertDeepEquals(expectedTouches, touchscreenTesterElement.getTouches());
      mockController.verifyMocks();
    }
  });

  test('ObserveDataSource', async () => {
    await initializeTouchscreenTester();
    assert(touchscreenTesterElement);
    const canvasDialog = await openTester();
    const canvas = canvasDialog.querySelector('canvas');
    assert(canvas);
    const mockController = new MockController();

    // Create a mock touch.
    const touch = new Touch({
      identifier: 1,
      target: canvas,
      pageX: 300,
      pageY: 200,
      force: 0.3,
    });
    const expectedTouchPt = {
      x: touch.pageX - canvas.offsetLeft,
      y: touch.pageY - canvas.offsetTop,
    };

    for (const [eventType, mockFunctionName] of [
             [TouchEventType.START, 'onDrawStart'],
             [TouchEventType.MOVE, 'onDraw'],
             [TouchEventType.END, 'onDrawEnd']]) {
      const mockFunction = mockController.createFunctionMock(
          touchscreenTesterElement, mockFunctionName);
      if (mockFunctionName === 'onDrawEnd') {
        mockFunction.addExpectation(touch.identifier, expectedTouchPt);
      } else {
        mockFunction.addExpectation(
            touch.identifier, expectedTouchPt, touch.force);
      }
      assert(eventType);
      const touchEvent = eventToPromise(eventType, canvas);
      canvas.dispatchEvent(
          new TouchEvent(eventType, {changedTouches: [touch]}));
      await touchEvent;
      mockController.verifyMocks();
    }
  });
});