diff --git a/src/components/forms/__tests__/badge-settings-form.test.js b/src/components/forms/__tests__/badge-settings-form.test.js new file mode 100644 index 000000000..c6e5ae19d --- /dev/null +++ b/src/components/forms/__tests__/badge-settings-form.test.js @@ -0,0 +1,61 @@ +import React from "react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import "@testing-library/jest-dom"; +import BadgeSettingsForm from "../badge-settings-form"; + +jest.mock("i18n-react/dist/i18n-react", () => ({ + __esModule: true, + default: { translate: (key) => key } +})); + +jest.mock("sweetalert2", () => ({ + __esModule: true, + default: { fire: jest.fn() } +})); + +const mockSummit = { id: 1, badge_features_types: [], badge_types: [] }; + +const renderForm = (onSubmit) => + render( + + ); + +it("should call onSubmit only once when Save is clicked twice while saving", async () => { + const pendingPromise = new Promise(() => {}); + const onSubmit = jest.fn(() => pendingPromise); + const { container } = renderForm(onSubmit); + + fireEvent.change(container.querySelector("#BADGE_TEMPLATE_WIDTH"), { + target: { value: "100" } + }); + + const saveButton = screen.getByRole("button", { name: "general.save" }); + fireEvent.click(saveButton); + fireEvent.click(saveButton); + + expect(onSubmit).toHaveBeenCalledTimes(1); +}); + +it("should re-enable Save and not throw an unhandled rejection when onSubmit rejects", async () => { + const onSubmit = jest.fn(() => Promise.reject(new Error("412"))); + const { container } = renderForm(onSubmit); + + fireEvent.change(container.querySelector("#BADGE_TEMPLATE_WIDTH"), { + target: { value: "100" } + }); + + fireEvent.click(screen.getByRole("button", { name: "general.save" })); + + await waitFor(() => { + expect( + screen.getByRole("button", { name: "general.save" }) + ).not.toBeDisabled(); + }); +}); diff --git a/src/components/forms/badge-settings-form.js b/src/components/forms/badge-settings-form.js index 27a190999..d9c88eff4 100644 --- a/src/components/forms/badge-settings-form.js +++ b/src/components/forms/badge-settings-form.js @@ -12,10 +12,10 @@ * */ import React from "react"; import T from "i18n-react/dist/i18n-react"; -import UploadInput from "openstack-uicore-foundation/lib/components/inputs/upload-input" -import Input from "openstack-uicore-foundation/lib/components/inputs/text-input" -import TextArea from "openstack-uicore-foundation/lib/components/inputs/textarea-input" -import Panel from "openstack-uicore-foundation/lib/components/sections/panel" +import UploadInput from "openstack-uicore-foundation/lib/components/inputs/upload-input"; +import Input from "openstack-uicore-foundation/lib/components/inputs/text-input"; +import TextArea from "openstack-uicore-foundation/lib/components/inputs/textarea-input"; +import Panel from "openstack-uicore-foundation/lib/components/sections/panel"; import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown"; import Switch from "react-switch"; import Swal from "sweetalert2"; @@ -30,7 +30,8 @@ class BadgeSettingsForm extends React.Component { this.state = { entity: { ...props.entity }, errors: props.errors, - showSection: null + showSection: null, + isSaving: false }; this.handleChange = this.handleChange.bind(this); @@ -159,6 +160,8 @@ class BadgeSettingsForm extends React.Component { handleSubmit(ev) { ev.preventDefault(); + if (this.state.isSaving) return; + // save only the settings with the following conditions const settingsToSave = Object.fromEntries( Object.entries(this.state.entity).filter( @@ -166,19 +169,27 @@ class BadgeSettingsForm extends React.Component { ) ); - this.props.onSubmit(settingsToSave).then(() => { - const success_message = { - title: T.translate("general.done"), - html: T.translate("badge_settings.badge_template_settings_updated"), - type: "success" - }; + this.setState({ isSaving: true }); - Swal.fire(success_message); - }); + this.props + .onSubmit(settingsToSave) + .then(() => { + const success_message = { + title: T.translate("general.done"), + html: T.translate("badge_settings.badge_template_settings_updated"), + type: "success" + }; + + Swal.fire(success_message); + }) + .catch(() => {}) + .finally(() => { + this.setState({ isSaving: false }); + }); } render() { - const { entity, showSection } = this.state; + const { entity, showSection, isSaving } = this.state; const { currentSummit } = this.props; const ddlAlignOptions = [ @@ -1580,6 +1591,7 @@ class BadgeSettingsForm extends React.Component { onClick={this.handleSubmit} className="btn btn-primary pull-right" value={T.translate("general.save")} + disabled={isSaving} />