/* eslint-disable max-lines */
import React from 'react';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import { fireEvent, screen, render, act } from '@testing-library/react';
import '@testing-library/jest-dom';
import * as api from 'foremanReact/redux/API';
import { JobWizard } from '../../../JobWizard';
import * as selectors from '../../../JobWizardSelectors';
import { jobTemplate, jobTemplateResponse } from '../../../__tests__/fixtures';
const lodash = require('lodash');
lodash.debounce = fn => fn;
jest.spyOn(api, 'get');
jest.spyOn(selectors, 'selectJobTemplate');
jest.spyOn(selectors, 'selectJobTemplates');
jest.spyOn(selectors, 'selectJobCategories');
const jobCategories = ['Ansible Commands', 'Puppet', 'Services'];
selectors.selectJobCategories.mockImplementation(() => jobCategories);
selectors.selectJobTemplates.mockImplementation(() => [
jobTemplate,
{ ...jobTemplate, id: 2, name: 'template2' },
]);
selectors.selectJobTemplate.mockImplementation(() => jobTemplateResponse);
api.get.mockImplementation(({ handleSuccess, ...action }) => {
if (action.key === 'JOB_CATEGORIES') {
handleSuccess && handleSuccess({ data: { job_categories: jobCategories } });
} else if (action.key === 'JOB_TEMPLATE') {
handleSuccess &&
handleSuccess({
data: jobTemplateResponse,
});
} else if (action.key === 'JOB_TEMPLATES') {
handleSuccess &&
handleSuccess({
data: { results: [jobTemplateResponse.job_template] },
});
}
return { type: 'get', ...action };
});
const mockStore = configureMockStore([]);
const store = mockStore({});
jest.useFakeTimers();
describe('Schedule', () => {
it('sub steps appear', () => {
render(
);
act(() => {
fireEvent.click(screen.getByText('Type of execution'));
});
expect(screen.getAllByText('Future execution')).toHaveLength(1);
expect(screen.getAllByText('Recurring execution')).toHaveLength(1);
act(() => {
fireEvent.click(screen.getByText('Future execution'));
});
expect(screen.getAllByText('Future execution')).toHaveLength(2);
expect(screen.getAllByText('Recurring execution')).toHaveLength(1);
act(() => {
fireEvent.click(screen.getByText('Recurring execution'));
});
expect(screen.getAllByText('Future execution')).toHaveLength(1);
expect(screen.getAllByText('Recurring execution')).toHaveLength(2);
});
it('Future execution', async () => {
render(
);
act(() => {
fireEvent.click(screen.getByText('Type of execution'));
});
act(() => {
fireEvent.click(screen.getByText('Future execution'));
});
act(() => {
fireEvent.click(screen.getByRole('button', { name: 'Future execution' }));
jest.runAllTimers(); // to handle pf4 date picker popover useTimer
});
const newStartAtDate = '2030/03/12';
const newStartBeforeDate = '2030/05/22';
const newStartAtTime = '12:46';
const newStartBeforeTime = '14:27';
const startsAtDateField = () =>
screen.getByLabelText('starts at datepicker');
const startsAtTimeField = () =>
screen.getByLabelText('starts at timepicker');
const startsBeforeDateField = () =>
screen.getByLabelText('starts before datepicker');
const startsBeforeTimeField = () =>
screen.getByLabelText('starts before timepicker');
await act(async () => {
await fireEvent.change(startsAtDateField(), {
target: { value: newStartAtDate },
});
fireEvent.change(startsAtTimeField(), {
target: { value: newStartAtTime },
});
await fireEvent.change(startsBeforeDateField(), {
target: { value: newStartBeforeDate },
});
fireEvent.change(startsBeforeTimeField(), {
target: { value: newStartBeforeTime },
});
jest.runOnlyPendingTimers();
});
act(() => {
fireEvent.click(screen.getByText('Category and Template'));
});
act(() => {
fireEvent.click(screen.getByRole('button', { name: 'Future execution' }));
jest.runAllTimers(); // to handle pf4 date picker popover useTimer
});
expect(startsAtDateField().value).toBe(newStartAtDate);
expect(startsAtTimeField().value).toBe(newStartAtTime);
expect(startsBeforeDateField().value).toBe(newStartBeforeDate);
expect(startsBeforeTimeField().value).toBe(newStartBeforeTime);
expect(
screen.queryAllByText(
"'Starts before' date must be after 'Starts at' date"
)
).toHaveLength(0);
await act(async () => {
await fireEvent.change(startsBeforeDateField(), {
target: { value: '2030/03/11' },
});
await fireEvent.click(startsBeforeTimeField());
await jest.runOnlyPendingTimers();
});
expect(startsBeforeDateField().value).toBe('2030/03/11');
expect(
screen.getAllByText("'Starts before' date must be after 'Starts at' date")
).toHaveLength(1);
expect(
screen.queryAllByText("'Starts before' date must in the future")
).toHaveLength(0);
await act(async () => {
await fireEvent.change(startsBeforeDateField(), {
target: { value: '2019/03/11' },
});
await fireEvent.change(startsAtDateField(), {
target: { value: '' },
});
jest.runOnlyPendingTimers();
});
expect(startsBeforeDateField().value).toBe('2019/03/11');
expect(
screen.getAllByText("'Starts before' date must in the future")
).toHaveLength(1);
});
it('Recurring execution - date pickers', async () => {
render(
);
act(() => {
fireEvent.click(screen.getByText('Type of execution'));
});
act(() => {
fireEvent.click(screen.getByText('Recurring execution'));
});
act(() => {
fireEvent.click(
screen.getByRole('button', { name: 'Recurring execution' })
);
jest.runAllTimers(); // to handle pf4 date picker popover useTimer
});
const newStartAtDate = '2030/03/12';
const newStartAtTime = '12:46';
const startsAtDateField = () =>
screen.getByLabelText('starts at datepicker');
const startsAtTimeField = () =>
screen.getByLabelText('starts at timepicker');
const endsAtDateField = () => screen.getByLabelText('ends on datepicker');
const endsAtTimeField = () => screen.getByLabelText('ends on timepicker');
expect(startsAtDateField().disabled).toBeTruthy();
act(() => {
fireEvent.click(screen.getAllByText('At')[0]);
});
expect(startsAtDateField().disabled).toBeFalsy();
await act(async () => {
await fireEvent.change(startsAtDateField(), {
target: { value: newStartAtDate },
});
fireEvent.change(startsAtTimeField(), {
target: { value: newStartAtTime },
});
jest.runOnlyPendingTimers();
});
expect(endsAtDateField().disabled).toBeTruthy();
act(() => {
fireEvent.click(screen.getByText('On'));
});
expect(endsAtDateField().disabled).toBeFalsy();
await act(async () => {
await fireEvent.change(endsAtDateField(), {
target: { value: newStartAtDate },
});
fireEvent.change(endsAtTimeField(), {
target: { value: newStartAtTime },
});
jest.runOnlyPendingTimers();
});
act(() => {
fireEvent.click(screen.getByText('Category and Template'));
});
act(() => {
fireEvent.click(
screen.getByRole('button', { name: 'Recurring execution' })
);
jest.runAllTimers(); // to handle pf4 date picker popover useTimer
});
expect(startsAtDateField().value).toBe(newStartAtDate);
expect(startsAtTimeField().value).toBe(newStartAtTime);
expect(endsAtDateField().value).toBe(newStartAtDate);
expect(endsAtTimeField().value).toBe(newStartAtTime);
act(() => {
fireEvent.click(screen.getByText('Now'));
fireEvent.click(screen.getByText('After'));
});
expect(startsAtDateField().disabled).toBeTruthy();
expect(endsAtDateField().disabled).toBeTruthy();
expect(startsAtDateField().value).toBe('');
expect(startsAtTimeField().value).toBe('');
expect(endsAtDateField().value).toBe('');
expect(endsAtTimeField().value).toBe('');
});
it('Recurring execution - repeat', async () => {
render(
);
act(() => {
fireEvent.click(screen.getByText('Type of execution'));
});
act(() => {
fireEvent.click(screen.getByText('Recurring execution'));
});
act(() => {
fireEvent.click(
screen.getByRole('button', { name: 'Recurring execution' })
);
jest.runAllTimers(); // to handle pf4 date picker popover useTimer
});
await act(async () => {
fireEvent.click(screen.getByLabelText('Daily', { selector: 'button' }));
});
await act(async () => {
fireEvent.click(screen.getByText('Cronline'));
});
const newCronline = '1 2';
const cronline = screen.getByLabelText('cronline');
expect(cronline.value).toBe('');
await act(async () => {
fireEvent.change(cronline, {
target: { value: newCronline },
});
});
expect(cronline.value).toBe(newCronline);
expect(screen.getByText('Review details').disabled).toBeFalsy();
await act(async () => {
fireEvent.click(screen.getByText('Category and Template'));
});
expect(screen.getAllByText('Category and Template')).toHaveLength(3);
await act(async () => {
fireEvent.click(
screen.getByRole('button', { name: 'Recurring execution' })
);
jest.runAllTimers();
});
expect(screen.queryAllByText('Recurring execution')).toHaveLength(3);
expect(cronline.value).toBe(newCronline);
fireEvent.click(screen.getByText('Cronline'));
await act(async () => {
fireEvent.click(screen.getByText('Monthly'));
});
expect(screen.getByText('Review details').disabled).toBeTruthy();
const newDays = '1,2,3';
const days = screen.getByLabelText('days');
expect(days.value).toBe('');
await act(async () => {
fireEvent.change(days, {
target: { value: newDays },
});
});
expect(days.value).toBe(newDays);
expect(screen.getByText('Review details').disabled).toBeTruthy();
const newAtMonthly = '13:07';
const at = () => screen.getByLabelText('repeat-at');
expect(at().value).toBe('');
await act(async () => {
fireEvent.change(at(), {
target: { value: newAtMonthly },
});
});
expect(at().value).toBe(newAtMonthly);
expect(screen.getByText('Review details').disabled).toBeFalsy();
fireEvent.click(screen.getByText('Monthly'));
await act(async () => {
fireEvent.click(screen.getByText('Weekly'));
});
expect(screen.getByText('Review details').disabled).toBeTruthy();
const dayTue = screen.getByLabelText('Tue checkbox');
const daySat = screen.getByLabelText('Sat checkbox');
expect(dayTue.checked).toBe(false);
expect(daySat.checked).toBe(false);
await act(async () => {
fireEvent.click(dayTue);
fireEvent.change(dayTue, {
target: { checked: true },
});
});
await act(async () => {
fireEvent.click(daySat);
fireEvent.change(daySat, {
target: { checked: true },
});
});
expect(dayTue.checked).toBe(true);
expect(daySat.checked).toBe(true);
const newAtWeekly = '17:53';
expect(at().value).toBe(newAtMonthly);
await act(async () => {
fireEvent.change(at(), {
target: { value: newAtWeekly },
});
});
expect(at().value).toBe(newAtWeekly);
expect(screen.getByText('Review details').disabled).toBeFalsy();
fireEvent.click(screen.getByText('Weekly'));
act(() => {
fireEvent.click(screen.getByText('Daily'));
});
expect(screen.getByText('Review details').disabled).toBeFalsy();
act(() => {
fireEvent.change(at(), {
target: { value: '' },
});
});
expect(screen.getByText('Review details').disabled).toBeTruthy();
const newAtDaily = '17:07';
expect(at().value).toBe('');
act(() => {
fireEvent.change(at(), {
target: { value: newAtDaily },
});
});
expect(at().value).toBe(newAtDaily);
expect(screen.getByText('Review details').disabled).toBeFalsy();
fireEvent.click(screen.getByText('Daily'));
act(() => {
fireEvent.click(screen.getByText('Hourly'));
});
expect(screen.getByText('Review details').disabled).toBeFalsy();
const newMinutes = '6';
const atHourly = () => screen.getByLabelText('repeat-at-minute-typeahead');
expect(atHourly().value).toBe('0');
act(() => {
fireEvent.change(atHourly(), {
target: { value: '62' },
});
});
await act(async () => {
await fireEvent.click(screen.getByText('Create "62"'));
});
expect(atHourly().value).toBe('0');
expect(
screen.queryAllByText('Minute can only be a number between 0-59')
).toHaveLength(1);
act(() => {
fireEvent.change(atHourly(), {
target: { value: newMinutes },
});
});
await act(async () => {
await fireEvent.click(screen.getByText(`Create "${newMinutes}"`));
});
expect(
screen.queryAllByText('Minute can only be a number between 0-59')
).toHaveLength(0);
expect(screen.getByText('Review details').disabled).toBeFalsy();
expect(atHourly().value).toBe(newMinutes);
});
});