mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-01-12 22:45:52 +08:00
JSTD adapter for running e2e tests
Couple of changes into angular.scenario runner: - add autotest config (runs tests when document ready) - update ObjectModel (forwards events) - use only one ObjectModel instance for all outputters - expose error msg and line number in ObjectModel.Spec and ObjectModel.Step - fix generating spec.ids - fix 'html' output so that it does not mutate ObjectModel Couple of changes into docs / generator: - rename copy -> copyTpl - move docs/static into docs/examples (to avoid conflict with jstd proxy) Running all docs e2e tests: ======================================================== 1/ compile angular-scenario, jstd-scenario-adapter >> rake compile 2/ build docs >> rake docs 3/ start jstd server >> ./server-scenario.sh 4/ capture some browser 5/ run node server to serve static content >> node ../lib/nodeserver/server.js 6/ run tests >> ./test-scenario.sh
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
<a name="0.9.16"><a/>
|
||||
# <angular/> 0.9.16 weather-control (in-progress) #
|
||||
|
||||
### Features
|
||||
- we can run scenario tests with jstd (from command line and in multiple browsers)
|
||||
|
||||
|
||||
### Breaking changes
|
||||
- html scenario runner requires ng:autotest option to start tests automatically
|
||||
|
||||
|
||||
<a name="0.9.15"><a/>
|
||||
# <angular/> 0.9.15 lethal-stutter (2011-04-11) #
|
||||
|
||||
32
Rakefile
32
Rakefile
@@ -53,7 +53,7 @@ ANGULAR_SCENARIO = [
|
||||
'src/scenario/output/Html.js',
|
||||
'src/scenario/output/Json.js',
|
||||
'src/scenario/output/Xml.js',
|
||||
'src/scenario/output/Object.js',
|
||||
'src/scenario/output/Object.js'
|
||||
]
|
||||
|
||||
BUILD_DIR = 'build'
|
||||
@@ -94,6 +94,30 @@ task :compile_scenario => :init do
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Compile JSTD Scenario Adapter'
|
||||
task :compile_jstd_scenario_adapter => :init do
|
||||
|
||||
deps = [
|
||||
'src/jstd-scenario-adapter/angular.prefix',
|
||||
'src/jstd-scenario-adapter/Adapter.js',
|
||||
'src/jstd-scenario-adapter/angular.suffix',
|
||||
]
|
||||
|
||||
concat = 'cat ' + deps.flatten.join(' ')
|
||||
|
||||
File.open(path_to('jstd-scenario-adapter.js'), 'w') do |f|
|
||||
f.write(%x{#{concat}})
|
||||
end
|
||||
|
||||
# TODO(vojta) use jstd configuration when implemented
|
||||
# (instead of including jstd-adapter-config.js)
|
||||
File.open(path_to('jstd-scenario-adapter-config.js'), 'w') do |f|
|
||||
f.write("/**\r\n" +
|
||||
" * Configuration for jstd scenario adapter \n */\n" +
|
||||
"var jstdScenarioAdapter = {\n relativeUrlPrefix: '/build/docs/'\n};\n")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
desc 'Generate IE css js patch'
|
||||
task :generate_ie_compat => :init do
|
||||
@@ -152,7 +176,7 @@ end
|
||||
|
||||
|
||||
desc 'Compile JavaScript'
|
||||
task :compile => [:init, :compile_scenario, :generate_ie_compat] do
|
||||
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter, :generate_ie_compat] do
|
||||
|
||||
deps = [
|
||||
'src/angular.prefix',
|
||||
@@ -195,7 +219,9 @@ task :package => [:clean, :compile, :docs] do
|
||||
path_to('angular.js'),
|
||||
path_to('angular.min.js'),
|
||||
path_to('angular-ie-compat.js'),
|
||||
path_to('angular-scenario.js')
|
||||
path_to('angular-scenario.js'),
|
||||
path_to('jstd-scenario-adapter.js'),
|
||||
path_to('jstd-scenario-adapter-config.js'),
|
||||
].each do |src|
|
||||
dest = src.gsub(/^[^\/]+\//, '').gsub(/((\.min)?\.js)$/, "-#{version}\\1")
|
||||
FileUtils.cp(src, pkg_dir + '/' + dest)
|
||||
|
||||
@@ -34,8 +34,8 @@ In this example we have a simple app which consist of two screens:
|
||||
|
||||
The two partials are defined in the following URLs:
|
||||
|
||||
* {@link ./static/settings.html}
|
||||
* {@link ./static/welcome.html}
|
||||
* {@link ./examples/settings.html}
|
||||
* {@link ./examples/welcome.html}
|
||||
|
||||
|
||||
<doc:example>
|
||||
@@ -44,8 +44,8 @@ The two partials are defined in the following URLs:
|
||||
AppCntl.$inject = ['$route']
|
||||
function AppCntl($route) {
|
||||
// define routes
|
||||
$route.when("", {template:'./static/welcome.html', controller:WelcomeCntl});
|
||||
$route.when("/settings", {template:'./static/settings.html', controller:SettingsCntl});
|
||||
$route.when("", {template:'./examples/welcome.html', controller:WelcomeCntl});
|
||||
$route.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
|
||||
$route.parent(this);
|
||||
|
||||
// initialize the model to something useful
|
||||
|
||||
@@ -25,22 +25,22 @@ var writes = callback.chain(function(){
|
||||
var metadata = ngdoc.metadata(docs);
|
||||
writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'], writes.waitFor());
|
||||
writer.copyDir('img', writes.waitFor());
|
||||
writer.copyDir('static', writes.waitFor());
|
||||
writer.copy('index.html', writes.waitFor());
|
||||
writer.copy('docs.js', writes.waitFor());
|
||||
writer.copy('docs.css', writes.waitFor());
|
||||
writer.copy('doc_widgets.js', writes.waitFor());
|
||||
writer.copy('doc_widgets.css', writes.waitFor());
|
||||
writer.copy('docs-scenario.html', writes.waitFor());
|
||||
writer.copyDir('examples', writes.waitFor());
|
||||
writer.copyTpl('index.html', writes.waitFor());
|
||||
writer.copyTpl('docs.js', writes.waitFor());
|
||||
writer.copyTpl('docs.css', writes.waitFor());
|
||||
writer.copyTpl('doc_widgets.js', writes.waitFor());
|
||||
writer.copyTpl('doc_widgets.css', writes.waitFor());
|
||||
writer.copyTpl('docs-scenario.html', writes.waitFor());
|
||||
writer.output('docs-scenario.js', ngdoc.scenarios(docs), writes.waitFor());
|
||||
writer.output('sitemap.xml', new SiteMap(docs).render(), writes.waitFor());
|
||||
writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n', writes.waitFor());
|
||||
writer.copy('syntaxhighlighter/shBrushJScript.js', writes.waitFor());
|
||||
writer.copy('syntaxhighlighter/shBrushXml.js', writes.waitFor());
|
||||
writer.copy('syntaxhighlighter/shCore.css', writes.waitFor());
|
||||
writer.copy('syntaxhighlighter/shCore.js', writes.waitFor());
|
||||
writer.copy('syntaxhighlighter/shThemeDefault.css', writes.waitFor());
|
||||
writer.copy('jquery.min.js', writes.waitFor());
|
||||
writer.copyTpl('syntaxhighlighter/shBrushJScript.js', writes.waitFor());
|
||||
writer.copyTpl('syntaxhighlighter/shBrushXml.js', writes.waitFor());
|
||||
writer.copyTpl('syntaxhighlighter/shCore.css', writes.waitFor());
|
||||
writer.copyTpl('syntaxhighlighter/shCore.js', writes.waitFor());
|
||||
writer.copyTpl('syntaxhighlighter/shThemeDefault.css', writes.waitFor());
|
||||
writer.copyTpl('jquery.min.js', writes.waitFor());
|
||||
});
|
||||
writes.onDone(function(){
|
||||
console.log('DONE. Generated ' + docs.length + ' pages in ' +
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html xmlns:ng="http://angularjs.org" wiki:ng="http://angularjs.org">
|
||||
<head>
|
||||
<title><angular/> Docs Scenario Runner</title>
|
||||
<script type="text/javascript" src="../angular-scenario.js" ng:autobind></script>
|
||||
<script type="text/javascript" src="../angular-scenario.js" ng:autotest></script>
|
||||
<script type="text/javascript" src="docs-scenario.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -49,7 +49,7 @@ exports.makeDir = function (path, callback) {
|
||||
})();
|
||||
};
|
||||
|
||||
exports.copy = function(filename, callback){
|
||||
exports.copyTpl = function(filename, callback) {
|
||||
copy('docs/src/templates/' + filename, OUTPUT_DIR + filename, callback);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Personal Log Scenario Runner</title>
|
||||
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
|
||||
<script type="text/javascript" src="personalLogScenario.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
10
jsTestDriver-scenario.conf
Normal file
10
jsTestDriver-scenario.conf
Normal file
@@ -0,0 +1,10 @@
|
||||
server: http://localhost:9877
|
||||
|
||||
load:
|
||||
- build/angular-scenario.js
|
||||
- build/jstd-scenario-adapter-config.js
|
||||
- build/jstd-scenario-adapter.js
|
||||
- build/docs/docs-scenario.js
|
||||
|
||||
proxy:
|
||||
- {matcher: "*", server: "http://localhost:8000"}
|
||||
@@ -13,11 +13,13 @@ load:
|
||||
- test/testabilityPatch.js
|
||||
- src/scenario/Scenario.js
|
||||
- src/scenario/output/*.js
|
||||
- src/jstd-scenario-adapter/*.js
|
||||
- src/scenario/*.js
|
||||
- src/angular-mocks.js
|
||||
- test/mocks.js
|
||||
- test/scenario/*.js
|
||||
- test/scenario/output/*.js
|
||||
- test/jstd-scenario-adapter/*.js
|
||||
- test/*.js
|
||||
- test/service/*.js
|
||||
- example/personalLog/test/*.js
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<script type="text/javascript" src="../build/angular-scenario.js"></script>
|
||||
<script type="text/javascript" src="../build/angular-scenario.js" ng:autotest></script>
|
||||
<script type="text/javascript" src="widgets-scenario.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<script type="text/javascript" src="../src/scenario/angular-bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../src/scenario/angular-bootstrap.js" ng:autotest></script>
|
||||
<script type="text/javascript" src="widgets-scenario.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
3
server-scenario.sh
Executable file
3
server-scenario.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
java -jar lib/jstestdriver/JsTestDriver.jar --port 9877 --browserTimeout 90000 --config jsTestDriver-scenario.conf
|
||||
175
src/jstd-scenario-adapter/Adapter.js
Normal file
175
src/jstd-scenario-adapter/Adapter.js
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* JSTestDriver adapter for angular scenario tests
|
||||
*
|
||||
* Example of jsTestDriver.conf for running scenario tests with JSTD:
|
||||
<pre>
|
||||
server: http://localhost:9877
|
||||
|
||||
load:
|
||||
- lib/angular-scenario.js
|
||||
- lib/jstd-scenario-adapter-config.js
|
||||
- lib/jstd-scenario-adapter.js
|
||||
# your test files go here #
|
||||
|
||||
proxy:
|
||||
- {matcher: "/your-prefix/*", server: "http://localhost:8000/"}
|
||||
</pre>
|
||||
*
|
||||
* For more information on how to configure jstd proxy, see {@link http://code.google.com/p/js-test-driver/wiki/Proxy}
|
||||
* Note the order of files - it's important !
|
||||
*
|
||||
* Example of jstd-scenario-adapter-config.js
|
||||
<pre>
|
||||
var jstdScenarioAdapter = {
|
||||
relativeUrlPrefix: '/your-prefix/'
|
||||
};
|
||||
</pre>
|
||||
*
|
||||
* Whenever you use <code>browser().navigateTo('relativeUrl')</code> in your scenario test, the relativeUrlPrefix will be prepended.
|
||||
* You have to configure this to work together with JSTD proxy.
|
||||
*
|
||||
* Let's assume you are using the above configuration (jsTestDriver.conf and jstd-scenario-adapter-config.js):
|
||||
* Now, when you call <code>browser().navigateTo('index.html')</code> in your scenario test, the browser will open /your-prefix/index.html.
|
||||
* That matches the proxy, so JSTD will proxy this request to http://localhost:8000/index.html.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Custom type of test case
|
||||
*
|
||||
* @const
|
||||
* @see jstestdriver.TestCaseInfo
|
||||
*/
|
||||
var SCENARIO_TYPE = 'scenario';
|
||||
|
||||
/**
|
||||
* Plugin for JSTestDriver
|
||||
* Connection point between scenario's jstd output and jstestdriver.
|
||||
*
|
||||
* @see jstestdriver.PluginRegistrar
|
||||
*/
|
||||
function JstdPlugin() {
|
||||
var nop = function() {};
|
||||
|
||||
this.reportResult = nop;
|
||||
this.reportEnd = nop;
|
||||
this.runScenario = nop;
|
||||
|
||||
this.name = 'Angular Scenario Adapter';
|
||||
|
||||
/**
|
||||
* Called for each JSTD TestCase
|
||||
*
|
||||
* Handles only SCENARIO_TYPE test cases. There should be only one fake TestCase.
|
||||
* Runs all scenario tests (under one fake TestCase) and report all results to JSTD.
|
||||
*
|
||||
* @param {jstestdriver.TestRunConfiguration} configuration
|
||||
* @param {Function} onTestDone
|
||||
* @param {Function} onAllTestsComplete
|
||||
* @returns {boolean} True if this type of test is handled by this plugin, false otherwise
|
||||
*/
|
||||
this.runTestConfiguration = function(configuration, onTestDone, onAllTestsComplete) {
|
||||
if (configuration.getTestCaseInfo().getType() != SCENARIO_TYPE) return false;
|
||||
|
||||
this.reportResult = onTestDone;
|
||||
this.reportEnd = onAllTestsComplete;
|
||||
this.runScenario();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.getTestRunsConfigurationFor = function(testCaseInfos, expressions, testRunsConfiguration) {
|
||||
testRunsConfiguration.push(
|
||||
new jstestdriver.TestRunConfiguration(
|
||||
new jstestdriver.TestCaseInfo(
|
||||
'Angular Scenario Tests', function() {}, SCENARIO_TYPE), []));
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Singleton instance of the plugin
|
||||
* Accessed using closure by:
|
||||
* - jstd output (reports to this plugin)
|
||||
* - initScenarioAdapter (register the plugin to jstd)
|
||||
*/
|
||||
var plugin = new JstdPlugin();
|
||||
|
||||
/**
|
||||
* Initialise scenario jstd-adapter
|
||||
* (only if jstestdriver is defined)
|
||||
*
|
||||
* @param {Object} jstestdriver Undefined when run from browser (without jstd)
|
||||
* @param {Function} initScenarioAndRun Function that inits scenario and runs all the tests
|
||||
* @param {Object=} config Configuration object, supported properties:
|
||||
* - relativeUrlPrefix: prefix for all relative links when navigateTo()
|
||||
*/
|
||||
function initScenarioAdapter(jstestdriver, initScenarioAndRun, config) {
|
||||
if (jstestdriver) {
|
||||
// create and register ScenarioPlugin
|
||||
jstestdriver.pluginRegistrar.register(plugin);
|
||||
plugin.runScenario = initScenarioAndRun;
|
||||
|
||||
/**
|
||||
* HACK (angular.scenario.Application.navigateTo)
|
||||
*
|
||||
* We need to navigate to relative urls when running from browser (without JSTD),
|
||||
* because we want to allow running scenario tests without creating its own virtual host.
|
||||
* For example: http://angular.local/build/docs/docs-scenario.html
|
||||
*
|
||||
* On the other hand, when running with JSTD, we need to navigate to absolute urls,
|
||||
* because of JSTD proxy. (proxy, because of same domain policy)
|
||||
*
|
||||
* So this hack is applied only if running with JSTD and change all relative urls to absolute.
|
||||
*/
|
||||
var appProto = angular.scenario.Application.prototype,
|
||||
navigateTo = appProto.navigateTo,
|
||||
relativeUrlPrefix = config && config.relativeUrlPrefix || '/';
|
||||
|
||||
appProto.navigateTo = function(url, loadFn, errorFn) {
|
||||
if (url.charAt(0) != '/' && url.charAt(0) != '#' &&
|
||||
url != 'about:blank' && !url.match(/^https?/)) {
|
||||
url = relativeUrlPrefix + url;
|
||||
}
|
||||
|
||||
return navigateTo.call(this, url, loadFn, errorFn);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds proper TestResult object from given model spec
|
||||
*
|
||||
* TODO(vojta) report error details
|
||||
*
|
||||
* @param {angular.scenario.ObjectModel.Spec} spec
|
||||
* @returns {jstestdriver.TestResult}
|
||||
*/
|
||||
function createTestResultFromSpec(spec) {
|
||||
var map = {
|
||||
success: 'PASSED',
|
||||
error: 'ERROR',
|
||||
failure: 'FAILED'
|
||||
};
|
||||
|
||||
return new jstestdriver.TestResult(
|
||||
spec.fullDefinitionName,
|
||||
spec.name,
|
||||
jstestdriver.TestResult.RESULT[map[spec.status]],
|
||||
spec.error || '',
|
||||
spec.line || '',
|
||||
spec.duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates JSTD output (jstestdriver.TestResult)
|
||||
*/
|
||||
angular.scenario.output('jstd', function(context, runner, model) {
|
||||
model.on('SpecEnd', function(spec) {
|
||||
plugin.reportResult(createTestResultFromSpec(spec));
|
||||
});
|
||||
|
||||
model.on('RunnerEnd', function() {
|
||||
plugin.reportEnd();
|
||||
});
|
||||
});
|
||||
24
src/jstd-scenario-adapter/angular.prefix
Normal file
24
src/jstd-scenario-adapter/angular.prefix
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010 Adam Abrons and Misko Hevery http://getangular.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
(function(window) {
|
||||
2
src/jstd-scenario-adapter/angular.suffix
Normal file
2
src/jstd-scenario-adapter/angular.suffix
Normal file
@@ -0,0 +1,2 @@
|
||||
initScenarioAdapter(window.jstestdriver, angular.scenario.setUpAndRun, window.jstdScenarioAdapter);
|
||||
})(window);
|
||||
@@ -37,6 +37,9 @@ angular.scenario.Describe = function(descName, parent) {
|
||||
// Shared Unique ID generator for every describe block
|
||||
angular.scenario.Describe.id = 0;
|
||||
|
||||
// Shared Unique ID generator for every it (spec)
|
||||
angular.scenario.Describe.specId = 0;
|
||||
|
||||
/**
|
||||
* Defines a block to execute before each it or nested describe.
|
||||
*
|
||||
@@ -93,6 +96,7 @@ angular.scenario.Describe.prototype.xdescribe = angular.noop;
|
||||
*/
|
||||
angular.scenario.Describe.prototype.it = function(name, body) {
|
||||
this.its.push({
|
||||
id: angular.scenario.Describe.specId++,
|
||||
definition: this,
|
||||
only: this.only,
|
||||
name: name,
|
||||
|
||||
@@ -4,21 +4,26 @@
|
||||
* @param {Object} runner The scenario Runner instance to connect to.
|
||||
*
|
||||
* TODO(esprehn): Every output type creates one of these, but we probably
|
||||
* want one glonal shared instance. Need to handle events better too
|
||||
* want one global shared instance. Need to handle events better too
|
||||
* so the HTML output doesn't need to do spec model.getSpec(spec.id)
|
||||
* silliness.
|
||||
*
|
||||
* TODO(vojta) refactor on, emit methods (from all objects) - use inheritance
|
||||
*/
|
||||
angular.scenario.ObjectModel = function(runner) {
|
||||
var self = this;
|
||||
|
||||
this.specMap = {};
|
||||
this.listeners = [];
|
||||
this.value = {
|
||||
name: '',
|
||||
children: {}
|
||||
};
|
||||
|
||||
runner.on('SpecBegin', function(spec) {
|
||||
var block = self.value;
|
||||
var block = self.value,
|
||||
definitions = [];
|
||||
|
||||
angular.forEach(self.getDefinitionPath(spec), function(def) {
|
||||
if (!block.children[def.name]) {
|
||||
block.children[def.name] = {
|
||||
@@ -29,49 +34,78 @@ angular.scenario.ObjectModel = function(runner) {
|
||||
};
|
||||
}
|
||||
block = block.children[def.name];
|
||||
definitions.push(def.name);
|
||||
});
|
||||
self.specMap[spec.id] = block.specs[spec.name] =
|
||||
new angular.scenario.ObjectModel.Spec(spec.id, spec.name);
|
||||
|
||||
var it = self.specMap[spec.id] =
|
||||
block.specs[spec.name] =
|
||||
new angular.scenario.ObjectModel.Spec(spec.id, spec.name, definitions);
|
||||
|
||||
// forward the event
|
||||
self.emit('SpecBegin', it);
|
||||
});
|
||||
|
||||
runner.on('SpecError', function(spec, error) {
|
||||
var it = self.getSpec(spec.id);
|
||||
it.status = 'error';
|
||||
it.error = error;
|
||||
|
||||
// forward the event
|
||||
self.emit('SpecError', it, error);
|
||||
});
|
||||
|
||||
runner.on('SpecEnd', function(spec) {
|
||||
var it = self.getSpec(spec.id);
|
||||
complete(it);
|
||||
|
||||
// forward the event
|
||||
self.emit('SpecEnd', it);
|
||||
});
|
||||
|
||||
runner.on('StepBegin', function(spec, step) {
|
||||
var it = self.getSpec(spec.id);
|
||||
it.steps.push(new angular.scenario.ObjectModel.Step(step.name));
|
||||
var step = new angular.scenario.ObjectModel.Step(step.name);
|
||||
it.steps.push(step);
|
||||
|
||||
// forward the event
|
||||
self.emit('StepBegin', it, step);
|
||||
});
|
||||
|
||||
runner.on('StepEnd', function(spec, step) {
|
||||
var it = self.getSpec(spec.id);
|
||||
if (it.getLastStep().name !== step.name)
|
||||
throw 'Events fired in the wrong order. Step names don\' match.';
|
||||
complete(it.getLastStep());
|
||||
var step = it.getLastStep();
|
||||
if (step.name !== step.name)
|
||||
throw 'Events fired in the wrong order. Step names don\'t match.';
|
||||
complete(step);
|
||||
|
||||
// forward the event
|
||||
self.emit('StepEnd', it, step);
|
||||
});
|
||||
|
||||
runner.on('StepFailure', function(spec, step, error) {
|
||||
var it = self.getSpec(spec.id);
|
||||
var item = it.getLastStep();
|
||||
item.error = error;
|
||||
if (!it.status) {
|
||||
it.status = item.status = 'failure';
|
||||
}
|
||||
var it = self.getSpec(spec.id),
|
||||
modelStep = it.getLastStep();
|
||||
|
||||
modelStep.setErrorStatus('failure', error, step.line());
|
||||
it.setStatusFromStep(modelStep);
|
||||
|
||||
// forward the event
|
||||
self.emit('StepFailure', it, modelStep, error);
|
||||
});
|
||||
|
||||
runner.on('StepError', function(spec, step, error) {
|
||||
var it = self.getSpec(spec.id);
|
||||
var item = it.getLastStep();
|
||||
it.status = 'error';
|
||||
item.status = 'error';
|
||||
item.error = error;
|
||||
var it = self.getSpec(spec.id),
|
||||
modelStep = it.getLastStep();
|
||||
|
||||
modelStep.setErrorStatus('error', error, step.line());
|
||||
it.setStatusFromStep(modelStep);
|
||||
|
||||
// forward the event
|
||||
self.emit('StepError', it, modelStep, error);
|
||||
});
|
||||
|
||||
runner.on('RunnerEnd', function() {
|
||||
self.emit('RunnerEnd');
|
||||
});
|
||||
|
||||
function complete(item) {
|
||||
@@ -81,6 +115,36 @@ angular.scenario.ObjectModel = function(runner) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a listener for an event.
|
||||
*
|
||||
* @param {string} eventName Name of the event to add a handler for
|
||||
* @param {Function} listener Function that will be called when event is fired
|
||||
*/
|
||||
angular.scenario.ObjectModel.prototype.on = function(eventName, listener) {
|
||||
eventName = eventName.toLowerCase();
|
||||
this.listeners[eventName] = this.listeners[eventName] || [];
|
||||
this.listeners[eventName].push(listener);
|
||||
};
|
||||
|
||||
/**
|
||||
* Emits an event which notifies listeners and passes extra
|
||||
* arguments.
|
||||
*
|
||||
* @param {string} eventName Name of the event to fire.
|
||||
*/
|
||||
angular.scenario.ObjectModel.prototype.emit = function(eventName) {
|
||||
var self = this,
|
||||
args = Array.prototype.slice.call(arguments, 1),
|
||||
eventName = eventName.toLowerCase();
|
||||
|
||||
if (this.listeners[eventName]) {
|
||||
angular.forEach(this.listeners[eventName], function(listener) {
|
||||
listener.apply(self, args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the path of definition describe blocks that wrap around
|
||||
* this spec.
|
||||
@@ -113,12 +177,14 @@ angular.scenario.ObjectModel.prototype.getSpec = function(id) {
|
||||
*
|
||||
* @param {string} id Id of the spec
|
||||
* @param {string} name Name of the spec
|
||||
* @param {Array<string>=} definitionNames List of all describe block names that wrap this spec
|
||||
*/
|
||||
angular.scenario.ObjectModel.Spec = function(id, name) {
|
||||
angular.scenario.ObjectModel.Spec = function(id, name, definitionNames) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.startTime = new Date().getTime();
|
||||
this.steps = [];
|
||||
this.fullDefinitionName = (definitionNames || []).join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -142,6 +208,19 @@ angular.scenario.ObjectModel.Spec.prototype.getLastStep = function() {
|
||||
return this.steps[this.steps.length-1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Set status of the Spec from given Step
|
||||
*
|
||||
* @param {angular.scenario.ObjectModel.Step} step
|
||||
*/
|
||||
angular.scenario.ObjectModel.Spec.prototype.setStatusFromStep = function(step) {
|
||||
if (!this.status || step.status == 'error') {
|
||||
this.status = step.status;
|
||||
this.error = step.error;
|
||||
this.line = step.line;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A single step inside a Spec.
|
||||
*
|
||||
@@ -151,3 +230,16 @@ angular.scenario.ObjectModel.Step = function(name) {
|
||||
this.name = name;
|
||||
this.startTime = new Date().getTime();
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method for setting all error status related properties
|
||||
*
|
||||
* @param {string} status
|
||||
* @param {string} error
|
||||
* @param {string} line
|
||||
*/
|
||||
angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, error, line) {
|
||||
this.status = status;
|
||||
this.error = error;
|
||||
this.line = line;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
/**
|
||||
* Runner for scenarios.
|
||||
* Runner for scenarios
|
||||
*
|
||||
* Has to be initialized before any test is loaded,
|
||||
* because it publishes the API into window (global space).
|
||||
*/
|
||||
angular.scenario.Runner = function($window) {
|
||||
this.listeners = [];
|
||||
|
||||
@@ -87,17 +87,20 @@ angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialization function for the scenario runner.
|
||||
* Initialize the scenario runner and run !
|
||||
*
|
||||
* @param {angular.scenario.Runner} $scenario The runner to setup
|
||||
* @param {Object} config Config options
|
||||
* Access global window and document object
|
||||
* Access $runner through closure
|
||||
*
|
||||
* @param {Object=} config Config options
|
||||
*/
|
||||
function angularScenarioInit($scenario, config) {
|
||||
angular.scenario.setUpAndRun = function (config) {
|
||||
var href = window.location.href;
|
||||
var body = _jQuery(document.body);
|
||||
var output = [];
|
||||
var objModel = new angular.scenario.ObjectModel($runner);
|
||||
|
||||
if (config.scenario_output) {
|
||||
if (config && config.scenario_output) {
|
||||
output = config.scenario_output.split(',');
|
||||
}
|
||||
|
||||
@@ -105,7 +108,7 @@ function angularScenarioInit($scenario, config) {
|
||||
if (!output.length || indexOf(output,name) != -1) {
|
||||
var context = body.append('<div></div>').find('div:last');
|
||||
context.attr('id', name);
|
||||
fn.call({}, context, $scenario);
|
||||
fn.call({}, context, $runner, objModel);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -121,12 +124,12 @@ function angularScenarioInit($scenario, config) {
|
||||
var appFrame = body.append('<div id="application"></div>').find('#application');
|
||||
var application = new angular.scenario.Application(appFrame);
|
||||
|
||||
$scenario.on('RunnerEnd', function() {
|
||||
$runner.on('RunnerEnd', function() {
|
||||
appFrame.css('display', 'none');
|
||||
appFrame.find('iframe').attr('src', 'about:blank');
|
||||
});
|
||||
|
||||
$scenario.on('RunnerError', function(error) {
|
||||
$runner.on('RunnerError', function(error) {
|
||||
if (window.console) {
|
||||
console.log(formatException(error));
|
||||
} else {
|
||||
@@ -135,8 +138,8 @@ function angularScenarioInit($scenario, config) {
|
||||
}
|
||||
});
|
||||
|
||||
$scenario.run(application);
|
||||
}
|
||||
$runner.run(application);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates through list with iterator function that must call the
|
||||
|
||||
8
src/scenario/angular-bootstrap.js
vendored
8
src/scenario/angular-bootstrap.js
vendored
@@ -23,7 +23,8 @@
|
||||
try {
|
||||
if (previousOnLoad) previousOnLoad();
|
||||
} catch(e) {}
|
||||
angularScenarioInit($scenario, angularJsConfig(document));
|
||||
var config = angularJsConfig(document);
|
||||
if (config.autotest) angular.scenario.setUpAndRun(config);
|
||||
};
|
||||
|
||||
addCSS("../../css/angular-scenario.css");
|
||||
@@ -52,8 +53,7 @@
|
||||
// Create the runner (which also sets up the global API)
|
||||
document.write(
|
||||
'<script type="text/javascript">' +
|
||||
'var $scenario = new angular.scenario.Runner(window, angular.scenario.SpecRunner);' +
|
||||
'</script>'
|
||||
);
|
||||
' var $runner = new angular.scenario.Runner(window);' +
|
||||
'</script>');
|
||||
|
||||
})(window.onload);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
var $scenario = new angular.scenario.Runner(window);
|
||||
var $runner = new angular.scenario.Runner(window),
|
||||
config = angularJsConfig(document);
|
||||
|
||||
if (config.autotest) {
|
||||
jqLiteWrap(document).ready(function() {
|
||||
angularScenarioInit($scenario, angularJsConfig(document));
|
||||
angular.scenario.setUpAndRun(config);
|
||||
});
|
||||
|
||||
}
|
||||
})(window, document);
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
* TODO(esprehn): This should be refactored now that ObjectModel exists
|
||||
* to use angular bindings for the UI.
|
||||
*/
|
||||
angular.scenario.output('html', function(context, runner) {
|
||||
var model = new angular.scenario.ObjectModel(runner);
|
||||
angular.scenario.output('html', function(context, runner, model) {
|
||||
var specUiMap = {},
|
||||
lastStepUiMap = {};
|
||||
|
||||
context.append(
|
||||
'<div id="header">' +
|
||||
@@ -22,7 +23,7 @@ angular.scenario.output('html', function(context, runner) {
|
||||
);
|
||||
|
||||
runner.on('InteractiveWait', function(spec, step) {
|
||||
var ui = model.getSpec(spec.id).getLastStep().ui;
|
||||
var ui = lastStepUiMap[spec.id];
|
||||
ui.find('.test-title').
|
||||
html('waiting for you to <a href="javascript:resume()">resume</a>.');
|
||||
});
|
||||
@@ -58,59 +59,62 @@ angular.scenario.output('html', function(context, runner) {
|
||||
name.removeClass('closed').addClass('open');
|
||||
}
|
||||
});
|
||||
model.getSpec(spec.id).ui = ui;
|
||||
|
||||
specUiMap[spec.id] = ui;
|
||||
});
|
||||
|
||||
runner.on('SpecError', function(spec, error) {
|
||||
var ui = model.getSpec(spec.id).ui;
|
||||
var ui = specUiMap[spec.id];
|
||||
ui.append('<pre></pre>');
|
||||
ui.find('> pre').text(formatException(error));
|
||||
});
|
||||
|
||||
runner.on('SpecEnd', function(spec) {
|
||||
var ui = specUiMap[spec.id];
|
||||
spec = model.getSpec(spec.id);
|
||||
spec.ui.removeClass('status-pending');
|
||||
spec.ui.addClass('status-' + spec.status);
|
||||
spec.ui.find("> .test-info .timer-result").text(spec.duration + "ms");
|
||||
ui.removeClass('status-pending');
|
||||
ui.addClass('status-' + spec.status);
|
||||
ui.find("> .test-info .timer-result").text(spec.duration + "ms");
|
||||
if (spec.status === 'success') {
|
||||
spec.ui.find('> .test-info .test-name').addClass('closed');
|
||||
spec.ui.find('> .scrollpane .test-actions').hide();
|
||||
ui.find('> .test-info .test-name').addClass('closed');
|
||||
ui.find('> .scrollpane .test-actions').hide();
|
||||
}
|
||||
updateTotals(spec.status);
|
||||
});
|
||||
|
||||
runner.on('StepBegin', function(spec, step) {
|
||||
var ui = specUiMap[spec.id];
|
||||
spec = model.getSpec(spec.id);
|
||||
step = spec.getLastStep();
|
||||
spec.ui.find('> .scrollpane .test-actions').
|
||||
append('<li class="status-pending"></li>');
|
||||
step.ui = spec.ui.find('> .scrollpane .test-actions li:last');
|
||||
step.ui.append(
|
||||
ui.find('> .scrollpane .test-actions').append('<li class="status-pending"></li>');
|
||||
var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
|
||||
stepUi.append(
|
||||
'<div class="timer-result"></div>' +
|
||||
'<div class="test-title"></div>'
|
||||
);
|
||||
step.ui.find('> .test-title').text(step.name);
|
||||
var scrollpane = step.ui.parents('.scrollpane');
|
||||
stepUi.find('> .test-title').text(step.name);
|
||||
var scrollpane = stepUi.parents('.scrollpane');
|
||||
scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
|
||||
});
|
||||
|
||||
runner.on('StepFailure', function(spec, step, error) {
|
||||
var ui = model.getSpec(spec.id).getLastStep().ui;
|
||||
var ui = lastStepUiMap[spec.id];
|
||||
addError(ui, step.line, error);
|
||||
});
|
||||
|
||||
runner.on('StepError', function(spec, step, error) {
|
||||
var ui = model.getSpec(spec.id).getLastStep().ui;
|
||||
var ui = lastStepUiMap[spec.id];
|
||||
addError(ui, step.line, error);
|
||||
});
|
||||
|
||||
runner.on('StepEnd', function(spec, step) {
|
||||
var stepUi = lastStepUiMap[spec.id];
|
||||
spec = model.getSpec(spec.id);
|
||||
step = spec.getLastStep();
|
||||
step.ui.find('.timer-result').text(step.duration + 'ms');
|
||||
step.ui.removeClass('status-pending');
|
||||
step.ui.addClass('status-' + step.status);
|
||||
var scrollpane = spec.ui.find('> .scrollpane');
|
||||
stepUi.find('.timer-result').text(step.duration + 'ms');
|
||||
stepUi.removeClass('status-pending');
|
||||
stepUi.addClass('status-' + step.status);
|
||||
var scrollpane = specUiMap[spec.id].find('> .scrollpane');
|
||||
scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
|
||||
});
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/**
|
||||
* Generates JSON output into a context.
|
||||
*/
|
||||
angular.scenario.output('json', function(context, runner) {
|
||||
var model = new angular.scenario.ObjectModel(runner);
|
||||
|
||||
runner.on('RunnerEnd', function() {
|
||||
angular.scenario.output('json', function(context, runner, model) {
|
||||
model.on('RunnerEnd', function() {
|
||||
context.text(angular.toJson(model.value));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Creates a global value $result with the result of the runner.
|
||||
*/
|
||||
angular.scenario.output('object', function(context, runner) {
|
||||
runner.$window.$result = new angular.scenario.ObjectModel(runner).value;
|
||||
angular.scenario.output('object', function(context, runner, model) {
|
||||
runner.$window.$result = model.value;
|
||||
});
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/**
|
||||
* Generates XML output into a context.
|
||||
*/
|
||||
angular.scenario.output('xml', function(context, runner) {
|
||||
var model = new angular.scenario.ObjectModel(runner);
|
||||
angular.scenario.output('xml', function(context, runner, model) {
|
||||
var $ = function(args) {return new context.init(args);};
|
||||
runner.on('RunnerEnd', function() {
|
||||
model.on('RunnerEnd', function() {
|
||||
var scenario = $('<scenario></scenario>');
|
||||
context.append(scenario);
|
||||
serializeXml(scenario, model.value);
|
||||
|
||||
7
test-scenario.sh
Executable file
7
test-scenario.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
tests=$1
|
||||
if [[ $tests = "" ]]; then
|
||||
tests="all"
|
||||
fi
|
||||
|
||||
java -jar lib/jstestdriver/JsTestDriver.jar --tests "$tests" --config jsTestDriver-scenario.conf --reset
|
||||
320
test/jstd-scenario-adapter/AdapterSpecs.js
Normal file
320
test/jstd-scenario-adapter/AdapterSpecs.js
Normal file
@@ -0,0 +1,320 @@
|
||||
describe('jstd-adapter', function() {
|
||||
var fakeJSTD = { pluginRegistrar: { register: function() {} } },
|
||||
originalNavigateTo = angular.scenario.Application.prototype.navigateTo;
|
||||
|
||||
/**
|
||||
* Reverts hack on angular.scenario.Application.navigateTo
|
||||
* We should revert this hack after any single call of initScenarioAdapter,
|
||||
* so that it doesn't influence other tests...
|
||||
*/
|
||||
function revertNavigateToHack() {
|
||||
angular.scenario.Application.prototype.navigateTo = originalNavigateTo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for building angular.scenario.ObjectModel.Spec
|
||||
* @returns {angular.scenario.ObjectModel.Spec}
|
||||
*/
|
||||
function buildSpec(status, name, duration, definitions, error, line) {
|
||||
var spec = new angular.scenario.ObjectModel.Spec(
|
||||
'fake-id', name || 'name', definitions || ['desc1', 'desc2']);
|
||||
spec.duration = duration || 10;
|
||||
spec.status = status || 'success';
|
||||
spec.error = error || '';
|
||||
spec.line = line || '';
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for building angular.scenario.ObjectModel.Spec with error and error line
|
||||
* @returns {angular.scenario.ObjectModel.Spec}
|
||||
*/
|
||||
function buildErrorSpec(error, line, status, name) {
|
||||
return buildSpec(status || 'error', name, null, null, error, line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for building TestConfiguration
|
||||
* @returns {jstestdriver.TestRunConfiguration}
|
||||
*/
|
||||
function buildTestConf(type) {
|
||||
return new jstestdriver.TestRunConfiguration(
|
||||
new jstestdriver.TestCaseInfo('Fake test - ' + Math.random(), function(){}, type), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for building SCENARIO TestConfiguration
|
||||
* @returns {jstestdriver.TestRunConfiguration}
|
||||
*/
|
||||
function buildScenarioTestConf() {
|
||||
return buildTestConf(SCENARIO_TYPE);
|
||||
}
|
||||
|
||||
describe('initScenarioAdapter', function() {
|
||||
afterEach(revertNavigateToHack);
|
||||
|
||||
it('should create and register plugin if jstestdriver defined', function() {
|
||||
spyOn(fakeJSTD.pluginRegistrar, 'register');
|
||||
initScenarioAdapter(fakeJSTD);
|
||||
expect(fakeJSTD.pluginRegistrar.register).toHaveBeenCalled();
|
||||
expect(fakeJSTD.pluginRegistrar.register.mostRecentCall.args[0] instanceof JstdPlugin);
|
||||
});
|
||||
|
||||
it('should do nothing if jstestdriver not defined', function() {
|
||||
expect(function() {
|
||||
initScenarioAdapter(undefined);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should set setUpAndRun callback to plugin', function() {
|
||||
var runFn = jasmine.createSpy('setUpAndRun');
|
||||
plugin.runScenario = null;
|
||||
|
||||
initScenarioAdapter(fakeJSTD, runFn);
|
||||
expect(plugin.runScenario).toBe(runFn);
|
||||
});
|
||||
|
||||
describe('navigateTo', function() {
|
||||
var fakeJSTD = { pluginRegistrar: { register: function() {} } },
|
||||
app = new angular.scenario.Application(_jQuery('<div></div>')),
|
||||
navigateSpy;
|
||||
|
||||
beforeEach(function() {
|
||||
navigateSpy = spyOn(angular.scenario.Application.prototype, 'navigateTo');
|
||||
});
|
||||
|
||||
it('should add url prefix when jstd defined', function() {
|
||||
initScenarioAdapter(fakeJSTD, null, {relativeUrlPrefix: '/prefix/'});
|
||||
|
||||
app.navigateTo('test.html');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('/prefix/test.html');
|
||||
});
|
||||
|
||||
it('should add forward-slash as default url prefix when jstd defined', function() {
|
||||
initScenarioAdapter(fakeJSTD);
|
||||
|
||||
app.navigateTo('test.html');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('/test.html');
|
||||
});
|
||||
|
||||
it('should not change url when jstd not defined', function() {
|
||||
initScenarioAdapter(null);
|
||||
|
||||
app.navigateTo('test.html');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('test.html');
|
||||
});
|
||||
|
||||
it('should not change hash url', function() {
|
||||
initScenarioAdapter(fakeJSTD);
|
||||
|
||||
app.navigateTo('#/index.html/a');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('#/index.html/a');
|
||||
});
|
||||
|
||||
it('should not change absolute url', function() {
|
||||
initScenarioAdapter(fakeJSTD);
|
||||
|
||||
app.navigateTo('/index.html/a');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('/index.html/a');
|
||||
});
|
||||
|
||||
it('should not change "about:blank" url', function() {
|
||||
initScenarioAdapter(fakeJSTD);
|
||||
|
||||
app.navigateTo('about:blank');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('about:blank');
|
||||
});
|
||||
|
||||
it('should not change url with domain', function() {
|
||||
initScenarioAdapter(fakeJSTD);
|
||||
|
||||
app.navigateTo('http://www.google.com');
|
||||
expect(navigateSpy).toHaveBeenCalled();
|
||||
expect(navigateSpy.mostRecentCall.args[0]).toEqual('http://www.google.com');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('JstdPlugin', function() {
|
||||
var p;
|
||||
|
||||
beforeEach(function() {
|
||||
p = new JstdPlugin();
|
||||
});
|
||||
|
||||
describe('runTestConfiguration', function() {
|
||||
var initScenarioSpy, onTestSpy, onAllTestsSpy, spec, modelSpec;
|
||||
|
||||
beforeEach(function() {
|
||||
initScenarioSpy = jasmine.createSpy('initScenarioAndRun');
|
||||
onTestSpy = jasmine.createSpy('onOneTest');
|
||||
onAllTestsSpy = jasmine.createSpy('onAllTests');
|
||||
|
||||
p.runScenario = initScenarioSpy;
|
||||
spec = {id: 'fake', name: 'Spec Name'};
|
||||
modelSpec = new angular.scenario.ObjectModel.Spec(spec.id, spec.name);
|
||||
});
|
||||
|
||||
it('should ignore non scenario test cases', function() {
|
||||
expect(p.runTestConfiguration(buildTestConf(), onTestSpy, onAllTestsSpy)).toBe(false);
|
||||
expect(p.runTestConfiguration(buildTestConf('async'), onTestSpy, onAllTestsSpy)).toBe(false);
|
||||
expect(initScenarioSpy).not.toHaveBeenCalled();
|
||||
expect(onTestSpy).not.toHaveBeenCalled();
|
||||
expect(onAllTestsSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should return true when scenario test case', function() {
|
||||
expect(p.runTestConfiguration(buildScenarioTestConf(), onTestSpy, onAllTestsSpy)).toBe(true);
|
||||
});
|
||||
|
||||
it('should call initAndRunTests when scenario test case', function() {
|
||||
p.runTestConfiguration(buildScenarioTestConf(), onTestSpy, onAllTestsSpy);
|
||||
expect(initScenarioSpy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTestRunsConfigurationFor', function() {
|
||||
it('should add TestRunConfiguration with SCENARIO_TYPE TestCase', function() {
|
||||
var configurations = [];
|
||||
p.getTestRunsConfigurationFor(null, null, configurations);
|
||||
|
||||
expect(configurations.length).toBe(1);
|
||||
expect(configurations[0] instanceof jstestdriver.TestRunConfiguration).toBe(true);
|
||||
expect(configurations[0].getTestCaseInfo().getType()).toEqual(SCENARIO_TYPE);
|
||||
});
|
||||
|
||||
it('should always return true', function() {
|
||||
expect(p.getTestRunsConfigurationFor(null, null, [])).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('createTestResultFromSpec', function() {
|
||||
it('should return jstestdriver.TestResult instance', function() {
|
||||
expect(createTestResultFromSpec(buildSpec()) instanceof jstestdriver.TestResult).toBe(true);
|
||||
});
|
||||
|
||||
it('should set proper test name', function() {
|
||||
expect(createTestResultFromSpec(buildSpec()).testName).toEqual('name');
|
||||
});
|
||||
|
||||
it('should set duration', function() {
|
||||
expect(createTestResultFromSpec(buildSpec()).time).toEqual(10);
|
||||
});
|
||||
|
||||
it('should set test case - full definition name', function() {
|
||||
var spec = buildSpec();
|
||||
expect(createTestResultFromSpec(spec).testCaseName).toEqual(spec.fullDefinitionName);
|
||||
});
|
||||
|
||||
it('should set passed result when success', function() {
|
||||
expect(createTestResultFromSpec(buildSpec('success')).result)
|
||||
.toEqual(jstestdriver.TestResult.RESULT.PASSED);
|
||||
});
|
||||
|
||||
it('should set error result when error', function() {
|
||||
expect(createTestResultFromSpec(buildSpec('error')).result)
|
||||
.toEqual(jstestdriver.TestResult.RESULT.ERROR);
|
||||
});
|
||||
|
||||
it('should set failed result when failure', function() {
|
||||
expect(createTestResultFromSpec(buildSpec('failure')).result)
|
||||
.toEqual(jstestdriver.TestResult.RESULT.FAILED);
|
||||
});
|
||||
|
||||
it('should set error message when error/failure', function() {
|
||||
expect(createTestResultFromSpec(buildErrorSpec('error-message')).message)
|
||||
.toEqual('error-message');
|
||||
});
|
||||
|
||||
it('should log line number when error/failure', function() {
|
||||
expect(createTestResultFromSpec(buildErrorSpec('msg', 'line-number')).log)
|
||||
.toEqual('line-number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('angular.scenario.output.jstd', function() {
|
||||
var model;
|
||||
|
||||
beforeEach(function() {
|
||||
var runner = new angular.scenario.testing.MockRunner(),
|
||||
context = _jQuery("<div></div>");
|
||||
|
||||
plugin = new JstdPlugin();
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
angular.scenario.output.jstd(context, runner, model);
|
||||
|
||||
spyOn(plugin, 'reportEnd');
|
||||
spyOn(plugin, 'reportResult');
|
||||
});
|
||||
|
||||
it('should report end of all tests', function() {
|
||||
model.emit('RunnerEnd');
|
||||
expect(plugin.reportEnd).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should report jstestdriver.TestResult', function() {
|
||||
model.emit('SpecEnd', buildSpec());
|
||||
expect(plugin.reportResult).toHaveBeenCalled();
|
||||
expect(plugin.reportResult.argsForCall[0][0] instanceof jstestdriver.TestResult).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// couple of higher level tests (wiring objects together)
|
||||
describe('HIGHER LEVEL', function() {
|
||||
var initScenarioSpy, onTestSpy, onAllTestsSpy, model;
|
||||
|
||||
beforeEach(function() {
|
||||
plugin = new JstdPlugin();
|
||||
initScenarioSpy = jasmine.createSpy('initScenarioAndRun');
|
||||
onTestSpy = jasmine.createSpy('onOneTest');
|
||||
onAllTestsSpy = jasmine.createSpy('onAllTests');
|
||||
|
||||
var runner = new angular.scenario.testing.MockRunner(),
|
||||
context = _jQuery("<div></div>");
|
||||
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
angular.scenario.output.jstd(context, runner, model);
|
||||
|
||||
initScenarioAdapter(fakeJSTD, initScenarioSpy);
|
||||
plugin.runTestConfiguration(buildScenarioTestConf(), onTestSpy, onAllTestsSpy);
|
||||
});
|
||||
|
||||
afterEach(revertNavigateToHack);
|
||||
|
||||
it('should report and of test suite', function() {
|
||||
model.emit('RunnerEnd');
|
||||
expect(onAllTestsSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should report success test result', function() {
|
||||
model.emit('SpecEnd', buildSpec('success', 'name'));
|
||||
expect(onTestSpy).toHaveBeenCalled();
|
||||
var result = onTestSpy.argsForCall[0][0];
|
||||
expect(result instanceof jstestdriver.TestResult).toBe(true);
|
||||
expect(result.testName).toEqual('name');
|
||||
expect(result.result).toEqual(jstestdriver.TestResult.RESULT.PASSED);
|
||||
});
|
||||
|
||||
it('should report error test result', function() {
|
||||
model.emit('SpecEnd', buildSpec('error'));
|
||||
expect(onTestSpy).toHaveBeenCalled();
|
||||
var result = onTestSpy.argsForCall[0][0];
|
||||
expect(result.result).toEqual(jstestdriver.TestResult.RESULT.ERROR);
|
||||
});
|
||||
|
||||
it('should report failed test result', function() {
|
||||
model.emit('SpecEnd', buildSpec('failure'));
|
||||
expect(onTestSpy).toHaveBeenCalled();
|
||||
var result = onTestSpy.argsForCall[0][0];
|
||||
expect(result.result).toEqual(jstestdriver.TestResult.RESULT.FAILED);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -107,4 +107,14 @@ describe('angular.scenario.Describe', function() {
|
||||
var b = new angular.scenario.Describe();
|
||||
expect(a.id).toNotEqual(b.id);
|
||||
});
|
||||
|
||||
it('should create uniqueIds for each spec', function() {
|
||||
var d = new angular.scenario.Describe();
|
||||
d.it('fake', function() {});
|
||||
d.it('fake', function() {});
|
||||
|
||||
expect(d.its[0].id).toBeDefined();
|
||||
expect(d.its[1].id).toBeDefined();
|
||||
expect(d.its[0].id).not.toEqual(d.its[1].id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,18 +3,36 @@ describe('angular.scenario.ObjectModel', function() {
|
||||
var runner;
|
||||
var spec, step;
|
||||
|
||||
beforeEach(function() {
|
||||
spec = {
|
||||
name: 'test spec',
|
||||
function buildSpec(id, name, definitions) {
|
||||
var spec = {
|
||||
id: id,
|
||||
name: name,
|
||||
definition: {
|
||||
id: 10,
|
||||
name: 'describe 1'
|
||||
name: definitions.shift()
|
||||
}
|
||||
};
|
||||
step = {
|
||||
name: 'test step',
|
||||
line: function() { return ''; }
|
||||
var currentDef = spec.definition;
|
||||
|
||||
forEach(definitions, function(defName) {
|
||||
currentDef.parent = {
|
||||
name: defName
|
||||
};
|
||||
currentDef = currentDef.parent;
|
||||
});
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
function buildStep(name, line) {
|
||||
return {
|
||||
name: name || 'test step',
|
||||
line: function() { return line || ''; }
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
spec = buildSpec(1, 'test spec', ['describe 1']);
|
||||
step = buildStep();
|
||||
runner = new angular.scenario.testing.MockRunner();
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
});
|
||||
@@ -27,23 +45,28 @@ describe('angular.scenario.ObjectModel', function() {
|
||||
});
|
||||
|
||||
it('should add spec and create describe blocks on SpecBegin event', function() {
|
||||
runner.emit('SpecBegin', {
|
||||
name: 'test spec',
|
||||
definition: {
|
||||
id: 10,
|
||||
name: 'describe 2',
|
||||
parent: {
|
||||
id: 12,
|
||||
name: 'describe 1'
|
||||
}
|
||||
}
|
||||
});
|
||||
runner.emit('SpecBegin', buildSpec(1, 'test spec', ['describe 2', 'describe 1']));
|
||||
|
||||
expect(model.value.children['describe 1']).toBeDefined();
|
||||
expect(model.value.children['describe 1'].children['describe 2']).toBeDefined();
|
||||
expect(model.value.children['describe 1'].children['describe 2'].specs['test spec']).toBeDefined();
|
||||
});
|
||||
|
||||
it('should set fullDefinitionName on SpecBegin event', function() {
|
||||
runner.emit('SpecBegin', buildSpec(1, 'fake spec', ['describe 2']));
|
||||
var spec = model.getSpec(1);
|
||||
|
||||
expect(spec.fullDefinitionName).toBeDefined();
|
||||
expect(spec.fullDefinitionName).toEqual('describe 2');
|
||||
});
|
||||
|
||||
it('should set fullDefinitionName on SpecBegin event (join more names by space)', function() {
|
||||
runner.emit('SpecBegin', buildSpec(1, 'fake spec', ['describe 2', 'describe 1']));
|
||||
var spec = model.getSpec(1);
|
||||
|
||||
expect(spec.fullDefinitionName).toEqual('describe 1 describe 2');
|
||||
});
|
||||
|
||||
it('should add step to spec on StepBegin', function() {
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
@@ -109,4 +132,200 @@ describe('angular.scenario.ObjectModel', function() {
|
||||
|
||||
expect(model.value.children['describe 1'].specs['test spec'].status).toEqual('error');
|
||||
});
|
||||
|
||||
describe('events', function() {
|
||||
var Spec = angular.scenario.ObjectModel.Spec,
|
||||
Step = angular.scenario.ObjectModel.Step,
|
||||
callback;
|
||||
|
||||
beforeEach(function() {
|
||||
callback = jasmine.createSpy('listener');
|
||||
});
|
||||
|
||||
it('should provide method for registering a listener', function() {
|
||||
expect(model.on).toBeDefined();
|
||||
expect(model.on instanceof Function).toBe(true);
|
||||
});
|
||||
|
||||
it('should forward SpecBegin event', function() {
|
||||
model.on('SpecBegin', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward SpecBegin event with ObjectModel.Spec as a param', function() {
|
||||
model.on('SpecBegin', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
|
||||
expect(callback.mostRecentCall.args[0] instanceof Spec).toBe(true);
|
||||
expect(callback.mostRecentCall.args[0].name).toEqual(spec.name);
|
||||
});
|
||||
|
||||
it('should forward SpecError event', function() {
|
||||
model.on('SpecError', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('SpecError', spec, {});
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward SpecError event with ObjectModel.Spec and error as a params', function() {
|
||||
var error = {};
|
||||
model.on('SpecError', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('SpecError', spec, error);
|
||||
|
||||
var param = callback.mostRecentCall.args[0];
|
||||
expect(param instanceof Spec).toBe(true);
|
||||
expect(param.name).toEqual(spec.name);
|
||||
expect(param.status).toEqual('error');
|
||||
expect(param.error).toBe(error);
|
||||
});
|
||||
|
||||
it('should forward SpecEnd event', function() {
|
||||
model.on('SpecEnd', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('SpecEnd', spec);
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward SpecEnd event with ObjectModel.Spec as a param', function() {
|
||||
model.on('SpecEnd', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('SpecEnd', spec);
|
||||
|
||||
expect(callback.mostRecentCall.args[0] instanceof Spec).toBe(true);
|
||||
expect(callback.mostRecentCall.args[0].name).toEqual(spec.name);
|
||||
});
|
||||
|
||||
it('should forward StepBegin event', function() {
|
||||
model.on('StepBegin', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward StepBegin event with Spec and Step as params', function() {
|
||||
model.on('StepBegin', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
|
||||
var params = callback.mostRecentCall.args;
|
||||
expect(params[0] instanceof Spec).toBe(true);
|
||||
expect(params[0].name).toEqual(spec.name);
|
||||
expect(params[1] instanceof Step).toBe(true);
|
||||
});
|
||||
|
||||
it('should forward StepError event', function() {
|
||||
model.on('StepError', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepError', spec, step, {});
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward StepError event with Spec, Step and error as params', function() {
|
||||
var error = {};
|
||||
model.on('StepError', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepError', spec, step, error);
|
||||
|
||||
var params = callback.mostRecentCall.args;
|
||||
expect(params[0] instanceof Spec).toBe(true);
|
||||
expect(params[0].name).toEqual(spec.name);
|
||||
expect(params[1] instanceof Step).toBe(true);
|
||||
expect(params[1].status).toEqual('error');
|
||||
expect(params[2]).toBe(error);
|
||||
});
|
||||
|
||||
it('should forward StepFailure event', function() {
|
||||
model.on('StepFailure', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepFailure', spec, step, {});
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward StepFailure event with Spec, Step and error as params', function() {
|
||||
var error = {};
|
||||
model.on('StepFailure', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepFailure', spec, step, error);
|
||||
|
||||
var params = callback.mostRecentCall.args;
|
||||
expect(params[0] instanceof Spec).toBe(true);
|
||||
expect(params[0].name).toEqual(spec.name);
|
||||
expect(params[1] instanceof Step).toBe(true);
|
||||
expect(params[1].status).toEqual('failure');
|
||||
expect(params[2]).toBe(error);
|
||||
});
|
||||
|
||||
it('should forward StepEnd event', function() {
|
||||
model.on('StepEnd', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepEnd', spec, step);
|
||||
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should forward StepEnd event with Spec and Step as params', function() {
|
||||
model.on('StepEnd', callback);
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepEnd', spec, step);
|
||||
|
||||
var params = callback.mostRecentCall.args;
|
||||
expect(params[0] instanceof Spec).toBe(true);
|
||||
expect(params[0].name).toEqual(spec.name);
|
||||
expect(params[1] instanceof Step).toBe(true);
|
||||
});
|
||||
|
||||
it('should forward RunnerEnd event', function() {
|
||||
model.on('RunnerEnd', callback);
|
||||
runner.emit('RunnerEnd');
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set error of first failure', function() {
|
||||
var error = 'first-error',
|
||||
step2 = buildStep();
|
||||
|
||||
model.on('SpecEnd', function(spec) {
|
||||
expect(spec.error).toBeDefined();
|
||||
expect(spec.error).toBe(error);
|
||||
});
|
||||
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepFailure', spec, step, error);
|
||||
runner.emit('StepBegin', spec, step2);
|
||||
runner.emit('StepFailure', spec, step2, 'second-error');
|
||||
runner.emit('SpecEnd', spec);
|
||||
});
|
||||
|
||||
it('should set line number of first failure', function() {
|
||||
var step = buildStep('fake', 'first-line'),
|
||||
step2 = buildStep('fake2', 'second-line');
|
||||
|
||||
model.on('SpecEnd', function(spec) {
|
||||
expect(spec.line).toBeDefined();
|
||||
expect(spec.line).toBe('first-line');
|
||||
});
|
||||
|
||||
runner.emit('SpecBegin', spec);
|
||||
runner.emit('StepBegin', spec, step);
|
||||
runner.emit('StepFailure', spec, step, null);
|
||||
runner.emit('StepBegin', spec, step2);
|
||||
runner.emit('StepFailure', spec, step2, null);
|
||||
runner.emit('SpecEnd', spec);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
describe('angular.scenario.output.html', function() {
|
||||
var runner, spec, listeners;
|
||||
var runner, model, spec, listeners;
|
||||
var ui, context;
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -22,8 +22,9 @@ describe('angular.scenario.output.html', function() {
|
||||
line: function() { return 'unknown:-1'; }
|
||||
};
|
||||
runner = new angular.scenario.testing.MockRunner();
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
context = _jQuery("<div></div>");
|
||||
ui = angular.scenario.output.html(context, runner);
|
||||
ui = angular.scenario.output.html(context, runner, model);
|
||||
});
|
||||
|
||||
it('should create nested describe context', function() {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
describe('angular.scenario.output.json', function() {
|
||||
var output, context;
|
||||
var runner, $window;
|
||||
var runner, model, $window;
|
||||
var spec, step;
|
||||
|
||||
beforeEach(function() {
|
||||
$window = {};
|
||||
context = _jQuery('<div></div>');
|
||||
runner = new angular.scenario.testing.MockRunner();
|
||||
output = angular.scenario.output.json(context, runner);
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
output = angular.scenario.output.json(context, runner, model);
|
||||
spec = {
|
||||
name: 'test spec',
|
||||
definition: {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
describe('angular.scenario.output.object', function() {
|
||||
var output;
|
||||
var runner, $window;
|
||||
var runner, model, $window;
|
||||
var spec, step;
|
||||
|
||||
beforeEach(function() {
|
||||
$window = {};
|
||||
runner = new angular.scenario.testing.MockRunner();
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
runner.$window = $window;
|
||||
output = angular.scenario.output.object(null, runner);
|
||||
output = angular.scenario.output.object(null, runner, model);
|
||||
spec = {
|
||||
name: 'test spec',
|
||||
definition: {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
describe('angular.scenario.output.json', function() {
|
||||
var output, context;
|
||||
var runner, $window;
|
||||
var runner, model, $window;
|
||||
var spec, step;
|
||||
|
||||
beforeEach(function() {
|
||||
$window = {};
|
||||
context = _jQuery('<div></div>');
|
||||
runner = new angular.scenario.testing.MockRunner();
|
||||
output = angular.scenario.output.xml(context, runner);
|
||||
model = new angular.scenario.ObjectModel(runner);
|
||||
output = angular.scenario.output.xml(context, runner, model);
|
||||
spec = {
|
||||
name: 'test spec',
|
||||
definition: {
|
||||
|
||||
Reference in New Issue
Block a user