|
1 |
| -import { defineComponent, nextTick, ref, watch, h } from 'vue' |
| 1 | +import { defineComponent, nextTick, ref, watch, h, onMounted } from 'vue' |
2 | 2 | import { createRenderTemplate, render } from '../../test-utils/vue-testing-library'
|
3 | 3 |
|
4 | 4 | import { Popover, PopoverGroup, PopoverButton, PopoverPanel, PopoverOverlay } from './popover'
|
@@ -85,38 +85,46 @@ describe('Rendering', () => {
|
85 | 85 | html`
|
86 | 86 | <PopoverGroup>
|
87 | 87 | <Popover>
|
88 |
| - <PopoverButton>Trigger 1</PopoverButton> |
89 |
| - <PopoverPanel>Panel 1</PopoverPanel> |
| 88 | + <PopoverButton data-trigger="1">Trigger 1</PopoverButton> |
| 89 | + <PopoverPanel data-panel="1">Panel 1</PopoverPanel> |
90 | 90 | </Popover>
|
91 | 91 | <Popover>
|
92 |
| - <PopoverButton>Trigger 2</PopoverButton> |
93 |
| - <PopoverPanel>Panel 2</PopoverPanel> |
| 92 | + <PopoverButton data-trigger="2">Trigger 2</PopoverButton> |
| 93 | + <PopoverPanel data-panel="2">Panel 2</PopoverPanel> |
94 | 94 | </Popover>
|
95 | 95 | </PopoverGroup>
|
96 | 96 | `
|
97 | 97 | )
|
98 | 98 |
|
99 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 1')) |
100 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 2')) |
| 99 | + function getTrigger(number: number) { |
| 100 | + return document.querySelector(`[data-trigger="${number}"]`)! as HTMLElement |
| 101 | + } |
101 | 102 |
|
102 |
| - assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getByText('Panel 1')) |
103 |
| - assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getByText('Panel 2')) |
| 103 | + function getPanel(number: number) { |
| 104 | + return document.querySelector(`[data-panel="${number}"]`)! as HTMLElement |
| 105 | + } |
104 | 106 |
|
105 |
| - await click(getByText('Trigger 1')) |
| 107 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(1)) |
| 108 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(2)) |
106 | 109 |
|
107 |
| - assertPopoverButton({ state: PopoverState.Visible }, getByText('Trigger 1')) |
108 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 2')) |
| 110 | + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getPanel(1)) |
| 111 | + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getPanel(2)) |
109 | 112 |
|
110 |
| - assertPopoverPanel({ state: PopoverState.Visible }, getByText('Panel 1')) |
111 |
| - assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getByText('Panel 2')) |
| 113 | + await click(getTrigger(1)) |
112 | 114 |
|
113 |
| - await click(getByText('Trigger 2')) |
| 115 | + assertPopoverButton({ state: PopoverState.Visible }, getTrigger(1)) |
| 116 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(2)) |
114 | 117 |
|
115 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 1')) |
116 |
| - assertPopoverButton({ state: PopoverState.Visible }, getByText('Trigger 2')) |
| 118 | + assertPopoverPanel({ state: PopoverState.Visible }, getPanel(1)) |
| 119 | + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getPanel(2)) |
| 120 | + |
| 121 | + await click(getTrigger(2)) |
117 | 122 |
|
118 |
| - assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getByText('Panel 1')) |
119 |
| - assertPopoverPanel({ state: PopoverState.Visible }, getByText('Panel 2')) |
| 123 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(1)) |
| 124 | + assertPopoverButton({ state: PopoverState.Visible }, getTrigger(2)) |
| 125 | + |
| 126 | + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getPanel(1)) |
| 127 | + assertPopoverPanel({ state: PopoverState.Visible }, getPanel(2)) |
120 | 128 | })
|
121 | 129 | )
|
122 | 130 | })
|
@@ -1098,47 +1106,55 @@ describe('Keyboard interactions', () => {
|
1098 | 1106 | html`
|
1099 | 1107 | <PopoverGroup>
|
1100 | 1108 | <Popover>
|
1101 |
| - <PopoverButton>Trigger 1</PopoverButton> |
1102 |
| - <PopoverPanel>Panel 1</PopoverPanel> |
| 1109 | + <PopoverButton data-trigger="1">Trigger 1</PopoverButton> |
| 1110 | + <PopoverPanel data-panel="1">Panel 1</PopoverPanel> |
1103 | 1111 | </Popover>
|
1104 | 1112 |
|
1105 | 1113 | <Popover>
|
1106 |
| - <PopoverButton>Trigger 2</PopoverButton> |
1107 |
| - <PopoverPanel>Panel 2</PopoverPanel> |
| 1114 | + <PopoverButton data-trigger="2">Trigger 2</PopoverButton> |
| 1115 | + <PopoverPanel data-panel="2">Panel 2</PopoverPanel> |
1108 | 1116 | </Popover>
|
1109 | 1117 | </PopoverGroup>
|
1110 | 1118 | `
|
1111 | 1119 | )
|
1112 | 1120 |
|
| 1121 | + function getTrigger(number: number) { |
| 1122 | + return document.querySelector(`[data-trigger="${number}"]`)! as HTMLElement |
| 1123 | + } |
| 1124 | + |
| 1125 | + function getPanel(number: number) { |
| 1126 | + return document.querySelector(`[data-panel="${number}"]`)! as HTMLElement |
| 1127 | + } |
| 1128 | + |
1113 | 1129 | // Focus the button of the first Popover
|
1114 |
| - getByText('Trigger 1')?.focus() |
| 1130 | + getTrigger(1)?.focus() |
1115 | 1131 |
|
1116 | 1132 | // Verify popover is closed
|
1117 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 1')) |
1118 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 2')) |
| 1133 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(1)) |
| 1134 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(2)) |
1119 | 1135 |
|
1120 | 1136 | // Open popover
|
1121 |
| - await click(getByText('Trigger 1')) |
| 1137 | + await click(getTrigger(1)) |
1122 | 1138 |
|
1123 | 1139 | // Verify popover is open
|
1124 |
| - assertPopoverButton({ state: PopoverState.Visible }, getByText('Trigger 1')) |
1125 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 2')) |
| 1140 | + assertPopoverButton({ state: PopoverState.Visible }, getTrigger(1)) |
| 1141 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(2)) |
1126 | 1142 |
|
1127 |
| - assertPopoverPanel({ state: PopoverState.Visible }, getByText('Panel 1')) |
1128 |
| - assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getByText('Panel 2')) |
| 1143 | + assertPopoverPanel({ state: PopoverState.Visible }, getPanel(1)) |
| 1144 | + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }, getPanel(2)) |
1129 | 1145 |
|
1130 | 1146 | // Focus the button of the second popover menu
|
1131 |
| - getByText('Trigger 2')?.focus() |
| 1147 | + getTrigger(2)?.focus() |
1132 | 1148 |
|
1133 | 1149 | // Close popover
|
1134 | 1150 | await press(Keys.Escape)
|
1135 | 1151 |
|
1136 | 1152 | // Verify both popovers are closed
|
1137 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 1')) |
1138 |
| - assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getByText('Trigger 2')) |
| 1153 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(1)) |
| 1154 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }, getTrigger(2)) |
1139 | 1155 |
|
1140 | 1156 | // Verify the button of the second popover is still focused
|
1141 |
| - assertActiveElement(getByText('Trigger 2')) |
| 1157 | + assertActiveElement(getTrigger(2)) |
1142 | 1158 | })
|
1143 | 1159 | )
|
1144 | 1160 | })
|
@@ -1696,6 +1712,54 @@ describe('Keyboard interactions', () => {
|
1696 | 1712 | })
|
1697 | 1713 | )
|
1698 | 1714 |
|
| 1715 | + it( |
| 1716 | + 'should focus the Popover.Button when pressing Shift+Tab when we focus inside the Popover.Panel (heuristc based portal)', |
| 1717 | + suppressConsoleLogs(async () => { |
| 1718 | + renderTemplate({ |
| 1719 | + template: html` |
| 1720 | + <Popover> |
| 1721 | + <PopoverButton>Trigger 1</PopoverButton> |
| 1722 | + <Teleport v-if="ready" to="#portal"> |
| 1723 | + <PopoverPanel focus> |
| 1724 | + <a href="/">Link 1</a> |
| 1725 | + <a href="/">Link 2</a> |
| 1726 | + </PopoverPanel> |
| 1727 | + </Teleport> |
| 1728 | + <button>Before</button> |
| 1729 | + <div id="portal" /> |
| 1730 | + <button>After</button> |
| 1731 | + </Popover> |
| 1732 | + `, |
| 1733 | + setup() { |
| 1734 | + let ready = ref(false) |
| 1735 | + onMounted(() => { |
| 1736 | + ready.value = true |
| 1737 | + }) |
| 1738 | + return { ready } |
| 1739 | + }, |
| 1740 | + }) |
| 1741 | + |
| 1742 | + // Open the popover |
| 1743 | + await click(getPopoverButton()) |
| 1744 | + |
| 1745 | + // Ensure the popover is open |
| 1746 | + assertPopoverButton({ state: PopoverState.Visible }) |
| 1747 | + |
| 1748 | + // Ensure the Link 1 is focused |
| 1749 | + assertActiveElement(getByText('Link 1')) |
| 1750 | + |
| 1751 | + // Tab out of the Panel |
| 1752 | + await press(shift(Keys.Tab)) |
| 1753 | + |
| 1754 | + // Ensure the Popover.Button is focused again |
| 1755 | + assertActiveElement(getPopoverButton()) |
| 1756 | + |
| 1757 | + // Ensure the Popover is closed |
| 1758 | + assertPopoverButton({ state: PopoverState.InvisibleUnmounted }) |
| 1759 | + assertPopoverPanel({ state: PopoverState.InvisibleUnmounted }) |
| 1760 | + }) |
| 1761 | + ) |
| 1762 | + |
1699 | 1763 | it(
|
1700 | 1764 | 'should be possible to focus the last item in the PopoverPanel when pressing Shift+Tab on the next PopoverButton',
|
1701 | 1765 | suppressConsoleLogs(async () => {
|
@@ -1981,7 +2045,7 @@ describe('Keyboard interactions', () => {
|
1981 | 2045 | })
|
1982 | 2046 | )
|
1983 | 2047 |
|
1984 |
| - xit( |
| 2048 | + it( |
1985 | 2049 | 'should close the Popover by pressing `Enter` on a PopoverButton and go to the href of the `a` inside a PopoverPanel',
|
1986 | 2050 | suppressConsoleLogs(async () => {
|
1987 | 2051 | renderTemplate(
|
|
0 commit comments