chromium/ui/file_manager/integration_tests/file_manager/office.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 {ENTRIES, getCaller, pending, repeatUntil, RootPath, sendTestMessage} from '../test_util.js';

import {remoteCall} from './background.js';
import {FILE_MANAGER_SWA_APP_ID, FILE_SWA_BASE_URL} from './test_data.js';

/**
 * Returns 'Open in Google Docs' task descriptor.
 */
function openDocWithDriveDescriptor():
    chrome.fileManagerPrivate.FileTaskDescriptor {
  const filesAppId = FILE_MANAGER_SWA_APP_ID;
  const filesTaskType = 'web';
  const actionId = `${FILE_SWA_BASE_URL}?open-web-drive-office-word`;

  return {appId: filesAppId, taskType: filesTaskType, actionId: actionId};
}

/**
 * Returns 'Open with Excel' task descriptor.
 */
function openExcelWithDriveDescriptor():
    chrome.fileManagerPrivate.FileTaskDescriptor {
  const filesAppId = FILE_MANAGER_SWA_APP_ID;
  const filesTaskType = 'web';
  const actionId = `${FILE_SWA_BASE_URL}?open-web-drive-office-excel`;

  return {appId: filesAppId, taskType: filesTaskType, actionId: actionId};
}

/**
 * Returns 'Open in PowerPoint' task descriptor.
 */
function openPowerPointWithDriveDescriptor():
    chrome.fileManagerPrivate.FileTaskDescriptor {
  const filesAppId = FILE_MANAGER_SWA_APP_ID;
  const filesTaskType = 'web';
  const actionId = `${FILE_SWA_BASE_URL}?open-web-drive-office-powerpoint`;

  return {appId: filesAppId, taskType: filesTaskType, actionId: actionId};
}


/**
 * Waits for the expected number of tasks executions, and returns the descriptor
 * of the last executed task.
 *
 * @param appId Window ID.
 */
async function getExecutedTask(appId: string, expectedCount: number = 1):
    Promise<chrome.fileManagerPrivate.FileTaskDescriptor> {
  const caller = getCaller();

  // Wait until a task has been executed.
  await repeatUntil(async () => {
    const executeTaskCount = await remoteCall.callRemoteTestUtil<number>(
        'staticFakeCounter', appId, ['chrome.fileManagerPrivate.executeTask']);
    if (executeTaskCount === expectedCount) {
      return true;
    }
    chrome.test.assertTrue(executeTaskCount < expectedCount);
    return pending(caller, 'Waiting for a task to execute');
  });

  // Arguments provided for the last call to executeTask().
  const executeTaskArgs = (await remoteCall.callRemoteTestUtil<
                           chrome.fileManagerPrivate.FileTaskDescriptor[][]>(
      'staticFakeCalledArgs', appId,
      ['chrome.fileManagerPrivate.executeTask']))[expectedCount - 1]!;

  // The task descriptor is the first argument.
  return executeTaskArgs[0]!;
}

export async function openOfficeWordFile() {
  await sendTestMessage({
    name: 'expectFileTask',
    fileNames: [ENTRIES.smallDocxHosted.targetPath],
    openType: 'launch',
  });

  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallDocxHosted]);

  // Disable office setup flow so the dialog doesn't open when the file is
  // opened.
  await sendTestMessage({name: 'setOfficeFileHandler'});

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocxHosted.nameText]));

  // Check that the Word file's alternate URL has been opened in a browser
  // window. The query parameter is concatenated to the URL as office files
  // opened from drive have this query parameter added
  // (https://crrev.com/c/3867338).
  await remoteCall.waitForLastOpenedBrowserTabUrl(
      ENTRIES.smallDocxHosted.alternateUrl.concat('&cros_files=true'));
}

export async function openOfficeWordFromMyFiles() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DOWNLOADS, [ENTRIES.smallDocx]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.EMPTY.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['empty']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocx.nameText]));

  // The available Office task should be "Upload to Drive".
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(
      taskDescriptor.actionId, openDocWithDriveDescriptor().actionId);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

