projects_spec.rb 10.9 KB
Newer Older
gitlabhq's avatar
gitlabhq committed
1 2
require 'spec_helper'

3
describe 'Project' do
4
  include ProjectForksHelper
5
  include MobileHelpers
6

7 8 9 10
  before do
    stub_feature_flags(approval_rules: false)
  end

11
  describe 'creating from template' do
12
    let(:user) { create(:user) }
13 14 15 16 17 18 19
    let(:template) { Gitlab::ProjectTemplate.find(:rails) }

    before do
      sign_in user
      visit new_project_path
    end

20
    it "allows creation from templates", :js do
21
      find('#create-from-template-tab').click
22
      find("label[for=#{template.name}]").click
23
      fill_in("project_name", with: template.name)
24 25 26 27 28

      page.within '#content-body' do
        click_button "Create project"
      end

29
      expect(page).to have_content template.name
30 31 32
    end
  end

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
  describe 'shows tip about push to create git command' do
    let(:user)    { create(:user) }

    before do
      sign_in user
      visit new_project_path
    end

    it 'shows the command in a popover', :js do
      page.within '.profile-settings-sidebar' do
        click_link 'Show command'
      end

      expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip')
      expect(page).to have_content 'Private projects can be created in your personal namespace with:'
    end
  end

51
  describe 'description' do
52
    let(:project) { create(:project, :repository) }
53
    let(:path)    { project_path(project) }
gitlabhq's avatar
gitlabhq committed
54

randx's avatar
randx committed
55
    before do
56
      sign_in(create(:admin))
randx's avatar
randx committed
57 58
    end

59 60 61
    it 'parses Markdown' do
      project.update_attribute(:description, 'This is **my** project')
      visit path
62
      expect(page).to have_css('.home-panel-description > .home-panel-description-markdown > p > strong')
63 64 65 66 67
    end

    it 'passes through html-pipeline' do
      project.update_attribute(:description, 'This project is the :poop:')
      visit path
68
      expect(page).to have_css('.home-panel-description > .home-panel-description-markdown > p > gl-emoji')
69 70 71
    end

    it 'sanitizes unwanted tags' do
Douwe Maan's avatar
Douwe Maan committed
72
      project.update_attribute(:description, "```\ncode\n```")
73
      visit path
74
      expect(page).not_to have_css('.home-panel-description code')
75 76 77 78 79
    end

    it 'permits `rel` attribute on links' do
      project.update_attribute(:description, 'https://google.com/')
      visit path
80
      expect(page).to have_css('.home-panel-description a[rel]')
81 82 83 84
    end

    context 'read more', :js do
      let(:read_more_selector)         { '.read-more-container' }
85
      let(:read_more_trigger_selector) { '.home-panel-home-desc .js-read-more-trigger' }
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

      it 'does not display "read more" link on desktop breakpoint' do
        project.update_attribute(:description, 'This is **my** project')
        visit path

        expect(find(read_more_trigger_selector, visible: false)).not_to be_visible
      end

      it 'displays "read more" link on mobile breakpoint' do
        project.update_attribute(:description, 'This is **my** project')
        visit path
        resize_screen_xs

        find(read_more_trigger_selector).click

101
        expect(page).to have_css('.home-panel-description .is-expanded')
102 103
      end
    end
104 105 106 107 108 109 110 111 112 113 114 115 116
  end

  describe 'project topics' do
    let(:project) { create(:project, :repository) }
    let(:path)    { project_path(project) }

    before do
      sign_in(create(:admin))
      visit path
    end

    it 'shows project topics' do
      project.update_attribute(:tag_list, 'topic1')
117

118
      visit path
119

120
      expect(page).to have_css('.home-panel-topic-list')
121
      expect(page).to have_link('Topic1', href: explore_projects_path(tag: 'topic1'))
122 123 124 125
    end

    it 'shows up to 3 project tags' do
      project.update_attribute(:tag_list, 'topic1, topic2, topic3, topic4')
126

127
      visit path
128

129
      expect(page).to have_css('.home-panel-topic-list')
130 131 132 133
      expect(page).to have_link('Topic1', href: explore_projects_path(tag: 'topic1'))
      expect(page).to have_link('Topic2', href: explore_projects_path(tag: 'topic2'))
      expect(page).to have_link('Topic3', href: explore_projects_path(tag: 'topic3'))
      expect(page).to have_content('+ 1 more')
134
    end
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  end

  describe 'copy clone URL to clipboard', :js do
    let(:project) { create(:project, :repository) }
    let(:path)    { project_path(project) }

    before do
      sign_in(create(:admin))
      visit path
    end

    context 'desktop component' do
      it 'shows on md and larger breakpoints' do
        expect(find('.git-clone-holder')).to be_visible
        expect(find('.mobile-git-clone', visible: false)).not_to be_visible
      end
    end

    context 'mobile component' do
      it 'shows mobile component on sm and smaller breakpoints' do
        resize_screen_xs
        expect(find('.mobile-git-clone')).to be_visible
        expect(find('.git-clone-holder', visible: false)).not_to be_visible
      end
159 160 161
    end
  end

162
  describe 'remove forked relationship', :js do
163
    let(:user)    { create(:user) }
164
    let(:project) { fork_project(create(:project, :public), user, namespace_id: user.namespace) }
165 166

    before do
167
      sign_in user
168
      visit edit_project_path(project)
169 170
    end

171
    it 'removes fork' do
172
      expect(page).to have_content 'Remove fork relationship'
173

174
      remove_with_confirm('Remove fork relationship', project.path)
175

Douwe Maan's avatar
Douwe Maan committed
176
      expect(page).to have_content 'The fork relationship has been removed.'
