mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-23 01:22:12 +03:00
feat: add ffmpeg video recorder for e2e tests (#4686)
This commit is contained in:
parent
00e3094795
commit
13a270613c
1
.github/workflows/test-e2e.yml
vendored
1
.github/workflows/test-e2e.yml
vendored
@ -29,6 +29,7 @@ jobs:
|
||||
libayatana-appindicator3-dev \
|
||||
libwebkit2gtk-4.0-dev \
|
||||
webkit2gtk-driver \
|
||||
ffmpeg \
|
||||
xvfb
|
||||
- name: Setup rust-toolchain stable
|
||||
id: rust-toolchain
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ generated-do-not-edit/
|
||||
|
||||
.sentryclirc
|
||||
.DS_Store
|
||||
apps/desktop/e2e/videos/*.mp4
|
||||
|
||||
.env
|
||||
.env.*
|
||||
|
82
apps/desktop/e2e/record.ts
Normal file
82
apps/desktop/e2e/record.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import path from 'node:path';
|
||||
import { spawn, type ChildProcessWithoutNullStreams } from 'child_process';
|
||||
import type { Frameworks } from '@wdio/types';
|
||||
|
||||
function filePath({
|
||||
test,
|
||||
videoPath,
|
||||
extension
|
||||
}: {
|
||||
test: Frameworks.Test;
|
||||
videoPath: string;
|
||||
extension: string;
|
||||
}) {
|
||||
return path.join(videoPath, `${fileName(test.parent)}-${fileName(test.title)}.${extension}`);
|
||||
}
|
||||
|
||||
function fileName(title: string) {
|
||||
return encodeURIComponent(title.trim().replace(/\s+/g, '-'));
|
||||
}
|
||||
|
||||
export class TestRecorder {
|
||||
ffmpeg!: ChildProcessWithoutNullStreams;
|
||||
|
||||
constructor() {}
|
||||
|
||||
stop() {
|
||||
this.ffmpeg?.kill('SIGINT');
|
||||
}
|
||||
|
||||
start(test: Frameworks.Test, videoPath: string) {
|
||||
if (!videoPath) {
|
||||
throw new Error('Video path not set. Set using setPath() function.');
|
||||
}
|
||||
|
||||
if (process.env.DISPLAY && process.env.DISPLAY.startsWith(':')) {
|
||||
const parsedPath = filePath({
|
||||
test,
|
||||
videoPath,
|
||||
extension: 'mp4'
|
||||
});
|
||||
|
||||
this.ffmpeg = spawn('ffmpeg', [
|
||||
'-f',
|
||||
'x11grab', // Grab the X11 display
|
||||
'-video_size',
|
||||
'1280x1024', // Video size
|
||||
'-i',
|
||||
process.env.DISPLAY, // Input file url
|
||||
'-loglevel',
|
||||
'error', // Log only errors
|
||||
'-y', // Overwrite output files without asking
|
||||
'-pix_fmt',
|
||||
'yuv420p', // QuickTime Player support, "Use -pix_fmt yuv420p for compatibility with outdated media players"
|
||||
parsedPath // Output file
|
||||
]);
|
||||
|
||||
const logBuffer = function (buffer: Buffer, prefix: string) {
|
||||
const lines = buffer.toString().trim().split('\n');
|
||||
lines.forEach(function (line) {
|
||||
console.log(prefix + line);
|
||||
});
|
||||
};
|
||||
|
||||
this.ffmpeg.stdout.on('data', (data: Buffer) => {
|
||||
logBuffer(data, '[ffmpeg:stdout] ');
|
||||
});
|
||||
|
||||
this.ffmpeg.stderr.on('data', (data: Buffer) => {
|
||||
logBuffer(data, '[ffmpeg:error] ');
|
||||
});
|
||||
|
||||
this.ffmpeg.on('close', (code: number, signal: string | unknown) => {
|
||||
if (code !== null) {
|
||||
console.log(`[ffmpeg:stdout] exited with code ${code}: ${videoPath}`);
|
||||
}
|
||||
if (signal !== null) {
|
||||
console.log(`[ffmpeg:stdout] received signal ${signal}: ${videoPath}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,12 @@ CLI=${1:?The first argument is the GitButler CLI}
|
||||
# Convert to absolute path
|
||||
CLI=$(realpath "$CLI")
|
||||
|
||||
function setGitDefaults() {
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Test User"
|
||||
git config init.defaultBranch master
|
||||
}
|
||||
|
||||
function tick() {
|
||||
if test -z "${tick+set}"; then
|
||||
tick=1675176957
|
||||
@ -20,7 +26,9 @@ function tick() {
|
||||
}
|
||||
tick
|
||||
|
||||
mkdir "$TEMP_DIR"
|
||||
if [ ! -d "$TEMP_DIR" ]; then
|
||||
mkdir "$TEMP_DIR"
|
||||
fi
|
||||
cd "$TEMP_DIR"
|
||||
|
||||
git init remote
|
||||
@ -28,9 +36,7 @@ git init remote
|
||||
(
|
||||
cd remote
|
||||
|
||||
git config user.email "test@example.com"
|
||||
git config user.name "Test User"
|
||||
git config init.defaultBranch master
|
||||
setGitDefaults
|
||||
|
||||
echo first >file
|
||||
git add . && git commit -m "init"
|
||||
|
0
apps/desktop/e2e/videos/.keep
Normal file
0
apps/desktop/e2e/videos/.keep
Normal file
@ -1,8 +1,10 @@
|
||||
import { spawn, ChildProcess } from 'node:child_process';
|
||||
import { TestRecorder } from './e2e/record.js';
|
||||
import { spawn, type ChildProcess } from 'node:child_process';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import type { Options } from '@wdio/types';
|
||||
import type { Options, Frameworks } from '@wdio/types';
|
||||
|
||||
const videoRecorder = new TestRecorder();
|
||||
let tauriDriver: ChildProcess;
|
||||
|
||||
export const config: Options.WebdriverIO = {
|
||||
@ -37,6 +39,15 @@ export const config: Options.WebdriverIO = {
|
||||
connectionRetryTimeout: 120000,
|
||||
connectionRetryCount: 0,
|
||||
|
||||
beforeTest: function (test: Frameworks.Test) {
|
||||
const videoPath = path.join(import.meta.dirname, '/e2e/videos');
|
||||
videoRecorder.start(test, videoPath);
|
||||
},
|
||||
|
||||
afterTest: function () {
|
||||
videoRecorder.stop();
|
||||
},
|
||||
|
||||
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
|
||||
beforeSession: () =>
|
||||
(tauriDriver = spawn(path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'), [], {
|
||||
|
Loading…
Reference in New Issue
Block a user