Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/actions/__tests__/email-actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import {
} from "../email-actions";
import * as methods from "../../utils/methods";

jest.mock("../../history", () => ({ push: jest.fn() }));

jest.mock("openstack-uicore-foundation/lib/utils/actions", () => ({
__esModule: true,
...jest.requireActual("openstack-uicore-foundation/lib/utils/actions"),
Expand Down
4 changes: 1 addition & 3 deletions src/actions/email-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
} from "openstack-uicore-foundation/lib/utils/actions";
import URI from "urijs";
import debounce from "lodash/debounce";
import history from "../history";
import { checkOrFilter, getAccessTokenSafely } from "../utils/methods";
import { saveMarketingSetting } from "./marketing-actions";
import {
Expand Down Expand Up @@ -160,9 +159,8 @@ export const saveEmailTemplate =
customErrorHandler,
entity
)(params)(dispatch)
.then((payload) => {
.then(() => {
dispatch(showSuccessMessage(T.translate("emails.template_created")));
history.push(`/app/emails/templates/${payload.response.id}`);
})
.finally(() => {
dispatch(stopLoading());
Expand Down
107 changes: 99 additions & 8 deletions src/components/forms/__tests__/email-template-form.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
afterEach
} from "@jest/globals";
import { render, act, fireEvent } from "@testing-library/react";
import showConfirmDialog from "openstack-uicore-foundation/lib/components/mui/show-confirm-dialog";

import EmailTemplateForm from "../email-template-form";

Expand All @@ -16,10 +17,13 @@ jest.mock("@uiw/react-codemirror", () => ({
__esModule: true,
default: () => null
}));
jest.mock("sweetalert2", () => ({
__esModule: true,
default: { fire: jest.fn(() => Promise.resolve({})) }
}));
jest.mock(
"openstack-uicore-foundation/lib/components/mui/show-confirm-dialog",
() => ({
__esModule: true,
default: jest.fn(() => Promise.resolve(true))
})
);
jest.mock("mjml-browser", () => ({
__esModule: true,
default: () => ({ html: "<html></html>" })
Expand All @@ -31,7 +35,6 @@ jest.mock("../../inputs/email-template-input", () => ({

const baseProps = (entity) => ({
entity,
match: { params: { template_id: `${entity.id}` } },
errors: {},
clients: [],
preview: null,
Expand Down Expand Up @@ -62,7 +65,10 @@ const htmlEntity = {
};

describe("EmailTemplateForm preview dispatch", () => {
beforeEach(() => jest.useFakeTimers());
beforeEach(() => {
jest.useFakeTimers();
showConfirmDialog.mockResolvedValue(true);
});
afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
Expand Down Expand Up @@ -135,7 +141,7 @@ describe("EmailTemplateForm preview dispatch", () => {

it("re-fires the HTML-mode preview when toggled from MJML to HTML", async () => {
const props = baseProps(mjmlEntity);
const { getByDisplayValue } = render(<EmailTemplateForm {...props} />);
const { getByText } = render(<EmailTemplateForm {...props} />);

// initial mount → one MJML-mode request
await act(async () => {
Expand All @@ -152,7 +158,7 @@ describe("EmailTemplateForm preview dispatch", () => {
// mutates neither content field directly
// T.translate returns the key string when no i18n config is loaded
await act(async () => {
fireEvent.click(getByDisplayValue("emails.display_html"));
fireEvent.click(getByText("emails.display_html"));
});
await act(async () => {
jest.advanceTimersByTime(600);
Expand All @@ -166,4 +172,89 @@ describe("EmailTemplateForm preview dispatch", () => {
false
);
});

it("warns before switching to MJML on an HTML-only template and keeps the switch on confirm", async () => {
showConfirmDialog.mockResolvedValue(true);
const props = baseProps(htmlEntity);
const { getByText } = render(<EmailTemplateForm {...props} />);

await act(async () => {
jest.advanceTimersByTime(600);
});

await act(async () => {
fireEvent.click(getByText("emails.display_mjml"));
});

expect(showConfirmDialog).toHaveBeenCalledWith(
expect.objectContaining({
text: "emails.mjml_warning",
iconType: "warning"
})
);

// switch is kept — the button now offers to go back to HTML
expect(getByText("emails.display_html")).toBeTruthy();
});

it("reverts to HTML mode when the MJML switch warning is cancelled", async () => {
showConfirmDialog.mockResolvedValue(false);
const props = baseProps(htmlEntity);
const { getByText } = render(<EmailTemplateForm {...props} />);

await act(async () => {
jest.advanceTimersByTime(600);
});

await act(async () => {
fireEvent.click(getByText("emails.display_mjml"));
});

// reverted back — the button offers to switch to MJML again
expect(getByText("emails.display_mjml")).toBeTruthy();
});
});

describe("EmailTemplateForm responsive preview scale", () => {
let offsetWidthSpy;

beforeEach(() => {
jest.useFakeTimers();
showConfirmDialog.mockResolvedValue(true);
offsetWidthSpy = jest
.spyOn(HTMLElement.prototype, "offsetWidth", "get")
.mockReturnValue(800);
});

afterEach(() => {
jest.runOnlyPendingTimers();
jest.useRealTimers();
jest.clearAllMocks();
offsetWidthSpy.mockRestore();
});

it("recovers to full scale once the preview container widens after an early narrow measurement", async () => {
// simulate the preview container being measured while still narrow --
// e.g. the surrounding page layout hasn't settled yet on first mount
offsetWidthSpy.mockReturnValue(400);
const props = baseProps(htmlEntity);
const { container } = render(<EmailTemplateForm {...props} />);

await act(async () => {
jest.advanceTimersByTime(600);
});

expect(container.querySelector("iframe").style.transform).toBe(
"scale(0.5)"
);

// the container widens (e.g. the rest of the page layout settles)
offsetWidthSpy.mockReturnValue(800);
await act(async () => {
window.dispatchEvent(new Event("resize"));
});

// FIX: scale must recover to 1 -- pre-fix it stays stuck at 0.5 forever
expect(container.querySelector("iframe").style.transform).toBe("scale(1)");
});
});
Loading
Loading