|
1 | 1 | import BModal from './modal'
|
2 | 2 | import BvModalEvent from './helpers/bv-modal-event.class'
|
3 | 3 |
|
4 |
| -import { mount, createWrapper } from '@vue/test-utils' |
| 4 | +import { mount, createWrapper, createLocalVue as CreateLocalVue } from '@vue/test-utils' |
5 | 5 |
|
6 | 6 | // The defautl Z-INDEX for modal backdrop
|
7 | 7 | const DEFAULT_ZINDEX = 1040
|
@@ -896,6 +896,282 @@ describe('modal', () => {
|
896 | 896 |
|
897 | 897 | // Modal should now be closed
|
898 | 898 | expect($modal.element.style.display).toEqual('none')
|
| 899 | + |
| 900 | + wrapper.destroy() |
| 901 | + }) |
| 902 | + }) |
| 903 | + |
| 904 | + describe('focus management', () => { |
| 905 | + const localVue = new CreateLocalVue() |
| 906 | + |
| 907 | + it('returns focus to document.body when no return focus set and not using v-b-toggle', async () => { |
| 908 | + // JSDOM won't focus the document unless it has a tab index |
| 909 | + document.body.tabIndex = 0 |
| 910 | + |
| 911 | + const wrapper = mount(BModal, { |
| 912 | + attachToDocument: true, |
| 913 | + localVue: localVue, |
| 914 | + stubs: { |
| 915 | + transition: false |
| 916 | + }, |
| 917 | + propsData: { |
| 918 | + id: 'test', |
| 919 | + visible: false |
| 920 | + } |
| 921 | + }) |
| 922 | + |
| 923 | + expect(wrapper.isVueInstance()).toBe(true) |
| 924 | + |
| 925 | + await wrapper.vm.$nextTick() |
| 926 | + await waitAF() |
| 927 | + await wrapper.vm.$nextTick() |
| 928 | + await waitAF() |
| 929 | + |
| 930 | + const $modal = wrapper.find('div.modal') |
| 931 | + expect($modal.exists()).toBe(true) |
| 932 | + |
| 933 | + expect($modal.element.style.display).toEqual('none') |
| 934 | + expect(document.activeElement).toBe(document.body) |
| 935 | + |
| 936 | + // Try and open modal via .toggle() method |
| 937 | + wrapper.vm.toggle() |
| 938 | + |
| 939 | + await wrapper.vm.$nextTick() |
| 940 | + await waitAF() |
| 941 | + await wrapper.vm.$nextTick() |
| 942 | + await waitAF() |
| 943 | + await wrapper.vm.$nextTick() |
| 944 | + await wrapper.vm.$nextTick() |
| 945 | + |
| 946 | + // Modal should now be open |
| 947 | + expect($modal.element.style.display).toEqual('') |
| 948 | + expect(document.activeElement).not.toBe(document.body) |
| 949 | + expect(wrapper.element.contains(document.activeElement)).toBe(true) |
| 950 | + |
| 951 | + // Try and close modal via .toggle() |
| 952 | + wrapper.vm.toggle() |
| 953 | + |
| 954 | + await wrapper.vm.$nextTick() |
| 955 | + await waitAF() |
| 956 | + await wrapper.vm.$nextTick() |
| 957 | + await waitAF() |
| 958 | + await wrapper.vm.$nextTick() |
| 959 | + await wrapper.vm.$nextTick() |
| 960 | + |
| 961 | + // Modal should now be closed |
| 962 | + expect($modal.element.style.display).toEqual('none') |
| 963 | + expect(document.activeElement).toBe(document.body) |
| 964 | + |
| 965 | + wrapper.destroy() |
| 966 | + }) |
| 967 | + |
| 968 | + it('returns focus to previous active element when return focus not set and not using v-b-toggle', async () => { |
| 969 | + const App = localVue.extend({ |
| 970 | + render(h) { |
| 971 | + return h('div', {}, [ |
| 972 | + h('button', { class: 'trigger', attrs: { id: 'trigger', type: 'button' } }, 'trigger'), |
| 973 | + h(BModal, { props: { id: 'test', visible: false } }, 'modal content') |
| 974 | + ]) |
| 975 | + } |
| 976 | + }) |
| 977 | + const wrapper = mount(App, { |
| 978 | + attachToDocument: true, |
| 979 | + localVue: localVue, |
| 980 | + stubs: { |
| 981 | + transition: false |
| 982 | + } |
| 983 | + }) |
| 984 | + |
| 985 | + expect(wrapper.isVueInstance()).toBe(true) |
| 986 | + |
| 987 | + await wrapper.vm.$nextTick() |
| 988 | + await waitAF() |
| 989 | + await wrapper.vm.$nextTick() |
| 990 | + await waitAF() |
| 991 | + await wrapper.vm.$nextTick() |
| 992 | + await wrapper.vm.$nextTick() |
| 993 | + |
| 994 | + const $button = wrapper.find('button.trigger') |
| 995 | + expect($button.exists()).toBe(true) |
| 996 | + expect($button.is('button')).toBe(true) |
| 997 | + |
| 998 | + const $modal = wrapper.find('div.modal') |
| 999 | + expect($modal.exists()).toBe(true) |
| 1000 | + |
| 1001 | + expect($modal.element.style.display).toEqual('none') |
| 1002 | + expect(document.activeElement).toBe(document.body) |
| 1003 | + |
| 1004 | + // Set the active element to the button |
| 1005 | + $button.element.focus() |
| 1006 | + expect(document.activeElement).toBe($button.element) |
| 1007 | + |
| 1008 | + // Try and open modal via .toggle() method |
| 1009 | + wrapper.find(BModal).vm.toggle() |
| 1010 | + |
| 1011 | + await wrapper.vm.$nextTick() |
| 1012 | + await waitAF() |
| 1013 | + await wrapper.vm.$nextTick() |
| 1014 | + await waitAF() |
| 1015 | + await wrapper.vm.$nextTick() |
| 1016 | + await wrapper.vm.$nextTick() |
| 1017 | + |
| 1018 | + // Modal should now be open |
| 1019 | + expect($modal.element.style.display).toEqual('') |
| 1020 | + expect(document.activeElement).not.toBe(document.body) |
| 1021 | + expect(document.activeElement).not.toBe($button.element) |
| 1022 | + expect($modal.element.contains(document.activeElement)).toBe(true) |
| 1023 | + |
| 1024 | + // Try and close modal via .toggle() |
| 1025 | + wrapper.find(BModal).vm.toggle() |
| 1026 | + |
| 1027 | + await wrapper.vm.$nextTick() |
| 1028 | + await waitAF() |
| 1029 | + await wrapper.vm.$nextTick() |
| 1030 | + await waitAF() |
| 1031 | + await wrapper.vm.$nextTick() |
| 1032 | + await wrapper.vm.$nextTick() |
| 1033 | + |
| 1034 | + // Modal should now be closed |
| 1035 | + expect($modal.element.style.display).toEqual('none') |
| 1036 | + expect(document.activeElement).toBe($button.element) |
| 1037 | + |
| 1038 | + wrapper.destroy() |
| 1039 | + }) |
| 1040 | + |
| 1041 | + it('returns focus to element specified in toggle() method', async () => { |
| 1042 | + const App = localVue.extend({ |
| 1043 | + render(h) { |
| 1044 | + return h('div', {}, [ |
| 1045 | + h('button', { class: 'trigger', attrs: { id: 'trigger', type: 'button' } }, 'trigger'), |
| 1046 | + h( |
| 1047 | + 'button', |
| 1048 | + { class: 'return-to', attrs: { id: 'return-to', type: 'button' } }, |
| 1049 | + 'trigger' |
| 1050 | + ), |
| 1051 | + h(BModal, { props: { id: 'test', visible: false } }, 'modal content') |
| 1052 | + ]) |
| 1053 | + } |
| 1054 | + }) |
| 1055 | + const wrapper = mount(App, { |
| 1056 | + attachToDocument: true, |
| 1057 | + localVue: localVue, |
| 1058 | + stubs: { |
| 1059 | + transition: false |
| 1060 | + } |
| 1061 | + }) |
| 1062 | + |
| 1063 | + expect(wrapper.isVueInstance()).toBe(true) |
| 1064 | + |
| 1065 | + await wrapper.vm.$nextTick() |
| 1066 | + await waitAF() |
| 1067 | + await wrapper.vm.$nextTick() |
| 1068 | + await waitAF() |
| 1069 | + await wrapper.vm.$nextTick() |
| 1070 | + await wrapper.vm.$nextTick() |
| 1071 | + |
| 1072 | + const $button = wrapper.find('button.trigger') |
| 1073 | + expect($button.exists()).toBe(true) |
| 1074 | + expect($button.is('button')).toBe(true) |
| 1075 | + |
| 1076 | + const $button2 = wrapper.find('button.return-to') |
| 1077 | + expect($button2.exists()).toBe(true) |
| 1078 | + expect($button2.is('button')).toBe(true) |
| 1079 | + |
| 1080 | + const $modal = wrapper.find('div.modal') |
| 1081 | + expect($modal.exists()).toBe(true) |
| 1082 | + |
| 1083 | + expect($modal.element.style.display).toEqual('none') |
| 1084 | + expect(document.activeElement).toBe(document.body) |
| 1085 | + |
| 1086 | + // Set the active element to the button |
| 1087 | + $button.element.focus() |
| 1088 | + expect(document.activeElement).toBe($button.element) |
| 1089 | + |
| 1090 | + // Try and open modal via .toggle() method |
| 1091 | + wrapper.find(BModal).vm.toggle('button.return-to') |
| 1092 | + |
| 1093 | + await wrapper.vm.$nextTick() |
| 1094 | + await waitAF() |
| 1095 | + await wrapper.vm.$nextTick() |
| 1096 | + await waitAF() |
| 1097 | + await wrapper.vm.$nextTick() |
| 1098 | + await wrapper.vm.$nextTick() |
| 1099 | + |
| 1100 | + // Modal should now be open |
| 1101 | + expect($modal.element.style.display).toEqual('') |
| 1102 | + expect(document.activeElement).not.toBe(document.body) |
| 1103 | + expect(document.activeElement).not.toBe($button.element) |
| 1104 | + expect(document.activeElement).not.toBe($button2.element) |
| 1105 | + expect($modal.element.contains(document.activeElement)).toBe(true) |
| 1106 | + |
| 1107 | + // Try and close modal via .toggle() |
| 1108 | + wrapper.find(BModal).vm.toggle() |
| 1109 | + |
| 1110 | + await wrapper.vm.$nextTick() |
| 1111 | + await waitAF() |
| 1112 | + await wrapper.vm.$nextTick() |
| 1113 | + await waitAF() |
| 1114 | + await wrapper.vm.$nextTick() |
| 1115 | + await wrapper.vm.$nextTick() |
| 1116 | + |
| 1117 | + // Modal should now be closed |
| 1118 | + expect($modal.element.style.display).toEqual('none') |
| 1119 | + expect(document.activeElement).toBe($button2.element) |
| 1120 | + |
| 1121 | + wrapper.destroy() |
| 1122 | + }) |
| 1123 | + |
| 1124 | + it('if focus leave modal it reutrns to modal', async () => { |
| 1125 | + const App = localVue.extend({ |
| 1126 | + render(h) { |
| 1127 | + return h('div', {}, [ |
| 1128 | + h('button', { class: 'trigger', attrs: { id: 'trigger', type: 'button' } }, 'trigger'), |
| 1129 | + h(BModal, { props: { id: 'test', visible: true } }, 'modal content') |
| 1130 | + ]) |
| 1131 | + } |
| 1132 | + }) |
| 1133 | + const wrapper = mount(App, { |
| 1134 | + attachToDocument: true, |
| 1135 | + localVue: localVue, |
| 1136 | + stubs: { |
| 1137 | + transition: false |
| 1138 | + } |
| 1139 | + }) |
| 1140 | + |
| 1141 | + expect(wrapper.isVueInstance()).toBe(true) |
| 1142 | + |
| 1143 | + await wrapper.vm.$nextTick() |
| 1144 | + await waitAF() |
| 1145 | + await wrapper.vm.$nextTick() |
| 1146 | + await waitAF() |
| 1147 | + await wrapper.vm.$nextTick() |
| 1148 | + await wrapper.vm.$nextTick() |
| 1149 | + |
| 1150 | + const $button = wrapper.find('button.trigger') |
| 1151 | + expect($button.exists()).toBe(true) |
| 1152 | + expect($button.is('button')).toBe(true) |
| 1153 | + |
| 1154 | + const $modal = wrapper.find('div.modal') |
| 1155 | + expect($modal.exists()).toBe(true) |
| 1156 | + |
| 1157 | + expect($modal.element.style.display).toEqual('') |
| 1158 | + expect(document.activeElement).not.toBe(document.body) |
| 1159 | + expect(document.activeElement).toBe($modal.element) |
| 1160 | + |
| 1161 | + // Try anf set focusin on external button |
| 1162 | + $button.trigger('focusin') |
| 1163 | + await wrapper.vm.$nextTick() |
| 1164 | + await wrapper.vm.$nextTick() |
| 1165 | + expect(document.activeElement).not.toBe($button.element) |
| 1166 | + expect(document.activeElement).toBe($modal.element) |
| 1167 | + |
| 1168 | + // Try anf set focusin on external button |
| 1169 | + $button.trigger('focus') |
| 1170 | + await wrapper.vm.$nextTick() |
| 1171 | + await wrapper.vm.$nextTick() |
| 1172 | + expect(document.activeElement).not.toBe($button.element) |
| 1173 | + expect(document.activeElement).toBe($modal.element) |
| 1174 | + |
899 | 1175 | wrapper.destroy()
|
900 | 1176 | })
|
901 | 1177 | })
|
|
0 commit comments