fastlane-plugin-flutter_tests 0.1.1 → 0.2.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 +4 -4
- data/lib/fastlane/plugin/flutter_tests/actions/flutter_tests_action.rb +67 -165
- data/lib/fastlane/plugin/flutter_tests/helper/flutter_integration_test_helper.rb +136 -0
- data/lib/fastlane/plugin/flutter_tests/helper/flutter_unit_test_helper.rb +114 -0
- data/lib/fastlane/plugin/flutter_tests/model/test_item.rb +71 -0
- data/lib/fastlane/plugin/flutter_tests/version.rb +1 -1
- metadata +4 -2
- data/lib/fastlane/plugin/flutter_tests/helper/flutter_tests_helper.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42e082a14be1e8489bfcc34fc32ca6863d3d8a4d8d9595d1d2ca52020d600c31
|
4
|
+
data.tar.gz: 2d2987def7370d09cd0f044c8379b18fca146ae7335099604ebc398484307955
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 167e72db449d86ae77abb6c9cef671fe922967e57a94b9f9b34aea45d19adc3d3a8386b56938d27e75c4b2fd770a6d811dbdd623c62b93efeccb2fd9743e127a
|
7
|
+
data.tar.gz: 1a1c09c0272c465312f03dd25c5bc6448072d3217ce08ffbe6ddc9c882ba18feb783269bfe1e93b54533563a445cd8740e3e937e2dcf51365d977b7077d98e8d
|
@@ -1,185 +1,36 @@
|
|
1
1
|
require 'fastlane/action'
|
2
|
-
require_relative '../helper/
|
2
|
+
require_relative '../helper/flutter_unit_test_helper'
|
3
|
+
require_relative '../helper/flutter_integration_test_helper'
|
3
4
|
require 'open3'
|
4
5
|
require 'json'
|
6
|
+
require_relative '../model/test_item'
|
5
7
|
|
6
8
|
module Fastlane
|
7
9
|
module Actions
|
8
10
|
class FlutterTestsAction < Action
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@test_name = name
|
14
|
-
@test_done = false
|
15
|
-
@test_successful = ''
|
16
|
-
@test_error = nil
|
17
|
-
@test_stacktrace = nil
|
18
|
-
@test_was_skipped = false
|
19
|
-
@test_was_printed = false
|
20
|
-
end
|
21
|
-
|
22
|
-
def mark_as_done(success, skipped, error, stacktrace)
|
23
|
-
@test_done = true
|
24
|
-
@test_successful = success
|
25
|
-
@test_was_skipped = skipped
|
26
|
-
@test_error = error
|
27
|
-
unless stacktrace.nil?
|
28
|
-
stacktrace = stacktrace.gsub(/ {2,}/, "\n")
|
29
|
-
@test_stacktrace = stacktrace
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def get_name
|
34
|
-
@test_name
|
35
|
-
end
|
36
|
-
|
37
|
-
def get_id
|
38
|
-
@test_id
|
39
|
-
end
|
40
|
-
|
41
|
-
def can_print
|
42
|
-
!@test_was_printed
|
43
|
-
end
|
44
|
-
|
45
|
-
def get_status
|
46
|
-
if @test_was_skipped
|
47
|
-
'skipped'
|
48
|
-
else
|
49
|
-
@test_successful
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def _generate_message
|
54
|
-
tag = @test_was_skipped ? 'skipped' : @test_successful
|
55
|
-
|
56
|
-
default_message = "[#{tag}] #{@test_name}"
|
57
|
-
if @test_successful != 'success'
|
58
|
-
default_message += "\n[ERROR] -> #{@test_error}\n[STACKTRACE]\n#{@test_stacktrace}"
|
59
|
-
end
|
60
|
-
|
61
|
-
if %w[success error].include?(@test_successful) || @test_was_skipped
|
62
|
-
color = if @test_was_skipped
|
63
|
-
34 # Skipped tests are displayed in blue
|
64
|
-
else
|
65
|
-
# Successful tests are in green and the failed in red
|
66
|
-
@test_successful == 'success' ? 32 : 31
|
67
|
-
end
|
68
|
-
|
69
|
-
"\e[#{color}m#{default_message}\e[0m"
|
70
|
-
else
|
71
|
-
default_message
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def print
|
76
|
-
UI.message(_generate_message)
|
77
|
-
@test_was_printed = true
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class TestRunner
|
82
|
-
def initialize
|
83
|
-
@launched_tests = Hash.new { |hash, key| hash[key] = nil }
|
84
|
-
end
|
85
|
-
|
86
|
-
# Wraps the message to color it
|
87
|
-
#
|
88
|
-
# @param message [String] the message that has to be wrapped
|
89
|
-
# @param color [Integer] the color of the message (34 -> blue, 32 -> green, 31 -> red)
|
90
|
-
def _colorize(message, color)
|
91
|
-
"\e[#{color}m#{message}\e[0m"
|
11
|
+
def self.run(params)
|
12
|
+
test_type = params[:test_type]
|
13
|
+
if %w[all unit].include? test_type
|
14
|
+
Helper::FlutterUnitTestHelper.new.run(params[:flutter_command], params[:print_only_failed], params[:print_stats])
|
92
15
|
end
|
16
|
+
if %w[all integration].include? test_type
|
93
17
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
Open3.popen3("#{flutter_command} test --machine") do |stdin, stdout, stderr, thread|
|
98
|
-
stdout.each_line do |line|
|
99
|
-
parse_json_output(line, print_only_failed)
|
100
|
-
end
|
18
|
+
if params[:driver_path].nil? || params[:integration_tests].nil?
|
19
|
+
UI.user_error!("If launching integration tests, 'driver_path' and 'integration_tests' parameters must be inserted")
|
20
|
+
exit(1)
|
101
21
|
end
|
102
22
|
|
103
|
-
|
104
|
-
stats = Hash.new { |hash, key| hash[key] = 0 }
|
105
|
-
@launched_tests.values.each do |item|
|
106
|
-
unless item.nil?
|
107
|
-
stats[item.get_status] += 1
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
skipped_tests = stats['skipped'].nil? ? 0 : stats['skipped']
|
112
|
-
failed_tests = stats['error'].nil? ? 0 : stats['error']
|
113
|
-
successful_tests = stats['success'].nil? ? 0 : stats['success']
|
114
|
-
table = [
|
115
|
-
%w[Successful Failed Skipped],
|
116
|
-
[successful_tests, failed_tests, skipped_tests]
|
117
|
-
]
|
118
|
-
|
119
|
-
messages = ["Ran #{@launched_tests.values.count { |e| !e.nil? }} tests"]
|
120
|
-
colors = { 0 => 32, 1 => 31, 2 => 34 }
|
121
|
-
max_length = 0
|
122
|
-
(0..2).each do |i|
|
123
|
-
msg = "#{table[0][i]}:\t#{table[1][i]}"
|
124
|
-
max_length = [max_length, msg.length].max
|
125
|
-
messages.append(_colorize(msg, colors[i]))
|
126
|
-
end
|
23
|
+
platform = params[:platform]
|
127
24
|
|
128
|
-
|
129
|
-
|
130
|
-
|
25
|
+
if params[:reuse_build] && platform != 'android'
|
26
|
+
UI.error("If 'reuse_build' is set to true, the platform must be android")
|
27
|
+
platform = 'android'
|
131
28
|
end
|
132
|
-
end
|
133
29
|
|
134
|
-
|
135
|
-
def parse_json_output(line, print_only_failed)
|
136
|
-
unless line.to_s.strip.empty?
|
137
|
-
output = JSON.parse(line)
|
138
|
-
unless output.kind_of?(Array)
|
139
|
-
type = output['type']
|
140
|
-
case type
|
141
|
-
when 'testStart'
|
142
|
-
id = output['test']['id']
|
143
|
-
name = output['test']['name']
|
144
|
-
if name.include?('loading')
|
145
|
-
return
|
146
|
-
end
|
147
|
-
|
148
|
-
test_item = Test.new(id, name)
|
149
|
-
@launched_tests[test_item.get_id] = test_item
|
150
|
-
when 'testDone'
|
151
|
-
test_id = output['testID']
|
152
|
-
test_item = @launched_tests[test_id]
|
153
|
-
if !test_item.nil? && test_item.can_print
|
154
|
-
was_skipped = output['skipped']
|
155
|
-
test_item.mark_as_done(output['result'], was_skipped, nil, nil)
|
156
|
-
if was_skipped || !print_only_failed
|
157
|
-
test_item.print
|
158
|
-
end
|
159
|
-
end
|
160
|
-
when 'error'
|
161
|
-
test_id = output['testID']
|
162
|
-
test_item = @launched_tests[test_id]
|
163
|
-
if !test_item.nil? && test_item.can_print
|
164
|
-
test_item.mark_as_done('error', false, output['error'], output['stackTrace'])
|
165
|
-
test_item.print
|
166
|
-
end
|
167
|
-
else
|
168
|
-
# ignored
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
rescue StandardError => e
|
173
|
-
UI.error("Got error during parse_json: #{e.message}")
|
174
|
-
UI.error(e.backtrace.join('\n'))
|
175
|
-
exit(1)
|
30
|
+
Helper::FlutterIntegrationTestHelper.new(params[:driver_path], params[:integration_tests], params[:flutter_command]).run(platform, params[:force_launch], params[:reuse_build])
|
176
31
|
end
|
177
32
|
end
|
178
33
|
|
179
|
-
def self.run(params)
|
180
|
-
TestRunner.new.run(params[:flutter_command], params[:print_only_failed], params[:print_stats])
|
181
|
-
end
|
182
|
-
|
183
34
|
def self.description
|
184
35
|
"Extension that helps to run flutter tests"
|
185
36
|
end
|
@@ -220,6 +71,57 @@ module Fastlane
|
|
220
71
|
optional: false,
|
221
72
|
type: Boolean
|
222
73
|
),
|
74
|
+
FastlaneCore::ConfigItem.new(
|
75
|
+
key: :test_type,
|
76
|
+
default_value: 'all',
|
77
|
+
description: "Specifies which tests should be run. Accepted values",
|
78
|
+
verify_block: proc do |value|
|
79
|
+
UI.user_error!("Wrong value, #{value} not accepted. Should be 'unit','integration' or 'all'.") unless %w[unit integration all].include? value
|
80
|
+
end,
|
81
|
+
optional: false,
|
82
|
+
type: String,
|
83
|
+
),
|
84
|
+
FastlaneCore::ConfigItem.new(
|
85
|
+
key: :driver_path,
|
86
|
+
description: "Specifies the path of the driver file",
|
87
|
+
optional: true,
|
88
|
+
type: String,
|
89
|
+
verify_block: proc do |value|
|
90
|
+
UI.user_error!("Driver file doesn't exists") unless File.file?(value)
|
91
|
+
end
|
92
|
+
),
|
93
|
+
FastlaneCore::ConfigItem.new(
|
94
|
+
key: :integration_tests,
|
95
|
+
description: "Specifies the path of the folder containing all the integration tests",
|
96
|
+
optional: true,
|
97
|
+
type: String,
|
98
|
+
verify_block: proc do |value|
|
99
|
+
UI.user_error!("Integration test folder doesn't exists") unless File.exist?(value) && File.directory?(value)
|
100
|
+
end
|
101
|
+
),
|
102
|
+
FastlaneCore::ConfigItem.new(
|
103
|
+
key: :platform,
|
104
|
+
description: "Specifies the os on which the tests should run on",
|
105
|
+
optional: false,
|
106
|
+
type: String,
|
107
|
+
verify_block: proc do |value|
|
108
|
+
UI.user_error!("Platform #{value} is not supported") unless %w[android ios].include? value.to_s.downcase
|
109
|
+
end
|
110
|
+
),
|
111
|
+
FastlaneCore::ConfigItem.new(
|
112
|
+
key: :force_launch,
|
113
|
+
description: "If true, the plugin will try to launch an emulator in case it's not already running",
|
114
|
+
optional: false,
|
115
|
+
type: Boolean,
|
116
|
+
default_value: true,
|
117
|
+
),
|
118
|
+
FastlaneCore::ConfigItem.new(
|
119
|
+
key: :reuse_build,
|
120
|
+
description: "If true, builds the app only for the first time then the other integration tests are run on the same build (much faster)",
|
121
|
+
default_value: false,
|
122
|
+
optional: false,
|
123
|
+
type: Boolean,
|
124
|
+
)
|
223
125
|
]
|
224
126
|
end
|
225
127
|
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Helper
|
6
|
+
class FlutterIntegrationTestHelper
|
7
|
+
# Initialize the helper that launches the integration tests
|
8
|
+
#
|
9
|
+
# @param driver [String] the path to the file that will be used as driver
|
10
|
+
# @param test_folder [String] the path to the folder that contains the
|
11
|
+
# @param flutter_command [String] the command to launch flutter
|
12
|
+
# integration tests
|
13
|
+
def initialize(driver, test_folder, flutter_command)
|
14
|
+
@driver = driver
|
15
|
+
@integration_tests = _load_files(test_folder)
|
16
|
+
@flutter_command = flutter_command
|
17
|
+
end
|
18
|
+
|
19
|
+
# Loads all the integration test files
|
20
|
+
#
|
21
|
+
# @param test_folder [String] the path that contains the test files
|
22
|
+
# @return [Array] An array containing all the paths to the files found
|
23
|
+
def _load_files(test_folder)
|
24
|
+
test_files = Dir.glob("#{test_folder}/**/*").reject do |f|
|
25
|
+
File.directory?(f) || !f.end_with?('_test.dart')
|
26
|
+
end
|
27
|
+
UI.message("Found #{test_files.length} test files")
|
28
|
+
test_files
|
29
|
+
end
|
30
|
+
|
31
|
+
# Launches the tests sequentially
|
32
|
+
#
|
33
|
+
# @param platform [String] Specifies on which platform the tests should be run
|
34
|
+
# @param force_launch [Boolean] If it's true and there aren't any devices ready, the plugin will try to start one for the given platform
|
35
|
+
# @param reuse_build [Boolean] If it's true, it will run the build only for the first integration test
|
36
|
+
def run(platform, force_launch, reuse_build)
|
37
|
+
UI.message("Checking for running devices")
|
38
|
+
device_id = _run_test_device(platform, force_launch)
|
39
|
+
if !device_id.nil?
|
40
|
+
_launch_tests(device_id, reuse_build)
|
41
|
+
else
|
42
|
+
UI.error("Failed to find a device to launch the tests on")
|
43
|
+
exit(1)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Executes the tests found on the device_id
|
48
|
+
#
|
49
|
+
# @param device_id [String] the id of the device previously found
|
50
|
+
# @param reuse_build [Boolean] If it's true, it will run the build only for the first integration test
|
51
|
+
def _launch_tests(device_id, reuse_build)
|
52
|
+
apk_path = nil
|
53
|
+
if reuse_build
|
54
|
+
UI.message("Building apk")
|
55
|
+
out, err, status = Open3.capture3("#{@flutter_command} build apk")
|
56
|
+
if _get_exit_code(status) != '0'
|
57
|
+
UI.error("Failed to build apk")
|
58
|
+
puts err
|
59
|
+
exit(1)
|
60
|
+
else
|
61
|
+
apk_path = _get_apk_path(out)
|
62
|
+
if !apk_path.nil? && File.file?(apk_path)
|
63
|
+
UI.message("Build apk at path #{apk_path}")
|
64
|
+
#TODO
|
65
|
+
else
|
66
|
+
UI.error("Apk path not found or it's not accessible")
|
67
|
+
exit(1)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
count = 0
|
74
|
+
@integration_tests.each do |test|
|
75
|
+
UI.message("Launching test #{count}/#{@integration_tests.length}: #{test.split("/").last}")
|
76
|
+
_, __, status = Open3.capture3("#{@flutter_command} drive --target #{@driver} --driver #{test} -d #{device_id} #{reuse_build ? "--use-application-binary #{apk_path}" : ''}")
|
77
|
+
UI.message("Test #{count} ended with code '#{_get_exit_code(status)}'")
|
78
|
+
count += 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the exit code of a process
|
83
|
+
#
|
84
|
+
# @param exit_status [String] status given back by [Open3]
|
85
|
+
# @return The exit code (0|1) as string
|
86
|
+
def _get_exit_code(exit_status)
|
87
|
+
exit_status.to_s.split(' ').last
|
88
|
+
end
|
89
|
+
|
90
|
+
# Parse the flutter build output looking for a .apk path
|
91
|
+
#
|
92
|
+
# @param message [String] the stdout of flutter build process
|
93
|
+
# @return the path to the apk that has been built
|
94
|
+
def _get_apk_path(message)
|
95
|
+
components = message.split(/\n/).last.split(' ')
|
96
|
+
if components.any? { |line| line.end_with? '.apk' }
|
97
|
+
components.detect { |c| c.end_with? '.apk' }
|
98
|
+
else
|
99
|
+
UI.warn('Apk path not found in the stdout')
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Checks if there's a device running and gets its id
|
105
|
+
# @param platform [String] Specifies the type of device that should be found
|
106
|
+
# @param force_launch [Boolean] If it's true and there aren't any devices ready, the plugin will try to start one for the given platform
|
107
|
+
# @return The deviceId if the device exists or [nil]
|
108
|
+
def _run_test_device(platform, force_launch)
|
109
|
+
out, _ = Open3.capture2("#{@flutter_command} devices | grep #{platform}")
|
110
|
+
device_id = nil
|
111
|
+
if out.to_s.strip.empty? && force_launch
|
112
|
+
out, _ = Open3.capture2("#{@flutter_command} emulators | grep #{platform}")
|
113
|
+
if out.to_s.strip.empty?
|
114
|
+
UI.error("No emulators found for platform #{platform}")
|
115
|
+
exit(1)
|
116
|
+
end
|
117
|
+
|
118
|
+
emulator_id = out.to_s.split('•')[0]
|
119
|
+
Open3.capture2("#{@flutter_command} emulators --launch #{emulator_id}")
|
120
|
+
|
121
|
+
out, _ = Open3.capture2("#{@flutter_command} devices | grep #{platform}")
|
122
|
+
else
|
123
|
+
device_id = (out.to_s.split("•")[1]).strip
|
124
|
+
UI.message("Found already running device: #{device_id}")
|
125
|
+
end
|
126
|
+
|
127
|
+
unless out.to_s.strip.empty?
|
128
|
+
device_id = (out.to_s.split("•")[1]).strip
|
129
|
+
UI.message("Got device id #{device_id}")
|
130
|
+
end
|
131
|
+
|
132
|
+
device_id.nil? ? nil : device_id
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
|
5
|
+
module Helper
|
6
|
+
class FlutterUnitTestHelper
|
7
|
+
def initialize
|
8
|
+
@launched_tests = Hash.new { |hash, key| hash[key] = nil }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Wraps the message to color it
|
12
|
+
#
|
13
|
+
# @param message [String] the message that has to be wrapped
|
14
|
+
# @param color [Integer] the color of the message (34 -> blue, 32 -> green, 31 -> red)
|
15
|
+
#
|
16
|
+
# @return [String] the colorized message ready to be printed
|
17
|
+
def _colorize(message, color)
|
18
|
+
"\e[#{color}m#{message}\e[0m"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Launches all the unit tests contained in the project
|
22
|
+
# folder
|
23
|
+
#
|
24
|
+
# @param flutter_command [String] Contains the command to launch flutter
|
25
|
+
# @param print_only_failed [Boolean] If true, prints only skipped and failed tests
|
26
|
+
# @param print_stats [Boolean] If true, it prints a table containing the info about
|
27
|
+
# the launched tests
|
28
|
+
def run(flutter_command, print_only_failed, print_stats)
|
29
|
+
Open3.popen3("#{flutter_command} test --machine") do |stdin, stdout, stderr, thread|
|
30
|
+
stdout.each_line do |line|
|
31
|
+
parse_json_output(line, print_only_failed)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if print_stats
|
36
|
+
stats = Hash.new { |hash, key| hash[key] = 0 }
|
37
|
+
@launched_tests.values.each do |item|
|
38
|
+
unless item.nil?
|
39
|
+
stats[item.get_status] += 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
skipped_tests = stats['skipped'].nil? ? 0 : stats['skipped']
|
44
|
+
failed_tests = stats['error'].nil? ? 0 : stats['error']
|
45
|
+
successful_tests = stats['success'].nil? ? 0 : stats['success']
|
46
|
+
table = [
|
47
|
+
%w[Successful Failed Skipped],
|
48
|
+
[successful_tests, failed_tests, skipped_tests]
|
49
|
+
]
|
50
|
+
|
51
|
+
messages = ["Ran #{@launched_tests.values.count { |e| !e.nil? }} tests"]
|
52
|
+
colors = { 0 => 32, 1 => 31, 2 => 34 }
|
53
|
+
max_length = 0
|
54
|
+
(0..2).each do |i|
|
55
|
+
msg = "#{table[0][i]}:\t#{table[1][i]}"
|
56
|
+
max_length = [max_length, msg.length].max
|
57
|
+
messages.append(_colorize(msg, colors[i]))
|
58
|
+
end
|
59
|
+
|
60
|
+
UI.message('-' * max_length)
|
61
|
+
messages.each { |m| UI.message(m) }
|
62
|
+
UI.message('-' * max_length)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Parses the json output given by [self.run]
|
67
|
+
#
|
68
|
+
# @param line [String] The json as string that has to be parsed
|
69
|
+
# @param print_only_failed [Boolean] See definition on run
|
70
|
+
def parse_json_output(line, print_only_failed)
|
71
|
+
unless line.to_s.strip.empty?
|
72
|
+
output = JSON.parse(line)
|
73
|
+
unless output.kind_of?(Array)
|
74
|
+
type = output['type']
|
75
|
+
case type
|
76
|
+
when 'testStart'
|
77
|
+
id = output['test']['id']
|
78
|
+
name = output['test']['name']
|
79
|
+
if name.include?('loading')
|
80
|
+
return
|
81
|
+
end
|
82
|
+
|
83
|
+
test_item = Test.new(id, name)
|
84
|
+
@launched_tests[test_item.get_id] = test_item
|
85
|
+
when 'testDone'
|
86
|
+
test_id = output['testID']
|
87
|
+
test_item = @launched_tests[test_id]
|
88
|
+
if !test_item.nil? && test_item.can_print
|
89
|
+
was_skipped = output['skipped']
|
90
|
+
test_item.mark_as_done(output['result'], was_skipped, nil, nil)
|
91
|
+
if was_skipped || !print_only_failed
|
92
|
+
UI.message(test_item.generate_message)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
when 'error'
|
96
|
+
test_id = output['testID']
|
97
|
+
test_item = @launched_tests[test_id]
|
98
|
+
if !test_item.nil? && test_item.can_print
|
99
|
+
test_item.mark_as_done('error', false, output['error'], output['stackTrace'])
|
100
|
+
UI.message(test_item.generate_message)
|
101
|
+
end
|
102
|
+
else
|
103
|
+
# ignored
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
rescue StandardError => e
|
108
|
+
UI.error("Got error during parse_json: #{e.message}")
|
109
|
+
UI.error(e.backtrace.join('\n'))
|
110
|
+
exit(1)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Class that represents a single test that has been run
|
2
|
+
class Test
|
3
|
+
def initialize(id, name)
|
4
|
+
@test_id = id
|
5
|
+
@test_name = name
|
6
|
+
@test_done = false
|
7
|
+
@test_successful = ''
|
8
|
+
@test_error = nil
|
9
|
+
@test_stacktrace = nil
|
10
|
+
@test_was_skipped = false
|
11
|
+
@test_was_printed = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def mark_as_done(success, skipped, error, stacktrace)
|
15
|
+
@test_done = true
|
16
|
+
@test_successful = success
|
17
|
+
@test_was_skipped = skipped
|
18
|
+
@test_error = error
|
19
|
+
unless stacktrace.nil?
|
20
|
+
stacktrace = stacktrace.gsub(/ {2,}/, "\n")
|
21
|
+
@test_stacktrace = stacktrace
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_name
|
26
|
+
@test_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_id
|
30
|
+
@test_id
|
31
|
+
end
|
32
|
+
|
33
|
+
def can_print
|
34
|
+
!@test_was_printed
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_status
|
38
|
+
if @test_was_skipped
|
39
|
+
'skipped'
|
40
|
+
else
|
41
|
+
@test_successful
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Generates a loggable message for the given test
|
46
|
+
#
|
47
|
+
# @return message [String] the message to print
|
48
|
+
def generate_message
|
49
|
+
@test_was_printed = true
|
50
|
+
tag = @test_was_skipped ? 'skipped' : @test_successful
|
51
|
+
|
52
|
+
default_message = "[#{tag}] #{@test_name}"
|
53
|
+
if @test_successful != 'success'
|
54
|
+
default_message += "\n[ERROR] -> #{@test_error}\n[STACKTRACE]\n#{@test_stacktrace}"
|
55
|
+
end
|
56
|
+
|
57
|
+
if %w[success error].include?(@test_successful) || @test_was_skipped
|
58
|
+
color = if @test_was_skipped
|
59
|
+
34 # Skipped tests are displayed in blue
|
60
|
+
else
|
61
|
+
# Successful tests are in green and the failed in red
|
62
|
+
@test_successful == 'success' ? 32 : 31
|
63
|
+
end
|
64
|
+
|
65
|
+
"\e[#{color}m#{default_message}\e[0m"
|
66
|
+
else
|
67
|
+
default_message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-flutter_tests
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- smaso
|
@@ -160,7 +160,9 @@ files:
|
|
160
160
|
- README.md
|
161
161
|
- lib/fastlane/plugin/flutter_tests.rb
|
162
162
|
- lib/fastlane/plugin/flutter_tests/actions/flutter_tests_action.rb
|
163
|
-
- lib/fastlane/plugin/flutter_tests/helper/
|
163
|
+
- lib/fastlane/plugin/flutter_tests/helper/flutter_integration_test_helper.rb
|
164
|
+
- lib/fastlane/plugin/flutter_tests/helper/flutter_unit_test_helper.rb
|
165
|
+
- lib/fastlane/plugin/flutter_tests/model/test_item.rb
|
164
166
|
- lib/fastlane/plugin/flutter_tests/version.rb
|
165
167
|
homepage: https://github.com/smsimone/fastlane_flutter_tests.git
|
166
168
|
licenses:
|
@@ -1,16 +0,0 @@
|
|
1
|
-
require 'fastlane_core/ui/ui'
|
2
|
-
|
3
|
-
module Fastlane
|
4
|
-
UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
|
5
|
-
|
6
|
-
module Helper
|
7
|
-
class FlutterTestsHelper
|
8
|
-
# class methods that you define here become available in your action
|
9
|
-
# as `Helper::FlutterTestsHelper.your_method`
|
10
|
-
#
|
11
|
-
def self.show_message
|
12
|
-
UI.message("Hello from the flutter_tests plugin helper!")
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|