Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: opal/opal-rspec
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d6464d433c73
Choose a base ref
...
head repository: opal/opal-rspec
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3aadd791a16e
Choose a head ref
  • 2 commits
  • 7 files changed
  • 2 contributors

Commits on Jul 29, 2015

  1. Copy the full SHA
    91285df View commit details
  2. Merge pull request #26 from wied03/master

    Add legacy async helpers back in
    elia committed Jul 29, 2015
    Copy the full SHA
    3aadd79 View commit details
Showing with 148 additions and 6 deletions.
  1. +1 −1 CHANGELOG.md
  2. +38 −4 README.md
  3. +2 −1 Rakefile
  4. +3 −0 opal/opal/rspec.rb
  5. +1 −0 opal/opal/rspec/async.rb
  6. +50 −0 opal/opal/rspec/async/legacy.rb
  7. +53 −0 spec/async_spec.rb
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## 0.5.0 (edge)

* By default, any subject, it example block, before(:each), after(:each), and around that returns a promise will be executed asynchronously. Async is NOT yet supported for context level hooks.
* By default, any subject, it example block, before(:each), after(:each), and around that returns a promise will be executed asynchronously. Async is NOT yet supported for context level hooks. Async approach from < 0.4.3 will still work.

* Update to RSpec 3.1 (core is 3.1.7, expectations/support 3.1.2, mocks 3.1.3)

42 changes: 38 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -51,8 +51,12 @@ in any web browser.

## Async examples

`opal-rspec` adds support for async specs to rspec. These specs are defined using
`#async` instead of `#it`:
`opal-rspec` adds support for async specs to rspec. These specs can be defined using 2 approaches:

1. Promises returned from subject or the `#it` block (preferred)
1. `#async` instead of `#it` (in use with opal-rspec <= 0.4.3)

### Promise approach

```ruby
describe MyClass do
@@ -107,9 +111,39 @@ describe MyClass2 do
end
```

Advantages:
* Assuming your subject under test (or matchers) return/use promises, the syntax is the same for sync or async specs

Limitations:
* Right now, async before(:context) and after(:context) hooks cannot be async
* let dependencies cannot be async, only subject
* Right now, async `before(:context)` and `after(:context)` hooks cannot be async
* `let` dependencies cannot be async, only subject
* Opal-rspec will not timeout while waiting for your async code to finish

### Async/it approach

This is the approach that was supported in opal-rspec <= 0.4.3 and it still works.

```ruby
describe MyClass2 do
async 'HTTP requests should work' do
HTTP.get('/users/1.json') do |res|
async {
expect(res).to be_ok
}
end
end
end
```

The block passed to the second `async` call informs the runner that this spec is finished
so it can move on. Any failures/expectations run inside this block will be run
in the context of the example.

Advantages:
* Hides promises from the specs

Disadvantages:
* Requires different syntax for async specs vs. sync specs

## Contributing

3 changes: 2 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -103,7 +103,8 @@ task :default do
'hooks after async match fails properly async match',
'hooks after async match fails properly sync match should eq 43',
'exception handling should fail properly if an exception is raised',
'exception handling should ignore an exception after a failed assertion'].sort
'exception handling should ignore an exception after a failed assertion',
'legacy async fails properly after a long delay'].sort
if actual_failures != expected_failures
unexpected = actual_failures - expected_failures
missing = expected_failures - actual_failures
3 changes: 3 additions & 0 deletions opal/opal/rspec.rb
Original file line number Diff line number Diff line change
@@ -9,6 +9,9 @@
RSpec.configure do |config|
# For now, always use our custom formatter for results
config.default_formatter = Opal::RSpec::Runner.default_formatter

# Legacy helpers
config.include Opal::RSpec::AsyncHelpers

# Always support expect() and .should syntax (we should not do this really..)
config.expect_with :rspec do |c|
1 change: 1 addition & 0 deletions opal/opal/rspec/async.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'opal/rspec/async/async_example'
require 'opal/rspec/async/example_group'
require 'opal/rspec/async/hooks'
require 'opal/rspec/async/legacy'
50 changes: 50 additions & 0 deletions opal/opal/rspec/async/legacy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
module Opal
module RSpec
module AsyncHelpers
module ClassMethods
def async(desc, *args, &block)
options = ::RSpec::Core::Metadata.build_hash_from(args)
options.update(:skip => ::RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block

examples << Opal::RSpec::LegacyAsyncExample.new(self, desc, options, block)
examples.last
end
end

attr_accessor :legacy_promise

def self.included(base)
base.extend ClassMethods
end

# Use {#async} instead.
#
# @deprecated
def run_async(&block)
async(&block)
end

def async(&block)
begin
instance_eval &block
legacy_promise.resolve
rescue Exception => e
legacy_promise.reject e
end
end
end
end
end

class Opal::RSpec::LegacyAsyncExample < ::RSpec::Core::Example
def initialize(example_group_class, description, user_metadata, example_block=nil)
example = self
legacy_promise_ex_block = lambda do
self.legacy_promise = Promise.new
instance_exec(example, &example_block)
self.legacy_promise
end

super example_group_class, description, user_metadata, legacy_promise_ex_block
end
end
53 changes: 53 additions & 0 deletions spec/async_spec.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,56 @@
describe 'legacy async' do
let(:foo) { 100 }

before do
@model = Object.new
end

async "fails properly after a long delay" do
obj = [2, 2, 3, 4]

delay(1) do
async { obj.should == [1, 2, 3, 4] }
end
end

async 'allows overriding the timeout', timeout: 15 do
delay(11) do
async { expect(42).to eq(42) }
end
end

async "can run examples async" do
async do
1.should == 1
end
end

async "can access let() helpers and before() helpers" do
async do
foo.should eq(100)
@model.should be_kind_of(Object)
end
end

async "can finish running after a long delay" do
obj = [1, 2, 3, 4]

delay(1) do
async { obj.should == [1, 2, 3, 4] }
end
end

async "should make example fail before async block reached" do
expect {
expect(:foo).to eq(:baz)
}.to raise_error(Exception)

delay(0) do
async { expect(42).to eq(42) }
end
end
end

describe 'promise' do
let(:foo) { 100 }