api-tester 1.0.0 → 1.1.1

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.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +15 -0
  3. data/.github/workflows/push.yml +39 -0
  4. data/.github/workflows/test.yml +31 -0
  5. data/.rubocop.yml +61 -0
  6. data/Gemfile +2 -0
  7. data/Guardfile +70 -0
  8. data/README.md +65 -61
  9. data/Rakefile +8 -3
  10. data/api-tester.gemspec +29 -24
  11. data/changelog.txt +10 -0
  12. data/lib/api-tester.rb +6 -3
  13. data/lib/api-tester/config.rb +16 -13
  14. data/lib/api-tester/definition/boundary_case.rb +4 -1
  15. data/lib/api-tester/definition/contract.rb +8 -3
  16. data/lib/api-tester/definition/endpoint.rb +32 -23
  17. data/lib/api-tester/definition/fields/array_field.rb +20 -19
  18. data/lib/api-tester/definition/fields/boolean_field.rb +12 -9
  19. data/lib/api-tester/definition/fields/email_field.rb +14 -11
  20. data/lib/api-tester/definition/fields/enum_field.rb +14 -11
  21. data/lib/api-tester/definition/fields/field.rb +46 -45
  22. data/lib/api-tester/definition/fields/number_field.rb +11 -8
  23. data/lib/api-tester/definition/fields/object_field.rb +34 -31
  24. data/lib/api-tester/definition/fields/plain_array_field.rb +25 -0
  25. data/lib/api-tester/definition/method.rb +7 -2
  26. data/lib/api-tester/definition/request.rb +43 -16
  27. data/lib/api-tester/definition/response.rb +29 -26
  28. data/lib/api-tester/method_case_test.rb +67 -53
  29. data/lib/api-tester/modules/extra_verbs.rb +29 -9
  30. data/lib/api-tester/modules/format.rb +23 -7
  31. data/lib/api-tester/modules/good_case.rb +25 -10
  32. data/lib/api-tester/modules/injection_module.rb +32 -17
  33. data/lib/api-tester/modules/required_fields.rb +51 -0
  34. data/lib/api-tester/modules/server_information.rb +13 -10
  35. data/lib/api-tester/modules/typo.rb +36 -13
  36. data/lib/api-tester/modules/unexpected_fields.rb +61 -0
  37. data/lib/api-tester/modules/unused_fields.rb +12 -6
  38. data/lib/api-tester/reporter/api_report.rb +24 -16
  39. data/lib/api-tester/reporter/missing_field_report.rb +12 -13
  40. data/lib/api-tester/reporter/report.rb +11 -8
  41. data/lib/api-tester/reporter/status_code_report.rb +9 -2
  42. data/lib/api-tester/test_helper.rb +6 -6
  43. data/lib/api-tester/util/response_evaluator.rb +70 -57
  44. data/lib/api-tester/util/supported_verbs.rb +8 -5
  45. data/lib/api-tester/version.rb +3 -1
  46. metadata +99 -25
  47. data/.travis.yml +0 -6
  48. data/lib/api-tester/reporter/missing_response_field_report.rb +0 -21
@@ -1,14 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'api-tester/definition/fields/field'
2
4
 
3
5
  module ApiTester
6
+ # Class for defining enumerators
4
7
  class EnumField < Field
5
8
  attr_accessor :acceptable_values
6
9
 
7
- def initialize name:, acceptable_values:, default_value: nil
10
+ def initialize(name:, acceptable_values:, default_value: nil, required: false)
8
11
  if default_value
9
- super name: name, default_value: default_value
12
+ super name: name, default_value: default_value, required: required
10
13
  else
11
- super name: name, default_value: acceptable_values[0]
14
+ super name: name, default_value: acceptable_values[0], required: required
12
15
  end
13
16
 
14
17
  self.acceptable_values = acceptable_values
@@ -16,14 +19,14 @@ module ApiTester
16
19
 
17
20
  def negative_boundary_values
18
21
  super +
19
- [
20
- 123,
21
- 0,
22
- 1,
23
- true,
24
- false,
25
- {}
26
- ]
22
+ [
23
+ 123,
24
+ 0,
25
+ 1,
26
+ true,
27
+ false,
28
+ {}
29
+ ]
27
30
  end
28
31
  end
29
32
  end
@@ -1,49 +1,50 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
4
+ # Base class for field definitions
2
5
  class Field
