diff --git a/package.json b/package.json
index 125488a..1967b2e 100644
--- a/package.json
+++ b/package.json
@@ -190,6 +190,5 @@
"console": {}
},
"testEnvironment": "jsdom"
- },
- "dependencies": {}
+ }
}
diff --git a/src/components/summit-dropdown/__tests__/summit-dropdown.test.js b/src/components/summit-dropdown/__tests__/summit-dropdown.test.js
new file mode 100644
index 0000000..943eff1
--- /dev/null
+++ b/src/components/summit-dropdown/__tests__/summit-dropdown.test.js
@@ -0,0 +1,120 @@
+/**
+ * @jest-environment jsdom
+ */
+import React from 'react';
+import "@testing-library/jest-dom";
+import { render, screen, act } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import SummitDropdown from '..';
+
+jest.mock('i18n-react/dist/i18n-react', () => ({
+ __esModule: true,
+ default: { translate: (key) => key },
+}));
+
+const summits = [
+ { id: 1, name: 'Summit A', start_date: 1000 },
+ { id: 2, name: 'Summit B', start_date: 2000 },
+];
+
+const defaultProps = {
+ summits,
+ actionLabel: 'Go',
+ actionClass: '',
+ onClick: jest.fn(),
+};
+
+function renderComponent(props = {}) {
+ return render();
+}
+
+describe('SummitDropdown summitValue state', () => {
+ beforeEach(() => {
+ defaultProps.onClick.mockClear();
+ jest.clearAllMocks();
+ });
+
+ test('summitValue is null on initial render', () => {
+ renderComponent();
+ expect(screen.getByRole('button', { name: 'Go' })).toBeDisabled();
+ });
+
+ test('handleChange sets summitValue when given a valid object', async () => {
+ const user = userEvent.setup();
+ renderComponent();
+
+ await user.click(screen.getByRole('textbox'));
+ await user.click(screen.getByText('Summit A'));
+
+ expect(screen.getByRole('button', { name: 'Go' })).toBeEnabled();
+ });
+
+ test('handleChange does not set summitValue when given a non-object', () => {
+ const ref = React.createRef();
+ render();
+
+ const option = { label: 'Summit A', value: 1 };
+ const invalidOption = 'not-an-object';
+
+ act(() => { ref.current.handleChange(invalidOption); });
+ expect(ref.current.state.summitValue).toBeNull();
+
+ act(() => { ref.current.handleChange(option); });
+ expect(ref.current.state.summitValue).toEqual(option);
+
+ act(() => { ref.current.handleChange(invalidOption); });
+ expect(ref.current.state.summitValue).toEqual(option);
+ });
+
+ test('handleChange does not set summitValue when given null', () => {
+ const ref = React.createRef();
+ render();
+
+ const option = { label: 'Summit A', value: 1 };
+
+ act(() => { ref.current.handleChange(null); });
+ expect(ref.current.state.summitValue).toBeNull();
+
+ act(() => { ref.current.handleChange(option); });
+ expect(ref.current.state.summitValue).toEqual(option);
+
+ act(() => { ref.current.handleChange(null); });
+ expect(ref.current.state.summitValue).toEqual(option);
+ });
+
+ test('handleClick does not call onClick when summitValue is null', async () => {
+ const user = userEvent.setup();
+ renderComponent();
+
+ // button is disabled — click is a no-op, onClick must NOT be called
+ await user.click(screen.getByRole('button', { name: 'Go' }));
+
+ expect(defaultProps.onClick).not.toHaveBeenCalled();
+ });
+
+ test('handleClick calls onClick with summit id when summitValue is set', async () => {
+ const user = userEvent.setup();
+ renderComponent();
+
+ await user.click(screen.getByRole('textbox'));
+ await user.click(screen.getByText('Summit A'));
+ await user.click(screen.getByRole('button', { name: 'Go' }));
+
+ expect(defaultProps.onClick).toHaveBeenCalledWith(1);
+ });
+
+ test('button is disabled when summitValue is null', () => {
+ renderComponent();
+ expect(screen.getByRole('button', { name: 'Go' })).toBeDisabled();
+ });
+
+ test('button is enabled after selecting a summit', async () => {
+ const user = userEvent.setup();
+ renderComponent();
+
+ await user.click(screen.getByRole('textbox'));
+ await user.click(screen.getByText('Summit A'));
+
+ expect(screen.getByRole('button', { name: 'Go' })).toBeEnabled();
+ });
+});
diff --git a/src/components/summit-dropdown/index.js b/src/components/summit-dropdown/index.js
index 40cb2e5..7a2a4f4 100644
--- a/src/components/summit-dropdown/index.js
+++ b/src/components/summit-dropdown/index.js
@@ -30,24 +30,29 @@ export default class SummitDropdown extends React.Component {
}
handleChange(summit) {
- this.setState({summitValue: summit});
+ const summitValue = summit?.value !== undefined ? summit : this.state.summitValue;
+
+ this.setState({ summitValue });
}
handleClick(ev) {
ev.preventDefault();
- this.props.onClick(this.state.summitValue.value);
+ if ( this.state?.summitValue?.value !== undefined )
+ this.props.onClick(this.state.summitValue.value);
}
render() {
- let {summits, actionLabel, actionClass} = this.props;
- let summitOptions = summits
+ let { summits, actionLabel, actionClass } = this.props;
+ let summitOptions = [...summits]
.sort(
(a, b) => (a.start_date < b.start_date ? 1 : (a.start_date > b.start_date ? -1 : 0))
).map(s => ({label: s.name, value: s.id}));
let bigClass = this.props.hasOwnProperty('big') ? 'big' : '';
- const isDisabled = !this.state.summitValue;
+ const isDisabled = this.state.summitValue?.value === undefined;
+
+
return (