| b69ab31 | | | 1 | /** |
| b69ab31 | | | 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
| b69ab31 | | | 3 | * |
| b69ab31 | | | 4 | * This source code is licensed under the MIT license found in the |
| b69ab31 | | | 5 | * LICENSE file in the root directory of this source tree. |
| b69ab31 | | | 6 | */ |
| b69ab31 | | | 7 | |
| b69ab31 | | | 8 | import {act, fireEvent, render, screen} from '@testing-library/react'; |
| b69ab31 | | | 9 | import userEvent from '@testing-library/user-event'; |
| b69ab31 | | | 10 | import App from '../App'; |
| b69ab31 | | | 11 | import {readAtom} from '../jotaiUtils'; |
| b69ab31 | | | 12 | import {individualToggleKey, selectedCommits} from '../selection'; |
| b69ab31 | | | 13 | import {mostRecentSubscriptionIds} from '../serverAPIState'; |
| b69ab31 | | | 14 | import {CommitInfoTestUtils, CommitTreeListTestUtils} from '../testQueries'; |
| b69ab31 | | | 15 | import { |
| b69ab31 | | | 16 | closeCommitInfoSidebar, |
| b69ab31 | | | 17 | COMMIT, |
| b69ab31 | | | 18 | commitInfoIsOpen, |
| b69ab31 | | | 19 | expectMessageSentToServer, |
| b69ab31 | | | 20 | resetTestMessages, |
| b69ab31 | | | 21 | simulateCommits, |
| b69ab31 | | | 22 | simulateRepoConnected, |
| b69ab31 | | | 23 | TEST_COMMIT_HISTORY, |
| b69ab31 | | | 24 | } from '../testUtils'; |
| b69ab31 | | | 25 | |
| b69ab31 | | | 26 | describe('selection', () => { |
| b69ab31 | | | 27 | beforeEach(() => { |
| b69ab31 | | | 28 | resetTestMessages(); |
| b69ab31 | | | 29 | render(<App />); |
| b69ab31 | | | 30 | act(() => { |
| b69ab31 | | | 31 | simulateRepoConnected(); |
| b69ab31 | | | 32 | expectMessageSentToServer({ |
| b69ab31 | | | 33 | type: 'subscribe', |
| b69ab31 | | | 34 | kind: 'smartlogCommits', |
| b69ab31 | | | 35 | subscriptionID: mostRecentSubscriptionIds.smartlogCommits, |
| b69ab31 | | | 36 | }); |
| b69ab31 | | | 37 | simulateCommits({value: TEST_COMMIT_HISTORY}); |
| b69ab31 | | | 38 | }); |
| b69ab31 | | | 39 | }); |
| b69ab31 | | | 40 | |
| b69ab31 | | | 41 | const click = ( |
| b69ab31 | | | 42 | name: string, |
| b69ab31 | | | 43 | opts?: {shiftKey?: boolean; metaKey?: boolean; ctrlKey?: boolean}, |
| b69ab31 | | | 44 | ) => { |
| b69ab31 | | | 45 | act( |
| b69ab31 | | | 46 | () => void fireEvent.click(CommitTreeListTestUtils.withinCommitTree().getByText(name), opts), |
| b69ab31 | | | 47 | ); |
| b69ab31 | | | 48 | }; |
| b69ab31 | | | 49 | |
| b69ab31 | | | 50 | const expectNoRealSelection = () => |
| b69ab31 | | | 51 | expect(CommitInfoTestUtils.withinCommitInfo().queryAllByTestId('selected-commit')).toHaveLength( |
| b69ab31 | | | 52 | 0, |
| b69ab31 | | | 53 | ); |
| b69ab31 | | | 54 | |
| b69ab31 | | | 55 | const expectOnlyOneCommitSelected = () => |
| b69ab31 | | | 56 | expect( |
| b69ab31 | | | 57 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 58 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 59 | |
| b69ab31 | | | 60 | const expectNCommitsSelected = (n: number) => |
| b69ab31 | | | 61 | expect( |
| b69ab31 | | | 62 | CommitInfoTestUtils.withinCommitInfo().queryByText(`${n} Commits Selected`), |
| b69ab31 | | | 63 | ).toBeInTheDocument(); |
| b69ab31 | | | 64 | |
| b69ab31 | | | 65 | const upArrow = (shift?: boolean) => { |
| b69ab31 | | | 66 | act(() => |
| b69ab31 | | | 67 | userEvent.type( |
| b69ab31 | | | 68 | screen.getByTestId('commit-tree-root'), |
| b69ab31 | | | 69 | (shift ? '{shift}' : '') + '{arrowup}', |
| b69ab31 | | | 70 | ), |
| b69ab31 | | | 71 | ); |
| b69ab31 | | | 72 | }; |
| b69ab31 | | | 73 | const downArrow = (shift?: boolean) => { |
| b69ab31 | | | 74 | act(() => |
| b69ab31 | | | 75 | userEvent.type( |
| b69ab31 | | | 76 | screen.getByTestId('commit-tree-root'), |
| b69ab31 | | | 77 | (shift ? '{shift}' : '') + '{arrowdown}', |
| b69ab31 | | | 78 | ), |
| b69ab31 | | | 79 | ); |
| b69ab31 | | | 80 | }; |
| b69ab31 | | | 81 | |
| b69ab31 | | | 82 | const rightArrow = () => { |
| b69ab31 | | | 83 | act(() => userEvent.type(screen.getByTestId('commit-tree-root'), '{arrowright}')); |
| b69ab31 | | | 84 | }; |
| b69ab31 | | | 85 | |
| b69ab31 | | | 86 | it('allows selecting via click', () => { |
| b69ab31 | | | 87 | act(() => void fireEvent.click(screen.getByText('Commit A'))); |
| b69ab31 | | | 88 | |
| b69ab31 | | | 89 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 90 | }); |
| b69ab31 | | | 91 | |
| b69ab31 | | | 92 | it("can't select public commits", () => { |
| b69ab31 | | | 93 | act(() => void fireEvent.click(screen.getByText('remote/master'))); |
| b69ab31 | | | 94 | // it remains selecting the head commit |
| b69ab31 | | | 95 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit E')).toBeInTheDocument(); |
| b69ab31 | | | 96 | }); |
| b69ab31 | | | 97 | |
| b69ab31 | | | 98 | it('click on different commits changes selection', () => { |
| b69ab31 | | | 99 | act(() => void fireEvent.click(screen.getByText('Commit A'))); |
| b69ab31 | | | 100 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 101 | act(() => void fireEvent.click(screen.getByText('Commit B'))); |
| b69ab31 | | | 102 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit B')).toBeInTheDocument(); |
| b69ab31 | | | 103 | |
| b69ab31 | | | 104 | // not a multi-selection |
| b69ab31 | | | 105 | expect( |
| b69ab31 | | | 106 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 107 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 108 | }); |
| b69ab31 | | | 109 | |
| b69ab31 | | | 110 | it('allows multi-selecting via cmd-click', () => { |
| b69ab31 | | | 111 | act(() => void fireEvent.click(screen.getByText('Commit A'), {[individualToggleKey]: true})); |
| b69ab31 | | | 112 | act(() => void fireEvent.click(screen.getByText('Commit B'), {[individualToggleKey]: true})); |
| b69ab31 | | | 113 | act(() => void fireEvent.click(screen.getByText('Commit C'), {[individualToggleKey]: true})); |
| b69ab31 | | | 114 | |
| b69ab31 | | | 115 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 116 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit B')).toBeInTheDocument(); |
| b69ab31 | | | 117 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 118 | expect( |
| b69ab31 | | | 119 | CommitInfoTestUtils.withinCommitInfo().getByText('3 Commits Selected'), |
| b69ab31 | | | 120 | ).toBeInTheDocument(); |
| b69ab31 | | | 121 | }); |
| b69ab31 | | | 122 | |
| b69ab31 | | | 123 | it('single click after multi-select resets to single selection', () => { |
| b69ab31 | | | 124 | act(() => void fireEvent.click(screen.getByText('Commit A'), {[individualToggleKey]: true})); |
| b69ab31 | | | 125 | act(() => void fireEvent.click(screen.getByText('Commit B'), {[individualToggleKey]: true})); |
| b69ab31 | | | 126 | |
| b69ab31 | | | 127 | act(() => void fireEvent.click(screen.getByText('Commit C'))); |
| b69ab31 | | | 128 | |
| b69ab31 | | | 129 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Commit A')).not.toBeInTheDocument(); |
| b69ab31 | | | 130 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Commit B')).not.toBeInTheDocument(); |
| b69ab31 | | | 131 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 132 | |
| b69ab31 | | | 133 | // not a multi-selection |
| b69ab31 | | | 134 | expect( |
| b69ab31 | | | 135 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 136 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 137 | }); |
| b69ab31 | | | 138 | |
| b69ab31 | | | 139 | it('clicking on a commit a second time deselects it', () => { |
| b69ab31 | | | 140 | const commitA = screen.getByText('Commit A'); |
| b69ab31 | | | 141 | act(() => void fireEvent.click(commitA)); |
| b69ab31 | | | 142 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 143 | act(() => void fireEvent.click(commitA)); |
| b69ab31 | | | 144 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Commit A')).not.toBeInTheDocument(); |
| b69ab31 | | | 145 | }); |
| b69ab31 | | | 146 | |
| b69ab31 | | | 147 | it('cmd-clicking on a commit a second time deselects it', () => { |
| b69ab31 | | | 148 | const commitA = screen.getByText('Commit A'); |
| b69ab31 | | | 149 | act(() => void fireEvent.click(commitA, {[individualToggleKey]: true})); |
| b69ab31 | | | 150 | act(() => void fireEvent.click(screen.getByText('Commit B'), {[individualToggleKey]: true})); |
| b69ab31 | | | 151 | act(() => void fireEvent.click(screen.getByText('Commit C'), {[individualToggleKey]: true})); |
| b69ab31 | | | 152 | |
| b69ab31 | | | 153 | act(() => void fireEvent.click(commitA, {[individualToggleKey]: true})); |
| b69ab31 | | | 154 | |
| b69ab31 | | | 155 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Commit A')).not.toBeInTheDocument(); |
| b69ab31 | | | 156 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit B')).toBeInTheDocument(); |
| b69ab31 | | | 157 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 158 | expect( |
| b69ab31 | | | 159 | CommitInfoTestUtils.withinCommitInfo().getByText('2 Commits Selected'), |
| b69ab31 | | | 160 | ).toBeInTheDocument(); |
| b69ab31 | | | 161 | }); |
| b69ab31 | | | 162 | |
| b69ab31 | | | 163 | it('single click after multi-select resets to single selection, even on a previously selected commits', () => { |
| b69ab31 | | | 164 | const commitA = screen.getByText('Commit A'); |
| b69ab31 | | | 165 | act(() => void fireEvent.click(commitA, {[individualToggleKey]: true})); |
| b69ab31 | | | 166 | act(() => void fireEvent.click(screen.getByText('Commit B'), {[individualToggleKey]: true})); |
| b69ab31 | | | 167 | act(() => void fireEvent.click(screen.getByText('Commit C'), {[individualToggleKey]: true})); |
| b69ab31 | | | 168 | |
| b69ab31 | | | 169 | act(() => void fireEvent.click(commitA)); |
| b69ab31 | | | 170 | |
| b69ab31 | | | 171 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 172 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Commit B')).not.toBeInTheDocument(); |
| b69ab31 | | | 173 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Commit C')).not.toBeInTheDocument(); |
| b69ab31 | | | 174 | |
| b69ab31 | | | 175 | // not a multi-selection |
| b69ab31 | | | 176 | expect( |
| b69ab31 | | | 177 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 178 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 179 | }); |
| b69ab31 | | | 180 | |
| b69ab31 | | | 181 | it("selecting a commit that's no longer available does not render", () => { |
| b69ab31 | | | 182 | // add a new commit F, then select it |
| b69ab31 | | | 183 | act(() => simulateCommits({value: [COMMIT('f', 'Commit F', 'e'), ...TEST_COMMIT_HISTORY]})); |
| b69ab31 | | | 184 | act(() => void fireEvent.click(screen.getByText('Commit F'))); |
| b69ab31 | | | 185 | // remove that commit from the history |
| b69ab31 | | | 186 | act(() => simulateCommits({value: TEST_COMMIT_HISTORY})); |
| b69ab31 | | | 187 | |
| b69ab31 | | | 188 | // F no longer exists to show, so now instead the head commit is selected |
| b69ab31 | | | 189 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit E')).toBeInTheDocument(); |
| b69ab31 | | | 190 | |
| b69ab31 | | | 191 | // not a multi-selection |
| b69ab31 | | | 192 | expect( |
| b69ab31 | | | 193 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 194 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 195 | }); |
| b69ab31 | | | 196 | |
| b69ab31 | | | 197 | it('does not show the submit button for multi selections in GitHub repos', () => { |
| b69ab31 | | | 198 | act(() => void fireEvent.click(screen.getByText('Commit A'), {[individualToggleKey]: true})); |
| b69ab31 | | | 199 | act(() => void fireEvent.click(screen.getByText('Commit B'), {[individualToggleKey]: true})); |
| b69ab31 | | | 200 | expect( |
| b69ab31 | | | 201 | CommitInfoTestUtils.withinCommitInfo().queryByText('Submit Selected Commits'), |
| b69ab31 | | | 202 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 203 | }); |
| b69ab31 | | | 204 | |
| b69ab31 | | | 205 | it("multi selection commit previews doesn't include uncommitted changes", () => { |
| b69ab31 | | | 206 | act( |
| b69ab31 | | | 207 | () => |
| b69ab31 | | | 208 | void fireEvent.click(CommitTreeListTestUtils.withinCommitTree().getByText('Commit E'), { |
| b69ab31 | | | 209 | [individualToggleKey]: true, |
| b69ab31 | | | 210 | }), |
| b69ab31 | | | 211 | ); |
| b69ab31 | | | 212 | act( |
| b69ab31 | | | 213 | () => |
| b69ab31 | | | 214 | void fireEvent.click(CommitTreeListTestUtils.withinCommitTree().getByText('Commit D'), { |
| b69ab31 | | | 215 | [individualToggleKey]: true, |
| b69ab31 | | | 216 | }), |
| b69ab31 | | | 217 | ); |
| b69ab31 | | | 218 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit E')).toBeInTheDocument(); |
| b69ab31 | | | 219 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 220 | |
| b69ab31 | | | 221 | expect( |
| b69ab31 | | | 222 | CommitInfoTestUtils.withinCommitInfo().queryByText('You are here'), |
| b69ab31 | | | 223 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 224 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Uncommit')).not.toBeInTheDocument(); |
| b69ab31 | | | 225 | expect(CommitInfoTestUtils.withinCommitInfo().queryByText('Go to')).not.toBeInTheDocument(); |
| b69ab31 | | | 226 | }); |
| b69ab31 | | | 227 | |
| b69ab31 | | | 228 | describe('shift click selection', () => { |
| b69ab31 | | | 229 | it('selects ranges of commits when shift-clicking', () => { |
| b69ab31 | | | 230 | click('Commit B'); |
| b69ab31 | | | 231 | click('Commit D', {shiftKey: true}); |
| b69ab31 | | | 232 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit B')).toBeInTheDocument(); |
| b69ab31 | | | 233 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 234 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 235 | expect( |
| b69ab31 | | | 236 | CommitInfoTestUtils.withinCommitInfo().getByText('3 Commits Selected'), |
| b69ab31 | | | 237 | ).toBeInTheDocument(); |
| b69ab31 | | | 238 | }); |
| b69ab31 | | | 239 | |
| b69ab31 | | | 240 | it('skips public commits, works across stacks and branches', () => { |
| b69ab31 | | | 241 | click('Commit D'); |
| b69ab31 | | | 242 | click('Commit Y', {shiftKey: true}); |
| b69ab31 | | | 243 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 244 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit E')).toBeInTheDocument(); |
| b69ab31 | | | 245 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit X')).toBeInTheDocument(); |
| b69ab31 | | | 246 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit Y')).toBeInTheDocument(); |
| b69ab31 | | | 247 | expect( |
| b69ab31 | | | 248 | CommitInfoTestUtils.withinCommitInfo().getByText('4 Commits Selected'), // skipped '2', the public base of 'Commit X' |
| b69ab31 | | | 249 | ).toBeInTheDocument(); |
| b69ab31 | | | 250 | }); |
| b69ab31 | | | 251 | |
| b69ab31 | | | 252 | it('adds to selection', () => { |
| b69ab31 | | | 253 | click('Commit A', {[individualToggleKey]: true}); |
| b69ab31 | | | 254 | click('Commit C', {[individualToggleKey]: true}); |
| b69ab31 | | | 255 | click('Commit E', {shiftKey: true}); |
| b69ab31 | | | 256 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 257 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 258 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 259 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit E')).toBeInTheDocument(); |
| b69ab31 | | | 260 | expect( |
| b69ab31 | | | 261 | CommitInfoTestUtils.withinCommitInfo().getByText('4 Commits Selected'), |
| b69ab31 | | | 262 | ).toBeInTheDocument(); |
| b69ab31 | | | 263 | }); |
| b69ab31 | | | 264 | |
| b69ab31 | | | 265 | it('prefers dag range to flatten range', () => { |
| b69ab31 | | | 266 | // a-b--c-d-e |
| b69ab31 | | | 267 | // \ |
| b69ab31 | | | 268 | // f-g |
| b69ab31 | | | 269 | act(() => |
| b69ab31 | | | 270 | simulateCommits({ |
| b69ab31 | | | 271 | value: [ |
| b69ab31 | | | 272 | COMMIT('f', 'Commit F', 'b'), |
| b69ab31 | | | 273 | COMMIT('g', 'Commit G', 'f'), |
| b69ab31 | | | 274 | ...TEST_COMMIT_HISTORY, |
| b69ab31 | | | 275 | ], |
| b69ab31 | | | 276 | }), |
| b69ab31 | | | 277 | ); |
| b69ab31 | | | 278 | |
| b69ab31 | | | 279 | { |
| b69ab31 | | | 280 | click('Commit A'); // select |
| b69ab31 | | | 281 | click('Commit G', {shiftKey: true}); |
| b69ab31 | | | 282 | const selected = readAtom(selectedCommits); |
| b69ab31 | | | 283 | expect([...selected].sort()).toEqual(['a', 'b', 'f', 'g']); |
| b69ab31 | | | 284 | } |
| b69ab31 | | | 285 | |
| b69ab31 | | | 286 | { |
| b69ab31 | | | 287 | click('Commit D'); // select |
| b69ab31 | | | 288 | click('Commit A', {shiftKey: true}); |
| b69ab31 | | | 289 | const selected = readAtom(selectedCommits); |
| b69ab31 | | | 290 | expect([...selected].sort()).toEqual(['a', 'b', 'c', 'd']); |
| b69ab31 | | | 291 | } |
| b69ab31 | | | 292 | }); |
| b69ab31 | | | 293 | |
| b69ab31 | | | 294 | it('deselecting clears last selected', () => { |
| b69ab31 | | | 295 | click('Commit A'); // select |
| b69ab31 | | | 296 | click('Commit A'); // deselect |
| b69ab31 | | | 297 | click('Commit C', {[individualToggleKey]: true}); |
| b69ab31 | | | 298 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 299 | // just one commit, C, selected |
| b69ab31 | | | 300 | expect( |
| b69ab31 | | | 301 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 302 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 303 | }); |
| b69ab31 | | | 304 | |
| b69ab31 | | | 305 | it('shift clicking when nothing selected acts like normal clicking', () => { |
| b69ab31 | | | 306 | click('Commit C', {metaKey: true}); |
| b69ab31 | | | 307 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 308 | expect( |
| b69ab31 | | | 309 | CommitInfoTestUtils.withinCommitInfo().queryByText(/\d Commits Selected/), |
| b69ab31 | | | 310 | ).not.toBeInTheDocument(); |
| b69ab31 | | | 311 | }); |
| b69ab31 | | | 312 | }); |
| b69ab31 | | | 313 | |
| b69ab31 | | | 314 | describe('up/down arrows to select', () => { |
| b69ab31 | | | 315 | it('down arrow with no selection starts you at the top', () => { |
| b69ab31 | | | 316 | expectNoRealSelection(); |
| b69ab31 | | | 317 | downArrow(); |
| b69ab31 | | | 318 | expectOnlyOneCommitSelected(); |
| b69ab31 | | | 319 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit Z')).toBeInTheDocument(); |
| b69ab31 | | | 320 | }); |
| b69ab31 | | | 321 | |
| b69ab31 | | | 322 | it('up arrow noop if nothing selected', () => { |
| b69ab31 | | | 323 | upArrow(); |
| b69ab31 | | | 324 | upArrow(true); |
| b69ab31 | | | 325 | expectNoRealSelection(); |
| b69ab31 | | | 326 | }); |
| b69ab31 | | | 327 | |
| b69ab31 | | | 328 | it('up arrow modifies selection', () => { |
| b69ab31 | | | 329 | click('Commit C'); |
| b69ab31 | | | 330 | upArrow(); |
| b69ab31 | | | 331 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 332 | expectOnlyOneCommitSelected(); |
| b69ab31 | | | 333 | }); |
| b69ab31 | | | 334 | |
| b69ab31 | | | 335 | it('down arrow modifies selection', () => { |
| b69ab31 | | | 336 | click('Commit C'); |
| b69ab31 | | | 337 | downArrow(); |
| b69ab31 | | | 338 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit B')).toBeInTheDocument(); |
| b69ab31 | | | 339 | expectOnlyOneCommitSelected(); |
| b69ab31 | | | 340 | }); |
| b69ab31 | | | 341 | |
| b69ab31 | | | 342 | it('multiple arrow keys keep modifying selection', () => { |
| b69ab31 | | | 343 | click('Commit A'); |
| b69ab31 | | | 344 | upArrow(); |
| b69ab31 | | | 345 | upArrow(); |
| b69ab31 | | | 346 | upArrow(); |
| b69ab31 | | | 347 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 348 | expectOnlyOneCommitSelected(); |
| b69ab31 | | | 349 | }); |
| b69ab31 | | | 350 | |
| b69ab31 | | | 351 | it('selection skips public commits', () => { |
| b69ab31 | | | 352 | click('Commit A'); |
| b69ab31 | | | 353 | upArrow(); // B |
| b69ab31 | | | 354 | upArrow(); // C |
| b69ab31 | | | 355 | upArrow(); // D |
| b69ab31 | | | 356 | upArrow(); // E |
| b69ab31 | | | 357 | upArrow(); // skip public base, go to X |
| b69ab31 | | | 358 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit X')).toBeInTheDocument(); |
| b69ab31 | | | 359 | expectOnlyOneCommitSelected(); |
| b69ab31 | | | 360 | }); |
| b69ab31 | | | 361 | |
| b69ab31 | | | 362 | it('goes from last selection if multiple are selected', () => { |
| b69ab31 | | | 363 | click('Commit A'); |
| b69ab31 | | | 364 | click('Commit C', {metaKey: true}); |
| b69ab31 | | | 365 | upArrow(); |
| b69ab31 | | | 366 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 367 | expectOnlyOneCommitSelected(); |
| b69ab31 | | | 368 | }); |
| b69ab31 | | | 369 | |
| b69ab31 | | | 370 | it('holding shift extends upwards', () => { |
| b69ab31 | | | 371 | click('Commit C'); |
| b69ab31 | | | 372 | upArrow(/* shift */ true); |
| b69ab31 | | | 373 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 374 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit D')).toBeInTheDocument(); |
| b69ab31 | | | 375 | expectNCommitsSelected(2); |
| b69ab31 | | | 376 | }); |
| b69ab31 | | | 377 | |
| b69ab31 | | | 378 | it('holding shift extends downwards', () => { |
| b69ab31 | | | 379 | click('Commit C'); |
| b69ab31 | | | 380 | downArrow(/* shift */ true); |
| b69ab31 | | | 381 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit C')).toBeInTheDocument(); |
| b69ab31 | | | 382 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit B')).toBeInTheDocument(); |
| b69ab31 | | | 383 | expectNCommitsSelected(2); |
| b69ab31 | | | 384 | }); |
| b69ab31 | | | 385 | |
| b69ab31 | | | 386 | it('right arrows opens sidebar', () => { |
| b69ab31 | | | 387 | click('Commit A'); |
| b69ab31 | | | 388 | act(() => closeCommitInfoSidebar()); |
| b69ab31 | | | 389 | |
| b69ab31 | | | 390 | expect(commitInfoIsOpen()).toEqual(false); |
| b69ab31 | | | 391 | rightArrow(); |
| b69ab31 | | | 392 | expect(CommitInfoTestUtils.withinCommitInfo().getByText('Commit A')).toBeInTheDocument(); |
| b69ab31 | | | 393 | expect(commitInfoIsOpen()).toEqual(true); |
| b69ab31 | | | 394 | }); |
| b69ab31 | | | 395 | }); |
| b69ab31 | | | 396 | }); |