Skip to content

Commit

Permalink
#2014 Use React Testing Library for common-properties tests - pt1 Act…
Browse files Browse the repository at this point in the history
…ions (#2015)
  • Loading branch information
mikieyx authored Jun 28, 2024
1 parent a718074 commit 8b7ace5
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ import * as UiConditionsParser from "../../src/common-properties/ui-conditions/u
import { mountWithIntl, mountWithIntlMessages } from "./intl-utils";
import { expect } from "chai";
import cloneDeep from "lodash/cloneDeep";

import CustomTableControl from "./custom-controls/CustomTableControl";
import CustomToggleControl from "./custom-controls/CustomToggleControl";
import CustomOpMax from "./custom-condition-ops/customMax";

import sinon from "sinon";

var renderedController;
function controllerHandler(propertyController) {
renderedController = propertyController;
Expand Down Expand Up @@ -60,7 +59,6 @@ function flyoutEditorForm(paramDef, propertiesConfigOverrides, callbacksOverride
if (propertiesConfigOverrides) {
propertiesConfig = Object.assign(propertiesConfig, propertiesConfigOverrides);
}

const wrapper = mountWithIntl(
<div className="properties-right-flyout">
<CommonProperties
Expand Down
120 changes: 120 additions & 0 deletions canvas_modules/common-canvas/__tests__/_utils_/property-utilsRTL.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2017-2023 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import React from "react";
import CommonProperties from "../../src/common-properties/common-properties.jsx";
import * as UiConditionsParser from "../../src/common-properties/ui-conditions/ui-conditions-parser.js";
import { renderWithIntl } from "./intl-utils";
import { expect } from "chai";
import cloneDeep from "lodash/cloneDeep";
import CustomTableControl from "./custom-controls/CustomTableControl";
import CustomToggleControl from "./custom-controls/CustomToggleControl";
import CustomOpMax from "./custom-condition-ops/customMax";
import sinon from "sinon";
import { fireEvent } from "@testing-library/react";

var renderedController;
function controllerHandler(propertyController) {
renderedController = propertyController;
}

function flyoutEditorForm(paramDef, propertiesConfigOverrides, callbacksOverrides, propertiesInfoOverrides) {
const applyPropertyChanges = sinon.spy();
const closePropertiesDialog = sinon.spy();
let callbacks = {
applyPropertyChanges: applyPropertyChanges,
closePropertiesDialog: closePropertiesDialog,
controllerHandler: controllerHandler
};
if (callbacksOverrides) {
callbacks = Object.assign(callbacks, callbacksOverrides);
}

let propertiesInfo = {
parameterDef: cloneDeep(paramDef)
};

if (propertiesInfoOverrides) {
propertiesInfo = Object.assign(propertiesInfo, propertiesInfoOverrides);
}

let propertiesConfig = {
applyOnBlur: true,
rightFlyout: true,
trimSpaces: true,
containerType: "Custom"
};
if (propertiesConfigOverrides) {
propertiesConfig = Object.assign(propertiesConfig, propertiesConfigOverrides);
}
const wrapper = renderWithIntl(
<div className="properties-right-flyout">
<CommonProperties
propertiesInfo={propertiesInfo}
propertiesConfig={propertiesConfig}
callbacks={callbacks}
customControls={[CustomTableControl, CustomToggleControl]}
customConditionOps={[CustomOpMax]}
/>
</div>
);
return { wrapper: wrapper, controller: renderedController, callbacks: callbacks };

}

function setControls(controller, controls) {
const parsedControls = [];
for (const control of controls) {
UiConditionsParser.parseControl(parsedControls, control);
}
controller.saveControls(parsedControls);
}

function genLongString(length) {
let str = "";
while (length > str.length) {
str += Math.random().toString(36)
.substr(2, 1);
}
return str;
}

function openSummaryPanel(wrapper, panelId) {
const { container } = wrapper;
const summaryPanel = container.querySelector(`div[data-id='properties-${panelId}']`);
expect(summaryPanel).to.exist;
fireEvent.click(summaryPanel.querySelector("button.properties-summary-link-button"));
return container.querySelector("div.properties-wf-content.show");
}

function getParameterFromParamDef(parameterId, paramDef) {
const parameters = paramDef.parameters;
let parameterFound = null;
parameters.forEach((parameter) => {
if (parameter.id === parameterId) {
parameterFound = parameter;
}
});
return parameterFound;
}

module.exports = {
flyoutEditorForm: flyoutEditorForm,
setControls: setControls,
genLongString: genLongString,
openSummaryPanel: openSummaryPanel,
getParameterFromParamDef: getParameterFromParamDef
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@
import React from "react";
import { Provider } from "react-redux";
import ActionButton from "./../../../src/common-properties/actions/button";
import { mount } from "../../_utils_/mount-utils.js";
import { render } from "../../_utils_/mount-utils.js";
import { expect } from "chai";
import { expect as expectJest } from "@jest/globals";
import sinon from "sinon";
import Controller from "./../../../src/common-properties/properties-controller";

import ACTION_PARAMDEF from "../../test_resources/paramDefs/action_paramDef.json";
import propertyUtils from "../../_utils_/property-utils";
import propertyUtilsRTL from "../../_utils_/property-utilsRTL";
import { fireEvent, within } from "@testing-library/react";


const actionHandler = sinon.spy();
const controller = new Controller();
Expand Down Expand Up @@ -51,34 +53,48 @@ const action = {
"class_name": "custom-class-for-action-button"
};

const mockActionButton = jest.fn();
jest.mock("./../../../src/common-properties/actions/button",
() => (props) => mockActionButton(props)
);

mockActionButton.mockImplementation((props) => {
const ActionButtonComp = jest.requireActual(
"./../../../src/common-properties/actions/button",
).default;
return <ActionButtonComp {...props} />;
});

describe("action-button renders correctly", () => {

it("props should have been defined", () => {
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);

const button = wrapper.find("ButtonAction");
const button = wrapper.queryAllByRole("button");
expect(button).to.have.length(1);
expect(button.prop("action")).to.equal(action);
expect(button.prop("controller")).to.equal(controller);

expectJest(mockActionButton).toHaveBeenCalledWith({
"action": action,
"controller": controller
});
});

it("should render a `ActionButton`", () => {
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);
const button = wrapper.find("button");
const button = wrapper.getAllByRole("button");
expect(button).to.have.length(1);
});
it("should fire action when button clicked", (done) => {
Expand All @@ -89,72 +105,78 @@ describe("action-button renders correctly", () => {
done();
}
controller.setHandlers({ actionHandler: callback });
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);
const button = wrapper.find("button");
button.simulate("click");
const button = wrapper.getByRole("button");
fireEvent.click(button);
});
it("action button renders when disabled", () => {
controller.updateActionState(actionStateId, "disabled");
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);
const buttonWrapper = wrapper.find("div[data-id='increment']");
expect(buttonWrapper.find("button").prop("disabled")).to.equal(true);
const { container } = wrapper;
const buttonWrapper = container.querySelector("div[data-id='increment']");
const button = within(buttonWrapper).getByRole("button");
expect(button.disabled).to.equal(true);
});
it("action button renders when hidden", () => {
controller.updateActionState(actionStateId, "hidden");
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);
const buttonWrapper = wrapper.find("div[data-id='increment']");
expect(buttonWrapper.hasClass("hide")).to.equal(true);
const { container } = wrapper;
const buttonWrapper = container.querySelector("div[data-id='increment']");
expect(buttonWrapper.className.includes("hide")).to.equal(true);
});
it("action button renders tooltip", () => {
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);
const tooltip = wrapper.find("div.tooltipContainer");
expect(tooltip).to.have.length(1);
expect(tooltip.text()).to.equal("Increment number by 1.");

const tooltips = wrapper.getAllByText("Increment number by 1.");
const parentTooltip = tooltips[0].parentElement;
expect(tooltips.length).equal(1);
expect(parentTooltip.className).equal("tooltipContainer");
});
it("action button kind and size", () => {
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={action}
controller={controller}
/>
</Provider>
);
const button = wrapper.find("button");
const { container } = wrapper;
const contButton = container.getElementsByClassName("cds--btn")[0];
const button = wrapper.getAllByRole("button");
expect(button).to.have.length(1);
// verify button kind is secondary
expect(button.prop("className").includes("cds--btn--secondary")).to.equal(true);
expect(contButton.className.includes("cds--btn--secondary")).to.equal(true);
// verify button size is extra large
expect(button.prop("className").includes("cds--btn--xl")).to.equal(true);
expect(contButton.className.includes("cds--btn--xl")).to.equal(true);
});
it("action button default kind is tertiary and size is small", () => {
const actionWithoutButtonObject = {
Expand All @@ -170,51 +192,57 @@ describe("action-button renders correctly", () => {
"parameter_ref": "number"
}
};
const wrapper = mount(
const wrapper = render(
<Provider store={controller.getStore()}>
<ActionButton
action={actionWithoutButtonObject}
controller={controller}
/>
</Provider>
);
const button = wrapper.find("button");
const { container } = wrapper;
const contButton = container.getElementsByClassName("cds--btn")[0];
const button = wrapper.getAllByRole("button");
expect(button).to.have.length(1);
// verify default button kind is tertiary
expect(button.prop("className").includes("cds--btn--tertiary")).to.equal(true);
expect(contButton.className.includes("cds--btn--tertiary")).to.equal(true);
// verify default button size is small
expect(button.prop("className").includes("cds--btn--sm")).to.equal(true);
expect(contButton.className.includes("cds--btn--sm")).to.equal(true);
});
});

describe("actions using paramDef", () => {
let wrapper;
let renderedObject;
beforeEach(() => {
renderedObject = propertyUtils.flyoutEditorForm(ACTION_PARAMDEF);
renderedObject = propertyUtilsRTL.flyoutEditorForm(ACTION_PARAMDEF);
wrapper = renderedObject.wrapper;
});

it("should fire action when button clicked", (done) => {
renderedObject = propertyUtils.flyoutEditorForm(ACTION_PARAMDEF, null, { actionHandler: callback }, { appData: appData });
renderedObject = propertyUtilsRTL.flyoutEditorForm(ACTION_PARAMDEF, null, { actionHandler: callback }, { appData: appData });
wrapper = renderedObject.wrapper;
function callback(id, inAppData, data) {
expect(id).to.equal("increment");
expect(inAppData).to.eql(appData);
expect(data.parameter_ref).to.equal("number");
done();
}
const button = wrapper.find("div[data-id='increment'] button");
button.simulate("click");
const { container } = wrapper;
const div = container.querySelector("div[data-id='increment']");
const button = within(div).getByRole("button");
fireEvent.click(button);
});

it("action button should have custom classname defined", () => {
const { container } = wrapper;
// class_name defined in uiHints action_info
const incrementButton = wrapper.find("div[data-id='increment']");
expect(incrementButton.prop("className")).to.equal("properties-action-button custom-class-for-action-button");
// const incrementButton = wrapper.find("div[data-id='increment']");
const incrementButton = container.querySelector("div[data-id='increment']");
expect(incrementButton.className).to.equal("properties-action-button custom-class-for-action-button");

// class_name not defined in uiHints action_info
const decrementButton = wrapper.find("div[data-id='decrement']");
expect(decrementButton.prop("className")).to.equal("properties-action-button");
const decrementButton = container.querySelector("div[data-id='decrement']");
expect(decrementButton.className).to.equal("properties-action-button");
});
});
Loading

0 comments on commit 8b7ace5

Please sign in to comment.