Skip to content

Commit

Permalink
Adding example tags and scenarios counts
Browse files Browse the repository at this point in the history
  • Loading branch information
elhuang committed Sep 29, 2017
1 parent 93bbb31 commit c6dd84a
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 32 deletions.
10 changes: 8 additions & 2 deletions example/scenario_outline.feature
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@scenario_outlines @bvt
@scenario_outlines @bvt @duplicate
Feature: Displaying Scenario Outlines
As a reader of the documentation I expect that scenario outlines are documented correctly

Expand All @@ -9,6 +9,7 @@ Feature: Displaying Scenario Outlines
When the customer has purchased the product
Then I expect the customer to be a member of the '<Product>' group

@tagged_examples
Examples:
| Customer | Product |
| Customer A | Product A |
Expand Down Expand Up @@ -61,6 +62,7 @@ Feature: Displaying Scenario Outlines

# This is an example of a scenario outline in development.
# The example table has not been defined yet
@fifth
Scenario Outline: Example Table Missing
When I click on an example row
Then I expect <name> to be replaced by the example name
Expand All @@ -70,6 +72,7 @@ Feature: Displaying Scenario Outlines

# This is an example of a scenario outline in development.
# The examples table has been defined, but is missing data.
@sixth
Scenario Outline: Empty Example Table
When I click on an example row
Then I expect <name> to be replaced by the example name
Expand All @@ -79,16 +82,19 @@ Feature: Displaying Scenario Outlines
Examples:
| name | price | denomination |

@seventh @duplicate
Scenario Outline: Multiple Example Table
Given that <Customer> is a valid customer
And that the product, named '<Product>', is a valid product
When the customer has purchased the product
Then I expect the customer to be a member of the '<Product>' group

@groupA @duplicate
Examples: Example group A
| Customer | Product |
| Customer A | Product A |

@groupB
Examples: Example group B
| Customer | Product |
| Customer B | Product A |
| Customer B | Product A |
66 changes: 57 additions & 9 deletions lib/cucumber/city_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def find_or_create_namespace(file)
def find_or_create_tag(tag_name,parent)
#log.debug "Processing tag #{tag_name}"
tag_code_object = YARD::Registry.all(:tag).find {|tag| tag.value == tag_name } ||
YARD::CodeObjects::Cucumber::Tag.new(YARD::CodeObjects::Cucumber::CUCUMBER_TAG_NAMESPACE,tag_name.gsub('@','')) {|t| t.owners = [] ; t.value = tag_name }
YARD::CodeObjects::Cucumber::Tag.new(YARD::CodeObjects::Cucumber::CUCUMBER_TAG_NAMESPACE,tag_name.gsub('@','')) {|t| t.owners = [] ; t.value = tag_name ; t.total_scenarios = 0}

tag_code_object.add_file(@file,parent.line)

Expand Down Expand Up @@ -108,11 +108,19 @@ def feature(document)
when :Background
background(s)
when :ScenarioOutline
scenario_outline(s)
outline = scenario_outline(s)
@feature.total_scenarios += outline.scenarios.size
when :Scenario
scenario(s)
@feature.total_scenarios += 1
end
}
}

@feature.tags.each { |feature_tag|
tag_code_object = YARD::Registry.all(:tag).find {|tag| tag.name.to_s == feature_tag[:name].to_s }
tag_code_object.total_scenarios += @feature.total_scenarios
}

end

#
Expand Down Expand Up @@ -172,6 +180,14 @@ def scenario(statement)
statement[:steps].each { |s|
step(s)
}

# count scenarios for scenario level tags
scenario.tags.uniq.each { |scenario_tag|
if !scenario.feature.tags.include?(scenario_tag)
tag_code_object = YARD::Registry.all(:tag).find {|tag| tag.name.to_s == scenario_tag[:name].to_s }
tag_code_object.total_scenarios += 1
end
}
end

#
Expand All @@ -197,32 +213,63 @@ def scenario_outline(statement)
end

outline.feature = @feature
@feature.scenarios << outline
@step_container = outline
statement[:steps].each { |s|
step(s)
}

statement[:examples].each { |e|
examples(e)
example = examples(e, outline)
}

@feature.scenarios << outline

# count scenarios for scenario outline level tags
outline.tags.uniq.each { |outline_tag|
if !outline.feature.tags.include?(outline_tag)
tag_code_object = YARD::Registry.all(:tag).find {|tag| tag.name.to_s == outline_tag[:name].to_s }
tag_code_object.total_scenarios += outline.scenarios.size
end
}

# count scenarios for example table level tags
outline.examples.each { |example|
unless !example.tags.any?
example.tags.uniq.each { |example_tag|
if !outline.feature.tags.include?(example_tag) && !outline.tags.include?(example_tag)
tag_code_object = YARD::Registry.all(:tag).find {|tag| tag.name.to_s == example_tag[:name].to_s }
tag_code_object.total_scenarios += example.data.size
end
}
end
}

