opal-rspec 1.0.0 → 1.1.0.alpha2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c68bbe588e9f4799786a07239f9b09201d9ff8852eba3d0427d475d2c7d26eb4
4
- data.tar.gz: f879318367b656f9da5068088a05093d02aa0ff30271b4886983e1f007e310ff
3
+ metadata.gz: daf042a48c3443b869f363a722554e1b71a3e4153f1ea6edd73562e1d0c5f6b1
4
+ data.tar.gz: 9e1db2043bedaa0c70c673a9485ecce6a99014db2b7f0eb51ec13d97c2b59d76
5
5
  SHA512:
6
- metadata.gz: 151736466857ed69765cac6061530352e9c43a37323a0c2cc5b75acffbddf2f4cccffe5dcd6d48e6ef1aa8ac88962fe2be6f38e283758adb5a76562823faec42
7
- data.tar.gz: b68d39d4ac974ccfa7893995e117329ffeaaf56e0f3999e8a39648a8d03e24e46f1bcd927df537618fba69348ccad9e576f0fae3864f95fe0a68c1e646f0133d
6
+ metadata.gz: c92f9b1bd05afa875b886deb5d48b81b568f5042a0d51bf82f1bbcd98c5403cc0dc69c26dc671c9fc92646adbb889771c4d1fce7e6c69fffe717f581f09be6f4
7
+ data.tar.gz: e5ec66ded2c2ed976a3234946efc8bb4b6a003d1dbc764831730bbd3de8cd348e1da1e3818b9777e5405b1cca743827b29ef96650cedd1fd4bd7d4875a8d336e
@@ -13,10 +13,11 @@ on:
13
13
  jobs:
14
14
  build:
15
15
  strategy:
16
+ fail-fast: false
16
17
  matrix:
17
18
  os: [ 'ubuntu-latest' ]
18
- ruby: [ ruby-head, 3.1, "3.0", 2.7 ]
19
- opal: [ master, 1.6.alpha1 ]
19
+ ruby: [ ruby-head, 3.2, 3.1, "3.0", 2.7 ]
20
+ opal: [ master, 1.7, 1.8 ]
20
21
 
21
22
  runs-on: ${{ matrix.os }}
22
23
 
@@ -24,7 +25,9 @@ jobs:
24
25
  OPAL_VERSION: ${{ matrix.opal }}
25
26
 
26
27
  steps:
27
- - uses: actions/checkout@v2
28
+ - uses: actions/checkout@v4
29
+ with:
30
+ submodules: true
28
31
  - uses: ruby/setup-ruby@v1
29
32
  with:
30
33
  ruby-version: ${{ matrix.ruby }}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Opal-RSpec Changelog
2
2
 
3
+ ## 1.1.0.alpha2 - 2023-09-20
4
+
5
+ - Drop advertised support for Opal v1.6
6
+
7
+ - Fix support for Ruby 2.7+
8
+
9
+ - Drop requirement of Opal-Sprockets
10
+
11
+
12
+ ## 1.1.0.alpha1 - 2023-09-16
13
+
14
+ - Support Opal headless browser runners
15
+
16
+ - (Almost) full support for `rspec` CLI util (which we run using `opal-rspec` command)
17
+ * Focus works, you can type `opal-rspec spec-opal-passing/tautology_spec.rb:8` to select a given test
18
+ * Most of other command line switches of `opal-rspec` work
19
+ * You can use a `.rspec-opal` configuration file akin to `.rspec` with the regular RSpec
20
+ * Just like with RSpec, switches set in this file propagate everywhere (eg. Rake task), so this is from now a prefered place to set up paths, etc.
21
+
22
+ - Compatibility for upcoming Opal v1.8
23
+
24
+
3
25
  ## 1.0.0 - 2022-11-24
4
26
 
5
27
  - Drop support for anything below Opal v1.6.alpha1
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
- unless Dir['rspec{,-{core,expectations,mocks,support}}/upstream'].any?
4
+ unless Dir[__dir__ + '/rspec{,-{core,expectations,mocks,support}}/upstream'].any?
5
5
  raise 'Run: "git submodule update --init" to get RSpec sources'
6
6
  end
7
7
 
@@ -18,7 +18,7 @@ case ENV['OPAL_VERSION']
18
18
  when 'local'
19
19
  gem 'opal', path: '../opal'
20
20
  when /^[0-9]/
21
- gem 'opal', ENV['OPAL_VERSION']
21
+ gem 'opal', "~> #{ENV['OPAL_VERSION']}.0a"
22
22
  when String
23
23
  gem 'opal', git: 'https://github.com/opal/opal.git', branch: ENV['OPAL_VERSION']
