text: /**
   * Copyright 2020 Google LLC
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import React from 'react';
  import {render, fireEvent, screen, waitFor} from '@testing-library/react';
  import '@testing-library/jest-dom/extend-expect';
  import * as api from '../../src/api.js';
  import Auth from '../../src/auth.js';
  import Main from '../../src/components/main.js';
  
  /**
   * Helper function -
   * Returns an array of items labeled as so: item1, item2...
   * @param {number} numItems Number of items to generate
   * @param {string} name The name of the items
   * @return {string[]} List of numbered items
   */
  const generateItems = (numItems, name) => {
    const items = [];
    for (let i = 1; i <= numItems; i++) {
      items.push(name + i);
    }
    return items;
  };
  
  // Set up mock functions for api calls
  jest.mock('../../src/api.js');
  jest.mock('../../src/auth.js');
  
  // Ensure the makeCancelable function is NOT mocked as it is needed
  // for the viewer component to function properly
  const {makeCancelable} = jest.requireActual('../../src/api.js');
  api.makeCancelable = makeCancelable;
  
  // Mock auth functions to prevent any use of the gapi client
  Auth.initClient.mockReturnValue(Promise.resolve());
  Auth.isSignedIn.mockReturnValue(true);
  Auth.getAccessToken.mockReturnValue('FAKE_ACCESS_TOKEN');
  
  // fetchProjects will resolve 5 mock projects
  api.fetchProjects.mockResolvedValue(
      generateItems(5, 'project'),
  );
  
  // fetchLocations will resolve 5 fake locations
  api.fetchLocations.mockResolvedValue(
      generateItems(5, 'location'),
  );
  
  // fetchDatasets will resolve 5 fake datasets
  api.fetchDatasets.mockResolvedValue(
      generateItems(5, 'dataset'),
  );
  
  // fetchDicomStores will resolve 5 fake dicomStores
  api.fetchDicomStores.mockResolvedValue(
      generateItems(5, 'dicomStore'),
  );
  
  // fetchStudies will resolve 1 fake study
  api.fetchStudies.mockResolvedValue([{
    '00100020': {
      Value: ['study1'],
    },
    '0020000D': {
      Value: ['study1-UID'],
    },
  }]);
  
  // fetchSeries will resolve 1 fake series
  api.fetchSeries.mockResolvedValue([{
    '00080060': {
      Value: ['series1'],
    },
    '0020000E': {
      Value: ['series1-UID'],
    },
  }]);
  
  // fetchMetadata will resolve 1 fake instance
  api.fetchMetadata.mockResolvedValue([{
    '00080016': {
      vr: 'UI',
      Value: ['instance1-UID'],
    },
    '00200013': {
      vr: 'IS',
      Value: [1],
    },
  }]);
  
  // eslint-disable-next-line max-len
  test('User can navigate between project, location, dataset, dicomStore, study, and series', async () => {
    render(
        <Main/>,
    );
  
    // Navigate through: project2 -> location5 -> dataset3 ->
    // dicomStore4 -> study1 -> series1
  
    // Ensure project1 through project5 are displayed
    await waitFor(() =>
      expect(screen.getAllByText(/^project\d+$/)).toHaveLength(5));
    fireEvent.click(screen.getByText('project2'));
  
    // Ensure location1 through location5 are displayed
    await waitFor(() =>
      expect(screen.getAllByText(/^location\d+$/)).toHaveLength(5));
    fireEvent.click(screen.getByText('location5'));
  
    // Ensure dataset1 through dataset5 are displayed
    await waitFor(() =>
      expect(screen.getAllByText(/^dataset\d+$/)).toHaveLength(5));
    fireEvent.click(screen.getByText('dataset3'));
  
    // Ensure dicomStore1 through dicomStore5 are displayed
    await waitFor(() =>
      expect(screen.getAllByText(/^dicomStore\d+$/)).toHaveLength(5));
    fireEvent.click(screen.getByText('dicomStore4'));
  
    // Ensure study1 is displayed
    await waitFor(() =>
      expect(screen.getAllByText(/^study\d+$/)).toHaveLength(1));
    fireEvent.click(screen.getByText('study1'));
  
    // Ensure series1 is displayed
    await waitFor(() =>
      expect(screen.getAllByText(/^series\d+$/)).toHaveLength(1));
    fireEvent.click(screen.getByText('series1'));
  
    // Confirm that breadcrumbs are all displaying correctly
    expect(screen.queryByText('project2')).not.toBeNull();
    expect(screen.queryByText('location5')).not.toBeNull();
    expect(screen.queryByText('dataset3')).not.toBeNull();
    expect(screen.queryByText('dicomStore4')).not.toBeNull();
    expect(screen.queryByText('study1')).not.toBeNull();
    expect(screen.queryByText('series1')).not.toBeNull();
  
    // Confirm that clicking a breadcrumb resets state back to
    // search list
    fireEvent.click(screen.getByText('project2'));
    await waitFor(() =>
      expect(screen.queryByText('Select Project')).not.toBeNull());
    await waitFor(() =>
      expect(screen.getAllByText(/^project\d+$/)).toHaveLength(5));
  }, 10000);
  