brine-dsl 0.5.0 → 0.6.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: 2a3988772e5439b101fa2d3d9ab87034c04bb8a9
4
- data.tar.gz: c1491585ad2734877fb636a0f0880b02960e9172
3
+ metadata.gz: f3a218b02acd1fc90e2ca605c74ce54a37b9b05a
4
+ data.tar.gz: 7919bf69e899db000df3bdb3c682875e02d1df32
5
5
  SHA512:
6
- metadata.gz: 72aa061fc15c4f629f74fc2ce37aa8c2818570591647dd33e8a7b0dde906f3daf735a2b22845210bb90636a3c04c2961e89b19b2cb463f198b8bd806779f8755
7
- data.tar.gz: 8888baf7504c251f3011660bdb96eebb66f2f3abe3ae206b6418cc7d0f9d8048bcf1a2fd2ccdf84a22c9c016b2be6c01500419deffca8ab4341976f271f1a421
6
+ metadata.gz: 52d2907d296a7794f619adbd6dfafabe45aa6d572c50d0520edea5310c47fbc91eed1c937b73551960ef1f89da8d35a7239bfa7f618e44bf9c095eec6c197430
7
+ data.tar.gz: 31b7748a12f98aa942d21e6e58ac7c26ed014bbf3c66bc9bb19308568fc52b70b8d62209fa8ab5fdfe6ed3d7b0743da889ad1910264a2761526c92ba0f2e7e14
data/.gitignore CHANGED
@@ -1,4 +1,3 @@
1
1
  pkg/
2
2
  tmp
3
3
  .gradle
4
- *~
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- brine-dsl (0.5.0)
4
+ brine-dsl (0.6.0.pre.SNAPSHOT)
5
5
  cucumber (~> 2.4)
6
6
  faraday
7
7
  faraday_middleware
@@ -59,8 +59,9 @@ GEM
59
59
  cucumber (~> 2.0)
60
60
  guard-compat (~> 1.0)
61
61
  nenv (~> 0.1)
62
- jsonpath (0.8.10)
62
+ jsonpath (0.8.11)
63
63
  multi_json
64
+ to_regexp (~> 0.2.1)
64
65
  jwt (1.5.6)
65
66
  listen (3.1.5)
66
67
  rb-fsevent (~> 0.9, >= 0.9.4)
@@ -86,7 +87,7 @@ GEM
86
87
  pry (0.11.3)
87
88
  coderay (~> 1.1.0)
88
89
  method_source (~> 0.9.0)
89
- rack (2.0.3)
90
+ rack (2.0.4)
90
91
  rake (12.3.0)
91
92
  rb-fsevent (0.10.2)
92
93
  rb-inotify (0.9.10)
@@ -95,7 +96,7 @@ GEM
95
96
  rspec-core (~> 3.7.0)
96
97
  rspec-expectations (~> 3.7.0)
97
98
  rspec-mocks (~> 3.7.0)
98
- rspec-core (3.7.0)
99
+ rspec-core (3.7.1)
99
100
  rspec-support (~> 3.7.0)
100
101
  rspec-expectations (3.7.0)
101
102
  diff-lcs (>= 1.2.0, < 2.0)
@@ -107,6 +108,7 @@ GEM
107
108
  ruby_dep (1.5.0)
108
109
  shellany (0.0.1)
109
110
  thor (0.20.0)
111
+ to_regexp (0.2.1)
110
112
 
111
113
  PLATFORMS
112
114
  ruby
data/README.md CHANGED
@@ -3,135 +3,5 @@ Brine
3
3
 
4
4
  > Cucumber DSL for testing REST APIs
5
5
 
