diff --git a/packages/components/Button/Button.test.tsx b/packages/components/Button/Button.test.tsx
index 5cff6a1..b731912 100644
--- a/packages/components/Button/Button.test.tsx
+++ b/packages/components/Button/Button.test.tsx
@@ -1,8 +1,9 @@
-import { describe, test, expect, vi } from "vitest";
+import { describe, test, it, expect, vi } from "vitest";
import { mount } from "@vue/test-utils";
import Icon from "../Icon/Icon.vue";
import Button from "./Button.vue";
+import ButtonGroup from "./ButtonGroup.vue";
describe("Button.vue", () => {
const onClick = vi.fn();
@@ -41,6 +42,7 @@ describe("Button.vue", () => {
// events
await wrapper.get("button").trigger("click");
expect(onClick).toHaveBeenCalledOnce();
+ expect(wrapper.emitted("click")).toBeUndefined();
});
test("loading button", () => {
@@ -90,4 +92,162 @@ describe("Button.vue", () => {
expect(iconElement.exists()).toBeTruthy();
expect(iconElement.attributes("icon")).toBe("arrow-up");
});
+
+ // Props: type
+ it("has the correct type class when type prop is set", () => {
+ const types = ["primary", "success", "warning", "danger", "info"];
+ types.forEach((type) => {
+ const wrapper = mount(Button, {
+ props: { type: type as any },
+ });
+ expect(wrapper.classes()).toContain(`er-button--${type}`);
+ });
+ });
+
+ // Props: size
+ it("has the correct size class when size prop is set", () => {
+ const sizes = ["large", "default", "small"];
+ sizes.forEach((size) => {
+ const wrapper = mount(Button, {
+ props: { size: size as any },
+ });
+ expect(wrapper.classes()).toContain(`er-button--${size}`);
+ });
+ });
+
+ // Props: plain, round, circle
+ it.each([
+ ["plain", "is-plain"],
+ ["round", "is-round"],
+ ["circle", "is-circle"],
+ ["disabled", "is-disabled"],
+ ["loading", "is-loading"],
+ ])("has the correct class when prop %s is set to true", (prop, className) => {
+ const wrapper = mount(Button, {
+ props: { [prop]: true },
+
+ global: {
+ stubs: ["ErIcon"],
+ },
+ });
+ expect(wrapper.classes()).toContain(className);
+ if (prop == "loading") {
+ // icon
+ const iconElement = wrapper.findComponent(Icon);
+ expect(iconElement.exists()).toBeTruthy();
+ expect(iconElement.attributes("icon")).toBe("spinner");
+ }
+ });
+
+ it("has the correct native type attribute when native-type prop is set", () => {
+ const wrapper = mount(Button, {
+ props: { nativeType: "submit" },
+ });
+ expect(wrapper.element.tagName).toBe("BUTTON");
+ expect((wrapper.element as any).type).toBe("submit");
+ });
+
+ // Test the click event with and without throttle
+ it.each([
+ ["withoutThrottle", false],
+ ["withThrottle", true],
+ ])("emits click event %s", async (_, useThrottle) => {
+ const clickSpy = vi.fn();
+ const wrapper = mount(() => (
+
+ ));
+
+ await wrapper.get("button").trigger("click");
+ expect(clickSpy).toHaveBeenCalled();
+ });
+
+ // Props: tag
+ it("should renders the custom tag when tag prop is set", () => {
+ const wrapper = mount(Button, {
+ props: { tag: "a" },
+ });
+ expect(wrapper.element.tagName.toLowerCase()).toBe("a");
+ });
+
+ // Events: click
+ it("should emits a click event when the button is clicked", async () => {
+ const wrapper = mount(Button, {});
+ await wrapper.trigger("click");
+ expect(wrapper.emitted().click).toHaveLength(1);
+ });
+
+ // Exception Handling: loading state
+ it("should display loading icon and not emit click event when button is loading", async () => {
+ const wrapper = mount(Button, {
+ props: { loading: true },
+ global: {
+ stubs: ["ErIcon"],
+ },
+ });
+
+ expect(wrapper.find(".loading-icon").exists()).toBe(true);
+ await wrapper.trigger("click");
+ expect(wrapper.emitted("click")).toBeUndefined();
+ });
+});
+
+describe("ButtonGroup.vue", () => {
+ test("basic button group", async () => {
+ const wrapper = mount(() => (
+
+
+
+
+ ));
+
+ expect(wrapper.classes()).toContain("er-button-group");
+ });
+
+ test("button group size", () => {
+ const sizes = ["large", "default", "small"];
+ sizes.forEach((size) => {
+ const wrapper = mount(() => (
+
+
+
+
+ ));
+
+ const buttonWrapper = wrapper.findComponent(Button);
+ expect(buttonWrapper.classes()).toContain(`er-button--${size}`);
+ });
+ });
+
+ test("button group type", () => {
+ const types = ["primary", "success", "warning", "danger", "info"];
+ types.forEach((type) => {
+ const wrapper = mount(() => (
+
+
+
+
+ ));
+
+ const buttonWrapper = wrapper.findComponent(Button);
+ expect(buttonWrapper.classes()).toContain(`er-button--${type}`);
+ });
+ });
+
+ test("button group disabled", () => {
+ const wrapper = mount(() => (
+
+
+
+
+ ));
+
+ const buttonWrapper = wrapper.findComponent(Button);
+ expect(buttonWrapper.classes()).toContain(`is-disabled`);
+ });
});
diff --git a/packages/components/Button/Button.vue b/packages/components/Button/Button.vue
index 456826e..213c699 100644
--- a/packages/components/Button/Button.vue
+++ b/packages/components/Button/Button.vue
@@ -28,7 +28,6 @@ const iconStyle = computed(() => ({
}));
const handleBtnClick = (e: MouseEvent) => {
- if (disabled.value) return;
emits("click", e);
};
const handlBtneCLickThrottle = throttle(handleBtnClick, props.throttleDuration);
@@ -63,6 +62,7 @@ defineExpose({