return outline
end


#
# Examples for a scenario outline are called here. This section differs
# from the Cucumber parser because here each of the examples are exploded
# out here as individual scenarios and step definitions. This is so that
# later we can ensure that we have all the variations of the scenario
# outline defined to be displayed.
#
def examples(examples)
def examples(examples, outline)
#log.debug "EXAMPLES"

return if has_exclude_tags?(examples[:tags].map { |t| t[:name].gsub(/^@/, '') })
example = YARD::CodeObjects::Cucumber::ScenarioOutline::Examples.new(:keyword => examples[:keyword],
:name => examples[:name],
:line => examples[:location][:line],
:comments => examples[:comments] ? examples.comments.map{|comment| comment.value}.join("\n") : '',
:rows => []
)
:rows => [],
:tags => [],
:scenario => outline )

unless !examples[:tags].any?
examples[:tags].each {|example_tag| find_or_create_tag(example_tag[:name], example)}
end

example.rows = [examples[:tableHeader][:cells].map{ |c| c[:value] }] if examples[:tableHeader]
example.rows += matrix(examples[:tableBody]) if examples[:tableBody]

Expand Down Expand Up @@ -282,6 +329,7 @@ def examples(examples)

end

return example
end

#
Expand Down
36 changes: 32 additions & 4 deletions lib/templates/default/featuretags/html/namespace.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<% if @namespace %>
<% count = 0 %>
<% features.each {|f| count += f.total_scenarios } %>

<div id="tags" class="requirements">
<script type="text/javascript" charset="utf-8">
var tag_list = [ <%= tags.collect{|t| "'#{t.value}'" }.join(',') %> ];
Expand All @@ -18,11 +21,13 @@

$("#tag_search").keyup(function(evt) {
updateTagFiltering($("#tag_search")[0].value);
updateScenarioCount();
});


$("#tag_search").keyup(function(evt) {
updateTagFiltering($("#tag_search")[0].value);
updateScenarioCount();
});

$(".tag").click(function(evt) {
Expand Down Expand Up @@ -50,6 +55,7 @@

tagSearchElement.value = (tagSearchElement.value != "" ? tagSearchElement.value + tagModifier : "") + tagToAdd;
updateTagFiltering(tagSearchElement.value);
updateScenarioCount();

}
});
Expand Down Expand Up @@ -89,7 +95,7 @@

<div id="features">
<div class="title">
<span class="name">Features</span>
<span class="name">Features<span id="scenario_count"> (<%= count %>)</span></span>
</div>
<% n = 1 %>
<ul style="padding-left: 0px;">
Expand All @@ -105,9 +111,9 @@
<% if feature.scenarios %>
<ul style="padding-left: 20px;">
<% feature.scenarios.each do |scenario| %>
<li class="scenario <%= n % 2 == 0 ? 'even' : 'odd' %> <%= feature.tags.collect{|t| t.value }.join(" ") %> <%= scenario.tags.collect{|t| t.value }.join(" ") %>">
<li class="scenario <%= n % 2 == 0 ? 'even' : 'odd' %> <%= feature.tags.collect{|t| t.value }.join(" ") %> <%= scenario.tags.collect{|t| t.value }.join(" ") %>" count="<%= scenario.outline? ? 0 : 1 %>">
<span class='object_link'>
<a href="<%= url_for(scenario.feature,"scenario#{scenario.feature.scenarios.index(scenario) }") %>">
<a href="<%= url_for(scenario.feature,"scenario_#{scenario.feature.scenarios.index(scenario) }") %>">
<%= h scenario.value %>
</a>
</span>
Expand All @@ -116,8 +122,30 @@
- <small><%= stags %></small>
<% end %>
</li>

<% n = n == 2 ? 1 : 2 %>
<% end %>

<% if scenario.outline? %>
<ul style="padding-left: 40px;">
<% scenario.examples.each do |example| %>
<li class="scenario <%= n % 2 == 0 ? 'even' : 'odd' %> <%= feature.tags.collect{|t| t.value }.join(" ") %> <%= scenario.tags.collect{|t| t.value }.join(" ") %> <%= example.tags.collect{|t| t.value }.join(" ") %>" count="<%= example.data.size %>">

<span class='object_link'>
<a href="<%= url_for(scenario.feature,"scenario_#{scenario.feature.scenarios.index(scenario) }") %>">
<%= example.name.nil? || example.name.empty? ? "Examples" : example.name %>
</a>
</span>

