openstax_api 2.5.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -6
  3. data/app/controllers/openstax/api/v1/api_controller.rb +1 -1
  4. data/app/representers/openstax/api/v1/abstract_search_representer.rb +40 -0
  5. data/lib/openstax/api/constraints.rb +3 -4
  6. data/lib/openstax/api/engine.rb +3 -8
  7. data/lib/openstax/api/representable_schema_printer.rb +58 -35
  8. data/lib/openstax/api/roar.rb +50 -93
  9. data/lib/openstax/api/version.rb +1 -1
  10. data/spec/controllers/openstax/api/v1/api_controller_spec.rb +88 -2
  11. data/spec/dummy/README.md +1 -1
  12. data/spec/dummy/Rakefile +1 -2
  13. data/spec/dummy/app/assets/javascripts/application.js +3 -5
  14. data/spec/dummy/app/assets/stylesheets/application.css +5 -3
  15. data/spec/dummy/app/models/user.rb +2 -0
  16. data/spec/dummy/app/representers/user_representer.rb +13 -0
  17. data/spec/dummy/app/representers/user_search_representer.rb +5 -0
  18. data/spec/dummy/app/routines/search_users.rb +22 -0
  19. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  20. data/spec/dummy/bin/bundle +3 -0
  21. data/spec/dummy/bin/rails +4 -0
  22. data/spec/dummy/bin/rake +4 -0
  23. data/spec/dummy/config/application.rb +0 -30
  24. data/spec/dummy/config/boot.rb +4 -9
  25. data/spec/dummy/config/database.yml +8 -8
  26. data/spec/dummy/config/environment.rb +3 -3
  27. data/spec/dummy/config/environments/development.rb +21 -13
  28. data/spec/dummy/config/environments/production.rb +41 -32
  29. data/spec/dummy/config/environments/test.rb +17 -13
  30. data/spec/dummy/config/initializers/assets.rb +8 -0
  31. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  32. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  33. data/spec/dummy/config/initializers/inflections.rb +6 -5
  34. data/spec/dummy/config/initializers/mime_types.rb +0 -1
  35. data/spec/dummy/config/initializers/openstax_api.rb +2 -2
  36. data/spec/dummy/config/initializers/session_store.rb +1 -6
  37. data/spec/dummy/config/initializers/wrap_parameters.rb +6 -6
  38. data/spec/dummy/config/locales/en.yml +20 -2
  39. data/spec/dummy/config/secrets.yml +22 -0
  40. data/spec/dummy/config.ru +1 -1
  41. data/spec/dummy/db/development.sqlite3 +0 -0
  42. data/spec/dummy/db/migrate/1_create_users.rb +16 -0
  43. data/spec/dummy/db/schema.rb +38 -32
  44. data/spec/dummy/db/test.sqlite3 +0 -0
  45. data/spec/dummy/lib/controller_includes.rb +2 -6
  46. data/spec/dummy/log/development.log +486 -1445
  47. data/spec/dummy/log/test.log +16720 -3757
  48. data/spec/dummy/public/404.html +54 -13
  49. data/spec/dummy/public/422.html +54 -13
  50. data/spec/dummy/public/500.html +53 -12
  51. data/spec/factories/user.rb +8 -0
  52. data/spec/lib/openstax/api/apipie_spec.rb +15 -0
  53. data/spec/lib/openstax/api/constraints_spec.rb +6 -6
  54. data/spec/lib/openstax/api/doorkeeper_application_includes_spec.rb +1 -1
  55. data/spec/lib/openstax/api/representable_schema_printer_spec.rb +5 -3
  56. data/spec/lib/openstax/api/roar_spec.rb +22 -0
  57. data/spec/lib/openstax/api/routing_mapper_includes_spec.rb +1 -1
  58. data/spec/lib/openstax_api_spec.rb +19 -0
  59. data/spec/models/openstax/api/api_user_spec.rb +2 -2
  60. data/spec/rails_helper.rb +54 -0
  61. data/spec/representers/openstax/api/v1/abstract_search_representer_spec.rb +127 -0
  62. data/spec/spec_helper.rb +80 -13
  63. metadata +85 -18
  64. data/spec/dummy/app/models/dummy_user.rb +0 -2
  65. data/spec/dummy/app/representers/dummy_user_representer.rb +0 -9
  66. data/spec/dummy/config/initializers/secret_token.rb +0 -7
  67. data/spec/dummy/db/migrate/1_create_dummy_users.rb +0 -10
  68. data/spec/dummy/script/rails +0 -6
  69. data/spec/lib/openstax/api/apipie.rb +0 -11
  70. data/spec/lib/openstax/api/roar.rb +0 -11
@@ -2,25 +2,66 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>The page you were looking for doesn't exist (404)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
16
54
  </style>
