api_maker 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/api_maker/api_helpers/api_maker_helpers.rb +5 -0
- data/app/api_maker/services/can_can/load_abilities.rb +30 -0
- data/app/api_maker/services/devise/sign_in.rb +64 -0
- data/app/api_maker/services/devise/sign_out.rb +9 -0
- data/app/api_maker/services/models/find_or_create_by.rb +18 -0
- data/app/channels/api_maker/subscriptions_channel.rb +33 -2
- data/app/controllers/api_maker/base_controller.rb +7 -3
- data/app/controllers/api_maker/commands_controller.rb +26 -4
- data/app/controllers/api_maker/session_statuses_controller.rb +1 -1
- data/app/services/api_maker/abilities_loader.rb +104 -0
- data/app/services/api_maker/application_service.rb +2 -1
- data/app/services/api_maker/base_command.rb +248 -0
- data/app/services/api_maker/collection_command_service.rb +29 -15
- data/app/services/api_maker/collection_loader.rb +124 -0
- data/app/services/api_maker/command_failed_error.rb +3 -0
- data/app/services/api_maker/command_response.rb +17 -6
- data/app/services/api_maker/command_service.rb +3 -3
- data/app/services/api_maker/create_command.rb +11 -26
- data/app/services/api_maker/create_command_service.rb +3 -3
- data/app/services/api_maker/database_type.rb +9 -0
- data/app/services/api_maker/deep_merge_params.rb +26 -0
- data/app/services/api_maker/deserializer.rb +35 -0
- data/app/services/api_maker/destroy_command.rb +15 -21
- data/app/services/api_maker/destroy_command_service.rb +3 -3
- data/app/services/api_maker/generate_react_native_api_service.rb +3 -19
- data/app/services/api_maker/include_helpers.rb +17 -0
- data/app/services/api_maker/index_command.rb +8 -88
- data/app/services/api_maker/index_command_service.rb +5 -5
- data/app/services/api_maker/js_method_namer_service.rb +1 -1
- data/app/services/api_maker/locals_from_controller.rb +14 -0
- data/app/services/api_maker/member_command_service.rb +15 -13
- data/app/services/api_maker/model_classes_java_script_generator_service.rb +37 -0
- data/app/services/api_maker/model_content_generator_service.rb +17 -21
- data/app/services/api_maker/models/save.rb +29 -0
- data/app/services/api_maker/models_finder_service.rb +6 -2
- data/app/services/api_maker/models_generator_service.rb +6 -43
- data/app/services/api_maker/move_components_to_routes.rb +50 -0
- data/app/services/api_maker/primary_id_for_model.rb +6 -0
- data/app/services/api_maker/reset_indexed_db_service.rb +36 -0
- data/app/services/api_maker/routes_file_reloader.rb +20 -0
- data/app/services/api_maker/select_columns_on_collection.rb +78 -0
- data/app/services/api_maker/select_parser.rb +32 -0
- data/app/services/api_maker/service_command.rb +27 -0
- data/app/services/api_maker/service_command_service.rb +14 -0
- data/app/services/api_maker/simple_model_errors.rb +52 -0
- data/app/services/api_maker/update_command.rb +8 -24
- data/app/services/api_maker/update_command_service.rb +3 -3
- data/app/services/api_maker/valid_command.rb +4 -13
- data/app/services/api_maker/valid_command_service.rb +3 -3
- data/app/services/api_maker/validation_errors_generator_service.rb +146 -0
- data/app/views/api_maker/_data.html.erb +17 -11
- data/config/routes.rb +0 -2
- data/lib/api_maker/ability.rb +22 -7
- data/lib/api_maker/ability_loader.rb +9 -6
- data/lib/api_maker/base_collection_instance.rb +15 -0
- data/lib/api_maker/base_resource.rb +135 -9
- data/lib/api_maker/base_service.rb +14 -0
- data/lib/api_maker/collection_serializer.rb +95 -34
- data/lib/api_maker/command_spec_helper.rb +41 -11
- data/lib/api_maker/configuration.rb +31 -4
- data/lib/api_maker/expect_to_able_to_helper.rb +31 -0
- data/lib/api_maker/individual_command.rb +24 -9
- data/lib/api_maker/javascript/model-template.js.erb +39 -25
- data/lib/api_maker/javascript/models.js.erb +6 -0
- data/lib/api_maker/loader.rb +1 -1
- data/lib/api_maker/memory_storage.rb +1 -1
- data/lib/api_maker/model_extensions.rb +34 -18
- data/lib/api_maker/permitted_params_argument.rb +5 -1
- data/lib/api_maker/preloader.rb +71 -32
- data/lib/api_maker/preloader_base.rb +108 -0
- data/lib/api_maker/preloader_belongs_to.rb +34 -33
- data/lib/api_maker/preloader_has_many.rb +45 -39
- data/lib/api_maker/preloader_has_one.rb +30 -47
- data/lib/api_maker/railtie.rb +3 -11
- data/lib/api_maker/relationship_preloader.rb +42 -0
- data/lib/api_maker/resource_routing.rb +18 -4
- data/lib/api_maker/result_parser.rb +34 -20
- data/lib/api_maker/serializer.rb +53 -22
- data/lib/api_maker/spec_helper/browser_logs.rb +14 -0
- data/lib/api_maker/spec_helper/execute_collection_command.rb +46 -0
- data/lib/api_maker/spec_helper/execute_member_command.rb +52 -0
- data/lib/api_maker/spec_helper/expect_no_browser_errors.rb +18 -0
- data/lib/api_maker/spec_helper/wait_for_expect.rb +20 -0
- data/lib/api_maker/spec_helper/wait_for_flash_message.rb +21 -0
- data/lib/api_maker/spec_helper.rb +112 -48
- data/lib/api_maker/version.rb +1 -1
- data/lib/api_maker.rb +7 -3
- metadata +108 -89
- data/README.md +0 -476
- data/app/controllers/api_maker/devise_controller.rb +0 -60
- data/lib/api_maker/base_command.rb +0 -81
- data/lib/api_maker/javascript/api.js +0 -92
- data/lib/api_maker/javascript/base-model.js +0 -543
- data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +0 -16
- data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +0 -47
- data/lib/api_maker/javascript/bootstrap/card.jsx +0 -79
- data/lib/api_maker/javascript/bootstrap/checkbox.jsx +0 -127
- data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +0 -105
- data/lib/api_maker/javascript/bootstrap/live-table.jsx +0 -168
- data/lib/api_maker/javascript/bootstrap/money-input.jsx +0 -136
- data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +0 -80
- data/lib/api_maker/javascript/bootstrap/select.jsx +0 -168
- data/lib/api_maker/javascript/bootstrap/string-input.jsx +0 -203
- data/lib/api_maker/javascript/cable-connection-pool.js +0 -169
- data/lib/api_maker/javascript/cable-subscription-pool.js +0 -111
- data/lib/api_maker/javascript/cable-subscription.js +0 -33
- data/lib/api_maker/javascript/collection.js +0 -186
- data/lib/api_maker/javascript/commands-pool.js +0 -123
- data/lib/api_maker/javascript/custom-error.js +0 -14
- data/lib/api_maker/javascript/deserializer.js +0 -35
- data/lib/api_maker/javascript/devise.js.erb +0 -113
- data/lib/api_maker/javascript/error-logger.js +0 -119
- data/lib/api_maker/javascript/event-connection.jsx +0 -24
- data/lib/api_maker/javascript/event-created.jsx +0 -26
- data/lib/api_maker/javascript/event-destroyed.jsx +0 -26
- data/lib/api_maker/javascript/event-emitter-listener.jsx +0 -32
- data/lib/api_maker/javascript/event-listener.jsx +0 -41
- data/lib/api_maker/javascript/event-updated.jsx +0 -26
- data/lib/api_maker/javascript/form-data-to-object.js +0 -70
- data/lib/api_maker/javascript/included.js +0 -39
- data/lib/api_maker/javascript/key-value-store.js +0 -47
- data/lib/api_maker/javascript/logger.js +0 -23
- data/lib/api_maker/javascript/model-name.js +0 -21
- data/lib/api_maker/javascript/models-response-reader.js +0 -43
- data/lib/api_maker/javascript/paginate.jsx +0 -128
- data/lib/api_maker/javascript/params.js +0 -68
- data/lib/api_maker/javascript/resource-route.jsx +0 -75
- data/lib/api_maker/javascript/resource-routes.jsx +0 -36
- data/lib/api_maker/javascript/result.js +0 -25
- data/lib/api_maker/javascript/session-status-updater.js +0 -113
- data/lib/api_maker/javascript/sort-link.jsx +0 -88
- data/lib/api_maker/javascript/updated-attribute.jsx +0 -60
- data/lib/api_maker/preloader_through.rb +0 -101
- data/lib/api_maker/relationship_includer.rb +0 -42
@@ -1,14 +1,14 @@
|
|
1
1
|
class ApiMaker::ResultParser
|
2
|
-
attr_reader :ability, :
|
2
|
+
attr_reader :ability, :api_maker_args
|
3
3
|
|
4
4
|
def self.parse(*args)
|
5
5
|
ApiMaker::ResultParser.new(*args).result
|
6
6
|
end
|
7
7
|
|
8
|
-
def initialize(object, ability: nil,
|
8
|
+
def initialize(object, ability: nil, api_maker_args: nil, controller: nil)
|
9
9
|
@object = object
|
10
10
|
@ability = ability || controller&.__send__(:current_ability)
|
11
|
-
@
|
11
|
+
@api_maker_args = api_maker_args || controller&.__send__(:api_maker_args) || {}
|
12
12
|
end
|
13
13
|
|
14
14
|
def result
|
@@ -17,32 +17,46 @@ class ApiMaker::ResultParser
|
|
17
17
|
|
18
18
|
private
|
19
19
|
|
20
|
+
def parse_active_record(object)
|
21
|
+
serializer = ApiMaker::Serializer.new(ability: ability, api_maker_args: api_maker_args, model: object)
|
22
|
+
|
23
|
+
{
|
24
|
+
api_maker_type: :model,
|
25
|
+
model_name: serializer.resource.collection_name,
|
26
|
+
serialized: parse_object(serializer.as_json)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_array(object)
|
31
|
+
object.map { |value| parse_object(value) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_hash(object)
|
35
|
+
result = {}
|
36
|
+
object.each do |key, value|
|
37
|
+
result[key] = parse_object(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
20
43
|
def parse_object(object)
|
21
44
|
if object.is_a?(Hash)
|
22
|
-
|
23
|
-
object.each do |key, value|
|
24
|
-
result[key] = parse_object(value)
|
25
|
-
end
|
26
|
-
|
27
|
-
result
|
45
|
+
parse_hash(object)
|
28
46
|
elsif object.is_a?(Array)
|
29
|
-
object
|
30
|
-
elsif object.class.name == "Money"
|
47
|
+
parse_array(object)
|
48
|
+
elsif object.class.name == "Money" # rubocop:disable Style/ClassEqualityComparison
|
31
49
|
{api_maker_type: :money, amount: object.cents, currency: object.currency.iso_code}
|
32
50
|
elsif object.is_a?(Date)
|
33
|
-
object.iso8601
|
51
|
+
{api_maker_type: :date, value: object.iso8601}
|
34
52
|
elsif object.is_a?(Time)
|
35
|
-
object.utc.iso8601
|
53
|
+
{api_maker_type: :time, value: object.utc.iso8601}
|
36
54
|
elsif object.is_a?(ApiMaker::CollectionSerializer) || object.is_a?(ApiMaker::Serializer)
|
37
55
|
parse_object(object.as_json)
|
56
|
+
elsif object.is_a?(Class) && object < ApiMaker::BaseResource
|
57
|
+
{api_maker_type: :resource, name: object.short_name}
|
38
58
|
elsif object.is_a?(ActiveRecord::Base)
|
39
|
-
|
40
|
-
|
41
|
-
{
|
42
|
-
api_maker_type: :model,
|
43
|
-
model_name: serializer.resource.collection_name,
|
44
|
-
serialized: parse_object(serializer.as_json)
|
45
|
-
}
|
59
|
+
parse_active_record(object)
|
46
60
|
else
|
47
61
|
object
|
48
62
|
end
|
data/lib/api_maker/serializer.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
class ApiMaker::Serializer
|
2
|
-
attr_reader :ability, :
|
2
|
+
attr_reader :ability, :api_maker_args, :locals, :model
|
3
|
+
|
4
|
+
delegate :id, to: :model
|
3
5
|
|
4
6
|
def self.resource_for(klass)
|
5
7
|
ApiMaker::MemoryStorage.current.resource_for_model(klass)
|
@@ -11,15 +13,16 @@ class ApiMaker::Serializer
|
|
11
13
|
ApiMaker::MemoryStorage.current.resource_for_model(klass)
|
12
14
|
end
|
13
15
|
|
14
|
-
def initialize(ability: nil,
|
15
|
-
@args = args
|
16
|
-
@model = model
|
16
|
+
def initialize(ability: nil, api_maker_args: {}, locals: nil, model:, select: nil)
|
17
17
|
@ability = ability
|
18
|
+
@api_maker_args = api_maker_args
|
19
|
+
@locals = locals || api_maker_args&.dig(:locals) || {}
|
20
|
+
@model = model
|
18
21
|
@select = select
|
19
22
|
end
|
20
23
|
|
21
24
|
def attributes
|
22
|
-
|
25
|
+
profile("attributes") do
|
23
26
|
result = {}
|
24
27
|
attributes_to_read.each do |attribute, data|
|
25
28
|
if (if_name = data.dig(:args, :if))
|
@@ -35,14 +38,18 @@ class ApiMaker::Serializer
|
|
35
38
|
end
|
36
39
|
|
37
40
|
def attributes_to_read
|
38
|
-
@attributes_to_read ||=
|
41
|
+
@attributes_to_read ||= profile("attributes_to_read") do
|
42
|
+
@select || resource.default_select
|
43
|
+
end
|
39
44
|
end
|
40
45
|
|
41
46
|
def attribute_value(attribute)
|
42
|
-
|
43
|
-
resource_instance.
|
44
|
-
|
45
|
-
|
47
|
+
profile("attribute_value #{attribute}") do
|
48
|
+
if resource_instance.respond_to?(attribute)
|
49
|
+
resource_instance.__send__(attribute)
|
50
|
+
else
|
51
|
+
model.__send__(attribute)
|
52
|
+
end
|
46
53
|
end
|
47
54
|
end
|
48
55
|
|
@@ -50,37 +57,61 @@ class ApiMaker::Serializer
|
|
50
57
|
result.fetch(*args, &blk)
|
51
58
|
end
|
52
59
|
|
60
|
+
def load_ability(ability_name, value)
|
61
|
+
@abilities ||= {}
|
62
|
+
@abilities[ability_name] = value
|
63
|
+
end
|
64
|
+
|
53
65
|
def relationships
|
54
66
|
@relationships ||= {}
|
55
67
|
end
|
56
68
|
|
57
69
|
def resource
|
58
|
-
@resource ||=
|
70
|
+
@resource ||= profile("resource") do
|
71
|
+
ApiMaker::MemoryStorage.current.resource_for_model(model.class)
|
72
|
+
end
|
59
73
|
end
|
60
74
|
|
61
75
|
def resource_instance
|
62
|
-
@resource_instance ||=
|
76
|
+
@resource_instance ||= profile("resource_instance") do
|
77
|
+
resource.new(ability: ability, api_maker_args: api_maker_args, locals: locals, model: model)
|
78
|
+
end
|
63
79
|
end
|
64
80
|
|
65
81
|
def result
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
82
|
+
result = {a: attributes}
|
83
|
+
result[:b] = @abilities if @abilities # Only use b-key if any abilities was loaded
|
84
|
+
result[:r] = @relationships if @relationships # Only preload relationships if set
|
85
|
+
result
|
71
86
|
end
|
72
87
|
|
73
|
-
def as_json(
|
74
|
-
|
88
|
+
def as_json(options = nil)
|
89
|
+
profile("as_json") do
|
90
|
+
if options && options[:result_parser]
|
91
|
+
ApiMaker::ResultParser.new(result, ability: ability, api_maker_args: api_maker_args).result
|
92
|
+
else
|
93
|
+
result
|
94
|
+
end
|
95
|
+
end
|
75
96
|
end
|
76
97
|
|
77
|
-
def to_json(
|
78
|
-
|
98
|
+
def to_json(options = nil)
|
99
|
+
profile("to_json") do
|
100
|
+
JSON.generate(as_json(options))
|
101
|
+
end
|
79
102
|
end
|
80
103
|
|
81
104
|
def inspect
|
82
|
-
"
|
105
|
+
profile("inspect") do
|
106
|
+
"<ApiMaker::Serializer id=\"#{model.id}\" model=\"#{model.class.name}\" relationships=\"#{relationships}\">"
|
107
|
+
end
|
83
108
|
end
|
84
109
|
|
85
110
|
alias to_s inspect
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def profile(message, &blk)
|
115
|
+
ApiMaker::Configuration.profile(-> { "Serializer for #{model.class.name}: #{message}" }, &blk)
|
116
|
+
end
|
86
117
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class ApiMaker::SpecHelper::ExecuteCollectionCommand < ApiMaker::ApplicationService
|
2
|
+
include RSpec::Mocks::ExampleMethods
|
3
|
+
|
4
|
+
attr_reader :api_maker_args, :args, :command, :model_class
|
5
|
+
|
6
|
+
def initialize(ability: nil, api_maker_args: {}, args: {}, command:, fake_controller: nil, model_class:)
|
7
|
+
@ability = ability
|
8
|
+
@api_maker_args = api_maker_args
|
9
|
+
@args = args
|
10
|
+
@command = command
|
11
|
+
@fake_controller = fake_controller
|
12
|
+
@model_class = model_class
|
13
|
+
end
|
14
|
+
|
15
|
+
def perform
|
16
|
+
helper_command
|
17
|
+
helper.execute!
|
18
|
+
succeed! helper_command.result
|
19
|
+
end
|
20
|
+
|
21
|
+
def ability
|
22
|
+
@ability ||= ApiMaker::Ability.new(api_maker_args: api_maker_args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def fake_controller
|
26
|
+
@fake_controller ||= instance_double(
|
27
|
+
ApiMaker::BaseController,
|
28
|
+
api_maker_args: api_maker_args,
|
29
|
+
current_ability: ability
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def helper
|
34
|
+
@helper ||= ApiMaker::CommandSpecHelper.new(
|
35
|
+
collection: model_class,
|
36
|
+
command: command,
|
37
|
+
controller: fake_controller
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def helper_command
|
42
|
+
@helper_command ||= helper.add_command(
|
43
|
+
args: args
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class ApiMaker::SpecHelper::ExecuteMemberCommand < ApiMaker::ApplicationService
|
2
|
+
include RSpec::Mocks::ExampleMethods
|
3
|
+
|
4
|
+
attr_reader :api_maker_args, :args, :command, :model
|
5
|
+
|
6
|
+
def initialize(ability: nil, api_maker_args: nil, collection: nil, command:, fake_controller: nil, model:, args: {})
|
7
|
+
@ability = ability
|
8
|
+
@api_maker_args = api_maker_args
|
9
|
+
@args = args
|
10
|
+
@collection = collection
|
11
|
+
@command = command
|
12
|
+
@fake_controller = fake_controller
|
13
|
+
@model = model
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform
|
17
|
+
helper_command
|
18
|
+
helper.execute!
|
19
|
+
succeed! helper_command.result
|
20
|
+
end
|
21
|
+
|
22
|
+
def ability
|
23
|
+
@ability ||= ApiMaker::Ability.new(api_maker_args: api_maker_args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def collection
|
27
|
+
@collection ||= model.class.where(id: model.id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fake_controller
|
31
|
+
@fake_controller ||= instance_double(
|
32
|
+
ApiMaker::BaseController,
|
33
|
+
api_maker_args: api_maker_args,
|
34
|
+
current_ability: ability
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def helper
|
39
|
+
@helper ||= ApiMaker::CommandSpecHelper.new(
|
40
|
+
collection: collection,
|
41
|
+
command: command,
|
42
|
+
controller: fake_controller
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def helper_command
|
47
|
+
@helper_command ||= helper.add_command(
|
48
|
+
primary_key: model.id,
|
49
|
+
args: args
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ApiMaker::SpecHelper::ExpectNoBrowserErrors
|
2
|
+
def expect_no_browser_errors
|
3
|
+
logs = browser_logs
|
4
|
+
.map(&:to_s)
|
5
|
+
.reject { |log| log.include?("Warning: Can't perform a React state update on an unmounted component.") }
|
6
|
+
.reject { |log| log.include?("DEBUG: ") }
|
7
|
+
.join("\n")
|
8
|
+
|
9
|
+
expect_no_browser_window_errors
|
10
|
+
return if logs.blank? || logs.exclude?("SEVERE ")
|
11
|
+
|
12
|
+
# Lets try one more time - just in case browser window error got registered meanwhile
|
13
|
+
sleep 0.4
|
14
|
+
expect_no_browser_window_errors
|
15
|
+
|
16
|
+
raise logs
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ApiMaker::SpecHelper::WaitForExpect
|
2
|
+
# Waits for an expect to not fail - this is great because it whines
|
3
|
+
def wait_for_expect(*args)
|
4
|
+
last_error = nil
|
5
|
+
|
6
|
+
begin
|
7
|
+
wait_for_browser(*args) do
|
8
|
+
yield
|
9
|
+
true
|
10
|
+
rescue RSpec::Expectations::ExpectationNotMetError => e
|
11
|
+
last_error = e
|
12
|
+
false
|
13
|
+
end
|
14
|
+
rescue WaitUtil::TimeoutError => e
|
15
|
+
raise last_error if last_error
|
16
|
+
|
17
|
+
raise e
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ApiMaker::SpecHelper::WaitForFlashMessage
|
2
|
+
def wait_for_flash_message(expected_message, delay_sec: 0.2, timeout_sec: 6)
|
3
|
+
received_messages = []
|
4
|
+
|
5
|
+
WaitUtil.wait_for_condition("wait for flash message", timeout_sec: timeout_sec, delay_sec: delay_sec) do
|
6
|
+
expect_no_browser_errors
|
7
|
+
current_message = flash_message_text
|
8
|
+
received_messages << current_message
|
9
|
+
|
10
|
+
if current_message.is_a?(Array)
|
11
|
+
current_message.include?(expected_message)
|
12
|
+
else
|
13
|
+
current_message == expected_message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
expect_no_browser_errors
|
18
|
+
rescue WaitUtil::TimeoutError
|
19
|
+
expect(received_messages.uniq.reject(&:blank?)).to eq include expected_message
|
20
|
+
end
|
21
|
+
end
|
@@ -1,11 +1,36 @@
|
|
1
|
-
|
1
|
+
require "waitutil"
|
2
|
+
|
3
|
+
module ApiMaker::SpecHelper # rubocop:disable Metrics/ModuleLength
|
4
|
+
autoload :ExecuteCollectionCommand, "#{__dir__}/spec_helper/execute_collection_command"
|
5
|
+
autoload :ExecuteMemberCommand, "#{__dir__}/spec_helper/execute_member_command"
|
6
|
+
|
7
|
+
require_relative "spec_helper/browser_logs"
|
8
|
+
require_relative "spec_helper/expect_no_browser_errors"
|
9
|
+
require_relative "spec_helper/wait_for_expect"
|
10
|
+
require_relative "spec_helper/wait_for_flash_message"
|
11
|
+
include BrowserLogs
|
12
|
+
include ExpectNoBrowserErrors
|
13
|
+
include WaitForExpect
|
14
|
+
include WaitForFlashMessage
|
15
|
+
|
16
|
+
class JavaScriptError < RuntimeError; end
|
17
|
+
class SelectorNotFoundError < RuntimeError; end
|
18
|
+
class SelectorFoundError < RuntimeError; end
|
19
|
+
|
20
|
+
def browser_firefox?
|
21
|
+
capabilities = page.driver.browser.try(:capabilities)
|
22
|
+
capabilities && capabilities[:browser_name] == "firefox"
|
23
|
+
end
|
24
|
+
|
2
25
|
def chrome_logs
|
3
26
|
page.driver.browser.manage.logs.get(:browser)
|
4
27
|
end
|
5
28
|
|
6
|
-
def
|
7
|
-
|
29
|
+
def confirm_accept
|
30
|
+
page.driver.browser.switch_to.alert.accept
|
31
|
+
end
|
8
32
|
|
33
|
+
def expect_no_browser_window_errors
|
9
34
|
errors = execute_script("if (window.errorLogger) { return window.errorLogger.getErrors() }")
|
10
35
|
return if !errors.is_a?(Array) || errors.empty?
|
11
36
|
|
@@ -15,81 +40,112 @@ module ApiMaker::SpecHelper
|
|
15
40
|
custom_trace += last_error.fetch("backtrace") if last_error["backtrace"].is_a?(Array)
|
16
41
|
custom_trace += caller
|
17
42
|
|
18
|
-
error =
|
43
|
+
error = JavaScriptError.new("#{last_error["errorClass"]}: #{last_error["message"]}")
|
19
44
|
error.set_backtrace(custom_trace)
|
20
45
|
|
21
46
|
raise error
|
22
47
|
end
|
23
48
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
49
|
+
def expect_no_errors
|
50
|
+
expect_no_flash_errors
|
51
|
+
expect_no_browser_errors
|
52
|
+
end
|
28
53
|
|
29
|
-
|
54
|
+
def expect_to_be_able_to(ability, model, permissions)
|
55
|
+
permissions.each do |permission|
|
56
|
+
# Test access through 'can?'
|
57
|
+
expect(ability).to be_able_to permission, model
|
30
58
|
|
31
|
-
|
32
|
-
|
59
|
+
# Test access through 'accessible_by'
|
60
|
+
if model.is_a?(ActiveRecord::Base) && model.persisted?
|
61
|
+
readable_models = model.class.where(id: model).accessible_by(ability, permission)
|
62
|
+
expect(readable_models).to eq [model]
|
63
|
+
end
|
64
|
+
end
|
33
65
|
end
|
34
66
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
67
|
+
def expect_not_to_be_able_to(ability, model, permissions)
|
68
|
+
permissions.each do |permission|
|
69
|
+
# Test access through 'can?'
|
70
|
+
expect(ability).not_to be_able_to permission, model
|
71
|
+
|
72
|
+
# Test access through 'accessible_by'
|
73
|
+
if model.is_a?(ActiveRecord::Base) && model.persisted?
|
74
|
+
readable_models = model.class.where(id: model).accessible_by(ability, permission)
|
75
|
+
expect(readable_models).to be_empty
|
76
|
+
end
|
77
|
+
end
|
38
78
|
end
|
39
79
|
|
40
80
|
def js_fill_in(element_id, with:)
|
41
81
|
page.execute_script("document.querySelector(#{element_id.to_json}).value = #{with.to_json}")
|
42
82
|
end
|
43
83
|
|
84
|
+
def model_row_selector(model)
|
85
|
+
".#{model.model_name.singular.dasherize}-row[data-model-id='#{model.id}']"
|
86
|
+
end
|
87
|
+
|
44
88
|
def pretty_html
|
45
89
|
require "htmlbeautifier"
|
46
90
|
HtmlBeautifier.beautify(page.html)
|
47
91
|
end
|
48
92
|
|
93
|
+
def recorded_browser_logs
|
94
|
+
@recorded_browser_logs || []
|
95
|
+
end
|
96
|
+
|
49
97
|
def reset_indexeddb
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
logs_text = chrome_logs.map(&:message).join("\n")
|
65
|
-
logs_text.include?("\"All databases was deleted\"")
|
66
|
-
end
|
98
|
+
ApiMaker::ResetIndexedDbService.execute!(context: self)
|
99
|
+
end
|
100
|
+
|
101
|
+
def wait_for_action_cable_to_connect
|
102
|
+
sleep 0.5
|
103
|
+
end
|
104
|
+
|
105
|
+
def wait_for_and_find(selector, *args)
|
106
|
+
element = find(selector, *args)
|
107
|
+
expect_no_browser_errors
|
108
|
+
element
|
109
|
+
rescue Capybara::ElementNotFound => e
|
110
|
+
expect_no_browser_errors
|
111
|
+
raise ApiMaker::SpecHelper::SelectorNotFoundError, e.message
|
67
112
|
end
|
68
113
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
114
|
+
def wait_for_attribute_row(attribute: nil, identifier: nil, label: nil, value: nil, **opts)
|
115
|
+
raise "No attribute or identifier given" if !attribute && !identifier
|
116
|
+
raise "No label or value was given" if !label && !value
|
117
|
+
|
118
|
+
tr_selector = ".component-api-maker-attribute-row"
|
119
|
+
tr_selector << "[data-attribute='#{attribute.camelize(:lower)}']" if attribute
|
120
|
+
tr_selector << "[data-identifier='#{identifier.camelize}']" if identifier
|
121
|
+
|
122
|
+
wait_for_selector "#{tr_selector} > .attribute-row-label", exact_text: label, **opts if label
|
123
|
+
wait_for_selector "#{tr_selector} > .attribute-row-value", exact_text: value, **opts if value
|
124
|
+
end
|
125
|
+
|
126
|
+
def wait_for_browser(delay_sec: 0.2, message: "wait for browser", timeout_sec: 6)
|
127
|
+
WaitUtil.wait_for_condition(message, timeout_sec: timeout_sec, delay_sec: delay_sec) do
|
128
|
+
expect_no_browser_errors
|
72
129
|
yield
|
73
130
|
end
|
74
131
|
end
|
75
132
|
|
76
|
-
def
|
77
|
-
|
133
|
+
def wait_for_path(expected_path, **args)
|
134
|
+
args[:ignore_query] = true unless args.key?(:ignore_query)
|
78
135
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
current_message == expected_message
|
85
|
-
end
|
86
|
-
rescue WaitUtil::TimeoutError
|
87
|
-
expect(received_messages.uniq.reject(&:blank?)).to eq include expected_message
|
88
|
-
end
|
136
|
+
expect(page).to have_current_path(expected_path, args)
|
137
|
+
expect_no_browser_errors
|
138
|
+
rescue RSpec::Expectations::ExpectationNotMetError => e
|
139
|
+
expect_no_browser_errors
|
140
|
+
raise e
|
89
141
|
end
|
90
142
|
|
91
|
-
def wait_for_selector(selector)
|
92
|
-
|
143
|
+
def wait_for_selector(selector, *args)
|
144
|
+
expect(page).to have_selector selector, *args
|
145
|
+
expect_no_browser_errors
|
146
|
+
rescue RSpec::Expectations::ExpectationNotMetError => e
|
147
|
+
expect_no_browser_errors
|
148
|
+
raise ApiMaker::SpecHelper::SelectorNotFoundError, e.message
|
93
149
|
end
|
94
150
|
|
95
151
|
def wait_for_selectors(*selectors)
|
@@ -97,4 +153,12 @@ module ApiMaker::SpecHelper
|
|
97
153
|
wait_for_selector(selector)
|
98
154
|
end
|
99
155
|
end
|
156
|
+
|
157
|
+
def wait_for_no_selector(selector, *args)
|
158
|
+
expect(page).to have_no_selector selector, *args
|
159
|
+
expect_no_browser_errors
|
160
|
+
rescue RSpec::Expectations::ExpectationNotMetError => e
|
161
|
+
expect_no_browser_errors
|
162
|
+
raise ApiMaker::SpecHelper::SelectorFoundError, e.message
|
163
|
+
end
|
100
164
|
end
|
data/lib/api_maker/version.rb
CHANGED
data/lib/api_maker.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require "api_maker/engine"
|
2
2
|
|
3
|
+
require "active_record_better_dependent_error_messages"
|
3
4
|
require "active_record_query_fixer"
|
5
|
+
require "cancancan"
|
4
6
|
require "ransack"
|
5
7
|
require "service_pattern"
|
6
8
|
|
@@ -11,22 +13,24 @@ module ApiMaker
|
|
11
13
|
|
12
14
|
autoload :Ability, "#{dir}/ability"
|
13
15
|
autoload :AbilityLoader, "#{dir}/ability_loader"
|
14
|
-
autoload :
|
16
|
+
autoload :BaseCollectionInstance, "#{dir}/base_collection_instance"
|
15
17
|
autoload :BaseResource, "#{dir}/base_resource"
|
18
|
+
autoload :BaseService, "#{dir}/base_service"
|
16
19
|
autoload :CollectionSerializer, "#{dir}/collection_serializer"
|
17
20
|
autoload :CommandSpecHelper, "#{dir}/command_spec_helper"
|
18
21
|
autoload :Configuration, "#{dir}/configuration"
|
22
|
+
autoload :ExpectToBeAbleToHelper, "#{dir}/expect_to_able_to_helper"
|
19
23
|
autoload :IndividualCommand, "#{dir}/individual_command"
|
20
24
|
autoload :Loader, "#{dir}/loader"
|
21
25
|
autoload :MemoryStorage, "#{dir}/memory_storage"
|
22
26
|
autoload :ModelExtensions, "#{dir}/model_extensions"
|
23
27
|
autoload :PermittedParamsArgument, "#{dir}/permitted_params_argument"
|
24
28
|
autoload :Preloader, "#{dir}/preloader"
|
29
|
+
autoload :PreloaderBase, "#{dir}/preloader_base"
|
25
30
|
autoload :PreloaderBelongsTo, "#{dir}/preloader_belongs_to"
|
26
31
|
autoload :PreloaderHasMany, "#{dir}/preloader_has_many"
|
27
32
|
autoload :PreloaderHasOne, "#{dir}/preloader_has_one"
|
28
|
-
autoload :
|
29
|
-
autoload :RelationshipIncluder, "#{dir}/relationship_includer"
|
33
|
+
autoload :RelationshipPreloader, "#{dir}/relationship_preloader"
|
30
34
|
autoload :ResourceRouting, "#{dir}/resource_routing"
|
31
35
|
autoload :ResultParser, "#{dir}/result_parser"
|
32
36
|
autoload :Serializer, "#{dir}/serializer"
|