24
24
  end
@@ -26,3 +26,4 @@ end
26
26
  gem 'opal-sprockets', '>=1.0'
27
27
 
28
28
  gem 'puma'
29
+ gem 'rack', '<3'
data/README.md CHANGED
@@ -135,6 +135,10 @@ end
135
135
 
136
136
  If you don't specify a runner using `task.runner`, a default one is Node. In this case you can also use `RUNNER=chrome` to run a particular test with Headless Chromium.
137
137
 
138
+ *(since v1.1.0)*
139
+
140
+ You can also put default options into an `.rspec-opal` file, akin to how RSpec works. Those options will be propagated to Rake task, invocations of `Opal::RSpec::Runner` and also the `opal-rspec` command line tool.
141
+
138
142
  ### Run specs in Node.js
139
143
 
140
144
  Same options as above, you can use the `RUNNER=node` environment variable
@@ -157,6 +161,11 @@ Opal::RSpec::RakeTask.new(:default) do |server, task|
157
161
  end
158
162
  ```
159
163
 
164
+ *(since v1.1.0)*
165
+
166
+ While `server` value runs a server, you can here supply also respectively
167
+ `chrome`, `firefox` or `safari` to run the test using a headless browser.
168
+
160
169
  ### Run specs in a browser (Sprockets, deprecated)
161
170
 
162
171
  `opal-rspec` can use sprockets to build and serve specs over a simple rack
@@ -347,7 +356,7 @@ When updating the RSpec versions, after updating the submodule revisions, you ma
347
356
 
348
357
  (The MIT License)
349
358
 
350
- Copyright (C) 2022 by hmdne and the Opal contributors
359
+ Copyright (C) 2022-2023 by hmdne and the Opal contributors
351
360
  Copyright (C) 2015 by Brady Wied
352
361
  Copyright (C) 2013 by Adam Beynon
353
362
 
data/exe/opal-rspec CHANGED
@@ -4,81 +4,23 @@
4
4
 
5
5
  require 'rake'
6
6
  require 'opal/rspec/runner'
7
+ require 'opal/rspec/configuration_parser'
7
8
 
8
9
  require 'shellwords'
9
- require 'optparse'
10
10
 
11
- options = {}
12
- OptionParser.new do |parser|
13
- parser.on('--init', 'Initialize your project with Opal-RSpec.') do |_cmd|
14
- Opal::RSpec::ProjectInitializer.new.run
15
- exit
16
- end
17
-
18
- parser.on('-c', '--[no-]color', '--[no-]colour', 'Enable color in the output.') do |o|
19
- options[:color] = o
20
- end
21
-
22
- parser.on('-f', '--format FORMATTER', 'Choose a formatter.',
23
- ' [p]rogress (default - dots)',
24
- ' [d]ocumentation (group and example names)',
25
- ' [h]tml',
26
- ' [j]son',
27
- ' custom formatter class name') do |o|
28
- options[:formatters] ||= []
29
- options[:formatters] << [o]
30
- end
31
-
32
- parser.on('-r', '--require PATH', 'Require a file.') do |path|
33
- options[:requires] ||= []
34
- options[:requires] << path
35
- end
36
-
37
- parser.on('-I PATH', 'Specify PATH to add to $LOAD_PATH (may be used more than once).') do |dir|
38
- options[:includes] ||= []
39
- options[:includes] << dir
40
- end
41
-
42
- parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec-opal/**/*_spec.rb").') do |o|
43
- options[:pattern] = o
44
- end
45
-
46
- parser.on('--default-path PATH', 'Set the default path where RSpec looks for examples (can',
47
- ' be a path to a file or a directory).') do |path|
48
- options[:default_path] = path
49
- end
50
-
51
- parser.separator 'Opal specific options:'
52
-
53
- parser.on('-R', '--runner NAME', 'Use a different JS runner (default is nodejs)') do |name|
54
- options[:runner] = name
55
- end
56
- end.parse!
57
-
58
- runner = Opal::RSpec::Runner.new do |server, config|
59
- spec_opts = []
60
- spec_opts += ['--color', options[:color]] if options[:color]
61
- options[:requires].each {|req| spec_opts += ['-r', req]} if options[:requires]
62
- raise "can accept only one formatter at this time" if options[:formatters] && options[:formatters].size != 1
63
- spec_opts += ['--format', options[:formatters].flatten.first] if options[:formatters]
64
- raw_files = ARGV
65
- raw_files = ['spec-opal'] if raw_files.empty?
11
+ parser = Opal::RSpec::Core::Parser.new(ARGV)
12
+ options = parser.parse
66
13
 
67
- files = raw_files.flat_map do |file|
68
- if File.directory? file
69
- Dir[File.join(file, '**{,/*/**}/*_spec{.js,}.rb')]
70
- elsif File.file? file
71
- file
72
- else
73
- raise "Can't stat path: #{file}"
74
- end
14
+ case options[:runner]
15
+ when String, nil
16
+ runner = Opal::RSpec::Runner.new do |server, config|
17
+ config.runner = options.delete(:runner)
18
+ config.spec_opts = options
75
19
  end
76
20
 
77
- options[:includes].each {|dir| server.append_path dir} if options[:includes]
78
- config.default_path = options[:default_path] if options[:default_path]
79
- config.spec_opts = spec_opts.shelljoin
80
- config.files = files
21
+ runner.run
22
+ else
23
+ exit options[:runner].(ARGV, $stderr, $stdout)
81
24
  end
82
25
 
83
- runner.run
84
26
 
@@ -0,0 +1,47 @@
1
+ require 'opal/rspec/util'
2
+ require 'optparse'
3
+
4
+ module Opal; module RSpec; module Core; end; end; end
5
+ # Load necessary files under Opal's namespace, so as not to conflict with RSpec if it's being loaded too.
6
+ # Later, we will monkey-patch those methods.
7
+ ::Opal::RSpec.load_namespaced __dir__ + "/../../../rspec-core/upstream/lib/rspec/core/invocations.rb", ::Opal
8
+ ::Opal::RSpec.load_namespaced __dir__ + "/../../../rspec-core/upstream/lib/rspec/core/option_parser.rb", ::Opal
9
+
10
+ class Opal::RSpec::Core::Parser
11
+ alias parser_before_opal parser
12
+
13
+ def parser(options)
14
+ parser_before_opal(options).tap do |parser|
15
+ parser.banner = "Usage: opal-rspec [options] [files or directories]\n\n"
16
+
17
+ parser.separator ''
18
+ parser.separator ' **** Opal specific options ****'
19
+ parser.separator ''
20
+
21
+ parser.on('-R', '--runner NAME', 'Use a different JS runner (default is nodejs)') do |name|
22
+ options[:runner] = name
23
+ end
24
+
25
+ parser.separator ''
26
+ parser.separator ' **** Help ****'
27
+ parser.separator ''
28
+ end
29
+ end
30
+ end
31
+
32
+ class Opal::RSpec::Core::Invocations::PrintVersion
33
+ alias call_before_opal call
34
+
35
+ def call(options, err, out)
36
+ exitcode = call_before_opal(options, err, out)
37
+ out.puts "Opal #{Opal::VERSION}"
38
+ out.puts " - opal-rspec #{Opal::RSpec::VERSION}"
39
+ exitcode
40
+ end
41
+ end
42
+
43
+ module Opal::RSpec::Support
44
+ def self.require_rspec_core(arg)
45
+ require "opal/rspec/"+arg
46
+ end
47
+ end
@@ -1,25 +1,33 @@
1
+ require 'opal/rspec/util'
1
2
  require 'pathname'
2
3
  require 'rake'
3
4
  # require the bundled RSpec's file and don't rely on the load path in case opal-rspec is included in a project's
4
5
  # Gemfile without rspec also being in the Gemfile
5
- require_relative '../../../rspec-core/upstream/lib/rspec/core/ruby_project'
6
+ ::Opal::RSpec.load_namespaced __dir__+'/../../../rspec-core/upstream/lib/rspec/core/ruby_project.rb', ::Opal
6
7
 
7
8
  module Opal
8
9
  module RSpec
9
10
  class Locator
10
- include ::RSpec::Core::RubyProject
11
+ include ::Opal::RSpec::Core::RubyProject
11
12
 
12
13
  DEFAULT_GLOB = '**{,/*/**}/*_spec{.js,}.{rb,opal}'
13
- DEFAULT_PATTERN = "spec-opal/#{DEFAULT_GLOB}"
14
14
  DEFAULT_DEFAULT_PATH = 'spec-opal'
15
15
 
16
16
  attr_accessor :spec_pattern, :spec_exclude_pattern, :spec_files, :default_path
17
17
 
18
18
  def initialize(pattern: nil, exclude_pattern: nil, files: nil, default_path: nil)
19
- @spec_pattern = pattern || DEFAULT_PATTERN
20
- @spec_exclude_pattern = exclude_pattern
19
+ @spec_exclude_pattern = Array(exclude_pattern)
21
20
  @spec_files = files
22
21
  @default_path = default_path || DEFAULT_DEFAULT_PATH
22
+ @spec_pattern = Array(pattern || DEFAULT_GLOB)
23
+
24
+ @spec_pattern = @spec_pattern.map do |pattern|
25
+ pattern.sub(/\A#{Regexp.escape(@default_path)}/, '')
26
+ end
27
+
28
+ @spec_exclude_pattern = @spec_exclude_pattern.map do |pattern|
29
+ pattern.sub(/\A#{Regexp.escape(@default_path)}/, '')
30
+ end
23
31
  end
24
32
 
25
33
  def determine_root
@@ -27,11 +35,28 @@ module Opal
27
35
  end
28
36
 
29
37
  def get_spec_load_paths
30
- [@default_path].map { |dir| File.join(root, dir) }
38
+ [File.join(root, @default_path)]
39
+ end
40
+
41
+ def get_matching_files_under(path: )
42
+ FileList[*@spec_pattern.map { |i| "#{path}/#{i}" }]
43
+ .exclude(*@spec_exclude_pattern.map { |i| "#{path}/#{i}" })
31
44
  end
32
45
 
33
46
  def get_opal_spec_requires
34
- files = @spec_files || FileList[*@spec_pattern].exclude(*@spec_exclude_pattern)
47
+ if !@spec_files || @spec_files.empty?
48
+ files = get_matching_files_under(path: @default_path)
49
+ else
50
+ files = @spec_files.map do |file|
51
+ file = file.split(/[\[:]/).first
52
+ if File.directory?(file)
53
+ get_matching_files_under(path: file).to_a
54
+ else
55
+ file
56
+ end
57
+ end.flatten
58
+ files = FileList[*files]
59
+ end
35
60
  files.uniq.map { |file| File.expand_path file }
36
61
  end
37
62
  end
@@ -1,2 +1 @@
1
- --color
2
1
  --require spec_helper
@@ -1,4 +1,88 @@
1
+ # This file was generated by the `opal-rspec --init` command. Conventionally, all
2
+ # specs live under a `spec-opal` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec-opal` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
1
16
  RSpec.configure do |config|
