You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

configuration_spec.rb 17 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. # frozen_string_literal: true
  2. require 'spec_helper'
  3. require 'yaml'
  4. module Cucumber
  5. module Cli
  6. module ExposesOptions
  7. attr_reader :options
  8. end
  9. describe Configuration do
  10. def given_cucumber_yml_defined_as(hash_or_string)
  11. allow(File).to receive(:exist?) { true }
  12. cucumber_yml = hash_or_string.is_a?(Hash) ? hash_or_string.to_yaml : hash_or_string
  13. allow(IO).to receive(:read).with('cucumber.yml') { cucumber_yml }
  14. end
  15. def given_the_following_files(*files)
  16. allow(File).to receive(:directory?) { true }
  17. allow(File).to receive(:file?) { true }
  18. allow(Dir).to receive(:[]) { files }
  19. end
  20. before(:each) do
  21. allow(File).to receive(:exist?) { false } # Meaning, no cucumber.yml exists
  22. allow(Kernel).to receive(:exit)
  23. end
  24. def config
  25. @config ||= Configuration.new(@out = StringIO.new, @error = StringIO.new).extend(ExposesOptions)
  26. end
  27. def reset_config
  28. @config = nil
  29. end
  30. attr_reader :out, :error
  31. it 'uses the default profile when no profile is defined' do
  32. given_cucumber_yml_defined_as('default' => '--require some_file')
  33. config.parse!(%w[--format progress])
  34. expect(config.options[:require]).to include('some_file')
  35. end
  36. context '--profile' do
  37. include RSpec::WorkInProgress
  38. it 'expands args from profiles in the cucumber.yml file' do
  39. given_cucumber_yml_defined_as('bongo' => '--require from/yml')
  40. config.parse!(%w[--format progress --profile bongo])
  41. expect(config.options[:formats]).to eq [['progress', {}, out]]
  42. expect(config.options[:require]).to eq ['from/yml']
  43. end
  44. it 'expands args from the default profile when no flags are provided' do
  45. given_cucumber_yml_defined_as('default' => '--require from/yml')
  46. config.parse!([])
  47. expect(config.options[:require]).to eq ['from/yml']
  48. end
  49. it 'allows --strict to be set by a profile' do
  50. given_cucumber_yml_defined_as('bongo' => '--strict')
  51. config.parse!(%w[--profile bongo])
  52. expect(config.options[:strict].strict?(:undefined)).to be true
  53. expect(config.options[:strict].strict?(:pending)).to be true
  54. expect(config.options[:strict].strict?(:flaky)).to be true
  55. end
  56. it 'allows --strict from a profile to be selectively overridden' do
  57. given_cucumber_yml_defined_as('bongo' => '--strict')
  58. config.parse!(%w[--profile bongo --no-strict-flaky])
  59. expect(config.options[:strict].strict?(:undefined)).to be true
  60. expect(config.options[:strict].strict?(:pending)).to be true
  61. expect(config.options[:strict].strict?(:flaky)).to be false
  62. end
  63. it 'parses ERB syntax in the cucumber.yml file' do
  64. given_cucumber_yml_defined_as("---\ndefault: \"<%=\"--require some_file\"%>\"\n")
  65. config.parse!([])
  66. expect(config.options[:require]).to include('some_file')
  67. end
  68. it 'parses ERB in cucumber.yml that makes uses nested ERB sessions' do
  69. given_cucumber_yml_defined_as(<<ERB_YML)
  70. <%= ERB.new({'standard' => '--require some_file'}.to_yaml).result %>
  71. <%= ERB.new({'enhanced' => '--require other_file'}.to_yaml).result %>
  72. ERB_YML
  73. config.parse!(%w[-p standard])
  74. expect(config.options[:require]).to include('some_file')
  75. end
  76. it 'provides a helpful error message when a specified profile does not exists in cucumber.yml' do
  77. given_cucumber_yml_defined_as('default' => '--require from/yml', 'json_report' => '--format json')
  78. expected_message = <<-END_OF_MESSAGE
  79. Could not find profile: 'i_do_not_exist'
  80. Defined profiles in cucumber.yml:
  81. * default
  82. * json_report
  83. END_OF_MESSAGE
  84. expect { config.parse!(%w[--profile i_do_not_exist]) }.to raise_error(ProfileNotFound, expected_message)
  85. end
  86. it 'allows profiles to be defined in arrays' do
  87. given_cucumber_yml_defined_as('foo' => ['-f', 'progress'])
  88. config.parse!(%w[--profile foo])
  89. expect(config.options[:formats]).to eq [['progress', {}, out]]
  90. end
  91. it 'disregards default STDOUT formatter defined in profile when another is passed in (via cmd line)' do
  92. given_cucumber_yml_defined_as('foo' => %w[--format pretty])
  93. config.parse!(%w[--format progress --profile foo])
  94. expect(config.options[:formats]).to eq [['progress', {}, out]]
  95. end
  96. ['--no-profile', '-P'].each do |flag|
  97. context 'when none is specified with #{flag}' do # rubocop:disable Lint/InterpolationCheck
  98. it 'disables profiles' do
  99. given_cucumber_yml_defined_as('default' => '-v --require file_specified_in_default_profile.rb')
  100. config.parse!("#{flag} --require some_file.rb".split(' '))
  101. expect(config.options[:require]).to eq ['some_file.rb']
  102. end
  103. it 'notifies the user that the profiles are being disabled' do
  104. given_cucumber_yml_defined_as('default' => '-v')
  105. config.parse!("#{flag} --require some_file.rb".split(' '))
  106. expect(out.string).to match(/Disabling profiles.../)
  107. end
  108. end
  109. end
  110. it 'issues a helpful error message when a specified profile exists but is nil or blank' do
  111. [nil, ' '].each do |bad_input|
  112. given_cucumber_yml_defined_as('foo' => bad_input)
  113. expected_error = /The 'foo' profile in cucumber.yml was blank. Please define the command line arguments for the 'foo' profile in cucumber.yml./
  114. expect { config.parse!(%w[--profile foo]) }.to raise_error(expected_error)
  115. end
  116. end
  117. it 'issues a helpful error message when no YAML file exists and a profile is specified' do
  118. expect(File).to receive(:exist?).with('cucumber.yml') { false }
  119. expected_error = /cucumber\.yml was not found/
  120. expect { config.parse!(%w[--profile i_do_not_exist]) }.to raise_error(expected_error)
  121. end
  122. it 'issues a helpful error message when cucumber.yml is blank or malformed' do
  123. expected_error_message = /cucumber\.yml was found, but was blank or malformed. Please refer to cucumber's documentation on correct profile usage./
  124. ['', 'sfsadfs', "--- \n- an\n- array\n", '---dddfd'].each do |bad_input|
  125. given_cucumber_yml_defined_as(bad_input)
  126. expect { config.parse!([]) }.to raise_error(expected_error_message)
  127. reset_config
  128. end
  129. end
  130. it 'issues a helpful error message when cucumber.yml can not be parsed' do
  131. expected_error_message = /cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentation on correct profile usage./
  132. given_cucumber_yml_defined_as('input that causes an exception in YAML loading')
  133. expect(YAML).to receive(:load).and_raise(ArgumentError)
  134. expect { config.parse!([]) }.to raise_error(expected_error_message)
  135. end
  136. it 'issues a helpful error message when cucumber.yml can not be parsed by ERB' do
  137. expected_error_message = /cucumber.yml was found, but could not be parsed with ERB. Please refer to cucumber's documentation on correct profile usage./
  138. given_cucumber_yml_defined_as('<% this_fails %>')
  139. expect { config.parse!([]) }.to raise_error(expected_error_message)
  140. end
  141. end
  142. it 'accepts --dry-run option' do
  143. config.parse!(%w[--dry-run])
  144. expect(config.options[:dry_run]).to be true
  145. end
  146. it 'implies --no-duration with --dry-run option' do
  147. config.parse!(%w[--dry-run])
  148. expect(config.options[:duration]).to be false
  149. end
  150. it 'accepts --no-source option' do
  151. config.parse!(%w[--no-source])
  152. expect(config.options[:source]).to be false
  153. end
  154. it 'accepts --no-snippets option' do
  155. config.parse!(%w[--no-snippets])
  156. expect(config.options[:snippets]).to be false
  157. end
  158. it 'sets snippets and source and duration to false with --quiet option' do
  159. config.parse!(%w[--quiet])
  160. expect(config.options[:snippets]).to be false
  161. expect(config.options[:source]).to be false
  162. expect(config.options[:duration]).to be false
  163. end
  164. it 'sets duration to false with --no-duration' do
  165. config.parse!(%w[--no-duration])
  166. expect(config.options[:duration]).to be false
  167. end
  168. it 'accepts --verbose option' do
  169. config.parse!(%w[--verbose])
  170. expect(config.options[:verbose]).to be true
  171. end
  172. it 'uses the pretty formatter to stdout when no formatter is defined' do
  173. config.parse!([])
  174. expect(config.formats).to eq [['pretty', {}, out]]
  175. end
  176. it 'adds the default formatter when no other formatter is defined with --publish' do
  177. config.parse!(['--publish'])
  178. expect(config.formats).to eq [
  179. ['pretty', {}, out],
  180. ['message', {}, 'https://messages.cucumber.io/api/reports -X GET']
  181. ]
  182. end
  183. it 'does not add the default formatter when a formatter is defined with --publish' do
  184. config.parse!(['--publish', '--format', 'progress'])
  185. expect(config.formats).to eq [
  186. ['progress', {}, out],
  187. ['message', {}, 'https://messages.cucumber.io/api/reports -X GET']
  188. ]
  189. end
  190. it 'does not add the default formatter with --format message' do
  191. config.parse!(['--format', 'message'])
  192. expect(config.formats).to eq [
  193. ['message', {}, out]
  194. ]
  195. end
  196. it 'accepts --out option' do
  197. config.parse!(%w[--out jalla.txt])
  198. expect(config.formats).to eq [['pretty', {}, 'jalla.txt']]
  199. end
  200. it 'accepts multiple --out options' do
  201. config.parse!(%w[--format progress --out file1 --out file2])
  202. expect(config.formats).to eq [['progress', {}, 'file2']]
  203. end
  204. it 'accepts multiple --format options and put the STDOUT one first so progress is seen' do
  205. config.parse!(%w[--format pretty --out pretty.txt --format progress])
  206. expect(config.formats).to eq [['progress', {}, out], ['pretty', {}, 'pretty.txt']]
  207. end
  208. it 'does not accept multiple --format options when both use implicit STDOUT' do
  209. expect { config.parse!(%w[--format pretty --format progress]) }.to raise_error('All but one formatter must use --out, only one can print to each stream (or STDOUT)')
  210. end
  211. it 'does not accept multiple --format options when both use implicit STDOUT (using profile with no formatters)' do
  212. given_cucumber_yml_defined_as('default' => ['-q'])
  213. expect { config.parse!(%w[--format pretty --format progress]) }.to raise_error('All but one formatter must use --out, only one can print to each stream (or STDOUT)')
  214. end
  215. it 'accepts same --format options with implicit STDOUT, and keep only one' do
  216. config.parse!(%w[--format pretty --format pretty])
  217. expect(config.formats).to eq [['pretty', {}, out]]
  218. end
  219. it 'does not accept multiple --out streams pointing to the same place' do
  220. expected_error = 'All but one formatter must use --out, only one can print to each stream (or STDOUT)'
  221. expect { config.parse!(%w[--format pretty --out file1 --format progress --out file1]) }.to raise_error(expected_error)
  222. end
  223. it 'does not accept multiple --out streams pointing to the same place (one from profile, one from command line)' do
  224. given_cucumber_yml_defined_as('default' => ['-f', 'progress', '--out', 'file1'])
  225. expect { config.parse!(%w[--format pretty --out file1]) }.to raise_error('All but one formatter must use --out, only one can print to each stream (or STDOUT)')
  226. end
  227. it 'associates --out to previous --format' do
  228. config.parse!(%w[--format progress --out file1 --format profile --out file2])
  229. expect(config.formats).to match_array([['progress', {}, 'file1'], ['profile', {}, 'file2']])
  230. end
  231. it 'accepts same --format options with same --out streams and keep only one' do
  232. config.parse!(%w[--format json --out file --format pretty --format json --out file])
  233. expect(config.formats).to eq [['pretty', {}, out], ['json', {}, 'file']]
  234. end
  235. it 'accepts same --format options with different --out streams' do
  236. config.parse!(%w[--format json --out file1 --format json --out file2])
  237. expect(config.formats).to match_array([['json', {}, 'file1'], ['json', {}, 'file2']])
  238. end
  239. it 'accepts --color option' do
  240. expect(Cucumber::Term::ANSIColor).to receive(:coloring=).with(true)
  241. config.parse!(['--color'])
  242. end
  243. it 'accepts --no-color option' do
  244. expect(Cucumber::Term::ANSIColor).to receive(:coloring=).with(false)
  245. config = Configuration.new(StringIO.new)
  246. config.parse!(['--no-color'])
  247. end
  248. describe '--backtrace' do
  249. before do
  250. Cucumber.use_full_backtrace = false
  251. end
  252. it 'shows full backtrace when --backtrace is present' do
  253. Main.new(['--backtrace'])
  254. begin
  255. expect('x').to eq 'y'
  256. rescue RSpec::Expectations::ExpectationNotMetError => e
  257. expect(e.backtrace[0]).not_to eq "#{__FILE__}:#{__LINE__ - 2}"
  258. end
  259. end
  260. after do
  261. Cucumber.use_full_backtrace = false
  262. end
  263. end
  264. it 'accepts multiple --name options' do
  265. config.parse!(['--name', 'User logs in', '--name', 'User signs up'])
  266. expect(config.options[:name_regexps]).to include(/User logs in/)
  267. expect(config.options[:name_regexps]).to include(/User signs up/)
  268. end
  269. it 'accepts multiple -n options' do
  270. config.parse!(['-n', 'User logs in', '-n', 'User signs up'])
  271. expect(config.options[:name_regexps]).to include(/User logs in/)
  272. expect(config.options[:name_regexps]).to include(/User signs up/)
  273. end
  274. it 'should allow specifying environment variables on the command line' do
  275. config.parse!(['foo=bar'])
  276. expect(ENV['foo']).to eq 'bar'
  277. expect(config.paths).not_to include('foo=bar')
  278. end
  279. it 'allows specifying environment variables in profiles' do
  280. given_cucumber_yml_defined_as('selenium' => 'RAILS_ENV=selenium')
  281. config.parse!(['--profile', 'selenium'])
  282. expect(ENV['RAILS_ENV']).to eq 'selenium'
  283. expect(config.paths).not_to include('RAILS_ENV=selenium')
  284. end
  285. describe '#tag_expressions' do
  286. it 'returns an empty expression when no tags are specified' do
  287. config.parse!([])
  288. expect(config.tag_expressions).to be_empty
  289. end
  290. it 'returns an expression when tags are specified' do
  291. config.parse!(['--tags', '@foo'])
  292. expect(config.tag_expressions).not_to be_empty
  293. end
  294. end
  295. describe '#tag_limits' do
  296. it 'returns an empty hash when no limits are specified' do
  297. config.parse!([])
  298. expect(config.tag_limits).to eq({})
  299. end
  300. it 'returns a hash of limits when limits are specified' do
  301. config.parse!(['--tags', '@foo:1'])
  302. expect(config.tag_limits).to eq('@foo' => 1)
  303. end
  304. end
  305. describe '#dry_run?' do
  306. it 'returns true when --dry-run was specified on in the arguments' do
  307. config.parse!(['--dry-run'])
  308. expect(config.dry_run?).to be true
  309. end
  310. it 'returns true when --dry-run was specified in yaml file' do
  311. given_cucumber_yml_defined_as('default' => '--dry-run')
  312. config.parse!([])
  313. expect(config.dry_run?).to be true
  314. end
  315. it 'returns false by default' do
  316. config.parse!([])
  317. expect(config.dry_run?).to be false
  318. end
  319. end
  320. describe '#snippet_type' do
  321. it 'returns the snippet type when it was set' do
  322. config.parse!(['--snippet-type', 'classic'])
  323. expect(config.snippet_type).to eq :classic
  324. end
  325. it 'returns the snippet type when it was set with shorthand option' do
  326. config.parse!(['-I', 'classic'])
  327. expect(config.snippet_type).to eq :classic
  328. end
  329. it 'returns the default snippet type if it was not set' do
  330. config.parse!([])
  331. expect(config.snippet_type).to eq :cucumber_expression
  332. end
  333. end
  334. describe '#retry_attempts' do
  335. it 'returns the specified number of retries' do
  336. config.parse!(['--retry=3'])
  337. expect(config.retry_attempts).to eql 3
  338. end
  339. end
  340. end
  341. end
  342. end

No Description

Contributors (1)