Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow video to be recorded till the end of the test #4804

Merged
merged 8 commits into from
Jul 29, 2019
36 changes: 29 additions & 7 deletions packages/server/lib/modes/run.coffee
Original file line number Diff line number Diff line change
@@ -4,6 +4,9 @@ path = require("path")
chalk = require("chalk")
human = require("human-interval")
debug = require("debug")("cypress:server:run")
# because this file also interacts with video recording
# some debug logs should have ":video" namespace
debugVideo = require("debug")("cypress:server:video")
Promise = require("bluebird")
logSymbols = require("log-symbols")

@@ -428,8 +431,8 @@ module.exports = {
errors.warning("VIDEO_RECORDING_FAILED", err.stack)
})

getElectronProps: (isHeaded, project, write) ->
obj = {
getElectronProps: (isHeaded, project, writeVideoFrame) ->
electronProps = {
width: 1280
height: 720
show: isHeaded
@@ -446,12 +449,12 @@ module.exports = {
options.show = false
}

if write
obj.recordFrameRate = 20
obj.onPaint = (event, dirty, image) ->
write(image.toJPEG(100))
if writeVideoFrame
electronProps.recordFrameRate = 20
electronProps.onPaint = (event, dirty, image) ->
writeVideoFrame(image.toJPEG(100))

obj
electronProps

displayResults: (obj = {}, estimated) ->
results = collectTestResults(obj, estimated)
@@ -677,10 +680,28 @@ module.exports = {
## is the one that matches our id!
project.on("socket:connected", fn)

_delayToLetVideoFinish: ->
# we are recording video of the test run
# and there still might be frames sent by the browser
# in order to avoid chopping off the end of the video
# delay closing the browser by N ms
DELAY_TO_LET_VIDEO_FINISH_MS = 1000
debugVideo('delaying closing the browser by %dms to let video finish', DELAY_TO_LET_VIDEO_FINISH_MS)
Promise.delay(DELAY_TO_LET_VIDEO_FINISH_MS)

waitForTestsToFinishRunning: (options = {}) ->
{ project, screenshots, started, end, name, cname, videoCompression, videoUploadOnPasses, exit, spec, estimated } = options

@listenForProjectEnd(project, exit)
.tap =>
# ? is this the best way to determine if we are recording a video?
# TODO rename "end" to something meaningful, like "videoCaptureEnd"
return unless end
# we are recording video of the test run
# and there still might be frames sent by the browser
# in order to avoid chopping off the end of the video
# delay closing the browser by N ms
@_delayToLetVideoFinish()
.then (obj) =>
_.defaults(obj, {
error: null
@@ -691,6 +712,7 @@ module.exports = {
reporterStats: null
})

# TODO rename "end" to something meaningful, like "videoCaptureEnd"
if end
obj.video = name

28 changes: 16 additions & 12 deletions packages/server/lib/video_capture.coffee
Original file line number Diff line number Diff line change
@@ -7,10 +7,12 @@ Promise = require("bluebird")
ffmpegPath = require("@ffmpeg-installer/ffmpeg").path
fs = require("./util/fs")

debug("using ffmpeg from %s", ffmpegPath)
ffmpeg.setFfmpegPath(ffmpegPath)

module.exports = {
copy: (src, dest) ->
debug("copying from %s to %s", src, dest)
fs
.copyAsync(src, dest, {overwrite: true})
.catch {code: "ENOENT"}, ->
@@ -77,13 +79,13 @@ module.exports = {
debug("capture started %o", { command })

started.resolve(new Date)

.on "codecData", (data) ->
debug("capture codec data: %o", data)

.on "stderr", (stderr) ->
debug("capture stderr log %o", { message: stderr })

.on "error", (err, stdout, stderr) ->
debug("capture errored: %o", { error: err.message, stdout, stderr })

@@ -114,6 +116,8 @@ module.exports = {
total = null

new Promise (resolve, reject) ->
debug("processing video from %s to %s video compression %o",
name, cname, videoCompression)
cmd = ffmpeg()
.input(name)
.videoCodec("libx264")
@@ -123,33 +127,33 @@ module.exports = {
])
.on "start", (command) ->
debug("compression started %o", { command })

.on "codecData", (data) ->
debug("compression codec data: %o", data)

total = utils.timemarkToSeconds(data.duration)

.on "stderr", (stderr) ->
debug("compression stderr log %o", { message: stderr })

.on "progress", (progress) ->
## bail if we dont have total yet
return if not total

debug("compression progress: %o", progress)

progressed = utils.timemarkToSeconds(progress.timemark)

onProgress(progressed / total)

.on "error", (err, stdout, stderr) ->
debug("compression errored: %o", { error: err.message, stdout, stderr })

reject(err)

.on "end", ->
debug("compression ended")

## we are done progressing
onProgress(1)

5 changes: 5 additions & 0 deletions packages/server/test/unit/modes/run_spec.coffee
Original file line number Diff line number Diff line change
@@ -288,6 +288,7 @@ describe "lib/modes/run", ->
context ".waitForTestsToFinishRunning", ->
beforeEach ->
sinon.stub(@projectInstance, "getConfig").resolves({})
sinon.stub(runMode, "_delayToLetVideoFinish").resolves()

it "end event resolves with obj, displays stats, displays screenshots, sets video timestamps", ->
started = new Date
@@ -331,6 +332,8 @@ describe "lib/modes/run", ->
}
})
.then (obj) ->
# since video was recording, there was a delay to let video finish
expect(runMode._delayToLetVideoFinish).to.be.calledOnce
expect(runMode.postProcessRecording).to.be.calledWith(end, "foo.mp4", "foo-compressed.mp4", 32, true)

expect(runMode.displayResults).to.be.calledWith(results)
@@ -389,6 +392,8 @@ describe "lib/modes/run", ->
}
})
.then (obj) ->
# since video was recording, there was a delay to let video finish
expect(runMode._delayToLetVideoFinish).to.be.calledOnce
expect(runMode.postProcessRecording).to.be.calledWith(end, "foo.mp4", "foo-compressed.mp4", 32, true)

expect(runMode.displayResults).to.be.calledWith(obj)