5.9 KB198 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import {act, render, waitFor} from '@testing-library/react';
9import userEvent from '@testing-library/user-event';
10import * as utils from 'shared/utils';
11import App from '../../App';
12import {CommitInfoTestUtils, CommitTreeListTestUtils} from '../../testQueries';
13import {
14 COMMIT,
15 expectMessageSentToServer,
16 getLastMessageOfTypeSentToServer,
17 openCommitInfoSidebar,
18 resetTestMessages,
19 simulateCommits,
20 simulateMessageFromServer,
21 simulateUncommittedChangedFiles,
22} from '../../testUtils';
23
24describe('AmendMessageOperation', () => {
25 beforeEach(() => {
26 resetTestMessages();
27 render(<App />);
28 act(() => {
29 simulateMessageFromServer({
30 type: 'repoInfo',
31 info: {
32 type: 'success',
33 command: 'sl',
34 repoRoot: '/path/to/testrepo',
35 dotdir: '/path/to/testrepo/.sl',
36 codeReviewSystem: {type: 'unknown'},
37 pullRequestDomain: undefined,
38 preferredSubmitCommand: undefined,
39 isEdenFs: false,
40 },
41 });
42 expectMessageSentToServer({
43 type: 'subscribe',
44 kind: 'smartlogCommits',
45 subscriptionID: expect.anything(),
46 });
47 simulateUncommittedChangedFiles({
48 value: [
49 {path: 'file1.txt', status: 'M'},
50 {path: 'file2.txt', status: 'A'},
51 {path: 'file3.txt', status: 'R'},
52 ],
53 });
54 simulateCommits({
55 value: [
56 COMMIT('111111111111', 'Commit 1', '0', {phase: 'public'}),
57 COMMIT('aaaaaaaaaaaa', 'Commit A', '1'),
58 COMMIT('bbbbbbbbbbbb', 'Commit B', 'a', {isDot: true}),
59 COMMIT('cccccccccccc', 'Commit C', 'b'),
60 ],
61 });
62 });
63 });
64
65 it('on error, restores edited commit message to try again', async () => {
66 act(() => CommitInfoTestUtils.clickToSelectCommit('aaaaaaaaaaaa'));
67 act(() => openCommitInfoSidebar());
68 act(() => {
69 CommitInfoTestUtils.clickToEditTitle();
70 CommitInfoTestUtils.clickToEditDescription();
71 });
72 act(() => {
73 const title = CommitInfoTestUtils.getTitleEditor();
74 userEvent.type(title, 'My Commit');
75 const desc = CommitInfoTestUtils.getDescriptionEditor();
76 userEvent.type(desc, 'My description');
77 });
78
79 act(() => {
80 CommitInfoTestUtils.clickAmendMessageButton();
81 });
82 const message = await waitFor(() =>
83 utils.nullthrows(getLastMessageOfTypeSentToServer('runOperation')),
84 );
85 const id = message.operation.id;
86
87 CommitInfoTestUtils.expectIsNOTEditingTitle();
88
89 act(() => CommitInfoTestUtils.clickToSelectCommit('bbbbbbbbbbbb'));
90 expect(CommitInfoTestUtils.withinCommitInfo().getByText('You are here')).toBeInTheDocument();
91
92 act(() => {
93 simulateMessageFromServer({
94 type: 'operationProgress',
95 kind: 'exit',
96 exitCode: 1,
97 id,
98 timestamp: 0,
99 });
100 });
101
102 waitFor(() => {
103 expect(
104 CommitInfoTestUtils.withinCommitInfo().getByText('You are here'),
105 ).not.toBeInTheDocument();
106 CommitInfoTestUtils.expectIsEditingTitle();
107 const title = CommitInfoTestUtils.getTitleEditor();
108 expect(title).toHaveValue('My Commit');
109 CommitInfoTestUtils.expectIsEditingDescription();
110 const desc = CommitInfoTestUtils.getDescriptionEditor();
111 expect(desc).toHaveValue('My description');
112 });
113 });
114
115 it('if a previous command errors and metaedit is queued, the message is recovered', async () => {
116 await CommitTreeListTestUtils.clickGoto('cccccccccccc');
117 expectMessageSentToServer({
118 type: 'runOperation',
119 operation: expect.objectContaining({
120 args: expect.arrayContaining(['goto']),
121 }),
122 });
123 const gotoMessage = utils.nullthrows(getLastMessageOfTypeSentToServer('runOperation'));
124 const gotoId = gotoMessage.operation.id;
125
126 act(() => {
127 simulateMessageFromServer({
128 type: 'operationProgress',
129 kind: 'spawn',
130 id: gotoId,
131 queue: [],
132 });
133 });
134
135 // then queue a metaedit
136 act(() => CommitInfoTestUtils.clickToSelectCommit('aaaaaaaaaaaa'));
137 act(() => openCommitInfoSidebar());
138 act(() => {
139 CommitInfoTestUtils.clickToEditTitle();
140 CommitInfoTestUtils.clickToEditDescription();
141 });
142 act(() => {
143 const title = CommitInfoTestUtils.getTitleEditor();
144 userEvent.type(title, 'My Commit');
145 const desc = CommitInfoTestUtils.getDescriptionEditor();
146 userEvent.type(desc, 'My description');
147 });
148
149 act(() => {
150 CommitInfoTestUtils.clickAmendMessageButton();
151 });
152 await waitFor(() => {
153 expectMessageSentToServer({
154 type: 'runOperation',
155 operation: expect.objectContaining({
156 args: expect.arrayContaining(['metaedit']),
157 }),
158 });
159 });
160 const amendMessage = utils.nullthrows(getLastMessageOfTypeSentToServer('runOperation'));
161 const amendMessageId = amendMessage.operation.id;
162
163 act(() => {
164 simulateMessageFromServer({
165 type: 'operationProgress',
166 kind: 'queue',
167 id: amendMessageId,
168 queue: [amendMessageId],
169 });
170 });
171
172 CommitInfoTestUtils.expectIsNOTEditingTitle();
173
174 act(() => CommitInfoTestUtils.clickToSelectCommit('bbbbbbbbbbbb'));
175
176 // the goto fails
177 act(() => {
178 simulateMessageFromServer({
179 type: 'operationProgress',
180 kind: 'exit',
181 exitCode: 1,
182 id: gotoId,
183 timestamp: 0,
184 });
185 });
186
187 // we recover the message
188 await waitFor(() => {
189 CommitInfoTestUtils.expectIsEditingTitle();
190 const title = CommitInfoTestUtils.getTitleEditor();
191 expect(title).toHaveValue('Commit AMy Commit');
192 CommitInfoTestUtils.expectIsEditingDescription();
193 const desc = CommitInfoTestUtils.getDescriptionEditor();
194 expect(desc.value).toContain('My description');
195 });
196 });
197});
198