department-of-veterans-affairs/vets-website

View on GitHub
src/applications/vaos/appointment-list/components/AppointmentsPage/index.unit.spec.js

Summary

Maintainability
F
1 wk
Test Coverage
import React from 'react';
import MockDate from 'mockdate';
import { expect } from 'chai';
import moment from 'moment';
import { waitFor, within } from '@testing-library/dom';
import environment from '@department-of-veterans-affairs/platform-utilities/environment';
import {
  mockFetch,
  setFetchJSONResponse,
} from '@department-of-veterans-affairs/platform-testing/helpers';
import userEvent from '@testing-library/user-event';
import {
  createTestStore,
  renderWithStoreAndRouter,
  getTestDate,
} from '../../../tests/mocks/setup';
import AppointmentsPage from '.';
import { mockVAOSAppointmentsFetch } from '../../../tests/mocks/helpers';
import { getVAOSRequestMock } from '../../../tests/mocks/mock';
import { createReferral } from '../../../referral-appointments/utils/referrals';
import { FETCH_STATUS } from '../../../utils/constants';

const initialState = {
  featureToggles: {
    vaOnlineSchedulingCancel: true,
    vaOnlineSchedulingRequests: true,
    vaOnlineSchedulingPast: true,
    // eslint-disable-next-line camelcase
    show_new_schedule_view_appointments_page: true,
    vaOnlineSchedulingDirect: true,
    vaOnlineSchedulingCommunityCare: false,
  },
};

