UNPKG

9.36 kBJavaScriptView Raw
1/* globals jasmine, describe, beforeEach, it, expect */
2var jasmineReporters = require('../index');
3var DOMParser = require('xmldom').DOMParser;
4
5var env, suite, subSuite, subSubSuite, siblingSuite,
6 reporter, writeCalls, suiteId=0, specId=0, noop=function(){};
7function fakeSpec(ste, name) {
8 var s = new jasmine.Spec({
9 env: env,
10 id: specId++,
11 description: name,
12 queueableFn: {fn: noop},
13 });
14 ste.addChild(s);
15 return s;
16}
17function fakeSuite(name, parentSuite) {
18 var s = new jasmine.Suite({
19 env: env,
20 id: suiteId++,
21 description: name,
22 parentSuite: parentSuite || jasmine.createSpy("pretend top suite") // I'm sure there's a good reason Jasmine does this...
23 });
24 if (parentSuite) {
25 parentSuite.addChild(s);
26 }
27 else {
28
29 env._suites = env._suites || [];
30 env._suites.push(s);
31 }
32 return s;
33}
34
35function setupReporterWithOptions(options) {
36 reporter = new jasmineReporters.NUnitXmlReporter(options);
37 reporter.writeFile = jasmine.createSpy();
38}
39
40// make sure reporter is set before calling this
41function triggerRunnerEvents() {
42 reporter.jasmineStarted();
43 for (var i=0; i<env._suites.length; i++) {
44 var s = env._suites[i];
45 triggerSuiteEvents(s);
46 }
47 reporter.jasmineDone();
48
49 // pre-parse some data to be used by various specs
50 writeCalls = reporter.writeFile.calls.all();
51 for (i=0; i<writeCalls.length; i++) {
52 writeCalls[i].output = writeCalls[i].args[0];
53 writeCalls[i].xmldoc = xmlDocumentFromString(writeCalls[i].output);
54 }
55}
56function triggerSuiteEvents(ste) {
57 reporter.suiteStarted(ste.result);
58 var thing;
59 for (var i=0; i<ste.children.length; i++) {
60 thing = ste.children[i];
61 if (thing instanceof jasmine.Suite) {
62 triggerSuiteEvents(thing);
63 } else {
64 reporter.specStarted(thing.result);
65 reporter.specDone(thing.result);
66 }
67 }
68 reporter.suiteDone(ste.result);
69}
70
71function xmlDocumentFromString(str) {
72 return (new DOMParser()).parseFromString(str, "text/xml");
73}
74
75describe("NUnitXmlReporter", function(){
76
77 beforeEach(function(){
78 env = new jasmine.Env();
79 suite = fakeSuite("ParentSuite");
80 subSuite = fakeSuite("SubSuite", suite);
81 subSubSuite = fakeSuite("SubSubSuite", subSuite);
82 siblingSuite = fakeSuite("SiblingSuite With Invalid Chars & < > \" ' | : \\ /");
83 fakeSpec(suite, "should be a dummy with invalid characters: & < >");
84 var failedSpec = fakeSpec(subSubSuite, "should be failed");
85 failedSpec.result.status = "failed";
86 failedSpec.result.failedExpectations.push({
87 passed: false,
88 message: "Expected true to be false.",
89 expected: false,
90 actual: true,
91 matcherName: 'toBe',
92 stack: "Stack trace! Stack trackes are cool & can have \"special\" characters <3\n\n Neat: yes."
93 });
94 fakeSpec(subSuite, "should be one level down");
95 fakeSpec(subSubSuite, "(1) should be two levels down");
96 fakeSpec(subSubSuite, "(2) should be two levels down");
97 fakeSpec(subSubSuite, "(3) should be two levels down");
98 fakeSpec(siblingSuite, "should be a sibling of Parent");
99 setupReporterWithOptions({reportName: "<Bad Character Report>"});
100 });
101
102 describe("constructor", function(){
103 beforeEach(function() {
104 setupReporterWithOptions();
105 });
106 it("should default path to an empty string", function(){
107 expect(reporter.savePath).toBe('');
108 });
109 it("should allow a custom path to be provided", function() {
110 setupReporterWithOptions({savePath:'/tmp'});
111 expect(reporter.savePath).toBe('/tmp');
112 });
113 it("should default filename to 'nunitresults.xml'", function(){
114 expect(reporter.filename).toBe("nunitresults.xml");
115 });
116 it("should allow a custom filename to be provided", function() {
117 setupReporterWithOptions({filename:'results.xml'});
118 expect(reporter.filename).toBe('results.xml');
119 });
120 it("should default reportName to 'Jasmine Results'", function(){
121 expect(reporter.reportName).toBe("Jasmine Results");
122 });
123 it("should allow a custom reportName to be provided", function() {
124 setupReporterWithOptions({reportName:"Test Results"});
125 expect(reporter.reportName).toBe("Test Results");
126 });
127 });
128
129 describe("generated xml output", function(){
130 var output, xmldoc;
131
132 beforeEach(function(){
133 triggerRunnerEvents();
134 output = writeCalls[0].output;
135 xmldoc = writeCalls[0].xmldoc;
136 });
137 it("should escape invalid xml chars from report name", function() {
138 expect(output).toContain('name="&lt;Bad Character Report&gt;"');
139 });
140 it("should escape invalid xml chars from suite names", function() {
141 expect(output).toContain('name="SiblingSuite With Invalid Chars &amp; &lt; &gt; &quot; &apos; | : \\ /"');
142 });
143 it("should escape invalid xml chars from spec names", function() {
144 expect(output).toContain('name="should be a dummy with invalid characters: &amp; &lt; &gt;');
145 });
146 describe("xml structure", function() {
147 var rootNode, suites, specs;
148 beforeEach(function() {
149 rootNode = xmldoc.getElementsByTagName("test-results")[0];
150 suites = rootNode.getElementsByTagName("test-suite");
151 specs = rootNode.getElementsByTagName("test-case");
152 });
153 it("should report the date / time that the tests were run", function() {
154 expect(rootNode.getAttribute("date")).toMatch(/\d{4}-\d{2}-\d{2}/);
155 expect(rootNode.getAttribute("time")).toMatch(/\d{2}:\d{2}:\d{2}/);
156 });
157 it("should report the appropriate number of suites", function() {
158 expect(suites.length).toBe(4);
159 });
160 it("should order suites appropriately", function() {
161 expect(suites[0].getAttribute("name")).toContain("ParentSuite");
162 expect(suites[1].getAttribute("name")).toContain("SubSuite");
163 expect(suites[2].getAttribute("name")).toContain("SubSubSuite");
164 expect(suites[3].getAttribute("name")).toContain("SiblingSuite");
165 });
166 it("should nest suites appropriately", function() {
167 expect(suites[0].parentNode).toBe(rootNode);
168 expect(suites[1].parentNode).toBe(suites[0].getElementsByTagName("results")[0]);
169 expect(suites[2].parentNode).toBe(suites[1].getElementsByTagName("results")[0]);
170 expect(suites[3].parentNode).toBe(rootNode);
171 });
172 it("should report the execution time for test specs", function() {
173 var time;
174 for (var i = 0; i < specs.length; i++) {
175 time = specs[i].getAttribute("time");
176 expect(time.length).toBeGreaterThan(0);
177 expect(time).not.toContain(":"); // as partial seconds, not a timestamp
178 }
179 });
180 it("should include a test-case for each spec and report the total number of specs on the root node", function() {
181 expect(rootNode.getAttribute("total")).toBe(specs.length.toString());
182 });
183 describe("passed specs", function() {
184 it("should indicate that the test case was successful", function() {
185 expect(specs[1].getAttribute("success")).toBe("true");
186 });
187 });
188 describe("failed specs", function() {
189 var failedSpec;
190 beforeEach(function() {
191 failedSpec = rootNode.getElementsByTagName("message")[0].parentNode.parentNode;
192 });
193 it("should indicate that the test case was not successful", function() {
194 expect(failedSpec.getAttribute("success")).toBe("false");
195 });
196 it("should include the error for failed specs", function() {
197 expect(failedSpec.getElementsByTagName("message")[0].textContent).toBe('Expected true to be false.');
198 });
199 it("should include the stack trace for failed specs", function() {
200 expect(failedSpec.getElementsByTagName("stack-trace")[0].textContent).toContain('cool & can have "special" characters <3');
201 });
202 it("should report the failure on ancestor suite nodes", function() {
203 var parentSuite = failedSpec.parentNode.parentNode;
204 var grandparentSuite = parentSuite.parentNode.parentNode;
205 expect(parentSuite.getAttribute("success")).toBe("false");
206 expect(grandparentSuite.getAttribute("success")).toBe("false");
207 });
208 it("should report the number of failed specs on the root node", function() {
209 expect(rootNode.getAttribute("failures")).toBe("1");
210 });
211 });
212 });
213 });
214});
215