1# frozen_string_literal: true
2
3require 'spec_helper'
4
5RSpec.describe 'Projects > Files > User edits files', :js do
6  include ProjectForksHelper
7  include BlobSpecHelpers
8
9  let(:project) { create(:project, :repository, name: 'Shop') }
10  let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
11  let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
12  let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) }
13  let(:user) { create(:user) }
14
15  before do
16    sign_in(user)
17  end
18
19  after do
20    unset_default_button
21  end
22
23  shared_examples 'unavailable for an archived project' do
24    it 'does not show the edit link for an archived project', :js do
25      project.update!(archived: true)
26      visit project_tree_path(project, project.repository.root_ref)
27
28      click_link('.gitignore')
29
30      aggregate_failures 'available edit buttons' do
31        expect(page).not_to have_text('Edit')
32        expect(page).not_to have_text('Web IDE')
33
34        expect(page).not_to have_text('Replace')
35        expect(page).not_to have_text('Delete')
36      end
37    end
38  end
39
40  context 'when an user has write access', :js do
41    before do
42      project.add_maintainer(user)
43      visit(project_tree_path_root_ref)
44      wait_for_requests
45    end
46
47    it 'inserts a content of a file' do
48      set_default_button('edit')
49      click_link('.gitignore')
50      click_link_or_button('Edit')
51      find('.file-editor', match: :first)
52
53      find('#editor')
54      set_editor_value('*.rbca')
55
56      expect(editor_value).to eq('*.rbca')
57    end
58
59    it 'does not show the edit link if a file is binary' do
60      binary_file = File.join(project.repository.root_ref, 'files/images/logo-black.png')
61      visit(project_blob_path(project, binary_file))
62      wait_for_requests
63
64      page.within '.content' do
65        expect(page).not_to have_link('edit')
66      end
67    end
68
69    it 'commits an edited file' do
70      set_default_button('edit')
71      click_link('.gitignore')
72      click_link_or_button('Edit')
73      find('.file-editor', match: :first)
74
75      find('#editor')
76      set_editor_value('*.rbca')
77      fill_in(:commit_message, with: 'New commit message', visible: true)
78      click_button('Commit changes')
79
80      expect(current_path).to eq(project_blob_path(project, 'master/.gitignore'))
81
82      wait_for_requests
83
84      expect(page).to have_content('*.rbca')
85    end
86
87    it 'commits an edited file to a new branch' do
88      set_default_button('edit')
89      click_link('.gitignore')
90      click_link_or_button('Edit')
91
92      find('.file-editor', match: :first)
93
94      find('#editor')
95      set_editor_value('*.rbca')
96      fill_in(:commit_message, with: 'New commit message', visible: true)
97      fill_in(:branch_name, with: 'new_branch_name', visible: true)
98      click_button('Commit changes')
99
100      expect(current_path).to eq(project_new_merge_request_path(project))
101
102      click_link('Changes')
103
104      expect(page).to have_content('*.rbca')
105    end
106
107    it 'shows the diff of an edited file' do
108      set_default_button('edit')
109      click_link('.gitignore')
110      click_link_or_button('Edit')
111      find('.file-editor', match: :first)
112
113      find('#editor')
114      set_editor_value('*.rbca')
115      click_link('Preview changes')
116
117      expect(page).to have_css('.line_holder.new')
118    end
119
120    it_behaves_like 'unavailable for an archived project'
121  end
122
123  context 'when an user does not have write access', :js do
124    before do
125      project2.add_reporter(user)
126      visit(project2_tree_path_root_ref)
127      wait_for_requests
128    end
129
130    def expect_fork_prompt
131      expect(page).to have_selector(:link_or_button, 'Fork')
132      expect(page).to have_selector(:link_or_button, 'Cancel')
133      expect(page).to have_content(
134        "You can’t edit files directly in this project. "\
135        "Fork this project and submit a merge request with your changes."
136      )
137    end
138
139    def expect_fork_status
140      expect(page).to have_content(
141        "You're not allowed to make changes to this project directly. "\
142        "A fork of this project has been created that you can make changes in, so you can submit a merge request."
143      )
144    end
145
146    it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do
147      set_default_button('edit')
148      click_link('.gitignore')
149      click_link_or_button('Edit')
150
151      expect_fork_prompt
152
153      click_link_or_button('Fork project')
154
155      expect_fork_status
156
157      find('.file-editor', match: :first)
158
159      find('#editor')
160      set_editor_value('*.rbca')
161
162      expect(editor_value).to eq('*.rbca')
163    end
164
165    it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do
166      set_default_button('webide')
167      click_link('.gitignore')
168      click_link_or_button('Web IDE')
169
170      expect_fork_prompt
171
172      click_link_or_button('Fork project')
173
174      expect_fork_status
175
176      expect(page).to have_css('.ide-sidebar-project-title', text: "#{project2.name} #{user.namespace.full_path}/#{project2.path}")
177      expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
178    end
179
180    it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do
181      set_default_button('edit')
182      click_link('.gitignore')
183      click_link_or_button('Edit')
184
185      expect_fork_prompt
186      click_link_or_button('Fork project')
187
188      find('.file-editor', match: :first)
189
190      find('#editor')
191      set_editor_value('*.rbca')
192      fill_in(:commit_message, with: 'New commit message', visible: true)
193      click_button('Commit changes')
194
195      fork = user.fork_of(project2.reload)
196
197      expect(current_path).to eq(project_new_merge_request_path(fork))
198
199      wait_for_requests
200
201      expect(page).to have_content('New commit message')
202    end
203
204    context 'when the user already had a fork of the project', :js do
205      let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) }
206
207      before do
208        visit(project2_tree_path_root_ref)
209        wait_for_requests
210      end
211
212      it 'links to the forked project for editing', :sidekiq_might_not_need_inline do
213        set_default_button('edit')
214        click_link('.gitignore')
215        click_link_or_button('Edit')
216
217        expect(page).not_to have_link('Fork project')
218
219        find('#editor')
220        set_editor_value('*.rbca')
221        fill_in(:commit_message, with: 'Another commit', visible: true)
222        click_button('Commit changes')
223
224        fork = user.fork_of(project2)
225
226        expect(current_path).to eq(project_new_merge_request_path(fork))
227
228        wait_for_requests
229
230        expect(page).to have_content('Another commit')
231        expect(page).to have_content("From #{forked_project.full_path}")
232        expect(page).to have_content("into #{project2.full_path}")
233      end
234
235      it_behaves_like 'unavailable for an archived project' do
236        let(:project) { project2 }
237      end
238    end
239
240    context 'when feature flag :consolidated_edit_button is off' do
241      before do
242        stub_feature_flags(consolidated_edit_button: false)
243      end
244
245      context 'when an user does not have write access', :js do
246        before do
247          project2.add_reporter(user)
248          visit(project2_tree_path_root_ref)
249          wait_for_requests
250        end
251
252        it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do
253          set_default_button('edit')
254          click_link('.gitignore')
255          click_link_or_button('Edit')
256
257          expect_fork_prompt
258
259          click_link_or_button('Fork')
260
261          expect_fork_status
262
263          find('.file-editor', match: :first)
264
265          find('#editor')
266          set_editor_value('*.rbca')
267
268          expect(editor_value).to eq('*.rbca')
269        end
270
271        it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do
272          set_default_button('webide')
273          click_link('.gitignore')
274          click_link_or_button('Web IDE')
275
276          expect_fork_prompt
277
278          click_link_or_button('Fork')
279
280          expect_fork_status
281
282          expect(page).to have_css('.ide-sidebar-project-title', text: "#{project2.name} #{user.namespace.full_path}/#{project2.path}")
283          expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
284        end
285
286        it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do
287          set_default_button('edit')
288          click_link('.gitignore')
289          click_link_or_button('Edit')
290
291          expect_fork_prompt
292
293          click_link_or_button('Fork')
294
295          expect_fork_status
296
297          find('.file-editor', match: :first)
298
299          find('#editor')
300          set_editor_value('*.rbca')
301          fill_in(:commit_message, with: 'New commit message', visible: true)
302          click_button('Commit changes')
303
304          fork = user.fork_of(project2.reload)
305
306          expect(current_path).to eq(project_new_merge_request_path(fork))
307
308          wait_for_requests
309
310          expect(page).to have_content('New commit message')
311        end
312
313        context 'when the user already had a fork of the project', :js do
314          let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) }
315
316          before do
317            visit(project2_tree_path_root_ref)
318            wait_for_requests
319          end
320
321          it 'links to the forked project for editing', :sidekiq_might_not_need_inline do
322            set_default_button('edit')
323            click_link('.gitignore')
324            click_link_or_button('Edit')
325
326            expect(page).not_to have_link('Fork')
327
328            find('#editor')
329            set_editor_value('*.rbca')
330            fill_in(:commit_message, with: 'Another commit', visible: true)
331            click_button('Commit changes')
332
333            fork = user.fork_of(project2)
334
335            expect(current_path).to eq(project_new_merge_request_path(fork))
336
337            wait_for_requests
338
339            expect(page).to have_content('Another commit')
340            expect(page).to have_content("From #{forked_project.full_path}")
341            expect(page).to have_content("into #{project2.full_path}")
342          end
343
344          it_behaves_like 'unavailable for an archived project' do
345            let(:project) { project2 }
346          end
347        end
348      end
349    end
350  end
351end
352