7.0 KB216 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, fireEvent, render, screen, waitFor, within} from '@testing-library/react';
9import userEvent from '@testing-library/user-event';
10import App from '../App';
11import platform from '../platform';
12import {CommitInfoTestUtils} from '../testQueries';
13import {
14 COMMIT,
15 expectMessageSentToServer,
16 openCommitInfoSidebar,
17 simulateCommits,
18 simulateMessageFromServer,
19} from '../testUtils';
20
21/* eslint-disable @typescript-eslint/no-non-null-assertion */
22
23const {
24 withinCommitInfo,
25 clickAmendMode,
26 clickCommitMode,
27 clickToSelectCommit,
28 getTitleEditor,
29 getDescriptionEditor,
30} = CommitInfoTestUtils;
31
32describe('FillCommitMessage', () => {
33 beforeEach(() => {
34 render(<App />);
35 act(() => {
36 openCommitInfoSidebar();
37 expectMessageSentToServer({
38 type: 'subscribe',
39 kind: 'smartlogCommits',
40 subscriptionID: expect.anything(),
41 });
42 simulateCommits({
43 value: [
44 COMMIT('1', 'some public base', '0', {phase: 'public'}),
45 COMMIT('a', 'My Commit', '1'),
46 COMMIT('b', 'Head Commit', 'a', {
47 isDot: true,
48 description: 'Summary: This is my commit message\n',
49 }),
50 ],
51 });
52 });
53 });
54
55 it('Shows fill message buttons in commit mode', () => {
56 clickCommitMode();
57 expect(screen.getByText('Fill commit message from', {exact: false})).toBeInTheDocument();
58 });
59
60 it('does not show fill buttons in amend mode', () => {
61 clickCommitMode();
62 clickToSelectCommit('a');
63 expect(screen.queryByText('Fill commit message from', {exact: false})).not.toBeInTheDocument();
64 clickToSelectCommit('b');
65 clickAmendMode();
66 expect(screen.queryByText('Fill commit message from', {exact: false})).not.toBeInTheDocument();
67 });
68
69 it('Load from last commit', async () => {
70 clickCommitMode();
71
72 expect(getTitleEditor()).toHaveValue('');
73 expect(getDescriptionEditor()).toHaveValue('');
74
75 const loadFromLastCommit = withinCommitInfo().getByText('last commit');
76 expect(loadFromLastCommit).toBeInTheDocument();
77 fireEvent.click(loadFromLastCommit);
78 await waitFor(() => {
79 expect(getTitleEditor().value).toMatch('Head Commit');
80 expect(getDescriptionEditor().value).toMatch(/This is my commit message/);
81 });
82 });
83
84 it('Load from commit template', async () => {
85 expectMessageSentToServer({type: 'fetchCommitMessageTemplate'});
86 act(() => {
87 simulateMessageFromServer({
88 type: 'fetchedCommitMessageTemplate',
89 template: 'template title\nSummary: template summary',
90 });
91 });
92 clickCommitMode();
93
94 // the template is used automatically, so let's clear it out
95 act(() => {
96 userEvent.clear(getTitleEditor());
97 userEvent.clear(getDescriptionEditor());
98 });
99
100 expect(getTitleEditor()).toHaveValue('');
101 expect(getDescriptionEditor()).toHaveValue('');
102
103 const loadFromLastCommit = withinCommitInfo().getByText('template file');
104 expect(loadFromLastCommit).toBeInTheDocument();
105 fireEvent.click(loadFromLastCommit);
106 await waitFor(() => {
107 expect(getTitleEditor().value).toMatch('template title');
108 expect(getDescriptionEditor().value).toMatch(/template summary/);
109 });
110 });
111
112 describe('conflicts in message to fill', () => {
113 async function triggerConflict() {
114 clickCommitMode();
115
116 act(() => {
117 userEvent.type(getTitleEditor(), 'existing title');
118 userEvent.type(getDescriptionEditor(), 'Summary: existing description');
119 });
120
121 const loadFromLastCommit = withinCommitInfo().getByText('last commit');
122 expect(loadFromLastCommit).toBeInTheDocument();
123 fireEvent.click(loadFromLastCommit);
124
125 await waitFor(() => {
126 expect(screen.getByText('Commit Messages Conflict')).toBeInTheDocument();
127 });
128 }
129
130 function withinConflictWarning() {
131 return within(screen.getByTestId('fill-message-conflict-warning'));
132 }
133
134 it('shows warning and differences', async () => {
135 await triggerConflict();
136
137 expect(withinConflictWarning().getByText('Title')).toBeInTheDocument();
138 expect(withinConflictWarning().getByText('existing title')).toBeInTheDocument();
139 expect(withinConflictWarning().getByText('Head Commit')).toBeInTheDocument();
140 expect(
141 withinConflictWarning().getByText('existing description', {exact: false}),
142 ).toBeInTheDocument();
143 expect(
144 withinConflictWarning().getByText('This is my commit message', {exact: false}),
145 ).toBeInTheDocument();
146 });
147
148 it('allows merging', async () => {
149 await triggerConflict();
150 const mergeButton = screen.getByText('Merge');
151 expect(mergeButton).toBeInTheDocument();
152 fireEvent.click(mergeButton);
153
154 await waitFor(() => {
155 expect(getTitleEditor().value).toMatch('existing title, Head Commit');
156 expect(getDescriptionEditor().value).toMatch(/existing description/);
157 expect(getDescriptionEditor().value).toMatch(/This is my commit message/);
158 });
159 });
160
161 it('allows merging non-empty', async () => {
162 await triggerConflict();
163 const mergeButton = screen.getByText('Only Fill Empty');
164 expect(mergeButton).toBeInTheDocument();
165 fireEvent.click(mergeButton);
166
167 await waitFor(() => {
168 expect(getTitleEditor().value).toMatch('existing title');
169 expect(getDescriptionEditor().value).toMatch(/existing description/);
170 expect(getDescriptionEditor().value).not.toMatch(/This is my commit message/);
171 });
172 });
173
174 it('allows cancelling', async () => {
175 await triggerConflict();
176 const cancelButton = screen.getByText('Cancel');
177 expect(cancelButton).toBeInTheDocument();
178 fireEvent.click(cancelButton);
179
180 expect(screen.queryByText('Commit Messages Conflict')).not.toBeInTheDocument();
181 await waitFor(() => {
182 expect(getTitleEditor().value).toMatch('existing title');
183 expect(getDescriptionEditor().value).toMatch(/existing description/);
184 });
185 });
186
187 it('allows overwriting', async () => {
188 await triggerConflict();
189 const overwrite = screen.getByText('Overwrite');
190 expect(overwrite).toBeInTheDocument();
191 fireEvent.click(overwrite);
192
193 await waitFor(() => {
194 expect(getTitleEditor().value).toMatch('Head Commit');
195 expect(getDescriptionEditor().value).toMatch(/This is my commit message/);
196 });
197 });
198 });
199
200 it('Clears commit message', async () => {
201 clickCommitMode();
202
203 expect(getTitleEditor()).toHaveValue('');
204 expect(getDescriptionEditor()).toHaveValue('');
205
206 const confirmSpy = jest
207 .spyOn(platform, 'confirm')
208 .mockImplementation(() => Promise.resolve(true));
209
210 fireEvent.click(screen.getByTestId('fill-commit-message-more-options'));
211 fireEvent.click(screen.getByText('Clear commit message'));
212
213 await waitFor(() => expect(confirmSpy).toHaveBeenCalled());
214 });
215});
216