How to use endVideoCapture method in Cypress

Best JavaScript code snippet using cypress

Run Cypress automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

video_capture.js

Source: video_capture.js Github

copy
1(function() {
2  var BlackHoleStream, Promise, _, debug, debugFrames, ffmpeg, ffmpegPath, fs, la, os, path, stream, utils;
3
4  _ = require("lodash");
5
6  la = require("lazy-ass");
7
8  os = require("os");
9
10  path = require("path");
11
12  utils = require("fluent-ffmpeg/lib/utils");
13
14  debug = require("debug")("cypress:server:video");
15
16  ffmpeg = require("fluent-ffmpeg");
17
18  stream = require("stream");
19
20  Promise = require("bluebird");
21
22  ffmpegPath = require("@ffmpeg-installer/ffmpeg").path;
23
24  BlackHoleStream = require("black-hole-stream");
25
26  fs = require("./util/fs");
27
28  debugFrames = require("debug")("cypress:server:video:frames");
29
30  debug("using ffmpeg from %s", ffmpegPath);
31
32  ffmpeg.setFfmpegPath(ffmpegPath);
33
34  module.exports = {
35    getMsFromDuration: function(duration) {
36      return utils.timemarkToSeconds(duration) * 1000;
37    },
38    getCodecData: function(src) {
39      return new Promise(function(resolve, reject) {
40        return ffmpeg().on("stderr", function(stderr) {
41          return debug("get codecData stderr log %o", {
42            message: stderr
43          });
44        }).on("codecData", resolve).input(src).format("null").output(new BlackHoleStream()).run();
45      }).tap(function(data) {
46        return debug('codecData %o', {
47          src: src,
48          data: data
49        });
50      }).tapCatch(function(err) {
51        return debug("getting codecData failed", {
52          err: err
53        });
54      });
55    },
56    copy: function(src, dest) {
57      debug("copying from %s to %s", src, dest);
58      return fs.copyAsync(src, dest, {
59        overwrite: true
60      })["catch"]({
61        code: "ENOENT"
62      }, function() {});
63    },
64    start: function(name, options) {
65      var done, endVideoCapture, ended, errored, logErrors, pt, skipped, startCapturing, wantsWrite, writeVideoFrame, written;
66      if (options == null) {
67        options = {};
68      }
69      pt = stream.PassThrough();
70      ended = Promise.pending();
71      done = false;
72      errored = false;
73      written = false;
74      logErrors = true;
75      wantsWrite = true;
76      skipped = 0;
77      _.defaults(options, {
78        onError: function() {}
79      });
80      endVideoCapture = function() {
81        done = true;
82        if (!written) {
83          logErrors = false;
84        }
85        pt.end();
86        return ended.promise;
87      };
88      writeVideoFrame = function(data) {
89        if (done) {
90          return;
91        }
92        written = true;
93        debugFrames("writing video frame");
94        if (wantsWrite) {
95          if (!(wantsWrite = pt.write(data))) {
96            return pt.once("drain", function() {
97              debugFrames("video stream drained");
98              return wantsWrite = true;
99            });
100          }
101        } else {
102          skipped += 1;
103          return debugFrames("skipping video frame %o", {
104            skipped: skipped
105          });
106        }
107      };
108      startCapturing = function() {
109        return new Promise(function(resolve) {
110          var cmd;
111          return cmd = ffmpeg({
112            source: pt,
113            priority: 20
114          }).inputFormat("image2pipe").inputOptions("-use_wallclock_as_timestamps 1").videoCodec("libx264").outputOptions("-preset ultrafast").on("start", function(command) {
115            debug("capture started %o", {
116              command: command
117            });
118            return resolve({
119              cmd: cmd,
120              startedVideoCapture: new Date
121            });
122          }).on("codecData", function(data) {
123            return debug("capture codec data: %o", data);
124          }).on("stderr", function(stderr) {
125            return debug("capture stderr log %o", {
126              message: stderr
127            });
128          }).on("error", function(err, stdout, stderr) {
129            debug("capture errored: %o", {
130              error: err.message,
131              stdout: stdout,
132              stderr: stderr
133            });
134            if (logErrors) {
135              options.onError(err, stdout, stderr);
136            }
137            return ended.reject(err);
138          }).on("end", function() {
139            debug("capture ended");
140            return ended.resolve();
141          }).save(name);
142        });
143      };
144      return startCapturing().then(function(arg) {
145        var cmd, startedVideoCapture;
146        cmd = arg.cmd, startedVideoCapture = arg.startedVideoCapture;
147        return {
148          cmd: cmd,
149          endVideoCapture: endVideoCapture,
150          writeVideoFrame: writeVideoFrame,
151          startedVideoCapture: startedVideoCapture
152        };
153      });
154    },
155    process: function(name, cname, videoCompression, onProgress) {
156      var total;
157      if (onProgress == null) {
158        onProgress = function() {};
159      }
160      total = null;
161      return new Promise(function(resolve, reject) {
162        var cmd;
163        debug("processing video from %s to %s video compression %o", name, cname, videoCompression);
164        return cmd = ffmpeg().input(name).videoCodec("libx264").outputOptions(["-preset fast", "-crf " + videoCompression]).on("start", function(command) {
165          return debug("compression started %o", {
166            command: command
167          });
168        }).on("codecData", function(data) {
169          debug("compression codec data: %o", data);
170          return total = utils.timemarkToSeconds(data.duration);
171        }).on("stderr", function(stderr) {
172          return debug("compression stderr log %o", {
173            message: stderr
174          });
175        }).on("progress", function(progress) {
176          var progressed;
177          if (!total) {
178            return;
179          }
180          debug("compression progress: %o", progress);
181          progressed = utils.timemarkToSeconds(progress.timemark);
182          return onProgress(progressed / total);
183        }).on("error", function(err, stdout, stderr) {
184          debug("compression errored: %o", {
185            error: err.message,
186            stdout: stdout,
187            stderr: stderr
188          });
189          return reject(err);
190        }).on("end", function() {
191          debug("compression ended");
192          onProgress(1);
193          return fs.moveAsync(cname, name, {
194            overwrite: true
195          }).then(function() {
196            return resolve();
197          });
198        }).save(cname);
199      });
200    }
201  };
202
203}).call(this);
204
Full Screen