177
      expect(project.reload.forked?).to be_falsey
178
      expect(page).not_to have_content 'Remove fork relationship'
179 180 181
    end
  end

182 183
  describe 'showing information about source of a project fork' do
    let(:user) { create(:user) }
184
    let(:base_project) { create(:project, :public, :repository) }
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    let(:forked_project) { fork_project(base_project, user, repository: true) }

    before do
      sign_in user
    end

    it 'shows a link to the source project when it is available' do
      visit project_path(forked_project)

      expect(page).to have_content('Forked from')
      expect(page).to have_link(base_project.full_name)
    end

    it 'does not contain fork network information for the root project' do
      forked_project

      visit project_path(base_project)

      expect(page).not_to have_content('In fork network of')
      expect(page).not_to have_content('Forked from')
    end

    it 'shows the name of the deleted project when the source was deleted' do
      forked_project
      Projects::DestroyService.new(base_project, base_project.owner).execute

      visit project_path(forked_project)

      expect(page).to have_content("Forked from #{base_project.full_name} (deleted)")
    end

    context 'a fork of a fork' do
      let(:fork_of_fork) { fork_project(forked_project, user, repository: true) }

      it 'links to the base project if the source project is removed' do
        fork_of_fork
        Projects::DestroyService.new(forked_project, user).execute

        visit project_path(fork_of_fork)

        expect(page).to have_content("Forked from")
        expect(page).to have_link(base_project.full_name)
      end
    end
  end

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
  describe 'when the project repository is disabled', :js do
    let(:user)    { create(:user) }
    let(:project) { create(:project, :repository_disabled, :repository, namespace: user.namespace) }

    before do
      sign_in(user)
      project.add_maintainer(user)
      visit project_path(project)
    end

    it 'does not show an error' do
      wait_for_requests

      expect(page).not_to have_selector('.flash-alert')
    end
  end

248
  describe 'removal', :js do
249 250
    let(:user)    { create(:user) }
    let(:project) { create(:project, namespace: user.namespace) }
251 252

    before do
253
      sign_in(user)
254
      project.add_maintainer(user)
255
      visit edit_project_path(project)
256 257
    end

258 259 260 261 262 263
    it 'focuses on the confirmation field' do
      click_button 'Remove project'

      expect(page).to have_selector '#confirm_name_input:focus'
    end

ubudzisz's avatar
ubudzisz committed
264
    it 'removes a project' do
265 266
      expect { remove_with_confirm('Remove project', project.path) }.to change { Project.count }.by(-1)
      expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted."
ubudzisz's avatar
ubudzisz committed
267 268 269
      expect(Project.all.count).to be_zero
      expect(project.issues).to be_empty
      expect(project.merge_requests).to be_empty
randx's avatar
randx committed
270 271
    end
  end
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
272

273 274 275 276 277
  describe 'tree view (default view is set to Files)' do
    let(:user) { create(:user, project_view: 'files') }
    let(:project) { create(:forked_project_with_submodules) }

    before do
278
      project.add_maintainer(user)
279
      sign_in user
280
      visit project_path(project)
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    end

    it 'has working links to files' do
      click_link('PROCESS.md')

      expect(page.status_code).to eq(200)
    end

    it 'has working links to directories' do
      click_link('encoding')

      expect(page.status_code).to eq(200)
    end

    it 'has working links to submodules' do
      click_link('645f6c4c')

      expect(page.status_code).to eq(200)
    end
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314

    context 'for signed commit on default branch', :js do
      before do
        project.change_head('33f3729a45c02fc67d00adb1b8bca394b0e761d9')
      end

      it 'displays a GPG badge' do
        visit project_path(project)
        wait_for_requests

        expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
        expect(page).to have_selector '.gpg-status-box.invalid'
      end
    end

315
    context 'for subgroups', :js, :nested_groups do
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
      let(:group) { create(:group) }
      let(:subgroup) { create(:group, parent: group) }
      let(:project) { create(:project, :repository, group: subgroup) }

      it 'renders tree table without errors' do
        wait_for_requests

        expect(page).to have_selector('.tree-item')
        expect(page).not_to have_selector('.flash-alert')
      end

      context 'for signed commit' do
        before do
          repository = project.repository
          repository.write_ref("refs/heads/#{project.default_branch}", '33f3729a45c02fc67d00adb1b8bca394b0e761d9')
          repository.expire_branches_cache
        end

        it 'displays a GPG badge' do
          visit project_path(project)
          wait_for_requests

          expect(page).not_to have_selector '.gpg-status-box.js-loading-gpg-badge'
          expect(page).to have_selector '.gpg-status-box.invalid'
        end
      end
    end
343 344
  end

345 346 347 348 349
  describe 'activity view' do
    let(:user) { create(:user, project_view: 'activity') }
    let(:project) { create(:project, :repository) }

    before do
350
      project.add_maintainer(user)
351 352 353 354 355 356 357 358 359
      sign_in user
      visit project_path(project)
    end

    it 'loads activity', :js do
      expect(page).to have_selector('.event-item')
    end
  end

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
  context 'content is not cached after signing out', :js do
    let(:user) { create(:user, project_view: 'activity') }
    let(:project) { create(:project, :repository) }

    it 'does not load activity', :js do
      project.add_maintainer(user)
      sign_in(user)
      visit project_path(project)
      sign_out(user)

      page.evaluate_script('window.history.back()')

      expect(page).not_to have_selector('.event-item')
    end
  end

376 377 378
  def remove_with_confirm(button_text, confirm_with)
    click_button button_text
    fill_in 'confirm_name_input', with: confirm_with
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
379 380
    click_button 'Confirm'
  end
gitlabhq's avatar
gitlabhq committed
381
end