3
- attr_accessor :name
4
- attr_accessor :default_value
5
- attr_accessor :required
6
- attr_accessor :is_seen
7
-
8
- def initialize name:, required:false, default_value:"string"
9
- self.name = name
10
- self.default_value = default_value
11
- self.required = required
12
- self.is_seen = 0
13
- end
14
-
15
- def is_required
16
- self.required = true
17
- self
18
- end
19
-
20
- def is_not_required
21
- self.required = false
22
- self
23
- end
24
-
25
- def has_subfields?
26
- false
27
- end
28
-
29
- def fields
30
- []
31
- end
32
-
33
- def negative_boundary_values
34
- cases = []
35
- if self.required
36
- cases << nil
37
- end
38
- cases
39
- end
40
-
41
- def seen
42
- self.is_seen += 1
43
- end
44
-
45
- def display_class
46
- self.class
47
- end
6
+ attr_accessor :name
7
+ attr_accessor :default_value
8
+ attr_accessor :required
9
+ attr_accessor :is_seen
10
+
11
+ def initialize(name:, required: false, default_value: 'string')
12
+ self.name = name
13
+ self.default_value = default_value
14
+ self.required = required
15
+ self.is_seen = 0
16
+ end
17
+
18
+ def is_required
19
+ self.required = true
20
+ self
21
+ end
22
+
23
+ def is_not_required
24
+ self.required = false
25
+ self
26
+ end
27
+
28
+ def subfields?
29
+ false
30
+ end
31
+
32
+ def fields
33
+ []
34
+ end
35
+
36
+ def negative_boundary_values
37
+ cases = []
38
+ cases << nil if required
39
+ cases
40
+ end
41
+
42
+ def seen
43
+ self.is_seen += 1
44
+ end
45
+
46
+ def display_class
47
+ self.class
48
+ end
48
49
  end
49
50
  end
@@ -1,19 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'api-tester/definition/fields/field'
2
4
 
3
5
  module ApiTester
6
+ # Class for defining numeric fields in contracts
4
7
  class NumberField < Field
5
- def initialize name:, default_value: 5
6
- super name: name, default_value: default_value
8
+ def initialize(name:, default_value: 5, required: false)
9
+ super name: name, default_value: default_value, required: required
7
10
  end
8
11
 
9
12
  def negative_boundary_values
10
13
  super +
11
- [
12
- "string",
13
- true,
14
- false,
15
- {}
16
- ]
14
+ [
15
+ 'string',
16
+ true,
17
+ false,
18
+ {}
19
+ ]
17
20
  end
18
21
  end
19
22
  end
@@ -1,44 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'api-tester/definition/fields/field'
2
4
 
3
5
  module ApiTester
6
+ # Class for defining objects in a contract
4
7
  class ObjectField < Field
5
- attr_accessor :fields
6
-
7
- def initialize name:
8
- super name: name
9
- self.fields = []
10
- end
8
+ attr_accessor :fields
11
9
 
12
- def with_field newField
13
- self.fields << newField
14
- self
15
- end
10
+ def initialize(name:, required: false)
11
+ super name: name, required: required
12
+ self.fields = []
13
+ end
16
14
 
17
- def has_subfields?
18
- true
19
- end
15
+ def with_field(new_field)
16
+ fields << new_field
17
+ self
18
+ end
20
19
 
21
- def default_value
22
- obj = Hash.new
20
+ def subfields?
21
+ true
22
+ end
23
23
 
24
- self.fields.each do |field|
25
- obj[field.name] = field.default_value
26
- end
24
+ def default_value
25
+ obj = {}
27
26
 
28
- obj
27
+ fields.each do |field|
28
+ obj[field.name] = field.default_value
29
29
  end
30
30
 
31
- def negative_boundary_values
32
- super +
33
- [
34
- "string",
35
- [],
36
- 123,
37
- 1,
38
- 0,
39
- true,
40
- false
41
- ]
42
- end
31
+ obj
32
+ end
33
+
34
+ def negative_boundary_values
35
+ super +
36
+ [
37
+ 'string',
38
+ [],
39
+ 123,
40
+ 1,
41
+ 0,
42
+ true,
43
+ false
44
+ ]
45
+ end
43
46
  end
44
47
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'api-tester/definition/fields/field'
4
+
5
+ module ApiTester
6
+ # Class for defining plain arrays
7
+ class PlainArrayField < Field
8
+ def initialize(name:, default_value: [], required: false)
9
+ super name: name, default_value: default_value, required: required
10
+ end
11
+
12
+ def negative_boundary_values
13
+ super +
14
+ [
15
+ 'string',
16
+ 123,
17
+ 0,
18
+ 1,
19
+ {},
20
+ true,
21
+ false
22
+ ]
23
+ end
24
+ end
25
+ end
@@ -1,17 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
4
+ # Class for defining methods as part of an endpoint
2
5
  class Method
3
6
  attr_accessor :request
4
7
  attr_accessor :expected_response
5
8
  attr_accessor :verb
6
9
 
7
- def initialize verb, response, request
10
+ def initialize(verb:, response:, request:)
8
11
  self.verb = verb
9
12
  self.request = request
10
13
  self.expected_response = response
11
14
  end
12
15
 
13
16
  def default_request
14
- {:method => self.verb, :payload => request.default_payload, :headers => request.default_headers}
17
+ { method: verb,
18
+ payload: request.default_payload,
19
+ headers: request.default_headers }
15
20
  end
