wiki_page_spec.rb 15.5 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

  describe "#create" do
130 131 132 133 134 135 136 137 138
    let(:wiki_attr) do
      {
        title: "Index",
        content: "Home Page",
        format: "markdown",
        message: 'Custom Commit Message'
      }
    end

139 140 141 142 143 144
    after do
      destroy_page("Index")
    end

    context "with valid attributes" do
      it "saves the wiki page" do
145
        subject.create(wiki_attr)
146
        expect(wiki.find_page("Index")).not_to be_nil
147 148 149
      end

      it "returns true" do
150 151 152 153 154 155 156
        expect(subject.create(wiki_attr)).to eq(true)
      end

      it 'saves the wiki page with message' do
        subject.create(wiki_attr)

        expect(wiki.find_page("Index").message).to eq 'Custom Commit Message'
157 158 159 160
      end
    end
  end

S
Stan Hu 已提交
161 162 163 164
  describe "dot in the title" do
    let(:title) { 'Index v1.2.3' }

    before do
165
      @wiki_attr = { title: title, content: "Home Page", format: "markdown" }
S
Stan Hu 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
    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
192
        @page.update(content: "new content")
S
Stan Hu 已提交
193 194 195 196
        @page = wiki.find_page(title)
      end

      it "returns true" do
197
        expect(@page.update(content: "more content")).to be_truthy
S
Stan Hu 已提交
198 199 200 201
      end
    end
  end

F
Francisco Javier López 已提交
202
  describe '#create' do
203 204 205 206 207 208
    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
209

210 211 212
        destroy_page('New Page')
        destroy_page('bar', 'foo')
      end
213

214 215
      it 'if the title is preceded by a / it is removed' do
        create_page('/New Page', 'content')
216

217 218 219
        expect(wiki.find_page('New Page')).not_to be_nil

        destroy_page('New Page')
220 221
      end
    end
222
  end
223

224 225 226 227
  describe "#update" do
    before do
      create_page("Update", "content")
      @page = wiki.find_page("Update")
228 229
    end

230 231
    after do
      destroy_page(@page.title, @page.directory)
232 233
    end

234 235 236 237 238
    context "with valid attributes" do
      it "updates the content of the page" do
        new_content = "new content"

        @page.update(content: new_content)
239
        @page = wiki.find_page("Update")
240

241
        expect(@page.content).to eq("new content")
242 243
      end

244 245
      it "updates the title of the page" do
        new_title = "Index v.1.2.4"
F
Francisco Javier López 已提交
246

247 248
        @page.update(title: new_title)
        @page = wiki.find_page(new_title)
F
Francisco Javier López 已提交
249

250 251
        expect(@page.title).to eq(new_title)
      end
252

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

258 259 260
    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
H
Hiroyuki Sato 已提交
261
      end
262
    end
H
Hiroyuki Sato 已提交
263

264 265 266
    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)
H
Hiroyuki Sato 已提交
267
      end
268
    end
269

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

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

278 279
        destroy_page('Existing Page')
      end
280

281 282 283
      it 'updates the content and rename the file' do
        new_title = 'Renamed Page'
        new_content = 'updated content'
284

285
        expect(@page.update(title: new_title, content: new_content)).to be_truthy
286

287
        @page = wiki.find_page(new_title)
288

289 290
        expect(@page).not_to be_nil
        expect(@page.content).to eq new_content
291
      end
292
    end
293

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

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

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

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

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

311
        page = wiki.find_page(new_title)
312

313 314 315
        expect(page).not_to be_nil
        expect(page.content).to eq new_content
      end
316

317 318 319 320 321
      context 'in subdir' do
        before do
          create_page('foo/Existing Page', 'content')
          @page = wiki.find_page('foo/Existing Page')
        end
322

323 324 325 326
        it 'moves the page to the root folder if the title is preceded by /' 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'
327 328
        end

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

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

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

341 342
          expect(@page.update(title: '/Update', content: 'new_content')).to be_truthy
          expect(@page.slug).to eq original_path
343 344 345 346
        end
      end
    end

347 348 349 350
    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'
351

352 353 354 355 356
        page = wiki.find_page('Update')
        expect(page.content).to eq 'content'

        @page.title = 'Update'
      end
357
    end
358 359 360 361 362 363 364 365
  end

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

366
    it "deletes the page" do
367
      @page.delete
368
      expect(wiki.pages).to be_empty