17
+ # rspec-expectations config goes here. You can use an alternate
18
+ # assertion/expectation library such as wrong or the stdlib/minitest
19
+ # assertions if you prefer.
20
+ config.expect_with :rspec do |expectations|
21
+ # This option will default to `true` in RSpec 4. It makes the `description`
22
+ # and `failure_message` of custom matchers include text for helper methods
23
+ # defined using `chain`, e.g.:
24
+ # be_bigger_than(2).and_smaller_than(4).description
25
+ # # => "be bigger than 2 and smaller than 4"
26
+ # ...rather than:
27
+ # # => "be bigger than 2"
28
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29
+ end
30
+
31
+ # rspec-mocks config goes here. You can use an alternate test double
32
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
33
+ config.mock_with :rspec do |mocks|
34
+ # Prevents you from mocking or stubbing a method that does not exist on
35
+ # a real object. This is generally recommended, and will default to
36
+ # `true` in RSpec 4.
37
+ mocks.verify_partial_doubles = true
38
+ end
39
+
40
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41
+ # have no way to turn it off -- the option exists only for backwards
42
+ # compatibility in RSpec 3). It causes shared context metadata to be
43
+ # inherited by the metadata hash of host groups and examples, rather than
44
+ # triggering implicit auto-inclusion in groups with matching metadata.
45
+ config.shared_context_metadata_behavior = :apply_to_host_groups
46
+
47
+ # The settings below are suggested to provide a good initial experience
48
+ # with RSpec, but feel free to customize to your heart's content.
49
+ =begin
50
+ # This allows you to limit a spec run to individual examples or groups
51
+ # you care about by tagging them with `:focus` metadata. When nothing
52
+ # is tagged with `:focus`, all examples get run. RSpec also provides
53
+ # aliases for `it`, `describe`, and `context` that include `:focus`
54
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
55
+ config.filter_run_when_matching :focus
56
+
57
+ # Allows RSpec to persist some state between runs in order to support
58
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
59
+ # you configure your source control system to ignore this file.
60
+ config.example_status_persistence_file_path = "spec/examples.txt"
61
+
62
+ # Limits the available syntax to the non-monkey patched syntax that is
63
+ # recommended. For more details, see:
64
+ # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode
65
+ config.disable_monkey_patching!
66
+
67
+ # This setting enables warnings. It's recommended, but in some cases may
68
+ # be too noisy due to issues in dependencies.
69
+ config.warnings = true
70
+
71
+ # Many RSpec users commonly either run the entire suite or an individual
72
+ # file, and it's useful to allow more verbose output when running an
73
+ # individual spec file.
74
+ if config.files_to_run.one?
75
+ # Use the documentation formatter for detailed output,
76
+ # unless a formatter has already been configured
77
+ # (e.g. via a command-line flag).
78
+ config.default_formatter = "doc"
79
+ end
80
+
81
+ # Print the 10 slowest examples and example groups at the
82
+ # end of the spec run, to help surface which specs are running
83
+ # particularly slow.
84
+ config.profile_examples = 10
85
+
2
86
  # Run specs in random order to surface order dependencies. If you find an