<% etags = example.tags.collect{|t| tagify(t) }.join(", ") %>
<% if etags && etags != "" %>
- <small><%= etags %></small>
<% end %>
</li>
<% n = n == 2 ? 1 : 2 %>
<% end %>
</ul>
<% end %>
<% end %>
</ul>
<% end %>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion lib/templates/default/fulldoc/html/full_list_features.erb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<div class="item" style="padding-left: 30px">
<%= "<a class='toggle'></a>" unless feature.scenarios.empty? %>
<%= linkify feature, feature.value %>
<small><%= feature.location %></small>
<small style="display: inline;"><%= feature.total_scenarios %></small>
</div>

<% n = n == 'odd' ? 'even' : 'odd' %>
Expand Down
2 changes: 1 addition & 1 deletion lib/templates/default/fulldoc/html/full_list_tags.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<li class="<%= n %>">
<div class="item" style="padding-left: 30px;">
<%= linkify tag, tag.value %>
<small style="display: inline;"><%= tag.all_scenarios.size %></small>
<small style="display: inline;"><%= tag.total_scenarios %></small>
</div>
</li>
<% n = n == 'odd' ? 'even' : 'odd' %>
Expand Down
9 changes: 9 additions & 0 deletions lib/templates/default/fulldoc/html/js/cucumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ function displayQualifyingFeaturesAndScenarios(tags) {

}

function updateScenarioCount() {
var count = 0;
$(".scenario:visible").each(function(index) {
count += parseInt($(this).attr("count"))
});
count_header = " (" + count + ")";
document.getElementById("scenario_count").innerHTML = count_header;
}

function generateCssSelectorFromTags(tagGroups) {

var tagSelectors = [ "" ];
Expand Down
30 changes: 26 additions & 4 deletions lib/templates/default/fulldoc/html/setup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def serialize_feature_directories_recursively(namespaces)
end
end


# Generate feature list
# @note this method is called automatically by YARD based on the menus defined in the layout
def generate_feature_list
Expand All @@ -82,11 +81,32 @@ def generate_feature_list
generate_full_list features_ordered_by_name, :features
end

# Count scenarios for features
def record_feature_scenarios(features)
count_with_examples = 0
features.each do |f|
count_with_examples += f.total_scenarios
end
return count_with_examples
end

# Count scenarios for tags
def record_tagged_scenarios(tags)
scenario_count = 0
count_with_examples = 0
tags.each do |t|
scenario_count += t.all_scenarios.size
count_with_examples += t.total_scenarios
end
end

# Generate tag list
# @note this method is called automatically by YARD based on the menus defined in the layout
def generate_tag_list
tags = Registry.all(:tag)
tags_ordered_by_use = Array(tags).sort {|x,y| y.all_scenarios.size <=> x.all_scenarios.size }
tags_ordered_by_use = Array(tags).sort {|x,y| y.total_scenarios <=> x.total_scenarios }

record_tagged_scenarios(tags)

generate_full_list tags_ordered_by_use, :tags
end
Expand Down Expand Up @@ -162,10 +182,12 @@ def class_list(root = Registry.root, tree = TreeContext.new)
# When there are is just one feature directory then we want to link to that directory
#
def all_features_link
features = Registry.all(:feature)
count_with_examples = record_feature_scenarios(features)
if root_feature_directories.length == 0 || root_feature_directories.length > 1
linkify YARD::CodeObjects::Cucumber::CUCUMBER_NAMESPACE, "All Features"
linkify YARD::CodeObjects::Cucumber::CUCUMBER_NAMESPACE, "All Features (#{count_with_examples})"
else
linkify root_feature_directories.first, "All Features"
linkify root_feature_directories.first, "All Features (#{count_with_examples})"
end
end

Expand Down
3 changes: 2 additions & 1 deletion lib/templates/default/tag/html/alpha_table.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
<% objects.each do |obj| %>
<li>
<% if obj.is_a?(YARD::CodeObjects::Cucumber::Scenario) || obj.is_a?(YARD::CodeObjects::Cucumber::ScenarioOutline) %>
<a href="<%= url_for(obj.feature,"scenario_#{obj.path[(/.+_(\d+)$/),1]}") %>">
<% index = obj.path[(/.+_(\d+)$/),1].to_i - 1 %>
<a href="<%= url_for(obj.feature,"scenario_#{index}") %>">
<%= h obj.value %>
</a>
<% else %>
Expand Down
5 changes: 3 additions & 2 deletions lib/yard/code_objects/cucumber/feature.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ module YARD::CodeObjects::Cucumber

class Feature < NamespaceObject

attr_accessor :background, :comments, :description, :keyword, :scenarios, :tags, :value
attr_accessor :background, :comments, :description, :keyword, :scenarios, :tags, :value, :total_scenarios

def initialize(namespace,name)
@comments = ""
@scenarios = []
@tags = []
@total_scenarios = 0
super(namespace,name.to_s.strip)
end

end

end
end
Loading

0 comments on commit c6dd84a

Please sign in to comment.