addons/isl/src/__tests__/operations/checkoutOperation.test.tsxblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import type {Hash} from '../../types';
b69ab319
b69ab3110import {act, fireEvent, render, screen} from '@testing-library/react';
b69ab3111import {nextTick} from 'shared/testUtils';
b69ab3112import App from '../../App';
b69ab3113import platform from '../../platform';
b69ab3114import {
b69ab3115 COMMIT,
b69ab3116 closeCommitInfoSidebar,
b69ab3117 expectMessageNOTSentToServer,
b69ab3118 expectMessageSentToServer,
b69ab3119 expectYouAreHerePointAt,
b69ab3120 resetTestMessages,
b69ab3121 simulateCommits,
b69ab3122} from '../../testUtils';
b69ab3123import {CommandRunner, succeedableRevset} from '../../types';
b69ab3124
b69ab3125describe('GotoOperation', () => {
b69ab3126 beforeEach(() => {
b69ab3127 resetTestMessages();
b69ab3128 render(<App />);
b69ab3129 act(() => {
b69ab3130 closeCommitInfoSidebar();
b69ab3131 expectMessageSentToServer({
b69ab3132 type: 'subscribe',
b69ab3133 kind: 'smartlogCommits',
b69ab3134 subscriptionID: expect.anything(),
b69ab3135 });
b69ab3136 simulateCommits({
b69ab3137 value: [
b69ab3138 COMMIT('2', 'master', '00', {phase: 'public', remoteBookmarks: ['remote/master']}),
b69ab3139 COMMIT('1', 'Commit 1', '0', {phase: 'public'}),
b69ab3140 COMMIT('a', 'Commit A', '1'),
b69ab3141 COMMIT('b', 'Commit B', 'a', {isDot: true}),
b69ab3142 COMMIT('c', 'Commit C', 'b'),
b69ab3143 ],
b69ab3144 });
b69ab3145 });
b69ab3146 });
b69ab3147
b69ab3148 const clickGoto = async (commit: Hash) => {
b69ab3149 const myCommit = screen.queryByTestId(`commit-${commit}`);
b69ab3150 const gotoButton = myCommit?.querySelector('.goto-button button');
b69ab3151 expect(gotoButton).toBeDefined();
b69ab3152 await act(async () => {
b69ab3153 fireEvent.click(gotoButton as Element);
b69ab3154 await nextTick(); // async check if commit is too old
b69ab3155 });
b69ab3156 };
b69ab3157
b69ab3158 it('goto button is accessible', () => {
b69ab3159 expect(screen.getByLabelText('Go to commit "Commit A"')).toBeInTheDocument();
b69ab3160 expect(screen.queryByLabelText('Go to commit "Commit B"')).not.toBeInTheDocument(); // already head, no goto button
b69ab3161 expect(screen.getByLabelText('Go to commit "Commit C"')).toBeInTheDocument();
b69ab3162 });
b69ab3163
b69ab3164 it('runs goto', async () => {
b69ab3165 await clickGoto('a');
b69ab3166
b69ab3167 expectMessageSentToServer({
b69ab3168 type: 'runOperation',
b69ab3169 operation: {
b69ab3170 args: ['goto', '--rev', succeedableRevset('a')],
b69ab3171 id: expect.anything(),
b69ab3172 runner: CommandRunner.Sapling,
b69ab3173 trackEventName: 'GotoOperation',
b69ab3174 },
b69ab3175 });
b69ab3176 });
b69ab3177
b69ab3178 it('renders optimistic state while running', async () => {
b69ab3179 await clickGoto('a');
b69ab3180
b69ab3181 expectYouAreHerePointAt('a');
b69ab3182 });
b69ab3183
b69ab3184 it('optimistic state resolves after goto completes', async () => {
b69ab3185 await clickGoto('a');
b69ab3186
b69ab3187 act(() => {
b69ab3188 simulateCommits({
b69ab3189 value: [
b69ab3190 COMMIT('1', 'Commit 1', '0', {phase: 'public'}),
b69ab3191 COMMIT('a', 'Commit A', '1', {isDot: true}),
b69ab3192 COMMIT('b', 'Commit B', 'a'),
b69ab3193 COMMIT('c', 'Commit C', 'b'),
b69ab3194 ],
b69ab3195 });
b69ab3196 });
b69ab3197
b69ab3198 // With the DAG renderer, we no longer show old "were here" and new "moving here".
b69ab3199 // The idea is that there would be a spinner on the "status" calculation to indicate
b69ab31100 // the in-progress checkout. For now this test looks the same as the above.
b69ab31101 expectYouAreHerePointAt('a');
b69ab31102 });
b69ab31103
b69ab31104 describe('bookmarks as destinations', () => {
b69ab31105 it('runs goto with bookmark', async () => {
b69ab31106 await clickGoto('2');
b69ab31107
b69ab31108 expectMessageSentToServer({
b69ab31109 type: 'runOperation',
b69ab31110 operation: {
b69ab31111 args: ['goto', '--rev', succeedableRevset('remote/master')],
b69ab31112 id: expect.anything(),
b69ab31113 runner: CommandRunner.Sapling,
b69ab31114 trackEventName: 'GotoOperation',
b69ab31115 },
b69ab31116 });
b69ab31117 });
b69ab31118
b69ab31119 it('renders optimistic state while running', async () => {
b69ab31120 await clickGoto('2');
b69ab31121
b69ab31122 expectYouAreHerePointAt('2');
b69ab31123 });
b69ab31124 });
b69ab31125
b69ab31126 describe('succession', () => {
b69ab31127 it('handles successions', async () => {
b69ab31128 await clickGoto('c');
b69ab31129
b69ab31130 // get a new batch of commits from some other operation like rebase, which
b69ab31131 // rewrites a,b,c into a1,b2,c2
b69ab31132 act(() => {
b69ab31133 simulateCommits({
b69ab31134 value: [
b69ab31135 COMMIT('2', 'master', '00', {phase: 'public', remoteBookmarks: ['remote/master']}),
b69ab31136 COMMIT('1', 'Commit 1', '0', {phase: 'public'}),
b69ab31137 COMMIT('a2', 'Commit A', '1', {closestPredecessors: ['a']}),
b69ab31138 COMMIT('b2', 'Commit B', 'a2', {isDot: true, closestPredecessors: ['b']}),
b69ab31139 COMMIT('c2', 'Commit C', 'b2', {closestPredecessors: ['c']}),
b69ab31140 ],
b69ab31141 });
b69ab31142 });
b69ab31143
b69ab31144 // "c" becomes "c2"
b69ab31145 expectYouAreHerePointAt('c2');
b69ab31146 });
b69ab31147 });
b69ab31148
b69ab31149 describe('age warning', () => {
b69ab31150 let confirmSpy: jest.SpyInstance;
b69ab31151 beforeEach(() => {
b69ab31152 confirmSpy = jest.spyOn(platform, 'confirm').mockImplementation(() => Promise.resolve(true));
b69ab31153 act(() => {
b69ab31154 simulateCommits({
b69ab31155 value: [
b69ab31156 COMMIT('b', 'Commit B', 'a', {isDot: true, date: new Date('2024-03-04')}),
b69ab31157 COMMIT('a', 'Commit A', '3', {date: new Date('2024-03-03')}),
b69ab31158 COMMIT('3', 'Commit 3', '003', {phase: 'public', date: new Date('2024-03-02')}),
b69ab31159 COMMIT('2', 'Commit 2', '002', {phase: 'public', date: new Date('2024-03-01')}),
b69ab31160 COMMIT('x', 'Commit X', '1', {date: new Date('2024-03-03')}),
b69ab31161 COMMIT('1', 'Commit 1', '001', {phase: 'public', date: new Date('2020-01-01')}),
b69ab31162 ],
b69ab31163 });
b69ab31164 });
b69ab31165 });
b69ab31166
b69ab31167 it('warns if going to an old commit', async () => {
b69ab31168 await clickGoto('1');
b69ab31169 expect(confirmSpy).toHaveBeenCalled();
b69ab31170 });
b69ab31171
b69ab31172 it("cancels goto if you don't confirm", async () => {
b69ab31173 confirmSpy = jest.spyOn(platform, 'confirm').mockImplementation(() => Promise.resolve(false));
b69ab31174 await clickGoto('1');
b69ab31175 expect(confirmSpy).toHaveBeenCalled();
b69ab31176 expectMessageNOTSentToServer({
b69ab31177 type: 'runOperation',
b69ab31178 operation: expect.objectContaining({
b69ab31179 args: expect.arrayContaining(['goto']),
b69ab31180 }),
b69ab31181 });
b69ab31182 });
b69ab31183
b69ab31184 it('does not warn for short goto', async () => {
b69ab31185 await clickGoto('a');
b69ab31186 expect(confirmSpy).not.toHaveBeenCalled();
b69ab31187 });
b69ab31188
b69ab31189 it('compares base public commit, not destination itself', async () => {
b69ab31190 await clickGoto('x'); // x is only 1 day old, but its parent is months older than b's public base.
b69ab31191 expect(confirmSpy).toHaveBeenCalled();
b69ab31192 });
b69ab31193
b69ab31194 it('only warns going backwards, not forwards', async () => {
b69ab31195 act(() => {
b69ab31196 simulateCommits({
b69ab31197 value: [
b69ab31198 COMMIT('b', 'Commit B', 'a', {date: new Date('2024-03-04')}),
b69ab31199 COMMIT('a', 'Commit A', '3', {date: new Date('2024-03-03')}),
b69ab31200 COMMIT('3', 'Commit 3', '003', {phase: 'public', date: new Date('2024-03-02')}),
b69ab31201 COMMIT('2', 'Commit 2', '002', {phase: 'public', date: new Date('2024-03-01')}),
b69ab31202 COMMIT('x', 'Commit X', '1', {isDot: true, date: new Date('2024-03-03')}),
b69ab31203 COMMIT('1', 'Commit 1', '001', {phase: 'public', date: new Date('2020-01-01')}),
b69ab31204 ],
b69ab31205 });
b69ab31206 });
b69ab31207 await clickGoto('b');
b69ab31208 expect(confirmSpy).not.toHaveBeenCalled();
b69ab31209 });
b69ab31210 });
b69ab31211});