diff --git a/package.json b/package.json
index 0aa5df3..9670526 100644
--- a/package.json
+++ b/package.json
@@ -51,6 +51,7 @@
"start": "react-scripts start",
"build": "react-scripts --optimize-for-size build",
"test": "react-scripts test",
+ "test-ci": "react-scripts test --watchAll=false",
"eject": "react-scripts eject",
"i18n-extract": "lingui extract",
"i18n-extract:clean": "lingui extract --clean",
diff --git a/src/utils/testing.js b/src/utils/testing.js
new file mode 100644
index 0000000..d92536d
--- /dev/null
+++ b/src/utils/testing.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';
+import theme from '../theme';
+import I18n from '../I18n';
+
+const AllTheProviders = ({ children }) => {
+ return (
+
+
+ {children}
+
+
+ );
+};
+
+const customRender = (ui, options) => render(ui, { wrapper: AllTheProviders, ...options });
+
+// re-export everything
+export * from '@testing-library/react';
+
+// override render method
+export { customRender as render };
diff --git a/src/views/Edit/Sources/Network.test.js b/src/views/Edit/Sources/Network.test.js
new file mode 100644
index 0000000..89f125b
--- /dev/null
+++ b/src/views/Edit/Sources/Network.test.js
@@ -0,0 +1,53 @@
+import React from 'react';
+import { render, fireEvent } from '../../../utils/testing';
+import '@testing-library/jest-dom';
+
+import * as Network from './Network';
+
+test('FFmpeg 5: RTSP with -timeout', async () => {
+ let $settings = {};
+ const handleChange = (settings) => {
+ $settings = settings;
+ };
+
+ let $inputs = [];
+ const handleProbe = (_, inputs) => {
+ $inputs = inputs;
+ };
+
+ const Source = Network.component;
+ let { getByLabelText, getByText, queryByText, getByRole, rerender } = render();
+
+ const input = getByLabelText('Address');
+ fireEvent.change(input, { target: { value: 'rtsp://127.0.0.1/live/stream' } });
+
+ expect($settings.mode).toBe('pull');
+ expect($settings.address).toBe('rtsp://127.0.0.1/live/stream');
+
+ rerender();
+
+ expect(queryByText('This protocol is unknown or not supported by the available FFmpeg binary.')).toBeInTheDocument();
+
+ const $skills = {
+ ffmpeg: {
+ version: '5.1.2',
+ },
+ formats: {
+ demuxers: ['rtsp'],
+ },
+ };
+
+ rerender();
+
+ expect(queryByText('This protocol is unknown or not supported by the available FFmpeg binary.')).toBe(null);
+ expect(getByText('Probe')).toBeInTheDocument();
+
+ const button = getByRole('button', { name: 'Probe' });
+ fireEvent.click(button, { bubbles: true });
+
+ expect($inputs.length).toBe(1);
+ expect($inputs[0]).toStrictEqual({
+ address: 'rtsp://127.0.0.1/live/stream',
+ options: ['-fflags', '+genpts', '-thread_queue_size', 512, '-timeout', 5000000, '-rtsp_transport', 'tcp'],
+ });
+});