Opal-RSpec
If you're a Rubyist, you know about RSpec. It's the testing framework that most of us like. RSpec's code base also happens to use a lot of features of the Ruby language, which means getting it to work on Opal is a challenge, but to some extent, we're there! Even if you're writing code in ES5/ES6, you might enjoy using RSpec as an alternative to Jasmine. Opal's native JS functionality makes that fairly easy to do.
What's new?
There were 394 commits since opal-rspec 0.4.3 that covered a variety of areas:
- Opal itself - 30+ pull requests went into Opal 0.9 to improve RSpec's stability on Opal. This obviously benefits anyone using opal, not just opal-rspec users.
- RSpec specs - opal-rspec 0.5 now runs and passes 80%+ of RSpec's own specs. For the first time, limitations, including some present in prior opal-rspec versions, are documented.
- New versions - Base RSpec version has been upgraded to 3.1 from the 3.0 beta (we know we're still behind, but read on) and the Rake task works with Phantom JS 1.9.8 and 2.0.
- New features - Node runner support and improved Rake task configurability.
How do you get started?
First step is adding it to your Gemfile
and bundle install
.
Then you'll need to ensure, for the default config, you have at 1.9.8 of PhantomJS installed.
Then you can start writing specs!
Put this in spec/42_spec.rb
describe 42 do
subject { 43 }
it { is_expected.to eq 43 }
end
Then in your Rakefile:
require 'opal/rspec/rake_task'
Opal::RSpec::RakeTask.new(:default)
After running bundle exec rake
, you'll see:
Running phantomjs /usr/local/bundle/gems/opal-rspec-0.5.0/vendor/spec_runner.js "http://localhost:9999/"
Object freezing is not supported by Opal
.
Finished in 0.013 seconds (files took 0.163 seconds to load)
1 example, 0 failures
Right off the bat, you can see at least a few things Opal doesn't like about RSpec's code base (the freeze warning), but as of opal-rspec 0.5, those are either limited to this warning message or other documented limitations.
Formatter support works as well.
After running SPEC_OPTS="--format json" bundle exec rake
:
Object freezing is not supported by Opal
{"examples":[{"description":"should eq 43", "full_description":"42 should eq 43", "status":"passed", "file_path":"http://localhost", "line_number":9999, "run_time":0.005}], "summary":{"duration":0.013, "example_count":1, "failure_count":0, "pending_count":0}, "summary_line":"1 example, 0 failures"}
Asynchronous testing on Opal
Since opal has a promise implementation built in, opal-rspec has some support for asynchronous testing. By default, any subject
, it
block, before(:each)
, after(:each)
, or around
hook that returns a promise will cause RSpec to wait for promise resolution before continuing. In the subject
case, any subject
resolution in your specs will be against the promise result, not the promise, which should DRY up your specs.
Example:
Create spec/async_spec.rb
with this content:
describe 'async' do
subject do
promise = Promise.new
delay 1 do
promise.resolve 42
end
promise
end
it { is_expected.to be_a Promise }
it { is_expected.to eq 42 }
end
Result:
Running phantomjs /usr/local/bundle/gems/opal-rspec-0.5.0/vendor/spec_runner.js "http://localhost:9999/"
Object freezing is not supported by Opal
.F.
Failures:
1) async should be a kind of Promise
Failure/Error: Unable to find matching line from backtrace
Exception::ExpectationNotMetError:
expected 42 to be a kind of Promise
# ExpectationNotMetError: expected 42 to be a kind of Promise
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:4294
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:50378
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:33927
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:33950
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:33708
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:53200
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:3000
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:52274
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:52348
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:1055
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:14805
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:52554
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:52573
# at http://localhost:9999/assets/opal/rspec/sprockets_runner.js:52555
#
# Showing full backtrace because every line was filtered out.
# See docs for RSpec::Configuration#backtrace_exclusion_patterns and
# RSpec::Configuration#backtrace_inclusion_patterns for more information.
Finished in 2.03 seconds (files took 0.156 seconds to load)
3 examples, 1 failure
Failed examples:
rspec http://localhost:9999 # async should be a kind of Promise
The failure is because we get a number back, not a Promise.
The chances are your CI tool supports at least 1 of those. Check out opal-rspec-formatter
Karma support
If you want to tap into the browser runners that Karma supports but keep using Opal, you might want to check out karma-opal-rspec.
Work to be done
As was mentioned above, we're still using RSpec 3.1, which as of this writing, is almost 1.5 years old. Due to the number of changes necessary to make RSpec Opal friendly, we cannot track with RSpec releases as fast as we would like. That said, several things we're doing should allow us to move faster in the future, including:
- Constantly improving Opal code base that allows more Ruby features to work out of the box.
- RSpec specs which helped improve Opal and allow us to easily identify far corners of RSpec's functionality.
- Work on arity checking is already in-progress (opal-rspec currently doesn't run with arity checking enabled). This will tease out even more issues.
All of these will eventually lead to less monkey patching and more out of the box stuff that works.
How to help
Arity checking is the top priority right now. If you can assist with issues like this opal issue that are documented on the opal-rspec arity check issue, that will help move things along.
After that is complete, we can begin work on RSpec 3.4.