Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 1abdc09

Browse files
Vojta JinaIgorMinar
Vojta Jina
authored andcommitted
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
1 parent 9f56af9 commit 1abdc09

35 files changed

+1034
-121
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
<a name="0.9.16"><a/>
22
# <angular/> 0.9.16 weather-control (in-progress) #
33

4+
### Features
5+
- we can run scenario tests with jstd (from command line and in multiple browsers)
6+
47

8+
### Breaking changes
9+
- html scenario runner requires ng:autotest option to start tests automatically
510

611

712
<a name="0.9.15"><a/>

Rakefile

+29-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ ANGULAR_SCENARIO = [
5353
'src/scenario/output/Html.js',
5454
'src/scenario/output/Json.js',
5555
'src/scenario/output/Xml.js',
56-
'src/scenario/output/Object.js',
56+
'src/scenario/output/Object.js'
5757
]
5858

5959
BUILD_DIR = 'build'
@@ -94,6 +94,30 @@ task :compile_scenario => :init do
9494
end
9595
end
9696

97+
desc 'Compile JSTD Scenario Adapter'
98+
task :compile_jstd_scenario_adapter => :init do
99+
100+
deps = [
101+
'src/jstd-scenario-adapter/angular.prefix',
102+
'src/jstd-scenario-adapter/Adapter.js',
103+
'src/jstd-scenario-adapter/angular.suffix',
104+
]
105+
106+
concat = 'cat ' + deps.flatten.join(' ')
107+
108+
File.open(path_to('jstd-scenario-adapter.js'), 'w') do |f|
109+
f.write(%x{#{concat}})
110+
end
111+
112+
# TODO(vojta) use jstd configuration when implemented
113+
# (instead of including jstd-adapter-config.js)
114+
File.open(path_to('jstd-scenario-adapter-config.js'), 'w') do |f|
115+
f.write("/**\r\n" +
116+
" * Configuration for jstd scenario adapter \n */\n" +
117+
"var jstdScenarioAdapter = {\n relativeUrlPrefix: '/build/docs/'\n};\n")
118+
end
119+
end
120+
97121

98122
desc 'Generate IE css js patch'
99123
task :generate_ie_compat => :init do
@@ -152,7 +176,7 @@ end
152176

153177

154178
desc 'Compile JavaScript'
155-
task :compile => [:init, :compile_scenario, :generate_ie_compat] do
179+
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter, :generate_ie_compat] do
156180

157181
deps = [
158182
'src/angular.prefix',
@@ -195,7 +219,9 @@ task :package => [:clean, :compile, :docs] do
195219
path_to('angular.js'),
196220
path_to('angular.min.js'),
197221
path_to('angular-ie-compat.js'),
198-
path_to('angular-scenario.js')
222+
path_to('angular-scenario.js'),
223+
path_to('jstd-scenario-adapter.js'),
224+
path_to('jstd-scenario-adapter-config.js'),
199225
].each do |src|
200226
dest = src.gsub(/^[^\/]+\//, '').gsub(/((\.min)?\.js)$/, "-#{version}\\1")
201227
FileUtils.cp(src, pkg_dir + '/' + dest)

docs/cookbook.deeplinking.ngdoc

+4-4
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ In this example we have a simple app which consist of two screens:
3434

3535
The two partials are defined in the following URLs:
3636

37-
* {@link ./static/settings.html}
38-
* {@link ./static/welcome.html}
37+
* {@link ./examples/settings.html}
38+
* {@link ./examples/welcome.html}
3939

4040

4141
<doc:example>
@@ -44,8 +44,8 @@ The two partials are defined in the following URLs:
4444
AppCntl.$inject = ['$route']
4545
function AppCntl($route) {
4646
// define routes
47-
$route.when("", {template:'./static/welcome.html', controller:WelcomeCntl});
48-
$route.when("/settings", {template:'./static/settings.html', controller:SettingsCntl});
47+
$route.when("", {template:'./examples/welcome.html', controller:WelcomeCntl});
48+
$route.when("/settings", {template:'./examples/settings.html', controller:SettingsCntl});
4949
$route.parent(this);
5050

5151
// initialize the model to something useful
File renamed without changes.
File renamed without changes.

docs/src/gen-docs.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ var writes = callback.chain(function(){
2525
var metadata = ngdoc.metadata(docs);
2626
writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'], writes.waitFor());
2727
writer.copyDir('img', writes.waitFor());
28-
writer.copyDir('static', writes.waitFor());
29-
writer.copy('index.html', writes.waitFor());
30-
writer.copy('docs.js', writes.waitFor());
31-
writer.copy('docs.css', writes.waitFor());
32-
writer.copy('doc_widgets.js', writes.waitFor());
33-
writer.copy('doc_widgets.css', writes.waitFor());
34-
writer.copy('docs-scenario.html', writes.waitFor());
28+
writer.copyDir('examples', writes.waitFor());
29+
writer.copyTpl('index.html', writes.waitFor());
30+
writer.copyTpl('docs.js', writes.waitFor());
31+
writer.copyTpl('docs.css', writes.waitFor());
32+
writer.copyTpl('doc_widgets.js', writes.waitFor());
33+
writer.copyTpl('doc_widgets.css', writes.waitFor());
34+
writer.copyTpl('docs-scenario.html', writes.waitFor());
3535
writer.output('docs-scenario.js', ngdoc.scenarios(docs), writes.waitFor());
3636
writer.output('sitemap.xml', new SiteMap(docs).render(), writes.waitFor());
3737
writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n', writes.waitFor());
38-
writer.copy('syntaxhighlighter/shBrushJScript.js', writes.waitFor());
39-
writer.copy('syntaxhighlighter/shBrushXml.js', writes.waitFor());
40-
writer.copy('syntaxhighlighter/shCore.css', writes.waitFor());
41-
writer.copy('syntaxhighlighter/shCore.js', writes.waitFor());
42-
writer.copy('syntaxhighlighter/shThemeDefault.css', writes.waitFor());
43-
writer.copy('jquery.min.js', writes.waitFor());
38+
writer.copyTpl('syntaxhighlighter/shBrushJScript.js', writes.waitFor());
39+
writer.copyTpl('syntaxhighlighter/shBrushXml.js', writes.waitFor());
40+
writer.copyTpl('syntaxhighlighter/shCore.css', writes.waitFor());
41+
writer.copyTpl('syntaxhighlighter/shCore.js', writes.waitFor());
42+
writer.copyTpl('syntaxhighlighter/shThemeDefault.css', writes.waitFor());
43+
writer.copyTpl('jquery.min.js', writes.waitFor());
4444
});
4545
writes.onDone(function(){
4646
console.log('DONE. Generated ' + docs.length + ' pages in ' +

docs/src/templates/docs-scenario.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html xmlns:ng="http://angularjs.org" wiki:ng="http://angularjs.org">
33
<head>
44
<title>&lt;angular/&gt; Docs Scenario Runner</title>
5-
<script type="text/javascript" src="../angular-scenario.js" ng:autobind></script>
5+
<script type="text/javascript" src="../angular-scenario.js" ng:autotest></script>
66
<script type="text/javascript" src="docs-scenario.js"></script>
77
</head>
88
<body>

docs/src/writer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ exports.makeDir = function (path, callback) {
4949
})();
5050
};
5151

52-
exports.copy = function(filename, callback){
52+
exports.copyTpl = function(filename, callback) {
5353
copy('docs/src/templates/' + filename, OUTPUT_DIR + filename, callback);
5454
};
5555

example/personalLog/scenario/runner.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
33
<head>
44
<title>Personal Log Scenario Runner</title>
5-
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js"></script>
5+
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
66
<script type="text/javascript" src="personalLogScenario.js"></script>
77
</head>
88
<body>

jsTestDriver-scenario.conf

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
server: http://localhost:9877
2+
3+
load:
4+
- build/angular-scenario.js
5+
- build/jstd-scenario-adapter-config.js
6+
- build/jstd-scenario-adapter.js
7+
- build/docs/docs-scenario.js
8+
9+
proxy:
10+
- {matcher: "*", server: "http://localhost:8000"}

jsTestDriver.conf

+2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ load:
1313
- test/testabilityPatch.js
1414
- src/scenario/Scenario.js
1515
- src/scenario/output/*.js
16+
- src/jstd-scenario-adapter/*.js
1617
- src/scenario/*.js
1718
- src/angular-mocks.js
1819
- test/mocks.js
1920
- test/scenario/*.js
2021
- test/scenario/output/*.js
22+
- test/jstd-scenario-adapter/*.js
2123
- test/*.js
2224
- test/service/*.js
2325
- example/personalLog/test/*.js

scenario/Runner-compiled.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
22
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
33
<head>
4-
<script type="text/javascript" src="../build/angular-scenario.js"></script>
4+
<script type="text/javascript" src="../build/angular-scenario.js" ng:autotest></script>
55
<script type="text/javascript" src="widgets-scenario.js"></script>
66
</head>
77
<body>

scenario/Runner.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
22
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
33
<head>
4-
<script type="text/javascript" src="../src/scenario/angular-bootstrap.js"></script>
4+
<script type="text/javascript" src="../src/scenario/angular-bootstrap.js" ng:autotest></script>
55
<script type="text/javascript" src="widgets-scenario.js"></script>
66
</head>
77
<body>

server-scenario.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
java -jar lib/jstestdriver/JsTestDriver.jar --port 9877 --browserTimeout 90000 --config jsTestDriver-scenario.conf

src/jstd-scenario-adapter/Adapter.js

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/**
2+
* JSTestDriver adapter for angular scenario tests
3+
*
4+
* Example of jsTestDriver.conf for running scenario tests with JSTD:
5+
<pre>
6+
server: http://localhost:9877
7+
8+
load:
9+
- lib/angular-scenario.js
10+
- lib/jstd-scenario-adapter-config.js
11+
- lib/jstd-scenario-adapter.js
12+
# your test files go here #
13+
14+
proxy:
15+
- {matcher: "/your-prefix/*", server: "http://localhost:8000/"}
16+
</pre>
17+
*
18+
* For more information on how to configure jstd proxy, see {@link http://code.google.com/p/js-test-driver/wiki/Proxy}
19+
* Note the order of files - it's important !
20+
*
21+
* Example of jstd-scenario-adapter-config.js
22+
<pre>
23+
var jstdScenarioAdapter = {
24+
relativeUrlPrefix: '/your-prefix/'
25+
};
26+
</pre>
27+
*
28+
* Whenever you use <code>browser().navigateTo('relativeUrl')</code> in your scenario test, the relativeUrlPrefix will be prepended.
29+
* You have to configure this to work together with JSTD proxy.
30+
*
31+
* Let's assume you are using the above configuration (jsTestDriver.conf and jstd-scenario-adapter-config.js):
32+
* Now, when you call <code>browser().navigateTo('index.html')</code> in your scenario test, the browser will open /your-prefix/index.html.
33+
* That matches the proxy, so JSTD will proxy this request to http://localhost:8000/index.html.
34+
*/
35+
36+
/**
37+
* Custom type of test case
38+
*
39+
* @const
40+
* @see jstestdriver.TestCaseInfo
41+
*/
42+
var SCENARIO_TYPE = 'scenario';
43+
44+
/**
45+
* Plugin for JSTestDriver
46+
* Connection point between scenario's jstd output and jstestdriver.
47+
*
48+
* @see jstestdriver.PluginRegistrar
49+
*/
50+
function JstdPlugin() {
51+
var nop = function() {};
52+
53+
this.reportResult = nop;
54+
this.reportEnd = nop;
55+
this.runScenario = nop;
56+
57+
this.name = 'Angular Scenario Adapter';
58+
59+
/**
60+
* Called for each JSTD TestCase
61+
*
62+
* Handles only SCENARIO_TYPE test cases. There should be only one fake TestCase.
63+
* Runs all scenario tests (under one fake TestCase) and report all results to JSTD.
64+
*
65+
* @param {jstestdriver.TestRunConfiguration} configuration
66+
* @param {Function} onTestDone
67+
* @param {Function} onAllTestsComplete
68+
* @returns {boolean} True if this type of test is handled by this plugin, false otherwise
69+
*/
70+
this.runTestConfiguration = function(configuration, onTestDone, onAllTestsComplete) {
71+
if (configuration.getTestCaseInfo().getType() != SCENARIO_TYPE) return false;
72+
73+
this.reportResult = onTestDone;
74+
this.reportEnd = onAllTestsComplete;
75+
this.runScenario();
76+
77+
return true;
78+
};
79+
80+
this.getTestRunsConfigurationFor = function(testCaseInfos, expressions, testRunsConfiguration) {
81+
testRunsConfiguration.push(
82+
new jstestdriver.TestRunConfiguration(
83+
new jstestdriver.TestCaseInfo(
84+
'Angular Scenario Tests', function() {}, SCENARIO_TYPE), []));
85+
86+
return true;
87+
};
88+
}
89+
90+
/**
91+
* Singleton instance of the plugin
92+
* Accessed using closure by:
93+
* - jstd output (reports to this plugin)
94+
* - initScenarioAdapter (register the plugin to jstd)
95+
*/
96+
var plugin = new JstdPlugin();
97+
98+
/**
99+
* Initialise scenario jstd-adapter
100+
* (only if jstestdriver is defined)
101+
*
102+
* @param {Object} jstestdriver Undefined when run from browser (without jstd)
103+
* @param {Function} initScenarioAndRun Function that inits scenario and runs all the tests
104+
* @param {Object=} config Configuration object, supported properties:
105+
* - relativeUrlPrefix: prefix for all relative links when navigateTo()
106+
*/
107+
function initScenarioAdapter(jstestdriver, initScenarioAndRun, config) {
108+
if (jstestdriver) {
109+
// create and register ScenarioPlugin
110+
jstestdriver.pluginRegistrar.register(plugin);
111+
plugin.runScenario = initScenarioAndRun;
112+
113+
/**
114+
* HACK (angular.scenario.Application.navigateTo)
115+
*
116+
* We need to navigate to relative urls when running from browser (without JSTD),
117+
* because we want to allow running scenario tests without creating its own virtual host.
118+
* For example: http://angular.local/build/docs/docs-scenario.html
119+
*
120+
* On the other hand, when running with JSTD, we need to navigate to absolute urls,
121+
* because of JSTD proxy. (proxy, because of same domain policy)
122+
*
123+
* So this hack is applied only if running with JSTD and change all relative urls to absolute.
124+
*/
125+
var appProto = angular.scenario.Application.prototype,
126+
navigateTo = appProto.navigateTo,
127+
relativeUrlPrefix = config && config.relativeUrlPrefix || '/';
128+
129+
appProto.navigateTo = function(url, loadFn, errorFn) {
130+
if (url.charAt(0) != '/' && url.charAt(0) != '#' &&
131+
url != 'about:blank' && !url.match(/^https?/)) {
132+
url = relativeUrlPrefix + url;
133+
}
134+
135+
return navigateTo.call(this, url, loadFn, errorFn);
136+
};
137+
}
138+
}
139+
140+
/**
141+
* Builds proper TestResult object from given model spec
142+
*
143+
* TODO(vojta) report error details
144+
*
145+
* @param {angular.scenario.ObjectModel.Spec} spec
146+
* @returns {jstestdriver.TestResult}
147+
*/
148+
function createTestResultFromSpec(spec) {
149+
var map = {
150+
success: 'PASSED',
151+
error: 'ERROR',
152+
failure: 'FAILED'
153+
};
154+
155+
return new jstestdriver.TestResult(
156+
spec.fullDefinitionName,
157+
spec.name,
158+
jstestdriver.TestResult.RESULT[map[spec.status]],
159+
spec.error || '',
160+
spec.line || '',
161+
spec.duration);
162+
}
163+
164+
/**
165+
* Generates JSTD output (jstestdriver.TestResult)
166+
*/
167+
angular.scenario.output('jstd', function(context, runner, model) {
168+
model.on('SpecEnd', function(spec) {
169+
plugin.reportResult(createTestResultFromSpec(spec));
170+
});
171+
172+
model.on('RunnerEnd', function() {
173+
plugin.reportEnd();
174+
});
175+
});

0 commit comments

Comments
 (0)