wiki_page_spec.rb 16.6 KB
Newer Older
1 2
require "spec_helper"

3
describe WikiPage do
Z
Zeger-Jan van de Weg 已提交
4
  let(:project) { create(:project, :wiki_repo) }
5
  let(:user) { project.owner }
6
  let(:wiki) { ProjectWiki.new(project, user) }
7

8
  subject { described_class.new(wiki) }
9

10
  describe '.group_by_directory' do
11
    context 'when there are no pages' do
12
      it 'returns an empty array' do
13 14
        expect(described_class.group_by_directory(nil)).to eq([])
        expect(described_class.group_by_directory([])).to eq([])
15 16 17 18
      end
    end

    context 'when there are pages' do
19
      before do
20
        create_page('dir_1/dir_1_1/page_3', 'content')
21
        create_page('dir_1/page_2', 'content')
22 23 24
        create_page('dir_2/page_5', 'content')
        create_page('dir_2/page_4', 'content')
        create_page('page_1', 'content')
25
      end
26 27 28 29 30 31 32 33 34 35 36 37
      let(:page_1) { wiki.find_page('page_1') }
      let(:dir_1) do
        WikiDirectory.new('dir_1', [wiki.find_page('dir_1/page_2')])
      end
      let(:dir_1_1) do
        WikiDirectory.new('dir_1/dir_1_1', [wiki.find_page('dir_1/dir_1_1/page_3')])
      end
      let(:dir_2) do
        pages = [wiki.find_page('dir_2/page_5'),
                 wiki.find_page('dir_2/page_4')]
        WikiDirectory.new('dir_2', pages)
      end
38

39 40
      it 'returns an array with pages and directories' do
        expected_grouped_entries = [page_1, dir_1, dir_1_1, dir_2]
41

42
        grouped_entries = described_class.group_by_directory(wiki.pages)
43

44 45 46 47
        grouped_entries.each_with_index do |page_or_dir, i|
          expected_page_or_dir = expected_grouped_entries[i]
          expected_slugs = get_slugs(expected_page_or_dir)
          slugs = get_slugs(page_or_dir)
48

49 50
          expect(slugs).to match_array(expected_slugs)
        end
51
      end
52

53 54 55 56 57
      it 'returns an array sorted by alphabetical position' do
        # Directories and pages within directories are sorted alphabetically.
        # Pages at root come before everything.
        expected_order = ['page_1', 'dir_1/page_2', 'dir_1/dir_1_1/page_3',
                          'dir_2/page_4', 'dir_2/page_5']
58

59
        grouped_entries = described_class.group_by_directory(wiki.pages)
60

61 62 63
        actual_order =
          grouped_entries.map do |page_or_dir|
            get_slugs(page_or_dir)
64 65
          end
          .flatten
66
        expect(actual_order).to eq(expected_order)
67
      end
68 69 70
    end
  end

A
Alex Braha Stoll 已提交
71 72 73 74
  describe '.unhyphenize' do
    it 'removes hyphens from a name' do
      name = 'a-name--with-hyphens'

75
      expect(described_class.unhyphenize(name)).to eq('a name with hyphens')
A
Alex Braha Stoll 已提交
76 77 78
    end
  end

79
  describe "#initialize" do
80
    context "when initialized with an existing page" do
81 82
      before do
        create_page("test page", "test content")
83
        @page = wiki.wiki.page(title: "test page")
84
        @wiki_page = described_class.new(wiki, @page, true)
85 86 87
      end

      it "sets the slug attribute" do
88
        expect(@wiki_page.slug).to eq("test-page")
89 90 91
      end

      it "sets the title attribute" do
92
        expect(@wiki_page.title).to eq("test page")
93 94 95
      end

      it "sets the formatted content attribute" do
96
        expect(@wiki_page.content).to eq("test content")
97 98 99
      end

      it "sets the format attribute" do
100
        expect(@wiki_page.format).to eq(:markdown)
101 102 103
      end

      it "sets the message attribute" do
104
        expect(@wiki_page.message).to eq("test commit")
105 106 107
      end

      it "sets the version attribute" do
