From d66ee9c391aa662d08489f8e64e87d6ef420755c Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Tue, 19 Apr 2022 17:56:21 +0800 Subject: [PATCH] feat: add radio and radio-group component Signed-off-by: Ryan Wang --- src/components/base/radio/Radio.vue | 69 +++++++++ src/components/base/radio/RadioGroup.vue | 45 ++++++ .../base/radio/__tests__/Radio.spec.ts | 98 +++++++++++++ .../base/radio/__tests__/RadioGroup.spec.ts | 135 ++++++++++++++++++ .../__snapshots__/Radio.spec.ts.snap | 8 ++ .../__snapshots__/RadioGroup.spec.ts.snap | 12 ++ src/components/base/radio/index.ts | 2 + src/views/ViewComponents.vue | 49 ++++++- 8 files changed, 411 insertions(+), 7 deletions(-) create mode 100644 src/components/base/radio/Radio.vue create mode 100644 src/components/base/radio/RadioGroup.vue create mode 100644 src/components/base/radio/__tests__/Radio.spec.ts create mode 100644 src/components/base/radio/__tests__/RadioGroup.spec.ts create mode 100644 src/components/base/radio/__tests__/__snapshots__/Radio.spec.ts.snap create mode 100644 src/components/base/radio/__tests__/__snapshots__/RadioGroup.spec.ts.snap create mode 100644 src/components/base/radio/index.ts diff --git a/src/components/base/radio/Radio.vue b/src/components/base/radio/Radio.vue new file mode 100644 index 00000000..09e96ddd --- /dev/null +++ b/src/components/base/radio/Radio.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/components/base/radio/RadioGroup.vue b/src/components/base/radio/RadioGroup.vue new file mode 100644 index 00000000..5c4b29be --- /dev/null +++ b/src/components/base/radio/RadioGroup.vue @@ -0,0 +1,45 @@ + + + diff --git a/src/components/base/radio/__tests__/Radio.spec.ts b/src/components/base/radio/__tests__/Radio.spec.ts new file mode 100644 index 00000000..26b5a505 --- /dev/null +++ b/src/components/base/radio/__tests__/Radio.spec.ts @@ -0,0 +1,98 @@ +import { describe, expect, it } from "vitest"; +import { VRadio } from "../index"; +import { mount } from "@vue/test-utils"; + +describe("Radio", () => { + it("should render", () => { + expect(VRadio).toBeDefined(); + expect(mount(VRadio).html()).toMatchSnapshot(); + }); + + it("should work with v-model", async function () { + const wrapper = mount({ + data() { + return { + value: "", + }; + }, + template: "", + components: { + VRadio, + }, + }); + + expect(wrapper.findComponent(VRadio).classes()).not.toContain( + "radio-wrapper-checked" + ); + + await wrapper.setData({ value: "bar" }); + + expect(wrapper.findComponent(VRadio).classes()).toContain( + "radio-wrapper-checked" + ); + }); + + it("should work with label prop", async function () { + const wrapper = mount(VRadio, { + props: { + value: "foo", + }, + }); + expect(wrapper.html()).not.toContain("label"); + + await wrapper.setProps({ label: "foo" }); + + expect(wrapper.html()).toContain("label"); + expect(wrapper.find("label").text()).toBe("foo"); + }); + + it("should work with multiple radio", async function () { + const wrapper = mount({ + data() { + return { + value: "foo", + }; + }, + template: + "" + + "", + components: { + VRadio, + }, + }); + + expect(wrapper.findAllComponents(VRadio).length).toBe(2); + expect(wrapper.findAllComponents(VRadio)[0].classes()).toContain( + "radio-wrapper-checked" + ); + + // set value to bar + await wrapper.setData({ value: "bar" }); + + expect(wrapper.findAllComponents(VRadio)[0].classes()).not.toContain( + "radio-wrapper-checked" + ); + expect(wrapper.findAllComponents(VRadio)[1].classes()).toContain( + "radio-wrapper-checked" + ); + + // click on the first radio + await wrapper + .findAllComponents(VRadio)[0] + .find('input[type="radio"]') + .trigger("change"); + + expect(wrapper.findAllComponents(VRadio)[0].classes()).toContain( + "radio-wrapper-checked" + ); + + // click on the second radio + await wrapper + .findAllComponents(VRadio)[1] + .find('input[type="radio"]') + .trigger("change"); + expect(wrapper.findAllComponents(VRadio)[1].classes()).toContain( + "radio-wrapper-checked" + ); + }); +}); diff --git a/src/components/base/radio/__tests__/RadioGroup.spec.ts b/src/components/base/radio/__tests__/RadioGroup.spec.ts new file mode 100644 index 00000000..0cddd2c1 --- /dev/null +++ b/src/components/base/radio/__tests__/RadioGroup.spec.ts @@ -0,0 +1,135 @@ +import { describe, expect, it } from "vitest"; +import { VRadio, VRadioGroup } from "../index"; +import { mount } from "@vue/test-utils"; + +describe("RadioGroup", () => { + it("should render", function () { + expect(VRadioGroup).toBeDefined(); + expect( + mount(VRadioGroup, { + props: { + options: [ + { + value: "foo", + label: "foo", + }, + { + value: "bar", + label: "bar", + }, + ], + }, + }).html() + ).toMatchSnapshot(); + }); + + it("should work with options prop", function () { + const wrapper = mount({ + data() { + return { + options: [ + { + value: "foo", + label: "foo", + }, + { + value: "bar", + label: "bar", + }, + ], + }; + }, + template: '', + components: { + VRadioGroup, + }, + }); + + expect(wrapper.findAllComponents(VRadio).length).toBe(2); + expect(wrapper.findAllComponents(VRadio)[0].vm.$props.value).toBe("foo"); + expect(wrapper.findAllComponents(VRadio)[0].vm.$props.label).toBe("foo"); + expect(wrapper.findAllComponents(VRadio)[1].vm.$props.value).toBe("bar"); + expect(wrapper.findAllComponents(VRadio)[1].vm.$props.label).toBe("bar"); + }); + + it("should work with v-model", async function () { + const wrapper = mount({ + data() { + return { + value: "foo", + options: [ + { + value: "foo", + label: "foo", + }, + { + value: "bar", + label: "bar", + }, + ], + }; + }, + template: '', + components: { + VRadioGroup, + }, + }); + + expect(wrapper.findAllComponents(VRadio)[0].classes()).toContain( + "radio-wrapper-checked" + ); + + await wrapper + .findAllComponents(VRadio)[1] + .find('input[type="radio"]') + .trigger("change"); + + expect(wrapper.findAllComponents(VRadio)[0].classes()).not.toContain( + "radio-wrapper-checked" + ); + expect(wrapper.findAllComponents(VRadio)[1].classes()).toContain( + "radio-wrapper-checked" + ); + }); + + it("should work with valueKey and labelKey props", async function () { + const wrapper = mount({ + data() { + return { + value: "foo", + options: [ + { + id: "foo", + name: "foo", + }, + { + id: "bar", + name: "bar", + }, + ], + }; + }, + template: + '', + components: { + VRadioGroup, + }, + }); + + expect( + wrapper.findAllComponents(VRadio)[0].find("input").attributes("value") + ).toBe("foo"); + expect( + wrapper.findAllComponents(VRadio)[0].find(".radio-label").text() + ).toBe("foo"); + + await wrapper + .findAllComponents(VRadio)[1] + .find('input[type="radio"]') + .trigger("change"); + + expect(wrapper.findAllComponents(VRadio)[1].classes()).toContain( + "radio-wrapper-checked" + ); + }); +}); diff --git a/src/components/base/radio/__tests__/__snapshots__/Radio.spec.ts.snap b/src/components/base/radio/__tests__/__snapshots__/Radio.spec.ts.snap new file mode 100644 index 00000000..e6510e34 --- /dev/null +++ b/src/components/base/radio/__tests__/__snapshots__/Radio.spec.ts.snap @@ -0,0 +1,8 @@ +// Vitest Snapshot v1 + +exports[`Radio > should render 1`] = ` +"
+
+ +
" +`; diff --git a/src/components/base/radio/__tests__/__snapshots__/RadioGroup.spec.ts.snap b/src/components/base/radio/__tests__/__snapshots__/RadioGroup.spec.ts.snap new file mode 100644 index 00000000..224bcd3c --- /dev/null +++ b/src/components/base/radio/__tests__/__snapshots__/RadioGroup.spec.ts.snap @@ -0,0 +1,12 @@ +// Vitest Snapshot v1 + +exports[`RadioGroup > should render 1`] = ` +"
+
+
+
+
+
+
+
" +`; diff --git a/src/components/base/radio/index.ts b/src/components/base/radio/index.ts new file mode 100644 index 00000000..57469df5 --- /dev/null +++ b/src/components/base/radio/index.ts @@ -0,0 +1,2 @@ +export { default as VRadio } from "./Radio.vue"; +export { default as VRadioGroup } from "./RadioGroup.vue"; diff --git a/src/views/ViewComponents.vue b/src/views/ViewComponents.vue index 12b6e7ef..9f0d2721 100644 --- a/src/views/ViewComponents.vue +++ b/src/views/ViewComponents.vue @@ -42,20 +42,20 @@

Size:

@@ -87,7 +87,7 @@

Disabled:

- +
@@ -97,8 +97,8 @@ {{ option.label }} @@ -109,14 +109,32 @@ {{ option.label }}
+
+

Radio

+

Radio:

+
+ +
+

Radio Group:

+
+ +
+
@@ -125,12 +143,14 @@ import { FilledLayout } from "../layouts"; import { VButton } from "@/components/base/button"; import { VInput } from "@/components/base/input"; -import { VSelect, VOption } from "@/components/base/select"; +import { VOption, VSelect } from "@/components/base/select"; import { VTextarea } from "@/components/base/textarea"; +import { VRadio, VRadioGroup } from "@/components/base/radio"; import { ref } from "vue"; const inputValue = ref(); const selectValue = ref(); +const radioValue = ref("apple"); const selectData = [ { @@ -142,4 +162,19 @@ const selectData = [ label: "2", }, ]; + +const radioData = [ + { + value: "banana", + label: "Banana", + }, + { + value: "apple", + label: "Apple", + }, + { + value: "orange", + label: "Orange", + }, +];