frigate/web/src/api/__tests__/ws.test.jsx
Nicolas Mowen c3b313a70d
Audio events (#6848)
* Initial audio classification model implementation

* fix mypy

* Keep audio labelmap local

* Cleanup

* Start adding config for audio

* Add the detector

* Add audio detection process keypoints

* Build out base config

* Load labelmap correctly

* Fix config bugs

* Start audio process

* Fix startup issues

* Try to cleanup restarting

* Add ffmpeg input args

* Get audio detection working

* Save event to db

* End events if not heard for 30 seconds

* Use not heard config

* Stop ffmpeg when shutting down

* Fixes

* End events correctly

* Use api instead of event queue to save audio events

* Get events working

* Close threads when stop event is sent

* remove unused

* Only start audio process if at least one camera is enabled

* Add const for float

* Cleanup labelmap

* Add audio icon in frontend

* Add ability to toggle audio with mqtt

* Set initial audio value

* Fix audio enabling

* Close logpipe

* Isort

* Formatting

* Fix web tests

* Fix web tests

* Handle cases where args are a string

* Remove log

* Cleanup process close

* Use correct field

* Simplify if statement

* Use var for localhost

* Add audio detectors docs

* Add restream docs to mention audio detection

* Add full config docs

* Fix links to other docs

---------

Co-authored-by: Jason Hunter <hunterjm@gmail.com>
2023-07-01 08:18:33 -05:00

150 lines
4.7 KiB
JavaScript

import { h } from 'preact';
import { WS, WsProvider, useWs } from '../ws';
import { useCallback, useContext } from 'preact/hooks';
import { fireEvent, render, screen } from 'testing-library';
function Test() {
const { state } = useContext(WS);
return state.__connected ? (
<div data-testid="data">
{Object.keys(state).map((key) => (
<div key={key} data-testid={key}>
{JSON.stringify(state[key])}
</div>
))}
</div>
) : null;
}
const TEST_URL = 'ws://test-foo:1234/ws';
describe('WsProvider', () => {
let createWebsocket, wsClient;
beforeEach(() => {
wsClient = {
close: vi.fn(),
send: vi.fn(),
};
createWebsocket = vi.fn((url) => {
wsClient.args = [url];
return new Proxy(
{},
{
get(_target, prop, _receiver) {
return wsClient[prop];
},
set(_target, prop, value) {
wsClient[prop] = typeof value === 'function' ? vi.fn(value) : value;
if (prop === 'onopen') {
wsClient[prop]();
}
return true;
},
}
);
});
});
test('connects to the ws server', async () => {
render(
<WsProvider config={mockConfig} createWebsocket={createWebsocket} wsUrl={TEST_URL}>
<Test />
</WsProvider>
);
await screen.findByTestId('data');
expect(wsClient.args).toEqual([TEST_URL]);
expect(screen.getByTestId('__connected')).toHaveTextContent('true');
});
test('receives data through useWs', async () => {
function Test() {
const {
value: { payload, retain },
connected,
} = useWs('tacos');
return connected ? (
<div>
<div data-testid="payload">{JSON.stringify(payload)}</div>
<div data-testid="retain">{JSON.stringify(retain)}</div>
</div>
) : null;
}
const { rerender } = render(
<WsProvider config={mockConfig} createWebsocket={createWebsocket} wsUrl={TEST_URL}>
<Test />
</WsProvider>
);
await screen.findByTestId('payload');
wsClient.onmessage({
data: JSON.stringify({ topic: 'tacos', payload: JSON.stringify({ yes: true }), retain: false }),
});
rerender(
<WsProvider config={mockConfig} createWebsocket={createWebsocket} wsUrl={TEST_URL}>
<Test />
</WsProvider>
);
expect(screen.getByTestId('payload')).toHaveTextContent('{"yes":true}');
expect(screen.getByTestId('retain')).toHaveTextContent('false');
});
test('can send values through useWs', async () => {
function Test() {
const { send, connected } = useWs('tacos');
const handleClick = useCallback(() => {
send({ yes: true });
}, [send]);
return connected ? <button onClick={handleClick}>click me</button> : null;
}
render(
<WsProvider config={mockConfig} createWebsocket={createWebsocket} wsUrl={TEST_URL}>
<Test />
</WsProvider>
);
await screen.findByRole('button');
fireEvent.click(screen.getByRole('button'));
await expect(wsClient.send).toHaveBeenCalledWith(
JSON.stringify({ topic: 'tacos', payload: JSON.stringify({ yes: true }), retain: false })
);
});
test('prefills the recordings/detect/snapshots state from config', async () => {
vi.spyOn(Date, 'now').mockReturnValue(123456);
const config = {
cameras: {
front: { name: 'front', detect: { enabled: true }, record: { enabled: false }, snapshots: { enabled: true }, audio: { enabled: false } },
side: { name: 'side', detect: { enabled: false }, record: { enabled: false }, snapshots: { enabled: false }, audio: { enabled: false } },
},
};
render(
<WsProvider config={config} createWebsocket={createWebsocket} wsUrl={TEST_URL}>
<Test />
</WsProvider>
);
await screen.findByTestId('data');
expect(screen.getByTestId('front/detect/state')).toHaveTextContent(
'{"lastUpdate":123456,"payload":"ON","retain":false}'
);
expect(screen.getByTestId('front/recordings/state')).toHaveTextContent(
'{"lastUpdate":123456,"payload":"OFF","retain":false}'
);
expect(screen.getByTestId('front/snapshots/state')).toHaveTextContent(
'{"lastUpdate":123456,"payload":"ON","retain":false}'
);
expect(screen.getByTestId('side/detect/state')).toHaveTextContent(
'{"lastUpdate":123456,"payload":"OFF","retain":false}'
);
expect(screen.getByTestId('side/recordings/state')).toHaveTextContent(
'{"lastUpdate":123456,"payload":"OFF","retain":false}'
);
expect(screen.getByTestId('side/snapshots/state')).toHaveTextContent(
'{"lastUpdate":123456,"payload":"OFF","retain":false}'
);
});
});
const mockConfig = {
cameras: {},
};