369 370
    end

371
    it "returns true" do
372
      expect(@page.delete).to eq(true)
373 374 375 376
    end
  end

  describe "#versions" do
377
    let(:page) { wiki.find_page("Update") }
378

379 380 381
    before do
      create_page("Update", "content")
    end
382

383 384
    after do
      destroy_page("Update")
385 386
    end

387 388 389 390
    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)
391 392
    end

393 394
    it 'returns instances of WikiPageVersion' do
      expect(page.versions).to all( be_a(Gitlab::Git::WikiPageVersion) )
395 396 397
    end
  end

398 399 400 401 402 403 404 405 406 407
  describe "#title" do
    before do
      create_page("Title", "content")
      @page = wiki.find_page("Title")
    end

    after do
      destroy_page("Title")
    end

408
    it "replaces a hyphen to a space" do
409
      @page.title = "Import-existing-repositories-into-GitLab"
410
      expect(@page.title).to eq("Import existing repositories into GitLab")
411
    end
J
Jacopo 已提交
412 413 414 415 416 417

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

      expect(@page.title).to eq('foo & bar')
    end
418 419
  end

420 421
  describe '#directory' do
    context 'when the page is at the root directory' do
A
Alex Braha Stoll 已提交
422
      it 'returns an empty string' do
423 424 425
        create_page('file', 'content')
        page = wiki.find_page('file')

A
Alex Braha Stoll 已提交
426
        expect(page.directory).to eq('')
427 428 429 430 431 432 433 434
      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 已提交
435
        expect(page.directory).to eq('dir_1/dir_1_1')
436 437 438 439
      end
    end
  end

440
  describe '#historical?' do
441 442 443 444 445 446
    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) }

447 448 449
    before do
      create_page('Update', 'content')
      @page = wiki.find_page('Update')
450
      3.times { |i| @page.update(content: "content #{i}") }
451 452 453 454 455 456 457
    end

    after do
      destroy_page('Update')
    end

    it 'returns true when requesting an old version' do
458
      expect(old_page.historical?).to be_truthy
459 460 461
    end

    it 'returns false when requesting latest version' do
462
      expect(latest_page.historical?).to be_falsy
463 464 465
    end

    it 'returns false when version is nil' do
466 467 468 469 470 471 472 473 474 475 476
      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 }
477

478
      expect(old_page.historical?).to be_falsy
479 480 481
    end
  end

A
Alex Braha Stoll 已提交
482 483 484 485 486 487 488 489
  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

490 491 492 493 494 495 496 497
  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
498
      updated_wiki_page = original_wiki_page.update(content: "Updated content")
499 500 501 502
      expect(original_wiki_page).not_to eq(updated_wiki_page)
    end
  end

H
Hiroyuki Sato 已提交
503 504 505 506 507 508 509 510 511 512 513
  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
514
      expect(@page.last_commit_sha).to eq @page.last_version.sha
H
Hiroyuki Sato 已提交
515 516 517 518 519
    end

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

520
      @page.update(content: "new content")
H
Hiroyuki Sato 已提交
521 522 523 524 525 526
      @page = wiki.find_page("Update")

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

527
  describe '#formatted_content' do
528 529 530
    it 'returns processed content of the page' do
      subject.create({ title: "RDoc", content: "*bold*", format: "rdoc" })
      page = wiki.find_page('RDoc')
531

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

534
      destroy_page('RDoc')
535 536 537
    end
  end

538
  describe '#hook_attrs' do
539
    it 'adds absolute urls for images in the content' do
540
      create_page("test page", "test![WikiPage_Image](/uploads/abc/WikiPage_Image.png)")
541 542
      page = wiki.wiki.page(title: "test page")
      wiki_page = described_class.new(wiki, page, true)
543

544
      expect(wiki_page.hook_attrs['content']).to eq("test![WikiPage_Image](#{Settings.gitlab.url}/uploads/abc/WikiPage_Image.png)")
545 546 547
    end
  end

548 549 550 551 552 553 554
  private

  def remove_temp_repo(path)
    FileUtils.rm_rf path
  end

  def commit_details
555
    Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "test commit")
556 557 558 559 560 561
  end

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

562 563
  def destroy_page(title, dir = '')
    page = wiki.wiki.page(title: title, dir: dir)
564
    wiki.delete_page(page, "test commit")
565
  end
566 567 568 569 570 571 572 573

  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
574
end