3
87
  # order dependency and want to debug it, you can fix the order by providing
4
88
  # the seed, which is printed after each run.
@@ -10,4 +94,5 @@ RSpec.configure do |config|
10
94
  # test failures related to randomization by passing the same `--seed` value
11
95
  # as the one that triggered the failure.
12
96
  Kernel.srand config.seed
97
+ =end
13
98
  end
@@ -19,6 +19,17 @@ module Opal
19
19
  end
20
20
 
21
21
  def run
22
+ puts <<~EOF
23
+ ** Do note, that Opal-RSpec defaults to the following paths:
24
+ ** - config file: .rspec-opal
25
+ ** - spec directory: spec-opal
26
+ ** - program: lib-opal
27
+ **
28
+ ** If you want to share Opal specs with Ruby specs, you will
29
+ ** need to put the following into your .rspec-opal:
30
+ **
31
+ ** -Ilib --default-path=spec
32
+ EOF
22
33
  copy_template DOT_RSPEC_FILE
23
34
  copy_template SPEC_HELPER_FILE
24
35
  end
@@ -9,7 +9,24 @@ require 'opal/rspec/locator'
9
9
  module Opal
10
10
  module RSpec
11
11
  class Runner
12
- attr_accessor :pattern, :requires, :exclude_pattern, :files, :default_path, :runner, :arity_checking, :spec_opts, :cli_options
12
+ attr_accessor :runner, :arity_checking, :spec_opts, :cli_options, :files
13
+
14
+ # Delegate property changes to spec_opts
15
+ def self.spec_opts_accessor(*names)
16
+ names.each do |name|
17
+ define_method name do
18
+ spec_opts[name]
19
+ end
20
+ define_method :"#{name}=" do |value|
21
+ spec_opts[name] = value
22
+ end
23
+ end
24
+ end
25
+
26
+ spec_opts_accessor :libs, :requires, :pattern, :exclude_pattern, :default_path, :files_or_directories_to_run
27
+
28
+ alias files files_or_directories_to_run
29
+ alias files= files_or_directories_to_run=
13
30
 
