chromium/chrome/test/data/webui/chromeos/os_feedback_ui/feedback_flow_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://os-feedback/confirmation_page.js';
import 'chrome://os-feedback/search_page.js';
import 'chrome://os-feedback/share_data_page.js';
import 'chrome://webui-test/chromeos/mojo_webui_test_support.js';

import {ConfirmationPageElement} from 'chrome://os-feedback/confirmation_page.js';
import {fakeFeedbackContext, fakeFeedbackContextWithoutLinkedCrossDevicePhone, fakeInternalUserFeedbackContext, fakePngData, fakeSearchResponse} from 'chrome://os-feedback/fake_data.js';
import {FakeFeedbackServiceProvider} from 'chrome://os-feedback/fake_feedback_service_provider.js';
import {FakeHelpContentProvider} from 'chrome://os-feedback/fake_help_content_provider.js';
import {AdditionalContextQueryParam, FeedbackFlowButtonClickEvent, FeedbackFlowElement, FeedbackFlowState} from 'chrome://os-feedback/feedback_flow.js';
import {OS_FEEDBACK_TRUSTED_ORIGIN} from 'chrome://os-feedback/help_content.js';
import {setFeedbackServiceProviderForTesting, setHelpContentProviderForTesting} from 'chrome://os-feedback/mojo_interface_provider.js';
import {FeedbackAppExitPath, FeedbackAppHelpContentOutcome, FeedbackAppPreSubmitAction, FeedbackContext, SendReportStatus} from 'chrome://os-feedback/os_feedback_ui.mojom-webui.js';
import {SearchPageElement} from 'chrome://os-feedback/search_page.js';
import {ShareDataPageElement} from 'chrome://os-feedback/share_data_page.js';
import {CrButtonElement} from 'chrome://resources/ash/common/cr_elements/cr_button/cr_button.js';
import {CrCheckboxElement} from 'chrome://resources/ash/common/cr_elements/cr_checkbox/cr_checkbox.js';
import {loadTimeData} from 'chrome://resources/ash/common/load_time_data.m.js';
import {strictQuery} from 'chrome://resources/ash/common/typescript_utils/strict_query.js';
import {getDeepActiveElement} from 'chrome://resources/ash/common/util.js';
import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise, isVisible} from 'chrome://webui-test/test_util.js';