16
21
  end
17
22
  end
@@ -1,30 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'api-tester/definition/boundary_case'
2
4
 
3
5
  module ApiTester
6
+ # Class for defining requests in a contract
4
7
  class Request
5
8
  attr_accessor :definition
6
9
  attr_accessor :header_fields
7
10
  attr_accessor :fields
11
+ attr_accessor :query_params
8
12
 
9
13
  def initialize
10
14
  self.fields = []
11
15
  self.header_fields = []
16
+ self.query_params = []
12
17
  end
13
18
 
14
19
  def add_field(new_field)
15
- self.fields << new_field
20
+ fields << new_field
21
+ self
22
+ end
23
+
24
+ def add_query_param(new_query_param)
25
+ query_params << new_query_param
16
26
  self
17
27
  end
18
28
 
19
- def add_header_field new_header
20
- self.header_fields << new_header
29
+ def default_query
30
+ query_params.map { |param| "#{param.name}=#{param.default_value}" }.join('&')
31
+ end
32
+
33
+ def add_header_field(new_header)
34
+ header_fields << new_header
21
35
  self
22
36
  end
23
37
 
24
38
  def payload
25
- response = Hash.new
26
- self.fields.each do |field|
27
- response[field.name] = field.default_value
39
+ response = {}
40
+ fields.each do |field|
41
+ if field.required == true
42
+ response[field.name] = field.default_value
43
+ end
28
44
  end
29
45
  response
30
46
  end
@@ -34,36 +50,47 @@ module ApiTester
34
50
  end
35
51
 
36
52
  def default_headers
37
- if self.header_fields != []
38
- self.headers
53
+ if header_fields != []
54
+ headers
39
55
  else
40
- {content_type: :json, accept: :json}
56
+ { content_type: :json, accept: :json }
41
57
  end
42
58
  end
43
59
 
44
60
  def headers
45
61
  header_response = {}
46
- self.header_fields.each do |header|
47
- header_response[header.name] = header.default_value
62
+ header_fields.each do |header_field|
63
+ header_response[header_field.name] = header_field.default_value
48
64
  end
49
65
  header_response
50
66
  end
51
67
 
52
68
  def cases
53
- boundary_cases = Array.new
54
- self.fields.each do |field|
69
+ boundary_cases = []
70
+ fields.each do |field|
55
71
  field.negative_boundary_values.each do |value|
56
- bcase = BoundaryCase.new("Setting #{field.name} to #{value}", altered_payload(field.name, value), default_headers)
57
- boundary_cases.push(bcase)
72
+ bcase = BoundaryCase.new description: "Setting #{field.name} to #{value}",
73
+ payload: altered_payload(field_name: field.name,
74
+ value: value),
75
+ headers: default_headers
76
+ boundary_cases.push bcase
58
77
  end
59
78
  end
60
79
  boundary_cases
61
80
  end
62
81
 
63
- def altered_payload field_name, value
82
+ def altered_payload(field_name:, value:)
64
83
  body = payload
65
84
  body[field_name] = value
66
85
  body
67
86
  end
87
+
88
+ def altered_payload_with(fields)
89
+ body = payload
90
+ fields.each do |field|
91
+ body[field[:name]] = field[:value]
92
+ end
93
+ body
94
+ end
68
95
  end
69
96
  end
@@ -1,36 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApiTester
4
+ # Class for defining expected responses
2
5
  class Response
3
- attr_accessor :code
4
- attr_accessor :body
6
+ attr_accessor :code
7
+ attr_accessor :body
5
8
 
6
- def initialize(status_code=200)
7
- self.code = status_code
8
- self.body = []
9
- end
9
+ def initialize(status_code: 200)
10
+ self.code = status_code
11
+ self.body = []
12
+ end
10
13
 
11
- def add_field(new_field)
12
- self.body << new_field
13
- self
14
- end
14
+ def add_field(new_field)
15
+ body << new_field
16
+ self
17
+ end
15
18
 
16
- def to_s
17
- des = {}
18
- self.body.map do |f|
19
- des[f.name] = field_display f
20
- end
21
- des.to_json
19
+ def to_s
20
+ des = {}
21
+ body.map do |f|
22
+ des[f.name] = field_display f
22
23
  end
24
+ des.to_json
25
+ end
23
26
 
24
- def field_display field
25
- des = field.display_class
26
- if field.has_subfields?
27
- des = {}
28
- field.fields.map do |f|
29
- des[f.name] = field_display f
30
- end
31
- des.to_json
32
- end
33
- des
27
+ def field_display(field)
28
+ des = field.display_class
29
+ if field.subfields?
30
+ des = {}
31
+ field.fields.map do |f|
32
+ des[f.name] = field_display f
33
+ end
34
+ des.to_json
34
35
  end
36
+ des
37
+ end
35
38
  end
36
39
  end