1 | import sinon from 'sinon'
|
2 | import chalk from 'chalk'
|
3 | import SpecReporter from '../lib/reporter'
|
4 | import {
|
5 | SUITE, RESULTLIST, SUMMARY, ERRORS, ERRORLIST,
|
6 | STATS, STATS_WITH_NO_SPECS, SUITERESULT, JOBLINKRESULT,
|
7 | ERRORS_NO_STACK, ERRORLIST_NO_STACK, SUITES_SUMMARY,
|
8 | STATS_WITH_MULTIPLE_RUNNERS
|
9 | } from './fixtures'
|
10 |
|
11 | const baseReporter = {
|
12 | symbols: {
|
13 | ok: '✓',
|
14 | err: '✖',
|
15 | dot: '․',
|
16 | error: 'F'
|
17 | }
|
18 | }
|
19 | const reporter = new SpecReporter(baseReporter)
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | reporter.chalk = new chalk.constructor({level: 0})
|
25 |
|
26 | describe('spec reporter', () => {
|
27 | describe('the runner:start event', () => {
|
28 | it('should setup an initial state', () => {
|
29 | reporter.emit('runner:start', {
|
30 | cid: 42,
|
31 | specs: {
|
32 | a: false,
|
33 | b: 1
|
34 | }
|
35 | })
|
36 | reporter.suiteIndents[42].should.be.empty()
|
37 | reporter.indents[42].should.equal(0)
|
38 | reporter.specs[42].should.eql({
|
39 | a: false,
|
40 | b: 1
|
41 | })
|
42 | reporter.results[42].should.eql({
|
43 | passing: 0,
|
44 | pending: 0,
|
45 | failing: 0
|
46 | })
|
47 | })
|
48 | })
|
49 |
|
50 | describe('the runner:end event', () => {
|
51 | it('should print results', done => {
|
52 | const origPrintSuiteResult = reporter.printSuiteResult
|
53 | reporter.printSuiteResult = () => done()
|
54 | reporter.emit('runner:end', {
|
55 | cid: 42
|
56 | })
|
57 |
|
58 | reporter.printSuiteResult = origPrintSuiteResult
|
59 | })
|
60 | })
|
61 |
|
62 | describe('the suite:start event', () => {
|
63 | it('should increase indent', () => {
|
64 | reporter.emit('suite:start', {
|
65 | cid: 42,
|
66 | uid: '123'
|
67 | })
|
68 | reporter.suiteIndents[42][123].should.equal(1)
|
69 | reporter.indents[42].should.equal(1)
|
70 | })
|
71 | })
|
72 |
|
73 | describe('the suite:end event', () => {
|
74 | it('should decrease indent', () => {
|
75 | reporter.emit('suite:end', {
|
76 | cid: 42
|
77 | })
|
78 | reporter.indents[42].should.equal(0)
|
79 | })
|
80 | })
|
81 |
|
82 | describe('the test:pending event', () => {
|
83 | it('should increase pending tests', () => {
|
84 | reporter.emit('test:pending', {
|
85 | cid: 42
|
86 | })
|
87 | reporter.results[42].pending.should.equal(1)
|
88 | })
|
89 | })
|
90 |
|
91 | describe('the test:pass event', () => {
|
92 | it('should increase passing tests', () => {
|
93 | reporter.emit('test:pass', {
|
94 | cid: 42
|
95 | })
|
96 | reporter.results[42].passing.should.equal(1)
|
97 | })
|
98 | })
|
99 |
|
100 | describe('the test:fail event', () => {
|
101 | it('should increase failing tests', () => {
|
102 | reporter.emit('test:fail', {
|
103 | cid: 42
|
104 | })
|
105 | reporter.results[42].failing.should.equal(1)
|
106 | })
|
107 | })
|
108 |
|
109 | describe('the end event', () => {
|
110 | it('should print summary', done => {
|
111 | const origPrintSuitesSummary = reporter.printSuitesSummary
|
112 | reporter.printSuitesSummary = () => done()
|
113 | reporter.emit('end')
|
114 |
|
115 | reporter.printSuitesSummary = origPrintSuitesSummary
|
116 | })
|
117 | })
|
118 |
|
119 | describe('indent', () => {
|
120 | it('should return nothing if indent is 1', () => {
|
121 | reporter.suiteIndents[0] = {
|
122 | 'some spec title': 1
|
123 | }
|
124 | reporter.indent(0, 'some spec title').should.be.equal('')
|
125 | })
|
126 |
|
127 | it('should return correct indent', () => {
|
128 | reporter.suiteIndents[0] = {
|
129 | 'some spec title': 3
|
130 | }
|
131 | reporter.indent(0, 'some spec title').should.be.equal(' ')
|
132 | })
|
133 | })
|
134 |
|
135 | describe('getSymbol', () => {
|
136 | it('should return the right symbol', () => {
|
137 | reporter.getSymbol('pass').should.be.equal('✓')
|
138 | reporter.getSymbol('pending').should.be.equal('-')
|
139 |
|
140 | reporter.errorCount = 23
|
141 | reporter.getSymbol('fail').should.be.equal('24)')
|
142 | })
|
143 | })
|
144 |
|
145 | describe('getColor', () => {
|
146 | it('should return the right symbol', () => {
|
147 | reporter.getColor('pass').should.be.equal('green')
|
148 | reporter.getColor('passing').should.be.equal('green')
|
149 | reporter.getColor('pending').should.be.equal('cyan')
|
150 | reporter.getColor('fail').should.be.equal('red')
|
151 | reporter.getColor('fail').should.be.equal('red')
|
152 | reporter.getColor('failing').should.be.equal('red');
|
153 | (reporter.getColor('foobar') === null).should.be.true()
|
154 | })
|
155 | })
|
156 |
|
157 | describe('getBrowserCombo', () => {
|
158 | it('should return verbose desktop combo', () => {
|
159 | reporter.getBrowserCombo({
|
160 | browserName: 'chrome',
|
161 | version: 50,
|
162 | platform: 'Windows 8.1'
|
163 | }).should.be.equal('chrome (v50) on Windows 8.1')
|
164 | })
|
165 |
|
166 | it('should return preface desktop combo', () => {
|
167 | reporter.getBrowserCombo({
|
168 | browserName: 'chrome',
|
169 | version: 50,
|
170 | platform: 'Windows 8.1'
|
171 | }, false).should.be.equal('chrome 50 Windows 8.1')
|
172 | })
|
173 |
|
174 | it('should return verbose mobile combo', () => {
|
175 | reporter.getBrowserCombo({
|
176 | deviceName: 'iPhone 6 Plus',
|
177 | platformVersion: '9.2',
|
178 | platformName: 'iOS'
|
179 | }).should.be.equal('iPhone 6 Plus on iOS 9.2')
|
180 | })
|
181 |
|
182 | it('should return preface mobile combo', () => {
|
183 | reporter.getBrowserCombo({
|
184 | deviceName: 'iPhone 6 Plus',
|
185 | platformVersion: '9.2',
|
186 | platformName: 'iOS'
|
187 | }, false).should.be.equal('iPhone 6 Plus iOS 9.2')
|
188 | })
|
189 |
|
190 | it('should return verbose mobile combo executing an app', () => {
|
191 | reporter.getBrowserCombo({
|
192 | deviceName: 'iPhone 6 Plus',
|
193 | platformVersion: '9.2',
|
194 | platformName: 'iOS',
|
195 | app: 'sauce-storage:myApp.app'
|
196 | }).should.be.equal('iPhone 6 Plus on iOS 9.2 executing myApp.app')
|
197 | })
|
198 |
|
199 | it('should return preface mobile combo executing an app', () => {
|
200 | reporter.getBrowserCombo({
|
201 | deviceName: 'iPhone 6 Plus',
|
202 | platformVersion: '9.2',
|
203 | platformName: 'iOS',
|
204 | app: 'sauce-storage:myApp.app'
|
205 | }).should.be.equal('iPhone 6 Plus on iOS 9.2 executing myApp.app')
|
206 | }, false)
|
207 |
|
208 | it('should return verbose mobile combo executing a browser', () => {
|
209 | reporter.getBrowserCombo({
|
210 | deviceName: 'iPhone 6 Plus',
|
211 | platformVersion: '9.2',
|
212 | platformName: 'iOS',
|
213 | browserName: 'Safari'
|
214 | }).should.be.equal('iPhone 6 Plus on iOS 9.2 executing Safari')
|
215 | })
|
216 |
|
217 | it('should return preface mobile combo executing a browser', () => {
|
218 | reporter.getBrowserCombo({
|
219 | deviceName: 'iPhone 6 Plus',
|
220 | platformVersion: '9.2',
|
221 | platformName: 'iOS',
|
222 | browserName: 'Safari'
|
223 | }, false).should.be.equal('iPhone 6 Plus iOS 9.2')
|
224 | })
|
225 |
|
226 | it('should return verbose desktop combo when using BrowserStack capabilities', () => {
|
227 | reporter.getBrowserCombo({
|
228 | browser: 'Chrome',
|
229 | browser_version: 50,
|
230 | os: 'Windows',
|
231 | os_version: '10'
|
232 | }).should.be.equal('Chrome (v50) on Windows 10')
|
233 | })
|
234 |
|
235 | it('should return preface desktop combo when using BrowserStack capabilities', () => {
|
236 | reporter.getBrowserCombo({
|
237 | browser: 'Chrome',
|
238 | browser_version: 50,
|
239 | os: 'Windows',
|
240 | os_version: '10'
|
241 | }, false).should.be.equal('Chrome 50 Windows 10')
|
242 | })
|
243 | })
|
244 |
|
245 | describe('getResultList', () => {
|
246 | it('return a correct result list', () => {
|
247 | reporter.errorCount = 27
|
248 | reporter.suiteIndents[0] = {
|
249 | 'some foobar test': 0,
|
250 | 'some other foobar test': 1,
|
251 | 'some spec title': 0
|
252 | }
|
253 | reporter.getResultList(0, SUITE, 'kuckkuck> ').should.be.equal(RESULTLIST)
|
254 | })
|
255 | })
|
256 |
|
257 | describe('getSummary', () => {
|
258 | it('should return correct summary', () => {
|
259 | reporter.getSummary({
|
260 | passing: 3,
|
261 | pending: 1,
|
262 | failing: 2
|
263 | }, 139000, 'kuckkuck> ').should.be.equal(SUMMARY)
|
264 | })
|
265 |
|
266 | it('should skip if the count is zero', () => {
|
267 | reporter.getSummary({
|
268 | passing: 0
|
269 | }, 139000, 'kuckkuck> ').should.be.equal('')
|
270 | })
|
271 | })
|
272 |
|
273 | describe('getFailureList', () => {
|
274 | it('should return correct failure list', () => {
|
275 | reporter.getFailureList(ERRORS, 'kuckkuck> ').should.be.equal(ERRORLIST)
|
276 | })
|
277 |
|
278 | it('should handle error messages without a stack trace correctly', () => {
|
279 | reporter.getFailureList(ERRORS_NO_STACK, 'kuckkuck> ').should.be.equal(ERRORLIST_NO_STACK)
|
280 | })
|
281 | })
|
282 |
|
283 | describe('getJobLink', () => {
|
284 | it('should return nothing if host is not specified', () => {
|
285 | reporter.getJobLink({ config: {} }).should.be.equal('')
|
286 | })
|
287 |
|
288 | it('should return nothing if host is not known', () => {
|
289 | reporter.getJobLink({ config: { host: 'localhost' } }).should.be.equal('')
|
290 | })
|
291 |
|
292 | it('should display job link if host is saucelabs', () => {
|
293 | reporter.getJobLink({
|
294 | config: { host: 'ondemand.saucelabs.com' },
|
295 | sessionID: '12345-12345-12345'
|
296 | }, 'kuckkuck> ').should.be.equal(JOBLINKRESULT)
|
297 | })
|
298 | })
|
299 |
|
300 | describe('printSuiteResult', () => {
|
301 | let origConsoleLog
|
302 |
|
303 | before(() => {
|
304 | origConsoleLog = console.log
|
305 | })
|
306 |
|
307 | beforeEach(() => {
|
308 | console.log = sinon.spy()
|
309 | })
|
310 |
|
311 | afterEach(() => {
|
312 | console.log = origConsoleLog
|
313 | })
|
314 |
|
315 | it('should print correct suite result', () => {
|
316 | reporter.specs = { '22': '/path/to/spec.js' }
|
317 | reporter.baseReporter.stats = STATS
|
318 | reporter.getResultList = () => ''
|
319 | reporter.getSummary = () => ''
|
320 | reporter.getFailureList = () => ''
|
321 | reporter.getJobLink = () => ''
|
322 |
|
323 | reporter.printSuiteResult({ cid: 22 })
|
324 | const wasCalledCorrectly = console.log.calledWith(SUITERESULT)
|
325 |
|
326 | wasCalledCorrectly.should.be.ok()
|
327 | })
|
328 |
|
329 | it('should not print anything if no spec got executed', () => {
|
330 | reporter.specs = { '22': '/path/to/spec.js' }
|
331 | reporter.baseReporter.stats = STATS_WITH_NO_SPECS
|
332 | reporter.getResultList = () => ''
|
333 | reporter.getSummary = () => ''
|
334 | reporter.getFailureList = () => ''
|
335 | reporter.getJobLink = () => ''
|
336 |
|
337 | reporter.printSuiteResult({ cid: 22 })
|
338 | const wasCalledCorrectly = console.log.calledWith('')
|
339 |
|
340 | wasCalledCorrectly.should.be.ok()
|
341 | })
|
342 | })
|
343 |
|
344 | describe('printSuitesSummary', () => {
|
345 | let origConsoleLog
|
346 |
|
347 | before(() => {
|
348 | origConsoleLog = console.log
|
349 | })
|
350 |
|
351 | beforeEach(() => {
|
352 | console.log = sinon.spy()
|
353 | })
|
354 |
|
355 | afterEach(() => {
|
356 | console.log = origConsoleLog
|
357 | })
|
358 |
|
359 | it('should print summary of how many specs where run', () => {
|
360 | reporter.baseReporter.stats = STATS_WITH_MULTIPLE_RUNNERS
|
361 | reporter.baseReporter.epilogue = () => console.log('foobar')
|
362 |
|
363 | reporter.printSuitesSummary()
|
364 | const wasCalledCorrectly = console.log.calledWith(SUITES_SUMMARY)
|
365 |
|
366 | wasCalledCorrectly.should.be.ok()
|
367 | })
|
368 |
|
369 | it('should not print summary if only one spec was run', () => {
|
370 | reporter.baseReporter.stats = STATS
|
371 | reporter.baseReporter.epilogue = () => console.log('foobar')
|
372 |
|
373 | reporter.printSuitesSummary()
|
374 | const callCount = console.log.callCount
|
375 |
|
376 | callCount.should.be.equal(0)
|
377 | })
|
378 | })
|
379 | })
|