// Tests that "Upload to Drive" cannot be enabled if the "Upload Office To
// Cloud" flag is disabled (test setup similar to `openOfficeWordFromMyFiles`).
export async function uploadToDriveRequiresUploadOfficeToCloudEnabled() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DOWNLOADS, [ENTRIES.smallDocx]);
  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.EMPTY.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['empty']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocx.nameText]));

  // Since the Upload Office To Cloud flag isn't enabled, the Upload to Drive
  // task should not be available: another task should have been executed
  // instead (QuickOffice or generic task).
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertFalse(
      taskDescriptor.actionId === openDocWithDriveDescriptor().actionId);
  chrome.test.assertFalse(
      taskDescriptor.actionId === openDocWithDriveDescriptor().actionId);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openOfficeWordFromDrive() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallDocxHosted]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.OPENED.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocxHosted.nameText]));

  // The Drive/Docs task should be available and executed.
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(openDocWithDriveDescriptor(), taskDescriptor);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openOfficeExcelFromDrive() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallXlsxPinned]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.OPENED.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallXlsxPinned.nameText]));

  // The Web Drive Office Excel task should be available and executed.
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(openExcelWithDriveDescriptor(), taskDescriptor);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openOfficePowerPointFromDrive() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallPptxPinned]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.OPENED.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallPptxPinned.nameText]));

  // The Web Drive Office PowerPoint task should be available and executed.
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(openPowerPointWithDriveDescriptor(), taskDescriptor);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openMultipleOfficeWordFromDrive() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [],
      [ENTRIES.smallDocx, ENTRIES.smallDocxPinned, ENTRIES.smallDocxHosted]);

  const enterKey = ['#file-list', 'Enter', false, false, false] as const;

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.OPENED.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Select all the files.
  const ctrlA = ['#file-list', 'a', true, false, false] as const;
  await remoteCall.fakeKeyDown(appId, ...ctrlA);

  // Check: the file-list should show 3 selected files.
  const caller = getCaller();
  await repeatUntil(async () => {
    const element = await remoteCall.waitForElement(
        appId, '.check-select #files-selected-label');
    if (element.text === '3 files selected') {
      return;
    }
    return pending(
        caller, `Waiting for files to be selected, got: ${element.text}`);
  });

  let taskDescriptor;
  let expectedExecuteTaskCount = 0;

  // Wait for the tasks calculation to complete, updating the "Open" button.
  await remoteCall.waitForElement(appId, '#tasks[get-tasks-completed]');

  // Wait until the open button is available.
  await remoteCall.waitForElement(appId, '#tasks');

  // TODO(petermarshall): Check that the Docs task is available but that we fell
  // back to Quick office: one of the selected entries doesn't have a
  // "docs.google.com" alternate URL.

  // Press Enter to execute the task.
  remoteCall.fakeKeyDown(appId, ...enterKey);

  // Check that it's the Docs task.
  expectedExecuteTaskCount++;
  taskDescriptor = await getExecutedTask(appId, expectedExecuteTaskCount);
  chrome.test.assertEq(
      taskDescriptor.actionId, openDocWithDriveDescriptor().actionId);

  // Unselect the file that doesn't have an alternate URL.
  await remoteCall.waitAndClickElement(
      appId, `#file-list [file-name="${ENTRIES.smallDocx.nameText}"]`,
      {ctrl: true});

  // Wait for the file to be unselected.
  await remoteCall.waitForElement(
      appId, `[file-name="${ENTRIES.smallDocx.nameText}"]:not([selected])`);

  // Press Enter.
  remoteCall.fakeKeyDown(appId, ...enterKey);

  // The Drive/Docs task should be available and executed.
  expectedExecuteTaskCount++;
  taskDescriptor = await getExecutedTask(appId, expectedExecuteTaskCount);
  chrome.test.assertEq(openDocWithDriveDescriptor(), taskDescriptor);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openOfficeWordFromDriveNotSynced() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallDocx]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.OPENED.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocx.nameText]));

  // The Drive/Docs task should be available and executed.
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(
      taskDescriptor.actionId, openDocWithDriveDescriptor().actionId);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openOfficeWordFromMyFilesOffline() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DOWNLOADS, [ENTRIES.smallDocx]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.EMPTY.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['empty']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocx.nameText]));

  // The Drive/Docs task should be executed, but it will fall back to
  // QuickOffice.
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(
      taskDescriptor.actionId, openDocWithDriveDescriptor().actionId);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

export async function openOfficeWordFromDriveOffline() {
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallDocxPinned]);

  // Fake chrome.fileManagerPrivate.executeTask to return
  // chrome.fileManagerPrivate.TaskResult.OPENED.
  const fakeData = {
    'chrome.fileManagerPrivate.executeTask': ['static_fake', ['opened']],
  };
  await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);

  // Open file.
  chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
      'openFile', appId, [ENTRIES.smallDocxPinned.nameText]));

  // The Drive/Docs task should be executed, but it will fall back to
  // QuickOffice.
  const taskDescriptor = await getExecutedTask(appId);
  chrome.test.assertEq(
      taskDescriptor.actionId, openDocWithDriveDescriptor().actionId);

  // Remove fakes.
  const removedCount = await remoteCall.callRemoteTestUtil(
      'removeAllForegroundFakes', appId, []);
  chrome.test.assertEq(1, removedCount);
}

/** Tests that the educational nudge is displayed when the preference is set. */
export async function officeShowNudgeGoogleDrive() {
  // Set the pref emulating that the user has moved a file.
  await sendTestMessage({
    name: 'setPrefOfficeFileMovedToGoogleDrive',
    timestamp: Date.now(),
  });

  // Open the Files app.
  const appId = await remoteCall.setupAndWaitUntilReady(
      RootPath.DRIVE, [], [ENTRIES.smallDocxPinned]);

  // Check that the nudge and its text is visible.
  await remoteCall.waitNudge(
      appId, 'Recently opened Microsoft files have moved to Google Drive');
}