requester 0.1.0
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 +7 -0
- data/README.md +400 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/requester.rb +10 -0
- data/lib/requester/config.rb +58 -0
- data/lib/requester/logger.rb +82 -0
- data/lib/requester/railtie.rb +8 -0
- data/lib/requester/request.rb +30 -0
- data/lib/requester/requests.rb +27 -0
- data/lib/requester/response.rb +27 -0
- data/lib/requester/version.rb +3 -0
- data/lib/tasks/requester.rake +20 -0
- metadata +112 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 5f3cc16c0a4d1f66db6398c2a4b19346a141c1ad
|
|
4
|
+
data.tar.gz: 5c36b763a9c82f1d59905c868301c652a84badd5
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b422f66f43c02bdf78f8b2bfb95f44cf043b094265541ce449432497c22888e17c3aaa1e186a7fda2f509396bd2bed86af046d53f4a72ea7ef30a702168f4062
|
|
7
|
+
data.tar.gz: 54d90e4eb0a7845ed5598b464bf4f51698cff53a9c14d5f50ede06bc93ee2b1c9985c332a9b7a50b2d8666cf134640d832ddeea3a1f225579e71b1bba0f3c671
|
data/README.md
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
# Requester
|
|
2
|
+
|
|
3
|
+
## What is Requester?
|
|
4
|
+
|
|
5
|
+
Requester coordinates json api requests and responses between the server test
|
|
6
|
+
suite and the client test suite in Rails-based web applications.
|
|
7
|
+
|
|
8
|
+
## How does it work?
|
|
9
|
+
|
|
10
|
+
Requester captures the api requests and responses generated by a Rails test
|
|
11
|
+
suite and writes them to a shared file. The client-side test suite (mocha,
|
|
12
|
+
ember-test, etc) uses that file as the source for mocking out those
|
|
13
|
+
same requests.
|
|
14
|
+
|
|
15
|
+
Requester can be used with Rails API and any front end framework.
|
|
16
|
+
|
|
17
|
+
## Why would you want this?
|
|
18
|
+
|
|
19
|
+
Many web applications with extensive front-end rendering test the front-end
|
|
20
|
+
independently from the relied upon server-side api. In these siutations, changes to the
|
|
21
|
+
server-side api may go unnoticed by the front-end test suite leading to
|
|
22
|
+
an a green test suite but a broken app. Additionally, when an api change is
|
|
23
|
+
communicated to the front-end team, effort is needed to ensure that the
|
|
24
|
+
test suite api is mocked correctly. Requester aims to save that effort
|
|
25
|
+
and provide more transparency to api changes.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Pretend we have a Rails app with a `DecksController` with
|
|
30
|
+
this set of tests:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
RSpec.describe DecksController, type: :request do
|
|
34
|
+
prepend Requester::Requests
|
|
35
|
+
|
|
36
|
+
before do
|
|
37
|
+
%w[diamonds hearts spades clubs].each do |suit|
|
|
38
|
+
Deck.create suit: suit, cards: "A 2 3 4 5 6 7 8 9 10 J Q K"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "GET /decks" do
|
|
43
|
+
it "works! (now write some real specs)" do
|
|
44
|
+
get decks_path
|
|
45
|
+
expect(response).to have_http_status(200)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'searches' do
|
|
49
|
+
get decks_path, { search: 'clubs' }, log_as: 'with search'
|
|
50
|
+
expect(response).to have_http_status(200)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe 'show' do
|
|
55
|
+
it "works! (now write some real specs)" do
|
|
56
|
+
get deck_path(1), headers
|
|
57
|
+
expect(response).to have_http_status(200)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "PUT /decks" do
|
|
62
|
+
it "works! (now write some real specs)" do
|
|
63
|
+
headers = { 'ACCEPT' => 'application/json' }
|
|
64
|
+
xhr :put, deck_path(1), { deck: {cards: '10 J Q K'} }, headers
|
|
65
|
+
expect(response).to have_http_status(200)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "POST /decks" do
|
|
70
|
+
it "works! (now write some real specs)" do
|
|
71
|
+
headers = { 'ACCEPT' => 'application/json' }
|
|
72
|
+
post decks_path, { deck: { cards: "1 2 3", suit: 'horseshoes'} }, headers
|
|
73
|
+
expect(response).to have_http_status(201)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Requester will generate JSON where the top level keys are controllers, followed by
|
|
80
|
+
actions, then the response/request generated by testing that endpoint:
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
//2017-07-11 13:34:11 UTC
|
|
84
|
+
|
|
85
|
+
export default {
|
|
86
|
+
"decks": {
|
|
87
|
+
"index": {
|
|
88
|
+
"response": {
|
|
89
|
+
"status": 200,
|
|
90
|
+
"body": {
|
|
91
|
+
"data": [
|
|
92
|
+
{
|
|
93
|
+
"id": "1",
|
|
94
|
+
"type": "decks",
|
|
95
|
+
"attributes": {
|
|
96
|
+
"cards": "A 2 3 4 5 6 7 8 9 10 J Q K",
|
|
97
|
+
"suit": "diamonds"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "2",
|
|
102
|
+
"type": "decks",
|
|
103
|
+
"attributes": {
|
|
104
|
+
"cards": "A 2 3 4 5 6 7 8 9 10 J Q K",
|
|
105
|
+
"suit": "hearts"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"id": "3",
|
|
110
|
+
"type": "decks",
|
|
111
|
+
"attributes": {
|
|
112
|
+
"cards": "A 2 3 4 5 6 7 8 9 10 J Q K",
|
|
113
|
+
"suit": "spades"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "4",
|
|
118
|
+
"type": "decks",
|
|
119
|
+
"attributes": {
|
|
120
|
+
"cards": "A 2 3 4 5 6 7 8 9 10 J Q K",
|
|
121
|
+
"suit": "clubs"
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
"message": "OK"
|
|
127
|
+
},
|
|
128
|
+
"request": {
|
|
129
|
+
"path": "/decks",
|
|
130
|
+
"method": "GET"
|
|
131
|
+
},
|
|
132
|
+
"with search": {
|
|
133
|
+
"response": {
|
|
134
|
+
"status": 200,
|
|
135
|
+
"body": {
|
|
136
|
+
"decks": {
|
|
137
|
+
"id": 4,
|
|
138
|
+
"suit": "clubs",
|
|
139
|
+
"cards": "A 2 3 4 5 6 7 8 9 10 J Q K"
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"message": "OK"
|
|
143
|
+
},
|
|
144
|
+
"request": {
|
|
145
|
+
"path": "/decks?search=clubs",
|
|
146
|
+
"method": "GET",
|
|
147
|
+
"query_string": "search=clubs"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"show": {
|
|
152
|
+
"response": {
|
|
153
|
+
"status": 200,
|
|
154
|
+
"body": {
|
|
155
|
+
"data": {
|
|
156
|
+
"id": "1",
|
|
157
|
+
"type": "decks",
|
|
158
|
+
"attributes": {
|
|
159
|
+
"cards": "A 2 3 4 5 6 7 8 9 10 J Q K",
|
|
160
|
+
"suit": "diamonds"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"message": "OK"
|
|
165
|
+
},
|
|
166
|
+
"request": {
|
|
167
|
+
"path": "/decks/1",
|
|
168
|
+
"method": "GET"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"update": {
|
|
172
|
+
"response": {
|
|
173
|
+
"status": 200,
|
|
174
|
+
"body": {
|
|
175
|
+
"data": {
|
|
176
|
+
"id": "1",
|
|
177
|
+
"type": "decks",
|
|
178
|
+
"attributes": {
|
|
179
|
+
"cards": "10 J Q K",
|
|
180
|
+
"suit": "diamonds"
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
"message": "OK"
|
|
185
|
+
},
|
|
186
|
+
"request": {
|
|
187
|
+
"path": "/decks/1",
|
|
188
|
+
"method": "PUT",
|
|
189
|
+
"request_parameters": {
|
|
190
|
+
"deck": {
|
|
191
|
+
"cards": "10 J Q K"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"media_type": "application/x-www-form-urlencoded"
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"create": {
|
|
198
|
+
"response": {
|
|
199
|
+
"status": 201,
|
|
200
|
+
"body": {
|
|
201
|
+
"data": {
|
|
202
|
+
"id": "5",
|
|
203
|
+
"type": "decks",
|
|
204
|
+
"attributes": {
|
|
205
|
+
"cards": "1 2 3",
|
|
206
|
+
"suit": "horseshoes"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
"message": "Created"
|
|
211
|
+
},
|
|
212
|
+
"request": {
|
|
213
|
+
"path": "/decks",
|
|
214
|
+
"method": "POST",
|
|
215
|
+
"request_parameters": {
|
|
216
|
+
"deck": {
|
|
217
|
+
"cards": "1 2 3",
|
|
218
|
+
"suit": "horseshoes"
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
"media_type": "application/x-www-form-urlencoded"
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Now in your front end app, using whatever fake API, you can use this data
|
|
229
|
+
to return responses you know work (assuming you ran requester with a green suite).
|
|
230
|
+
You also have access to the requests.
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
// meanwhile, in some fake server config in some JS framework...
|
|
234
|
+
import responses from 'dummy-ui/tests/responses';
|
|
235
|
+
|
|
236
|
+
myFakeApi.get('/decks', () => {
|
|
237
|
+
return data.decks.index.response.body;
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Usage
|
|
242
|
+
|
|
243
|
+
There is no magic involved in Requester. It simply prepends itself in your tests so it can log the request/response. Requester expects your tests to use a reasonable set of method calls to initiate a request (xhr, get, put, patch, post, delete, head).
|
|
244
|
+
Requester won't actually do anything when you run your test suite normally.
|
|
245
|
+
When you want to capture data, run `rake requester`.
|
|
246
|
+
|
|
247
|
+
## Setup
|
|
248
|
+
|
|
249
|
+
Install requester in your development and test groups
|
|
250
|
+
|
|
251
|
+
```ruby
|
|
252
|
+
gem 'requester'
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
The minimum required configuration is to tell Requester where you want the JSON
|
|
256
|
+
dump to be stored for your front end, and dump the Requester logs when the suite ends.
|
|
257
|
+
|
|
258
|
+
```ruby
|
|
259
|
+
# rails_helper.rb
|
|
260
|
+
|
|
261
|
+
Requester::Config.initialize do |config|
|
|
262
|
+
config.front_end_path = '/Users/you/code/my_ui/tests'
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
RSpec.configure do |config|
|
|
266
|
+
config.after :suite do
|
|
267
|
+
Requester::Logger.dump
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
#### Config options
|
|
273
|
+
|
|
274
|
+
* `file_name`: By default this is set to `'responses.js'`. If you want
|
|
275
|
+
to use something different, set it here.
|
|
276
|
+
* `additional_request_attributes`: By default the the following methods are called/logged on the request object:
|
|
277
|
+
- `path`, `method`, `request_parameters`, `query_string`, `media_type`.
|
|
278
|
+
You can add additional methods to be logged here.
|
|
279
|
+
* `additional_response_attributes`: By default the the following methods are called/logged on the request object:
|
|
280
|
+
- `status`, `body`, `message`
|
|
281
|
+
You can add additional methods to be logged here.
|
|
282
|
+
|
|
283
|
+
```ruby
|
|
284
|
+
# rails_helper.rb
|
|
285
|
+
|
|
286
|
+
Request::Config.initialize do |config|
|
|
287
|
+
config.file_name = 'rails_responses.js'
|
|
288
|
+
config.additional_request_attributes = [:ssl?]
|
|
289
|
+
config.additional_response_attributes = [:headers, :cookies]
|
|
290
|
+
end
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
See below for other config options.
|
|
294
|
+
|
|
295
|
+
You can set up your tests in a few ways:
|
|
296
|
+
|
|
297
|
+
#### 1. Capture request/response for every test in the file
|
|
298
|
+
|
|
299
|
+
Prepend `Requester::Requests` and every test in this group
|
|
300
|
+
will have a log entry.
|
|
301
|
+
|
|
302
|
+
```ruby
|
|
303
|
+
RSpec.describe DecksController, type: :request do
|
|
304
|
+
prepend Requester::Requests
|
|
305
|
+
|
|
306
|
+
describe "GET /decks" do
|
|
307
|
+
it "works! (now write some real specs)" do
|
|
308
|
+
get decks_path
|
|
309
|
+
expect(response).to have_http_status(200)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
it 'searches' do
|
|
313
|
+
get decks_path, { search: 'clubs' }, log_as: 'with search'
|
|
314
|
+
expect(response).to have_http_status(200)
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
describe 'show' do
|
|
319
|
+
it "works! (now write some real specs)" do
|
|
320
|
+
get deck_path(1), headers
|
|
321
|
+
expect(response).to have_http_status(200)
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
#### 2. Capture request/response for a describe/context block
|
|
327
|
+
|
|
328
|
+
Prepend `Requester::Requests` and only the tests in this group
|
|
329
|
+
will have a log entry.
|
|
330
|
+
|
|
331
|
+
```ruby
|
|
332
|
+
RSpec.describe DecksController, type: :request do
|
|
333
|
+
|
|
334
|
+
describe "GET /decks" do
|
|
335
|
+
prepend Requester::Requests
|
|
336
|
+
|
|
337
|
+
it "works! (now write some real specs)" do
|
|
338
|
+
get decks_path
|
|
339
|
+
expect(response).to have_http_status(200)
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
it 'searches' do
|
|
343
|
+
get decks_path, { search: 'clubs' }, log_as: 'with search'
|
|
344
|
+
expect(response).to have_http_status(200)
|
|
345
|
+
end
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
describe 'show' do
|
|
349
|
+
it "works! (now write some real specs)" do
|
|
350
|
+
get deck_path(1), headers
|
|
351
|
+
expect(response).to have_http_status(200)
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### 3. Capture request/response for individual tests
|
|
357
|
+
|
|
358
|
+
```ruby
|
|
359
|
+
describe "GET /decks" do
|
|
360
|
+
it "works! (now write some real specs)" do
|
|
361
|
+
get decks_path
|
|
362
|
+
|
|
363
|
+
Requester.log_data(
|
|
364
|
+
request: request,
|
|
365
|
+
response: response,
|
|
366
|
+
controller: controller
|
|
367
|
+
)
|
|
368
|
+
expect(response).to have_http_status(200)
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
it 'searches' do
|
|
372
|
+
get decks_path, { search: 'clubs' }, log_as: 'with search'
|
|
373
|
+
expect(response).to have_http_status(200)
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
You will likely have tests hitting the same endpoint testing different things.
|
|
379
|
+
For example, a test for an index action, and index with optional search params.
|
|
380
|
+
Specify a `log_as` option when you have multiple tests hitting the same endpoint.
|
|
381
|
+
Requester won't override an endpoint entry once it exists.
|
|
382
|
+
|
|
383
|
+
```ruby
|
|
384
|
+
describe "GET /decks" do
|
|
385
|
+
it "works! (now write some real specs)" do
|
|
386
|
+
get decks_path
|
|
387
|
+
expect(response).to have_http_status(200)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
it 'searches' do
|
|
391
|
+
get decks_path, { search: 'clubs' }, log_as: 'with search'
|
|
392
|
+
expect(response).to have_http_status(200)
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Contributing
|
|
398
|
+
|
|
399
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Jason Cummings/requester.
|
|
400
|
+
I am not looking to increase the scope of this gem, but I'll consider any ideas.
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "requester"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/requester.rb
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Requester
|
|
2
|
+
class Config
|
|
3
|
+
class RequesterConfigError < StandardError; end
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
attr_accessor :file_name
|
|
7
|
+
attr_reader :front_end_path, :additional_response_attributes, :additional_request_attributes
|
|
8
|
+
|
|
9
|
+
def initialize(&block)
|
|
10
|
+
@file_name = 'responses.js'
|
|
11
|
+
@additional_request_attributes = []
|
|
12
|
+
@additional_response_attributes = []
|
|
13
|
+
|
|
14
|
+
class_exec(self, &block)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def front_end_path=(path)
|
|
18
|
+
@front_end_path = path
|
|
19
|
+
|
|
20
|
+
unless valid_path_to_front_end_app?
|
|
21
|
+
raise RequesterConfigError, config_error
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def additional_request_attributes=(*args)
|
|
26
|
+
@additional_request_attributes = args.flatten
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def additional_response_attributes=(*args)
|
|
30
|
+
@additional_response_attributes = args.flatten
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def back_end_path
|
|
34
|
+
dir = defined?(RSpec) ? 'spec' : 'test'
|
|
35
|
+
File.join(Rails.root, dir)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def export_type
|
|
39
|
+
:es6
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def valid_path_to_front_end_app?
|
|
45
|
+
front_end_path && File.exist?(front_end_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def config_error
|
|
49
|
+
<<-UIERROR
|
|
50
|
+
\n *********************************************************
|
|
51
|
+
\n Requester needs to know the path to your front end app
|
|
52
|
+
\n *********************************************************
|
|
53
|
+
\n
|
|
54
|
+
UIERROR
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require_relative 'request'
|
|
2
|
+
require_relative 'response'
|
|
3
|
+
|
|
4
|
+
module Requester
|
|
5
|
+
class Logger
|
|
6
|
+
class << self
|
|
7
|
+
def log
|
|
8
|
+
@log ||= {}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def log_response(response, controller, **options)
|
|
12
|
+
write('response', controller, options) do
|
|
13
|
+
Requester::Response.generate(response)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def log_request(request, controller, **options)
|
|
18
|
+
write('request', controller, options) do
|
|
19
|
+
Requester::Request.generate(request)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def dump
|
|
24
|
+
return unless ENV['REQUESTER']
|
|
25
|
+
|
|
26
|
+
api_dump = File.new(back_end_file, 'w+')
|
|
27
|
+
ui_dump = File.new(front_end_file, 'w+')
|
|
28
|
+
json = JSON.pretty_generate(log)
|
|
29
|
+
|
|
30
|
+
# would like to support other types as well
|
|
31
|
+
case Requester::Config.export_type
|
|
32
|
+
when :es6
|
|
33
|
+
ui_dump.write(es6_export + json)
|
|
34
|
+
api_dump.write(es6_export + json)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
puts <<-DUMP
|
|
38
|
+
\n**************************
|
|
39
|
+
\n Interceptor logs dumped at:
|
|
40
|
+
\n #{File.expand_path(front_end_file)}
|
|
41
|
+
\n #{File.expand_path(back_end_file)}
|
|
42
|
+
\n**************************
|
|
43
|
+
DUMP
|
|
44
|
+
ensure
|
|
45
|
+
api_dump.close if api_dump
|
|
46
|
+
ui_dump.close if ui_dump
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def write(request_or_response, controller, **options, &block)
|
|
52
|
+
c_name = controller.controller_name
|
|
53
|
+
a_name = controller.action_name
|
|
54
|
+
log_as = options[:log_as]
|
|
55
|
+
|
|
56
|
+
log[c_name] ||= {}
|
|
57
|
+
log[c_name][a_name] ||= {}
|
|
58
|
+
|
|
59
|
+
json = block.call
|
|
60
|
+
|
|
61
|
+
if log_as
|
|
62
|
+
log[c_name][a_name][log_as] ||= {}
|
|
63
|
+
log[c_name][a_name][log_as][request_or_response] ||= json
|
|
64
|
+
else
|
|
65
|
+
log[c_name][a_name][request_or_response] ||= json
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def es6_export
|
|
70
|
+
"//#{Time.zone.now}\n\nexport default "
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def front_end_file
|
|
74
|
+
File.join(Requester::Config.front_end_path, Requester::Config.file_name)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def back_end_file
|
|
78
|
+
File.join(Requester::Config.back_end_path, Requester::Config.file_name)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require_relative 'config'
|
|
2
|
+
|
|
3
|
+
module Requester
|
|
4
|
+
class Request
|
|
5
|
+
def self.generate(request)
|
|
6
|
+
new(request).json
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(request)
|
|
10
|
+
@request = request
|
|
11
|
+
@config = Requester::Config
|
|
12
|
+
@json = {
|
|
13
|
+
path: request.fullpath,
|
|
14
|
+
method: request.method
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def json
|
|
19
|
+
@json.tap do |json|
|
|
20
|
+
json[:request_parameters] = @request.request_parameters if @request.request_parameters
|
|
21
|
+
json[:query_string] = @request.query_string if @request.query_string
|
|
22
|
+
json[:media_type] = @request.media_type if @request.media_type
|
|
23
|
+
|
|
24
|
+
Requester::Config.additional_request_attributes.each do |attr|
|
|
25
|
+
json[attr] = @request.public_send(attr)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require_relative 'config'
|
|
2
|
+
|
|
3
|
+
module Requester
|
|
4
|
+
module Requests
|
|
5
|
+
REQUEST_TYPES = [
|
|
6
|
+
:xhr, :get, :put, :patch, :post, :delete, :head
|
|
7
|
+
]
|
|
8
|
+
|
|
9
|
+
REQUEST_TYPES.each do |method|
|
|
10
|
+
define_method(method) do |*args, **options|
|
|
11
|
+
super(*args, **options)
|
|
12
|
+
log_data(options) if ENV['REQUESTER']
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def log_data(**options)
|
|
17
|
+
Logger.log_response(response, controller, options)
|
|
18
|
+
Logger.log_request(request, controller, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.log_data(request:, response:, controller:, **options)
|
|
22
|
+
return unless ENV['REQUESTER']
|
|
23
|
+
Logger.log_response(response, controller, options)
|
|
24
|
+
Logger.log_request(request, controller, options)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Requester
|
|
4
|
+
class Response
|
|
5
|
+
|
|
6
|
+
def self.generate(response)
|
|
7
|
+
new(response).json
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(response)
|
|
11
|
+
@response = response
|
|
12
|
+
@json = {
|
|
13
|
+
status: response.status,
|
|
14
|
+
body: JSON.parse(response.body),
|
|
15
|
+
message: response.message
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def json
|
|
20
|
+
@json.tap do |json|
|
|
21
|
+
Requester::Config.additional_response_attributes.each do |attr|
|
|
22
|
+
json[attr] = @response.public_send(attr)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
desc 'Runs your specs and generates a JSON file based on the selected specs'
|
|
2
|
+
|
|
3
|
+
task :requester do
|
|
4
|
+
ENV['REQUESTER'] = 'true'
|
|
5
|
+
|
|
6
|
+
command = defined?(RSpec) ? 'rspec' : 'rails test'
|
|
7
|
+
|
|
8
|
+
command += " #{ARGV[1..-1].join(' ')}"
|
|
9
|
+
|
|
10
|
+
puts(<<-COMMAND)
|
|
11
|
+
\n *********************************************************
|
|
12
|
+
\n Running requester using command: #{command.rstrip}
|
|
13
|
+
\n *********************************************************
|
|
14
|
+
\n
|
|
15
|
+
COMMAND
|
|
16
|
+
|
|
17
|
+
system(command)
|
|
18
|
+
|
|
19
|
+
ENV['REQUESTER'] = nil
|
|
20
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: requester
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jason Cummings
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-07-30 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.15'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.15'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: railties
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '4.0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '4.0'
|
|
69
|
+
description:
|
|
70
|
+
email: []
|
|
71
|
+
executables: []
|
|
72
|
+
extensions: []
|
|
73
|
+
extra_rdoc_files: []
|
|
74
|
+
files:
|
|
75
|
+
- README.md
|
|
76
|
+
- bin/console
|
|
77
|
+
- bin/setup
|
|
78
|
+
- lib/requester.rb
|
|
79
|
+
- lib/requester/config.rb
|
|
80
|
+
- lib/requester/logger.rb
|
|
81
|
+
- lib/requester/railtie.rb
|
|
82
|
+
- lib/requester/request.rb
|
|
83
|
+
- lib/requester/requests.rb
|
|
84
|
+
- lib/requester/response.rb
|
|
85
|
+
- lib/requester/version.rb
|
|
86
|
+
- lib/tasks/requester.rake
|
|
87
|
+
homepage: https://github.com/jsncmgs1/requester
|
|
88
|
+
licenses: []
|
|
89
|
+
metadata: {}
|
|
90
|
+
post_install_message:
|
|
91
|
+
rdoc_options: []
|
|
92
|
+
require_paths:
|
|
93
|
+
- lib
|
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
requirements: []
|
|
105
|
+
rubyforge_project:
|
|
106
|
+
rubygems_version: 2.4.8
|
|
107
|
+
signing_key:
|
|
108
|
+
specification_version: 4
|
|
109
|
+
summary: Requester coordinates json api requests and responses between the server
|
|
110
|
+
test suite and the client test suite in Rails-based web applications.
|
|
111
|
+
test_files: []
|
|
112
|
+
has_rdoc:
|