17
55
  </head>
18
56
 
19
57
  <body>
20
58
  <!-- This file lives in public/404.html -->
21
59
  <div class="dialog">
22
- <h1>The page you were looking for doesn't exist.</h1>
23
- <p>You may have mistyped the address or the page may have moved.</p>
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
24
65
  </div>
25
66
  </body>
26
67
  </html>
@@ -2,25 +2,66 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>The change you wanted was rejected (422)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
16
54
  </style>
17
55
  </head>
18
56
 
19
57
  <body>
20
58
  <!-- This file lives in public/422.html -->
21
59
  <div class="dialog">
22
- <h1>The change you wanted was rejected.</h1>
23
- <p>Maybe you tried to change something you didn't have access to.</p>
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
24
65
  </div>
25
66
  </body>
26
67
  </html>
@@ -2,24 +2,65 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>We're sorry, but something went wrong (500)</title>
5
- <style type="text/css">
6
- body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
- div.dialog {
8
- width: 25em;
9
- padding: 0 4em;
10
- margin: 4em auto 0 auto;
11
- border: 1px solid #ccc;
12
- border-right-color: #999;
13
- border-bottom-color: #999;
14
- }
15
- h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
16
54
  </style>
17
55
  </head>
18
56
 
19
57
  <body>
20
58
  <!-- This file lives in public/500.html -->
21
59
  <div class="dialog">
22
- <h1>We're sorry, but something went wrong.</h1>
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
23
64
  </div>
24
65
  </body>
25
66
  </html>
@@ -0,0 +1,8 @@
1
+ FactoryGirl.define do
2
+ factory :user do
3
+ username { SecureRandom.hex.to_s }
4
+ password_hash { SecureRandom.hex.to_s }
5
+ name { Faker::Name.name }
6
+ email { Faker::Internet.email }
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+ describe Apipie do
7
+ it 'adds methods to ApiController class' do
8
+ expect(OpenStax::Api::V1::ApiController).to respond_to(:api_example)
9
+ expect(OpenStax::Api::V1::ApiController).to respond_to(:json_schema)
10
+ expect(OpenStax::Api::V1::ApiController).to respond_to(:representer)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
3
  module OpenStax
4
4
  module Api
@@ -9,14 +9,14 @@ module OpenStax
9
9
 
10
10
  it 'matches if version is correct in the accept headers' do
11
11
  allow(req).to receive(:headers).and_return({
12
- 'Accept' => 'application/vnd.dummy.openstax.v1'
12
+ 'Accept' => 'application/vnd.openstax.dummy.v1'
13
13
  })
14
14
  expect(constraints.matches? req).to eq true
15
15
  end
16
16
 
17
17
  it 'does not match if version is incorrect in the accept headers' do
18
18
  allow(req).to receive(:headers).and_return({
19
- 'Accept' => 'application/vnd.dummy.openstax.v2'
19
+ 'Accept' => 'application/vnd.openstax.dummy.v2'
20
20
  })
21
21
  expect(constraints.matches? req).to eq false
22
22
  end
@@ -43,13 +43,13 @@ module OpenStax
43
43
 
44
44
  it 'matches if version is correct in the accept headers or if default' do
45
45
  allow(req).to receive(:headers).and_return({
46
- 'Accept' => 'application/vnd.dummy.openstax.v1'
46
+ 'Accept' => 'application/vnd.openstax.dummy.v1'
47
47
  })
48
48
  expect(constraints.matches? req).to eq true
49
49
  expect(constraints_2.matches? req).to eq true
50
50
 
51
51
  allow(req).to receive(:headers).and_return({
52
- 'Accept' => 'application/vnd.dummy.openstax.v2'
52
+ 'Accept' => 'application/vnd.openstax.dummy.v2'
53
53
  })
54
54
  expect(constraints.matches? req).to eq false
55
55
  expect(constraints_2.matches? req).to eq true
@@ -57,7 +57,7 @@ module OpenStax
57
57
 
58
58
  it 'matches if version is invalid' do
59
59
  allow(req).to receive(:headers).and_return({
60
- 'Accept' => 'application/vnd.dummy.openstax.v3'
60
+ 'Accept' => 'application/vnd.openstax.dummy.v3'
61
61
  })
62
62
  expect(constraints.matches? req).to eq false
63
63
  expect(constraints_2.matches? req).to eq true
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
3
  module OpenStax
4
4
  module Api
@@ -1,10 +1,10 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
3
  module OpenStax
4
4
  module Api
5
5
  describe RepresentableSchemaPrinter do
6
6
  it 'must print model schemas' do
7
- schema = RepresentableSchemaPrinter.json(DummyUserRepresenter)
7
+ schema = RepresentableSchemaPrinter.json(UserRepresenter)
8
8
  expect(schema).to include('## Schema')
