diff --git a/awx/ui/src/screens/Template/shared/PlaybookSelect.js b/awx/ui/src/screens/Template/shared/PlaybookSelect.js
index 860acf5956..7f073bd84b 100644
--- a/awx/ui/src/screens/Template/shared/PlaybookSelect.js
+++ b/awx/ui/src/screens/Template/shared/PlaybookSelect.js
@@ -59,13 +59,14 @@ function PlaybookSelect({
onToggle={setIsOpen}
placeholderText={t`Select a playbook`}
typeAheadAriaLabel={t`Select a playbook`}
- isCreatable={false}
+ isCreatable
+ createText=""
onSelect={(event, value) => {
setIsOpen(false);
onChange(value);
}}
id="template-playbook"
- isValid={isValid}
+ validated={isValid ? 'default' : 'error'}
onBlur={onBlur}
isDisabled={isLoading || isDisabled}
maxHeight="1000%"
diff --git a/awx/ui/src/screens/Template/shared/PlaybookSelect.test.js b/awx/ui/src/screens/Template/shared/PlaybookSelect.test.js
index 43a8aab8b7..444e02ce6e 100644
--- a/awx/ui/src/screens/Template/shared/PlaybookSelect.test.js
+++ b/awx/ui/src/screens/Template/shared/PlaybookSelect.test.js
@@ -1,15 +1,15 @@
import React from 'react';
-import { act } from 'react-dom/test-utils';
+import { render, fireEvent, waitFor, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
import { ProjectsAPI } from 'api';
-import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
import PlaybookSelect from './PlaybookSelect';
-jest.mock('../../../api');
+jest.mock('api');
describe('', () => {
beforeEach(() => {
ProjectsAPI.readPlaybooks.mockReturnValue({
- data: ['debug.yml'],
+ data: ['debug.yml', 'test.yml'],
});
});
@@ -18,24 +18,90 @@ describe('', () => {
});
test('should reload playbooks when project value changes', async () => {
- let wrapper;
- await act(async () => {
- wrapper = mountWithContexts(
- {}}
- onError={() => {}}
- />
+ const { rerender } = render(
+ {}}
+ onError={() => {}}
+ />
+ );
+
+ await waitFor(() => {
+ expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledWith(1);
+ });
+
+ rerender(
+ {}}
+ onError={() => {}}
+ />
+ );
+
+ await waitFor(() => {
+ expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledTimes(2);
+ expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledWith(15);
+ });
+ });
+
+ test('should trigger the onChange callback for the option selected from the list', async () => {
+ const mockCallback = jest.fn();
+
+ const { container } = render(
+ {}}
+ />
+ );
+
+ await waitFor(() => {
+ const selectToggleButton = container.querySelector(
+ 'button.pf-c-select__toggle-button'
);
+ fireEvent.click(selectToggleButton);
+ // Select options are displayed
+ expect(screen.getAllByRole('option').length).toBe(2);
+
+ fireEvent.click(screen.getByText('debug.yml'));
+
+ expect(mockCallback).toHaveBeenCalledWith('debug.yml');
+ });
+ });
+
+ test('should allow entering playbook file name manually', async () => {
+ const mockCallback = jest.fn();
+
+ const { container } = render(
+ {}}
+ />
+ );
+
+ await waitFor(() => {
+ const input = container.querySelector('input.pf-c-form-control');
+ expect(input).toBeVisible();
+ fireEvent.change(input, { target: { value: 'foo.yml' } });
});
- expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledWith(1);
- await act(async () => {
- wrapper.setProps({ projectId: 15 });
- });
+ await waitFor(() => {
+ // A new select option is displayed ("foo.yml")
+ expect(
+ screen.getByText('"foo.yml"', { selector: '[role="option"]' })
+ ).toBeVisible();
+ expect(screen.getAllByRole('option').length).toBe(1);
- expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledTimes(2);
- expect(ProjectsAPI.readPlaybooks).toHaveBeenCalledWith(15);
+ fireEvent.click(
+ screen.getByText('"foo.yml"', { selector: '[role="option"]' })
+ );
+
+ expect(mockCallback).toHaveBeenCalledWith('foo.yml');
+ });
});
});