label_reference_filter_spec.rb 22.8 KB
Newer Older
1 2
# frozen_string_literal: true

3 4 5
require 'spec_helper'
require 'html/pipeline'

6
describe Banzai::Filter::LabelReferenceFilter do
7 8
  include FilterSpecHelper

9
  let(:project)   { create(:project, :public, name: 'sample-project') }
10 11 12 13 14 15 16 17 18 19
  let(:label)     { create(:label, project: project) }
  let(:reference) { label.to_reference }

  it 'requires project context' do
    expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
  end

  %w(pre code a style).each do |elem|
    it "ignores valid references contained inside '#{elem}' element" do
      exp = act = "<#{elem}>Label #{reference}</#{elem}>"
20
      expect(reference_filter(act).to_html).to eq exp
21 22 23 24
    end
  end

  it 'includes default classes' do
25
    doc = reference_filter("Label #{reference}")
26
    expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label has-tooltip'
27 28 29
  end

  it 'includes a data-project attribute' do
30
    doc = reference_filter("Label #{reference}")
31 32 33 34 35 36 37
    link = doc.css('a').first

    expect(link).to have_attribute('data-project')
    expect(link.attr('data-project')).to eq project.id.to_s
  end

  it 'includes a data-label attribute' do
38
    doc = reference_filter("See #{reference}")
39 40 41 42 43 44 45
    link = doc.css('a').first

    expect(link).to have_attribute('data-label')
    expect(link.attr('data-label')).to eq label.id.to_s
  end

  it 'supports an :only_path context' do
46
    doc = reference_filter("Label #{reference}", only_path: true)
47 48 49
    link = doc.css('a').first.attr('href')

    expect(link).not_to match %r(https?://)
50
    expect(link).to eq urls.project_issues_path(project, label_name: label.name)
51 52
  end

53 54 55 56 57 58 59 60
  context 'project that does not exist referenced' do
    let(:result) { reference_filter('aaa/bbb~ccc') }

    it 'does not link reference' do
      expect(result.to_html).to eq 'aaa/bbb~ccc'
    end
  end

61 62
  describe 'label span element' do
    it 'includes default classes' do
63
      doc = reference_filter("Label #{reference}")
64
      expect(doc.css('a span').first.attr('class')).to eq 'badge color-label has-tooltip'
65 66 67
    end

    it 'includes a style attribute' do
68
      doc = reference_filter("Label #{reference}")
69 70 71 72 73 74
      expect(doc.css('a span').first.attr('style')).to match(/\Abackground-color: #\h{6}; color: #\h{6}\z/)
    end
  end

  context 'Integer-based references' do
    it 'links to a valid reference' do
75
      doc = reference_filter("See #{reference}")
76

77
      expect(doc.css('a').first.attr('href')).to eq urls
78
        .project_issues_url(project, label_name: label.name)
79 80 81
    end

    it 'links with adjacent text' do
82
      doc = reference_filter("Label (#{reference}.)")
83 84 85 86 87 88
      expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
    end

    it 'ignores invalid label IDs' do
      exp = act = "Label #{invalidate_reference(reference)}"

89
      expect(reference_filter(act).to_html).to eq exp
90 91 92 93 94 95 96 97
    end
  end

  context 'String-based single-word references' do
    let(:label)     { create(:label, name: 'gfm', project: project) }
    let(:reference) { "#{Label.reference_prefix}#{label.name}" }

    it 'links to a valid reference' do
98
      doc = reference_filter("See #{reference}")
99

100
      expect(doc.css('a').first.attr('href')).to eq urls
101
        .project_issues_url(project, label_name: label.name)
102 103 104 105
      expect(doc.text).to eq 'See gfm'
    end

    it 'links with adjacent text' do
106 107
      doc = reference_filter("Label (#{reference}).")
      expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\)\.))
108 109 110 111 112
    end

    it 'ignores invalid label names' do
      exp = act = "Label #{Label.reference_prefix}#{label.name.reverse}"

113
      expect(reference_filter(act).to_html).to eq exp
114 115 116
    end
  end

117 118 119 120 121 122 123
  context 'String-based single-word references that begin with a digit' do
    let(:label)     { create(:label, name: '2fa', project: project) }
    let(:reference) { "#{Label.reference_prefix}#{label.name}" }

    it 'links to a valid reference' do
      doc = reference_filter("See #{reference}")

124
      expect(doc.css('a').first.attr('href')).to eq urls
125
        .project_issues_url(project, label_name: label.name)
126 127 128 129
      expect(doc.text).to eq 'See 2fa'
    end

    it 'links with adjacent text' do
130 131
      doc = reference_filter("Label (#{reference}).")
      expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\)\.))
132 133 134 135 136 137 138 139 140
    end

    it 'ignores invalid label names' do
      exp = act = "Label #{Label.reference_prefix}#{label.id}#{label.name.reverse}"

      expect(reference_filter(act).to_html).to eq exp
    end
  end

141
  context 'String-based single-word references with special characters' do
142
    let(:label)     { create(:label, name: '?g.fm&', project: project) }
143 144 145 146 147
    let(:reference) { "#{Label.reference_prefix}#{label.name}" }

    it 'links to a valid reference' do
      doc = reference_filter("See #{reference}")

148
      expect(doc.css('a').first.attr('href')).to eq urls
149
        .project_issues_url(project, label_name: label.name)
150
      expect(doc.text).to eq 'See ?g.fm&'
151 152
    end