14
31
  def timeout= _
15
32
  warn "deprecated: setting timeout has no effect"
@@ -33,11 +50,11 @@ module Opal
33
50
  end
34
51
 
35
52
  def requires
36
- @requires ||= []
53
+ spec_opts[:requires] ||= []
37
54
  end
38
55
 
39
56
  def spec_opts
40
- @spec_opts ||= ENV['SPEC_OPTS']
57
+ @spec_opts = Opal::RSpec.convert_spec_opts(@spec_opts)
41
58
  end
42
59
 
43
60
  def get_load_asset_code(server)
@@ -80,9 +97,16 @@ module Opal
80
97
  @legacy_server_proxy = LegacyServerProxy.new
81
98
  block.call(@legacy_server_proxy, self) if block_given? # for compatibility
82
99
 
83
- raise 'Cannot supply both a pattern and files!' if self.files and self.pattern
100
+ raise 'Cannot supply both a pattern and files!' if self.files \
101
+ && !self.files.empty? \
102
+ && self.pattern
84
103
 
85
- locator = ::Opal::RSpec::Locator.new pattern: self.pattern, exclude_pattern: self.exclude_pattern, files: self.files, default_path: self.default_path
104
+ append_opts_from_config_file
105
+
106
+ locator = ::Opal::RSpec::Locator.new pattern: self.pattern,
107
+ exclude_pattern: self.exclude_pattern,
108
+ files: self.files,
109
+ default_path: self.default_path
86
110
 
87
111
  options = []
88
112
  options << '--arity-check' if arity_checking?
@@ -93,21 +117,55 @@ module Opal
93
117
  options << '--missing-require=ignore'
94
118
  options += @legacy_server_proxy.to_cli_options
95
119
 
96
- Opal.paths.each { |p| options << "-I#{p}" }
97
- locator.get_spec_load_paths.each { |p| options << "-I#{p}" }
120
+ load_paths = [Opal.paths, locator.get_spec_load_paths, self.libs].compact.sum([]).uniq
121
+
122
+ load_paths.each { |p| options << "-I#{p}" }
98
123
  requires.each { |p| options << "-r#{p}" }