suite('FeedbackFlowTestSuite', () => {
  let page: FeedbackFlowElement;

  let helpContentProvider: FakeHelpContentProvider;

  let feedbackServiceProvider: FakeFeedbackServiceProvider;

  setup(() => {
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    // Create helpContentProvider.
    helpContentProvider = new FakeHelpContentProvider();
    // Setup search response.
    helpContentProvider.setFakeSearchResponse(fakeSearchResponse);
    // Set the fake helpContentProvider.
    setHelpContentProviderForTesting(helpContentProvider);

    feedbackServiceProvider = new FakeFeedbackServiceProvider();
    feedbackServiceProvider.setFakeFeedbackContext(fakeFeedbackContext);
    setFeedbackServiceProviderForTesting(feedbackServiceProvider);
  });

  function initializePage() {
    page = document.createElement('feedback-flow');
    assertTrue(!!page);
    document.body.appendChild(page);
    return flushTasks();
  }

  function findChildElement(element: Element, selector: string): Element|null {
    return element.shadowRoot!.querySelector(selector);
  }

  function getFeedbackContext(): FeedbackContext {
    return page!.getFeedbackContextForTesting() as FeedbackContext;
  }

  function getSearchPage(): SearchPageElement {
    return strictQuery('#searchPage', page!.shadowRoot, SearchPageElement);
  }

  function getDescriptionElement(): HTMLTextAreaElement {
    return strictQuery(
        '#descriptionText', getSearchPage().shadowRoot, HTMLTextAreaElement);
  }

  type ActivePageElement =
      SearchPageElement|ShareDataPageElement|ConfirmationPageElement;

  function getActivePage<T extends ActivePageElement>(): T {
    return page!.shadowRoot!.querySelector('.iron-selected') as T;
  }

  function verifyRecordExitPathCalled(
      isCalled: boolean, exitPath: FeedbackAppExitPath) {
    isCalled ?
        assertTrue(feedbackServiceProvider.isRecordExitPathCalled(exitPath)) :
        assertFalse(feedbackServiceProvider.isRecordExitPathCalled(exitPath));
  }

  function verifyHelpContentOutcomeMetricCalled(
      isCalled: boolean, outcome: FeedbackAppHelpContentOutcome) {
    isCalled ?
        assertTrue(feedbackServiceProvider.isHelpContentOutcomeMetricEmitted(
            outcome)) :
        assertFalse(
            feedbackServiceProvider.isHelpContentOutcomeMetricEmitted(outcome));
  }

  function verifyExitPathMetricsEmitted(
      exitPage: FeedbackFlowState, exitPath: FeedbackAppExitPath,
      helpContentClicked: boolean) {
    page.setCurrentStateForTesting(exitPage);
    page.setHelpContentClickedForTesting(helpContentClicked);

    verifyRecordExitPathCalled(/*metric_emitted=*/ false, exitPath);
    window.dispatchEvent(new CustomEvent('beforeunload'));
    verifyRecordExitPathCalled(/*metric_emitted=*/ true, exitPath);
  }

  function testWithInternalAccount() {
    feedbackServiceProvider = new FakeFeedbackServiceProvider();
    feedbackServiceProvider.setFakeFeedbackContext(
        fakeInternalUserFeedbackContext);
    setFeedbackServiceProviderForTesting(feedbackServiceProvider);
  }

  function setupTestWithoutLinkedCrossDevicePhone() {
    feedbackServiceProvider = new FakeFeedbackServiceProvider();
    feedbackServiceProvider.setFakeFeedbackContext(
        fakeFeedbackContextWithoutLinkedCrossDevicePhone);
    setFeedbackServiceProviderForTesting(feedbackServiceProvider);
  }

  function setFromAssistantFlag(fromAssistant: boolean) {
    if (fromAssistant) {
      const queryParams = new URLSearchParams(window.location.search);
      const fromAssistant = 'true';
      queryParams.set(
          AdditionalContextQueryParam.FROM_ASSISTANT, fromAssistant);

      window.history.replaceState(null, '', '?' + queryParams.toString());
    } else {
      window.history.replaceState(
          null, '',
          '?' +
              '');
    }
  }

  function setFromSettingsSearchFlag(fromSettingsSearch: boolean) {
    if (fromSettingsSearch) {
      const queryParams = new URLSearchParams(window.location.search);
      const fromSettingsSearch = 'true';
      queryParams.set(
          AdditionalContextQueryParam.FROM_SETTINGS_SEARCH, fromSettingsSearch);

      window.history.replaceState(null, '', '?' + queryParams.toString());
    } else {
      window.history.replaceState(
          null, '',
          '?' +
              '');
    }
  }

  // Test that the search page is shown by default.
  test('SearchPageIsShownByDefault', async () => {
    await initializePage();

    // Find the element whose class is iron-selected.
    const activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);

    // Verify the title is in the page.
    const title =
        strictQuery('.page-title', activePage.shadowRoot, HTMLElement);
    assertTrue(!!title);
    assertEquals('Send feedback', title.textContent!.trim());

    // Verify the continue button is in the page.
    const buttonContinue =
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement);
    assertTrue(!!buttonContinue);
    assertEquals('Continue', buttonContinue.textContent!.trim());
  });


  // Test that the share data page is shown.
  test('ShareDataPageIsShown', async () => {
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);

    const activePage = getActivePage<ShareDataPageElement>();
    assertEquals('shareDataPage', activePage.id);

    assertTrue(!!activePage);
    // Verify the title is in the page.
    const title =
        strictQuery('.page-title', activePage.shadowRoot, HTMLElement);
    assertTrue(!!title);
    assertEquals('Send feedback', title.textContent!.trim());

    // Verify the back button is in the page.
    const buttonBack =
        strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement);
    assertTrue(!!buttonBack);
    assertEquals('Back', buttonBack.textContent!.trim());

    // Verify the send button is in the page.
    const buttonSend =
        strictQuery('#buttonSend', activePage.shadowRoot, CrButtonElement);
    assertTrue(!!buttonSend);
    assertEquals('Send', buttonSend.textContent!.trim());
  });


  // Test that the confirmation page is shown.
  test('ConfirmationPageIsShown', async () => {
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.CONFIRMATION);
    page.setSendReportStatusForTesting(SendReportStatus.kSuccess);

    const activePage = getActivePage<ConfirmationPageElement>();
    assertTrue(!!activePage);
    assertEquals('confirmationPage', activePage.id);

    // Verify the title is in the page.
    const title =
        strictQuery('.page-title', activePage.shadowRoot, HTMLElement);
    assertTrue(!!title);
    assertEquals('Thanks for your feedback', title.textContent!.trim());

    // Verify the done button is in the page.
    const buttonDone =
        strictQuery('#buttonDone', activePage.shadowRoot, CrButtonElement);
    assertTrue(!!buttonDone);
    assertEquals('Done', buttonDone.textContent!.trim());

    // Verify the startNewReport button is in the page.
    const buttonNewReport = strictQuery(
        '#buttonNewReport', activePage.shadowRoot, CrButtonElement);
    assertTrue(!!buttonNewReport);
    assertEquals('Send new report', buttonNewReport.textContent!.trim());
  });

  // Test the navigation from search page to share data page.
  test('NavigateFromSearchPageToShareDataPage', async () => {
    await initializePage();

    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kContinueHelpContentClicked);
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kContinueNoHelpContentClicked);

    page.setHelpContentClickedForTesting(true);

    let activePage: ActivePageElement = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);

    const inputElement =
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement);
    const continueButton =
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement);

    // Clear the description.
    inputElement.value = '';
    continueButton.click();
    await flushTasks();
    // Should stay on search page when click the continue button.
    activePage = getActivePage();
    assertEquals('searchPage', activePage.id);
    assertEquals(0, feedbackServiceProvider.getScreenshotPngCallCount());
    feedbackServiceProvider.setFakeScreenshotPng(fakePngData);

    const clickPromise = eventToPromise('continue-click', page);

    let eventDetail: FeedbackFlowButtonClickEvent;
    page.addEventListener(
        'continue-click', (event: FeedbackFlowButtonClickEvent) => {
          eventDetail = event;
        });

    // Enter some text.
    inputElement.value = 'abc';
    continueButton.click();
    await clickPromise;

    assertEquals(FeedbackFlowState.SEARCH, eventDetail!.detail!.currentState);
    assertEquals('abc', eventDetail!.detail!.description);

    // Should move to share data page when click the continue button.
    activePage = getActivePage<ShareDataPageElement>();
    assertEquals('shareDataPage', activePage.id);

    // Verify that the getScreenshotPng is called once.
    assertEquals(1, feedbackServiceProvider.getScreenshotPngCallCount());
    const screenshotImg = strictQuery(
        '#screenshotImage', activePage.shadowRoot, HTMLImageElement);
    assertTrue(!!screenshotImg);
    assertTrue(!!screenshotImg.src);
    // Verify that the src of the screenshot image is set.
    assertTrue(screenshotImg.src.startsWith('blob:chrome://os-feedback/'));
    // Verify that click continue after viewing helpcontent will emit the
    // correct metric.
    verifyHelpContentOutcomeMetricCalled(
        true, FeedbackAppHelpContentOutcome.kContinueHelpContentClicked);
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kContinueNoHelpContentClicked);
  });

  // Test the navigation from share data page back to search page when click
  // the back button.
  test('NavigateFromShareDataPageToSearchPage', async () => {
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);

    let activePage = getActivePage();
    assertEquals('shareDataPage', activePage.id);

    strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement).click();
    await flushTasks();
    // Should go back to share data page.
    activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);

    // The description input element should have received focused.
    const descriptionElement =
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement);
    assertEquals(descriptionElement, getDeepActiveElement());
  });

  // Test the navigation from share data page to confirmation page after the
  // send button is clicked.
  test('NavigateFromShareDataPageToConfirmationPage', async () => {
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);
    // In normal flow, the description should have been set when arriving to the
    // share data page.
    page.setDescriptionForTesting('abc123');

    let activePage = getActivePage();
    assertEquals('shareDataPage', activePage.id);

    const clickPromise = eventToPromise('continue-click', page);

    let eventDetail;
    page.addEventListener('continue-click', (event) => {
      eventDetail = event;
    });

    assertEquals(0, feedbackServiceProvider.getSendReportCallCount());

    strictQuery('#buttonSend', activePage.shadowRoot, CrButtonElement).click();
    await clickPromise;

    // Verify the sendReport method was invoked.
    assertEquals(1, feedbackServiceProvider.getSendReportCallCount());
    assertEquals(
        FeedbackFlowState.SHARE_DATA, eventDetail!.detail!.currentState);

    // Should navigate to confirmation page.
    activePage = getActivePage<ConfirmationPageElement>();
    assertTrue(!!activePage);
    assertEquals('confirmationPage', activePage.id);
    assertEquals(SendReportStatus.kSuccess, activePage.sendReportStatus);
  });

  // Test the bluetooth logs will show up if logged with internal account and
  // input description is related.
  test('ShowBluetoothLogsWithRelatedDescription', async () => {
    testWithInternalAccount();
    await initializePage();

    // Check the bluetooth checkbox component hidden when input is not related
    // to bluetooth.
    let activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);

    strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement).value =
        'abc';
    strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
        .click();
    await flushTasks();

    activePage = getActivePage();
    assertEquals('shareDataPage', activePage.id);
    const bluetoothCheckbox = strictQuery(
        '#bluetoothCheckboxContainer', activePage.shadowRoot, HTMLElement);
    assertTrue(!!bluetoothCheckbox);
    assertFalse(isVisible(bluetoothCheckbox));

    strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement).click();
    await flushTasks();

    // Go back to search page and set description input related to bluetooth.
    activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);

    const descriptionElement =
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement);
    descriptionElement.value = 'bluetooth';

    strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
        .click();
    await flushTasks();

    activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('shareDataPage', activePage.id);

    assertTrue(!!bluetoothCheckbox);
    assertTrue(isVisible(bluetoothCheckbox));
  });

  // Test the bluetooth logs will not show up if not logged with an Internal
  // google account.
  test('BluetoothHiddenWithoutInternalAccount', async () => {
    await initializePage();

    // Set input description related to bluetooth.
    let activePage = getActivePage();

    strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement).value =
        'bluetooth';
    strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
        .click();
    await flushTasks();

    activePage = getActivePage();
    assertEquals('shareDataPage', activePage.id);
    const bluetoothCheckbox = strictQuery(
        '#bluetoothCheckboxContainer', activePage.shadowRoot, HTMLElement);
    assertTrue(!!bluetoothCheckbox);
    assertFalse(isVisible(bluetoothCheckbox));
  });

  // Test that the flag ShouldShowWifiDebugLogsCheckBox_ is false if
  // - is not internal account.
  // - wifi, wi-fi, internet, network, and hotspot are mentioned in description.
  test('DoNotShowWifiDebugLogsCheckBox_ExternalAccount', async () => {
    await initializePage();
    assertFalse(page.getShouldShowWifiDebugLogsCheckboxForTesting());

    const searchPage = findChildElement(page, '.iron-selected');
    assertTrue(!!searchPage);
    assertEquals('searchPage', searchPage!.id);

    const inputElement = findChildElement(searchPage as Element, 'textarea') as
        HTMLTextAreaElement;
    inputElement.value = 'wifi wi-fi internet network hotspot';
    // The flag ShouldShowWifiDebugLogsCheckBox_ is only updated when continue
    // button is clicked.
    const continueButton =
        findChildElement(searchPage as Element, '#buttonContinue') as
        CrButtonElement;
    continueButton.click();
    await flushTasks();

    assertFalse(page.getShouldShowWifiDebugLogsCheckboxForTesting());
  });

  // Test that the flag ShouldShowWifiDebugLogsCheckBox_ is true if
  // - is internal account.
  // - wifiDebugLogsAllowed is false.
  // - Wi-fi is mentioned in description.
  test('DoNotShowWifiDebugLogsCheckBox_NotAllowed', async () => {
    testWithInternalAccount();
    await initializePage();
    assertFalse(getFeedbackContext().wifiDebugLogsAllowed);
    assertFalse(page.getShouldShowWifiDebugLogsCheckboxForTesting());

    const searchPage = findChildElement(page, '.iron-selected');
    assertTrue(!!searchPage);
    assertEquals('searchPage', searchPage.id);

    const inputElement = findChildElement(searchPage as Element, 'textarea') as
        HTMLTextAreaElement;
    inputElement.value = 'wi-fi';
    // The flag ShouldShowWifiDebugLogsCheckBox_ is only updated when continue
    // button is clicked.
    const continueButton =
        findChildElement(searchPage as Element, '#buttonContinue') as
        CrButtonElement;
    continueButton.click();
    await flushTasks();

    assertFalse(page.getShouldShowWifiDebugLogsCheckboxForTesting());
  });

  // Test that the flag ShouldShowWifiDebugLogsCheckBox_ is true if
  // - is internal account.
  // - wifiDebugLogsAllowed is true.
  // - Wi-fi is mentioned in description.
  test('ShowWifiDebugLogsCheckBox', async () => {
    testWithInternalAccount();
    await initializePage();
    getFeedbackContext().wifiDebugLogsAllowed = true;
    assertFalse(page.getShouldShowWifiDebugLogsCheckboxForTesting());

    const searchPage = findChildElement(page, '.iron-selected');
    assertTrue(!!searchPage);
    assertEquals('searchPage', searchPage.id);

    const inputElement = findChildElement(searchPage as Element, 'textarea') as
        HTMLTextAreaElement;
    inputElement.value = 'wi-fi';
    // The flag ShouldShowWifiDebugLogsCheckBox_ is only updated when continue
    // button is clicked.
    const continueButton =
        findChildElement(searchPage as Element, '#buttonContinue') as
        CrButtonElement;
    continueButton.click();
    await flushTasks();

    assertTrue(page.getShouldShowWifiDebugLogsCheckboxForTesting());
  });

  // Test the "Link Cross Device Dogfood Feedback" checkbox will show up if
  // logged with internal account and input description is related.
  test(
      'ShowLinkCrossDeviceDogfoodFeedbackCheckboxsWithRelatedDescription',
      async () => {
        testWithInternalAccount();
        await initializePage();

        // Check the "Link Cross Device Dogfood Feedback" checkbox component is
        // hidden when input is not related to cross device.
        let activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('searchPage', activePage.id);

        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement)
            .value = 'abc';
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        loadTimeData.overrideValues(
            {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

        activePage = getActivePage();
        assertEquals('shareDataPage', activePage.id);
        const linkCrossDeviceDogfoodFeedbackCheckbox =
            activePage.shadowRoot!.querySelector(
                '#linkCrossDeviceDogfoodFeedbackCheckboxContainer');
        assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
        assertFalse(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));

        strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        loadTimeData.overrideValues(
            {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

        // Go back to search page and set description input related to cross
        // device.
        activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('searchPage', activePage.id);

        // Testing tetherRegEx
        let descriptionElement = strictQuery(
            'textarea', activePage.shadowRoot, HTMLTextAreaElement);
        descriptionElement.value = 'hotspot';

        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('shareDataPage', activePage.id);

        assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
        assertTrue(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));

        strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        loadTimeData.overrideValues(
            {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

        // Go back to search page and set description input related to cross
        // device.
        activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('searchPage', activePage.id);

        // Testing phoneHubRegEx
        descriptionElement = strictQuery(
            'textarea', activePage.shadowRoot, HTMLTextAreaElement);
        descriptionElement.value = 'appstream';

        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('shareDataPage', activePage.id);

        assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
        assertTrue(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));

        strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        loadTimeData.overrideValues(
            {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

        // Go back to search page and set description input related to cross
        // device.
        activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('searchPage', activePage.id);

        // Testing phoneHubRegEx variation.
        descriptionElement = strictQuery(
            'textarea', activePage.shadowRoot, HTMLTextAreaElement);
        descriptionElement.value = 'camera roll';

        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        activePage = getActivePage();
        assertTrue(!!activePage);
        assertEquals('shareDataPage', activePage.id);

        assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
        assertTrue(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));
      });

  // Test the "Link Cross Device Dogfood Feedback" checkbox will not show up if
  // not logged with an Internal google account.
  test(
      'LinkCrossDeviceDogfoodFeedbackHiddenWithoutInternalAccount',
      async () => {
        await initializePage();

        // Enable flag.
        loadTimeData.overrideValues(
            {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

        // Set input description related to cross device.
        let activePage = getActivePage();
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement)
            .value = 'phone';
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        activePage = getActivePage();
        assertEquals('shareDataPage', activePage.id);
        const linkCrossDeviceDogfoodFeedbackCheckbox =
            activePage.shadowRoot!.querySelector(
                '#linkCrossDeviceDogfoodFeedbackCheckboxContainer');
        assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
        assertFalse(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));
      });

  // Test the "Link Cross Device Dogfood Feedback" checkbox will not show up if
  // the ChromeOs device is not linked to a phone.
  test(
      'LinkCrossDeviceDogfoodFeedbackHiddenWithoutLinkedCrossDevicePhone',
      async () => {
        setupTestWithoutLinkedCrossDevicePhone();

        await initializePage();

        // Enable flag.
        loadTimeData.overrideValues(
            {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

        // Set input description related to cross device.
        let activePage = getActivePage();

        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement)
            .value = 'phone';
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        activePage = getActivePage();
        assertEquals('shareDataPage', activePage.id);
        const linkCrossDeviceDogfoodFeedbackCheckbox =
            activePage.shadowRoot!.querySelector(
                '#linkCrossDeviceDogfoodFeedbackCheckboxContainer');
        assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
        assertFalse(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));
      });

  // Test the "Link Cross Device Dogfood Feedback" checkbox will only show up
  // when 'enableLinkCrossDeviceDogfoodFeedbackFlag' is enabled.
  test('LinkCrossDeviceDogfoodFeedbackTestingFlag', async () => {
    testWithInternalAccount();
    await initializePage();

    // Enable flag and check that the checkbox appears.
    loadTimeData.overrideValues(
        {'enableLinkCrossDeviceDogfoodFeedbackFlag': true});

    // Set input description related to cross device.
    let activePage = getActivePage();

    strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement).value =
        'phone';
    strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
        .click();
    await flushTasks();

    activePage = getActivePage();
    assertEquals('shareDataPage', activePage.id);
    const linkCrossDeviceDogfoodFeedbackCheckbox =
        activePage.shadowRoot!.querySelector(
            '#linkCrossDeviceDogfoodFeedbackCheckboxContainer');
    assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
    assertTrue(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));

    strictQuery('#buttonBack', activePage.shadowRoot, CrButtonElement).click();
    await flushTasks();

    // Go back to search page and set description input related to cross device.
    activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);

    const descriptionElement =
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement);
    descriptionElement.value = 'phone';

    // Disable flag and check that the checkbox doesn't appear.
    loadTimeData.overrideValues(
        {'enableLinkCrossDeviceDogfoodFeedbackFlag': false});

    strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
        .click();
    await flushTasks();

    activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('shareDataPage', activePage.id);

    assertTrue(!!linkCrossDeviceDogfoodFeedbackCheckbox);
    assertFalse(isVisible(linkCrossDeviceDogfoodFeedbackCheckbox));
  });

  // Test the assistant logs will show up if logged with internal account and
  // the fromAssistant flag is true.
  test('ShowAssistantCheckboxWithInternalAccountAndFlagSetTrue', async () => {
    // Replacing the query string to set the fromAssistant flag as true.
    setFromAssistantFlag(true);
    testWithInternalAccount();
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);

    const feedbackContext = getFeedbackContext();
    assertTrue(feedbackContext.isInternalAccount);
    assertTrue(feedbackContext.fromAssistant);
    // Check the assistant checkbox component visible when input is not
    // related to bluetooth.
    const activePage = getActivePage();
    assertEquals('shareDataPage', activePage.id);

    const assistantCheckbox = strictQuery(
        '#assistantLogsContainer', activePage.shadowRoot, HTMLElement);

    assertTrue(!!assistantCheckbox);
    assertTrue(isVisible(assistantCheckbox));
  });

  // Test the assistant checkbox will not show up to external account user
  // with fromAssistant flag passed.
  test('AssistantCheckboxHiddenWithExternalAccount', async () => {
    // Replacing the query string to set the fromAssistant flag as true.
    setFromAssistantFlag(true);
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);

    const feedbackContext = getFeedbackContext();
    assertFalse(feedbackContext.isInternalAccount);
    assertTrue(feedbackContext.fromAssistant);
    let activePage = getActivePage();
    activePage = getActivePage();

    assertEquals('shareDataPage', activePage.id);
    const assistantCheckbox = strictQuery(
        '#assistantLogsContainer', activePage.shadowRoot, HTMLElement);
    assertTrue(!!assistantCheckbox);
    assertFalse(isVisible(assistantCheckbox));
  });

  // Test the assistant logs will not show up if fromAssistant flag is not
  // passed but logged in with Internal google account.
  test('AssistantCheckboxHiddenWithoutFlagPassed', async () => {
    // Replace the current querystring back to default.
    setFromAssistantFlag(false);
    // Set Internal Account flag as true.
    testWithInternalAccount();
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);

    const feedbackContext = getFeedbackContext();
    assertTrue(feedbackContext.isInternalAccount);
    assertFalse(feedbackContext.fromAssistant);
    // Set input description related to bluetooth.
    let activePage = getActivePage();
    activePage = getActivePage();

    assertEquals('shareDataPage', activePage.id);
    const assistantCheckbox = strictQuery(
        '#assistantLogsContainer', activePage.shadowRoot, HTMLElement);
    assertTrue(!!assistantCheckbox);
    assertFalse(isVisible(assistantCheckbox));
    // Set the flag back to true.
    fakeInternalUserFeedbackContext.fromAssistant = true;
  });

  // Test the sys info and metrics checkbox will not be checked if
  // fromSettingsSearch flag has been passed.
  test(
      'SysinfoAndMetricsCheckboxIsUncheckedWhenFeedbackIsSentFromSettingsSearch',
      async () => {
        // Replacing the query string to set the fromSettingsSearch flag as
        // true.
        setFromSettingsSearchFlag(true);
        await initializePage();
        const feedbackContext = getFeedbackContext();
        assertTrue(feedbackContext.fromSettingsSearch);

        const activePage = getActivePage<SearchPageElement>();
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement)
            .value = 'text';
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        // Check the sys info and metrics checkbox component is unchecked when
        // the feedback app has opened through settings search
        const newActivePage = getActivePage<ShareDataPageElement>();
        assertEquals('shareDataPage', newActivePage.id);

        const sysInfoAndMetricsCheckboxContainer = strictQuery(
            '#sysInfoContainer', newActivePage.shadowRoot, HTMLElement);
        assertTrue(!!sysInfoAndMetricsCheckboxContainer);

        const sysInfoAndMetricsCheckbox = strictQuery(
            '#sysInfoCheckbox', newActivePage.shadowRoot, CrCheckboxElement);
        assertTrue(!!sysInfoAndMetricsCheckbox);
        assertFalse(sysInfoAndMetricsCheckbox.checked);
      });

  // Test the sys info and metrics checkbox will be checked if
  // fromSettingsSearch flag not passed.
  test(
      'SysinfoAndMetricsCheckboxIsCheckedWhenFeedbackIsNotSentFromSettingsSearch',
      async () => {
        // Replacing the query string to set the fromSettingsSearch flag as
        // false.
        setFromSettingsSearchFlag(false);
        await initializePage();
        const feedbackContext = getFeedbackContext();
        assertFalse(feedbackContext.fromSettingsSearch);

        const activePage = getActivePage<SearchPageElement>();
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement)
            .value = 'text';
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement)
            .click();
        await flushTasks();

        const newActivePage = getActivePage<ShareDataPageElement>();
        assertEquals('shareDataPage', newActivePage.id);

        const sysInfoAndMetricsContainer = strictQuery(
            '#sysInfoContainer', newActivePage.shadowRoot, HTMLElement);
        assertTrue(!!sysInfoAndMetricsContainer);

        const sysInfoAndMetricsCheckbox = strictQuery(
            '#sysInfoCheckbox', newActivePage.shadowRoot, CrCheckboxElement);
        assertTrue(!!sysInfoAndMetricsCheckbox);
        assertTrue(sysInfoAndMetricsCheckbox.checked);
      });

  // Test the navigation from confirmation page to search page after the
  // send new report button is clicked.
  test('NavigateFromConfirmationPageToSearchPage', async () => {
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.CONFIRMATION);
    // Set text input in search page for testing.
    const searchPage = getSearchPage();
    searchPage.setDescription(/*text=*/ 'abc123');

    const activePage = getActivePage<ConfirmationPageElement>();
    assertEquals('confirmationPage', activePage.id);

    const clickPromise = eventToPromise('go-back-click', page);

    let eventDetail: FeedbackFlowButtonClickEvent;
    page.addEventListener(
        'go-back-click', (event: FeedbackFlowButtonClickEvent) => {
          eventDetail = event;
        });

    strictQuery('#buttonNewReport', activePage.shadowRoot, CrButtonElement)
        .click();
    await clickPromise;

    assertEquals(
        FeedbackFlowState.CONFIRMATION, eventDetail!.detail!.currentState);

    // Should navigate to search page.
    const newActivePage = getActivePage<SearchPageElement>();
    assertEquals('searchPage', newActivePage.id);

    // Search text should be empty.
    const inputElement = getDescriptionElement();
    assertEquals(inputElement.value, '');
    // The description input element should have received focused.
    assertEquals(inputElement, getDeepActiveElement());
  });

  // When starting a new report, the send button in share data page
  // should be re-enabled.
  test('SendNewReportShouldEnableSendButton', async () => {
    await initializePage();
    page.setCurrentStateForTesting(FeedbackFlowState.SHARE_DATA);
    // In normal flow, the description should have been set when arriving to the
    // share data page.
    page.setDescriptionForTesting('abc123');

    const continueClickPromise = eventToPromise('continue-click', page);
    const goBackClickPromise = eventToPromise('go-back-click', page);

    const activePage = getActivePage<ShareDataPageElement>();
    const shareDataPageSendButton =
        strictQuery('#buttonSend', activePage.shadowRoot, CrButtonElement);
    strictQuery('#buttonSend', activePage.shadowRoot, CrButtonElement).click();
    await continueClickPromise;

    // Should navigate to confirmation page.
    const confirmationPage = getActivePage<ConfirmationPageElement>();
    assertEquals('confirmationPage', confirmationPage.id);

    // The send button in the share data page should be disabled after
    // sending the report and before send new report button is clicked
    assertTrue(shareDataPageSendButton.disabled);

    // Click send new report button.
    strictQuery(
        '#buttonNewReport', confirmationPage!.shadowRoot, CrButtonElement)
        .click();
    await goBackClickPromise;

    // Should navigate to search page.
    const searchPage = getActivePage<SearchPageElement>();
    assertTrue(!!searchPage);
    assertEquals('searchPage', searchPage.id);

    // Add some text and clicks continue button.
    searchPage.setDescription(/*text=*/ 'abc123');
    strictQuery('#buttonContinue', searchPage!.shadowRoot, CrButtonElement)
        .click();
    await continueClickPromise;

    // Should navigate to share data page.
    const shareDataPage = getActivePage<ShareDataPageElement>();
    assertEquals('shareDataPage', shareDataPage.id);

    // The send button in the share data page should be re-enabled.
    assertFalse(shareDataPageSendButton.disabled);
  });

  // Test that the getUserEmail is called after initialization.
  test('GetUserEmailIsCalled', async () => {
    assertEquals(0, feedbackServiceProvider.getFeedbackContextCallCount());
    await initializePage();
    assertEquals(1, feedbackServiceProvider.getFeedbackContextCallCount());
  });

  // Test that the extra diagnostics, category tag, page_url, fromAssistant
  // and fromSettingsSearch flag get set when query parameter is non-empty.
  test(
      'AdditionalContextParametersProvidedInUrl_FeedbackContext_Matches',
      async () => {
        const queryParams = new URLSearchParams(window.location.search);
        const extra_diagnostics = 'some%20extra%20diagnostics';
        queryParams.set(
            AdditionalContextQueryParam.EXTRA_DIAGNOSTICS, extra_diagnostics);
        const description_template = 'Q1%3A%20Question%20one?';
        queryParams.set(
            AdditionalContextQueryParam.DESCRIPTION_TEMPLATE,
            description_template);
        const description_placeholder_text =
            'Thanks%20for%20giving%20feedback%20on%20the%20Camera%20app';
        queryParams.set(
            AdditionalContextQueryParam.DESCRIPTION_PLACEHOLDER_TEXT,
            description_placeholder_text);
        const category_tag = 'some%20category%20tag';
        queryParams.set(AdditionalContextQueryParam.CATEGORY_TAG, category_tag);
        const page_url = 'some%20page%20url';
        queryParams.set(AdditionalContextQueryParam.PAGE_URL, page_url);
        const fromAssistant = 'true';
        queryParams.set(
            AdditionalContextQueryParam.FROM_ASSISTANT, fromAssistant);
        const fromSettingsSearch = 'true';
        queryParams.set(
            AdditionalContextQueryParam.FROM_SETTINGS_SEARCH,
            fromSettingsSearch);
        // Replace current querystring with the new one.
        window.history.replaceState(null, '', '?' + queryParams.toString());
        await initializePage();
        page.setCurrentStateForTesting(FeedbackFlowState.SEARCH);
        const descriptionElement = getDescriptionElement();

        const feedbackContext = getFeedbackContext();
        assertEquals(page_url, feedbackContext.pageUrl!.url);
        assertEquals(fakeFeedbackContext.email, feedbackContext.email);
        assertEquals(
            decodeURIComponent(extra_diagnostics),
            feedbackContext.extraDiagnostics);
        assertEquals(
            decodeURIComponent(description_template), descriptionElement.value);
        assertEquals(
            decodeURIComponent(description_placeholder_text),
            descriptionElement.placeholder);
        assertEquals(
            decodeURIComponent(category_tag), feedbackContext.categoryTag);
        assertTrue(feedbackContext.fromAssistant);
        assertTrue(feedbackContext.fromSettingsSearch);

        // Set the pageUrl in fake feedback context back to its origin value
        // because it's overwritten by the page_url passed from the app.
        fakeFeedbackContext.pageUrl = {url: 'chrome://tab/'};
      });

  // Test that the extra diagnostics gets set, and pageUrl uses the one passed
  // from the feedbackContext when query parameter is empty.
  test(
      'AdditionalContextParametersNotProvidedInUrl_FeedbackContext_UsesDefault',
      async () => {
        // Replace current querystring with the new one.
        window.history.replaceState(
            null, '',
            '?' +
                '');
        await initializePage();
        page.setCurrentStateForTesting(FeedbackFlowState.SEARCH);
        const descriptionElement =
            findChildElement(getSearchPage(), '#descriptionText') as
            HTMLTextAreaElement;

        const feedbackContext = getFeedbackContext();
        // TODO(ashleydp): Update expectation when page_url passed.
        assertEquals(fakeFeedbackContext.pageUrl, feedbackContext.pageUrl);
        assertEquals(fakeFeedbackContext.email, feedbackContext.email);
        assertEquals('', feedbackContext.extraDiagnostics);
        assertEquals('', descriptionElement.value);
        assertEquals('', feedbackContext.categoryTag);
        assertFalse(feedbackContext.fromAssistant);
        assertFalse(feedbackContext.fromSettingsSearch);
      });

  /**
   * Test that the untrusted page can send "help-content-clicked" message to
   * feedback flow page via postMessage.
   */
  test('CanCommunicateWithUntrustedPage', async () => {
    // Whether feedback flow page has received that help content has been
    // clicked;
    let helpContentClicked = false;
    await initializePage();

    assertEquals(
        0,
        feedbackServiceProvider.getRecordPreSubmitActionCallCount(
            FeedbackAppPreSubmitAction.kViewedHelpContent));
    assertEquals(
        0, feedbackServiceProvider.getRecordHelpContentSearchResultCount());

    // Get Search Page.
    const SearchPage = getSearchPage();
    const iframe =
        strictQuery('iframe', SearchPage.shadowRoot, HTMLIFrameElement);

    assertTrue(!!iframe);
    // Wait for the iframe completes loading.
    await eventToPromise('load', iframe);

    // There is another message posted from iframe which sends the height of
    // the help content.
    const expectedMessageEventCount = 2;
    let messageEventCount = 0;
    const resolver = new PromiseResolver<void>();

    window.addEventListener('message', event => {
      if ('help-content-clicked-for-testing' === event.data.id &&
          OS_FEEDBACK_TRUSTED_ORIGIN === event.origin) {
        helpContentClicked = true;
        feedbackServiceProvider.recordPreSubmitAction(
            FeedbackAppPreSubmitAction.kViewedHelpContent);
        feedbackServiceProvider.recordHelpContentSearchResultCount();
      }
      messageEventCount++;
      if (messageEventCount === expectedMessageEventCount) {
        resolver.resolve();
      }
    });

    // Data to be posted from untrusted page to feedback flow page.
    const data = {
      id: 'help-content-clicked-for-testing',
    };
    iframe.contentWindow!.parent!.postMessage(data, OS_FEEDBACK_TRUSTED_ORIGIN);

    // Wait for the "help-content-clicked" message has been received.
    await resolver.promise;

    // Verify that help content have been clicked.
    assertTrue(helpContentClicked);
    // Verify that viewedHelpContent metrics is emitted.
    assertEquals(
        1,
        feedbackServiceProvider.getRecordPreSubmitActionCallCount(
            FeedbackAppPreSubmitAction.kViewedHelpContent));
    // Verify that clicks the help content will emit the
    // recordHelpContentSearchResult metric.
    assertEquals(
        1, feedbackServiceProvider.getRecordHelpContentSearchResultCount());
  });

  // Test that correct exitPathMetrics is emitted when user clicks help content
  // and quits on search page.
  test('QuitSearchPageHelpContentClicked', async () => {
    await initializePage();
    verifyExitPathMetricsEmitted(
        FeedbackFlowState.SEARCH,
        FeedbackAppExitPath.kQuitSearchPageHelpContentClicked, true);
  });

  // Test that correct exitPathMetrics is emitted when user quits on search page
  // without clicking any help contents.
  test('QuitSearchPageNoHelpContentClicked', async () => {
    await initializePage();
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kQuitHelpContentClicked);
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kQuitNoHelpContentClicked);

    // This will emit an close-app event with no help content clicked.
    verifyExitPathMetricsEmitted(
        FeedbackFlowState.SEARCH,
        FeedbackAppExitPath.kQuitSearchPageNoHelpContentClicked, false);

    // Verify that close app without viewing helpcontent will emit the
    // correct metric.
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kQuitHelpContentClicked);
    verifyHelpContentOutcomeMetricCalled(
        true, FeedbackAppHelpContentOutcome.kQuitNoHelpContentClicked);
  });

  // Test that correct metrics are emitted when user quits on
  // search page because no help content is shown.
  test('QuitSearchPagesetNoHelpContentDisplayed', async () => {
    await initializePage();
    page.setNoHelpContentDisplayedForTesting(true);

    verifyRecordExitPathCalled(
        false, FeedbackAppExitPath.kQuitNoHelpContentDisplayed);
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kQuitNoHelpContentDisplayed);

    window.dispatchEvent(new CustomEvent('beforeunload'));

    verifyRecordExitPathCalled(
        true, FeedbackAppExitPath.kQuitNoHelpContentDisplayed);
    verifyHelpContentOutcomeMetricCalled(
        true, FeedbackAppHelpContentOutcome.kQuitNoHelpContentDisplayed);
  });

  // Test that correct exitPathMetrics is emitted when user quits on share data
  // page.
  test('QuitShareDataPageHelpContentClicked', async () => {
    await initializePage();
    verifyExitPathMetricsEmitted(
        FeedbackFlowState.SHARE_DATA,
        FeedbackAppExitPath.kQuitShareDataPageHelpContentClicked, true);
  });

  // Test that correct exitPathMetrics is emitted when user quits on share data
  // page.
  test('QuitShareDataPageNoHelpContentClicked', async () => {
    await initializePage();
    verifyExitPathMetricsEmitted(
        FeedbackFlowState.SHARE_DATA,
        FeedbackAppExitPath.kQuitShareDataPageNoHelpContentClicked, false);
  });

  // Test that correct exitPathMetrics is emitted when user clicks help content
  // and quits on confirmation page.
  test('QuitConfirmationPageHelpContentClicked', async () => {
    await initializePage();
    verifyExitPathMetricsEmitted(
        FeedbackFlowState.CONFIRMATION,
        FeedbackAppExitPath.kSuccessHelpContentClicked, true);
  });

  // Test that correct exitPathMetrics is emitted when user quits on
  // confirmation page without clicking any help contents.
  test('QuitConfirmationPageNoHelpContentClicked', async () => {
    await initializePage();
    verifyExitPathMetricsEmitted(
        FeedbackFlowState.CONFIRMATION,
        FeedbackAppExitPath.kSuccessNoHelpContentClicked, false);
  });

  // Test that correct helpContentOutcomeMetrics is emitted when user click
  // continue when there is no help content shown.
  test('HelpContentOutcomeContinuesetNoHelpContentDisplayed', async () => {
    await initializePage();
    page.setNoHelpContentDisplayedForTesting(true);
    verifyHelpContentOutcomeMetricCalled(
        false, FeedbackAppHelpContentOutcome.kContinueNoHelpContentDisplayed);

    // Now on search page.
    const activePage = getActivePage();
    assertTrue(!!activePage);
    assertEquals('searchPage', activePage.id);
    const inputElement =
        strictQuery('textarea', activePage.shadowRoot, HTMLTextAreaElement);
    const continueButton =
        strictQuery('#buttonContinue', activePage.shadowRoot, CrButtonElement);

    // Enter some text.
    inputElement.value = 'abc';
    continueButton.click();

    verifyHelpContentOutcomeMetricCalled(
        true, FeedbackAppHelpContentOutcome.kContinueNoHelpContentDisplayed);
  });

  test('UpdatesCSSUrl_TrustedUi', async () => {
    /*@type {HTMLLinkElement}*/
    const link = document.createElement('link');
    const disabledUrl = 'chrome://resources/chromeos/colors/cros_styles.css';
    link.href = disabledUrl;
    document.head.appendChild(link);

    await initializePage();

    const enabledUrl = 'theme/colors.css';
    assertTrue(link.href.includes(enabledUrl));

    // Clean up test specific element.
    document.head.removeChild(link);
  });

  // Test that test helper message is triggered on untrusted UI.
  test(
      'UpdatesCSSUrlBasedOn_UntrustedUi', async () => {
        const resolver = new PromiseResolver<void>();
        let colorChangeUpdaterCalled = false;
        const testMessageListener = (event: {data: {id: string}}) => {
          if (event.data.id === 'color-change-updater-started-for-testing') {
            colorChangeUpdaterCalled = true;
            resolver.resolve();
          }
        };
        window.addEventListener('message', testMessageListener);

        await initializePage();
        await resolver.promise;

        assertTrue(colorChangeUpdaterCalled);

        window.removeEventListener('message', testMessageListener);
      });

  // Test that when dialog args is present, it will be used to populate the
  // feedback context.
  test('Create_feedback_context_from_dialogArguments_if_present', async () => {
    // Save the original chrome.getVariableValue function.
    const chromeGetVariableValue = chrome.getVariableValue;
    // Mock the chrome.getVariableValue to return dialogArguments.
    const mockChromeGetVariableValue = (message: string) => {
      if (message === 'dialogArguments') {
        return '{' +
            '"autofillMetadata":{"fake key1": "fake value1"},' +
            '"categoryTag":"Login",' +
            '"description":"fake description",' +
            '"descriptionPlaceholder":"fake description placeholder",' +
            '"fromAssistant": true, ' +
            '"fromAutofill": true, ' +
            '"fromSettingsSearch": true, ' +
            '"hasLinkedCrossDevicePhone": true, ' +
            '"isInternalAccount": true, ' +
            '"pageUrl":"chrome://flags/",' +
            '"systemInformation":[' +
            '  {' +
            '    "key": "EXTRA_DIAGNOSTICS",' +
            '    "value": "fake extra log data"' +
            '  }' +
            ']' +
            '}';
      }
      return '{}';
    };
    chrome.getVariableValue = mockChromeGetVariableValue;

    await initializePage();

    const feedbackContext = getFeedbackContext();
    assertEquals('Login', feedbackContext.categoryTag);
    assertEquals('fake extra log data', feedbackContext.extraDiagnostics);
    assertEquals('chrome://flags/', feedbackContext.pageUrl!.url);
    assertEquals(
        '{"fake key1":"fake value1"}', feedbackContext.autofillMetadata);
    assertTrue(feedbackContext.fromAssistant);
    assertTrue(feedbackContext.fromAutofill);
    assertTrue(feedbackContext.fromSettingsSearch);
    assertTrue(feedbackContext.hasLinkedCrossDevicePhone);
    assertTrue(feedbackContext.isInternalAccount);

    assertEquals('fake description', page.getDescriptionTemplateForTesting());
    assertEquals(
        'fake description placeholder',
        page.getDescriptionPlaceholderTextForTesting());
    assertFalse(page.getIsUserLoggedInForTesting());

    // Restore chrome.getVariableValue.
    chrome.getVariableValue = chromeGetVariableValue;
    // Verify that the getFeedbackContext is not called.
    assertEquals(0, feedbackServiceProvider.getFeedbackContextCallCount());
  });

  // Test that when dialog args is present, it will be used to populate the
  // feedback context. All fields are empty/absent.
  test(
      'Create_feedback_context_from_dialogArguments_if_present_empty',
      async () => {
        // Save the original chrome.getVariableValue function.
        const chromeGetVariableValue = chrome.getVariableValue;
        // Mock the chrome.getVariableValue to return dialogArguments.
        const mockChromeGetVariableValue = () => {
          return '{}';
        };
        chrome.getVariableValue = mockChromeGetVariableValue;

        await initializePage();

        const feedbackContext = getFeedbackContext();
        assertEquals('', feedbackContext.categoryTag);
        assertEquals('', feedbackContext.extraDiagnostics);
        assertEquals('', feedbackContext.pageUrl!.url);
        assertEquals('{}', feedbackContext.autofillMetadata);
        assertFalse(feedbackContext.fromAssistant);
        assertFalse(feedbackContext.fromAutofill);
        assertFalse(feedbackContext.fromSettingsSearch);
        assertFalse(feedbackContext.isInternalAccount);
        assertFalse(feedbackContext.hasLinkedCrossDevicePhone);

        assertTrue(!page.getDescriptionTemplateForTesting());
        assertTrue(!page.getDescriptionPlaceholderTextForTesting());
        assertTrue(page.getIsUserLoggedInForTesting());

        // Restore chrome.getVariableValue.
        chrome.getVariableValue = chromeGetVariableValue;

        // Verify that the getFeedbackContext is not called.
        assertEquals(0, feedbackServiceProvider.getFeedbackContextCallCount());
      });
});