describe('VAOS Page: AppointmentsPage', () => {
  beforeEach(() => {
    mockFetch();
    MockDate.set(getTestDate());
  });
  afterEach(() => {
    MockDate.reset();
  });

  const userState = {
    profile: {
      facilities: [{ facilityId: '983', isCerner: false }],
    },
  };

  it('should render warning message', async () => {
    setFetchJSONResponse(
      global.fetch.withArgs(`${environment.API_URL}/v0/maintenance_windows/`),
      {
        data: [
          {
            id: '139',
            type: 'maintenance_windows',
            attributes: {
              externalService: 'vaosWarning',
              description: 'My description',
              startTime: moment.utc().subtract('1', 'days'),
              endTime: moment.utc().add('1', 'days'),
            },
          },
        ],
      },
    );
    const store = createTestStore(initialState);
    const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
      store,
    });

    expect(
      await screen.findByRole('heading', {
        level: 3,
        name: /You may have trouble using the VA appointments tool right now/,
      }),
    ).to.exist;
  });

  it('start scheduling button should open new appointment flow', async () => {
    const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
      initialState: {
        ...initialState,
        user: userState,
      },
    });

    expect(screen.getByText(/Start scheduling/)).to.be.ok;
    userEvent.click(
      await screen.findByRole('link', { name: /Start scheduling/i }),
    );

    await waitFor(() =>
      expect(screen.history.push.lastCall.args[0]).to.equal('/new-appointment'),
    );
  });

  it('should display updated upcoming appointments page', async () => {
    // Given the veteran lands on the VAOS homepage
    // When the page displays
    const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
      initialState,
    });

    // Then it should display the upcoming appointments
    expect(
      await screen.findByRole('heading', {
        level: 1,
        name: 'Appointments',
      }),
    );
    await waitFor(() => {
      expect(global.document.title).to.equal(
        `Appointments | VA online scheduling | Veterans Affairs`,
      );
    });

    // and breadcrumbs should be updated
    const navigation = screen.getByRole('navigation', {
      name: 'Breadcrumbs',
    });
    expect(navigation).to.be.ok;
    expect(
      within(navigation).queryByRole('link', {
        name: 'Pending appointments',
      }),
    ).not.to.exist;
    expect(
      within(navigation).queryByRole('link', { name: 'Past appointments' }),
    ).not.to.exist;

    // and scheduling link should be displayed
    expect(screen.getByRole('link', { name: 'Start scheduling' })).to.be.ok;

    // and appointment list navigation should be displayed
    expect(
      screen.getByRole('navigation', { name: 'Appointment list navigation' }),
    ).to.be.ok;
    expect(screen.getByRole('link', { name: 'Upcoming' })).to.be.ok;
    expect(screen.getByRole('link', { name: /Pending \(\d\)/ })).to.be.ok;
    expect(screen.getByRole('link', { name: 'Past' })).to.be.ok;

    // and status dropdown should not be displayed
    expect(screen.queryByLabelText('Show by status')).not.to.exists;
  });

  it('should display updated appointment request page', async () => {
    // Given the veteran lands on the VAOS homepage
    const appointment = getVAOSRequestMock();
    appointment.id = '1';
    appointment.attributes = {
      id: '1',
      kind: 'clinic',
      locationId: '983',
      requestedPeriods: [{}],
      serviceType: 'primaryCare',
      status: 'proposed',
    };

    mockVAOSAppointmentsFetch({
      start: moment()
        .subtract(1, 'month')
        .format('YYYY-MM-DD'),
      end: moment()
        .add(395, 'days')
        .format('YYYY-MM-DD'),
      statuses: ['booked', 'arrived', 'fulfilled', 'cancelled'],
      requests: [appointment],
    });
    mockVAOSAppointmentsFetch({
      start: moment()
        .subtract(120, 'days')
        .format('YYYY-MM-DD'),
      end: moment().format('YYYY-MM-DD'),
      statuses: ['proposed', 'cancelled'],
      requests: [appointment],
    });

    // When the page displays
    const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
      initialState,
    });

    // Then it should display upcoming appointments
    await screen.findByRole('heading', { name: 'Appointments' });

    // When the veteran clicks the Pending button
    let navigation = await screen.findByRole('link', {
      name: /^Pending \(1\)/,
    });
    userEvent.click(navigation);
    await waitFor(() => {
      expect(screen.history.push.lastCall.args[0].pathname).to.equal(
        '/pending',
      );
    });

    // Then it should display the requested appointments
    await waitFor(() => {
      expect(
        screen.findByRole('heading', {
          level: 1,
          name: 'Pending appointments',
        }),
      );
    });
    await waitFor(() => {
      expect(global.document.title).to.equal(
        `Pending appointments | VA online scheduling | Veterans Affairs`,
      );
    });

    // and breadcrumbs should be updated
    navigation = screen.getByRole('navigation', { name: 'Breadcrumbs' });
    expect(navigation).to.exist;
    const crumb =
      navigation.breadcrumbList[navigation.breadcrumbList.length - 1].label;
    expect(crumb).to.equal('Pending appointments');

    expect(
      screen.getByText(
        'Appointments that you request will show here until staff review and schedule them.',
      ),
    ).to.be.ok;

    // and scheduling button should not be displayed
    expect(
      screen.queryByRole('button', {
        name: 'Start scheduling an appointment',
      }),
    ).not.to.exist;

    // and status dropdown should not be displayed
    expect(screen.queryByLabelText('Show by status')).not.to.exists;

    expect(
      global.window.dataLayer.some(
        e => e === `vaos-status-pending-link-clicked`,
      ),
    );
  });

  it('should display updated past appointment page', async () => {
    // Given the veteran lands on the VAOS homepage
    // When the page displays
    const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
      initialState,
    });

    // Then it should display the upcoming appointments
    await screen.findByRole('heading', { name: 'Appointments' });

    // When the veteran clicks the Past button
    let navigation = screen.getByRole('link', { name: 'Past' });
    userEvent.click(navigation);
    await waitFor(() =>
      expect(screen.history.push.lastCall.args[0].pathname).to.equal('/past'),
    );

    // Then it should display the past appointments
    expect(
      await screen.findByRole('heading', {
        level: 1,
        name: 'Past appointments',
      }),
    ).to.be.ok;
    await waitFor(() => {
      expect(global.document.title).to.equal(
        `Past appointments | VA online scheduling | Veterans Affairs`,
      );
    });

    // and breadcrumbs should be updated
    navigation = screen.getByRole('navigation', { name: 'Breadcrumbs' });
    expect(navigation).to.exist;
    const crumb =
      navigation.breadcrumbList[navigation.breadcrumbList.length - 1].label;
    expect(crumb).to.equal('Past appointments');

    const dropdown = await screen.findByTestId('vaosSelect');

    // and date range dropdown should be displayed
    expect(dropdown).to.have.attribute('label', 'Select a date range');

    // and scheduling button should not be displayed
    expect(
      screen.queryByRole('button', {
        name: 'Start scheduling an appointment',
      }),
    ).not.to.exist;

    // and status dropdown should not be displayed
    expect(screen.queryByLabelText('Show by status')).not.to.exists;

    expect(
      global.window.dataLayer.some(e => e === `vaos-status-past-link-clicked`),
    );
  });

  it('should show tertiary print button', async () => {
    const defaultState = {
      featureToggles: {
        ...initialState.featureToggles,
        vaOnlineSchedulingDirect: true,
        vaOnlineSchedulingCommunityCare: false,
      },
      user: userState,
    };

    // Given the veteran lands on the VAOS homepage
    // When the page displays
    const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
      initialState: defaultState,
    });

    // Then it should display the tertiary print button
    expect(screen.getByRole('button', { name: 'print list' })).to.be.ok;
  });

  describe('when scheduling breadcrumb url update flag is on', () => {
    const defaultState = {
      featureToggles: {
        ...initialState.featureToggles,
        vaOnlineSchedulingDirect: true,
        vaOnlineSchedulingCommunityCare: false,
        vaOnlineSchedulingBreadcrumbUrlUpdate: true,
      },
      user: userState,
    };

    it('should display updated title on upcoming appointments page', async () => {
      // Given the veteran lands on the VAOS homepage
      // When the page displays
      const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
        initialState: defaultState,
      });

      // Then it should display the upcoming appointments
      expect(
        await screen.findByRole('heading', {
          level: 1,
          name: 'Appointments',
        }),
      );
      await waitFor(() => {
        expect(global.document.title).to.equal(
          `Appointments | Veterans Affairs`,
        );
      });

      // and breadcrumbs should be updated
      const navigation = screen.getByRole('navigation', {
        name: 'Breadcrumbs',
      });
      expect(navigation).to.be.ok;
      expect(within(navigation).queryByRole('link', { name: 'Pending' })).not.to
        .exist;
      expect(within(navigation).queryByRole('link', { name: 'Past' })).not.to
        .exist;

      // and scheduling link should be displayed
      expect(screen.getByRole('link', { name: 'Start scheduling' })).to.be.ok;

      // and appointment list navigation should be displayed
      expect(
        screen.getByRole('navigation', { name: 'Appointment list navigation' }),
      ).to.be.ok;
      expect(screen.getByRole('link', { name: 'Upcoming' })).to.be.ok;
      expect(screen.getByRole('link', { name: /Pending \(\d\)/ })).to.be.ok;
      expect(screen.getByRole('link', { name: 'Past' })).to.be.ok;

      // and status dropdown should not be displayed
      expect(screen.queryByLabelText('Show by status')).not.to.exists;
    });

    it('should display updated title on pending appointments page', async () => {
      // Given the veteran lands on the VAOS homepage
      const appointment = getVAOSRequestMock();
      appointment.id = '1';
      appointment.attributes = {
        id: '1',
        kind: 'clinic',
        locationId: '983',
        requestedPeriods: [{}],
        serviceType: 'primaryCare',
        status: 'proposed',
      };

      mockVAOSAppointmentsFetch({
        start: moment()
          .subtract(1, 'month')
          .format('YYYY-MM-DD'),
        end: moment()
          .add(395, 'days')
          .format('YYYY-MM-DD'),
        statuses: ['booked', 'arrived', 'fulfilled', 'cancelled'],
        requests: [appointment],
      });
      mockVAOSAppointmentsFetch({
        start: moment()
          .subtract(120, 'days')
          .format('YYYY-MM-DD'),
        end: moment().format('YYYY-MM-DD'),
        statuses: ['proposed', 'cancelled'],
        requests: [appointment],
      });

      // When the page displays
      const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
        initialState: defaultState,
      });

      // Then it should display upcoming appointments
      await screen.findByRole('heading', { name: 'Appointments' });

      // When the veteran clicks the Pending button
      const navigation = await screen.findByRole('link', {
        name: /^Pending \(1\)/,
      });
      userEvent.click(navigation);
      await waitFor(() => {
        expect(screen.history.push.lastCall.args[0].pathname).to.equal(
          '/pending',
        );
      });

      // Then it should display the requested appointments
      await waitFor(() => {
        expect(
          screen.findByRole('heading', {
            level: 1,
            name: 'Pending appointments',
          }),
        );
      });
      await waitFor(() => {
        expect(global.document.title).to.equal(
          `Pending appointments | Veterans Affairs`,
        );
      });

      expect(
        global.window.dataLayer.some(
          e => e === `vaos-status-pending-link-clicked`,
        ),
      );
    });

    it('should display updated past appointments page title', async () => {
      // Given the veteran lands on the VAOS homepage
      // When the page displays
      const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
        initialState: defaultState,
      });

      // Then it should display the upcoming appointments
      await screen.findByRole('heading', { name: 'Appointments' });

      // When the veteran clicks the Past button
      const navigation = screen.getByRole('link', { name: 'Past' });
      userEvent.click(navigation);
      await waitFor(() =>
        expect(screen.history.push.lastCall.args[0].pathname).to.equal('/past'),
      );

      // Then it should display the past appointments
      expect(
        await screen.findByRole('heading', {
          level: 1,
          name: 'Past appointments',
        }),
      ).to.be.ok;
      await waitFor(() => {
        expect(global.document.title).to.equal(
          `Past appointments | Veterans Affairs`,
        );
      });

      expect(
        global.window.dataLayer.some(
          e => e === `vaos-status-past-link-clicked`,
        ),
      );
    });
  });

  describe('when CC direct scheduling flag is on', () => {
    const defaultState = {
      featureToggles: {
        ...initialState.featureToggles,
        vaOnlineSchedulingCCDirectScheduling: true,
      },
      user: userState,
    };

    it('should display reivew request and referrals link', async () => {
      // Given the veteran lands on the VAOS homepage
      const appointment = getVAOSRequestMock();
      appointment.id = '1';
      appointment.attributes = {
        id: '1',
        kind: 'clinic',
        locationId: '983',
        requestedPeriods: [{}],
        serviceType: 'primaryCare',
        status: 'proposed',
      };

      mockVAOSAppointmentsFetch({
        start: moment()
          .subtract(1, 'month')
          .format('YYYY-MM-DD'),
        end: moment()
          .add(395, 'days')
          .format('YYYY-MM-DD'),
        statuses: ['booked', 'arrived', 'fulfilled', 'cancelled'],
        requests: [appointment],
      });
      mockVAOSAppointmentsFetch({
        start: moment()
          .subtract(120, 'days')
          .format('YYYY-MM-DD'),
        end: moment().format('YYYY-MM-DD'),
        statuses: ['proposed', 'cancelled'],
        requests: [appointment],
      });
      // Given the veteran lands on the VAOS homepage
      // When the page displays
      const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
        initialState: defaultState,
      });

      // Then it should display the upcoming appointments
      await screen.findByRole('heading', { name: 'Appointments' });

      expect(await screen.findByTestId('review-requests-and-referrals')).to
        .exist;

      expect(screen.queryByRole('link', { name: /Pending \(1\)/ })).not.to
        .exist;

      // Then it should not display the referral task card
      expect(await screen.queryByTestId('referral-task-card')).not.to.exist;
    });

    describe('when a referral ID is passed', () => {
      it('should display the referral task card', async () => {
        // Given the veteran lands on the VAOS homepage with with a ID passed
        // When the page displays
        const screen = renderWithStoreAndRouter(<AppointmentsPage />, {
          initialState: {
            ...defaultState,
            referral: {
              facility: null,
              referrals: [
                createReferral(
                  moment().format('YYYY-MM-DD'),
                  'add2f0f4-a1ea-4dea-a504-a54ab57c6801',
                ),
              ],
              referralFetchStatus: FETCH_STATUS.succeeded,
            },
          },
          path: '/?id=add2f0f4-a1ea-4dea-a504-a54ab57c6801',
        });

        await screen.findByRole('heading', { name: 'Appointments' });

        expect(await screen.findByTestId('review-requests-and-referrals')).to
          .exist;

        expect(screen.queryByRole('link', { name: /Pending \(1\)/ })).not.to
          .exist;

        // Then it should display the referral task card
        expect(await screen.findByTestId('referral-task-card')).to.exist;
      });
    });
  });
});