108
        expect(@wiki_page.version).to be_a Gitlab::Git::WikiPageVersion
109 110 111 112 113 114
      end
    end
  end

  describe "validations" do
    before do
115
      subject.attributes = { title: 'title', content: 'content' }
116 117 118 119
    end

    it "validates presence of title" do
      subject.attributes.delete(:title)
120
      expect(subject.valid?).to be_falsey
121 122 123 124
    end

    it "validates presence of content" do
      subject.attributes.delete(:content)
125
      expect(subject.valid?).to be_falsey
126 127 128 129
    end
  end

  before do
130
    @wiki_attr = { title: "Index", content: "Home Page", format: "markdown" }
131 132 133 134 135 136 137 138 139 140
  end

  describe "#create" do
    after do
      destroy_page("Index")
    end

    context "with valid attributes" do
      it "saves the wiki page" do
        subject.create(@wiki_attr)
141
        expect(wiki.find_page("Index")).not_to be_nil
142 143 144
      end

      it "returns true" do
145
        expect(subject.create(@wiki_attr)).to eq(true)
146 147 148 149
      end
    end
  end

S
Stan Hu 已提交
150 151 152 153
  describe "dot in the title" do
    let(:title) { 'Index v1.2.3' }

    before do
154
      @wiki_attr = { title: title, content: "Home Page", format: "markdown" }
S
Stan Hu 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
    end

    describe "#create" do
      after do
        destroy_page(title)
      end

      context "with valid attributes" do
        it "saves the wiki page" do
          subject.create(@wiki_attr)
          expect(wiki.find_page(title)).not_to be_nil
        end

        it "returns true" do
          expect(subject.create(@wiki_attr)).to eq(true)
        end
      end
    end

    describe "#update" do
      before do
        create_page(title, "content")
        @page = wiki.find_page(title)
      end

      it "updates the content of the page" do
181
        @page.update(content: "new content")
S
Stan Hu 已提交
182 183 184 185
        @page = wiki.find_page(title)
      end

      it "returns true" do
186
        expect(@page.update(content: "more content")).to be_truthy
S
Stan Hu 已提交
187 188 189 190
      end
    end
  end