99
- locator.get_opal_spec_requires.each { |p| options << "-r#{p}" }
124
+ locator.get_opal_spec_requires.each { |p| options << "-p#{p}" }
100
125
  ::Opal::Config.stubbed_files.each { |p| options << "-s#{p}" }
101
126
 
102
127
  options += @cli_options if @cli_options
103
- bootstrap_code = [
104
- ::Opal::RSpec.spec_opts_code(spec_opts),
105
- '::RSpec::Core::Runner.autorun',
106
- ].join(';')
128
+
129
+ bootstrap_code = ::Opal::RSpec.spec_opts_code(spec_opts)
107
130
 
108
131
  @args = "#{options.map(&:shellescape).join ' '} -e #{bootstrap_code.shellescape}"
109
132
  end
110
133
 
134
+ def append_opts_from_config_file
135
+ self.libs ||= []
136
+ self.requires ||= []
137
+
138
+ config_location = nil
139
+ path = self.default_path || "spec-opal"
140
+
141
+ # Locate config file
142
+ begin
143
+ loop do
144
+ if File.exist?(File.join(path, ".rspec-opal"))
145
+ path = File.join(path, ".rspec-opal")
146
+ break
147
+ else
148
+ new_path = File.expand_path("..", path)
149
+ return if new_path == path
150
+ path = new_path
151
+ end
152
+ end
153
+ rescue e
154
+ # we've gone too far beyond our permissions without finding a config file
155
+ return
156
+ end
157
+
158
+ if path
159
+ config_opts = Opal::RSpec.convert_spec_opts(File.read(path))
160
+ else
161
+ return
162
+ end
163
+
164
+ self.spec_opts = config_opts.merge(spec_opts) do |key, oldval, newval|
165
+ [:libs, :requires].include?(key) ? oldval + newval : newval
166
+ end
167
+ end
168
+
111
169
  def options
