chromium/chrome/test/data/webui/settings/storage_access_site_list_entry_test.ts

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

/** @fileoverview Suite of tests for storage-access-site-list-entry. */

// clang-format off
import 'chrome://settings/lazy_load.js';

import type {CrExpandButtonElement, StorageAccessStaticSiteListEntry, StorageAccessSiteException, StorageAccessSiteListEntryElement} from 'chrome://settings/lazy_load.js';
import {ContentSetting, ContentSettingsTypes, SiteSettingsPrefsBrowserProxyImpl} from 'chrome://settings/lazy_load.js';
import {assertEquals, assertDeepEquals, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {loadTimeData} from 'chrome://settings/settings.js';

import {TestSiteSettingsPrefsBrowserProxy} from './test_site_settings_prefs_browser_proxy.js';
import {createStorageAccessSiteException, createStorageAccessEmbeddingException} from './test_util.js';
// clang-format on

/**
 * Origin used in `storageAccessException` and
 * `storageAccessExceptionAppliesToEverything`.
 */
const origin = 'https://example.com';

/**
 * An example of a `StorageAccessSiteException`.
 */
const storageAccessException: StorageAccessSiteException =
    createStorageAccessSiteException(origin, {
      setting: ContentSetting.BLOCK,
      closeDescription: 'open description',
      openDescription: 'close description',
      exceptions: [
        createStorageAccessEmbeddingException(
            'https://foo.com', {description: 'embedding description'}),
        createStorageAccessEmbeddingException(
            'https://foo2.com', {description: '', incognito: true}),
      ],
    });

/**
 * An example of a `StorageAccessSiteException` with only one exception that
 * applies to every origin.
 */
const storageAccessExceptionAppliesToEverything: StorageAccessSiteException =
    createStorageAccessSiteException(origin, {
      setting: ContentSetting.BLOCK,
      description: 'description',
      incognito: false,
      exceptions: [],
    });

suite('StorageAccessSiteListEntry', function() {
  /**
   * A site list element created before each test.
   */
  let testElement: StorageAccessSiteListEntryElement;

  /**
   * The mock proxy object to use during test.
   */
  let browserProxy: TestSiteSettingsPrefsBrowserProxy;

  // Initialize a storage-access-site-list-entry before each test.
  setup(function() {
    browserProxy = new TestSiteSettingsPrefsBrowserProxy();
    SiteSettingsPrefsBrowserProxyImpl.setInstance(browserProxy);
    document.body.innerHTML = window.trustedTypes!.emptyHTML;
    testElement = document.createElement('storage-access-site-list-entry');
    document.body.appendChild(testElement);
  });

  /**
   * Configures the test element for a particular category.
   * @param exceptions The `StorageAccessSiteException` to use.
   */
  function setUpEntry(exception: StorageAccessSiteException): Promise<void> {
    testElement.model = exception;
    return flushTasks();
  }

  test('origin site name', async function() {
    await setUpEntry(storageAccessException);

    assertTrue(!!testElement.shadowRoot);
    const displayName = testElement.shadowRoot.querySelector('#displayName');
    assertTrue(!!displayName);

    // Validate that the StorageAccess origin is displayed on the top level row.
    assertEquals(
        origin,
        displayName.querySelector('.site-representation')!.textContent!.trim());
  });

  test('origin site description', async function() {
    await setUpEntry(storageAccessException);

    assertTrue(!!testElement.shadowRoot);
    const displayName = testElement.shadowRoot.querySelector('#displayName');
    assertTrue(!!displayName);

    const secondLine = displayName.querySelector('.second-line');
    assertTrue(!!secondLine);

    // Validate the row description when closed.
    assertEquals(
        storageAccessException.closeDescription,
        secondLine.textContent!.trim());

    const expandButton =
        testElement.shadowRoot.querySelector<CrExpandButtonElement>(
            '#expandButton');
    assertTrue(!!expandButton);
    expandButton.click();
    await expandButton.updateComplete;

    // Validate the row description when opened.
    assertEquals(
        storageAccessException.openDescription, secondLine.textContent!.trim());
  });

  test('nested site rows', async function() {
    await setUpEntry(storageAccessException);

    assertTrue(!!testElement.shadowRoot);
    const expandButton =
        testElement.shadowRoot.querySelector<CrExpandButtonElement>(
            '#expandButton');
    assertTrue(!!expandButton);
    expandButton.click();
    await expandButton.updateComplete;

    // Validate that the nested site entries are created on the collapsible
    // element.
    const siteListEntry = testElement.shadowRoot.querySelectorAll(
        'storage-access-static-site-list-entry');

    assertEquals(
        storageAccessException.exceptions.length, siteListEntry.length);

    // Validate that the first nested site entry.
    const firstNested = siteListEntry[0];
    assertTrue(!!firstNested);
    const firstException = storageAccessException.exceptions[0];
    assertTrue(!!firstException);

    const expectedFirstReset = loadTimeData.getStringF(
        'storageAccessResetSite', origin, firstException.embeddingDisplayName);

    const expectedFirstModel: StorageAccessStaticSiteListEntry = {
      faviconOrigin: firstException.embeddingOrigin,
      displayName: firstException.embeddingDisplayName,
      description: firstException.description,
      resetAriaLabel: expectedFirstReset,
      origin: storageAccessException.origin,
      embeddingOrigin: firstException.embeddingOrigin,
      incognito: firstException.incognito,
    };

    assertDeepEquals(expectedFirstModel, firstNested.model);

    // Validate that the second nested site entry.
    const secondNested = siteListEntry[1];
    assertTrue(!!secondNested);
    const secondException = storageAccessException.exceptions[1];
    assertTrue(!!secondException);

    const expectedSecondReset = loadTimeData.getStringF(
        'storageAccessResetSite', origin, secondException.embeddingDisplayName);

    const expectedSecondModel: StorageAccessStaticSiteListEntry = {
      faviconOrigin: secondException.embeddingOrigin,
      displayName: secondException.embeddingDisplayName,
      description: secondException.description,
      resetAriaLabel: expectedSecondReset,
      origin: storageAccessException.origin,
      embeddingOrigin: secondException.embeddingOrigin,
      incognito: secondException.incognito,
    };

    assertDeepEquals(expectedSecondModel, secondNested.model);
  });

  test('reset all permissions with the same origin site', async function() {
    await setUpEntry(storageAccessException);

    assertTrue(!!testElement.shadowRoot);
    const resetAllButton =
        testElement.shadowRoot.querySelector<HTMLElement>('#resetAllButton');
    assertTrue(!!resetAllButton);
    resetAllButton.click();

    await browserProxy.whenCalled('resetCategoryPermissionForPattern');
    assertEquals(
        storageAccessException.exceptions.length,
        browserProxy.getCallCount('resetCategoryPermissionForPattern'));

    // Check if the calls were made with the correct arguments.
    const args = browserProxy.getArgs('resetCategoryPermissionForPattern');

    const argsFirstCall = args[0];
    assertEquals(origin, argsFirstCall[0]);
    assertEquals(
        storageAccessException.exceptions[0]!.embeddingOrigin,
        argsFirstCall[1]);
    assertEquals(ContentSettingsTypes.STORAGE_ACCESS, argsFirstCall[2]);
    assertEquals(
        storageAccessException.exceptions[0]!.incognito, argsFirstCall[3]);

    const argsSecondCall = args[1];
    assertEquals(origin, argsSecondCall[0]);
    assertEquals(
        storageAccessException.exceptions[1]!.embeddingOrigin,
        argsSecondCall[1]);
    assertEquals(ContentSettingsTypes.STORAGE_ACCESS, argsSecondCall[2]);
    assertEquals(
        storageAccessException.exceptions[1]!.incognito, argsSecondCall[3]);
  });

  test('reset all aria-label', async function() {
    await setUpEntry(storageAccessException);

    assertTrue(!!testElement.shadowRoot);
    const resetAllButton =
        testElement.shadowRoot.querySelector<HTMLElement>('#resetAllButton');
    assertTrue(!!resetAllButton);
    resetAllButton.click();

    // Validate reset button aria-label for top-row.
    const expectedResetAllLabel =
        loadTimeData.getStringF('storageAccessResetAll', origin);
    assertEquals(
        expectedResetAllLabel, resetAllButton.getAttribute('aria-label'));
  });

  test('expand aria-label', async function() {
    await setUpEntry(storageAccessException);

    assertTrue(!!testElement.shadowRoot);
    const expandButton =
        testElement.shadowRoot.querySelector<CrExpandButtonElement>(
            '#expandButton');
    assertTrue(!!expandButton);

    // Validate expand button aria-label when closed.
    const expectedExpandOpenArialLabel =
        loadTimeData.getString('storageAccessOpenExpand');
    assertEquals(
        expectedExpandOpenArialLabel, expandButton.getAttribute('aria-label'));

    expandButton.click();
    await expandButton.updateComplete;

    // Validate expand button aria-label when opened.
    const expectedExpandCloseArialLabel =
        loadTimeData.getString('storageAccessCloseExpand');
    assertEquals(
        expectedExpandCloseArialLabel, expandButton.getAttribute('aria-label'));
  });

  test(
      'static entry for exception that applies to everything',
      async function() {
        await setUpEntry(storageAccessExceptionAppliesToEverything);

        assertTrue(!!testElement.shadowRoot);

        const staticRow = testElement.shadowRoot.querySelector(
            'storage-access-static-site-list-entry');
        assertTrue(!!staticRow);

        const expectedResetAllLabel =
            loadTimeData.getStringF('storageAccessResetAll', origin);

        const expectedModel: StorageAccessStaticSiteListEntry = {
          faviconOrigin: storageAccessExceptionAppliesToEverything.origin,
          displayName: storageAccessExceptionAppliesToEverything.displayName,
          description: storageAccessExceptionAppliesToEverything.description,
          resetAriaLabel: expectedResetAllLabel,
          origin: storageAccessExceptionAppliesToEverything.origin,
          embeddingOrigin: '',
          incognito:
              storageAccessExceptionAppliesToEverything.incognito || false,
        };
        assertDeepEquals(expectedModel, staticRow.model);
      });
});