9
9
  expect(schema).to include('{#')
10
10
  expect(schema).to include(' .schema}')
@@ -15,7 +15,9 @@ module OpenStax
15
15
  "type" => "object",
16
16
  "required" => [ "username" ],
17
17
  "properties" => {
18
- "username" => { "type" => "string" }
18
+ "username" => { "type" => "string" },
19
+ "name" => { "type" => "string" },
20
+ "email" => { "type" => "string" }
19
21
  },
20
22
  "additionalProperties" => false
21
23
  })
@@ -0,0 +1,22 @@
1
+ require 'rails_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+ describe Roar do
7
+ let!(:controller) { OpenStax::Api::V1::ApiController.new }
8
+
9
+ it 'adds methods to ApiController instance' do
10
+ expect(controller).to respond_to(:standard_create)
11
+ expect(controller).to respond_to(:standard_read)
12
+ expect(controller).to respond_to(:standard_update)
13
+ expect(controller).to respond_to(:standard_destroy)
14
+ expect(controller).to respond_to(:standard_nested_create)
15
+ expect(controller).to respond_to(:standard_index)
16
+ expect(controller).to respond_to(:standard_search)
17
+ expect(controller).to respond_to(:standard_sort)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
3
  module OpenStax
4
4
  module Api
@@ -0,0 +1,19 @@
1
+ require 'rails_helper'
2
+
3
+ describe OpenStax::Api do
4
+ it 'is configurable' do
5
+ expect(OpenStax::Api.configuration).to respond_to(:user_class_name)
6
+ expect(OpenStax::Api.configuration).to respond_to(:current_user_method)
7
+ expect(OpenStax::Api.configuration).to respond_to(:routing_error_app)
8
+
9
+ expect(OpenStax::Api.configuration.user_class_name).to eq 'User'
10
+
11
+ OpenStax::Api.configure { |config| config.user_class_name = 'Test' }
12
+
13
+ expect(OpenStax::Api.configuration.user_class_name).to eq 'Test'
14
+
15
+ OpenStax::Api.configure { |config| config.user_class_name = 'User' }
16
+
17
+ expect(OpenStax::Api.configuration.user_class_name).to eq 'User'
18
+ end
19
+ end
@@ -1,9 +1,9 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
3
  module OpenStax
4
4
  module Api
5
5
  describe ApiUser do
6
- let(:user) { DummyUser.create }
6
+ let(:user) { FactoryGirl.create :user }
7
7
  let(:application) { double('Doorkeeper::Application') }
8
8
  let(:doorkeeper_token) { double('Doorkeeper::AccessToken') }
9
9
  let(:non_doorkeeper_user_proc) { lambda { user } }
