chromium/chrome/test/data/pdf/ink2_save_test.ts

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

import {PluginController, SaveRequestType} from 'chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai/pdf_viewer_wrapper.js';
import {eventToPromise, microtasksFinished} from 'chrome://webui-test/test_util.js';

import {createMockPdfPluginForTest, finishInkStroke, getRequiredElement} from './test_util.js';

const viewer = document.body.querySelector('pdf-viewer')!;
const viewerToolbar = viewer.$.toolbar;
const controller = PluginController.getInstance();
const mockPlugin = createMockPdfPluginForTest();
controller.setPluginForTesting(mockPlugin);

function getDownloadControls() {
  return getRequiredElement(viewerToolbar, 'viewer-download-controls');
}

chrome.test.runTests([
  // Tests that while in annotation mode, on a PDF without any edits, clicking
  // the download button will save the PDF as original.
  async function testSaveOriginal() {
    viewerToolbar.toggleAnnotation();
    await microtasksFinished();
    chrome.test.assertTrue(viewerToolbar.annotationMode);

    const downloadControls = getDownloadControls();
    const downloadButton = downloadControls.$.download;
    const actionMenu = downloadControls.$.menu;
    chrome.test.assertFalse(actionMenu.open);

    downloadButton.click();

    // A message should be sent to the plugin to save as original.
    await eventToPromise('save', viewer);
    const saveMessage = mockPlugin.findMessage('save');
    chrome.test.assertTrue(saveMessage !== undefined);
    chrome.test.assertEq(saveMessage.saveRequestType, SaveRequestType.ORIGINAL);
    chrome.test.assertFalse(actionMenu.open);
    chrome.test.assertTrue(viewerToolbar.annotationMode);
    chrome.test.succeed();
  },

  // Tests that while in annotation mode, after adding an ink stroke, clicking
  // the download button will prompt the download menu.
  async function testSaveMenuWithStroke() {
    mockPlugin.clearMessages();

    const downloadControls = getDownloadControls();
    const downloadButton = downloadControls.$.download;
    const actionMenu = downloadControls.$.menu;

    chrome.test.assertFalse(actionMenu.open);

    finishInkStroke(controller);
    await microtasksFinished();
    downloadButton.click();

    // The download menu should be shown.
    await eventToPromise('download-menu-shown-for-testing', downloadControls);
    chrome.test.assertTrue(mockPlugin.findMessage('save') === undefined);
    chrome.test.assertTrue(actionMenu.open);
    chrome.test.succeed();
  },

  // Tests that while outside of annotation mode, on a PDF with an ink stroke,
  // clicking the download button will prompt the download menu.
  async function testSaveMenuWithStrokeExitAnnotationMode() {
    chrome.test.assertTrue(viewerToolbar.annotationMode);

    viewerToolbar.toggleAnnotation();
    await microtasksFinished();
    chrome.test.assertFalse(viewerToolbar.annotationMode);

    const downloadControls = getDownloadControls();
    const downloadButton = downloadControls.$.download;
    const actionMenu = downloadControls.$.menu;
    actionMenu.close();

    downloadButton.click();

    // The download menu should be shown.
    await eventToPromise('download-menu-shown-for-testing', downloadControls);
    chrome.test.assertTrue(mockPlugin.findMessage('save') === undefined);
    chrome.test.assertTrue(actionMenu.open);
    chrome.test.succeed();
  },

  // An undo operation will remove the only ink stroke from the PDF. Tests that
  // while in annotation mode, after an undo operation, clicking the download
  // button will save the PDF as original.
  async function testSaveOriginalAfterUndo() {
    chrome.test.assertFalse(viewerToolbar.annotationMode);

    viewerToolbar.toggleAnnotation();
    await microtasksFinished();
    chrome.test.assertTrue(viewerToolbar.annotationMode);

    mockPlugin.clearMessages();

    const undoButton =
        getRequiredElement<HTMLButtonElement>(viewerToolbar, '#undo');
    chrome.test.assertFalse(undoButton.disabled);

    const downloadControls = getDownloadControls();
    const downloadButton = downloadControls.$.download;
    const actionMenu = downloadControls.$.menu;
    actionMenu.close();

    undoButton.click();
    await microtasksFinished();

    // After undo, there aren't any ink strokes on the PDF, and the button will
    // be disabled.
    chrome.test.assertTrue(undoButton.disabled);

    downloadButton.click();

    // A message should be sent to the plugin to save as original.
    await eventToPromise('save', viewer);
    const saveMessage = mockPlugin.findMessage('save');
    chrome.test.assertTrue(saveMessage !== undefined);
    chrome.test.assertEq(saveMessage.saveRequestType, SaveRequestType.ORIGINAL);
    chrome.test.assertFalse(actionMenu.open);
    chrome.test.succeed();
  },

  // A redo operation will add the ink stroke back to the PDF. Tests that while
  // in annotation mode, after a redo operation, clicking the download button
  // will prompt the download menu.
  async function testSaveMenuAfterRedo() {
    mockPlugin.clearMessages();

    const redoButton =
        getRequiredElement<HTMLButtonElement>(viewerToolbar, '#redo');
    chrome.test.assertFalse(redoButton.disabled);

    const downloadControls = getDownloadControls();
    const downloadButton = downloadControls.$.download;
    const actionMenu = downloadControls.$.menu;

    redoButton.click();
    await microtasksFinished();
    downloadButton.click();

    // The download menu should be shown.
    await eventToPromise('download-menu-shown-for-testing', downloadControls);
    chrome.test.assertTrue(mockPlugin.findMessage('save') === undefined);
    chrome.test.assertTrue(actionMenu.open);
    chrome.test.succeed();
  },

  // Tests that while in annotation mode, after undoing all edits on the PDF,
  // clicking the download button will save the PDF as original.
  async function testSaveOriginalAfterFullUndo() {
    mockPlugin.clearMessages();

    // Add another ink stroke. There should now be two ink strokes on the PDF.
    finishInkStroke(controller);
    await microtasksFinished();

    const undoButton =
        getRequiredElement<HTMLButtonElement>(viewerToolbar, '#undo');
    chrome.test.assertFalse(undoButton.disabled);

    // Undo both ink strokes.
    undoButton.click();
    undoButton.click();
    await microtasksFinished();

    // There shouldn't be any ink strokes on the PDF.
    chrome.test.assertTrue(undoButton.disabled);

    const downloadControls = getDownloadControls();
    const downloadButton = downloadControls.$.download;
    const actionMenu = downloadControls.$.menu;
    actionMenu.close();

    downloadButton.click();

    // A message should be sent to the plugin to save as original.
    await eventToPromise('save', viewer);
    const saveMessage = mockPlugin.findMessage('save');
    chrome.test.assertTrue(saveMessage !== undefined);
    chrome.test.assertEq(saveMessage.saveRequestType, SaveRequestType.ORIGINAL);
    chrome.test.assertFalse(actionMenu.open);
    chrome.test.succeed();
  },
]);