Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

planterbox

https://api.travis-ci.org/npilon/planterbox.png?branch=master

A plugin for running behavior-driven tests using gherkin inside nose2.

Usage

To enable planterbox for your project, you'll want to add the following lines (or similar) to your unittest.cfg:

[unittest]plugins = planterbox
[planterbox]always-on = True

planterbox is compatible with nose2.plugins.mp.

Writing Tests

planterbox tests exist inside a python package which provides a context for their execution. You should write your tests in .feature files in the package directory. .feature files have access to all steps defined in or imported into their package's __init__.py. For example, with the directory structure:

planterbox/
tests/
test_feature/
__init__.py
basic.feature

If __init__.py contains:

fromplanterboximportstep@step(r'I add (\d+) and (\d+)')defadd(test, a, b):
a=int(a)
b=int(b)
test.result=a+b@step(r'the result should be (\d+)')defcheck_result(test, value):
value=int(value)
test.assertEqual(test.result, value)

basic.feature could contain:

Feature: Basic TestsI want to exercise generation of a simple test from a feature.
Scenario: I need to verify basic arithmetic.Given I add 1 and 1
Then the result should be 2

We could then run this test either by running all of the tests in the suite with nose2 or run it specifically with nose2 planterbox.tests.test_feature:basic.feature. We could even run the first scenario specifically with nose2 planterbox.tests.test_feature:basic.feature:0.

Writing Steps

planterbox steps are python functions decorated with @planterbox.step(PATTERN). PATTERN can be a python regular expression, which must start matching expected step text after the gherkin step prefixes.

Groups matched within PATTERN are provided to the decorated function as arguments. All steps are provided with the ScenarioTestCase object for the currently executing scenario as their first argument. Unnamed groups are provided to the step as positional arguments after this. Named groups will be passed as keyword arguments. PATTERN cannot mix unnamed and named groups. If any named groups are used, all groups must be named groups.

All the steps in a feature's package will be available to that feature's scenario. These steps can be defined in the package or imported from somewhere else.

Hooks, Setup, and Teardown

setUpModule and tearDownModule methods in a feature's __init__.py will be run before and after all features in that package, respectively. planterbox provides some extra hooks for doing preparation or cleanup. Functions can be registered as hooks by decorating them with @planterbox.hook(TIMING, STAGE). TIMING can be 'before' or 'after' and STAGE any of 'feature', 'scenario', 'step', 'failure', or 'error'.

All hooks are expected to take one argument: the TestCase subclass for the active feature.

As with steps, hooks must be directly present in the feature's __init__.py in order to be run.

Scenario Outlines

planterbox supports scenario outlines. These allow you to execute a scenario multiple times with different values. For example:

Feature: Example TestsI want to exercise generation of a test with examples from a feature.
Scenario Outline: I need to verify basic arithmetic with examples.Given I add <x> and <y>Then the result should be <z>Examples:
x | y | z
1 | 1 | 2
1 | 2 | 3
2 | 1 | 3
2 | 2 | 4

You may also specify Examples in a .csv file by using Examples file: followed by the path to the .csv file on the next line.

Feature: Example TestsI want to exercise using a csv file for examples
Scenario Outline: I want to exercise using a csv file for examplesGiven I squiggly-add {<x>} and {<y>}
Then the result should be <z>
Examples file:
/tests/test_feature/examples.csv

Your 'before' and 'after''scenario' hooks will only run once for the entire scenario outline.

Invoking Tests

You can run tests by allowing nose2's autodiscovery to find all of your tests, or you can specify specific tests to be run on the command line. When specifying specific tests, you can either specify an entire package, an entire feature, or individual scenarios. Individual scenarios can be specified either by index (from 0) or by name.

nose2 planterbox.tests.test_feature
nose2 planterbox.tests.test_feature:basic.feature planterbox.tests.test_hooks:hooks.feature
nose2 planterbox.tests.test_feature:basic.feature:1
nose2 planterbox.tests.test_feature:basic.feature:0
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic"
nose2 planterbox.tests.test_feature:basic.feature:"I need to verify basic arithmetic."

If your feature includes multiple scenarios with the same name, all will be run when that name is given. Names with a trailing period can be specified with or without the trailing period.

Validating Tests

You can use the --planterbox-check-only flag to verify that your features are correct without running them:

nose2 --planterbox-check-only planterbox.tests.test_feature
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK

While a failure would produce a traceback:

nose2 --planterbox-check-only planterbox.tests.test_feature
Traceback (most recent call last):
File "planterbox_ve/bin/nose2", line 11, in <module>
sys.exit(discover())
File "nose2/main.py", line 306, in discover
return main(*args, **kwargs)
File "nose2/main.py", line 100, in __init__
super(PluggableTestProgram, self).__init__(**kw)
File "/opt/python/lib/python3.6/unittest/main.py", line 94, in __init__
self.parseArgs(argv)
File "nose2/main.py", line 133, in parseArgs
self.createTests()
File "nose2/main.py", line 258, in createTests
self.testNames, self.module)
File "nose2/loader.py", line 68, in loadTestsFromNames
for name in event.names]
File "nose2/loader.py", line 68, in <listcomp>
for name in event.names]
File "nose2/loader.py", line 83, in loadTestsFromName
result = self.session.hooks.loadTestsFromName(event)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "nose2/plugins/loader/discovery.py", line 247, in loadTestsFromName
return Discoverer.loadTestsFromName(self, event)
File "nose2/plugins/loader/discovery.py", line 84, in loadTestsFromName
self._find_tests_in_module(event, module, top_level_dir))
File "nose2/plugins/loader/discovery.py", line 229, in _find_tests_in_module
event, full_path, top_level_dir):
File "nose2/plugins/loader/discovery.py", line 161, in _find_tests_in_dir
event, path, entry_path, top_level):
File "nose2/plugins/loader/discovery.py", line 176, in _find_tests_in_file
result = self.session.hooks.handleFile(evt)
File "nose2/events.py", line 225, in __call__
result = getattr(plugin, self.method)(event)
File "planterbox/planterbox/plugin.py", line 106, in handleFile
feature_path=feature_path,
File "planterbox/planterbox/plugin.py", line 75, in makeSuiteFromFeature
config=self.config,
File "planterbox/planterbox/feature.py", line 81, in __init__
self.check_scenarios()
File "planterbox/planterbox/feature.py", line 227, in check_scenarios
raise UnmatchedStepException("Unmatched steps:\n" + '\n'.join(unmatched))
planterbox.exceptions.UnmatchedStepException: Unmatched steps:
Given I bad 1 and 1

About

A plugin for nose2 for running behavior-driven tests.

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages