nuker 0.0.47 → 1.0.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/.gitignore +7 -0
- data/.ruby-version +1 -0
- data/.rvmrc +62 -0
- data/.rvmrc.08.13.2014-14:58:37 +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE +165 -0
- data/Rakefile +5 -0
- data/bin/nuker +26 -0
- data/config.ru +2 -0
- data/example-features/generic/example-with-background.feature +11 -0
- data/example-features/generic/example-with-data-table.feature +7 -0
- data/example-features/generic/example-with-scenario-outline-examples.feature +11 -0
- data/example-features/generic/example_with_tags.feature +8 -0
- data/example-features/generic/has-lots-of-tags.feature +5 -0
- data/example-features/generic/multiple-scenarios.feature +7 -0
- data/example-features/too-many-wip-tags/too-many-wip-tags.feature +21 -0
- data/features/counts.feature +25 -0
- data/features/feature_page.feature +69 -0
- data/features/list_tags.feature +31 -0
- data/features/notifications.feature +9 -0
- data/features/progress_bar.feature +21 -0
- data/features/project_home.feature +25 -0
- data/features/projects.feature +19 -0
- data/features/push_features.feature +34 -0
- data/features/scenario_page.feature +84 -0
- data/features/search_features.feature +100 -0
- data/features/step_definitions/feature_page_steps.rb +15 -0
- data/features/step_definitions/notifications_steps.rb +11 -0
- data/features/step_definitions/project_home_steps.rb +10 -0
- data/features/step_definitions/projects_steps.rb +28 -0
- data/features/step_definitions/push_features_steps.rb +48 -0
- data/features/step_definitions/scenario_page_steps.rb +29 -0
- data/features/step_definitions/search_features_steps.rb +24 -0
- data/features/step_definitions/steps.rb +35 -0
- data/features/step_definitions/welcome_page.rb +19 -0
- data/features/support/env.rb +33 -0
- data/features/welcome_page.feature +30 -0
- data/lib/nuker/application.rb +161 -0
- data/lib/nuker/counts_tags.rb +27 -0
- data/lib/nuker/feature.rb +16 -0
- data/lib/nuker/parses_features.rb +30 -0
- data/lib/nuker/project.rb +8 -0
- data/lib/nuker/public/bootstrap.min.css +356 -0
- data/lib/nuker/public/nuker-logo.png +0 -0
- data/lib/nuker/public/scripts/projects.js +6 -0
- data/lib/nuker/public/skin.css +208 -0
- data/lib/nuker/public/wally-logo.png +0 -0
- data/lib/nuker/search_features.rb +47 -0
- data/lib/nuker/version.rb +3 -0
- data/lib/nuker/views/feature.haml +19 -0
- data/lib/nuker/views/feature_link.haml +6 -0
- data/lib/nuker/views/layout.haml +53 -0
- data/lib/nuker/views/progress.haml +15 -0
- data/lib/nuker/views/project.haml +0 -0
- data/lib/nuker/views/scenario.haml +31 -0
- data/lib/nuker/views/search.haml +36 -0
- data/lib/nuker/views/table.haml +10 -0
- data/lib/nuker/views/tag_links.haml +4 -0
- data/lib/nuker.rb +7 -0
- data/nuker.gemspec +37 -0
- data/spec/spec_helper.rb +35 -0
- metadata +88 -3
@@ -0,0 +1,84 @@
|
|
1
|
+
Feature: Scenario Page
|
2
|
+
In order to view a scenario's intent
|
3
|
+
As a stakeholder
|
4
|
+
I want a page that displays each scenario and its steps
|
5
|
+
|
6
|
+
Scenario: Content
|
7
|
+
Given a feature file named "sample.feature" with the contents:
|
8
|
+
"""
|
9
|
+
Feature: Sample Feature
|
10
|
+
|
11
|
+
@tag1 @tag2
|
12
|
+
Scenario: Sample Aidy
|
13
|
+
Given my name is "Aidy"
|
14
|
+
When I drink alcohol
|
15
|
+
Then I go nuts
|
16
|
+
"""
|
17
|
+
When I visit the sample feature page
|
18
|
+
And click on a scenario header link
|
19
|
+
Then a page appears with the scenario content
|
20
|
+
And I see "tag1"
|
21
|
+
And I see "tag2"
|
22
|
+
|
23
|
+
Scenario: Background
|
24
|
+
Given a feature file named "sample.feature" with the contents:
|
25
|
+
"""
|
26
|
+
Feature: Sample Feature
|
27
|
+
|
28
|
+
Background:
|
29
|
+
Given some things
|
30
|
+
|
31
|
+
Scenario: Sample Aidy
|
32
|
+
"""
|
33
|
+
When I visit the sample feature page
|
34
|
+
And click on a scenario header link
|
35
|
+
Then the background is visible
|
36
|
+
|
37
|
+
Scenario: Tags
|
38
|
+
Given a feature file named "sample.feature" with the contents:
|
39
|
+
"""
|
40
|
+
Feature: Sample Feature
|
41
|
+
|
42
|
+
Background:
|
43
|
+
Given some things
|
44
|
+
|
45
|
+
@work_in_progress
|
46
|
+
Scenario: Sample Aidy
|
47
|
+
"""
|
48
|
+
When I visit the sample feature page
|
49
|
+
And click on a scenario header link
|
50
|
+
Then I see "work_in_progress"
|
51
|
+
|
52
|
+
Scenario: Data Table
|
53
|
+
Given a feature file named "sample.feature" with the contents:
|
54
|
+
"""
|
55
|
+
Feature: Sample Feature
|
56
|
+
|
57
|
+
Scenario: Data Table
|
58
|
+
Given the following people exist:
|
59
|
+
| name | email |
|
60
|
+
| Aidy | aidy@example.com |
|
61
|
+
| Andrew | vos@example.com |
|
62
|
+
"""
|
63
|
+
When I visit the sample feature page
|
64
|
+
And click on a scenario header link
|
65
|
+
Then I see the data table
|
66
|
+
|
67
|
+
Scenario: Scenario Outline
|
68
|
+
Given a feature file named "sample.feature" with the contents:
|
69
|
+
"""
|
70
|
+
Feature: Sample Feature
|
71
|
+
|
72
|
+
Scenario Outline: Outline with examples
|
73
|
+
Given there are <start> cucumbers
|
74
|
+
When I eat <eat> cucumbers
|
75
|
+
Then I have <left> cucumbers
|
76
|
+
|
77
|
+
Examples:
|
78
|
+
| start | eat | left |
|
79
|
+
| 12 | 5 | 7 |
|
80
|
+
| 20 | 5 | 15 |
|
81
|
+
"""
|
82
|
+
When I visit the sample feature page
|
83
|
+
And click on a scenario header link
|
84
|
+
Then I see the examples table
|
@@ -0,0 +1,100 @@
|
|
1
|
+
Feature: Search features
|
2
|
+
In order to have fast access to features and scenarios
|
3
|
+
As a stakeholder
|
4
|
+
I want to be able to search features
|
5
|
+
|
6
|
+
Scenario Outline: Search feature name
|
7
|
+
Given a feature file named "sample.feature" with the contents:
|
8
|
+
"""
|
9
|
+
@QA
|
10
|
+
Feature: Sample Feature
|
11
|
+
"""
|
12
|
+
And I am on the search page
|
13
|
+
When I search for "<query>"
|
14
|
+
Then I see a search result link to "<feature name>" with the url "<url>"
|
15
|
+
|
16
|
+
Examples:
|
17
|
+
| query | feature name | url |
|
18
|
+
| Sample | Sample Feature |/projects/project/features/sample-feature |
|
19
|
+
| sAmPlE | Sample Feature |/projects/project/features/sample-feature |
|
20
|
+
| @QA | Sample Feature |/projects/project/features/sample-feature |
|
21
|
+
|
22
|
+
Scenario: Search feature narrative
|
23
|
+
Given a feature file named "sample.feature" with the contents:
|
24
|
+
"""
|
25
|
+
Feature: Sample Feature
|
26
|
+
In order to bla bla bla
|
27
|
+
As donkey
|
28
|
+
I want ermm I dunno.
|
29
|
+
"""
|
30
|
+
And I am on the search page
|
31
|
+
When I search for "donkey"
|
32
|
+
Then I see a search result link to "Sample Feature" with the url "/projects/project/features/sample-feature"
|
33
|
+
|
34
|
+
Scenario: Search scenario name
|
35
|
+
Given a feature file named "sample.feature" with the contents:
|
36
|
+
"""
|
37
|
+
Feature: Sample Feature
|
38
|
+
Scenario: Sample Scenario
|
39
|
+
"""
|
40
|
+
And I am on the search page
|
41
|
+
When I search for "Sample Scenario"
|
42
|
+
Then I see a search result link to "Sample Scenario" with the url "/projects/project/features/sample-feature/scenario/sample-scenario"
|
43
|
+
|
44
|
+
Scenario: Search scenario steps
|
45
|
+
Given a feature file named "sample.feature" with the contents:
|
46
|
+
"""
|
47
|
+
Feature: Sample Feature
|
48
|
+
Scenario: Sample Scenario
|
49
|
+
Given I do something
|
50
|
+
"""
|
51
|
+
And I am on the search page
|
52
|
+
When I search for "I do something"
|
53
|
+
Then I see a search result link to "Sample Scenario" with the url "/projects/project/features/sample-feature/scenario/sample-scenario"
|
54
|
+
|
55
|
+
Scenario: Search suggests other searches
|
56
|
+
Given a feature file named "sample.feature" with the contents:
|
57
|
+
"""
|
58
|
+
Feature: Batman
|
59
|
+
"""
|
60
|
+
And I am on the search page
|
61
|
+
When I search for "btman"
|
62
|
+
Then I see "Did you mean"
|
63
|
+
And I see a search result link to "Batman" with the url "/projects/project/search?q=Batman"
|
64
|
+
|
65
|
+
Scenario: Search displays tags
|
66
|
+
Given a feature file named "sample.feature" with the contents:
|
67
|
+
"""
|
68
|
+
@feature_tag
|
69
|
+
Feature: Batman
|
70
|
+
|
71
|
+
@scenario_tag
|
72
|
+
Scenario: Batman?
|
73
|
+
"""
|
74
|
+
And I am on the search page
|
75
|
+
When I search for "Batman"
|
76
|
+
Then I see "feature_tag" in the search results
|
77
|
+
And I see "scenario_tag" in the search results
|
78
|
+
|
79
|
+
Scenario: Highlighted search result with multiple matches
|
80
|
+
Given a feature file named "sample1.feature" with the contents:
|
81
|
+
"""
|
82
|
+
@feature_tag
|
83
|
+
Feature: Some <long WORD feature word name
|
84
|
+
Scenario: Some <long WORD scenario word name
|
85
|
+
Given I have a word
|
86
|
+
"""
|
87
|
+
And I am on the search page
|
88
|
+
When I search for "word"
|
89
|
+
Then I see the html:
|
90
|
+
"""
|
91
|
+
Some <long <span class="search-result">WORD</span> feature <span class="search-result">word</span> name
|
92
|
+
"""
|
93
|
+
And I see the html:
|
94
|
+
"""
|
95
|
+
Some <long <span class="search-result">WORD</span> scenario <span class="search-result">word</span> name
|
96
|
+
"""
|
97
|
+
And I see the html:
|
98
|
+
"""
|
99
|
+
I have a <span class="search-result">word</span>
|
100
|
+
"""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Then /^I see the feature free\-form narrative$/ do
|
2
|
+
page.should have_content "In order to get some value"
|
3
|
+
page.should have_content "As a person"
|
4
|
+
page.should have_content "I want to create value"
|
5
|
+
end
|
6
|
+
|
7
|
+
Then /^I see Scenario headers as links$/ do
|
8
|
+
page.body.should have_content "Scenarios"
|
9
|
+
page.should have_link "Sample Aidy", :href => "/projects/project/features/sample-feature/scenario/sample-aidy"
|
10
|
+
page.should have_link "Sample Andrew", :href => "/projects/project/features/sample-feature/scenario/sample-andrew"
|
11
|
+
end
|
12
|
+
|
13
|
+
Then /^the scenario links are sorted$/ do
|
14
|
+
page.body.should =~ /C.*I.*N.*V/m
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Given /^a feature file with (\d+) @wip tags$/ do |wip_tag_count|
|
2
|
+
contents = "Feature: Feature 1\n"
|
3
|
+
1.upto(wip_tag_count.to_i) do |number|
|
4
|
+
contents += "@wip\nScenario: Scenario #{number}\n"
|
5
|
+
end
|
6
|
+
create_feature("project", "sample1.feature", contents)
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^I see a notification that says "([^"]*)"$/ do |text|
|
10
|
+
page.should have_content text
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Then /^I see a link to my sample features$/ do
|
2
|
+
page.should have_link "Kate Moss", :href => "/projects/project/features/kate-moss"
|
3
|
+
page.should have_link "Katie Price", :href => "/projects/project/features/katie-price"
|
4
|
+
page.should have_link "Jessica-Jane Clement", :href => "/projects/project/features/jessica-jane-clement"
|
5
|
+
page.should have_link "Elle Macpherson", :href => "/projects/project/features/elle-macpherson"
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^the features are ordered alphabetically$/ do
|
9
|
+
page.body.should =~ /Elle Macpherson.*Jessica-Jane Clement.*Kate Moss.*Katie Price/m
|
10
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Given /^a feature file on the project "([^"]*)" with the contents:$/ do |project, contents|
|
2
|
+
create_feature(project, "feature1.feature", contents)
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^I visit the project page for "([^"]*)"$/ do |project|
|
6
|
+
visit "/projects/#{project}"
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^(\d+) projects exist$/ do |number_of_projects|
|
10
|
+
number_of_projects.to_i.times do |project_number|
|
11
|
+
project(project_number + 1)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Then /^I see a link to the feature "([^"]*)"$/ do |feature|
|
16
|
+
page.should have_link feature
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^I can switch to the (\d).+ project$/ do |project_number|
|
20
|
+
select project_number, :from => 'projects'
|
21
|
+
|
22
|
+
#This is needed because there seems to be a bug in the chrome driver.
|
23
|
+
#The first time this is called, we get the old url, and the second time we get the new url.
|
24
|
+
page.current_url
|
25
|
+
|
26
|
+
page.current_url.end_with?(project_number).should be_true
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
After do
|
2
|
+
File.delete ".nuker" if File.exist? ".wally"
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^I don't have a \.nuker authorisation file$/ do
|
6
|
+
end
|
7
|
+
|
8
|
+
Given /^I have a \.nuker authentication file$/ do
|
9
|
+
@authentication_code = "authCodE!!2322"
|
10
|
+
File.open(".nuker", "w") do |file|
|
11
|
+
file.write @authentication_code
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Then /^I get a (\d+) http status$/ do |status|
|
16
|
+
page.driver.status_code.should eql status.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
Then /^I see the uploaded feature$/ do
|
20
|
+
page.body.should have_content "Feature Name"
|
21
|
+
end
|
22
|
+
|
23
|
+
When /^I put data to \/my_project_name\/features with the authentication code$/ do
|
24
|
+
gherkin = Nuker::ParsesFeatures.new.parse("Feature: Feature Name")
|
25
|
+
data = [{:path => "feature-name.feature", :gherkin => gherkin}].to_json
|
26
|
+
page.driver.put "/projects/my_project_name/features?authentication_code=#{@authentication_code}", data
|
27
|
+
end
|
28
|
+
|
29
|
+
Given /^I create a project called "([^"]*)"$/ do |project_name|
|
30
|
+
project project_name
|
31
|
+
Nuker::Project.first(:name => project_name).class.should equal Nuker::Project
|
32
|
+
end
|
33
|
+
|
34
|
+
When /^I send DELETE to "([^"]*)"$/ do |project_path|
|
35
|
+
page.driver.delete "#{project_path}?authentication_code=#{@authentication_code}"
|
36
|
+
end
|
37
|
+
|
38
|
+
Then /^"([^"]*)" should exist$/ do |project_name|
|
39
|
+
Nuker::Project.first(:name => project_name).class.should equal Nuker::Project
|
40
|
+
end
|
41
|
+
|
42
|
+
Then /^"([^"]*)" should not exist$/ do |project_name|
|
43
|
+
Nuker::Project.first(:name => project_name).class.should_not equal Nuker::Project
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^I visit "([^"]*)" page$/ do |project_name|
|
47
|
+
visit "/projects/#{project_name}"
|
48
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
When /^click on a scenario header link$/ do
|
2
|
+
find('.scenarios a').click
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^a page appears with the scenario content$/ do
|
6
|
+
page.body.should have_content "Sample Aidy"
|
7
|
+
page.body.should have_content "Given my name is \"Aidy\""
|
8
|
+
page.body.should have_content "When I drink alcohol"
|
9
|
+
page.body.should have_content "Then I go nuts"
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^the background is visible$/ do
|
13
|
+
page.body.should have_content "Background:"
|
14
|
+
page.body.should have_content "Given some things"
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^I see the data table$/ do
|
18
|
+
text_for_all('th').should == ['name', 'email']
|
19
|
+
text_for_all('td').should == ['Aidy', 'aidy@example.com', 'Andrew', 'vos@example.com']
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^I see the examples table$/ do
|
23
|
+
text_for_all('th').should == ['start', 'eat', 'left']
|
24
|
+
text_for_all('td').should == ['12', '5', '7', '20', '5', '15']
|
25
|
+
end
|
26
|
+
|
27
|
+
def text_for_all tag
|
28
|
+
page.all(tag).collect { |heading| heading.text.strip }
|
29
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Given /^I am on the search page$/ do
|
2
|
+
visit "/projects/project/search"
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I search for "([^"]*)"$/ do |text|
|
6
|
+
fill_in 'q', :with => text
|
7
|
+
click_button 'Search'
|
8
|
+
end
|
9
|
+
|
10
|
+
Then /^I see a search result link to "([^"]*)" with the url "([^"]*)"$/ do |text, url|
|
11
|
+
within ".content" do
|
12
|
+
page.should have_link text, :href => url
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Then /^I see "([^"]*)" in the search results$/ do |text|
|
17
|
+
within ".content" do
|
18
|
+
page.should have_content text
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^I see the html:$/ do |html|
|
23
|
+
page.body.should include html
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Given /^a feature file named "([^"]*)" with the contents:$/ do |filename, contents|
|
2
|
+
@contents = contents
|
3
|
+
create_feature("project", filename, @contents)
|
4
|
+
end
|
5
|
+
|
6
|
+
When /^I visit the project page$/ do
|
7
|
+
visit "/projects/project"
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^I visit the sample feature page$/ do
|
11
|
+
visit "/projects/project/features/sample-feature"
|
12
|
+
end
|
13
|
+
|
14
|
+
When /^I select "([^"]*)"$/ do |text|
|
15
|
+
click_link text
|
16
|
+
end
|
17
|
+
|
18
|
+
Then /^I see a link to "([^"]*)" with the url "([^"]*)"$/ do |text, url|
|
19
|
+
page.should have_link text, :href => url
|
20
|
+
end
|
21
|
+
|
22
|
+
Then /^I see "([^"]*)"$/ do |text|
|
23
|
+
page.should have_content(text)
|
24
|
+
end
|
25
|
+
|
26
|
+
Then /^the total tag count is displayed$/ do
|
27
|
+
save_and_open_page
|
28
|
+
end
|
29
|
+
|
30
|
+
Then /^I see each tag has an individual colour$/ do
|
31
|
+
find('a.tag-tag1').should be_visible
|
32
|
+
find('a.tag-tag2').should be_visible
|
33
|
+
find('a.tag-tag3').should be_visible
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Given /^there aren't any projects$/ do
|
2
|
+
end
|
3
|
+
|
4
|
+
When /^I view the welcome page$/ do
|
5
|
+
visit "/"
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^I am redirected to the "([^"]*)" project page$/ do |project|
|
9
|
+
sleep 1
|
10
|
+
page.current_path.should include "/projects/#{project}"
|
11
|
+
end
|
12
|
+
|
13
|
+
When /^I select the project "([^"]*)"$/ do |project|
|
14
|
+
select(project, :from => "projects")
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^I see the nuker README$/ do
|
18
|
+
page.should have_content "Nuker is a web-based Cucumber viewer and navigator"
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), "../../lib"))
|
2
|
+
ENV['RACK_ENV'] = 'test'
|
3
|
+
require "nuker"
|
4
|
+
require "fileutils"
|
5
|
+
require "capybara/cucumber"
|
6
|
+
require "rspec"
|
7
|
+
require "fakefs/spec_helpers"
|
8
|
+
|
9
|
+
Capybara.app = Sinatra::Application
|
10
|
+
|
11
|
+
After do
|
12
|
+
Nuker::Project.delete_all
|
13
|
+
end
|
14
|
+
|
15
|
+
Capybara.register_driver :selenium_chrome do |app|
|
16
|
+
Capybara::Selenium::Driver.new(app, :browser => :chrome)
|
17
|
+
end
|
18
|
+
Capybara.javascript_driver = :selenium_chrome
|
19
|
+
|
20
|
+
def project name
|
21
|
+
project = Nuker::Project.first(:name => name)
|
22
|
+
unless project
|
23
|
+
project = Nuker::Project.create(:name => name)
|
24
|
+
end
|
25
|
+
project
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_feature project, path, content
|
29
|
+
project = project(project)
|
30
|
+
feature = Nuker::Feature.new(:path => path, :gherkin => Nuker::ParsesFeatures.new.parse(content))
|
31
|
+
project.features << feature
|
32
|
+
project.save
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Feature: Welcome Page
|
2
|
+
As a stakeholder
|
3
|
+
I want a welcome page
|
4
|
+
|
5
|
+
Scenario: No projects
|
6
|
+
Given there aren't any projects
|
7
|
+
When I view the welcome page
|
8
|
+
Then I see the nuker README
|
9
|
+
|
10
|
+
@javascript
|
11
|
+
Scenario: Project links on home page
|
12
|
+
Given a feature file on the project "sample1" with the contents:
|
13
|
+
"""
|
14
|
+
Feature: Sample1
|
15
|
+
"""
|
16
|
+
And a feature file on the project "sample2" with the contents:
|
17
|
+
"""
|
18
|
+
Feature: Sample2
|
19
|
+
"""
|
20
|
+
When I view the welcome page
|
21
|
+
And I select the project "sample2"
|
22
|
+
Then I am redirected to the "sample2" project page
|
23
|
+
|
24
|
+
Scenario: Redirect to first project
|
25
|
+
Given a feature file on the project "sample1" with the contents:
|
26
|
+
"""
|
27
|
+
Feature: Sample1
|
28
|
+
"""
|
29
|
+
When I view the welcome page
|
30
|
+
Then I am redirected to the "sample1" project page
|
@@ -0,0 +1,161 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__)))
|
2
|
+
require "sinatra"
|
3
|
+
require "haml"
|
4
|
+
require "rdiscount"
|
5
|
+
require "mongo_mapper"
|
6
|
+
require "nuker/feature"
|
7
|
+
require "nuker/project"
|
8
|
+
require "nuker/search_features"
|
9
|
+
require "nuker/counts_tags"
|
10
|
+
require "nuker/parses_features"
|
11
|
+
require "cgi"
|
12
|
+
|
13
|
+
configure do
|
14
|
+
set :haml, { :ugly=>true }
|
15
|
+
end
|
16
|
+
|
17
|
+
if ENV['MONGOHQ_URL']
|
18
|
+
uri = URI.parse(ENV['MONGOHQ_URL'])
|
19
|
+
MongoMapper.connection = Mongo::Connection.from_uri(ENV['MONGOHQ_URL'])
|
20
|
+
MongoMapper.database = uri.path.gsub(/^\//, '')
|
21
|
+
else
|
22
|
+
MongoMapper.connection = Mongo::Connection.new('localhost')
|
23
|
+
MongoMapper.database = "nuker"
|
24
|
+
end
|
25
|
+
|
26
|
+
def current_project
|
27
|
+
@current_project ||= Nuker::Project.first(:name => params[:project])
|
28
|
+
end
|
29
|
+
|
30
|
+
def tag_count
|
31
|
+
return {} if current_project.nil?
|
32
|
+
@tag_count ||= Nuker::CountsTags.new(current_project).count_tags
|
33
|
+
end
|
34
|
+
|
35
|
+
def excessive_wip_tags
|
36
|
+
tag_count["@wip"] >= 10 if tag_count["@wip"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def scenario_count
|
40
|
+
current_project.features.inject(0) do |count, feature|
|
41
|
+
if feature.gherkin["elements"]
|
42
|
+
count += feature.gherkin["elements"].select { |e| e["type"] == "scenario" }.size
|
43
|
+
end
|
44
|
+
if feature.gherkin["elements"]
|
45
|
+
count += feature.gherkin["elements"].select { |e| e["type"] == "scenario_outline" }.size
|
46
|
+
end
|
47
|
+
count
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def highlighted_search_result_blurb search_result
|
52
|
+
offset = 0
|
53
|
+
highlighted = search_result.object.text.dup
|
54
|
+
span_start = "!!SPAN_START!!"
|
55
|
+
span_end = "!!SPAN_END!!"
|
56
|
+
search_result.matches.each do |match|
|
57
|
+
highlighted.insert(match.index + offset, span_start)
|
58
|
+
offset += span_start.length
|
59
|
+
highlighted.insert(match.index + match.text.length + offset, span_end)
|
60
|
+
offset += span_end.length
|
61
|
+
end
|
62
|
+
highlighted = CGI::escapeHTML(highlighted)
|
63
|
+
highlighted.gsub!(span_start, "<span class=\"search-result\">")
|
64
|
+
highlighted.gsub!(span_end, "</span>")
|
65
|
+
highlighted
|
66
|
+
end
|
67
|
+
|
68
|
+
def authenticated?
|
69
|
+
File.exist?(".nuker") && params[:authentication_code] == File.read(".nuker").strip
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_scenario_url(scenario)
|
73
|
+
url = "/projects/#{current_project.name}/features/#{scenario["id"].gsub(";", "/scenario/")}"
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_sorted_scenarios(feature)
|
77
|
+
scenarios = []
|
78
|
+
|
79
|
+
if feature.gherkin["elements"]
|
80
|
+
feature.gherkin["elements"].each do |element|
|
81
|
+
if element["type"] == "scenario" || element["type"] == "scenario_outline"
|
82
|
+
scenarios << element
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
scenarios.sort! { |a, b| a["name"] <=> b["name"] }
|
87
|
+
scenarios
|
88
|
+
end
|
89
|
+
|
90
|
+
put '/projects/:project/features/?' do
|
91
|
+
error 403 unless authenticated?
|
92
|
+
|
93
|
+
current_project.delete if current_project
|
94
|
+
project = Nuker::Project.create(:name => params[:project])
|
95
|
+
|
96
|
+
JSON.parse(request.body.read).each do |json|
|
97
|
+
project.features << Nuker::Feature.new(:path => json["path"], :gherkin => json["gherkin"])
|
98
|
+
end
|
99
|
+
project.save
|
100
|
+
halt 201
|
101
|
+
end
|
102
|
+
|
103
|
+
get '/?' do
|
104
|
+
first_project = Nuker::Project.first
|
105
|
+
if first_project
|
106
|
+
redirect "/projects/#{first_project.name}"
|
107
|
+
else
|
108
|
+
readme_path = File.expand_path(File.join(File.dirname(__FILE__), "../../README.md"))
|
109
|
+
markdown File.read(readme_path), :layout => false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
get '/robots.txt' do
|
114
|
+
"User-agent: *\nDisallow: /"
|
115
|
+
end
|
116
|
+
|
117
|
+
get '/projects/:project/?' do
|
118
|
+
haml :project
|
119
|
+
end
|
120
|
+
|
121
|
+
delete '/projects/:project' do
|
122
|
+
error 403 unless authenticated?
|
123
|
+
project = Nuker::Project.first(:name => params[:project])
|
124
|
+
project.destroy
|
125
|
+
halt 201
|
126
|
+
end
|
127
|
+
|
128
|
+
get '/projects/:project/features/:feature/?' do
|
129
|
+
current_project.features.each do |feature|
|
130
|
+
@feature = feature if feature.gherkin["id"] == params[:feature]
|
131
|
+
end
|
132
|
+
haml :feature
|
133
|
+
end
|
134
|
+
|
135
|
+
get '/projects/:project/progress/?' do
|
136
|
+
haml :progress
|
137
|
+
end
|
138
|
+
|
139
|
+
get '/projects/:project/search/?' do
|
140
|
+
if params[:q]
|
141
|
+
@search_results = Nuker::SearchFeatures.new(current_project).find(:query => params[:q])
|
142
|
+
end
|
143
|
+
haml :search
|
144
|
+
end
|
145
|
+
|
146
|
+
get '/projects/:project/features/:feature/scenario/:scenario/?' do
|
147
|
+
current_project.features.each do |feature|
|
148
|
+
if feature.gherkin["id"] == params[:feature]
|
149
|
+
@feature = feature
|
150
|
+
feature.gherkin["elements"].each do |element|
|
151
|
+
if element["type"] == "background"
|
152
|
+
@background = element
|
153
|
+
end
|
154
|
+
if (element["type"] == "scenario" || element["type"] == "scenario_outline") && element["id"] == "#{params[:feature]};#{params[:scenario]}"
|
155
|
+
@scenario = element
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
haml :scenario
|
161
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Nuker
|
2
|
+
class CountsTags
|
3
|
+
def initialize project
|
4
|
+
@project = project
|
5
|
+
end
|
6
|
+
|
7
|
+
def count_tags
|
8
|
+
@project.features.inject(Hash.new(0)) do |tag_count, feature|
|
9
|
+
if feature.gherkin["tags"]
|
10
|
+
feature.gherkin["tags"].each do |tag|
|
11
|
+
tag_count[tag["name"].downcase] += 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
if feature.gherkin["elements"]
|
15
|
+
feature.gherkin["elements"].each do |element|
|
16
|
+
if element["tags"]
|
17
|
+
element["tags"].each do |tag|
|
18
|
+
tag_count[tag["name"].downcase] += 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
tag_count
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Nuker
|
2
|
+
class Feature
|
3
|
+
include MongoMapper::EmbeddedDocument
|
4
|
+
|
5
|
+
key :path, String
|
6
|
+
key :gherkin, Hash
|
7
|
+
key :name, String
|
8
|
+
|
9
|
+
before_save :save_feature_name
|
10
|
+
|
11
|
+
private
|
12
|
+
def save_feature_name
|
13
|
+
@name = gherkin["name"]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|