golden_rose 0.1.0 → 1.0.0.pre
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/.gitignore +1 -0
- data/README.md +10 -5
- data/golden_rose.gemspec +3 -1
- data/lib/golden_rose/build_log/build_section.rb +56 -0
- data/lib/golden_rose/build_log/build_target.rb +21 -0
- data/lib/golden_rose/build_log/parser.rb +40 -0
- data/lib/golden_rose/build_log.rb +3 -0
- data/lib/golden_rose/child_item.rb +91 -9
- data/lib/golden_rose/class_configurator.rb +49 -0
- data/lib/golden_rose/cli/app.rb +12 -3
- data/lib/golden_rose/execution_details.rb +22 -42
- data/lib/golden_rose/file_resource.rb +98 -0
- data/lib/golden_rose/generators/html_format.rb +70 -7
- data/lib/golden_rose/info.rb +11 -0
- data/lib/golden_rose/parser.rb +28 -30
- data/lib/golden_rose/results_filterer.rb +4 -54
- data/lib/golden_rose/templates/_build_logs.haml +24 -0
- data/lib/golden_rose/templates/_footer.haml +5 -0
- data/lib/golden_rose/templates/_test_logs.haml +9 -0
- data/lib/golden_rose/templates/_tests.haml +52 -0
- data/lib/golden_rose/templates/assets/javascript/main.js.haml +48 -0
- data/lib/golden_rose/templates/assets/styles/main.css.haml +203 -0
- data/lib/golden_rose/templates/assets/styles/test_logs.css.haml +101 -0
- data/lib/golden_rose/templates/index.haml +23 -116
- data/lib/golden_rose/templates/test_logs/index.haml +38 -0
- data/lib/golden_rose/testable_summary.rb +90 -0
- data/lib/golden_rose/version.rb +1 -1
- data/lib/golden_rose/xcactivitylog_reader.rb +54 -0
- data/lib/golden_rose.rb +20 -5
- metadata +51 -6
data/lib/golden_rose/parser.rb
CHANGED
@@ -2,57 +2,55 @@
|
|
2
2
|
# from zip file or folder
|
3
3
|
|
4
4
|
require "plist"
|
5
|
-
require "zip"
|
6
|
-
require "securerandom"
|
7
5
|
|
8
6
|
module GoldenRose
|
9
7
|
class Parser
|
10
|
-
|
11
|
-
|
12
|
-
attr_accessor :parsed_plist, :folder_path
|
8
|
+
attr_accessor :folder_path
|
9
|
+
attr_reader :parsed_test_summaries_plist, :parsed_info_plist, :parsed_build_logs
|
13
10
|
|
14
11
|
def initialize(folder_path)
|
15
12
|
@folder_path = folder_path
|
16
13
|
end
|
17
14
|
|
18
15
|
def parse!
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
read_plists
|
17
|
+
parse_plists
|
18
|
+
parse_build_logs
|
19
|
+
delete_extracted_files
|
20
|
+
self
|
21
|
+
end
|
25
22
|
|
26
|
-
|
27
|
-
|
23
|
+
def source_type
|
24
|
+
archive? ? :zip : :dir
|
28
25
|
end
|
29
26
|
|
30
27
|
private
|
31
28
|
|
32
|
-
def
|
33
|
-
@
|
29
|
+
def read_plists
|
30
|
+
@test_summaries_resource = FileResource.new(:test_summaries_plist, source_type, folder_path)
|
31
|
+
@info_resource = FileResource.new(:info_plist, source_type, folder_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse_plists
|
35
|
+
@parsed_test_summaries_plist = @test_summaries_resource.path ? Plist.parse_xml(@test_summaries_resource.path) : nil
|
36
|
+
puts("Could not parse test_summaries.plist correctly") unless @parsed_test_summaries_plist
|
37
|
+
@parsed_info_plist = Plist.parse_xml(@info_resource.path)
|
38
|
+
fail GeneratingError, 'Could not parse Info.plist correctly.' unless @parsed_info_plist
|
34
39
|
end
|
35
40
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
test_summaries?(file_name)
|
41
|
-
end
|
42
|
-
if entry
|
43
|
-
uuid = ::SecureRandom.uuid
|
44
|
-
@plist_file_path = File.join(GoldenRose::root, "/source_#{uuid}.plist")
|
45
|
-
entry.extract(@plist_file_path)
|
46
|
-
end
|
47
|
-
end
|
41
|
+
def parse_build_logs
|
42
|
+
build_log_path = Info.new(@parsed_info_plist).build_log_path
|
43
|
+
@build_log_resource = FileResource.new(:build_log, source_type, folder_path, build_log_path)
|
44
|
+
@parsed_build_logs = GoldenRose::BuildLog::Parser.new(@build_log_resource.path).parse!
|
48
45
|
end
|
49
46
|
|
50
|
-
def
|
51
|
-
|
47
|
+
def delete_extracted_files
|
48
|
+
[@test_summaries_resource, @info_resource, @build_log_resource]
|
49
|
+
.map(&:delete_extracted_file)
|
52
50
|
end
|
53
51
|
|
54
52
|
def archive?
|
55
53
|
!(folder_path =~ /\.(?:rar|zip|tar.gz)$/).nil?
|
56
54
|
end
|
57
55
|
end
|
58
|
-
end
|
56
|
+
end
|
@@ -3,65 +3,15 @@
|
|
3
3
|
|
4
4
|
module GoldenRose
|
5
5
|
class ResultsFilterer
|
6
|
-
attr_accessor :parsed_plist
|
6
|
+
attr_accessor :parsed_plist
|
7
7
|
|
8
8
|
def initialize(parsed_plist)
|
9
9
|
@parsed_plist = parsed_plist
|
10
10
|
end
|
11
11
|
|
12
12
|
def filter!
|
13
|
-
|
14
|
-
|
15
|
-
@results = Results.new(execution_details, items)
|
13
|
+
return nil if @parsed_plist.nil?
|
14
|
+
ExecutionDetails.new(@parsed_plist)
|
16
15
|
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def iterate_subtests(items)
|
21
|
-
items.map do |subtest|
|
22
|
-
child_subtests = subtest["Subtests"]
|
23
|
-
next if child_subtests && child_subtests.empty?
|
24
|
-
|
25
|
-
if child_subtests
|
26
|
-
ParentItem.new(subtest).tap do |item|
|
27
|
-
item.subtests = iterate_subtests(child_subtests)
|
28
|
-
end.to_h
|
29
|
-
else
|
30
|
-
ChildItem.new(subtest).to_h
|
31
|
-
end
|
32
|
-
end.compact
|
33
|
-
end
|
34
|
-
|
35
|
-
def items
|
36
|
-
@items ||= compact_results(iterate_subtests(tests))
|
37
|
-
end
|
38
|
-
|
39
|
-
# This method simplify results structure,
|
40
|
-
# it sets only one level of nesting
|
41
|
-
# by leaving parents only with collection as child
|
42
|
-
def compact_results(items)
|
43
|
-
items.map do |subtest|
|
44
|
-
subtests = subtest[:subtests]
|
45
|
-
if subtests.size > 1
|
46
|
-
subtests
|
47
|
-
elsif subtests.size == 1
|
48
|
-
compact_results(subtests)
|
49
|
-
end
|
50
|
-
end.flatten.compact
|
51
|
-
end
|
52
|
-
|
53
|
-
def execution_details
|
54
|
-
ExecutionDetails.new(parsed_plist, items)
|
55
|
-
end
|
56
|
-
|
57
|
-
def testable_summaries
|
58
|
-
parsed_plist['TestableSummaries']
|
59
|
-
end
|
60
|
-
|
61
|
-
def tests
|
62
|
-
testable_summaries.first['Tests']
|
63
|
-
end
|
64
|
-
|
65
|
-
class Results < Struct.new(:details, :items); end
|
66
16
|
end
|
67
|
-
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
%ol#collapsible
|
2
|
+
- @build_logs.each do |build_target|
|
3
|
+
%li
|
4
|
+
%label(for="#{build_target.target_name}")
|
5
|
+
= "Build target #{build_target.target_name}"
|
6
|
+
%input(type="checkbox" id="#{build_target.target_name}")
|
7
|
+
%ol
|
8
|
+
- build_target.sections.each do |build_section|
|
9
|
+
%li
|
10
|
+
%span{class: (build_section.success? ? 'build-log-success' : 'build-log-error')}
|
11
|
+
= build_section.name
|
12
|
+
- if build_section.file?
|
13
|
+
%span.file
|
14
|
+
= build_section.file
|
15
|
+
%span.path
|
16
|
+
= "...in #{build_section.directory}"
|
17
|
+
- elsif !build_section.file? && build_section.path?
|
18
|
+
%span.path
|
19
|
+
= "#{build_section.path}"
|
20
|
+
- if build_section.errors?
|
21
|
+
%ul
|
22
|
+
- build_section.errors.each do |build_error|
|
23
|
+
%li.build-log-error.error-text
|
24
|
+
= build_error
|
@@ -0,0 +1,52 @@
|
|
1
|
+
- if @details.testable_summaries.size > 1
|
2
|
+
%ul.tab-nd.tests-tabs
|
3
|
+
- @details.testable_summaries.each.with_index do |testable_summary, idx|
|
4
|
+
%li
|
5
|
+
%a.tablinks-nd{href: "javascript:void(0)", onclick: "openTabNd(event, 'testable-summary-#{idx}')"}
|
6
|
+
= testable_summary.name
|
7
|
+
- @details.testable_summaries.each.with_index do |testable_summary, idx|
|
8
|
+
%div{id: "testable-summary-#{idx}", class: 'tabcontent-nd'}
|
9
|
+
%h1
|
10
|
+
= testable_summary.name
|
11
|
+
#details
|
12
|
+
#{testable_summary.total_tests_count} tests run on
|
13
|
+
%strong
|
14
|
+
#{@details.model_name} iOS #{@details.os_version}
|
15
|
+
with
|
16
|
+
%strong
|
17
|
+
#{testable_summary.passing_count} passing
|
18
|
+
and
|
19
|
+
%strong
|
20
|
+
#{testable_summary.failures_count} failing
|
21
|
+
in #{testable_summary.formatted_time}
|
22
|
+
#results
|
23
|
+
%ol#collapsible
|
24
|
+
- testable_summary.items.each do |item|
|
25
|
+
%li
|
26
|
+
%label(for="#{item[:node_id]}")
|
27
|
+
= item[:name]
|
28
|
+
- if item[:failures_count]
|
29
|
+
%span.failures-count
|
30
|
+
= "Failures: "
|
31
|
+
= item[:failures_count]
|
32
|
+
%input(type="checkbox" id="#{item[:node_id]}")
|
33
|
+
%ol
|
34
|
+
- (item[:subtests] || []).each do |subtest|
|
35
|
+
%li
|
36
|
+
%span(class="#{subtest[:status]}")
|
37
|
+
- if subtest[:has_activity_summaries]
|
38
|
+
%a.link{:href => "test_logs/#{subtest[:uuid]}.html", :target => "_blank"}
|
39
|
+
= subtest[:name]
|
40
|
+
- else
|
41
|
+
= subtest[:name]
|
42
|
+
%span.time
|
43
|
+
= subtest[:time]
|
44
|
+
- if subtest[:failures]
|
45
|
+
- subtest[:failures].each do |failure|
|
46
|
+
.failure-message
|
47
|
+
= failure[:message]
|
48
|
+
.failure-details
|
49
|
+
#{failure[:file_name]}:#{failure[:line_number]}
|
50
|
+
- if subtest[:instance].screenshot
|
51
|
+
%a{:href => "#{subtest[:instance].screenshot}"}
|
52
|
+
%img.screenshot-thumb{alt: "#{subtest[:instance].screenshot}", src: "#{subtest[:instance].screenshot}"}/
|
@@ -0,0 +1,48 @@
|
|
1
|
+
:javascript
|
2
|
+
function openTab(evt, tabId) {
|
3
|
+
var i, tabcontent, tablinks;
|
4
|
+
|
5
|
+
// Get all elements with class="tabcontent" and hide them
|
6
|
+
tabcontent = document.getElementsByClassName("tabcontent");
|
7
|
+
for (i = 0; i < tabcontent.length; i++) {
|
8
|
+
tabcontent[i].style.display = "none";
|
9
|
+
}
|
10
|
+
|
11
|
+
// Get all elements with class="tablinks" and remove the class "active"
|
12
|
+
tablinks = document.getElementsByClassName("tablinks");
|
13
|
+
for (i = 0; i < tablinks.length; i++) {
|
14
|
+
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
15
|
+
}
|
16
|
+
|
17
|
+
// Show the current tab, and add an "active" class to the link that opened the tab
|
18
|
+
document.getElementById(tabId).style.display = "block";
|
19
|
+
evt.currentTarget.className += " active";
|
20
|
+
}
|
21
|
+
|
22
|
+
function openTabNd(evt, tabId) {
|
23
|
+
var i, tabcontent, tablinks;
|
24
|
+
|
25
|
+
// Get all elements with class="tabcontent" and hide them
|
26
|
+
tabcontent = document.getElementsByClassName("tabcontent-nd");
|
27
|
+
for (i = 0; i < tabcontent.length; i++) {
|
28
|
+
tabcontent[i].style.display = "none";
|
29
|
+
}
|
30
|
+
|
31
|
+
// Get all elements with class="tablinks" and remove the class "active"
|
32
|
+
tablinks = document.getElementsByClassName("tablinks-nd");
|
33
|
+
for (i = 0; i < tablinks.length; i++) {
|
34
|
+
tablinks[i].className = tablinks[i].className.replace(" active", "");
|
35
|
+
}
|
36
|
+
|
37
|
+
// Show the current tab, and add an "active" class to the link that opened the tab
|
38
|
+
document.getElementById(tabId).style.display = "block";
|
39
|
+
evt.currentTarget.className += " active";
|
40
|
+
}
|
41
|
+
|
42
|
+
|
43
|
+
// Get the element with id="defaultOpen" and click on it
|
44
|
+
document.getElementById("default-open").click();
|
45
|
+
var firstTablinkNd = document.getElementsByClassName("tablinks-nd")[0];
|
46
|
+
if (firstTablinkNd) {
|
47
|
+
firstTablinkNd.click();
|
48
|
+
}
|
@@ -0,0 +1,203 @@
|
|
1
|
+
:css
|
2
|
+
body { font-family: 'Source Sans Pro', sans-serif; }
|
3
|
+
#container { max-width: 1170px; margin: auto;}
|
4
|
+
h1 {
|
5
|
+
color: #ff7726;
|
6
|
+
font-size: 48px;
|
7
|
+
font-weight: 600;
|
8
|
+
line-height: 18px;
|
9
|
+
text-align: left;
|
10
|
+
margin: 73px 0 24px 0;
|
11
|
+
}
|
12
|
+
#details {
|
13
|
+
color: #4e4e4e;
|
14
|
+
margin: 0 0 60px 0;
|
15
|
+
font-size: 18px;
|
16
|
+
line-height: 18px;
|
17
|
+
}
|
18
|
+
.no-results-info {
|
19
|
+
text-align: center;
|
20
|
+
font-size: 28pt;
|
21
|
+
color: grey;
|
22
|
+
margin-top: 80px;
|
23
|
+
}
|
24
|
+
#results { margin-right: 34px; }
|
25
|
+
input[type=checkbox], input[type=checkbox] + ol > li { display: none; }
|
26
|
+
input[type=checkbox]:checked + ol > li { display: block; }
|
27
|
+
ol, li { position: relative; }
|
28
|
+
ol { margin: 0; padding: 0 0 0 34px; }
|
29
|
+
ol#collapsible { padding: 0; }
|
30
|
+
ol::before {
|
31
|
+
content: "▶";
|
32
|
+
position: absolute;
|
33
|
+
top: -33px; left: 15px;
|
34
|
+
font-size: 10px;
|
35
|
+
color: #ff7726;
|
36
|
+
}
|
37
|
+
ol#collapsible::before { display: none; }
|
38
|
+
input[type=checkbox]:checked + ol::before { content: "▼"; }
|
39
|
+
li { list-style: none; }
|
40
|
+
label { cursor: pointer; }
|
41
|
+
label, .success, .failure {
|
42
|
+
padding: 13.5px 0 13.5px 34px;
|
43
|
+
width: auto;
|
44
|
+
display: block;
|
45
|
+
background: #f6f6f6;
|
46
|
+
border-bottom: 3px #fff solid;
|
47
|
+
color: #4e4e4e;
|
48
|
+
letter-spacing: -0.32px;
|
49
|
+
line-height: 18px;
|
50
|
+
}
|
51
|
+
.time, .failures-count {
|
52
|
+
float: right;
|
53
|
+
width: 90px;
|
54
|
+
}
|
55
|
+
.failures-count { color: #a80000; }
|
56
|
+
.success {
|
57
|
+
background: #ccffcc;
|
58
|
+
color: #005e37;
|
59
|
+
padding: 8.5px 0 8.5px 34px;
|
60
|
+
font-weight: 400;
|
61
|
+
}
|
62
|
+
.failure {
|
63
|
+
background: #ffcfcf;
|
64
|
+
color: #a80000;
|
65
|
+
}
|
66
|
+
.failure-message, .failure-details {
|
67
|
+
clear: both;
|
68
|
+
display: block;
|
69
|
+
font-size: 14px;
|
70
|
+
letter-spacing: -0.28px;
|
71
|
+
margin-right: 34px;
|
72
|
+
}
|
73
|
+
#build-logs-id {
|
74
|
+
margin-right: 34px;
|
75
|
+
padding-top: 80px;
|
76
|
+
}
|
77
|
+
#build-logs-id .build-log-success:before {
|
78
|
+
content:'✓';
|
79
|
+
font-weight: bold;
|
80
|
+
display:inline-block;
|
81
|
+
vertical-align: top;
|
82
|
+
line-height: 1em;
|
83
|
+
width: 1em;
|
84
|
+
height:1em;
|
85
|
+
margin-right: 0.3em;
|
86
|
+
text-align: center;
|
87
|
+
color: #FFF;
|
88
|
+
background-color: green;
|
89
|
+
-moz-border-radius: 0.5em;
|
90
|
+
-webkit-border-radius: 0.5em;
|
91
|
+
border-radius: 0.5em;
|
92
|
+
margin-top: 2px;
|
93
|
+
}
|
94
|
+
#build-logs-id .build-log-error:before {
|
95
|
+
content:'✗';
|
96
|
+
font-weight: bold;
|
97
|
+
display:inline-block;
|
98
|
+
line-height: 1em;
|
99
|
+
vertical-align: top;
|
100
|
+
width: 1em;
|
101
|
+
height:1em;
|
102
|
+
margin-right: 0.3em;
|
103
|
+
text-align: center;
|
104
|
+
color: #FFF;
|
105
|
+
background-color: red;
|
106
|
+
-moz-border-radius: 0.5em;
|
107
|
+
-webkit-border-radius: 0.5em;
|
108
|
+
border-radius: 0.5em;
|
109
|
+
margin-top: 2px;
|
110
|
+
}
|
111
|
+
.error-text {
|
112
|
+
color: red;
|
113
|
+
font-size: 14px;
|
114
|
+
}
|
115
|
+
#build-logs-id .path {
|
116
|
+
color: #737373;
|
117
|
+
font-family: Courier New;
|
118
|
+
font-size: 14px;
|
119
|
+
}
|
120
|
+
#build-logs-id .file {
|
121
|
+
font-size: 14px;
|
122
|
+
}
|
123
|
+
#footer {
|
124
|
+
color: #4e4e4e;
|
125
|
+
font-size: 14px;
|
126
|
+
margin-top: 40px;
|
127
|
+
}
|
128
|
+
.heart { color: #ff7726; }
|
129
|
+
#footer a { color: #ff7726; text-decoration: none; }
|
130
|
+
/* TABS styles - BEGIN ========================== */
|
131
|
+
ul.tab, ul.tab-nd {
|
132
|
+
list-style-type: none;
|
133
|
+
margin: 0;
|
134
|
+
padding: 0;
|
135
|
+
overflow: hidden;
|
136
|
+
}
|
137
|
+
/* Float the list items side by side */
|
138
|
+
ul.tab li, ul.tab-nd li {float: left;}
|
139
|
+
/* Style the links inside the list items */
|
140
|
+
ul.tab li a {
|
141
|
+
display: inline-block;
|
142
|
+
color: black;
|
143
|
+
text-align: center;
|
144
|
+
padding: 14px 35px;
|
145
|
+
text-decoration: none;
|
146
|
+
transition: 0.3s;
|
147
|
+
font-size: 17px;
|
148
|
+
font-weight: bold;
|
149
|
+
}
|
150
|
+
ul.tab-nd li a {
|
151
|
+
display: inline-block;
|
152
|
+
color: black;
|
153
|
+
text-align: center;
|
154
|
+
padding: 10px 30px;
|
155
|
+
text-decoration: none;
|
156
|
+
transition: 0.3s;
|
157
|
+
font-size: 17px;
|
158
|
+
font-weight: bold;
|
159
|
+
}
|
160
|
+
ul.tab-nd {
|
161
|
+
display: inline-block;
|
162
|
+
position: relative;
|
163
|
+
left: -13px;
|
164
|
+
}
|
165
|
+
/* Create an active/current tablink class */
|
166
|
+
ul.tab li a:focus, ul.tab li a.active, ul.tab li a:hover {
|
167
|
+
background-color: #FF7726;
|
168
|
+
color: #FFF;
|
169
|
+
}
|
170
|
+
ul.tab-nd li a:focus, ul.tab-nd li a.active, ul.tab-nd li a:hover {
|
171
|
+
border-width: 1px 1px 0 1px;
|
172
|
+
}
|
173
|
+
ul.tab-nd li a:hover {
|
174
|
+
background-color: #FF7726;
|
175
|
+
color: #FFF;
|
176
|
+
}
|
177
|
+
ul.tab-nd li a {
|
178
|
+
background-color: #FFF;
|
179
|
+
color: black;
|
180
|
+
border-color: #FF7726;
|
181
|
+
border-width: 0 0 1px 0;
|
182
|
+
border-style: solid;
|
183
|
+
}
|
184
|
+
/* Style the tab content */
|
185
|
+
.tabcontent {
|
186
|
+
display: none;
|
187
|
+
padding: 6px 12px;
|
188
|
+
border-top: none;
|
189
|
+
}
|
190
|
+
.tests-tabs {
|
191
|
+
top: 50px;
|
192
|
+
}
|
193
|
+
/* TABS styles - END ===================== */
|
194
|
+
|
195
|
+
.link {
|
196
|
+
text-decoration : none;
|
197
|
+
color:inherit;
|
198
|
+
}
|
199
|
+
|
200
|
+
.screenshot-thumb {
|
201
|
+
height:100px;
|
202
|
+
width:auto;
|
203
|
+
}
|
@@ -0,0 +1,101 @@
|
|
1
|
+
:css
|
2
|
+
/*** Table Styles **/
|
3
|
+
#test-logs .table-fill {
|
4
|
+
background: white;
|
5
|
+
border-radius:3px;
|
6
|
+
border-collapse: collapse;
|
7
|
+
margin: auto;
|
8
|
+
padding:0px;
|
9
|
+
width: 100%;
|
10
|
+
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
|
11
|
+
animation: float 5s infinite;
|
12
|
+
}
|
13
|
+
#test-logs th {
|
14
|
+
color: #FFFFFF;
|
15
|
+
background: #FF7726;
|
16
|
+
border-bottom:1px solid #ff7e33;
|
17
|
+
border-right: 1px solid #ff7e33;
|
18
|
+
font-size:16px;
|
19
|
+
font-weight: 900;
|
20
|
+
padding:6px;
|
21
|
+
text-align:left;
|
22
|
+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
|
23
|
+
vertical-align:middle;
|
24
|
+
}
|
25
|
+
|
26
|
+
#test-logs th:first-child {
|
27
|
+
border-top-left-radius:3px;
|
28
|
+
}
|
29
|
+
|
30
|
+
#test-logs th:last-child {
|
31
|
+
border-top-right-radius:3px;
|
32
|
+
border-right:none;
|
33
|
+
}
|
34
|
+
|
35
|
+
#test-logs tr {
|
36
|
+
border-top: 1px solid #C1C3D1;
|
37
|
+
border-bottom-: 1px solid #C1C3D1;
|
38
|
+
color:#666B85;
|
39
|
+
font-size:16px;
|
40
|
+
font-weight:normal;
|
41
|
+
text-shadow: 0 1px 1px rgba(256, 256, 256, 0.1);
|
42
|
+
}
|
43
|
+
|
44
|
+
#test-logs tr:first-child {
|
45
|
+
border-top:none;
|
46
|
+
}
|
47
|
+
|
48
|
+
#test-logs tr:last-child {
|
49
|
+
border-bottom:none;
|
50
|
+
}
|
51
|
+
|
52
|
+
#test-logs tr:nth-child(odd) td {
|
53
|
+
background:#ffefe6;
|
54
|
+
}
|
55
|
+
|
56
|
+
#test-logs tr:last-child td:first-child {
|
57
|
+
border-bottom-left-radius:3px;
|
58
|
+
}
|
59
|
+
|
60
|
+
#test-logs tr:last-child td:last-child {
|
61
|
+
border-bottom-right-radius:3px;
|
62
|
+
}
|
63
|
+
|
64
|
+
#test-logs td {
|
65
|
+
background:#FFFFFF;
|
66
|
+
padding:4px 6px;
|
67
|
+
text-align:left;
|
68
|
+
vertical-align:middle;
|
69
|
+
font-weight:300;
|
70
|
+
font-size:16px;
|
71
|
+
text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
|
72
|
+
border-right: 1px solid #C1C3D1;
|
73
|
+
}
|
74
|
+
|
75
|
+
#test-logs td:last-child {
|
76
|
+
border-right: 0px;
|
77
|
+
}
|
78
|
+
|
79
|
+
#test-logs th.text-left {
|
80
|
+
text-align: left;
|
81
|
+
}
|
82
|
+
|
83
|
+
#test-logs th.text-center {
|
84
|
+
text-align: center;
|
85
|
+
}
|
86
|
+
|
87
|
+
#test-logs th.text-right {
|
88
|
+
text-align: right;
|
89
|
+
}
|
90
|
+
|
91
|
+
#test-logs td.text-left {
|
92
|
+
text-align: left;
|
93
|
+
}
|
94
|
+
|
95
|
+
#test-logs td.text-center {
|
96
|
+
text-align: center;
|
97
|
+
}
|
98
|
+
|
99
|
+
#test-logs td.text-right {
|
100
|
+
text-align: right;
|
101
|
+
}
|