rspec-activejob 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f57742790063ccf2ed6cd10e683e20389dbac437
4
- data.tar.gz: 231a686b90f41591f5ad437e8beaec9421ae8144
3
+ metadata.gz: 5ec1b26448aaa3732cc1239e94ed67be18fdd034
4
+ data.tar.gz: 53d956546e042ad727cc3d02094c5fb9851c24ff
5
5
  SHA512:
6
- metadata.gz: b95a86346e700b872030feb2d8046e9bfd6c33f9419709186caaee85a49807f72dc51a4e641e13e308fc740053731278b3fb4dc70f278824b44e01276137b8c6
7
- data.tar.gz: 38fedfe32066a157dd1b8b5e77edc9221889acbadf4a81fdaf14309cb58e08bfaa5efad2ec8044afeb2f051764ba7587e2376e67dd8c47a69cea51a3b4d6ef0d
6
+ metadata.gz: 7dbbdb3029c97cb2c71fe0b57d112fece98190849934e26e861e01cb4f2f9a427921fa541cba527589f341f06a1a5629a7a5afd9fddceb7f59d06ec56fabfddf
7
+ data.tar.gz: ded3be79382e60bf7fa9c590da4f34a0732ff660c51236cba33153aae22da379b3144bcd7a8cf8b4f4193dc24b47e35fca75a920bde1eebdaae8396719a61ee2
@@ -0,0 +1,33 @@
1
+ # Limit lines to 90 characters.
2
+ LineLength:
3
+ Max: 90
4
+
5
+ ClassLength:
6
+ Enabled: false
7
+
8
+ # Avoid single-line methods.
9
+ SingleLineMethods:
10
+ AllowIfMethodIsEmpty: true
11
+
12
+ StringLiterals:
13
+ Enabled: false
14
+
15
+ # Wants you to use the same argument names for every reduce. This seems kinda
16
+ # naff compared to naming them semantically
17
+ SingleLineBlockParams:
18
+ Enabled: false
19
+
20
+ Style/SignalException:
21
+ EnforcedStyle: 'only_raise'
22
+
23
+ # Use trailing rather than leading dots on multi-line call chains
24
+ Style/DotPosition:
25
+ EnforcedStyle: trailing
26
+
27
+ # Whatever
28
+ Style/Documentation:
29
+ Enabled: false
30
+
31
+ # RSpec argument matchers use ===. Sorry cop.
32
+ Style/CaseEquality:
33
+ Enabled: false
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 - January 18, 2015
2
+
3
+ - Added support for argument matchers (e.g. `instance_of`, `hash_including`), like the `receive` matcher.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-activejob (0.1.0)
4
+ rspec-activejob (0.2.0)
5
5
  activejob (>= 4.2)
6
6
  rspec-mocks
7
7
 
data/README.md CHANGED
@@ -1,15 +1,48 @@
1
1
  # RSpec ActiveJob matchers
2
2
 
