-
Notifications
You must be signed in to change notification settings - Fork 0
Add RSpec test suite with Rake task and CI workflow #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
julioalucero
wants to merge
6
commits into
main
Choose a base branch
from
add-test-suite
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
8792bc6
Add RSpec test suite with Rake task and CI workflow
julioalucero 237973d
Extend CI matrix through Ruby 4.0 and add changelog entry
julioalucero 1e8cf42
Potential fix for pull request finding
etagwerker 651624f
Potential fix for pull request finding
etagwerker 6eeb0b7
Potential fix for pull request finding
etagwerker 7427baa
Update Gemfile.lock
julioalucero File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| ruby: ['2.7', '3.0', '3.1', '3.2', '3.3', '3.4', '3.5', '4.0'] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: ${{ matrix.ruby }} | ||
| bundler-cache: true | ||
| - run: bundle exec rake | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| --require spec_helper | ||
| --color | ||
| --format documentation |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'rspec/core/rake_task' | ||
|
|
||
| RSpec::Core::RakeTask.new(:spec) | ||
|
|
||
| task default: :spec |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| RSpec.describe 'pages :post_render hook' do | ||
| # Fires the registered hook for a page with the given extension. | ||
| def trigger(extname) | ||
| page = fake_page('<html><body></body></html>', 'url' => 'https://example.com') | ||
| page.define_singleton_method(:extname) { extname } | ||
| Jekyll::Hooks.trigger(:pages, :post_render, page) | ||
| end | ||
|
|
||
| before do | ||
| allow(Jekyll::ExternalLinkAccessibility).to receive(:modify_links) | ||
| end | ||
|
|
||
| it 'rewrites html pages' do | ||
| trigger('.html') | ||
| trigger('.htm') | ||
|
|
||
| expect(Jekyll::ExternalLinkAccessibility).to have_received(:modify_links).twice | ||
| end | ||
|
|
||
| it 'skips non-html pages so xml/json/txt are not corrupted' do | ||
| trigger('.xml') | ||
| trigger('.json') | ||
| trigger('.txt') | ||
|
|
||
| expect(Jekyll::ExternalLinkAccessibility).not_to have_received(:modify_links) | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| RSpec.describe Jekyll::ExternalLinkAccessibility do | ||
| # Runs modify_links over a snippet wrapped in .post-content and hands back a | ||
| # parsed document so specs can assert on the rewritten markup. | ||
| def rewrite(inner_html, config: { 'url' => 'https://example.com' }, wrapper: 'post-content') | ||
| html = "<html><body><div class='#{wrapper}'>#{inner_html}</div></body></html>" | ||
| page = fake_page(html, config) | ||
| described_class.modify_links(page) | ||
| Nokogiri::HTML5(page.output) | ||
| end | ||
|
|
||
| describe '.host_for' do | ||
| it 'downcases the host' do | ||
| expect(described_class.host_for('https://Example.COM/path')).to eq('example.com') | ||
| end | ||
|
|
||
| it 'strips a leading www.' do | ||
| expect(described_class.host_for('https://www.example.com')).to eq('example.com') | ||
| end | ||
|
|
||
| it 'returns nil for a blank or nil url' do | ||
| expect(described_class.host_for(nil)).to be_nil | ||
| expect(described_class.host_for('')).to be_nil | ||
| end | ||
|
|
||
| it 'returns nil on an invalid uri' do | ||
| expect(described_class.host_for('http://[invalid')).to be_nil | ||
| end | ||
| end | ||
|
|
||
| describe '.external_link?' do | ||
| let(:site_host) { 'example.com' } | ||
|
|
||
| it 'is true for another host over http, https or protocol-relative' do | ||
| expect(described_class.external_link?('http://other.com', site_host)).to be(true) | ||
| expect(described_class.external_link?('https://other.com', site_host)).to be(true) | ||
| expect(described_class.external_link?('//other.com/page', site_host)).to be(true) | ||
| end | ||
|
|
||
| it 'is false for the same host, including the www variant' do | ||
| expect(described_class.external_link?('https://example.com/blog', site_host)).to be(false) | ||
| expect(described_class.external_link?('https://www.example.com/blog', site_host)).to be(false) | ||
| end | ||
|
|
||
| it 'is false for relative and anchor links' do | ||
| expect(described_class.external_link?('/blog/post', site_host)).to be(false) | ||
| expect(described_class.external_link?('#section', site_host)).to be(false) | ||
| end | ||
|
|
||
| it 'is true when the scheme matches but the host cannot be parsed' do | ||
| expect(described_class.external_link?('http://[invalid', site_host)).to be(true) | ||
| end | ||
| end | ||
|
|
||
| describe '.modify_links' do | ||
| it 'rewrites anchors inside .post-content' do | ||
| link = rewrite("<a href='https://other.com'>read</a>").at_css('.post-content a') | ||
|
|
||
| expect(link['target']).to eq('_blank') | ||
| expect(link['title']).to eq('Opens a new window') | ||
| expect(link.at_css('i.icon-external-link')).not_to be_nil | ||
| expect(link.text).to include('opens a new window') | ||
| end | ||
|
|
||
| it 'rewrites anchors inside .post-excerpt' do | ||
| link = rewrite("<a href='https://other.com'>read</a>", wrapper: 'post-excerpt') | ||
| .at_css('.post-excerpt a') | ||
|
|
||
| expect(link['target']).to eq('_blank') | ||
| end | ||
|
|
||
| it 'leaves anchors outside those containers untouched' do | ||
| html = "<html><body><nav><a href='https://other.com'>home</a></nav></body></html>" | ||
| page = fake_page(html, 'url' => 'https://example.com') | ||
| described_class.modify_links(page) | ||
| link = Nokogiri::HTML5(page.output).at_css('nav a') | ||
|
|
||
| expect(link['target']).to be_nil | ||
| expect(link.at_css('i.icon-external-link')).to be_nil | ||
| end | ||
|
|
||
| it 'adds rel only to external links' do | ||
| external = rewrite("<a href='https://other.com'>x</a>").at_css('a') | ||
| internal = rewrite("<a href='https://example.com/blog'>x</a>").at_css('a') | ||
|
|
||
| expect(external['rel']).to eq('external nofollow noopener noreferrer') | ||
| expect(internal['rel']).to be_nil | ||
| end | ||
|
|
||
| it 'skips links with no href, empty href, anchors or data-no-external' do | ||
| doc = rewrite(<<~HTML) | ||
| <a>no href</a> | ||
| <a href=''>empty</a> | ||
| <a href='#top'>anchor</a> | ||
| <a href='https://other.com' data-no-external='true'>opted out</a> | ||
| HTML | ||
|
|
||
| doc.css('.post-content a').each do |a| | ||
| expect(a['target']).to be_nil | ||
| expect(a.at_css('i.icon-external-link')).to be_nil | ||
| end | ||
| end | ||
|
|
||
| it 'does not overwrite an existing target, title or rel' do | ||
| link = rewrite( | ||
| "<a href='https://other.com' target='_self' title='Keep me' rel='ugc'>x</a>" | ||
| ).at_css('a') | ||
|
|
||
| expect(link['target']).to eq('_self') | ||
| expect(link['title']).to eq('Keep me') | ||
| expect(link['rel']).to eq('ugc') | ||
| end | ||
|
|
||
| it 'honors config overrides for rel, target and title' do | ||
| config = { | ||
| 'url' => 'https://example.com', | ||
| 'external_links' => { | ||
| 'rel' => 'nofollow', | ||
| 'target' => '_top', | ||
| 'title' => 'External site' | ||
| } | ||
| } | ||
| link = rewrite("<a href='https://other.com'>x</a>", config: config).at_css('a') | ||
|
|
||
| expect(link['rel']).to eq('nofollow') | ||
| expect(link['target']).to eq('_top') | ||
| expect(link['title']).to eq('External site') | ||
| end | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'jekyll-external-link-accessibility' | ||
|
|
||
| module SpecHelpers | ||
| # The gem only touches page.output, page.output= and page.site.config, so a | ||
| # couple of Structs are enough to stand in for a real Jekyll page. | ||
| def fake_page(html, config = {}) | ||
| site = Struct.new(:config).new(config) | ||
| Struct.new(:output, :site).new(html, site) | ||
| end | ||
| end | ||
|
|
||
| RSpec.configure do |config| | ||
| config.include SpecHelpers | ||
|
|
||
| config.expect_with :rspec do |expectations| | ||
| expectations.include_chain_clauses_in_custom_matcher_descriptions = true | ||
| end | ||
|
|
||
| config.mock_with :rspec do |mocks| | ||
| mocks.verify_partial_doubles = true | ||
| end | ||
|
|
||
| config.disable_monkey_patching! | ||
| config.order = :random | ||
| Kernel.srand config.seed | ||
| end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.