mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-12-23 19:11:14 +01:00
test(web): CameraImage (basic)
Testing Image and Canvas calls requires a lot of heavy dependencies, so this skips that part of the tests
This commit is contained in:
parent
a202c44a0f
commit
1aa9a7a093
@ -2,32 +2,19 @@ import { h } from 'preact';
|
||||
import ActivityIndicator from './ActivityIndicator';
|
||||
import { useApiHost, useConfig } from '../api';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
||||
import { useResizeObserver } from '../hooks';
|
||||
|
||||
export default function CameraImage({ camera, onload, searchParams = '' }) {
|
||||
const { data: config } = useConfig();
|
||||
const apiHost = useApiHost();
|
||||
const [availableWidth, setAvailableWidth] = useState(0);
|
||||
const [hasLoaded, setHasLoaded] = useState(false);
|
||||
const containerRef = useRef(null);
|
||||
const canvasRef = useRef(null);
|
||||
const [{ width: availableWidth }] = useResizeObserver(containerRef);
|
||||
|
||||
const { name, width, height } = config.cameras[camera];
|
||||
const aspectRatio = width / height;
|
||||
|
||||
const resizeObserver = useMemo(() => {
|
||||
return new ResizeObserver((entries) => {
|
||||
window.requestAnimationFrame(() => {
|
||||
if (Array.isArray(entries) && entries.length) {
|
||||
setAvailableWidth(entries[0].contentRect.width);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
resizeObserver.observe(containerRef.current);
|
||||
}, [resizeObserver, containerRef]);
|
||||
|
||||
const scaledHeight = useMemo(() => Math.min(Math.ceil(availableWidth / aspectRatio), height), [
|
||||
availableWidth,
|
||||
aspectRatio,
|
||||
@ -57,7 +44,7 @@ export default function CameraImage({ camera, onload, searchParams = '' }) {
|
||||
|
||||
return (
|
||||
<div className="relative w-full" ref={containerRef}>
|
||||
<canvas height={scaledHeight} ref={canvasRef} width={scaledWidth} />
|
||||
<canvas data-testid="cameraimage-canvas" height={scaledHeight} ref={canvasRef} width={scaledWidth} />
|
||||
{!hasLoaded ? (
|
||||
<div className="absolute inset-0 flex justify-center" style={`height: ${scaledHeight}px`}>
|
||||
<ActivityIndicator />
|
||||
|
36
web/src/components/__tests__/CameraImage.test.jsx
Normal file
36
web/src/components/__tests__/CameraImage.test.jsx
Normal file
@ -0,0 +1,36 @@
|
||||
import { h } from 'preact';
|
||||
import * as Api from '../../api';
|
||||
import * as Hooks from '../../hooks';
|
||||
import CameraImage from '../CameraImage';
|
||||
import { render, screen } from '@testing-library/preact';
|
||||
|
||||
jest.mock('../../api/baseUrl');
|
||||
|
||||
describe('CameraImage', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(Api, 'useConfig').mockImplementation(() => {
|
||||
return { data: { cameras: { front: { name: 'front', width: 1280, height: 720 } } } };
|
||||
});
|
||||
jest.spyOn(Api, 'useApiHost').mockReturnValue('http://base-url.local:5000');
|
||||
jest.spyOn(Hooks, 'useResizeObserver').mockImplementation(() => [{ width: 0 }]);
|
||||
});
|
||||
|
||||
test('renders an activity indicator while loading', async () => {
|
||||
render(<CameraImage camera="front" />);
|
||||
expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('creates a scaled canvas using the available width & height, preserving camera aspect ratio', async () => {
|
||||
jest.spyOn(Hooks, 'useResizeObserver').mockReturnValueOnce([{ width: 720 }]);
|
||||
|
||||
render(<CameraImage camera="front" />);
|
||||
expect(screen.queryByLabelText('Loading…')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('cameraimage-canvas')).toMatchInlineSnapshot(`
|
||||
<canvas
|
||||
data-testid="cameraimage-canvas"
|
||||
height="405"
|
||||
width="720"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
});
|
30
web/src/hooks/index.jsx
Normal file
30
web/src/hooks/index.jsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { useEffect, useMemo, useState } from 'preact/hooks';
|
||||
|
||||
export function useResizeObserver(...refs) {
|
||||
const [dimensions, setDimensions] = useState(
|
||||
new Array(refs.length).fill({ width: 0, height: 0, x: -Infinity, y: -Infinity })
|
||||
);
|
||||
const resizeObserver = useMemo(
|
||||
() =>
|
||||
new ResizeObserver((entries) => {
|
||||
window.requestAnimationFrame(() => {
|
||||
setDimensions(entries.map((entry) => entry.contentRect));
|
||||
});
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
refs.forEach((ref) => {
|
||||
resizeObserver.observe(ref.current);
|
||||
});
|
||||
|
||||
return () => {
|
||||
refs.forEach((ref) => {
|
||||
resizeObserver.unobserve(ref.current);
|
||||
});
|
||||
};
|
||||
}, [refs, resizeObserver]);
|
||||
|
||||
return dimensions;
|
||||
}
|
@ -3,14 +3,14 @@ import Card from '../components/Card.jsx';
|
||||
import Button from '../components/Button.jsx';
|
||||
import Heading from '../components/Heading.jsx';
|
||||
import Switch from '../components/Switch.jsx';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
||||
import { useResizeObserver } from '../hooks';
|
||||
import { useCallback, useMemo, useRef, useState } from 'preact/hooks';
|
||||
import { useApiHost, useConfig } from '../api';
|
||||
|
||||
export default function CameraMasks({ camera, url }) {
|
||||
const { data: config } = useConfig();
|
||||
const apiHost = useApiHost();
|
||||
const imageRef = useRef(null);
|
||||
const [imageScale, setImageScale] = useState(1);
|
||||
const [snap, setSnap] = useState(true);
|
||||
|
||||
const cameraConfig = config.cameras[camera];
|
||||
@ -22,26 +22,8 @@ export default function CameraMasks({ camera, url }) {
|
||||
zones,
|
||||
} = cameraConfig;
|
||||
|
||||
const resizeObserver = useMemo(
|
||||
() =>
|
||||
new ResizeObserver((entries) => {
|
||||
window.requestAnimationFrame(() => {
|
||||
if (Array.isArray(entries) && entries.length) {
|
||||
const scaledWidth = entries[0].contentRect.width;
|
||||
const scale = scaledWidth / width;
|
||||
setImageScale(scale);
|
||||
}
|
||||
});
|
||||
}),
|
||||
[width, setImageScale]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!imageRef.current) {
|
||||
return;
|
||||
}
|
||||
resizeObserver.observe(imageRef.current);
|
||||
}, [resizeObserver, imageRef]);
|
||||
const [{ width: scaledWidth }] = useResizeObserver(imageRef);
|
||||
const imageScale = scaledWidth / width;
|
||||
|
||||
const [motionMaskPoints, setMotionMaskPoints] = useState(
|
||||
Array.isArray(motionMask)
|
||||
|
Loading…
Reference in New Issue
Block a user