chromium/chrome/test/data/webui/chromeos/print_preview_cros/capabilities_manager_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 'chrome://os-print/js/data/capabilities_manager.js';

import {CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING, CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY, CAPABILITIES_MANAGER_SESSION_INITIALIZED, CapabilitiesManager} from 'chrome://os-print/js/data/capabilities_manager.js';
import {DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED, DestinationManager} from 'chrome://os-print/js/data/destination_manager.js';
import {DestinationProviderComposite} from 'chrome://os-print/js/data/destination_provider_composite.js';
import {FakeDestinationProvider, getFakeCapabilitiesResponse} from 'chrome://os-print/js/fakes/fake_destination_provider.js';
import {FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL} from 'chrome://os-print/js/fakes/fake_print_preview_page_handler.js';
import {createCustomEvent} from 'chrome://os-print/js/utils/event_utils.js';
import {getDestinationProvider} from 'chrome://os-print/js/utils/mojo_data_providers.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/chromeos/mock_controller.m.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';

import {createTestDestination, resetDataManagersAndProviders} from './test_utils.js';

suite('CapabilitiesManager', () => {
  let destinationProvider: FakeDestinationProvider;
  let mockController: MockController;

  setup(() => {
    // Setup fakes for testing.
    mockController = new MockController();
    resetDataManagersAndProviders();
    destinationProvider =
        (getDestinationProvider() as DestinationProviderComposite)
            .fakeDestinationProvider;
    assert(destinationProvider);
  });

  teardown(() => {
    mockController.reset();
    resetDataManagersAndProviders();
  });

  // Initialize the DestinationManager and wait for it to send all events.
  async function waitForDestinationManagerLoad(): Promise<void> {
    const destinationManager = DestinationManager.getInstance();
    destinationManager.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
    const activeDestinationChangedEvent = eventToPromise(
        DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED, destinationManager);
    return activeDestinationChangedEvent;
  }


  test('is a singleton', () => {
    const instance1 = CapabilitiesManager.getInstance();
    const instance2 = CapabilitiesManager.getInstance();
    assertEquals(instance1, instance2);
  });

  test('can clear singleton', () => {
    const instance1 = CapabilitiesManager.getInstance();
    CapabilitiesManager.resetInstanceForTesting();
    const instance2 = CapabilitiesManager.getInstance();
    assertTrue(instance1 !== instance2);
  });

  // Verify `isSessionInitialized` returns true and triggers
  // CAPABILITIES_MANAGER_SESSION_INITIALIZED event after `initializeSession`
  // called.
  test(
      'initializeSession updates isSessionInitialized and triggers ' +
          CAPABILITIES_MANAGER_SESSION_INITIALIZED,
      async () => {
        await waitForDestinationManagerLoad();

        const instance = CapabilitiesManager.getInstance();
        assertFalse(
            instance.isSessionInitialized(),
            'Before initializeSession, instance should not be initialized');

        // Set initial context.
        const sessionInit =
            eventToPromise(CAPABILITIES_MANAGER_SESSION_INITIALIZED, instance);
        instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
        await sessionInit;

        assertTrue(
            instance.isSessionInitialized(),
            'After initializeSession, instance should be initialized');
      });

  // Verify when Destination Manager signals the active destination changed, the
  // Capabilities Manager fetches capabilities.
  test(
      'fetch capabilities on active destination changed and cache response',
      async () => {
        // Set the active destination.
        const activeCapabilities = getFakeCapabilitiesResponse().capabilities;
        const activeDestination =
            createTestDestination(activeCapabilities.destinationId);
        destinationProvider.setCapabilities(activeCapabilities);

        await waitForDestinationManagerLoad();

        const destinationManager = DestinationManager.getInstance();
        const getActiveDestinationFn = mockController.createFunctionMock(
            destinationManager, 'getActiveDestination');
        getActiveDestinationFn.returnValue = activeDestination;

        const instance = CapabilitiesManager.getInstance();
        instance.initializeSession(FAKE_PRINT_SESSION_CONTEXT_SUCCESSFUL);
        let providerCallCount = 0;
        assertEquals(
            providerCallCount,
            destinationProvider.getCallCount('fetchCapabilities'));

        // Simulate the active destination change and wait for the capabilities
        // manager to signal capabilities are ready.
        let capsLoadingEvent = eventToPromise(
            CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING, instance);
        let capsReadyEvent = eventToPromise(
            CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY, instance);
        destinationManager.dispatchEvent(
            createCustomEvent(DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED));
        ++providerCallCount;
        await capsLoadingEvent;
        await capsReadyEvent;

        assertEquals(
            providerCallCount,
            destinationProvider.getCallCount('fetchCapabilities'));
        assertDeepEquals(
            activeCapabilities, instance.getActiveDestinationCapabilities());

        // Simulate the active destination changing again except this time the
        // cached capabilities result is returned.
        capsLoadingEvent = eventToPromise(
            CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_LOADING, instance);
        capsReadyEvent = eventToPromise(
            CAPABILITIES_MANAGER_ACTIVE_DESTINATION_CAPS_READY, instance);
        destinationManager.dispatchEvent(
            createCustomEvent(DESTINATION_MANAGER_ACTIVE_DESTINATION_CHANGED));
        await capsLoadingEvent;
        await capsReadyEvent;

        assertEquals(
            providerCallCount,
            destinationProvider.getCallCount('fetchCapabilities'));
        assertDeepEquals(
            activeCapabilities, instance.getActiveDestinationCapabilities());
      });
});