153 154 155 156 157
    it 'does not include trailing punctuation', :aggregate_failures do
      ['.', ', ok?', '...', '?', '!', ': is that ok?'].each do |trailing_punctuation|
        doc = filter("Label #{reference}#{trailing_punctuation}")
        expect(doc.to_html).to match(%r(<a.+><span.+>\?g\.fm&amp;</span></a>#{Regexp.escape(trailing_punctuation)}))
      end
158 159 160 161
    end

    it 'ignores invalid label names' do
      act = "Label #{Label.reference_prefix}#{label.name.reverse}"
162
      exp = "Label #{Label.reference_prefix}&amp;mf.g?"
163 164 165 166 167

      expect(reference_filter(act).to_html).to eq exp
    end
  end

168 169
  context 'String-based multi-word references in quotes' do
    let(:label)     { create(:label, name: 'gfm references', project: project) }
170
    let(:reference) { label.to_reference(format: :name) }
171 172

    it 'links to a valid reference' do
173
      doc = reference_filter("See #{reference}")
174

175
      expect(doc.css('a').first.attr('href')).to eq urls
176
        .project_issues_url(project, label_name: label.name)
177 178 179 180
      expect(doc.text).to eq 'See gfm references'
    end

    it 'links with adjacent text' do
181
      doc = reference_filter("Label (#{reference}.)")
182 183 184 185 186 187
      expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
    end

    it 'ignores invalid label names' do
      exp = act = %(Label #{Label.reference_prefix}"#{label.name.reverse}")

188
      expect(reference_filter(act).to_html).to eq exp
189 190 191
    end
  end

192 193 194 195 196 197 198
  context 'String-based multi-word references that begin with a digit' do
    let(:label)     { create(:label, name: '2 factor authentication', project: project) }
    let(:reference) { label.to_reference(format: :name) }

    it 'links to a valid reference' do
      doc = reference_filter("See #{reference}")

199
      expect(doc.css('a').first.attr('href')).to eq urls
200
        .project_issues_url(project, label_name: label.name)
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
      expect(doc.text).to eq 'See 2 factor authentication'
    end

    it 'links with adjacent text' do
      doc = reference_filter("Label (#{reference}.)")
      expect(doc.to_html).to match(%r(\(<a.+><span.+>#{label.name}</span></a>\.\)))
    end

    it 'ignores invalid label names' do
      exp = act = "Label #{Label.reference_prefix}#{label.id}#{label.name.reverse}"

      expect(reference_filter(act).to_html).to eq exp
    end
  end

216
  context 'String-based multi-word references with special characters in quotes' do
217
    let(:label)     { create(:label, name: 'g.fm & references?', project: project) }
218 219 220 221 222
    let(:reference) { label.to_reference(format: :name) }

    it 'links to a valid reference' do
      doc = reference_filter("See #{reference}")

223
      expect(doc.css('a').first.attr('href')).to eq urls
224
        .project_issues_url(project, label_name: label.name)
225
      expect(doc.text).to eq 'See g.fm & references?'
226 227 228 229
    end

    it 'links with adjacent text' do
      doc = reference_filter("Label (#{reference}.)")
230
      expect(doc.to_html).to match(%r(\(<a.+><span.+>g\.fm &amp; references\?</span></a>\.\)))
231 232 233 234
    end

    it 'ignores invalid label names' do
      act = %(Label #{Label.reference_prefix}"#{label.name.reverse}")
235
      exp = %(Label #{Label.reference_prefix}"?secnerefer &amp; mf.g\")
236 237 238 239 240

      expect(reference_filter(act).to_html).to eq exp
    end
  end

241
  context 'References with html entities' do
242
    let!(:label) { create(:label, name: '&lt;html&gt;', project: project) }
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

    it 'links to a valid reference' do
      doc = reference_filter('See ~"&lt;html&gt;"')

      expect(doc.css('a').first.attr('href')).to eq urls
        .project_issues_url(project, label_name: label.name)
      expect(doc.text).to eq 'See <html>'
    end

    it 'ignores invalid label names and escapes entities' do
      act = %(Label #{Label.reference_prefix}"&lt;non valid&gt;")

      expect(reference_filter(act).to_html).to eq act
    end
  end

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
  describe 'consecutive references' do
    let(:bug) { create(:label, name: 'bug', project: project) }
    let(:feature_proposal) { create(:label, name: 'feature proposal', project: project) }
    let(:technical_debt) { create(:label, name: 'technical debt', project: project) }

    let(:bug_reference) { "#{Label.reference_prefix}#{bug.name}" }
    let(:feature_proposal_reference) { feature_proposal.to_reference(format: :name) }
    let(:technical_debt_reference) { technical_debt.to_reference(format: :name) }

    context 'separated with a comma' do
      let(:references) { "#{bug_reference}, #{feature_proposal_reference}, #{technical_debt_reference}" }

      it 'links to valid references' do
        doc = reference_filter("See #{references}")

        expect(doc.css('a').map { |a| a.attr('href') }).to match_array([
275 276 277
          urls.project_issues_url(project, label_name: bug.name),
          urls.project_issues_url(project, label_name: feature_proposal.name),
          urls.project_issues_url(project, label_name: technical_debt.name)
278 279 280 281 282 283 284 285 286 287 288 289
        ])
        expect(doc.text).to eq 'See bug, feature proposal, technical debt'
      end
    end

    context 'separated with a space' do
      let(:references) { "#{bug_reference} #{feature_proposal_reference} #{technical_debt_reference}" }

      it 'links to valid references' do
        doc = reference_filter("See #{references}")

        expect(doc.css('a').map { |a| a.attr('href') }).to match_array([
290 291 292
          urls.project_issues_url(project, label_name: bug.name),
          urls.project_issues_url(project, label_name: feature_proposal.name),
          urls.project_issues_url(project, label_name: technical_debt.name)
293 294 295 296 297 298
        ])
        expect(doc.text).to eq 'See bug feature proposal technical debt'
      end
    end
  end

299 300 301
  describe 'edge cases' do
    it 'gracefully handles non-references matching the pattern' do
      exp = act = '(format nil "~0f" 3.0) ; 3.0'
302 303 304 305 306 307 308 309 310 311
      expect(reference_filter(act).to_html).to eq exp
    end
  end

  describe 'referencing a label in a link href' do
    let(:reference) { %Q{<a href="#{label.to_reference}">Label</a>} }

    it 'links to a valid reference' do
      doc = reference_filter("See #{reference}")

312
      expect(doc.css('a').first.attr('href')).to eq urls
313
        .project_issues_url(project, label_name: label.name)
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
    end

    it 'links with adjacent text' do
      doc = reference_filter("Label (#{reference}.)")
      expect(doc.to_html).to match(%r(\(<a.+>Label</a>\.\)))
    end

    it 'includes a data-project attribute' do
      doc = reference_filter("Label #{reference}")
      link = doc.css('a').first

      expect(link).to have_attribute('data-project')
      expect(link.attr('data-project')).to eq project.id.to_s
    end

    it 'includes a data-label attribute' do
      doc = reference_filter("See #{reference}")
      link = doc.css('a').first

      expect(link).to have_attribute('data-label')
      expect(link.attr('data-label')).to eq label.id.to_s
    end
336
  end
337

338 339
  describe 'group label references' do
    let(:group)       { create(:group) }
340
    let(:project)     { create(:project, :public, namespace: group) }
341 342 343 344 345 346 347 348
    let(:group_label) { create(:group_label, name: 'gfm references', group: group) }

    context 'without project reference' do
      let(:reference) { group_label.to_reference(format: :name) }

      it 'links to a valid reference' do
        doc = reference_filter("See #{reference}", project: project)

349
        expect(doc.css('a').first.attr('href')).to eq urls
350
          .project_issues_url(project, label_name: group_label.name)
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
        expect(doc.text).to eq 'See gfm references'
      end

      it 'links with adjacent text' do
        doc = reference_filter("Label (#{reference}.)")
        expect(doc.to_html).to match(%r(\(<a.+><span.+>#{group_label.name}</span></a>\.\)))
      end

      it 'ignores invalid label names' do
        exp = act = %(Label #{Label.reference_prefix}"#{group_label.name.reverse}")

        expect(reference_filter(act).to_html).to eq exp
      end
    end

    context 'with project reference' do
367
      let(:reference) { "#{project.to_reference}#{group_label.to_reference(format: :name)}" }
368 369 370 371

      it 'links to a valid reference' do
        doc = reference_filter("See #{reference}", project: project)

372
        expect(doc.css('a').first.attr('href')).to eq urls
373
          .project_issues_url(project, label_name: group_label.name)
374
        expect(doc.text).to eq "See gfm references"
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
      end

      it 'links with adjacent text' do
        doc = reference_filter("Label (#{reference}.)")
        expect(doc.to_html).to match(%r(\(<a.+><span.+>#{group_label.name}</span></a>\.\)))
      end

      it 'ignores invalid label names' do
        exp = act = %(Label #{project.to_reference}#{Label.reference_prefix}"#{group_label.name.reverse}")

        expect(reference_filter(act).to_html).to eq exp
      end
    end
  end

390
  describe 'cross-project / cross-namespace complete reference' do
391
    let(:project2)  { create(:project) }
392
    let(:label)     { create(:label, project: project2, color: '#00ff00') }
393
    let(:reference) { "#{project2.full_path}~#{label.name}" }
394
    let!(:result)   { reference_filter("See #{reference}") }
395

396 397
    it 'links to a valid reference' do
      expect(result.css('a').first.attr('href'))
398
        .to eq urls.project_issues_url(project2, label_name: label.name)
399
    end
400

401 402 403
    it 'has valid color' do
      expect(result.css('a span').first.attr('style')).to match /background-color: #00ff00/
    end
404

405
    it 'has valid link text' do
406
      expect(result.css('a').first.text).to eq "#{label.name} in #{project2.full_name}"
407
    end
408

409
    it 'has valid text' do
410
      expect(result.text).to eq "See #{label.name} in #{project2.full_name}"
411 412
    end

413 414
    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"
415

416 417 418 419 420 421
      expect(reference_filter(act).to_html).to eq exp
    end
  end

  describe 'cross-project / same-namespace complete reference' do
    let(:namespace) { create(:namespace) }
422 423
    let(:project)   { create(:project, namespace: namespace) }
    let(:project2)  { create(:project, namespace: namespace) }
424
    let(:label)     { create(:label, project: project2, color: '#00ff00') }
425
    let(:reference) { "#{project2.full_path}~#{label.name}" }
426 427 428 429
    let!(:result)   { reference_filter("See #{reference}") }

    it 'links to a valid reference' do
      expect(result.css('a').first.attr('href'))
430
        .to eq urls.project_issues_url(project2, label_name: label.name)
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
    end

    it 'has valid color' do
      expect(result.css('a span').first.attr('style')).to match /background-color: #00ff00/
    end

    it 'has valid link text' do
      expect(result.css('a').first.text).to eq "#{label.name} in #{project2.name}"
    end

    it 'has valid text' do
      expect(result.text).to eq "See #{label.name} in #{project2.name}"
    end

    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"

      expect(reference_filter(act).to_html).to eq exp
    end
  end

  describe 'cross-project shorthand reference' do
    let(:namespace) { create(:namespace) }
454 455
    let(:project)   { create(:project, namespace: namespace) }
    let(:project2)  { create(:project, namespace: namespace) }
456 457 458 459 460 461
    let(:label)     { create(:label, project: project2, color: '#00ff00') }
    let(:reference) { "#{project2.path}~#{label.name}" }
    let!(:result)   { reference_filter("See #{reference}") }

    it 'links to a valid reference' do
      expect(result.css('a').first.attr('href'))
462
        .to eq urls.project_issues_url(project2, label_name: label.name)
463 464 465
    end

    it 'has valid color' do
466 467
      expect(result.css('a span').first.attr('style'))
        .to match /background-color: #00ff00/
468 469 470 471 472 473 474 475 476 477 478 479 480 481
    end

    it 'has valid link text' do
      expect(result.css('a').first.text).to eq "#{label.name} in #{project2.name}"
    end

    it 'has valid text' do
      expect(result.text).to eq "See #{label.name} in #{project2.name}"
    end

    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"

      expect(reference_filter(act).to_html).to eq exp
482 483
    end
  end
484 485

  describe 'cross group label references' do
486
    let(:group)            { create(:group) }
487
    let(:project)          { create(:project, :public, namespace: group) }
488
    let(:another_group)    { create(:group) }
489
    let(:another_project)  { create(:project, :public, namespace: another_group) }
490
    let(:group_label)      { create(:group_label, group: another_group, color: '#00ff00') }
491
    let(:reference)        { "#{another_project.full_path}~#{group_label.name}" }
492
    let!(:result)          { reference_filter("See #{reference}", project: project) }
493

494 495
    it 'points to referenced project issues page' do
      expect(result.css('a').first.attr('href'))
496
        .to eq urls.project_issues_url(another_project, label_name: group_label.name)
497
    end
498

499
    it 'has valid color' do
500 501
      expect(result.css('a span').first.attr('style'))
        .to match /background-color: #00ff00/
502 503 504
    end

    it 'has valid link text' do
505
      expect(result.css('a').first.text)
506
        .to eq "#{group_label.name} in #{another_project.full_name}"
507 508 509
    end

    it 'has valid text' do
510
      expect(result.text)
511
        .to eq "See #{group_label.name} in #{another_project.full_name}"
512 513 514 515 516 517 518 519 520 521 522
    end

    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"

      expect(reference_filter(act).to_html).to eq exp
    end
  end

  describe 'cross-project / same-group_label complete reference' do
    let(:group)            { create(:group) }
523 524
    let(:project)          { create(:project, :public, namespace: group) }
    let(:another_project)  { create(:project, :public, namespace: group) }
525
    let(:group_label)      { create(:group_label, group: group, color: '#00ff00') }
526
    let(:reference)        { "#{another_project.full_path}~#{group_label.name}" }
527 528 529
    let!(:result)          { reference_filter("See #{reference}", project: project) }

    it 'points to referenced project issues page' do
530
      expect(result.css('a').first.attr('href'))
531
        .to eq urls.project_issues_url(another_project, label_name: group_label.name)
532 533 534
    end

    it 'has valid color' do
535 536
      expect(result.css('a span').first.attr('style'))
        .to match /background-color: #00ff00/
537 538 539
    end

    it 'has valid link text' do
540 541
      expect(result.css('a').first.text)
        .to eq "#{group_label.name} in #{another_project.name}"
542 543 544
    end

    it 'has valid text' do
545 546
      expect(result.text)
        .to eq "See #{group_label.name} in #{another_project.name}"
547 548 549 550 551 552 553 554 555 556 557
    end

    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"

      expect(reference_filter(act).to_html).to eq exp
    end
  end

  describe 'same project / same group_label complete reference' do
    let(:group)       { create(:group) }
558
    let(:project)     { create(:project, :public, namespace: group) }
559
    let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
560
    let(:reference)   { "#{project.full_path}~#{group_label.name}" }
561 562 563 564
    let!(:result)     { reference_filter("See #{reference}", project: project) }

    it 'points to referenced project issues page' do
      expect(result.css('a').first.attr('href'))
565
        .to eq urls.project_issues_url(project, label_name: group_label.name)
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
    end

    it 'has valid color' do
      expect(result.css('a span').first.attr('style'))
        .to match /background-color: #00ff00/
    end

    it 'has valid link text' do
      expect(result.css('a').first.text).to eq group_label.name
    end

    it 'has valid text' do
      expect(result.text).to eq "See #{group_label.name}"
    end

    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"

      expect(reference_filter(act).to_html).to eq exp
    end
  end

  describe 'same project / same group_label shorthand reference' do
    let(:group)       { create(:group) }
590
    let(:project)     { create(:project, :public, namespace: group) }
591 592 593 594 595 596
    let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
    let(:reference)   { "#{project.path}~#{group_label.name}" }
    let!(:result)     { reference_filter("See #{reference}", project: project) }

    it 'points to referenced project issues page' do
      expect(result.css('a').first.attr('href'))
597
        .to eq urls.project_issues_url(project, label_name: group_label.name)
598 599 600
    end

    it 'has valid color' do
601 602
      expect(result.css('a span').first.attr('style'))
        .to match /background-color: #00ff00/
603 604 605 606 607 608 609 610 611 612 613 614 615 616
    end

    it 'has valid link text' do
      expect(result.css('a').first.text).to eq group_label.name
    end

    it 'has valid text' do
      expect(result.text).to eq "See #{group_label.name}"
    end

    it 'ignores invalid IDs on the referenced label' do
      exp = act = "See #{invalidate_reference(reference)}"

      expect(reference_filter(act).to_html).to eq exp
617 618
    end
  end
619 620

  describe 'group context' do
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
    it 'points to the page defined in label_url_method' do
      group = create(:group)
      label = create(:group_label, group: group)
      reference = "~#{label.name}"

      result = reference_filter("See #{reference}", { project: nil, group: group, label_url_method: :group_url } )

      expect(result.css('a').first.attr('href')).to eq(urls.group_url(group, label_name: label.name))
    end

    it 'finds labels also in ancestor groups' do
      group = create(:group)
      label = create(:group_label, group: group)
      subgroup = create(:group, parent: group)
      reference = "~#{label.name}"

      result = reference_filter("See #{reference}", { project: nil, group: subgroup, label_url_method: :group_url } )

      expect(result.css('a').first.attr('href')).to eq(urls.group_url(subgroup, label_name: label.name))
    end

642 643 644 645 646 647 648 649
    it 'points to referenced project issues page' do
      project = create(:project)
      label = create(:label, project: project)
      reference = "#{project.full_path}~#{label.name}"

      result = reference_filter("See #{reference}", { project: nil, group: create(:group) } )

      expect(result.css('a').first.attr('href')).to eq(urls.project_issues_url(project, label_name: label.name))
650
      expect(result.css('a').first.text).to eq "#{label.name} in #{project.full_name}"
651 652
    end
  end
653
end