run_spec.js

Source: run_spec.js Github

copy
1require('../../spec_helper')
2
3const Promise = require('bluebird')
4const electron = require('electron')
5const stripAnsi = require('strip-ansi')
6const snapshot = require('snap-shot-it')
7const R = require('ramda')
8const pkg = require('@packages/root')
9const { ProjectBase } = require('../../../lib/project-base')
10const { fs } = require(`${root}../lib/util/fs`)
11const user = require(`${root}../lib/user`)
12const errors = require(`${root}../lib/errors`)
13const config = require(`${root}../lib/config`)
14const { ProjectE2E } = require(`${root}../lib/project-e2e`)
15const browsers = require(`${root}../lib/browsers`)
16const Reporter = require(`${root}../lib/reporter`)
17const runMode = require(`${root}../lib/modes/run`)
18const openProject = require(`${root}../lib/open_project`)
19const videoCapture = require(`${root}../lib/video_capture`)
20const env = require(`${root}../lib/util/env`)
21const random = require(`${root}../lib/util/random`)
22const system = require(`${root}../lib/util/system`)
23const specsUtil = require(`${root}../lib/util/specs`)
24const { experimental } = require(`${root}../lib/experiments`)
25
26describe('lib/modes/run', () => {
27  beforeEach(function () {
28    this.projectInstance = new ProjectBase('/_test-output/path/to/project-e2e')
29  })
30
31  context('.getProjectId', () => {
32    it('resolves if id', () => {
33      return runMode.getProjectId('project', 'id123')
34      .then((ret) => {
35        expect(ret).to.eq('id123')
36      })
37    })
38
39    it('resolves if CYPRESS_PROJECT_ID set', () => {
40      sinon.stub(env, 'get').withArgs('CYPRESS_PROJECT_ID').returns('envId123')
41
42      return runMode.getProjectId('project')
43      .then((ret) => {
44        expect(ret).to.eq('envId123')
45      })
46    })
47
48    it('is null when no projectId', () => {
49      const project = {
50        getProjectId: sinon.stub().rejects(new Error),
51      }
52
53      return runMode.getProjectId(project)
54      .then((ret) => {
55        expect(ret).to.be.null
56      })
57    })
58  })
59
60  context('.openProjectCreate', () => {
61    let onError
62
63    beforeEach(() => {
64      sinon.stub(openProject, 'create').resolves()
65
66      onError = sinon.spy()
67      const options = {
68        onError,
69        port: 8080,
70        env: { foo: 'bar' },
71        isTextTerminal: true,
72        projectRoot: '/_test-output/path/to/project/foo',
73      }
74
75      return runMode.openProjectCreate(options.projectRoot, 1234, options)
76    })
77
78    it('calls openProject.create with projectRoot + options', () => {
79      expect(openProject.create).to.be.calledWithMatch('/_test-output/path/to/project/foo', {
80        port: 8080,
81        projectRoot: '/_test-output/path/to/project/foo',
82        env: { foo: 'bar' },
83      }, {
84        morgan: false,
85        socketId: 1234,
86        report: true,
87        isTextTerminal: true,
88      })
89    })
90
91    it('calls options.onError with error message onError', () => {
92      const error = { message: 'the message' }
93
94      expect(openProject.create.lastCall.args[2].onError).to.be.a('function')
95      openProject.create.lastCall.args[2].onError(error)
96      expect(onError).to.be.calledWith(error)
97    })
98  })
99
100  context('.getElectronProps', () => {
101    it('sets width and height', () => {
102      const props = runMode.getElectronProps()
103
104      expect(props.width).to.eq(1920)
105
106      expect(props.height).to.eq(1080)
107    })
108
109    it('sets show to boolean', () => {
110      let props = runMode.getElectronProps(false)
111
112      expect(props.show).to.be.false
113
114      props = runMode.getElectronProps(true)
115
116      expect(props.show).to.be.true
117    })
118
119    it('sets onScreencastFrame when write is true', () => {
120      const write = sinon.stub()
121
122      const image = {
123        data: '',
124      }
125
126      const props = runMode.getElectronProps(true, write)
127
128      props.onScreencastFrame(image)
129
130      expect(write).to.be.calledOnce
131    })
132
133    it('does not set onScreencastFrame when write is falsy', () => {
134      const props = runMode.getElectronProps(true, false)
135
136      expect(props).not.to.have.property('recordFrameRate')
137      expect(props).not.to.have.property('onScreencastFrame')
138    })
139
140    it('sets options.show = false onNewWindow callback', () => {
141      const options = { show: true }
142
143      const props = runMode.getElectronProps()
144
145      props.onNewWindow(null, null, null, null, options)
146
147      expect(options.show).to.eq(false)
148    })
149
150    it('calls options.onError when webContents crashes', function () {
151      sinon.spy(errors, 'get')
152      sinon.spy(errors, 'log')
153
154      const onError = sinon.spy()
155      const props = runMode.getElectronProps(true, this.projectInstance, onError)
156
157      props.onCrashed()
158
159      expect(errors.get).to.be.calledWith('RENDERER_CRASHED')
160      expect(errors.log).to.be.calledOnce
161
162      expect(onError).to.be.called
163      expect(onError.lastCall.args[0].message).to.include('We detected that the Chromium Renderer process just crashed.')
164    })
165  })
166
167  context('.launchBrowser', () => {
168    beforeEach(function () {
169      this.launch = sinon.stub(openProject, 'launch')
170      sinon.stub(runMode, 'screenshotMetadata').returns({ a: 'a' })
171    })
172
173    it('can launch electron', function () {
174      const screenshots = []
175
176      const spec = {
177        absolute: '/path/to/spec',
178      }
179
180      const browser = {
181        name: 'electron',
182        family: 'chromium',
183        isHeaded: false,
184      }
185
186      runMode.launchBrowser({
187        spec,
188        browser,
189        project: this.projectInstance,
190        writeVideoFrame: 'write',
191        screenshots,
192      })
193
194      expect(this.launch).to.be.calledWithMatch(browser, spec)
195
196      const browserOpts = this.launch.firstCall.args[2]
197
198      const { onAfterResponse } = browserOpts.automationMiddleware
199
200      expect(onAfterResponse).to.be.a('function')
201
202      onAfterResponse('take:screenshot', {}, {})
203      onAfterResponse('get:cookies')
204
205      expect(screenshots).to.deep.eq([{ a: 'a' }])
206    })
207
208    it('can launch chrome', function () {
209      const spec = {
210        absolute: '/path/to/spec',
211      }
212
213      const browser = {
214        name: 'chrome',
215        family: 'chromium',
216        isHeaded: true,
217      }
218
219      runMode.launchBrowser({
220        spec,
221        browser,
222        project: {},
223      })
224
225      expect(this.launch).to.be.calledWithMatch(browser, spec, {})
226    })
227  })
228
229  context('.postProcessRecording', () => {
230    beforeEach(() => {
231      sinon.stub(videoCapture, 'process').resolves()
232    })
233
234    it('calls video process with name, cname and videoCompression', () => {
235      return runMode.postProcessRecording('foo', 'foo-compress', 32, true)
236      .then(() => {
237        expect(videoCapture.process).to.be.calledWith('foo', 'foo-compress', 32)
238      })
239    })
240
241    it('does not call video process when videoCompression is false', () => {
242      return runMode.postProcessRecording('foo', 'foo-compress', false, true)
243      .then(() => {
244        expect(videoCapture.process).not.to.be.called
245      })
246    })
247
248    it('calls video process if we have been told to upload videos', () => {
249      return runMode.postProcessRecording('foo', 'foo-compress', 32, true)
250      .then(() => {
251        expect(videoCapture.process).to.be.calledWith('foo', 'foo-compress', 32)
252      })
253    })
254
255    it('does not call video process if there are no failing tests and we have set not to upload video on passing', () => {
256      return runMode.postProcessRecording('foo', 'foo-compress', 32, false)
257      .then(() => {
258        expect(videoCapture.process).not.to.be.called
259      })
260    })
261  })
262
263  context('.waitForBrowserToConnect', () => {
264    it('throws TESTS_DID_NOT_START_FAILED after 3 connection attempts', function () {
265      sinon.spy(errors, 'warning')
266      sinon.spy(errors, 'get')
267      sinon.spy(openProject, 'closeBrowser')
268      sinon.stub(runMode, 'launchBrowser').resolves()
269      sinon.stub(runMode, 'waitForSocketConnection').callsFake(() => {
270        return Promise.delay(1000)
271      })
272
273      const onError = sinon.spy()
274
275      return runMode.waitForBrowserToConnect({ project: this.projectInstance, timeout: 10, onError })
276      .then(() => {
277        expect(openProject.closeBrowser).to.be.calledThrice
278        expect(runMode.launchBrowser).to.be.calledThrice
279        expect(errors.warning).to.be.calledWith('TESTS_DID_NOT_START_RETRYING', 'Retrying...')
280        expect(errors.warning).to.be.calledWith('TESTS_DID_NOT_START_RETRYING', 'Retrying again...')
281        expect(errors.get).to.be.calledWith('TESTS_DID_NOT_START_FAILED')
282
283        expect(onError).to.be.called
284        expect(onError.lastCall.args[0].message).to.include('The browser never connected. Something is wrong. The tests cannot run. Aborting...')
285      })
286    })
287  })
288
289  context('.waitForSocketConnection', () => {
290    beforeEach(function () {
291      this.projectStub = sinon.stub({
292        on () {},
293        removeListener () {},
294      })
295    })
296
297    it('attaches fn to \'socket:connected\' event', function () {
298      runMode.waitForSocketConnection(this.projectStub, 1234)
299
300      expect(this.projectStub.on).to.be.calledWith('socket:connected')
301    })
302
303    it('calls removeListener if socketId matches id', function () {
304      this.projectStub.on.yields(1234)
305
306      return runMode.waitForSocketConnection(this.projectStub, 1234)
307      .then(() => {
308        expect(this.projectStub.removeListener).to.be.calledWith('socket:connected')
309      })
310    })
311
312    describe('integration', () => {
313      it('resolves undefined when socket:connected fires', function () {
314        process.nextTick(() => {
315          return this.projectInstance.emit('socket:connected', 1234)
316        })
317
318        return runMode.waitForSocketConnection(this.projectInstance, 1234)
319        .then((ret) => {
320          expect(ret).to.be.undefined
321        })
322      })
323
324      it('does not resolve if socketId does not match id', function () {
325        process.nextTick(() => {
326          return this.projectInstance.emit('socket:connected', 12345)
327        })
328
329        return runMode
330        .waitForSocketConnection(this.projectInstance, 1234)
331        .timeout(50)
332        .then(() => {
333          throw new Error('should time out and not resolve')
334        }).catch(Promise.TimeoutError, (err) => {})
335      })
336
337      it('actually removes the listener', function () {
338        process.nextTick(() => {
339          this.projectInstance.emit('socket:connected', 12345)
340          expect(this.projectInstance.listeners('socket:connected')).to.have.length(1)
341          this.projectInstance.emit('socket:connected', '1234')
342          expect(this.projectInstance.listeners('socket:connected')).to.have.length(1)
343          this.projectInstance.emit('socket:connected', 1234)
344
345          expect(this.projectInstance.listeners('socket:connected')).to.have.length(0)
346        })
347
348        return runMode.waitForSocketConnection(this.projectInstance, 1234)
349      })
350    })
351  })
352
353  context('.waitForTestsToFinishRunning', () => {
354    beforeEach(function () {
355      sinon.stub(fs, 'pathExists').resolves(true)
356      sinon.stub(this.projectInstance, 'getConfig').resolves({})
357      sinon.spy(runMode, 'getVideoRecordingDelay')
358      sinon.spy(errors, 'warning')
359
360      this.setupProjectEnd = (results) => {
361        results = results || {
362          stats: {
363            failures: 0,
364          },
365        }
366
367        process.nextTick(() => {
368          this.projectInstance.emit('end', results)
369        })
370      }
371    })
372
373    it('end event resolves with obj, displays stats, displays screenshots, sets video timestamps', function () {
374      const startedVideoCapture = new Date
375      const screenshots = [{}, {}, {}]
376      const endVideoCapture = sinon.stub().resolves()
377      const results = {
378        tests: [{ attempts: [1] }, { attempts: [2] }, { attempts: [3] }],
379        stats: {
380          tests: 1,
381          passes: 2,
382          failures: 3,
383          pending: 4,
384          duration: 5,
385        },
386      }
387
388      sinon.stub(Reporter, 'setVideoTimestamp')
389      sinon.stub(runMode, 'postProcessRecording').resolves()
390      sinon.spy(runMode, 'displayResults')
391      sinon.spy(runMode, 'displayScreenshots')
392      sinon.spy(Promise.prototype, 'delay')
393
394      this.setupProjectEnd(results)
395
396      return runMode.waitForTestsToFinishRunning({
397        project: this.projectInstance,
398        videoName: 'foo.mp4',
399        compressedVideoName: 'foo-compressed.mp4',
400        videoCompression: 32,
401        videoUploadOnPasses: true,
402        gui: false,
403        screenshots,
404        startedVideoCapture,
405        endVideoCapture,
406        spec: {
407          path: 'cypress/integration/spec.js',
408        },
409      })
410      .then((obj) => {
411        // since video was recording, there was a delay to let video finish
412        expect(Reporter.setVideoTimestamp).calledWith(startedVideoCapture, [1, 2, 3])
413        expect(runMode.getVideoRecordingDelay).to.have.returned(1000)
414        expect(Promise.prototype.delay).to.be.calledWith(1000)
415        expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, true)
416
417        expect(runMode.displayResults).to.be.calledWith(results)
418        expect(runMode.displayScreenshots).to.be.calledWith(screenshots)
419
420        expect(obj).to.deep.eq({
421          screenshots,
422          video: 'foo.mp4',
423          error: null,
424          hooks: null,
425          reporterStats: null,
426          shouldUploadVideo: true,
427          tests: results.tests,
428          spec: {
429            path: 'cypress/integration/spec.js',
430          },
431          stats: {
432            tests: 1,
433            passes: 2,
434            failures: 3,
435            pending: 4,
436            duration: 5,
437          },
438        })
439      })
440    })
441
442    it('exiting early resolves with no tests, and error', function () {
443      sinon.useFakeTimers({ shouldAdvanceTime: true })
444
445      const err = new Error('foo')
446      const startedVideoCapture = new Date
447      const wallClock = new Date()
448      const screenshots = [{}, {}, {}]
449      const endVideoCapture = sinon.stub().resolves()
450
451      sinon.stub(runMode, 'postProcessRecording').resolves()
452      sinon.spy(runMode, 'displayResults')
453      sinon.spy(runMode, 'displayScreenshots')
454      sinon.spy(Promise.prototype, 'delay')
455
456      process.nextTick(() => {
457        runMode.exitEarly(err)
458      })
459
460      return runMode.waitForTestsToFinishRunning({
461        project: this.projectInstance,
462        videoName: 'foo.mp4',
463        compressedVideoName: 'foo-compressed.mp4',
464        videoCompression: 32,
465        videoUploadOnPasses: true,
466        gui: false,
467        screenshots,
468        startedVideoCapture,
469        endVideoCapture,
470        spec: {
471          path: 'cypress/integration/spec.js',
472        },
473      })
474      .then((obj) => {
475        // since video was recording, there was a delay to let video finish
476        expect(runMode.getVideoRecordingDelay).to.have.returned(1000)
477        expect(Promise.prototype.delay).to.be.calledWith(1000)
478        expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, true)
479
480        expect(runMode.displayResults).to.be.calledWith(obj)
481        expect(runMode.displayScreenshots).to.be.calledWith(screenshots)
482
483        expect(obj).to.deep.eq({
484          screenshots,
485          error: err.message,
486          video: 'foo.mp4',
487          hooks: null,
488          tests: null,
489          reporterStats: null,
490          shouldUploadVideo: true,
491          spec: {
492            path: 'cypress/integration/spec.js',
493          },
494          stats: {
495            failures: 1,
496            tests: 0,
497            passes: 0,
498            pending: 0,
499            suites: 0,
500            skipped: 0,
501            wallClockDuration: 0,
502            wallClockStartedAt: wallClock.toJSON(),
503            wallClockEndedAt: wallClock.toJSON(),
504          },
505        })
506      })
507    })
508
509    it('logs warning and resolves on failed video end', async function () {
510      this.setupProjectEnd()
511
512      sinon.spy(videoCapture, 'process')
513      const endVideoCapture = sinon.stub().rejects()
514
515      await runMode.waitForTestsToFinishRunning({
516        project: this.projectInstance,
517        videoName: 'foo.mp4',
518        compressedVideoName: 'foo-compressed.mp4',
519        videoCompression: 32,
520        videoUploadOnPasses: true,
521        gui: false,
522        endVideoCapture,
523      })
524
525      expect(errors.warning).to.be.calledWith('VIDEO_POST_PROCESSING_FAILED')
526
527      expect(videoCapture.process).not.to.be.called
528    })
529
530    it('logs warning and resolves on failed video compression', async function () {
531      this.setupProjectEnd()
532
533      const endVideoCapture = sinon.stub().resolves()
534
535      sinon.stub(videoCapture, 'process').rejects()
536
537      await runMode.waitForTestsToFinishRunning({
538        project: this.projectInstance,
539        videoName: 'foo.mp4',
540        compressedVideoName: 'foo-compressed.mp4',
541        videoCompression: 32,
542        videoUploadOnPasses: true,
543        gui: false,
544        endVideoCapture,
545      })
546
547      expect(errors.warning).to.be.calledWith('VIDEO_POST_PROCESSING_FAILED')
548    })
549
550    it('does not upload video when videoUploadOnPasses is false and no failures', function () {
551      this.setupProjectEnd()
552
553      sinon.spy(runMode, 'postProcessRecording')
554      sinon.spy(videoCapture, 'process')
555      const endVideoCapture = sinon.stub().resolves()
556
557      return runMode.waitForTestsToFinishRunning({
558        project: this.projectInstance,
559        videoName: 'foo.mp4',
560        compressedVideoName: 'foo-compressed.mp4',
561        videoCompression: 32,
562        videoUploadOnPasses: false,
563        gui: false,
564        endVideoCapture,
565      })
566      .then(() => {
567        expect(runMode.postProcessRecording).to.be.calledWith('foo.mp4', 'foo-compressed.mp4', 32, false)
568
569        expect(videoCapture.process).not.to.be.called
570      })
571    })
572
573    it('does not delay when not capturing a video', () => {
574      sinon.stub(runMode, 'listenForProjectEnd').resolves({})
575
576      return runMode.waitForTestsToFinishRunning({
577        startedVideoCapture: null,
578      })
579      .then(() => {
580        expect(runMode.getVideoRecordingDelay).to.have.returned(0)
581      })
582    })
583
584    describe('when video is deleted in after:spec event', function () {
585      beforeEach(function () {
586        this.setupProjectEnd()
587        sinon.spy(runMode, 'postProcessRecording')
588        sinon.spy(videoCapture, 'process')
589
590        fs.pathExists.resolves(false)
591      })
592
593      it('does not process or upload video', function () {
594        return runMode.waitForTestsToFinishRunning({
595          project: this.projectInstance,
596          startedVideoCapture: new Date(),
597          videoName: 'foo.mp4',
598          endVideoCapture: sinon.stub().resolves(),
599        })
600        .then((results) => {
601          expect(runMode.postProcessRecording).not.to.be.called
602          expect(videoCapture.process).not.to.be.called
603          expect(results.shouldUploadVideo).to.be.false
604        })
605      })
606
607      it('nulls out video value from results', function () {
608        return runMode.waitForTestsToFinishRunning({
609          project: this.projectInstance,
610          startedVideoCapture: new Date(),
611          videoName: 'foo.mp4',
612          endVideoCapture: sinon.stub().resolves(),
613        })
614        .then((results) => {
615          expect(results.video).to.be.null
616        })
617      })
618    })
619  })
620
621  context('.listenForProjectEnd', () => {
622    it('resolves with end event + argument', function () {
623      process.nextTick(() => {
624        return this.projectInstance.emit('end', { foo: 'bar' })
625      })
626
627      return runMode.listenForProjectEnd(this.projectInstance)
628      .then((obj) => {
629        expect(obj).to.deep.eq({
630          foo: 'bar',
631        })
632      })
633    })
634
635    it('stops listening to end event', function () {
636      process.nextTick(() => {
637        expect(this.projectInstance.listeners('end')).to.have.length(1)
638        this.projectInstance.emit('end', { foo: 'bar' })
639
640        expect(this.projectInstance.listeners('end')).to.have.length(0)
641      })
642
643      return runMode.listenForProjectEnd(this.projectInstance)
644    })
645  })
646
647  context('.run browser vs video recording', () => {
648    beforeEach(function () {
649      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()
650      sinon.stub(user, 'ensureAuthToken')
651      sinon.stub(ProjectE2E, 'ensureExists').resolves()
652      sinon.stub(ProjectBase, 'ensureExists').resolves()
653      sinon.stub(random, 'id').returns(1234)
654      sinon.stub(openProject, 'create').resolves(openProject)
655      sinon.stub(runMode, 'waitForSocketConnection').resolves()
656      sinon.stub(runMode, 'waitForTestsToFinishRunning').resolves({
657        stats: { failures: 10 },
658        spec: {},
659      })
660
661      sinon.spy(runMode, 'waitForBrowserToConnect')
662      sinon.stub(videoCapture, 'start').resolves()
663      sinon.stub(openProject, 'launch').resolves()
664      sinon.stub(openProject, 'getProject').resolves(this.projectInstance)
665      sinon.spy(errors, 'warning')
666      sinon.stub(config, 'get').resolves({
667        proxyUrl: 'http://localhost:12345',
668        video: true,
669        videosFolder: 'videos',
670        integrationFolder: '/path/to/integrationFolder',
671      })
672
673      sinon.stub(specsUtil, 'find').resolves([
674        {
675          name: 'foo_spec.js',
676          path: 'cypress/integration/foo_spec.js',
677          absolute: '/path/to/spec.js',
678        },
679      ])
680    })
681
682    it('shows no warnings for default browser', () => {
683      return runMode.run()
684      .then(() => {
685        expect(errors.warning).to.not.be.called
686      })
687    })
688
689    it('throws an error if invalid browser family supplied', () => {
690      const browser = { name: 'opera', family: 'opera - btw when is Opera support coming?' }
691
692      sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves(browser)
693
694      return expect(runMode.run({ browser: 'opera' }))
695      .to.be.rejectedWith(/invalid browser family in/)
696    })
697
698    it('shows no warnings for chrome browser', () => {
699      return runMode.run({ browser: 'chrome' })
700      .then(() => {
701        expect(errors.warning).to.not.be.called
702      })
703    })
704
705    it('names video file with spec name', () => {
706      return runMode.run()
707      .then(() => {
708        expect(videoCapture.start).to.be.calledWith('videos/foo_spec.js.mp4')
709
710        expect(runMode.waitForTestsToFinishRunning).to.be.calledWithMatch({
711          compressedVideoName: 'videos/foo_spec.js-compressed.mp4',
712        })
713      })
714    })
715  })
716
717  context('.run', () => {
718    beforeEach(function () {
719      sinon.stub(this.projectInstance, 'getConfig').resolves({
720        proxyUrl: 'http://localhost:12345',
721      })
722
723      sinon.stub(electron.app, 'on').withArgs('ready').yieldsAsync()
724      sinon.stub(user, 'ensureAuthToken')
725      sinon.stub(ProjectE2E, 'ensureExists').resolves()
726      sinon.stub(ProjectBase, 'ensureExists').resolves()
727      sinon.stub(random, 'id').returns(1234)
728      sinon.stub(openProject, 'create').resolves(openProject)
729      sinon.stub(system, 'info').resolves({ osName: 'osFoo', osVersion: 'fooVersion' })
730      sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves({
731        name: 'fooBrowser',
732        path: 'path/to/browser',
733        version: '777',
734        family: 'chromium',
735      })
736
737      sinon.stub(runMode, 'waitForSocketConnection').resolves()
738      sinon.stub(runMode, 'waitForTestsToFinishRunning').resolves({
739        stats: { failures: 10 },
740        spec: {},
741      })
742
743      sinon.spy(runMode, 'waitForBrowserToConnect')
744      sinon.spy(runMode, 'runSpecs')
745      sinon.stub(openProject, 'launch').resolves()
746      sinon.stub(openProject, 'getProject').resolves(this.projectInstance)
747      sinon.stub(specsUtil, 'find').resolves([
748        {
749          name: 'foo_spec.js',
750          path: 'cypress/integration/foo_spec.js',
751          absolute: '/path/to/spec.js',
752        },
753      ])
754    })
755
756    it('no longer ensures user session', () => {
757      return runMode.run()
758      .then(() => {
759        expect(user.ensureAuthToken).not.to.be.called
760      })
761    })
762
763    it('resolves with object and totalFailed', () => {
764      return runMode.run()
765      .then((results) => {
766        expect(results).to.have.property('totalFailed', 10)
767      })
768    })
769
770    it('passes projectRoot + options to openProject', () => {
771      const opts = { projectRoot: '/path/to/project', foo: 'bar' }
772
773      return runMode.run(opts)
774      .then(() => {
775        expect(openProject.create).to.be.calledWithMatch(opts.projectRoot, opts)
776      })
777    })
778
779    it('passes project + id to waitForBrowserToConnect', function () {
780      return runMode.run()
781      .then(() => {
782        expect(runMode.waitForBrowserToConnect).to.be.calledWithMatch({
783          project: this.projectInstance,
784          socketId: 1234,
785        })
786      })
787    })
788
789    it('passes project to waitForTestsToFinishRunning', function () {
790      return runMode.run()
791      .then(() => {
792        expect(runMode.waitForTestsToFinishRunning).to.be.calledWithMatch({
793          project: this.projectInstance,
794        })
795      })
796    })
797
798    it('passes headed to openProject.launch', () => {
799      const browser = { name: 'electron', family: 'chromium' }
800
801      browsers.ensureAndGetByNameOrPath.resolves(browser)
802
803      return runMode.run({ headed: true })
804      .then(() => {
805        expect(openProject.launch).to.be.calledWithMatch(
806          browser,
807          {
808            name: 'foo_spec.js',
809            path: 'cypress/integration/foo_spec.js',
810            absolute: '/path/to/spec.js',
811          },
812          {
813            show: true,
814          },
815        )
816      })
817    })
818
819    it('passes sys to runSpecs', () => {
820      return runMode.run()
821      .then(() => {
822        expect(runMode.runSpecs).to.be.calledWithMatch({
823          sys: {
824            osName: 'osFoo',
825            osVersion: 'fooVersion',
826          },
827        })
828      })
829    })
830
831    it('passes browser to runSpecs', () => {
832      return runMode.run()
833      .then(() => {
834        expect(runMode.runSpecs).to.be.calledWithMatch({
835          browser: {
836            name: 'fooBrowser',
837            path: 'path/to/browser',
838            version: '777',
839          },
840        })
841      })
842    })
843  })
844
845  context('#displayRunStarting', () => {
846    // restore pkg.version property
847    // for some reason I cannot stub property value using Sinon
848    let version
849    // save a copy of "true" experiments right away
850    const names = R.clone(experimental.names)
851
852    before(() => {
853      // reset experiments names before each test
854      experimental.names = {}
855      version = pkg.version
856    })
857
858    afterEach(() => {
859      pkg.version = version
860      experimental.names = names
861    })
862
863    it('returns heading with experiments', () => {
864      pkg.version = '1.2.3'
865
866      experimental.names = {
867        experimentalFeatureA: 'experimentalFeatureA',
868        experimentalFeatureB: 'experimentalFeatureB',
869      }
870
871      const options = {
872        browser: {
873          displayName: 'Electron',
874          majorVersion: 99,
875          isHeadless: true,
876        },
877        config: {
878          resolved: {
879            experimentalFeatureA: {
880              value: true,
881              from: 'config',
882            },
883            experimentalFeatureB: {
884              value: 4,
885              from: 'cli',
886            },
887          },
888        },
889      }
890      const heading = runMode.displayRunStarting(options)
891
892      snapshot('enabled experiments', stripAnsi(heading))
893    })
894
895    it('resets the experiments names', () => {
896      expect(experimental.names, 'experiments were reset').to.deep.equal(names)
897    })
898
899    it('returns heading with some enabled experiments', () => {
900      pkg.version = '1.2.3'
901
902      experimental.names = {
903        experimentalFeatureA: 'experimentalFeatureA',
904        experimentalFeatureB: 'experimentalFeatureB',
905      }
906
907      const options = {
908        browser: {
909          displayName: 'Electron',
910          majorVersion: 99,
911          isHeadless: true,
912        },
913        config: {
914          resolved: {
915            // means this feature is not enabled, should not appear in the heading
916            experimentalFeatureA: {
917              value: true,
918              from: 'default',
919            },
920            experimentalFeatureB: {
921              value: 4,
922              from: 'cli',
923            },
924          },
925        },
926      }
927      const heading = runMode.displayRunStarting(options)
928
929      const text = stripAnsi(heading)
930
931      snapshot('some enabled experiments', text)
932      // explicit assertions for test clarity
933      expect(text).to.not.include('experimentalFeatureA')
934      expect(text).to.include('experimentalFeatureB')
935    })
936
937    it('returns heading without experiments', () => {
938      pkg.version = '1.2.3'
939
940      const options = {
941        browser: {
942          displayName: 'Electron',
943          majorVersion: 99,
944          isHeadless: true,
945        },
946        config: {
947          resolved: {},
948        },
949      }
950      const heading = runMode.displayRunStarting(options)
951
952      snapshot('without enabled experiments', stripAnsi(heading))
953    })
954
955    it('restores pkg.version', () => {
956      expect(pkg.version).to.not.equal('1.2.3')
957    })
958  })
959})
960
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Cypress on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)