-
-
Notifications
You must be signed in to change notification settings - Fork 2k
[Core] Merge cucumber-html into cucumber-core #1650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mpkorstanje
merged 3 commits into
cucumber:master
from
grasshopper7:remove-cucumber-html
Jun 4, 2019
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -14,6 +14,7 @@ target/ | |||
tmp/ | ||||
gen-external-apklibs/ | ||||
out/ | ||||
some/ | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
|
||||
# Build & test droppings | ||||
pom.xml.releaseBackup | ||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+16.2 KB
core/src/main/resources/io/cucumber/formatter/html/bubble_256x256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
251 changes: 251 additions & 0 deletions
251
core/src/main/resources/io/cucumber/formatter/html/formatter.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
var CucumberHTML = {}; | ||
|
||
CucumberHTML.DOMFormatter = function(rootNode) { | ||
var currentUri; | ||
var currentFeature; | ||
var currentElement; | ||
var currentSteps; | ||
|
||
var currentStepIndex; | ||
var currentStep; | ||
var $templates = $(CucumberHTML.templates); | ||
|
||
this.uri = function(uri) { | ||
currentUri = uri; | ||
}; | ||
|
||
this.feature = function(feature) { | ||
currentFeature = blockElement(rootNode, feature, 'feature'); | ||
}; | ||
|
||
this.background = function(background) { | ||
currentElement = featureElement(background, 'background'); | ||
currentStepIndex = 1; | ||
}; | ||
|
||
this.scenario = function(scenario) { | ||
currentElement = featureElement(scenario, 'scenario'); | ||
currentStepIndex = 1; | ||
}; | ||
|
||
this.scenarioOutline = function(scenarioOutline) { | ||
currentElement = featureElement(scenarioOutline, 'scenario_outline'); | ||
currentStepIndex = 1; | ||
}; | ||
|
||
this.step = function(step) { | ||
var stepElement = $('.step', $templates).clone(); | ||
stepElement.appendTo(currentSteps); | ||
populate(stepElement, step, 'step'); | ||
|
||
if (step.doc_string) { | ||
docString = $('.doc_string', $templates).clone(); | ||
docString.appendTo(stepElement); | ||
// TODO: use a syntax highlighter based on the content_type | ||
docString.text(step.doc_string.value); | ||
} | ||
if (step.rows) { | ||
dataTable = $('.data_table', $templates).clone(); | ||
dataTable.appendTo(stepElement); | ||
var tBody = dataTable.find('tbody'); | ||
$.each(step.rows, function(index, row) { | ||
var tr = $('<tr></tr>').appendTo(tBody); | ||
$.each(row.cells, function(index, cell) { | ||
var td = $('<td>' + cell + '</td>').appendTo(tBody); | ||
}); | ||
}); | ||
} | ||
}; | ||
|
||
this.examples = function(examples) { | ||
var examplesElement = blockElement(currentElement.children('details'), examples, 'examples'); | ||
var examplesTable = $('.examples_table', $templates).clone(); | ||
examplesTable.appendTo(examplesElement.children('details')); | ||
|
||
$.each(examples.rows, function(index, row) { | ||
var parent = index == 0 ? examplesTable.find('thead') : examplesTable.find('tbody'); | ||
var tr = $('<tr></tr>').appendTo(parent); | ||
$.each(row.cells, function(index, cell) { | ||
var td = $('<td>' + cell + '</td>').appendTo(tr); | ||
}); | ||
}); | ||
}; | ||
|
||
this.match = function(match) { | ||
currentStep = currentSteps.find('li:nth-child(' + currentStepIndex + ')'); | ||
currentStepIndex++; | ||
}; | ||
|
||
this.result = function(result) { | ||
currentStep.addClass(result.status); | ||
if (result.error_message != '') { | ||
populateStepError(currentStep, result.error_message); | ||
} | ||
currentElement.addClass(result.status); | ||
var isLastStep = currentSteps.find('li:nth-child(' + currentStepIndex + ')').length == 0; | ||
if (isLastStep) { | ||
if (currentSteps.find('.failed').length == 0) { | ||
// No failed steps. Collapse it. | ||
currentElement.find('details').removeAttr('open'); | ||
} else { | ||
currentElement.find('details').attr('open', 'open'); | ||
} | ||
} | ||
}; | ||
|
||
this.embedding = function(mimeType, data) { | ||
if (currentStepIndex == 1) { | ||
this.dummyStep(); | ||
} | ||
if (mimeType.match(/^image\//)) | ||
{ | ||
currentStep.append('<img src="' + data + '">'); | ||
} | ||
else if (mimeType.match(/^video\//)) | ||
{ | ||
currentStep.append('<video src="' + data + '" type="' + mimeType + '" autobuffer controls>Your browser doesn\'t support video.</video>'); | ||
} | ||
else if (mimeType.match(/^text\//)) | ||
{ | ||
this.write(data); | ||
} | ||
}; | ||
|
||
this.write = function(text) { | ||
if (currentStepIndex == 1) { | ||
this.dummyStep(); | ||
} | ||
currentStep.append('<pre class="embedded-text">' + text + '</pre>'); | ||
}; | ||
|
||
this.before = function(before) { | ||
this.handleHookResult(before); | ||
}; | ||
|
||
this.after = function(after) { | ||
this.handleHookResult(after); | ||
}; | ||
|
||
this.beforestep = function(beforestep) { | ||
this.handleHookResult(beforestep); | ||
}; | ||
|
||
this.afterstep = function(afterstep) { | ||
this.handleHookResult(afterstep); | ||
}; | ||
|
||
this.handleHookResult = function(hook) { | ||
if (hook.status != 'passed' && hook.error_message != '') { | ||
this.dummyStep(); | ||
currentStep.addClass(hook.status); | ||
currentElement.addClass(hook.status); | ||
populateStepError(currentStep, hook.error_message); | ||
} | ||
}; | ||
|
||
this.dummyStep = function() { | ||
var stepElement = $('.step', $templates).clone(); | ||
stepElement.appendTo(currentSteps); | ||
populate(stepElement, {keyword: '', name: ''}, 'step'); | ||
currentStep = currentSteps.find('li:nth-child(' + currentStepIndex + ')'); | ||
currentStepIndex++; | ||
}; | ||
|
||
function featureElement(statement, itemtype) { | ||
var e = blockElement(currentFeature.children('details'), statement, itemtype); | ||
|
||
currentSteps = $('.steps', $templates).clone(); | ||
currentSteps.appendTo(e.children('details')); | ||
|
||
return e; | ||
} | ||
|
||
function blockElement(parent, statement, itemtype) { | ||
var e = $('.blockelement', $templates).clone(); | ||
e.appendTo(parent); | ||
return populate(e, statement, itemtype); | ||
} | ||
|
||
function populate(e, statement, itemtype) { | ||
populateTags(e, statement.tags); | ||
populateComments(e, statement.comments); | ||
e.find('.keyword').text(statement.keyword); | ||
e.find('.name').text(statement.name); | ||
e.find('.description').text(statement.description); | ||
e.attr('itemtype', 'http://cukes.info/microformat/' + itemtype); | ||
e.addClass(itemtype); | ||
return e; | ||
} | ||
|
||
function populateComments(e, comments) { | ||
if (comments !== undefined) { | ||
var commentsNode = $('.comments', $templates).clone().prependTo(e.find('.header')); | ||
$.each(comments, function(index, comment) { | ||
var commentNode = $('.comment', $templates).clone().appendTo(commentsNode); | ||
commentNode.text(comment.value); | ||
}); | ||
} | ||
} | ||
|
||
function populateTags(e, tags) { | ||
if (tags !== undefined) { | ||
var tagsNode = $('.tags', $templates).clone().prependTo(e.find('.header')); | ||
$.each(tags, function(index, tag) { | ||
var tagNode = $('.tag', $templates).clone().appendTo(tagsNode); | ||
tagNode.text(tag.name); | ||
}); | ||
} | ||
} | ||
|
||
function populateStepError(e, error) { | ||
if (error !== undefined) { | ||
errorNode = $('.error', $templates).clone().appendTo(e); | ||
errorNode.text(error); | ||
} | ||
} | ||
}; | ||
|
||
CucumberHTML.templates = '<div>\ | ||
<section class="blockelement" itemscope>\ | ||
<details open>\ | ||
<summary class="header">\ | ||
<span class="keyword" itemprop="keyword">Keyword</span>: <span itemprop="name" class="name">This is the block name</span>\ | ||
</summary>\ | ||
<div itemprop="description" class="description">The description goes here</div>\ | ||
</details>\ | ||
</section>\ | ||
\ | ||
<ol class="steps"></ol>\ | ||
\ | ||
<ol>\ | ||
<li class="step"><div class="header"></div><span class="keyword" itemprop="keyword">Keyword</span><span class="name" itemprop="name">Name</span></li>\ | ||
</ol>\ | ||
\ | ||
<pre class="doc_string"></pre>\ | ||
\ | ||
<pre class="error"></pre>\ | ||
\ | ||
<table class="data_table">\ | ||
<tbody>\ | ||
</tbody>\ | ||
</table>\ | ||
\ | ||
<table class="examples_table">\ | ||
<thead></thead>\ | ||
<tbody></tbody>\ | ||
</table>\ | ||
\ | ||
<section class="embed">\ | ||
<img itemprop="screenshot" class="screenshot" />\ | ||
</section>\ | ||
<div class="tags"></div>\ | ||
<span class="tag"></span>\ | ||
<div class="comments"></div>\ | ||
<div class="comment"></div>\ | ||
<div>'; | ||
|
||
if (typeof module !== 'undefined') { | ||
module.exports = CucumberHTML; | ||
} else if (typeof define !== 'undefined') { | ||
define([], function() { return CucumberHTML; }); | ||
} |
14 changes: 14 additions & 0 deletions
14
core/src/main/resources/io/cucumber/formatter/html/index.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>Cucumber Features</title> | ||
<link href="style.css" rel="stylesheet"> | ||
<script src="jquery-1.8.2.min.js"></script> | ||
<script src="formatter.js"></script> | ||
<script src="report.js"></script> | ||
</head> | ||
<body> | ||
<div class="cucumber-report"></div> | ||
</body> | ||
</html> |
2 changes: 2 additions & 0 deletions
2
core/src/main/resources/io/cucumber/formatter/html/jquery-1.8.2.min.js
Large diffs are not rendered by default.
Oops, something went wrong.
93 changes: 93 additions & 0 deletions
93
core/src/main/resources/io/cucumber/formatter/html/report.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
$(document).ready(function() { | ||
var formatter = new CucumberHTML.DOMFormatter($('.cucumber-report')); | ||
var N = document.location.hash ? parseInt(document.location.hash.substring(1)) : 1; | ||
var start = new Date().getTime(); | ||
for(var n = 0; n < N; n++) { | ||
formatter.uri('report.feature'); | ||
formatter.feature({ | ||
comments: [ | ||
{value: "# A comment"}, | ||
{value: "# Another comment"} | ||
], | ||
keyword:'Feature', | ||
name:'Generating html report', | ||
description: 'It could be useful to have an html report to facilitate documentation reading.\n\nEspecially when the whitespace formatting is preserved', | ||
line:2 | ||
}); | ||
|
||
formatter.background({ | ||
comments: [ | ||
{value: "# Background comment"} | ||
], | ||
keyword:'Background', | ||
name:'Setting up the context', | ||
line:3, | ||
description: 'These steps will be executed before each scenario.' | ||
}); | ||
formatter.write('Output from before hook'); | ||
formatter.embedding('text/plain', 'Text embedding from before hook'); | ||
formatter.step({keyword:'Given ', name:'I have a background', line:4}); | ||
formatter.step({keyword:'And ', name:'I set some context', line: 5}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'passed', duration: 0}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'passed', duration: 0}); | ||
|
||
formatter.before({status: 'passed', duration: 668816288}); | ||
formatter.scenario({"tags":[{"name":"@foo","line":3},{"name":"@bar","line":4},{"name":"@doh","line":5}], keyword:'Scenario', name: 'Creating a simple report', line: 6}); | ||
formatter.step({comments: [ | ||
{value: "# Step comment 1"}, | ||
{value: "# Step comment 2"} | ||
],keyword:'Given ', name:'I have a feature', line: 7, doc_string:{value: "A\ndoc string\non several lines", content_type:"text/plain", line:8}}); | ||
formatter.step({keyword:'When ', name:'I format it', line: 11}); | ||
formatter.step({keyword:'Then ', name:'It should look pretty', line: 12}); | ||
formatter.step({keyword:'And ', name:'It should show tables', line: 13, rows: [{cells:['name', 'price'], line: 14}, {cells:['milk', '9'], line: 15}]}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'passed', duration: 0}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'failed', error_message:'something went wrong...', duration: 0}); | ||
formatter.embedding('image/png', 'bubble_256x256.png'); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'undefined', duration: 0}); | ||
formatter.embedding('text/plain', 'Look at this video'); | ||
formatter.embedding('video/mp4', 'http://www.808.dk/pics/video/gizmo.mp4'); | ||
formatter.embedding('text/plain', 'Look at this multi-line embedding\nReal fancy'); | ||
formatter.write('What a nice helicopter'); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'skipped', duration: 0}); | ||
formatter.after({status: 'passed', duration: 668816288}); | ||
|
||
formatter.scenarioOutline({keyword:'Scenario Outline', name: 'Scenario with examples', description:'It should be good to format outlined arguments.', line: 16}); | ||
formatter.step({keyword:'Given ', name:'I have a <name> which costs <price>', line: 17}); | ||
formatter.examples({description:'', name:'Some good examples', keyword:'Examples', line: 18, rows:[{cells:['name', 'price'], line:19}, {cells:['milk', '9'], line:20}, {cells:['bread', '7'], line:21}, {cells:['soap', '5'], line:22}]}); | ||
formatter.before({status: 'passed', duration: 668816288}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'passed', duration: 0}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'passed', duration: 0}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'failed', error_message:'I didn\'t do it.', duration: 0}); | ||
formatter.after({status: 'failed', duration: 668816288, "error_message": 'com.example.MyDodgyException: Widget underflow\r\n\tat org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)\r\n\tat com.example.WidgetFurbicator.furbicateWidgets(WidgetFurbicator.java:678)'}); | ||
|
||
formatter.scenario({"tags":[{"name":"@stephooks","line":24}], keyword:'Scenario', name: 'Scenario with step hooks', line: 25}); | ||
formatter.before({status: 'passed', duration: 668816288}); | ||
formatter.beforestep({status: 'passed', duration: 668816288}); | ||
formatter.step({keyword:'Given ', name:'step 1', line: 26}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'passed', duration: 0}); | ||
formatter.afterstep({status: 'passed', duration: 668816288}); | ||
formatter.beforestep({status: 'failed', duration: 668816288, "error_message": 'com.example.MyDodgyException: Widget underflow\r\n\tat org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)\r\n\tat com.example.StepDefinitions.beforeStepHook()'}); | ||
formatter.step({keyword:'When ', name:'step 2', line: 27}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'skipped', duration: 0}); | ||
formatter.afterstep({status: 'failed', duration: 668816288, "error_message": 'com.example.MyDodgyException: Widget underflow\r\n\tat org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)\r\n\tat com.example.StepDefinitions.afterStepHook()'}); | ||
formatter.beforestep({status: 'skipped', duration: 0}); | ||
formatter.step({keyword:'Then ', name:'step 3', line: 28}); | ||
formatter.match({uri:'report.feature'}); | ||
formatter.result({status:'skipped', duration: 0}); | ||
formatter.afterstep({status: 'skipped', duration: 0}); | ||
formatter.after({status: 'passed', duration: 668816288}); | ||
} | ||
console.log('Rendered %s features in %s ms', N, new Date().getTime() - start); | ||
|
||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should really figure out who creates this directory.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HTMLFormatterTest is the culprit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll make a seperate PR to fix that.