112
170
  {
113
171
  pattern: pattern,
@@ -0,0 +1,15 @@
1
+ module ::Opal
2
+ module RSpec
3
+ def self.load_namespaced(file, mod)
4
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1")
5
+ load file, mod
6
+ else
7
+ str = ""
8
+ str += "module ::#{mod.name};"
9
+ str += File.read(file)
10
+ str += ";end"
11
+ eval(str)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,12 @@
1
+ require 'opal/rspec/util'
2
+
1
3
  module Opal
2
4
  module RSpec
3
- VERSION = '1.0.0'
5
+ VERSION = '1.1.0.alpha2'
4
6
  end
5
7
  end
8
+
9
+ ::Opal::RSpec.load_namespaced __dir__ + "/../../../rspec-core/upstream/lib/rspec/core/version.rb", ::Opal
10
+ ::Opal::RSpec.load_namespaced __dir__ + "/../../../rspec-expectations/upstream/lib/rspec/expectations/version.rb", ::Opal
11
+ ::Opal::RSpec.load_namespaced __dir__ + "/../../../rspec-mocks/upstream/lib/rspec/mocks/version.rb", ::Opal
12
+ ::Opal::RSpec.load_namespaced __dir__ + "/../../../rspec-support/upstream/lib/rspec/support/version.rb", ::Opal
data/lib/opal/rspec.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'opal'
2
- require 'opal-sprockets'
3
2
  require 'opal/rspec/version'
4
3
  require 'opal/rspec/runner'
4
+ require 'opal/rspec/configuration_parser'
5
5
 
6
6
  # Just register our opal code path with opal build tools
7
7
  Opal.append_path File.expand_path('../../../lib-opal', __FILE__)
@@ -19,32 +19,31 @@ module Opal
19
19
  module RSpec
20
20
  autoload :ProjectInitializer, 'opal/rspec/project_initializer'
21
21
 
22
+ def self.convert_spec_opts(opts)
23
+ opts ||= ENV['SPEC_OPTS'] || {}
24
+
25
+ unless opts.is_a? Hash
26
+ opts = Shellwords.split(opts) if opts.is_a? String
27
+ opts = Opal::RSpec::Core::Parser.parse(opts || [])
28
+ end
29
+
30
+ opts
31
+ end
32
+
22
33
  def self.spec_opts_code(spec_opts)
34
+ spec_opts = convert_spec_opts(spec_opts)
35
+
23
36
  code = []
24
- if spec_opts && !spec_opts.empty?
25
- code << 'RSpec.configure do |config|'
26
-
27
- if (match = /--(no-)?color\b/.match(spec_opts))
28
- color_value = !match.captures[0]
29
- # Have to use instance_variable_set because config.color= is designed to not allow overriding color once it's set, but
30
- # we do not yet have true SPEC_OPTS parsing via RSpec config to get it initially set
31
- code << "config.instance_variable_set(:@color, #{color_value})"
32
- end
33
-
34
- if (requires = spec_opts.scan(/(?:--require|-r) \S+/)).any?
35
- requires.map {|r| /--require (.*)/.match(r).captures[0]}.each do |req|
36
- code << %{require "#{req}"}
37
- end
38
- end
39
-
40
- if (match = /--format (\S+)/.match(spec_opts))
41
- formatter = match.captures[0]
42
- code << %{config.formatter = "#{formatter}"}
43
- end
44
-
45
- code << 'end'
46
- end
47
- code.join('; ')
37
+ code << '# await: true'
38
+
39
+ # New API - passthru options
40
+ spec_opts[:files_or_directories_to_run] ||= []
41
+
42
+ code << "$rspec_opts = #{spec_opts.inspect}"
43
+ code << "$0 = 'opal-rspec'"
44
+
45
+ code << '::RSpec::Core::Runner.invoke.__await__'
46
+ code.join("\n")
48
47
  end
49
48
  end
50
49
  end
@@ -1,5 +1,9 @@
1
1
  require 'opal/rspec/formatter/browser_formatter'
2
2
 
3
3
  RSpec.configure do |config|
4
- config.default_formatter = ::Opal::RSpec::BrowserFormatter
4
+ if OPAL_PLATFORM.nil?
5
+ # We want the browser formatter ONLY for the real browser, not
6
+ # our headless browser runners.
7
+ config.default_formatter = ::Opal::RSpec::BrowserFormatter
8
+ end
5
9
  end
@@ -1,20 +1,112 @@
1
- class ::RSpec::Core::Configuration
2
- # This needs to be implemented if/when we allow the Opal side to decide what files to run
1
+ # backtick_javascript: true
2
+
3
+ require 'rspec/core/configuration'
4
+
5
+ module ::RSpec; module Core; class Configuration
3
6
  def files_or_directories_to_run=(*files)
4
- @files_or_directories_to_run = []
7
+ files = files.flatten
8
+
9
+ # patch: rspec -> opal-rspec
10
+ if (command == 'opal-rspec' || Runner.running_in_drb?) && default_path && files.empty?
11
+ files << default_path
12
+ end
13
+
14
+ @files_or_directories_to_run = files
5
15
  @files_to_run = nil
6
16
  end
7
17
 
8
18
  def requires=(paths)
9
19
  # can't change requires @ this stage, this method calls RubyProject which will crash on Opal
10
20
  end
11
- end
21
+
22
+ def remove_ruby_ext(str)
23
+ str.gsub(/(?:\.js)?\.(?:rb|opal|\{rb,opal\})\z/, '')
24
+ end
25
+
26
+ def glob_to_re(path, pattern)
27
+ pattern = remove_ruby_ext(pattern)
28
+ path = "" if pattern.start_with?(path)
29
+ path += "/" unless path.end_with?("/")
30
+ re = Regexp.escape(pattern).gsub('\*\*', '.*?')
31
+ .gsub('\*', '[^/]*?')
32
+ .gsub('\?', '[^/]')
33
+ .gsub(/\\{(.*?)\\}/) {
34
+ '(?:' + $1.gsub(",", "|") + ')'
35
+ }
36
+ re = "(?:^|/)" + Regexp.escape(path) + re + "$"
37
+ # Strip the first `/` so it acts more like the intention of `**`
38
+ re = re.gsub("/.*?", ".*?")
39
+ # Strip the `/./`
40
+ re = re.gsub("/\\.\\/", "\\/")
41
+ re = re.gsub("/)\\.\\/", "\\/)")
42
+ Regexp.new(re)
43
+ end
44
+
45
+ # Only load from loaded files
46
+ def get_matching_files(path, pattern)
47
+ `Object.keys(Opal.modules)`.grep(glob_to_re(path, pattern)).sort
48
+ end
49
+
50
+ # A crude logic to check if a path is a directory perhaps...
51
+ # This ought to work in places where we don't have a filesystem.
52
+ def is_directory?(path)
53
+ return true if path.end_with? '/'
54
+ # This is passed with ":" if we run something like:
55
+ # opal-rspec spec-opal-passing/tautology_spec.rb:8
56
+ return false if path =~ /\[[0-9:]+\]$|:[0-9]+$/
57
+ # Ruby files are certainly not directories
58
+ return false if ['.rb', '.opal'].any? { |i| path.end_with? i }
59
+ # Otherwise, let's check for modules
60
+ !`Object.keys(Opal.modules)`.any? { |i| i.end_with?("/"+remove_ruby_ext(path)) }
61
+ end
62
+
63
+ def get_files_to_run(paths)
64
+ files = paths_to_check(paths).flat_map do |path|
65
+ path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
66
+ is_directory?(path) ? gather_directories(path) : extract_location(path)
67
+ end.uniq
68
+
69
+ return files unless only_failures?
70
+ relative_files = files.map { |f| Metadata.relative_path(File.expand_path f) }
71
+ intersection = (relative_files & spec_files_with_failures.to_a)
72
+ intersection.empty? ? files : intersection
73
+ end
74
+
75
+ def opal_special_load(file)
76
+ file = remove_ruby_ext(file)
77
+ long_file = `Object.keys(Opal.modules)`.find { |i| i.end_with?(file) }
78
+ `Opal.modules[file] = Opal.modules[long_file]` if long_file
79
+
80
+ # Let's try a normalized load
81
+ `Opal.load_normalized(file)`
82
+ rescue LoadError
83
+ # Otherwise, a regular require
84
+ require file
85
+ end
86
+
87
+ alias load_file_handling_errors_before_opal load_file_handling_errors
88
+
89
+ def load_file_handling_errors(method, file)
90
+ load_file_handling_errors_before_opal(:opal_special_load, file)
91
+ end
92
+ end; end; end
12
93
 
13
94
  class ::RSpec::Core::ConfigurationOptions
95
+ # Opal-RSpec should work without need of filesystem
96
+ # access, therefore we can't support access to the
97
+ # options file.
14
98
  def options_file_as_erb_string(path)
15
99
  # ERB.new(File.read(path), nil, '-').result(binding)
16
100
  # ERB.new(File.read(path), nil, '-')
17
101
  ''
18
102
  end
103
+
104
+ # Pass command line options directly
105
+ def command_line_options
106
+ $rspec_opts || {}
107
+ end
19
108
  end
20
109
 
110
+ # Set the default path to spec-opal, to be overwritten
111
+ # later.
112
+ RSpec.configuration.default_path = "spec-opal"
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  # Random causes problems that can lock up a browser (see README)
2
4
  class ::RSpec::Core::Ordering::Random
3
5
  HIDE_RANDOM_WARNINGS = false
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  module Opal
2
4
  module RSpec
3
5
  class DocumentIO < IO
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  module Opal
2
4
  module RSpec
3
5
  class Element
@@ -1,3 +1,5 @@
1
+ # backtick_javascript: true
2
+
1
3
  require_relative 'noop_flush_string_io'
2
4
  require_relative 'element'
3
5
 
@@ -1,3 +1,5 @@
1
+ # await: true
2
+
1
3
  # This file is used by Opal::Server to basically load all spec files that
2
4
  # can be found in the spec/ directory.
3
5
 
@@ -10,5 +12,5 @@ require <%= s.inspect %>
10
12
  <% end %>
11
13
  require 'opal/rspec/spec_opts'
12
14
 
13
- ::RSpec::Core::Runner.autorun
15
+ ::RSpec::Core::Runner.invoke.__await__
14
16
  ::Kernel.exit
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opal-rspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0.alpha2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Beynon
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-11-24 00:00:00.000000000 Z
13
+ date: 2023-09-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: opal
@@ -294,6 +294,7 @@ files:
294
294
  - lib/opal-rspec.rb
295
295
  - lib/opal/rspec.rb
296
296
  - lib/opal/rspec/cached_environment.rb
297
+ - lib/opal/rspec/configuration_parser.rb
297
298
  - lib/opal/rspec/locator.rb
298
299
  - lib/opal/rspec/project_initializer.rb
299
300
  - lib/opal/rspec/project_initializer/.rspec-opal
@@ -302,6 +303,7 @@ files:
302
303
  - lib/opal/rspec/runner.rb
303
304
  - lib/opal/rspec/sprockets.rb
304
305
  - lib/opal/rspec/sprockets_environment.rb
306
+ - lib/opal/rspec/util.rb
305
307
  - lib/opal/rspec/version.rb
306
308
  - opal-rspec.gemspec
307
309
  - rspec-core/upstream/.document
@@ -951,11 +953,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
951
953
  version: '0'
952
954
  required_rubygems_version: !ruby/object:Gem::Requirement
953
955
  requirements:
954
- - - ">="
956
+ - - ">"
955
957
  - !ruby/object:Gem::Version
956
- version: '0'
958
+ version: 1.3.1
957
959
  requirements: []
958
- rubygems_version: 3.3.7
960
+ rubygems_version: 3.4.10
959
961
  signing_key:
960
962
  specification_version: 4
961
963
  summary: RSpec for Opal