api-tester 1.0.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
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