diff --git a/src/cascader/README.md b/src/cascader/README.md
index 9841a296a..cd289495a 100644
--- a/src/cascader/README.md
+++ b/src/cascader/README.md
@@ -81,7 +81,7 @@ export default {
| Attribute | Description | Type | Default |
| --- | --- | --- | --- |
| title | Title | _string_ | - |
-| value | Values of selected options | _string \| number_ | - |
+| value | Value of selected option | _string \| number_ | - |
| options | Options | _Option[]_ | `[]` |
| placeholder | Placeholder of unselected tab | _string_ | `Select` |
| active-color | Active color | _string_ | `#ee0a24` |
diff --git a/src/cascader/test/__snapshots__/demo.spec.js.snap b/src/cascader/test/__snapshots__/demo.spec.js.snap
new file mode 100644
index 000000000..2124ea98e
--- /dev/null
+++ b/src/cascader/test/__snapshots__/demo.spec.js.snap
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders demo correctly 1`] = `
+
+`;
diff --git a/src/cascader/test/__snapshots__/index.spec.js.snap b/src/cascader/test/__snapshots__/index.spec.js.snap
new file mode 100644
index 000000000..882d6490b
--- /dev/null
+++ b/src/cascader/test/__snapshots__/index.spec.js.snap
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render title slot correctly 1`] = `Custom Title
`;
+
+exports[`should select correct option when value changed 1`] = `
+Ouhai
+
+`;
diff --git a/src/cascader/test/index.spec.js b/src/cascader/test/index.spec.js
new file mode 100644
index 000000000..96b52e39a
--- /dev/null
+++ b/src/cascader/test/index.spec.js
@@ -0,0 +1,96 @@
+import Cascader from '..';
+import { mount, later } from '../../../test';
+import options from '../demo/area-en-US';
+
+test('should emit change event when active option changed', async () => {
+ const wrapper = mount(Cascader, {
+ propsData: {
+ options,
+ },
+ });
+
+ await later();
+ wrapper.find('.van-cascader__option').trigger('click');
+
+ const firstOption = options[0];
+ expect(wrapper.emitted('change')[0]).toEqual([
+ {
+ value: firstOption.value,
+ tabIndex: 0,
+ selectedOptions: [firstOption],
+ },
+ ]);
+
+ await later();
+ wrapper
+ .findAll('.van-cascader__options')
+ .at(1)
+ .find('.van-cascader__option')
+ .trigger('click');
+ const secondOption = options[0].children[0];
+ expect(wrapper.emitted('change')[1]).toEqual([
+ {
+ value: secondOption.value,
+ tabIndex: 1,
+ selectedOptions: [firstOption, secondOption],
+ },
+ ]);
+});
+
+test('should emit finish event when all options is selected', async () => {
+ const option = { value: '1', text: 'foo' };
+ const wrapper = mount(Cascader, {
+ propsData: {
+ options: [option],
+ },
+ });
+
+ await later();
+ wrapper.find('.van-cascader__option').trigger('click');
+ expect(wrapper.emitted('finish')[0]).toEqual([
+ {
+ value: option.value,
+ tabIndex: 0,
+ selectedOptions: [option],
+ },
+ ]);
+});
+
+test('should emit close event when close icon is clicked', () => {
+ const wrapper = mount(Cascader);
+ wrapper.find('.van-cascader__close-icon').trigger('click');
+ expect(wrapper.emitted('close')[0]).toBeTruthy();
+});
+
+test('should not render close icon when closeable is false', () => {
+ const wrapper = mount(Cascader, {
+ propsData: {
+ closeable: false,
+ },
+ });
+ expect(wrapper.contains('.van-cascader__close-icon')).toBeFalsy();
+});
+
+test('should render title slot correctly', () => {
+ const wrapper = mount(Cascader, {
+ scopedSlots: {
+ title: () => 'Custom Title',
+ },
+ });
+ expect(wrapper.find('.van-cascader__title').html()).toMatchSnapshot();
+});
+
+test('should select correct option when value changed', async () => {
+ const wrapper = mount(Cascader, {
+ propsData: {
+ options,
+ },
+ });
+
+ await later();
+ wrapper.setProps({ value: '330304' });
+ await later();
+ const selectedOptions = wrapper.findAll('.van-cascader__option--selected');
+ const lastSelectedOption = selectedOptions.at(selectedOptions.length - 1);
+ expect(lastSelectedOption).toMatchSnapshot();
+});