F
Francisco Javier López 已提交
191 192 193 194 195 196 197 198 199 200 201 202
  describe '#create' do
    shared_examples 'create method' do
      context 'with valid attributes' do
        it 'raises an error if a page with the same path already exists' do
          create_page('New Page', 'content')
          create_page('foo/bar', 'content')
          expect { create_page('New Page', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError
          expect { create_page('foo/bar', 'other content') }.to raise_error Gitlab::Git::Wiki::DuplicatePageError

          destroy_page('New Page')
          destroy_page('bar', 'foo')
        end
203

F
Francisco Javier López 已提交
204 205
        it 'if the title is preceded by a / it is removed' do
          create_page('/New Page', 'content')
206

F
Francisco Javier López 已提交
207
          expect(wiki.find_page('New Page')).not_to be_nil
208

F
Francisco Javier López 已提交
209 210
          destroy_page('New Page')
        end
211 212 213
      end
    end

F
Francisco Javier López 已提交
214 215
    context 'when Gitaly is enabled' do
      it_behaves_like 'create method'
216 217
    end

F
Francisco Javier López 已提交
218 219
    context 'when Gitaly is disabled', :skip_gitaly_mock do
      it_behaves_like 'create method'
220
    end
F
Francisco Javier López 已提交
221
  end
222

F
Francisco Javier López 已提交
223 224 225 226
  describe "#update" do
    shared_examples 'update method' do
      before do
        create_page("Update", "content")
227
        @page = wiki.find_page("Update")
F
Francisco Javier López 已提交
228
      end
229

F
Francisco Javier López 已提交
230 231
      after do
        destroy_page(@page.title, @page.directory)
232 233
      end

F
Francisco Javier López 已提交
234 235 236
      context "with valid attributes" do
        it "updates the content of the page" do
          new_content = "new content"
237

F
Francisco Javier López 已提交
238 239
          @page.update(content: new_content)
          @page = wiki.find_page("Update")
240

F
Francisco Javier López 已提交
241 242
          expect(@page.content).to eq("new content")
        end
243

F
Francisco Javier López 已提交
244 245 246 247 248 249 250 251 252 253 254 255
        it "updates the title of the page" do
          new_title = "Index v.1.2.4"

          @page.update(title: new_title)
          @page = wiki.find_page(new_title)

          expect(@page.title).to eq(new_title)
        end

        it "returns true" do
          expect(@page.update(content: "more content")).to be_truthy
        end
256
      end
H
Hiroyuki Sato 已提交
257

F
Francisco Javier López 已提交
258 259 260 261
      context 'with same last commit sha' do
        it 'returns true' do
          expect(@page.update(content: 'more content', last_commit_sha: @page.last_commit_sha)).to be_truthy
        end
H
Hiroyuki Sato 已提交
262 263
      end

F
Francisco Javier López 已提交
264 265 266 267
      context 'with different last commit sha' do
        it 'raises exception' do
          expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError)
        end
H
Hiroyuki Sato 已提交
268
      end
269

F
Francisco Javier López 已提交
270 271 272
      context 'when renaming a page' do
        it 'raises an error if the page already exists' do
          create_page('Existing Page', 'content')
273

F
Francisco Javier López 已提交
274 275 276
          expect { @page.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
          expect(@page.title).to eq 'Update'
          expect(@page.content).to eq 'new_content'
277

F
Francisco Javier López 已提交
278 279
          destroy_page('Existing Page')
        end
280

F
Francisco Javier López 已提交
281 282 283
        it 'updates the content and rename the file' do
          new_title = 'Renamed Page'
          new_content = 'updated content'
284

F
Francisco Javier López 已提交
285
          expect(@page.update(title: new_title, content: new_content)).to be_truthy
286

F
Francisco Javier López 已提交
287
          @page = wiki.find_page(new_title)
288

F
Francisco Javier López 已提交
289 290 291
          expect(@page).not_to be_nil
          expect(@page.content).to eq new_content
        end
292 293
      end

F
Francisco Javier López 已提交
294 295 296
      context 'when moving a page' do
        it 'raises an error if the page already exists' do
          create_page('foo/Existing Page', 'content')
297

F
Francisco Javier López 已提交
298 299 300
          expect { @page.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
          expect(@page.title).to eq 'Update'
          expect(@page.content).to eq 'new_content'
301

F
Francisco Javier López 已提交
302 303
          destroy_page('Existing Page', 'foo')
        end
304

F
Francisco Javier López 已提交
305 306 307
        it 'updates the content and moves the file' do
          new_title = 'foo/Other Page'
          new_content = 'new_content'
308

F
Francisco Javier López 已提交
309
          expect(@page.update(title: new_title, content: new_content)).to be_truthy
310

F
Francisco Javier López 已提交
311
          page = wiki.find_page(new_title)
312

F
Francisco Javier López 已提交
313 314
          expect(page).not_to be_nil
          expect(page.content).to eq new_content
315 316
        end

F
Francisco Javier López 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
        context 'in subdir' do
          before do
            create_page('foo/Existing Page', 'content')
            @page = wiki.find_page('foo/Existing Page')
          end

          it 'moves the page to the root folder if the title is preceded by /', :skip_gitaly_mock do
            expect(@page.slug).to eq 'foo/Existing-Page'
            expect(@page.update(title: '/Existing Page', content: 'new_content')).to be_truthy
            expect(@page.slug).to eq 'Existing-Page'
          end

          it 'does nothing if it has the same title' do
            original_path = @page.slug

            expect(@page.update(title: 'Existing Page', content: 'new_content')).to be_truthy
            expect(@page.slug).to eq original_path
          end
335 336
        end

F
Francisco Javier López 已提交
337 338 339
        context 'in root dir' do
          it 'does nothing if the title is preceded by /' do
            original_path = @page.slug
340

F
Francisco Javier López 已提交
341 342 343
            expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy
            expect(@page.slug).to eq original_path
          end
344 345 346
        end
      end

F
Francisco Javier López 已提交
347 348 349 350 351 352 353
      context "with invalid attributes" do
        it 'aborts update if title blank' do
          expect(@page.update(title: '', content: 'new_content')).to be_falsey
          expect(@page.content).to eq 'new_content'

          page = wiki.find_page('Update')
          expect(page.content).to eq 'content'
354

F
Francisco Javier López 已提交
355
          @page.title = 'Update'
356 357 358 359
        end
      end
    end

F
Francisco Javier López 已提交
360 361 362
    context 'when Gitaly is enabled' do
      it_behaves_like 'update method'
    end
363

F
Francisco Javier López 已提交
364 365
    context 'when Gitaly is disabled', :skip_gitaly_mock do
      it_behaves_like 'update method'
366
    end
367 368 369 370 371 372 373 374
  end

  describe "#destroy" do
    before do
      create_page("Delete Page", "content")
      @page = wiki.find_page("Delete Page")
    end

375
    it "deletes the page" do
376
      @page.delete
377
      expect(wiki.pages).to be_empty
378 379
    end

380
    it "returns true" do
381
      expect(@page.delete).to eq(true)
382 383 384 385
    end
  end

  describe "#versions" do
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
    shared_examples 'wiki page versions' do
      let(:page) { wiki.find_page("Update") }

      before do
        create_page("Update", "content")
      end

      after do
        destroy_page("Update")
      end

      it "returns an array of all commits for the page" do
        3.times { |i| page.update(content: "content #{i}") }

        expect(page.versions.count).to eq(4)
      end

      it 'returns instances of WikiPageVersion' do
        expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
      end
406 407
    end

408 409
    context 'when Gitaly is enabled' do
      it_behaves_like 'wiki page versions'
410 411
    end

412 413
    context 'when Gitaly is disabled', :disable_gitaly do
      it_behaves_like 'wiki page versions'
414 415 416
    end
  end

417 418 419 420 421 422 423 424 425 426
  describe "#title" do
    before do
      create_page("Title", "content")
      @page = wiki.find_page("Title")
    end

    after do
      destroy_page("Title")
    end

427
    it "replaces a hyphen to a space" do
428
      @page.title = "Import-existing-repositories-into-GitLab"
429
      expect(@page.title).to eq("Import existing repositories into GitLab")
430
    end
J
Jacopo 已提交
431 432 433 434 435 436

    it 'unescapes html' do
      @page.title = 'foo & bar'

      expect(@page.title).to eq('foo & bar')
    end
437 438
  end

439 440
  describe '#directory' do
    context 'when the page is at the root directory' do
A
Alex Braha Stoll 已提交
441
      it 'returns an empty string' do
442 443 444
        create_page('file', 'content')
        page = wiki.find_page('file')

A
Alex Braha Stoll 已提交
445
        expect(page.directory).to eq('')
446 447 448 449 450 451 452 453
      end
    end

    context 'when the page is inside an actual directory' do
      it 'returns the full directory hierarchy' do
        create_page('dir_1/dir_1_1/file', 'content')
        page = wiki.find_page('dir_1/dir_1_1/file')

A
Alex Braha Stoll 已提交
454
        expect(page.directory).to eq('dir_1/dir_1_1')
455 456 457 458
      end
    end
  end

459
  describe '#historical?' do
460 461 462 463 464 465
    let(:page) { wiki.find_page('Update') }
    let(:old_version) { page.versions.last.id }
    let(:old_page) { wiki.find_page('Update', old_version) }
    let(:latest_version) { page.versions.first.id }
    let(:latest_page) { wiki.find_page('Update', latest_version) }

466 467 468
    before do
      create_page('Update', 'content')
      @page = wiki.find_page('Update')
469
      3.times { |i| @page.update(content: "content #{i}") }
470 471 472 473 474 475 476
    end

    after do
      destroy_page('Update')
    end

    it 'returns true when requesting an old version' do
477
      expect(old_page.historical?).to be_truthy
478 479 480
    end

    it 'returns false when requesting latest version' do
481
      expect(latest_page.historical?).to be_falsy
482 483 484
    end

    it 'returns false when version is nil' do
485 486 487 488 489 490 491 492 493 494 495
      expect(latest_page.historical?).to be_falsy
    end

    it 'returns false when the last version is nil' do
      expect(old_page).to receive(:last_version) { nil }

      expect(old_page.historical?).to be_falsy
    end

    it 'returns false when the version is nil' do
      expect(old_page).to receive(:version) { nil }
496

497
      expect(old_page.historical?).to be_falsy
498 499 500
    end
  end

A
Alex Braha Stoll 已提交
501 502 503 504 505 506 507 508
  describe '#to_partial_path' do
    it 'returns the relative path to the partial to be used' do
      page = build(:wiki_page)

      expect(page.to_partial_path).to eq('projects/wikis/wiki_page')
    end
  end

509 510 511 512 513 514 515 516
  describe '#==' do
    let(:original_wiki_page) { create(:wiki_page) }

    it 'returns true for identical wiki page' do
      expect(original_wiki_page).to eq(original_wiki_page)
    end

    it 'returns false for updated wiki page' do
517
      updated_wiki_page = original_wiki_page.update(content: "Updated content")
518 519 520 521
      expect(original_wiki_page).not_to eq(updated_wiki_page)
    end
  end

H
Hiroyuki Sato 已提交
522 523 524 525 526 527 528 529 530 531 532
  describe '#last_commit_sha' do
    before do
      create_page("Update", "content")
      @page = wiki.find_page("Update")
    end

    after do
      destroy_page("Update")
    end

    it 'returns commit sha' do
533
      expect(@page.last_commit_sha).to eq @page.last_version.sha
H
Hiroyuki Sato 已提交
534 535 536 537 538
    end

    it 'is changed after page updated' do
      last_commit_sha_before_update = @page.last_commit_sha

539
      @page.update(content: "new content")
H
Hiroyuki Sato 已提交
540 541 542 543 544 545
      @page = wiki.find_page("Update")

      expect(@page.last_commit_sha).not_to eq last_commit_sha_before_update
    end
  end

546
  describe '#formatted_content' do
547 548 549 550
    shared_examples 'fetching page formatted content' do
      it 'returns processed content of the page' do
        subject.create({ title: "RDoc", content: "*bold*", format: "rdoc" })
        page = wiki.find_page('RDoc')
551

552
        expect(page.formatted_content).to eq("\n<p><strong>bold</strong></p>\n")
553

554 555 556 557 558 559 560 561 562 563
        destroy_page('RDoc')
      end
    end

    context 'when Gitaly wiki_page_formatted_data is enabled' do
      it_behaves_like 'fetching page formatted content'
    end

    context 'when Gitaly wiki_page_formatted_data is disabled', :disable_gitaly do
      it_behaves_like 'fetching page formatted content'
564 565 566
    end
  end

567
  describe '#hook_attrs' do
568
    it 'adds absolute urls for images in the content' do
569
      create_page("test page", "test![WikiPage_Image](/uploads/abc/WikiPage_Image.png)")
570 571
      page = wiki.wiki.page(title: "test page")
      wiki_page = described_class.new(wiki, page, true)
572

573
      expect(wiki_page.hook_attrs['content']).to eq("test![WikiPage_Image](#{Settings.gitlab.url}/uploads/abc/WikiPage_Image.png)")
574 575 576
    end
  end

577 578 579 580 581 582 583
  private

  def remove_temp_repo(path)
    FileUtils.rm_rf path
  end

  def commit_details
584
    Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "test commit")
585 586 587 588 589 590
  end

  def create_page(name, content)
    wiki.wiki.write_page(name, :markdown, content, commit_details)
  end

591 592
  def destroy_page(title, dir = '')
    page = wiki.wiki.page(title: title, dir: dir)
593
    wiki.delete_page(page, "test commit")
594
  end
595 596 597 598 599 600 601 602

  def get_slugs(page_or_dir)
    if page_or_dir.is_a? WikiPage
      [page_or_dir.slug]
    else
      page_or_dir.pages.present? ? page_or_dir.pages.map(&:slug) : []
    end
  end
603
end