Improves detection of WP Version, Plugins etc by checking 404

This commit is contained in:
erwanlr
2019-10-31 19:56:05 +00:00
parent 85aa9f61cd
commit 6b5e016770
44 changed files with 456 additions and 146 deletions

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
describe WPScan::Finders::MainTheme::CssStyleIn404Page do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'css_style_in_404_page') }
# This stuff is just a child class of CssStyleInHomepage (using the error_404_res rather than homepage_res)
# which already has a spec
end

View File

@@ -1,10 +1,10 @@
# frozen_string_literal: true
describe WPScan::Finders::MainTheme::CssStyle do
describe WPScan::Finders::MainTheme::CssStyleInHomepage do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'css_style') }
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'css_style_in_homepage') }
describe '#passive' do
after do
@@ -33,7 +33,7 @@ describe WPScan::Finders::MainTheme::CssStyle do
@expected = WPScan::Model::Theme.new(
'twentyfifteen',
target,
found_by: 'Css Style (Passive Detection)',
found_by: 'Css Style In Homepage (Passive Detection)',
confidence: 70,
style_url: 'http://wp.lab/wp-content/themes/twentyfifteen/style.css?ver=4.1.1'
)
@@ -47,7 +47,7 @@ describe WPScan::Finders::MainTheme::CssStyle do
@expected = WPScan::Model::Theme.new(
'custom',
target,
found_by: 'Css Style (Passive Detection)',
found_by: 'Css Style In Homepage (Passive Detection)',
confidence: 70,
style_url: 'http://wp.lab/wp-content/themes/custom/style.css'
)

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
describe WPScan::Finders::MainTheme::UrlsIn404Page do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'urls_in_404_page') }
# This stuff is just a child class of URLsInHomepage (using the error_404_res rather than homepage_res)
# which already has a spec
end

View File

@@ -6,7 +6,8 @@ describe WPScan::Finders::MainTheme::UrlsInHomepage do
let(:url) { 'http://wp.lab/' }
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'urls_in_homepage') }
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
it_behaves_like 'App::Finders::WpItems::UrlsInPage' do
let(:page_url) { url }
let(:type) { 'themes' }
let(:uniq_links) { false }
let(:uniq_codes) { false }
@@ -18,6 +19,8 @@ describe WPScan::Finders::MainTheme::UrlsInHomepage do
before do
stub_request(:get, /.*.css/)
stub_request(:get, target.url).to_return(body: File.read(fixtures.join('found.html')))
allow(target).to receive(:content_dir).and_return('wp-content')
end
it 'returns the expected Themes' do

View File

@@ -7,32 +7,50 @@ describe WPScan::Finders::MainTheme::WooFrameworkMetaGenerator do
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'woo_framework_meta_generator') }
describe '#passive' do
after do
stub_request(:get, url).to_return(body: File.read(fixtures.join(@file)))
expect(finder.passive).to eql @expected
before do
stub_request(:get, url).to_return(body: File.read(fixtures.join(homepage_fixture)))
stub_request(:get, ERROR_404_URL_PATTERN).to_return(body: File.read(fixtures.join(error_404_fixture)))
end
context 'when no Woo generator' do
let(:homepage_fixture) { 'no_woo_generator.html' }
let(:error_404_fixture) { 'no_woo_generator.html' }
it 'returns nil' do
@file = 'no_woo_generator.html'
@expected = nil
expect(finder.passive).to eql nil
end
end
context 'when Woo generator' do
before do
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
allow(target).to receive(:content_dir).and_return('wp-content')
stub_request(:get, "#{url}wp-content/themes/Merchant/style.css")
end
it 'returns the expected theme' do
@file = 'woo_generator.html'
@expected = WPScan::Model::Theme.new(
'Merchant', target,
found_by: 'Woo Framework Meta Generator (Passive Detection)',
confidence: 80
)
context 'from the homepage' do
let(:homepage_fixture) { 'woo_generator.html' }
let(:error_404_fixture) { 'no_woo_generator.html' }
it 'returns the expected theme' do
expect(finder.passive).to eql WPScan::Model::Theme.new(
'Merchant', target,
found_by: 'Woo Framework Meta Generator (Passive Detection)',
confidence: 80
)
end
end
context 'from the 404 page' do
let(:homepage_fixture) { 'no_woo_generator.html' }
let(:error_404_fixture) { 'woo_generator.html' }
it 'returns the expected theme' do
expect(finder.passive).to eql WPScan::Model::Theme.new(
'Merchant', target,
found_by: 'Woo Framework Meta Generator (Passive Detection)',
confidence: 80
)
end
end
end
end

