Add tests for discarding

Summary:
I noticed we had no tests for some cases here, namely:
- deleting an untracked file
- bulk discarding all files
- bulk discarding a subset of files

This is stuff affected by the commits earlier in this stack, so let's add tests for this moving forward

Reviewed By: quark-zju

Differential Revision: D49617784

fbshipit-source-id: 2107c4f5e7481d14bbbcfcae322c9d8c989e5455
This commit is contained in:
Evan Krause 2023-09-27 13:30:34 -07:00 committed by Facebook GitHub Bot
parent 6208ef0e0b
commit a2a0a06e35
2 changed files with 185 additions and 1 deletions

View File

@ -465,6 +465,7 @@ function FileSelectionCheckbox({
<VSCodeCheckbox
checked={selection.isFullyOrPartiallySelected(file.path)}
indeterminate={selection.isPartiallySelected(file.path)}
data-testid={'file-selection-checkbox'}
// Note: Using `onClick` instead of `onChange` since onChange apparently fires when the controlled `checked` value changes,
// which means this fires when using "select all" / "deselect all"
onClick={e => {
@ -656,6 +657,7 @@ export function UncommittedChanges({place}: {place: Place}) {
<VSCodeButton
appearance="icon"
disabled={noFilesSelected}
data-testid={'discard-all-selected-button'}
onClick={() => {
platform.confirm(t('confirmDiscardChanges')).then(ok => {
if (!ok) {
@ -967,6 +969,7 @@ function FileActions({
className="file-show-on-hover"
key={file.path}
appearance="icon"
data-testid="file-action-delete"
onClick={async () => {
const ok = await platform.confirm(
t('Are you sure you want to delete $file?', {replace: {$file: file.path}}),

View File

@ -14,12 +14,15 @@ import {
simulateCommits,
COMMIT,
simulateUncommittedChangedFiles,
expectMessageNOTSentToServer,
} from '../../testUtils';
import {CommandRunner} from '../../types';
import {fireEvent, render, screen, within} from '@testing-library/react';
import {act} from 'react-dom/test-utils';
import {nextTick} from 'shared/testUtils';
/* eslint-disable require-await */
jest.mock('../../MessageBus');
describe('RevertOperation', () => {
@ -61,6 +64,28 @@ describe('RevertOperation', () => {
});
};
const clickDelete = async (inside: HTMLElement, fileName: string) => {
await act(async () => {
const revertButton = within(
within(inside).getByTestId(`changed-file-${fileName}`),
).getByTestId('file-action-delete');
expect(revertButton).toBeInTheDocument();
fireEvent.click(revertButton);
// confirm modal takes 1 tick to resolve
await nextTick();
});
};
const clickCheckboxForFile = async (inside: HTMLElement, fileName: string) => {
await act(async () => {
const checkbox = within(within(inside).getByTestId(`changed-file-${fileName}`)).getByTestId(
'file-selection-checkbox',
);
expect(checkbox).toBeInTheDocument();
fireEvent.click(checkbox);
});
};
describe('from uncommitted changes', () => {
beforeEach(() => {
act(() => {
@ -87,7 +112,7 @@ describe('RevertOperation', () => {
});
});
it('renders optimistic state while running', async () => {
it('renders optimistic state while running revert', async () => {
expect(
CommitTreeListTestUtils.withinCommitTree().getByText(ignoreRTL('myFile1.txt')),
).toBeInTheDocument();
@ -96,6 +121,162 @@ describe('RevertOperation', () => {
CommitTreeListTestUtils.withinCommitTree().queryByText(ignoreRTL('myFile1.txt')),
).not.toBeInTheDocument();
});
describe('untracked files get purged', () => {
beforeEach(() => {
act(() => {
simulateUncommittedChangedFiles({
value: [
{path: 'myFile1.txt', status: 'M'},
{path: 'untracked.txt', status: '?'},
],
});
});
});
it('runs purge for untracked uncommitted changes', async () => {
await clickDelete(screen.getByTestId('commit-tree-root'), 'untracked.txt');
expectMessageSentToServer({
type: 'runOperation',
operation: {
args: ['purge', '--files', {type: 'repo-relative-file', path: 'untracked.txt'}],
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: 'PurgeOperation',
},
});
});
it('renders optimistic state while running purge', async () => {
expect(
CommitTreeListTestUtils.withinCommitTree().getByText(ignoreRTL('untracked.txt')),
).toBeInTheDocument();
await clickDelete(screen.getByTestId('commit-tree-root'), 'untracked.txt');
expect(
CommitTreeListTestUtils.withinCommitTree().queryByText(ignoreRTL('untracked.txt')),
).not.toBeInTheDocument();
});
});
});
describe('bulk discard', () => {
let confirmSpy: jest.SpyInstance;
beforeEach(() => {
confirmSpy = jest.spyOn(platform, 'confirm').mockImplementation(() => Promise.resolve(true));
act(() => {
simulateUncommittedChangedFiles({
value: [
{path: 'myFile1.txt', status: 'M'},
{path: 'myFile2.txt', status: 'M'},
{path: 'untracked1.txt', status: '?'},
{path: 'untracked2.txt', status: '?'},
],
});
});
});
it('discards all changes with goto --clean if everything selected', async () => {
await act(async () => {
fireEvent.click(
within(screen.getByTestId('commit-tree-root')).getByTestId('discard-all-selected-button'),
);
});
expectMessageSentToServer({
type: 'runOperation',
operation: {
args: ['goto', '--clean', '.'],
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: 'DiscardOperation',
},
});
expectMessageSentToServer({
type: 'runOperation',
operation: {
args: ['purge', '--files'],
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: 'PurgeOperation',
},
});
expect(confirmSpy).toHaveBeenCalled();
});
it('discards selected changes with revert and purge', async () => {
const commitTree = screen.getByTestId('commit-tree-root');
await clickCheckboxForFile(commitTree, 'myFile1.txt');
await clickCheckboxForFile(commitTree, 'untracked1.txt');
await act(async () => {
fireEvent.click(
within(screen.getByTestId('commit-tree-root')).getByTestId('discard-all-selected-button'),
);
});
expectMessageSentToServer({
type: 'runOperation',
operation: {
args: ['revert', {type: 'repo-relative-file', path: 'myFile2.txt'}],
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: 'RevertOperation',
},
});
expectMessageSentToServer({
type: 'runOperation',
operation: {
args: ['purge', '--files', {type: 'repo-relative-file', path: 'untracked2.txt'}],
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: 'PurgeOperation',
},
});
expect(confirmSpy).toHaveBeenCalled();
});
it('no need to run purge if no files are untracked', async () => {
const commitTree = screen.getByTestId('commit-tree-root');
await clickCheckboxForFile(commitTree, 'untracked1.txt');
await clickCheckboxForFile(commitTree, 'untracked2.txt');
await act(async () => {
fireEvent.click(
within(screen.getByTestId('commit-tree-root')).getByTestId('discard-all-selected-button'),
);
});
expectMessageSentToServer({
type: 'runOperation',
operation: {
args: [
'revert',
{type: 'repo-relative-file', path: 'myFile1.txt'},
{type: 'repo-relative-file', path: 'myFile2.txt'},
],
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: 'RevertOperation',
},
});
expectMessageNOTSentToServer({
type: 'runOperation',
operation: {
args: expect.arrayContaining(['purge', '--files']),
id: expect.anything(),
runner: CommandRunner.Sapling,
trackEventName: expect.anything(),
},
});
expect(confirmSpy).toHaveBeenCalled();
});
});
describe('in commit info view for a given commit', () => {