6
- Motivation
7
- ---
8
- REpresentational State Transfer APIs expose their functionality
9
- through combinations of fairly coarse primitives that generally
10
- revolve around the use of transferring data in a standard exchange
11
- format (such as JSON) using HTTP methods and other aspects of the very
12
- simple HTTP protocol. Tests for such an API can therefore be defined
13
- using a domain specific language (DSL) built around those higher level
14
- ideas rather than requiring a general purpose language (the equivalent
15
- of scripted `curl` commands with some glue code and assertions).
16
- This project provides such a DSL by using select libraries
17
- integrated into Cucumber, where Cucumber provides a test-oriented
18
- framework for DSL creation.
19
-
20
- Sample Usage
21
- ---
22
- The general usage pattern revolves around construction of a request
23
- and performing assertions against the received response.
24
-
25
- ```gherkin
26
- When the request body is assigned:
27
- """
28
- {"first_name": "John",
29
- "last_name": "Smith"}
30
- """
31
- And a POST is sent to `/users`
32
- Then the value of the response status is equal to `200`
33
- And the value of the response body is including:
34
- """
35
- {"first_name": "John",
36
- "last_name": "Smith"}
37
- """
38
- ```
39
-
40
- Disclaimer
41
- ---
42
- Right now this project is new and features are being implemented as
43
- needed rather than speculatively. Some of the info here may be more
44
- optimistic than realistic until things are smoothed out or hopes abandoned.
45
-
46
- Features
47
- ---
48
-
49
- ### Variable Binding/Expansion
50
-
51
- In cases where dynamic data is in the response or is desired for the
52
- request, then values can be bound to identifiers which can then be
53
- expanded using [Mustache](mustache.github.io) templates in your
54
- feature files.
55
-
56
- ### Type Transforms
57
-
58
- Different types of data can be expressed directly in the feature files
59
- or expanded into variables by using the appropriate syntax for that
60
- type.
61
-
62
- [Read More](https://github.com/brightcove/brine/wiki/Argument-Transforms)
63
-
64
- #### Type Coercion
65
-
66
- Related to transforms, a facility to coerce types is also provided. This allows
67
- more intelligent comparison of inputs which have been transformed to a
68
- richer data type with those that have not been transformed (normally strings).
69
- As an example comparing a date/time value with a string will attempt to parse
70
- the string to a date/time so that the values can be compared using the proper semantics.
71
-
72
- ### Resource Cleanup
73
-
74
- Tests are likely to create resources which should then be cleaned up,
75
- restoring the pre-test state of the system: steps to facilitate this
76
- are provided.
77
-
78
- ### Authentication
79
-
80
- Presently OAuth2 is supported to issue authenticated requests during a
81
- test (likely using a feature `Background`).
82
-
83
- ### Division of Selection and Assertion
84
-
85
- To allow for a wider range of tests without an exploding code base
86
- (and keeping the assertions easier to write), Brine internall splits the
87
- selection of the value(s) to test from the assertion(s) that will be performed against it.
88
-
89
- [Read Mode](https://github.com/brightcove/brine/wiki/Selection-and-Assertion)
90
-
91
- ### Request Construction and Response Assertion Step Definitions
92
-
93
- The previous features combined with the library of provide steps should
94
- cover all of the functionality needed to exercise and validate all of
95
- the functionality exposed by your REST API.
96
-
97
-
98
- Installation
99
- ---
100
-
101
- Presently the gem for this project isn't being published anywhere:
102
- primarily because tracking down a local gem repository seems scary. If
103
- this project is open sourced then this will probably change but in the
104
- meantime the project can be used off of GitHub by adding this to your
105
- `Gemfile` and performing the usual `bundle install` dance:
106
-
107
- ```ruby
108
- git 'git@github.com:brightcove/brine.git', :branch => 'master' do
109
- gem 'brine'
110
- end
111
- ```
112
-
113
- Specific branches and refs can be targetted as
114
- documented [here](http://bundler.io/git.html). This should likely be
115
- done in any cases where you're not actively tracking Brine and don't want
116
- your tests to suddenly break because of changes to it.
117
-
118
- Brine can then be "mixed in" to your project (which adds assorted
119
- modules to the `World` and loads all the step definitions and other
120
- Cucumber magic) by adding the following to your `support/env.rb` or
121
- other ruby file:
122
-
123
- ```ruby
124
- require 'brine'
125
-
126
- World(brine_mix)
127
- ```
128
-
129
- Select pieces can also be loaded (to be documented). With the above,
130
- feature files should be able to be written and executed without
131
- requiring any additional ruby code.
132
-
133
- Questions? Comments?
134
- ---
135
- Check out the [wiki](https://github.com/brightcove/brine/wiki) for more information
136
- and search for related [issues](https://github.com/brightcove/brine/issues)
137
- or open one for anything not documented or implemented elsewhere.
6
+ Documentation is hosted at:
7
+ https://brightcove.github.io/brine/
data/Rakefile CHANGED
@@ -1,6 +1,9 @@
1
1
  # encoding: utf-8
2
+ require 'bundler'
2
3
  require 'cucumber/rake/task'
4
+
3
5
  Cucumber::Rake::Task.new
6
+ Bundler::GemHelper.install_tasks
4
7
 
5
8
  task default: %w[check]
6
9
 
data/brine-dsl.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'brine-dsl'
4
- s.version = '0.5.0'
4
+ s.version = '0.6.0'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Matt Whipple"]
7
7
  s.email = ["mwhipple@brightcove.com"]
data/docs/cookbook.html CHANGED
@@ -427,13 +427,20 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
427
427
  <div id="toctitle">Table of Contents</div>
428
428
  <ul class="sectlevel1">
429
429
  <li><a href="#_overview">Overview</a></li>
430
- <li><a href="#__assurances">"Assurances"</a>
430
+ <li><a href="#_intercepting_of_http_calls">Intercepting of HTTP Calls</a>
431
431
  <ul class="sectlevel2">
432
432
  <li><a href="#_context">Context</a></li>
433
433
  <li><a href="#_solution">Solution</a></li>
434
434
  <li><a href="#_recipe">Recipe</a></li>
435
435
  </ul>
436
436
  </li>
437
+ <li><a href="#__assurances">"Assurances"</a>
438
+ <ul class="sectlevel2">
439
+ <li><a href="#_context_2">Context</a></li>
440
+ <li><a href="#_solution_2">Solution</a></li>
441
+ <li><a href="#_recipe_2">Recipe</a></li>
442
+ </ul>
443
+ </li>
437
444
  </ul>
438
445
  </div>
439
446
  </div>
@@ -447,14 +454,75 @@ Brine but are not considered part of Brine&#8217;s responsibility (at least pres
447
454
  Many of these are focused on simplicity and ease rather than robustness or elegance,
448
455
  and modification to address specific cases should be expected.</p>
449
456
  </div>
457
+ <div class="paragraph">
458
+ <p>Many of these will also be platform specific and be subject to further organization
459
+ once platforms beyond ruby are supported.</p>
460
+ </div>
450
461
  </div>
451
462
  </div>
452
463
  <div class="sect1">
453
- <h2 id="__assurances">"Assurances"</h2>
464
+ <h2 id="_intercepting_of_http_calls">Intercepting of HTTP Calls</h2>
454
465
  <div class="sectionbody">
455
466
  <div class="sect2">
456
467
  <h3 id="_context">Context</h3>
457
468
  <div class="paragraph">
469
+ <p>There may be cases where the request or reponse may need to be modified
470
+ in some way before or after transmission, for example to add a custom header
471
+ which is somehow specific to the testing configuration and therefore outside
472
+ of anything that belongs in the specification.</p>
473
+ </div>
474
+ </div>
475
+ <div class="sect2">
476
+ <h3 id="_solution">Solution</h3>
477
+ <div class="paragraph">
478
+ <p>This can be done through the registration of custom Faraday middleware on
479
+ the Brine client. All of the registered middleware attaches
480
+ to the generated connection through an array of functions in
481
+ <a href="https://github.com/brightcove/brine/blob/master/lib/brine/requester.rb">requester.rb</a>.
482
+ Each function accepts the connection object as its single parameter. The array of functions
483
+ is exposed as <code>connection_handlers</code> and can be modified through getting that property
484
+ from either the default <code>World</code> (for the default client) or from an appropriate <code>ClientBuilder</code>
485
+ if creating custom clients and mutating it accordingly (setting the reference is not suported).
486
+ You could just build your own client without the facilities provided by Brine.</p>
487
+ </div>
488
+ </div>
489
+ <div class="sect2">
490
+ <h3 id="_recipe">Recipe</h3>
491
+ <div class="paragraph">
492
+ <p>An example to add a custom header could be implemented as follows:</p>
493
+ </div>
494
+ <div class="listingblock">
495
+ <div class="content">
496
+ <pre class="highlightjs highlight"><code class="language-ruby" data-lang="ruby">require 'faraday'
497
+ class CustomHeaderAdder &lt; Faraday::Middleware
498
+ def initialize(app, key, val)
499
+ super(app)
500
+ @key = key
501
+ @val = val
502
+ end
503
+
504
+ def call(env)
505
+ env[:request_headers].merge!({@key =&gt; @val})
506
+ @app.call(env)
507
+ end
508
+ end
509
+
510
+ ...
511
+
512
+ connection_handlers.unshift(proc do |conn|
513
+ conn.use CustomHeaderAdder, 'x-header', 'I am a test'
514
+ end)</code></pre>
515
+ </div>
516
+ </div>
517
+ </div>
518
+ </div>
519
+ </div>
520
+ <div class="sect1">
521
+ <h2 id="__assurances">"Assurances"</h2>
522
+ <div class="sectionbody">
523
+ <div class="sect2">
524
+ <h3 id="_context_2">Context</h3>
525
+ <div class="paragraph">
458
526
  <p>Ideally all tests should be as self-contained and isolated as possible;
459
527
  when writing functional tests, however, there are cases where this isn&#8217;t
460
528
  feasible or possible. In some cases a system depends on another external
@@ -474,7 +542,7 @@ complete test isolation.</p>
474
542
  </div>
475
543
  </div>
476
544
  <div class="sect2">
477
- <h3 id="_solution">Solution</h3>
545
+ <h3 id="_solution_2">Solution</h3>
478
546
  <div class="paragraph">
479
547
  <p>In such cases a standard solution is to designate certain resources to be reused for
480
548
  certain tests. These are analogous to the concept of "fixtures" in some test suites
@@ -517,7 +585,7 @@ up test runs through the use of parallelism/asynchronicity.</p>
517
585
  </div>
518
586
  </div>
519
587
  <div class="sect2">
520
- <h3 id="_recipe">Recipe</h3>
588
+ <h3 id="_recipe_2">Recipe</h3>
521
589
  <div class="paragraph">
522
590
  <p>This can be done using standard cucumber tags. Assurances can be defined in designated
523
591
  <code>assure_*.feature</code> files where each Feature is appropriately tagged:</p>
@@ -560,7 +628,7 @@ Cucumber behavior so that the full test suite can be more stochastic
560
628
  </div>
561
629
  <div id="footer">
562
630
  <div id="footer-text">
563
- Last updated 2017-10-25 10:06:13 -04:00
631
+ Last updated 2018-02-08 14:37:47 EST
564
632
  </div>
565
633
  </div>
566
634
  </body>
data/docs/guide.html CHANGED
@@ -578,24 +578,18 @@ the functionality exposed by your REST API.</p>
578
578
  <h2 id="_installation">Installation</h2>
579
579
  <div class="sectionbody">
580
580
  <div class="paragraph">
581
- <p>Presently the gem for this project isn&#8217;t being published anywhere:
582
- primarily because tracking down a local gem repository seems scary. If
583
- this project is open sourced then this will probably change but in the
584
- meantime the project can be used off of GitHub by adding this to your
585
- <code>Gemfile</code> and performing the usual <code>bundle install</code> dance:</p>
581
+ <p>Brine is published as <code>brine-dsl</code> on rubygems, the page for which is
582
+ at <a href="https://rubygems.org/gems/brine-dsl" class="bare">https://rubygems.org/gems/brine-dsl</a>. The latest version and other
583
+ gem metadata can be viewed on that page. Brine can be used by
584
+ declaring that gem in your project Gemfile such as:</p>
586
585
  </div>
587
586
  <div class="listingblock">
588
587
  <div class="content">
589
- <pre class="highlightjs highlight"><code class="language-ruby" data-lang="ruby">git 'git@github.com:brightcove/brine.git', :branch =&gt; 'master' do
590
- gem 'brine'
591
- end</code></pre>
588
+ <pre class="highlightjs highlight"><code class="language-ruby" data-lang="ruby">gem 'brine-dsl', '~&gt; 1.0'</code></pre>
592
589
  </div>
593
590
  </div>
594
591
  <div class="paragraph">
595
- <p>Specific branches and refs can be targetted as
596
- documented <a href="http://bundler.io/git.html">here</a>. This should likely be
597
- done in any cases where you&#8217;re not actively tracking Brine and don&#8217;t want
598
- your tests to suddenly break because of changes to it.</p>
592
+ <p>(after version 1.0 is released).</p>
599
593
  </div>
600
594
  <div class="paragraph">
601
595
  <p>Brine can then be "mixed in" to your project (which adds assorted
@@ -1105,6 +1099,12 @@ which the step was evaluated.</p>
1105
1099
  <dd>
1106
1100
  <p>Assert that the current select value includes/is a superset of <code>VALUE</code>.</p>
1107
1101
  </dd>
1102
+ <dt class="hdlist1"><code>Then it is empty</code></dt>
1103
+ <dd>
1104
+ <p> Assert that value is empty or null. Any type which is not testable for emptiness
1105
+ (such as booleans or numbers) will always return false. Null is treated as an empty
1106
+ value so that it can be treated as such for endpoints that return null in place of empty collections, and non-null empty values can easily be tested for using conjunction.</p>
1107
+ </dd>
1108
1108
  <dt class="hdlist1"><code>Then it is a valid `$TYPE`</code></dt>
1109
1109
  <dd>
1110
1110
  <p> Assert that the selected value is a valid instance of a <code>TYPE</code>. Presently this
@@ -1142,7 +1142,7 @@ wiring and documentation. The current supported types are:</p>
1142
1142
  </div>
1143
1143
  <div id="footer">
1144
1144
  <div id="footer-text">
1145
- Last updated 2017-11-15 22:28:26 -05:00
1145
+ Last updated 2018-02-08 12:09:12 EST
1146
1146
  </div>
1147
1147
  </div>
1148
1148
  </body>
data/docs/index.html CHANGED
@@ -465,7 +465,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
465
465
  </div>
466
466
  <div id="footer">
467
467
  <div id="footer-text">
468
- Last updated 2017-10-25 10:06:13 -04:00
468
+ Last updated 2017-10-17 16:14:35 EDT
469
469
  </div>
470
470
  </div>
471
471
  </body>
data/docs/specs.html CHANGED
@@ -451,6 +451,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
451
451
  <li><a href="#__span_class_feature_name_equal_to_span"><span class="feature name">Equal to</span></a></li>
452
452
  <li><a href="#__span_class_feature_name_matching_span"><span class="feature name">Matching</span></a></li>
453
453
  <li><a href="#__span_class_feature_name_including_span"><span class="feature name">Including</span></a></li>
454
+ <li><a href="#__span_class_feature_name_empty_span"><span class="feature name">Empty</span></a></li>
454
455
  <li><a href="#__span_class_feature_name_a_valid_span"><span class="feature name">A valid &#8230;&#8203;</span></a></li>
455
456
  </ul>
456
457
  </li>
@@ -1247,10 +1248,10 @@ Then the value of the response body children `..val` has elements which are all
1247
1248
  <div class="sect2">
1248
1249
  <h3 id="__span_class_feature_name_equal_to_span"><span class="feature name">Equal to</span></h3>
1249
1250
  <div class="paragraph">
1250
- <p>It can be asserted that a value is equal to another value</p>
1251
+ <p>It can be asserted that a value is equal to another value.</p>
1251
1252
  </div>
1252
1253
  <div class="sect3">
1253
- <h4 id="__span_class_scenario_name_assorted_positive_and_negative_assertions_span_3"><span class="scenario name">Assorted positive and negative assertions.</span></h4>
1254
+ <h4 id="__span_class_scenario_name_assorted_positive_and_negative_assertions_pass_span"><span class="scenario name">Assorted positive and negative assertions pass.</span></h4>
1254
1255
  <div class="ulist step-list">
1255
1256
  <ul>
1256
1257
  <li>
@@ -1334,10 +1335,10 @@ Examples:
1334
1335
  <div class="sect2">
1335
1336
  <h3 id="__span_class_feature_name_matching_span"><span class="feature name">Matching</span></h3>
1336
1337
  <div class="paragraph">
1337
- <p>It can be asserted that a value matches another string or regex</p>
1338
+ <p>It can be asserted that a value matches another string or regex.</p>
1338
1339
  </div>
1339
1340
  <div class="sect3">
1340
- <h4 id="__span_class_scenario_name_assorted_positive_and_negative_assertions_span_4"><span class="scenario name">Assorted positive and negative assertions.</span></h4>
1341
+ <h4 id="__span_class_scenario_name_assorted_positive_and_negative_assertions_span_3"><span class="scenario name">Assorted positive and negative assertions.</span></h4>
1341
1342
  <div class="ulist step-list">
1342
1343
  <ul>
1343
1344
  <li>
@@ -1347,8 +1348,8 @@ Examples:
1347
1348
  </div>
1348
1349
  <div class="listingblock">
1349
1350
  <div class="content">
1350
- <pre class="highlightjs highlight"><code class="language-gherkin" data-lang="gherkin">Feature: Assert value matchiness
1351
- Scenario: String in response body matched against a regex
1351
+ <pre class="highlightjs highlight"><code class="language-gherkin" data-lang="gherkin">Feature: Assert value matchiness.
1352
+ Scenario: String in response body is matched against a regex.
1352
1353
  When the response body is assigned:
1353
1354
  """
1354
1355
  http://www.github.com?var=val
@@ -1452,6 +1453,99 @@ And the value of the response body is not including:
1452
1453
  </div>
1453
1454
  </div>
1454
1455
  <div class="sect2">
1456
+ <h3 id="__span_class_feature_name_empty_span"><span class="feature name">Empty</span></h3>
1457
+ <div class="paragraph">
1458
+ <p>It can be asserted that a value is empty.</p>
1459
+ </div>
1460
+ <div class="sect3">
1461
+ <h4 id="__span_class_scenario_name_assorted_positive_and_negative_assertions_pass_span_2"><span class="scenario name">Assorted positive and negative assertions pass.</span></h4>
1462
+ <div class="ulist step-list">
1463
+ <ul>
1464
+ <li>
1465
+ <p><strong>Given</strong> a file named "features/is_empty.feature" with:</p>
1466
+ </li>
1467
+ </ul>
1468
+ </div>
1469
+ <div class="listingblock">
1470
+ <div class="content">
1471
+ <pre class="highlightjs highlight"><code class="language-gherkin" data-lang="gherkin">Feature: Assert emptiness for multiple types.
1472
+ Scenario: Empty body is empty.
1473
+ When the response body is assigned ``
1474
+ Then the value of the response body is empty
1475
+
1476
+ Scenario: Whitespace-only body is empty.
1477
+ When the response body is assigned:
1478
+ """
1479
+
1480
+ """
1481
+ Then the value of the response body is empty
1482
+
1483
+ Scenario: Empty string is empty.
1484
+ When the response body is assigned `""`
1485
+ Then the value of the response body is empty
1486
+
1487
+ Scenario: Non-empty string is not empty.
1488
+ When the response body is assigned `blah`
1489
+ Then the value of the response body is not empty
1490
+
1491
+ Scenario: Quoted whitespace is not empty.
1492
+ When the response body is assigned `" "`
1493
+ Then the value of the response body is not empty
1494
+
1495
+ Scenario: Empty arrays are empty.
1496
+ When the response body is assigned `[]`
1497
+ Then the value of the response body is empty
1498
+
1499
+ Scenario: Non-empty arrays are not empty.
1500
+ When the response body is assigned `[[]]`
1501
+ Then the value of the response body is not empty
1502
+
1503
+ Scenario: Empty objects are empty.
1504
+ When the response body is assigned `{}`
1505
+ Then the value of the response body is empty
1506
+
1507
+ Scenario: Non-empty objects are not empty.
1508
+ When the response body is assigned `{"foo":{}}`
1509
+ Then the value of the response body is not empty
1510
+
1511
+ Scenario: Null values are empty.
1512
+ When the response body is assigned `{"foo": null}`
1513
+ Then the value of the response body child `foo` is empty
1514
+
1515
+ Scenario: False is not empty.
1516
+ When the response body is assigned `false`
1517
+ Then the value of the response body is not empty
1518
+
1519
+ Scenario: 0 is not empty.
1520
+ When the response body is assigned `0`
1521
+ Then the value of the response body is not empty</code></pre>
1522
+ </div>
1523
+ </div>
1524
+ <div class="ulist">
1525
+ <ul>
1526
+ <li>
1527
+ <p><strong>When</strong> I run <code>cucumber --strict features/is_empty.feature</code></p>
1528
+ </li>
1529
+ <li>
1530
+ <p><strong>Then</strong> the output should contain:</p>
1531
+ </li>
1532
+ </ul>
1533
+ </div>
1534
+ <div class="listingblock">
1535
+ <div class="content">
1536
+ <pre class="highlightjs highlight"><code class="language-gherkin" data-lang="gherkin">12 passed</code></pre>
1537
+ </div>
1538
+ </div>
1539
+ <div class="ulist">
1540
+ <ul>
1541
+ <li>
1542
+ <p><strong>And</strong> it should pass</p>
1543
+ </li>
1544
+ </ul>
1545
+ </div>
1546
+ </div>
1547
+ </div>
1548
+ <div class="sect2">
1455
1549
  <h3 id="__span_class_feature_name_a_valid_span"><span class="feature name">A valid &#8230;&#8203;</span></h3>
1456
1550
  <div class="sect3">
1457
1551
  <h4 id="__span_class_scenario_name_positive_and_negative_assertions_for_json_types_span"><span class="scenario name">Positive and negative assertions for JSON types.</span></h4>
@@ -1665,7 +1759,7 @@ Then the value of the response body children `.val` has elements which are all a
1665
1759
  </div>
1666
1760
  <div id="footer">
1667
1761
  <div id="footer-text">
1668
- Last updated 2017-11-16 16:15:35 -05:00
1762
+ Last updated 2018-02-08 12:09:12 EST
1669
1763
  </div>
1670
1764
  </div>
1671
1765
  </body>
@@ -4,13 +4,67 @@ Matt Whipple <http://github.com/mwhipple[@mwhipple]>
4
4
  :keywords: Brine, Cucumber, REST, DSL
5
5
 
6
6
  == Overview
7
+
7
8
  The following are some recipes to address issues which may arise while using
8
9
  Brine but are not considered part of Brine's responsibility (at least presently).
9
10
  Many of these are focused on simplicity and ease rather than robustness or elegance,
10
11
  and modification to address specific cases should be expected.
11
12
 
13
+ Many of these will also be platform specific and be subject to further organization
14
+ once platforms beyond ruby are supported.
15
+
16
+ == Intercepting of HTTP Calls
17
+
18
+ === Context
19
+
20
+ There may be cases where the request or reponse may need to be modified
21
+ in some way before or after transmission, for example to add a custom header
22
+ which is somehow specific to the testing configuration and therefore outside
23
+ of anything that belongs in the specification.
24
+
25
+ === Solution
26
+
27
+ This can be done through the registration of custom Faraday middleware on
28
+ the Brine client. All of the registered middleware attaches
29
+ to the generated connection through an array of functions in
30
+ https://github.com/brightcove/brine/blob/master/lib/brine/requester.rb[requester.rb].
31
+ Each function accepts the connection object as its single parameter. The array of functions
32
+ is exposed as `connection_handlers` and can be modified through getting that property
33
+ from either the default `World` (for the default client) or from an appropriate `ClientBuilder`
34
+ if creating custom clients and mutating it accordingly (setting the reference is not suported).
35
+ You could just build your own client without the facilities provided by Brine.
36
+
37
+ === Recipe
38
+
39
+ An example to add a custom header could be implemented as follows:
40
+
41
+ [source,ruby]
42
+ ----
43
+ require 'faraday'
44
+ class CustomHeaderAdder < Faraday::Middleware
45
+ def initialize(app, key, val)
46
+ super(app)
47
+ @key = key
48
+ @val = val
49
+ end
50
+
51
+ def call(env)
52
+ env[:request_headers].merge!({@key => @val})
53
+ @app.call(env)
54
+ end
55
+ end
56
+
57
+ ...
58
+
59
+ connection_handlers.unshift(proc do |conn|
60
+ conn.use CustomHeaderAdder, 'x-header', 'I am a test'
61
+ end)
62
+ ----
63
+
12
64
  == "Assurances"
65
+
13
66
  === Context
67
+
14
68
  Ideally all tests should be as self-contained and isolated as possible;
15
69
  when writing functional tests, however, there are cases where this isn't
16
70
  feasible or possible. In some cases a system depends on another external
@@ -28,6 +82,7 @@ and the number of accounts is limited, then that is likely to unfortunately prev
28
82
  complete test isolation.
29
83
 
30
84
  === Solution
85
+
31
86
  In such cases a standard solution is to designate certain resources to be reused for
32
87
  certain tests. These are analogous to the concept of "fixtures" in some test suites
33
88
  though there may be slight differences in implementation and reliance on them.
@@ -41,6 +96,7 @@ validate that preconditions are met; ideally if such preconditions can be establ
41
96
  idempotently then the assurances can do so before the validation.
42
97
 
43
98
  ==== Assurances are NOT Tests
99
+
44
100
  **Assurances validate a state which is desired to be consistently retained within the
45
101
  system rather than being changed**. This means that they should _not_ be used for tests
46
102
  as that would require state changes, nor should they clean up after themselves (as that
data/docs/src/guide.adoc CHANGED
@@ -75,23 +75,17 @@ cover all of the functionality needed to exercise and validate all of
75
75
  the functionality exposed by your REST API.
76
76
 
77
77
  == Installation
78
- Presently the gem for this project isn't being published anywhere:
79
- primarily because tracking down a local gem repository seems scary. If
80
- this project is open sourced then this will probably change but in the
81
- meantime the project can be used off of GitHub by adding this to your
82
- `Gemfile` and performing the usual `bundle install` dance:
78
+ Brine is published as `brine-dsl` on rubygems, the page for which is
79
+ at https://rubygems.org/gems/brine-dsl. The latest version and other
80
+ gem metadata can be viewed on that page. Brine can be used by
81
+ declaring that gem in your project Gemfile such as:
83
82
 
84
83
  [source,ruby]
85
84
  ----
86
- git 'git@github.com:brightcove/brine.git', :branch => 'master' do
87
- gem 'brine'
88
- end
85
+ gem 'brine-dsl', '~> 1.0'
89
86
  ----
90
87
 
91
- Specific branches and refs can be targetted as
92
- documented http://bundler.io/git.html[here]. This should likely be
93
- done in any cases where you're not actively tracking Brine and don't want
94
- your tests to suddenly break because of changes to it.
88
+ (after version 1.0 is released).
95
89
 
96
90
  Brine can then be "mixed in" to your project (which adds assorted
97
91
  modules to the `World` and loads all the step definitions and other
@@ -414,6 +408,11 @@ _see <<_selection_and_assertion>>_
414
408
  `Then it is including {grave}$VALUE{grave}`::
415
409
  Assert that the current select value includes/is a superset of `VALUE`.
416
410
 
411
+ `Then it is empty`::
412
+ Assert that value is empty or null. Any type which is not testable for emptiness
413
+ (such as booleans or numbers) will always return false. Null is treated as an empty
414
+ value so that it can be treated as such for endpoints that return null in place of empty collections, and non-null empty values can easily be tested for using conjunction.
415
+
417
416
  `Then it is a valid {grave}$TYPE{grave}`::
418
417
  Assert that the selected value is a valid instance of a `TYPE`. Presently this
419
418
  is focused on standard data types (intially based on those specified by JSON),
@@ -424,4 +423,4 @@ wiring and documentation. The current supported types are:
424
423
  * `Number`
425
424
  * `Integer`
426
425
  * `Array`
427
- * `Boolean`
426
+ * `Boolean`
data/docs/src/specs.adoc CHANGED
@@ -21,4 +21,5 @@ gherkin::../../features/selectors/all.feature[spec.erb]
21
21
  gherkin::../../features/assertions/is_equal_to.feature[spec.erb]
22
22
  gherkin::../../features/assertions/is_matching.feature[spec.erb]
23
23
  gherkin::../../features/assertions/is_including.feature[spec.erb]
24
- gherkin::../../features/assertions/is_a_valid.feature[spec.erb]
24
+ gherkin::../../features/assertions/is_empty.feature[spec.erb]
25
+ gherkin::../../features/assertions/is_a_valid.feature[spec.erb]
@@ -0,0 +1,67 @@
1
+ Feature: Empty
2
+ It can be asserted that a value is empty.
3
+
4
+ Scenario: Assorted positive and negative assertions pass.
5
+ Given a file named "features/is_empty.feature" with:
6
+ """
7
+
8
+ Feature: Assert emptiness for multiple types.
9
+ Scenario: Empty body is empty.
10
+ When the response body is assigned ``
11
+ Then the value of the response body is empty
12
+
13
+ Scenario: Whitespace-only body is empty.
14
+ When the response body is assigned:
15
+ \"\"\"
16
+
17
+ \"\"\"
18
+ Then the value of the response body is empty
19
+
20
+ Scenario: Empty string is empty.
21
+ When the response body is assigned `""`
22
+ Then the value of the response body is empty
23
+
24
+ Scenario: Non-empty string is not empty.
25
+ When the response body is assigned `blah`
26
+ Then the value of the response body is not empty
27
+
28
+ Scenario: Quoted whitespace is not empty.
29
+ When the response body is assigned `" "`
30
+ Then the value of the response body is not empty
31
+
32
+ Scenario: Empty arrays are empty.
33
+ When the response body is assigned `[]`
34
+ Then the value of the response body is empty
35
+
36
+ Scenario: Non-empty arrays are not empty.
37
+ When the response body is assigned `[[]]`
38
+ Then the value of the response body is not empty
39
+
40
+ Scenario: Empty objects are empty.
41
+ When the response body is assigned `{}`
42
+ Then the value of the response body is empty
43
+
44
+ Scenario: Non-empty objects are not empty.
45
+ When the response body is assigned `{"foo":{}}`
46
+ Then the value of the response body is not empty
47
+
48
+ Scenario: Null values are empty.
49
+ When the response body is assigned `{"foo": null}`
50
+ Then the value of the response body child `foo` is empty
51
+
52
+ Scenario: False is not empty.
53
+ When the response body is assigned `false`
54
+ Then the value of the response body is not empty
55
+
56
+ Scenario: 0 is not empty.
57
+ When the response body is assigned `0`
58
+ Then the value of the response body is not empty
59
+
60
+ """
61
+ When I run `cucumber --strict features/is_empty.feature`
62
+ Then the output should contain:
63
+ """
64
+ 12 passed
65
+ """
66
+ And it should pass
67
+
@@ -1,7 +1,7 @@
1
1
  Feature: Equal to
2
- It can be asserted that a value is equal to another value
2
+ It can be asserted that a value is equal to another value.
3
3
 
4
- Scenario: Assorted positive and negative assertions.
4
+ Scenario: Assorted positive and negative assertions pass.
5
5
  Given a file named "features/is_equal_to.feature" with:
6
6
  """
7
7
 
@@ -1,12 +1,12 @@
1
1
  Feature: Matching
2
- It can be asserted that a value matches another string or regex
2
+ It can be asserted that a value matches another string or regex.
3
3
 
4
4
  Scenario: Assorted positive and negative assertions.
5
5
  Given a file named "features/is_matching.feature" with:
6
6
  """
7
7
 
8
- Feature: Assert value matchiness
9
- Scenario: String in response body matched against a regex
8
+ Feature: Assert value matchiness.
9
+ Scenario: String in response body is matched against a regex.
10
10
  When the response body is assigned:
11
11
  \"\"\"
12
12
  http://www.github.com?var=val
@@ -32,4 +32,4 @@ Feature: Assert value matchiness
32
32
  """
33
33
  2 passed
34
34
  """
35
- And it should pass
35
+ And it should pass
@@ -32,21 +32,32 @@ module ClientBuilding
32
32
  self
33
33
  end
34
34
 
35
+ # This is represented as list of functions so that it can be more easily customized for
36
+ # unexpected use cases.
37
+ # It should likely be broken up a bit more sensibly and more useful insertion commands added...
38
+ # but it's likely enough of a power feature and platform specific to leave pretty raw.
39
+ def connection_handlers
40
+ @connection_handlers ||= [
41
+ proc do |conn|
42
+ conn.request :json
43
+ if @oauth2
44
+ conn.request :oauth2, @oauth2.token, :token_type => @oauth2.token_type
45
+ end
46
+ end,
47
+ proc do |conn|
48
+ if @logging
49
+ conn.response :logger, nil, :bodies => (@logging.casecmp('DEBUG') == 0)
50
+ end
51
+ conn.response :json, :content_type => /\bjson$/
52
+ end,
53
+ proc{|conn| conn.adapter Faraday.default_adapter }
54
+ ]
55
+ end
56
+
35
57
  def client_for_host(host, logging: ENV['BRINE_LOG_HTTP'])
58
+ @logging = logging
36
59
  Faraday.new(host) do |conn|
37
- conn.request :json
38
-
39
- if @oauth2
40
- conn.request :oauth2, @oauth2.token, :token_type => @oauth2.token_type
41
- end
42
-
43
- if logging
44
- conn.response :logger, nil, :bodies => (logging.casecmp('DEBUG') == 0)
45
- end
46
-
47
- conn.response :json, :content_type => /\bjson$/
48
-
49
- conn.adapter Faraday.default_adapter
60
+ connection_handlers.each{|h| h.call(conn) }
50
61
  end
51
62
  end
52
63
  end
@@ -25,6 +25,13 @@ Then(/^it is less than or equal to `([^`]*)`$/) do |value|
25
25
  selector.assert_that(value) {|v| be <= v}
26
26
  end
27
27
 
28
+ # Be a little smarter than default.
29
+ Then(/^it is empty$/) do
30
+ selector.assert_that(nil) do
31
+ satisfy{|i| i.nil? || (i.respond_to?(:empty?) && i.empty?) }
32
+ end
33
+ end
34
+
28
35
  Then(/^it is including `([^`]*)`$/) do |value|
29
36
  selector.assert_that(value) {|v| include v }
30
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brine-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Whipple
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-05 00:00:00.000000000 Z
11
+ date: 2018-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -220,6 +220,7 @@ files:
220
220
  - features/argument_transforms/template.feature
221
221
  - features/argument_transforms/whitespace.feature
222
222
  - features/assertions/is_a_valid.feature
223
+ - features/assertions/is_empty.feature
223
224
  - features/assertions/is_equal_to.feature
224
225
  - features/assertions/is_including.feature
225
226
  - features/assertions/is_matching.feature
@@ -290,6 +291,7 @@ test_files:
290
291
  - features/argument_transforms/template.feature
291
292
  - features/argument_transforms/whitespace.feature
292
293
  - features/assertions/is_a_valid.feature
294
+ - features/assertions/is_empty.feature
293
295
  - features/assertions/is_equal_to.feature
294
296
  - features/assertions/is_including.feature
295
297
  - features/assertions/is_matching.feature