View File

@@ -8,7 +8,7 @@ describe WPScan::Finders::MainTheme::Base do
describe '#finders' do
it 'contains the expected finders' do
expect(main_theme.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[CssStyle WooFrameworkMetaGenerator UrlsInHomepage]
.to eq %w[CssStyleInHomepage CssStyleIn404Page WooFrameworkMetaGenerator UrlsInHomepage UrlsIn404Page]
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
describe WPScan::Finders::Plugins::UrlsIn404Page do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'https://wp.lab/' }
let(:fixtures) { FINDERS_FIXTURES.join('plugins', 'urls_in_404_page') }
# This stuff is just a child class of URLsInHomepage (using the error_404_res rather than homepage_res)
# which already has a spec
end

View File

@@ -8,7 +8,8 @@ describe WPScan::Finders::Plugins::UrlsInHomepage do
before { target.scope << 'sub.lab' }
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
it_behaves_like 'App::Finders::WpItems::UrlsInPage' do
let(:page_url) { url }
let(:type) { 'plugins' }
let(:uniq_links) { true }
let(:uniq_codes) { true }

View File

@@ -8,7 +8,7 @@ describe WPScan::Finders::Plugins::Base do
describe '#finders' do
it 'contains the expected finders' do
expect(plugins.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[UrlsInHomepage HeaderPattern Comment Xpath BodyPattern JavascriptVar KnownLocations]
.to eq %w[UrlsInHomepage UrlsIn404Page HeaderPattern Comment Xpath BodyPattern JavascriptVar KnownLocations]
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
describe WPScan::Finders::Themes::UrlsIn404Page do
subject(:finder) { described_class.new(target) }
let(:target) { WPScan::Target.new(url) }
let(:url) { 'http://wp.lab/' }
let(:fixtures) { FINDERS_FIXTURES.join('themes', 'urls_in_404_page') }
# This stuff is just a child class of URLsInHomepage (using the error_404_res rather than homepage_res)
# which already has a spec
end

View File

@@ -8,7 +8,8 @@ describe WPScan::Finders::Themes::UrlsInHomepage do
# before { target.scope << 'sub.lab' }
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
it_behaves_like 'App::Finders::WpItems::UrlsInPage' do
let(:page_url) { url }
let(:type) { 'themes' }
let(:uniq_links) { true }
let(:uniq_codes) { true }

View File

@@ -8,7 +8,7 @@ describe WPScan::Finders::Themes::Base do
describe '#finders' do
it 'contains the expected finders' do
expect(themes.finders.map { |f| f.class.to_s.demodulize })
.to eq %w[UrlsInHomepage KnownLocations]
.to eq %w[UrlsInHomepage UrlsIn404Page KnownLocations]
end
end
end

View File

@@ -87,6 +87,8 @@ describe WPScan::Finders::Users::WpJsonApi do
describe '#api_url' do
let(:fixtures) { super().join('api_url') }
before { allow(target).to receive(:sub_dir).and_return(false) }
context 'when url in the homepage' do
{
in_scope: 'https://wp.lab/wp-json/wp/v2/users/',
@@ -100,7 +102,7 @@ describe WPScan::Finders::Users::WpJsonApi do
end
context 'when subdir' do
before { allow(target).to receive(:subdir).and_return('cms') }
before { allow(target).to receive(:sub_dir).and_return('cms') }
{
in_scope_subdir: 'https://wp.lab/cms/wp-json/wp/v2/users/',

View File

@@ -38,13 +38,21 @@ WPScan::DB::DynamicFinders::Plugin.versions_finders_configs.each do |slug, confi
end
end
let(:stubbed_response) { { body: 'aa' } }
before { allow(target).to receive(:content_dir).and_return('wp-content') }
describe '#passive', slow: true do
before do
stub_request(:get, target.url).to_return(stubbed_response)
if defined?(stubbed_homepage_res)
stub_request(:get, target.url).to_return(stubbed_homepage_res)
else
stub_request(:get, target.url)
end
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
if defined?(stubbed_404_res)
stub_request(:get, ERROR_404_URL_PATTERN).to_return(stubbed_404_res)
else
stub_request(:get, ERROR_404_URL_PATTERN)
end
end
if config['path']
@@ -56,27 +64,63 @@ WPScan::DB::DynamicFinders::Plugin.versions_finders_configs.each do |slug, confi
else
context 'when no PATH' do
context 'when the version is detected' do
let(:stubbed_response) do
df_stubbed_response(
fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
finder_super_class
)
context 'from the homepage' do
let(:ie_url) { target.url }
let(:stubbed_homepage_res) do
df_stubbed_response(
fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
finder_super_class
)
end
it 'returns the expected version/s' do
found = [*finder.passive]
expect(found).to_not be_empty
found.each_with_index do |version, index|
expected_version = expected.at(index)
expected_ie = expected_version['interesting_entries'].map do |ie|
ie.gsub(target.url + ',', ie_url + ',')
end
expect(version).to be_a WPScan::Model::Version
expect(version.number).to eql expected_version['number'].to_s
expect(version.found_by).to eql expected_version['found_by']
expect(version.interesting_entries).to match_array expected_ie
expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
end
end
end
it 'returns the expected version/s from the homepage' do
found = [*finder.passive]
context 'from the 404' do
let(:ie_url) { target.error_404_url }
let(:stubbed_404_res) do
df_stubbed_response(
fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
finder_super_class
)
end
expect(found).to_not be_empty
it 'returns the expected version/s' do
found = [*finder.passive]
found.each_with_index do |version, index|
expected_version = expected.at(index)
expect(found).to_not be_empty
expect(version).to be_a WPScan::Model::Version
expect(version.number).to eql expected_version['number'].to_s
expect(version.found_by).to eql expected_version['found_by']
expect(version.interesting_entries).to match_array expected_version['interesting_entries']
found.each_with_index do |version, index|
expected_version = expected.at(index)
expected_ie = expected_version['interesting_entries'].map do |ie|
ie.gsub(target.url + ',', ie_url + ',')
end
expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
expect(version).to be_a WPScan::Model::Version
expect(version.number).to eql expected_version['number'].to_s
expect(version.found_by).to eql expected_version['found_by']
expect(version.interesting_entries).to match_array expected_ie
expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
end
end
end
end
@@ -91,11 +135,10 @@ WPScan::DB::DynamicFinders::Plugin.versions_finders_configs.each do |slug, confi
end
describe '#aggressive' do
let(:fixtures) { super().join(slug, finder_class.underscore) }
let(:fixtures) { super().join(slug, finder_class.underscore) }
let(:stubbed_response) { { body: 'aa' } }
before do
expect(target).to receive(:content_dir).at_least(1).and_return('wp-content')
stub_request(:get, plugin.url(config['path'])).to_return(stubbed_response) if config['path']
end

View File

@@ -38,8 +38,6 @@ WPScan::DB::DynamicFinders::Theme.versions_finders_configs.each do |slug, config
end
end
let(:stubbed_response) { { body: 'aa' } }
before do
allow(target).to receive(:content_dir).and_return('wp-content')
@@ -48,7 +46,19 @@ WPScan::DB::DynamicFinders::Theme.versions_finders_configs.each do |slug, config
end
describe '#passive', slow: true do
before { stub_request(:get, target.url).to_return(stubbed_response) }
before do
if defined?(stubbed_homepage_res)
stub_request(:get, target.url).to_return(stubbed_homepage_res)
else
stub_request(:get, target.url)
end
if defined?(stubbed_404_res)
stub_request(:get, ERROR_404_URL_PATTERN).to_return(stubbed_404_res)
else
stub_request(:get, ERROR_404_URL_PATTERN)
end
end
if config['path']
context 'when PATH' do
@@ -59,27 +69,63 @@ WPScan::DB::DynamicFinders::Theme.versions_finders_configs.each do |slug, config
else
context 'when no PATH' do
context 'when the version is detected' do
let(:stubbed_response) do
df_stubbed_response(
fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
finder_super_class
)
context 'from the homepage' do
let(:ie_url) { target.url }
let(:stubbed_homepage_res) do
df_stubbed_response(
fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
finder_super_class
)
end
it 'returns the expected version/s' do
found = [*finder.passive]
expect(found).to_not be_empty
found.each_with_index do |version, index|
expected_version = expected.at(index)
expected_ie = expected_version['interesting_entries'].map do |ie|
ie.gsub(target.url + ',', ie_url + ',')
end
expect(version).to be_a WPScan::Model::Version
expect(version.number).to eql expected_version['number'].to_s
expect(version.found_by).to eql expected_version['found_by']
expect(version.interesting_entries).to match_array expected_ie
expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
end
end
end
it 'returns the expected version/s from the homepage' do
found = [*finder.passive]
context 'from the 404' do
let(:ie_url) { target.error_404_url }
let(:stubbed_404_res) do
df_stubbed_response(
fixtures.join("#{finder_super_class.underscore}_passive_all.html"),
finder_super_class
)
end
expect(found).to_not be_empty
it 'returns the expected version/s' do
found = [*finder.passive]
found.each_with_index do |version, index|
expected_version = expected.at(index)
expect(found).to_not be_empty
expect(version).to be_a WPScan::Model::Version
expect(version.number).to eql expected_version['number'].to_s
expect(version.found_by).to eql expected_version['found_by']
expect(version.interesting_entries).to match_array expected_version['interesting_entries']
found.each_with_index do |version, index|
expected_version = expected.at(index)
expected_ie = expected_version['interesting_entries'].map do |ie|
ie.gsub(target.url + ',', ie_url + ',')
end
expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
expect(version).to be_a WPScan::Model::Version
expect(version.number).to eql expected_version['number'].to_s
expect(version.found_by).to eql expected_version['found_by']
expect(version.interesting_entries).to match_array expected_ie
expect(version.confidence).to eql expected_version['confidence'] if expected_version['confidence']
end
end
end
end
@@ -94,7 +140,8 @@ WPScan::DB::DynamicFinders::Theme.versions_finders_configs.each do |slug, config
end
describe '#aggressive' do
let(:fixtures) { super().join(slug, finder_class.underscore) }
let(:fixtures) { super().join(slug, finder_class.underscore) }
let(:stubbed_response) { { body: 'aa' } }
before do
stub_request(:get, theme.url(config['path'])).to_return(stubbed_response) if config['path']

View File

@@ -25,7 +25,10 @@ WPScan::DB::DynamicFinders::Wordpress.versions_finders_configs.each do |finder_c
let(:stubbed_response) { { body: '' } }
describe '#passive' do
before { stub_request(:get, target.url).to_return(stubbed_response) }
before do
stub_request(:get, target.url).to_return(stubbed_response)
stub_request(:get, ERROR_404_URL_PATTERN)
end
if config['path']
context 'when PATH' do
@@ -66,7 +69,7 @@ WPScan::DB::DynamicFinders::Wordpress.versions_finders_configs.each do |finder_c
let(:fixtures) { super().join(finder_class.underscore) }
before do
allow(target).to receive(:sub_dir).and_return(nil)
allow(target).to receive(:sub_dir).and_return(false)
stub_request(:get, target.url(config['path'])).to_return(stubbed_response) if config['path']
end

View File

@@ -5,6 +5,6 @@ require 'shared_examples/views/wp_version'
require 'shared_examples/views/main_theme'
require 'shared_examples/views/enumeration'
require 'shared_examples/target/platform/wordpress'
require 'shared_examples/finders/wp_items/urls_in_homepage'
require 'shared_examples/finders/wp_items/urls_in_page'
require 'shared_examples/references'
require 'shared_examples/dynamic_finders/wp_items'

View File

@@ -16,13 +16,15 @@ shared_examples WPScan::Finders::DynamicFinder::WpItems::Finder do
describe '#passive' do
before do
stub_request(:get, target.url).to_return(body: body)
stub_request(:get, target.url).to_return(body: homepage_body)
stub_request(:get, ERROR_404_URL_PATTERN).to_return(body: error_404_body)
allow(target).to receive(:content_dir).and_return('wp-content')
end
context 'when no matches' do
let(:body) { '' }
let(:homepage_body) { '' }
let(:error_404_body) { '' }
it 'returns an empty array' do
expect(finder.passive).to eql([])
@@ -30,9 +32,7 @@ shared_examples WPScan::Finders::DynamicFinder::WpItems::Finder do
end
context 'when matches' do
let(:body) { File.read(passive_fixture) }
it 'contains the expected items' do
let(:expected_items) do
expected = []
finder.passive_configs.each do |slug, configs|
@@ -48,7 +48,25 @@ shared_examples WPScan::Finders::DynamicFinder::WpItems::Finder do
end
end
expect(finder.passive).to match_array(expected.map { |item| eql(item) })
expected
end
context 'from the homepage' do
let(:homepage_body) { File.read(passive_fixture) }
let(:error_404_body) { '' }
it 'contains the expected items' do
expect(finder.passive).to match_array(expected_items.map { |item| eql(item) })
end
end
context 'from the 404' do
let(:homepage_body) { '' }
let(:error_404_body) { File.read(passive_fixture) }
it 'contains the expected items' do
expect(finder.passive).to match_array(expected_items.map { |item| eql(item) })
end
end
end
end

View File

@@ -1,8 +1,8 @@
# frozen_string_literal: true
shared_examples 'App::Finders::WpItems::URLsInHomepage' do
shared_examples 'App::Finders::WpItems::UrlsInPage' do
before do
stub_request(:get, finder.target.url).to_return(body: File.read(fixtures.join(file)))
stub_request(:get, page_url).to_return(body: File.read(fixtures.join(file)))
end
describe '#items_from_links' do

View File

@@ -7,14 +7,17 @@ shared_examples WPScan::Target::Platform::WordPress do
let(:fixtures) { FIXTURES.join('target', 'platform', 'wordpress') }
describe '#wordpress?' do
describe '#wordpress?, wordpress_from_meta_comments_or_scripts?' do
let(:fixtures) { super().join('detection') }
before do
stub_request(:get, target.url).to_return(body: File.read(fixtures.join("#{homepage}.html")))
stub_request(:get, ERROR_404_URL_PATTERN).to_return(body: File.read(fixtures.join("#{page_404}.html")))
end
context 'when pattern/s in the homepage' do
let(:page_404) { 'not_wp' }
%w[default wp_includes only_scripts meta_generator comments mu_plugins wp_admin wp_json_oembed].each do |file|
context "when a wordpress page (#{file}.html)" do
let(:homepage) { file }
@@ -29,39 +32,55 @@ shared_examples WPScan::Target::Platform::WordPress do
context 'when no clues in the homepage' do
let(:homepage) { 'not_wp' }
context 'when only passive detection mode' do
it 'returns false' do
expect(subject.wordpress?(:passive)).to be false
context 'when pattern/s in the 404 page' do
%w[default wp_includes only_scripts meta_generator comments mu_plugins wp_admin wp_json_oembed].each do |file|
context "when a wordpress page (#{file}.html)" do
let(:page_404) { file }
it 'returns true' do
expect(subject.wordpress?(:mixed)).to be true
end
end
end
end
context 'when mixed or aggressive detection modes' do
context 'when wp-admin/install.php and wp-login.php not there' do
context 'when no clues in the 404 page' do
let(:page_404) { 'not_wp' }
context 'when only passive detection mode' do
it 'returns false' do
%w[wp-admin/install.php wp-login.php].each do |path|
stub_request(:get, target.url(path)).to_return(status: 404)
expect(subject.wordpress?(:passive)).to be false
end
end
context 'when mixed or aggressive detection modes' do
context 'when wp-admin/install.php and wp-login.php not there' do
it 'returns false' do
%w[wp-admin/install.php wp-login.php].each do |path|
stub_request(:get, target.url(path)).to_return(status: 404)
end
expect(subject.wordpress?(:mixed)).to be false
end
expect(subject.wordpress?(:mixed)).to be false
end
end
context 'when wp-admin/install.php is matching a WP install' do
it 'returns true' do
stub_request(:get, target.url('wp-admin/install.php'))
.to_return(body: File.read(fixtures.join('wp-admin-install.php')))
context 'when wp-admin/install.php is matching a WP install' do
it 'returns true' do
stub_request(:get, target.url('wp-admin/install.php'))
.to_return(body: File.read(fixtures.join('wp-admin-install.php')))
expect(subject.wordpress?(:mixed)).to be true
expect(subject.wordpress?(:mixed)).to be true
end
end
end
context 'when wp-admin/install.php not there but wp-login.php is matching a WP install' do
it 'returns true' do
stub_request(:get, target.url('wp-admin/install.php')).to_return(status: 404)
stub_request(:get, target.url('wp-login.php'))
.to_return(body: File.read(fixtures.join('wp-login.php')))
context 'when wp-admin/install.php not there but wp-login.php is matching a WP install' do
it 'returns true' do
stub_request(:get, target.url('wp-admin/install.php')).to_return(status: 404)
stub_request(:get, target.url('wp-login.php'))
.to_return(body: File.read(fixtures.join('wp-login.php')))
expect(subject.wordpress?(:mixed)).to be true
expect(subject.wordpress?(:mixed)).to be true
end
end
end
end

View File

@@ -4,6 +4,9 @@ shared_examples 'WordPress::CustomDirectories' do
let(:fixtures) { super().join('custom_directories') }
describe '#content_dir' do
# Stub the error_404_res to make it easier to test
before { stub_request(:get, ERROR_404_URL_PATTERN) }
{
default: 'wp-content', https: 'wp-content', custom_w_spaces: 'custom content spaces',
relative_one: 'wp-content', relative_two: 'wp-content', cache: 'wp-content',
@@ -45,9 +48,9 @@ shared_examples 'WordPress::CustomDirectories' do
end
end
context 'when not found via the homepage' do
context 'when not found via the homepage or 404' do
before do
stub_request(:get, target.url).to_return(body: '')
stub_request(:get, target.url)
expect(target).to receive(:default_content_dir_exists?).and_return(dir_exist)
end
@@ -123,6 +126,9 @@ shared_examples 'WordPress::CustomDirectories' do
end
describe '#sub_dir' do
# Stub the error_404_res to make it easier to test
before { stub_request(:get, ERROR_404_URL_PATTERN) }
{ default: false, with_sub_dir: 'wp', relative_two_sub_dir: 'cms' }.each do |file, expected|
it "returns #{expected} for #{file}.html" do
fixture = File.join(fixtures, "#{file}.html")

View File

@@ -102,5 +102,6 @@ SPECS = Pathname.new(__FILE__).dirname
FIXTURES = SPECS.join('fixtures')
FINDERS_FIXTURES = FIXTURES.join('finders')
DYNAMIC_FINDERS_FIXTURES = FIXTURES.join('dynamic_finders')
ERROR_404_URL_PATTERN = %r{/[a-z\d]{7}\.html$}
redefine_constant(:DB_DIR, FIXTURES.join('db'))