@@ -0,0 +1,54 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ require 'spec_helper'
4
+ require File.expand_path("../dummy/config/environment", __FILE__)
5
+ require 'rspec/rails'
6
+ require 'factory_girl_rails'
7
+ require 'faker'
8
+ require 'squeel'
9
+
10
+ # Add additional requires below this line. Rails is not loaded until this point!
11
+
12
+ # Requires supporting ruby files with custom matchers and macros, etc, in
13
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
14
+ # run as spec files by default. This means that files in spec/support that end
15
+ # in _spec.rb will both be required and run as specs, causing the specs to be
16
+ # run twice. It is recommended that you do not name files matching this glob to
17
+ # end with _spec.rb. You can configure this pattern with the --pattern
18
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
19
+ #
20
+ # The following line is provided for convenience purposes. It has the downside
21
+ # of increasing the boot-up time by auto-requiring all files in the support
22
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
23
+ # require only the support files necessary.
24
+ #
25
+ # Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
26
+
27
+ # Checks for pending migrations before tests are run.
28
+ # If you are not using ActiveRecord, you can remove this line.
29
+ ActiveRecord::Migration.maintain_test_schema!
30
+
31
+ RSpec.configure do |config|
32
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
33
+ # config.fixture_path = "#{::Rails.root}/spec/fixtures"
34
+
35
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
36
+ # examples within a transaction, remove the following line or assign false
37
+ # instead of true.
38
+ # config.use_transactional_fixtures = true
39
+
40
+ # RSpec Rails can automatically mix in different behaviours to your tests
41
+ # based on their file location, for example enabling you to call `get` and
42
+ # `post` in specs under `spec/controllers`.
43
+ #
44
+ # You can disable this behaviour by removing the line below, and instead
45
+ # explicitly tag your specs with their type, e.g.:
46
+ #
47
+ # RSpec.describe UsersController, :type => :controller do
48
+ # # ...
49
+ # end
50
+ #
51
+ # The different available types are documented in the features, such as in
52
+ # https://relishapp.com/rspec/rspec-rails/docs
53
+ config.infer_spec_type_from_file_location!
54
+ end
@@ -0,0 +1,127 @@
1
+ require 'rails_helper'
2
+
3
+ module OpenStax
4
+ module Api
5
+ module V1
6
+ describe AbstractSearchRepresenter do
7
+
8
+ before(:all) do
9
+ 100.times do
10
+ FactoryGirl.create(:user)
11
+ end
12
+
13
+ User.where{name.like "% doe%"}.delete_all
14
+
15
+ john_doe = FactoryGirl.create :user, name: "John Doe",
16
+ username: "doejohn",
17
+ email: "john@doe.com"
18
+ jane_doe = FactoryGirl.create :user, name: "Jane Doe",
19
+ username: "doejane",
20
+ email: "jane@doe.com"
21
+ jack_doe = FactoryGirl.create :user, name: "Jack Doe",
22
+ username: "doejack",
23
+ email: "jack@doe.com"
24
+
25
+ @john_hash = JSON.parse(UserRepresenter.new(john_doe).to_json)
26
+ @jane_hash = JSON.parse(UserRepresenter.new(jane_doe).to_json)
27
+ @jack_hash = JSON.parse(UserRepresenter.new(jack_doe).to_json)
28
+ end
29
+
30
+ it "represents search results" do
31
+ outputs = SearchUsers.call('last_name:dOe').outputs
32
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
33
+ total_count = response['total_count']
34
+ items = response['items']
35
+
36
+ expect(total_count).to eq 3
37
+ expect(items).to include(@john_hash)
38
+ expect(items).to include(@jane_hash)
39
+ expect(items).to include(@jack_hash)
40
+
41
+ outputs = SearchUsers.call('first_name:jOhN last_name:DoE').outputs
42
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
43
+ total_count = response['total_count']
44
+ items = response['items']
45
+
46
+ expect(total_count).to eq 1
47
+ expect(items).to include(@john_hash)
48
+ expect(items).not_to include(@jane_hash)
49
+ expect(items).not_to include(@jack_hash)
50
+
51
+ outputs = SearchUsers.call('first_name:JoHn,JaNe last_name:dOe').outputs
52
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
53
+ total_count = response['total_count']
54
+ items = response['items']
55
+
56
+ expect(total_count).to eq 2
57
+ expect(items).to include(@john_hash)
58
+ expect(items).to include(@jane_hash)
59
+ expect(items).not_to include(@jack_hash)
60
+ end
61
+
62
+ it "represents ordered results" do
63
+ outputs = SearchUsers.call('username:DoE', order_by: 'cReAtEd_At AsC, iD')
64
+ .outputs
65
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
66
+ total_count = response['total_count']
67
+ items = response['items']
68
+
69
+ expect(total_count).to eq 3
70
+ expect(items[0]).to eq @john_hash
71
+ expect(items[1]).to eq @jane_hash
72
+ expect(items[2]).to eq @jack_hash
73
+
74
+ outputs = SearchUsers.call('username:dOe', order_by: 'CrEaTeD_aT dEsC, Id DeSc')
75
+ .outputs
76
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
77
+ total_count = response['total_count']
78
+ items = response['items']
79
+
80
+ expect(total_count).to eq 3
81
+ expect(items[0]).to eq @jack_hash
82
+ expect(items[1]).to eq @jane_hash
83
+ expect(items[2]).to eq @john_hash
84
+ end
85
+
86
+ it "represents paginated results" do
87
+ user_count = User.count
88
+
89
+ outputs = SearchUsers.call('').outputs
90
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
91
+ total_count = response['total_count']
92
+ items = response['items']
93
+
94
+ expect(total_count).to eq user_count
95
+ expect(items.count).to eq user_count
96
+
97
+ outputs = SearchUsers.call('', per_page: 20).outputs
98
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
99
+ total_count = response['total_count']
100
+ items = response['items']
101
+
102
+ expect(total_count).to eq user_count
103
+ expect(items.count).to eq 20
104
+
105
+ for page in 1..5
106
+ outputs = SearchUsers.call('', page: page, per_page: 20).outputs
107
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
108
+ total_count = response['total_count']
109
+ items = response['items']
110
+
111
+ expect(total_count).to eq user_count
112
+ expect(items.count).to eq 20
113
+ end
114
+
115
+ outputs = SearchUsers.call('', page: 1000, per_page: 20).outputs
116
+ response = JSON.parse(UserSearchRepresenter.new(outputs).to_json)
117
+ total_count = response['total_count']
118
+ items = response['items']
119
+
120
+ expect(total_count).to eq user_count
121
+ expect(items.count).to eq 0
122
+ end
123
+
124
+ end
125
+ end
126
+ end
127
+ end