3
3
  ```ruby
4
+ # config/environments/test.rb
5
+ config.active_job.queue_adapter = :test
6
+
7
+ # spec/spec_helper.rb
4
8
  RSpec.configure do |config|
5
9
  config.include(RSpec::ActiveJob)
10
+
11
+ # clean out the queue after each spec
12
+ config.after(:each) do
13
+ ActiveJob::Base.queue_adapter.enqueued_jobs = []
14
+ ActiveJob::Base.queue_adapter.performed_jobs = []
15
+ end
6
16
  end
7
17
 
18
+ # spec/controllers/my_controller_spec.rb
8
19
  RSpec.describe MyController do
9
20
  let(:user) { create(:user) }
10
21
  let(:params) { { user_id: user.id } }
11
22
  subject(:make_request) { described_class.make_request(params) }
12
23
 
13
- specify { expect { make_request }.to enqueue_a(RequestMaker).with(user) }
24
+ specify { expect { make_request }.to enqueue_a(RequestMaker).with(global_id(user)) }
14
25
  end
15
- ```
26
+ ```
27
+
28
+ rspec-activejob expects the current queue adapter to expose an array of `enqueued_jobs`, like the included
29
+ test adapter. The test adapter included in ActiveJob 4.2.0 does not fully serialize its arguments, so you
30
+ will not need to use the GlobalID matcher until ActiveJob 4.2.1. See rails/rails#18266 for the improved
31
+ test adapter.
32
+
33
+ This gem defines two matchers:
34
+
35
+ * `enqueue_a`: for a block or proc, expects that to enqueue an job to the ActiveJob test adapter. Optionally
36
+ takes the job class as its argument, and can be modified with a `.with(*args)` call to expect specific arguments.
37
+ This will use the same argument list matcher as rspec-mocks' `receive(:message).with(*args)` matcher.
38
+
39
+ * `global_id(model_or_class)`: an argument matcher, matching ActiveJob-serialized versions of model classes or
40
+ specific models (or any other class which implements `to_global_id`). If you pass a model class, it will match
41
+ the serialized version of any instance of that model; if you pass an instance, it will expect the serialized
42
+ version of that specific instance.
43
+
44
+
45
+ With the `global_id` matcher it's important to note that it's specific to ActiveJob-serialized GlobalIDs.
46
+ ActiveJob serializes them as a hash like `{ '_aj_global_id' => 'gid://my-app/MyModel/ID123' }`, to avoid
47
+ clashes with plain strings which accidentally match the GlobalID syntax. This matcher will not work with
48
+ other usages of GlobalID.
@@ -1,8 +1,14 @@
1
- require 'rspec/active_job/matchers'
1
+ require 'rspec/active_job/enqueue_a'
2
+ require 'rspec/active_job/global_id'
3
+
2
4
  module RSpec
3
5
  module ActiveJob
4
6
  def enqueue_a(job_class)
5
7
  Matchers::EnqueueA.new(job_class)
6
8
  end
9
+
10
+ def global_id(expected)
11
+ Matchers::GlobalID.new(expected)
12
+ end
7
13
  end
8
14
  end
@@ -27,10 +27,12 @@ module RSpec
27
27
  end
28
28
 
29
29
  unless enqueued_correct_class?
30
- return "expected to enqueue a #{job_class}, enqueued a #{enqueued_jobs.last[:job]}"
30
+ return "expected to enqueue a #{job_class}, " \
31
+ "enqueued a #{enqueued_jobs.last[:job]}"
31
32
  end
32
33
 
33
- "expected to enqueue a #{job_class} with #{argument_list_matcher.expected_args}, but enqueued with " \
34
+ "expected to enqueue a #{job_class} with " \
35
+ "#{argument_list_matcher.expected_args}, but enqueued with " \
34
36
  "#{new_jobs_with_correct_class.first[:args]}"
35
37
  end
36
38
 
@@ -38,6 +40,12 @@ module RSpec
38
40
  true
39
41
  end
40
42
 
43
+ def description
44
+ return "enqueue a job" unless job_class
45
+ return "enqueue a #{job_class.name}" unless argument_list_matcher
46
+ "enqueue a #{job_class.name} with #{argument_list_matcher.expected_args}"
47
+ end
48
+
41
49
  private
42
50
 
43
51
  attr_reader :before_count, :after_count, :job_class, :argument_list_matcher
@@ -65,7 +73,8 @@ module RSpec
65
73
  end
66
74
 
67
75
  def new_jobs_with_correct_class_and_args
68
- new_jobs_with_correct_class.select { |job| argument_list_matcher.args_match?(*job[:args]) }
76
+ new_jobs_with_correct_class.
77
+ select { |job| argument_list_matcher.args_match?(*job[:args]) }
69
78
  end
70
79
 
71
80
  def enqueued_jobs
@@ -0,0 +1,47 @@
1
+ require 'global_id'
2
+
3
+ module RSpec
4
+ module ActiveJob
5
+ module Matchers
6
+ class GlobalID
7
+ def initialize(expected)
8
+ unless valid_expected?(expected)
9
+ raise "expected argument must implement to_global_id"
10
+ end
11
+
12
+ @expected = expected
13
+ end
14
+
15
+ def ===(other)
16
+ other.is_a?(Hash) &&
17
+ other.keys == ['_aj_globalid'] &&
18
+ global_id_matches?(other['_aj_globalid'])
19
+ end
20
+
21
+ def description
22
+ "serialized global ID of #{@expected}" unless @expected.is_a?(Class)
23
+ "serialized global ID of #{@expected.name}"
24
+ end
25
+
26
+ private
27
+
28
+ def valid_expected?(expected)
29
+ return expected.instance_method(:to_global_id) if expected.is_a?(Class)
30
+ expected.respond_to?(:to_global_id)
31
+ end
32
+
33
+ def global_id_matches?(other)
34
+ parsed = ::GlobalID.parse(other)
35
+ return false unless parsed
36
+ return correct_class?(parsed) if @expected.is_a?(Class)
37
+ other == @expected.to_global_id.to_s
38
+ end
39
+
40
+ def correct_class?(other)
41
+ other.app == ::GlobalID.app &&
42
+ other.model_class == @expected
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module ActiveJob
3
- VERSION = '0.1.0'.freeze
3
+ VERSION = '0.2.0'.freeze
4
4
  end
5
5
  end
@@ -41,7 +41,7 @@ RSpec.describe RSpec::ActiveJob::Matchers::EnqueueA do
41
41
 
42
42
  context "when it enqueues two jobs" do
43
43
  let(:proc) do
44
- -> { enqueued_jobs << { job: AJob, args: []} << { job: BJob, args: [] } }
44
+ -> { enqueued_jobs << { job: AJob, args: [] } << { job: BJob, args: [] } }
45
45
  end
46
46
 
47
47
  it { is_expected.to be(true) }
@@ -70,4 +70,4 @@ RSpec.describe RSpec::ActiveJob::Matchers::EnqueueA do
70
70
  end
71
71
  end
72
72
  end
73
- end
73
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RSpec::ActiveJob::Matchers::GlobalID do
4
+ class MyModel
5
+ def to_global_id
6
+ "gid://my-app/MyModel/ID123"
7
+ end
8
+ end
9
+
10
+ let(:instance) { described_class.new(expected) }
11
+ subject(:matches?) { instance === actual }
12
+
13
+ before { GlobalID.app = 'my-app' }
14
+
15
+ context "expecting a class" do
16
+ let(:expected) { MyModel }
17
+
18
+ context "serialized model" do
19
+ let(:actual) { { '_aj_globalid' => 'gid://my-app/MyModel/ID123' } }
20
+ it { is_expected.to be(true) }
21
+ end
22
+
23
+ context "actual model" do
24
+ let(:actual) { MyModel.new }
25
+ it { is_expected.to be(false) }
26
+ end
27
+
28
+ context "model class" do
29
+ let(:actual) { MyModel }
30
+ it { is_expected.to be(false) }
31
+ end
32
+
33
+ context "hash with extra stuff" do
34
+ let(:actual) do
35
+ { '_aj_globalid' => 'gid://my-app/MyModel/ID123', 'other' => 'stuff' }
36
+ end
37
+ it { is_expected.to be(false) }
38
+ end
39
+
40
+ context "invalid GlobalID" do
41
+ let(:actual) { { '_aj_globalid' => 'not://a/global/id' } }
42
+ it { is_expected.to be(false) }
43
+ end
44
+
45
+ context "nil" do
46
+ let(:actual) { nil }
47
+ it { is_expected.to be(false) }
48
+ end
49
+ end
50
+
51
+ context "expecting a specific instance" do
52
+ let(:expected) { MyModel.new }
53
+
54
+ context "serialized instance" do
55
+ let(:actual) { { '_aj_globalid' => 'gid://my-app/MyModel/ID123' } }
56
+ it { is_expected.to be(true) }
57
+ end
58
+
59
+ context "model class" do
60
+ let(:actual) { MyModel }
61
+ it { is_expected.to be(false) }
62
+ end
63
+
64
+ context "instance itself" do
65
+ let(:actual) { expected }
66
+ it { is_expected.to be(false) }
67
+ end
68
+
69
+ context "hash with extra stuff" do
70
+ let(:actual) do
71
+ { '_aj_globalid' => 'gid://my-app/MyModel/ID123', 'other' => 'stuff' }
72
+ end
73
+ it { is_expected.to be(false) }
74
+ end
75
+
76
+ context "mismatching app" do
77
+ let(:actual) { { '_aj_globalid' => 'gid://other-app/MyModel/ID123' } }
78
+ it { is_expected.to be(false) }
79
+ end
80
+
81
+ context "mismatching model" do
82
+ let(:actual) { { '_aj_globalid' => 'gid://my-app/OtherModel/ID123' } }
83
+ it { is_expected.to be(false) }
84
+ end
85
+
86
+ context "mismatching ID" do
87
+ let(:actual) { { '_aj_globalid' => 'gid://my-app/MyModel/ID456' } }
88
+ it { is_expected.to be(false) }
89
+ end
90
+ end
91
+
92
+ context "expecting a non-gid instance" do
93
+ let(:expected) { Object.new }
94
+ specify { expect { matches? }.to raise_error }
95
+ end
96
+
97
+ context "expecting a non-gid class" do
98
+ let(:expected) { Object }
99
+ specify { expect { matches? }.to raise_error }
100
+ end
101
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-activejob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Isaac Seymour
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-18 00:00:00.000000000 Z
11
+ date: 2015-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -76,14 +76,18 @@ extensions: []
76
76
  extra_rdoc_files: []
77
77
  files:
78
78
  - .gitignore
79
+ - .rubocop.yml
80
+ - CHANGELOG.md
79
81
  - Gemfile
80
82
  - Gemfile.lock
81
83
  - README.md
82
84
  - lib/rspec/active_job.rb
83
- - lib/rspec/active_job/matchers.rb
85
+ - lib/rspec/active_job/enqueue_a.rb
86
+ - lib/rspec/active_job/global_id.rb
84
87
  - lib/rspec/active_job/version.rb
85
88
  - rspec-activejob.gemspec
86
- - spec/rspec/active_job/matchers_spec.rb
89
+ - spec/rspec/active_job/enqueue_a_spec.rb
90
+ - spec/rspec/active_job/global_id_spec.rb
87
91
  - spec/spec_helper.rb
88
92
  homepage: http://github.com/gocardless/rspec-activejob
89
93
  licenses: