addons/isl/src/__tests__/operations/commitOperation.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 {act, fireEvent, render, screen, waitFor, within} from '@testing-library/react';
b69ab319import userEvent from '@testing-library/user-event';
b69ab3110import * as utils from 'shared/utils';
b69ab3111import App from '../../App';
b69ab3112import {CommitInfoTestUtils} from '../../testQueries';
b69ab3113import {
b69ab3114 COMMIT,
b69ab3115 expectMessageSentToServer,
b69ab3116 getLastMessageOfTypeSentToServer,
b69ab3117 openCommitInfoSidebar,
b69ab3118 resetTestMessages,
b69ab3119 simulateCommits,
b69ab3120 simulateMessageFromServer,
b69ab3121 simulateUncommittedChangedFiles,
b69ab3122} from '../../testUtils';
b69ab3123import {CommandRunner} from '../../types';
b69ab3124
b69ab3125describe('CommitOperation', () => {
b69ab3126 beforeEach(() => {
b69ab3127 resetTestMessages();
b69ab3128 render(<App />);
b69ab3129 act(() => {
b69ab3130 expectMessageSentToServer({
b69ab3131 type: 'subscribe',
b69ab3132 kind: 'smartlogCommits',
b69ab3133 subscriptionID: expect.anything(),
b69ab3134 });
b69ab3135 simulateUncommittedChangedFiles({
b69ab3136 value: [
b69ab3137 {path: 'file1.txt', status: 'M'},
b69ab3138 {path: 'file2.txt', status: 'A'},
b69ab3139 {path: 'file3.txt', status: 'R'},
b69ab3140 ],
b69ab3141 });
b69ab3142 simulateCommits({
b69ab3143 value: [
b69ab3144 COMMIT('2', 'master', '00', {phase: 'public', remoteBookmarks: ['remote/master']}),
b69ab3145 COMMIT('1', 'Commit 1', '0', {phase: 'public'}),
b69ab3146 COMMIT('a', 'Commit A', '1'),
b69ab3147 COMMIT('b', 'Commit B', 'a', {isDot: true}),
b69ab3148 ],
b69ab3149 });
b69ab3150 });
b69ab3151 });
b69ab3152
b69ab3153 const clickQuickCommit = async () => {
b69ab3154 const quickCommitButton = screen.getByTestId('quick-commit-button');
b69ab3155 act(() => {
b69ab3156 fireEvent.click(quickCommitButton);
b69ab3157 });
b69ab3158 await waitFor(() =>
b69ab3159 expectMessageSentToServer({
b69ab3160 type: 'runOperation',
b69ab3161 operation: expect.objectContaining({
b69ab3162 args: expect.arrayContaining(['commit']),
b69ab3163 }),
b69ab3164 }),
b69ab3165 );
b69ab3166 };
b69ab3167
b69ab3168 const clickCheckboxForFile = (inside: HTMLElement, fileName: string) => {
b69ab3169 act(() => {
b69ab3170 const checkbox = within(within(inside).getByTestId(`changed-file-${fileName}`)).getByTestId(
b69ab3171 'file-selection-checkbox',
b69ab3172 );
b69ab3173 expect(checkbox).toBeInTheDocument();
b69ab3174 fireEvent.click(checkbox);
b69ab3175 });
b69ab3176 };
b69ab3177
b69ab3178 it('runs commit', async () => {
b69ab3179 await clickQuickCommit();
b69ab3180
b69ab3181 expectMessageSentToServer({
b69ab3182 type: 'runOperation',
b69ab3183 operation: {
b69ab3184 args: [
b69ab3185 'commit',
b69ab3186 '--addremove',
b69ab3187 '--message',
b69ab3188 expect.stringContaining(`Temporary Commit at`),
b69ab3189 ],
b69ab3190 id: expect.anything(),
b69ab3191 runner: CommandRunner.Sapling,
b69ab3192 trackEventName: 'CommitOperation',
b69ab3193 },
b69ab3194 });
b69ab3195 });
b69ab3196
b69ab3197 it('runs commit with subset of files selected', async () => {
b69ab3198 const commitTree = screen.getByTestId('commit-tree-root');
b69ab3199 clickCheckboxForFile(commitTree, 'file2.txt');
b69ab31100
b69ab31101 await clickQuickCommit();
b69ab31102
b69ab31103 expectMessageSentToServer({
b69ab31104 type: 'runOperation',
b69ab31105 operation: {
b69ab31106 args: [
b69ab31107 'commit',
b69ab31108 '--addremove',
b69ab31109 '--message',
b69ab31110 expect.stringContaining(`Temporary Commit at`),
b69ab31111 {type: 'repo-relative-file', path: 'file1.txt'},
b69ab31112 {type: 'repo-relative-file', path: 'file3.txt'},
b69ab31113 ],
b69ab31114 id: expect.anything(),
b69ab31115 runner: CommandRunner.Sapling,
b69ab31116 trackEventName: 'CommitFileSubsetOperation',
b69ab31117 },
b69ab31118 });
b69ab31119 });
b69ab31120
b69ab31121 it('changed files are shown in commit info view', async () => {
b69ab31122 const commitTree = screen.getByTestId('commit-tree-root');
b69ab31123 clickCheckboxForFile(commitTree, 'file2.txt');
b69ab31124
b69ab31125 const quickInput = screen.getByTestId('quick-commit-title');
b69ab31126
b69ab31127 act(() => {
b69ab31128 userEvent.type(quickInput, 'My Commit');
b69ab31129 });
b69ab31130
b69ab31131 await clickQuickCommit();
b69ab31132
b69ab31133 expect(
b69ab31134 within(screen.getByTestId('changes-to-amend')).queryByText(/file1.txt/),
b69ab31135 ).not.toBeInTheDocument();
b69ab31136 expect(
b69ab31137 within(screen.getByTestId('changes-to-amend')).getByText(/file2.txt/),
b69ab31138 ).toBeInTheDocument();
b69ab31139 expect(
b69ab31140 within(screen.getByTestId('changes-to-amend')).queryByText(/file3.txt/),
b69ab31141 ).not.toBeInTheDocument();
b69ab31142
b69ab31143 expect(
b69ab31144 within(screen.getByTestId('committed-changes')).getByText(/file1.txt/),
b69ab31145 ).toBeInTheDocument();
b69ab31146 expect(
b69ab31147 within(screen.getByTestId('committed-changes')).queryByText(/file2.txt/),
b69ab31148 ).not.toBeInTheDocument();
b69ab31149 expect(
b69ab31150 within(screen.getByTestId('committed-changes')).getByText(/file3.txt/),
b69ab31151 ).toBeInTheDocument();
b69ab31152 });
b69ab31153
b69ab31154 it('uses commit template if provided', async () => {
b69ab31155 await waitFor(() => {
b69ab31156 expectMessageSentToServer({type: 'fetchCommitMessageTemplate'});
b69ab31157 });
b69ab31158 act(() => {
b69ab31159 simulateMessageFromServer({
b69ab31160 type: 'fetchedCommitMessageTemplate',
b69ab31161 template: 'Template Title\n\nSummary: my template',
b69ab31162 });
b69ab31163 });
b69ab31164
b69ab31165 await clickQuickCommit();
b69ab31166
b69ab31167 expectMessageSentToServer({
b69ab31168 type: 'runOperation',
b69ab31169 operation: {
b69ab31170 args: ['commit', '--addremove', '--message', expect.stringContaining('Template Title')],
b69ab31171 id: expect.anything(),
b69ab31172 runner: CommandRunner.Sapling,
b69ab31173 trackEventName: 'CommitOperation',
b69ab31174 },
b69ab31175 });
b69ab31176 });
b69ab31177
b69ab31178 it('clears quick commit title after committing', async () => {
b69ab31179 const commitTree = screen.getByTestId('commit-tree-root');
b69ab31180 clickCheckboxForFile(commitTree, 'file2.txt'); // partial commit, so the quick input box isn't unmounted
b69ab31181
b69ab31182 const quickInput = screen.getByTestId('quick-commit-title');
b69ab31183 act(() => {
b69ab31184 userEvent.type(quickInput, 'My Commit');
b69ab31185 });
b69ab31186
b69ab31187 await clickQuickCommit();
b69ab31188
b69ab31189 expect(quickInput).toHaveValue('');
b69ab31190 });
b69ab31191
b69ab31192 it('on error, restores edited commit message to try again', async () => {
b69ab31193 act(() => openCommitInfoSidebar());
b69ab31194 act(() => CommitInfoTestUtils.clickCommitMode());
b69ab31195
b69ab31196 act(() => {
b69ab31197 const title = CommitInfoTestUtils.getTitleEditor();
b69ab31198 userEvent.type(title, 'My Commit');
b69ab31199 const desc = CommitInfoTestUtils.getDescriptionEditor();
b69ab31200 userEvent.type(desc, 'My description');
b69ab31201 });
b69ab31202
b69ab31203 await CommitInfoTestUtils.clickCommitButton();
b69ab31204 const message = await waitFor(() =>
b69ab31205 utils.nullthrows(getLastMessageOfTypeSentToServer('runOperation')),
b69ab31206 );
b69ab31207 const id = message.operation.id;
b69ab31208
b69ab31209 CommitInfoTestUtils.expectIsNOTEditingTitle();
b69ab31210
b69ab31211 act(() => {
b69ab31212 simulateMessageFromServer({
b69ab31213 type: 'operationProgress',
b69ab31214 kind: 'exit',
b69ab31215 exitCode: 1,
b69ab31216 id,
b69ab31217 timestamp: 0,
b69ab31218 });
b69ab31219 });
b69ab31220
b69ab31221 await waitFor(() => {
b69ab31222 CommitInfoTestUtils.expectIsEditingTitle();
b69ab31223 const title = CommitInfoTestUtils.getTitleEditor();
b69ab31224 expect(title).toHaveValue('My Commit');
b69ab31225 CommitInfoTestUtils.expectIsEditingDescription();
b69ab31226 const desc = CommitInfoTestUtils.getDescriptionEditor();
b69ab31227 expect(desc.value).toContain('My description');
b69ab31228 });
b69ab31229 });
b69ab31230
b69ab31231 it('on error, merges messages when restoring edited commit message to try again', async () => {
b69ab31232 act(() => openCommitInfoSidebar());
b69ab31233 act(() => CommitInfoTestUtils.clickCommitMode());
b69ab31234
b69ab31235 act(() => {
b69ab31236 const title = CommitInfoTestUtils.getTitleEditor();
b69ab31237 userEvent.type(title, 'My Commit');
b69ab31238 const desc = CommitInfoTestUtils.getDescriptionEditor();
b69ab31239 userEvent.type(desc, 'My description');
b69ab31240 });
b69ab31241
b69ab31242 await CommitInfoTestUtils.clickCommitButton();
b69ab31243 const message = await waitFor(() =>
b69ab31244 utils.nullthrows(getLastMessageOfTypeSentToServer('runOperation')),
b69ab31245 );
b69ab31246 const id = message.operation.id;
b69ab31247
b69ab31248 CommitInfoTestUtils.expectIsNOTEditingTitle();
b69ab31249
b69ab31250 act(() => {
b69ab31251 openCommitInfoSidebar();
b69ab31252 CommitInfoTestUtils.clickCommitMode();
b69ab31253 });
b69ab31254 act(() => {
b69ab31255 const title = CommitInfoTestUtils.getTitleEditor();
b69ab31256 userEvent.type(title, 'other title');
b69ab31257 const desc = CommitInfoTestUtils.getDescriptionEditor();
b69ab31258 userEvent.type(desc, 'other description');
b69ab31259 });
b69ab31260
b69ab31261 act(() => {
b69ab31262 simulateMessageFromServer({
b69ab31263 type: 'operationProgress',
b69ab31264 kind: 'exit',
b69ab31265 exitCode: 1,
b69ab31266 id,
b69ab31267 timestamp: 0,
b69ab31268 });
b69ab31269 });
b69ab31270
b69ab31271 await waitFor(() => {
b69ab31272 CommitInfoTestUtils.expectIsEditingTitle();
b69ab31273 const title = CommitInfoTestUtils.getTitleEditor();
b69ab31274 expect(title).toHaveValue('other title, My Commit');
b69ab31275 CommitInfoTestUtils.expectIsEditingDescription();
b69ab31276 const desc = CommitInfoTestUtils.getDescriptionEditor();
b69ab31277 expect(desc.value).toContain('other description');
b69ab31278 expect(desc.value).toContain('My description');
b69ab31279 });
b69ab31280 });
b69ab31281});