diff --git a/src/dropdown-menu/test/__snapshots__/index.legacy.js.snap b/src/dropdown-menu/test/__snapshots__/index.legacy.js.snap
deleted file mode 100644
index a32d0ba96..000000000
--- a/src/dropdown-menu/test/__snapshots__/index.legacy.js.snap
+++ /dev/null
@@ -1,345 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`click option 1`] = `
-
-`;
-
-exports[`close-on-click-outside 1`] = `
-
-`;
-
-exports[`destroy one item 1`] = `
-
-`;
-
-exports[`didn\`t find matched option 1`] = `
-
-`;
-
-exports[`direction up 1`] = `
-
-`;
-
-exports[`direction up 2`] = `
-
-`;
-
-exports[`disable close-on-click-outside 1`] = `
-
-`;
-
-exports[`disable dropdown item 1`] = `
-
-`;
-
-exports[`render option icon 1`] = `
-
-`;
-
-exports[`show dropdown item 1`] = `
-
-`;
-
-exports[`show dropdown item 2`] = `
-
-`;
-
-exports[`show dropdown item 3`] = `
-
-`;
-
-exports[`title prop 1`] = `
-
-`;
-
-exports[`title slot 1`] = `
-
-`;
diff --git a/src/dropdown-menu/test/__snapshots__/index.spec.tsx.snap b/src/dropdown-menu/test/__snapshots__/index.spec.tsx.snap
new file mode 100644
index 000000000..30c5b5817
--- /dev/null
+++ b/src/dropdown-menu/test/__snapshots__/index.spec.tsx.snap
@@ -0,0 +1,850 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`click option 1`] = `
+
+`;
+
+exports[`close-on-click-outside 1`] = `
+
+`;
+
+exports[`destroy one item 1`] = `
+
+`;
+
+exports[`direction up 1`] = `
+
+`;
+
+exports[`direction up 2`] = `
+
+`;
+
+exports[`disable close-on-click-outside 1`] = `
+
+`;
+
+exports[`disable dropdown item 1`] = `
+
+`;
+
+exports[`render option icon 1`] = `
+
+`;
+
+exports[`show dropdown item 1`] = `
+
+`;
+
+exports[`show dropdown item 2`] = `
+
+`;
+
+exports[`show dropdown item 3`] = `
+
+`;
+
+exports[`title prop 1`] = `
+
+`;
+
+exports[`title slot 1`] = `
+
+`;
diff --git a/src/dropdown-menu/test/index.legacy.js b/src/dropdown-menu/test/index.legacy.js
deleted file mode 100644
index 370f6436e..000000000
--- a/src/dropdown-menu/test/index.legacy.js
+++ /dev/null
@@ -1,255 +0,0 @@
-import { mount, later } from '../../../test';
-
-function renderWrapper(options = {}) {
- return mount({
- template: `
-
-
-
-
- `,
- data() {
- return {
- value: options.value || 0,
- title: options.title || '',
- direction: options.direction || 'down',
- closeOnClickOutside: options.closeOnClickOutside,
- options: [
- { text: 'A', value: 0, icon: options.icon },
- { text: 'B', value: 1, icon: options.icon },
- ],
- };
- },
- });
-}
-
-test('show dropdown item', async () => {
- const wrapper = renderWrapper();
-
- await later();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
-
- titles[0].trigger('click');
- expect(wrapper.html()).toMatchSnapshot();
-
- titles[1].trigger('click');
- expect(wrapper.html()).toMatchSnapshot();
-
- titles[1].trigger('click');
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('render option icon', async () => {
- const wrapper = renderWrapper({
- icon: 'success',
- });
-
- await later();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
-
- titles[0].trigger('click');
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('close-on-click-outside', async () => {
- const wrapper = renderWrapper({
- closeOnClickOutside: true,
- });
-
- await later();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
-
- titles[0].trigger('click');
- document.body.click();
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('disable close-on-click-outside', async () => {
- const wrapper = renderWrapper({
- closeOnClickOutside: false,
- });
-
- await later();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
-
- titles[0].trigger('click');
- document.body.click();
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('direction up', async () => {
- const { innerHeight } = window;
- window.innerHeight = 1000;
-
- const wrapper = renderWrapper({
- direction: 'up',
- });
-
- await later();
- expect(wrapper.html()).toMatchSnapshot();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
- titles[0].trigger('click');
- expect(wrapper.html()).toMatchSnapshot();
-
- window.innerHeight = innerHeight;
-});
-
-test('click option', async () => {
- const wrapper = renderWrapper();
-
- await later();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
- titles[0].trigger('click');
-
- const options = wrapper.findAll('.van-dropdown-item .van-cell');
- options[1].trigger('click');
-
- await later();
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('title prop', async () => {
- const wrapper = renderWrapper({ title: 'Title' });
- await later();
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('didn`t find matched option', async () => {
- const wrapper = renderWrapper({ value: -1 });
- await later();
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('destroy one item', async () => {
- const wrapper = mount({
- template: `
-
-
-
-
- `,
- data() {
- return {
- value: 0,
- render: true,
- options: [
- { text: 'A', value: 0 },
- { text: 'B', value: 1 },
- ],
- };
- },
- });
-
- await later();
- wrapper.setData({ render: false });
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('disable dropdown item', async () => {
- const wrapper = mount({
- template: `
-
-
-
- `,
- data() {
- return {
- value: 0,
- options: [
- { text: 'A', value: 0 },
- { text: 'B', value: 1 },
- ],
- };
- },
- });
-
- const title = wrapper.find('.van-dropdown-menu__title');
- title.trigger('click');
- expect(wrapper.html()).toMatchSnapshot();
-});
-
-test('change event', async () => {
- const onChange = jest.fn();
-
- const wrapper = mount({
- template: `
-
-
-
-
- `,
- data() {
- return {
- value: 0,
- options: [
- { text: 'A', value: 0 },
- { text: 'B', value: 1 },
- ],
- };
- },
- methods: {
- onChange,
- },
- });
-
- await later();
-
- const titles = wrapper.findAll('.van-dropdown-menu__title');
- titles[0].trigger('click');
-
- const options = wrapper.findAll('.van-dropdown-item .van-cell');
- options[0].trigger('click');
-
- expect(onChange).toHaveBeenCalledTimes(0);
-
- options[1].trigger('click');
- expect(onChange).toHaveBeenCalledWith(1);
- expect(onChange).toHaveBeenCalledTimes(1);
-});
-
-test('toggle method', async (done) => {
- const wrapper = mount({
- template: `
-
-
-
- `,
- async mounted() {
- // show
- this.$refs.item.toggle(true, { immediate: true });
- await later();
-
- const content = wrapper.find('.van-dropdown-item__content');
- expect(content.style.display).toEqual('');
-
- // hide
- this.$refs.item.toggle(false, { immediate: true });
- await later();
- expect(content.style.display).toEqual('none');
-
- done();
- },
- });
-});
-
-test('title slot', () => {
- const wrapper = mount({
- template: `
-
-
-
- Custom Title
-
-
-
- `,
- });
-
- expect(wrapper.html()).toMatchSnapshot();
-});
diff --git a/src/dropdown-menu/test/index.spec.tsx b/src/dropdown-menu/test/index.spec.tsx
new file mode 100644
index 000000000..f3c6df722
--- /dev/null
+++ b/src/dropdown-menu/test/index.spec.tsx
@@ -0,0 +1,280 @@
+import { later, mount } from '../../../test';
+import { reactive, ref, onMounted } from 'vue';
+import DropdownItem from '../../dropdown-item';
+import DropdownMenu, { DropdownMenuDirection } from '..';
+
+function renderWrapper(
+ options: {
+ value?: number;
+ title?: string;
+ direction?: DropdownMenuDirection | undefined;
+ closeOnClickOutside?: boolean;
+ icon?: string;
+ } = {}
+) {
+ return mount({
+ setup() {
+ const state = reactive({
+ value: options.value || 0,
+ title: options.title || '',
+ direction: options.direction || 'down',
+ closeOnClickOutside: !!options.closeOnClickOutside,
+ options: [
+ { text: 'A', value: 0, icon: options.icon },
+ { text: 'B', value: 1, icon: options.icon },
+ ],
+ });
+
+ return () => (
+
+
+
+
+ );
+ },
+ });
+}
+
+test('show dropdown item', async () => {
+ const wrapper = renderWrapper();
+
+ await later();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+
+ await titles[0].trigger('click');
+ expect(wrapper.html()).toMatchSnapshot();
+
+ await titles[1].trigger('click');
+ expect(wrapper.html()).toMatchSnapshot();
+
+ await titles[1].trigger('click');
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('render option icon', async () => {
+ const wrapper = renderWrapper({
+ icon: 'success',
+ });
+
+ await later();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+
+ await titles[0].trigger('click');
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('close-on-click-outside', async () => {
+ const wrapper = renderWrapper({
+ closeOnClickOutside: true,
+ });
+
+ await later();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+
+ await titles[0].trigger('click');
+
+ document.body.click();
+ await later();
+
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('disable close-on-click-outside', async () => {
+ const wrapper = renderWrapper({
+ closeOnClickOutside: false,
+ });
+
+ await later();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+
+ await titles[0].trigger('click');
+ document.body.click();
+ await later();
+
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('direction up', async () => {
+ const wrapper = renderWrapper({
+ direction: 'up',
+ });
+
+ await later();
+ expect(wrapper.html()).toMatchSnapshot();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+ await titles[0].trigger('click');
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('click option', async () => {
+ const wrapper = renderWrapper();
+
+ await later();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+ await titles[0].trigger('click');
+
+ const options = wrapper.findAll('.van-dropdown-item .van-cell');
+ await options[1].trigger('click');
+
+ await later();
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('title prop', async () => {
+ const wrapper = renderWrapper({ title: 'Title' });
+ await later();
+
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('destroy one item', async () => {
+ const wrapper = mount({
+ props: {
+ render: {
+ type: Boolean,
+ default: true,
+ },
+ },
+ setup(props) {
+ const options = [
+ { text: 'A', value: 0 },
+ { text: 'B', value: 1 },
+ ];
+ const value = 0;
+
+ return () => (
+
+ {props.render && (
+
+ )}
+
+
+ );
+ },
+ });
+
+ await later();
+ await wrapper.setProps({ render: false });
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('disable dropdown item', async () => {
+ const wrapper = mount({
+ setup() {
+ const options = [
+ { text: 'A', value: 0 },
+ { text: 'B', value: 1 },
+ ];
+
+ return () => (
+
+
+
+ );
+ },
+ });
+
+ await later();
+ const title = wrapper.find('.van-dropdown-menu__title');
+ await title.trigger('click');
+ expect(wrapper.html()).toMatchSnapshot();
+});
+
+test('change event', async () => {
+ const onChange = jest.fn();
+
+ const wrapper = mount({
+ setup() {
+ const options = [
+ { text: 'A', value: 0 },
+ { text: 'B', value: 1 },
+ ];
+
+ return () => (
+
+
+
+
+ );
+ },
+ });
+
+ await later();
+
+ const titles = wrapper.findAll('.van-dropdown-menu__title');
+ await titles[0].trigger('click');
+
+ const options = wrapper.findAll('.van-dropdown-item .van-cell');
+ await options[0].trigger('click');
+
+ expect(onChange).toHaveBeenCalledTimes(0);
+
+ await options[1].trigger('click');
+ expect(onChange).toHaveBeenCalledWith(1);
+ expect(onChange).toHaveBeenCalledTimes(1);
+});
+
+test('toggle method', async (done) => {
+ const wrapper = mount({
+ setup() {
+ const item = ref();
+
+ onMounted(async () => {
+ // show
+ item.value.toggle(true, { immediate: true });
+ await later();
+
+ expect(
+ wrapper.find('.van-dropdown-item__content').style.display
+ ).toEqual('');
+
+ // hide
+ item.value.toggle(false, { immediate: true });
+ await later();
+ expect(
+ wrapper.find('.van-dropdown-item__content').style.display
+ ).toEqual('none');
+
+ done();
+ });
+
+ return () => (
+
+
+
+ );
+ },
+ });
+});
+
+test('title slot', async () => {
+ const wrapper = mount({
+ setup() {
+ return () => (
+
+ {{ title: () => 'Custom Title' }}
+
+ );
+ },
+ });
+
+ await later();
+ expect(wrapper.html()).toMatchSnapshot();
+});