Files
frigate/web/e2e/specs/setup/wizard-hardware.spec.ts
T
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Josh Hawkins
63c12cf135 Bump the web-minor-patch group in /web with 18 updates (#24844)
* Bump the web-minor-patch group in /web with 18 updates

Bumps the web-minor-patch group in /web with 18 updates:

| Package | From | To |
| --- | --- | --- |
| [@cycjimmy/jsmpeg-player](https://github.com/cycjimmy/jsmpeg-player) | `6.1.2` | `6.1.6` |
| [@hookform/resolvers](https://github.com/react-hook-form/resolvers) | `6.0.0` | `6.0.2` |
| [apexcharts](https://github.com/apexcharts/apexcharts.js) | `8.4.1` | `8.5.0` |
| [axios](https://github.com/axios/axios) | `1.20.0` | `1.21.0` |
| [framer-motion](https://github.com/motiondivision/motion) | `14.6.0` | `14.7.1` |
| [hls.js](https://github.com/video-dev/hls.js) | `1.7.3` | `1.7.4` |
| [i18next](https://github.com/i18next/i18next) | `26.5.5` | `26.5.11` |
| [i18next-http-backend](https://github.com/i18next/i18next-http-backend) | `4.0.4` | `4.0.6` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.61.0` | `1.64.0` |
| [react-apexcharts](https://github.com/apexcharts/react-apexcharts) | `2.1.1` | `2.1.2` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.90.0` | `7.91.0` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.1.1` | `17.1.9` |
| [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) | `7.18.4` | `7.18.5` |
| [virtua](https://github.com/inokawa/virtua) | `0.53.6` | `0.54.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.6.5` | `26.6.6` |
| [autoprefixer](https://github.com/postcss/autoprefixer) | `10.6.1` | `10.6.2` |
| [postcss](https://github.com/postcss/postcss) | `8.5.31` | `8.5.32` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.72.0` | `8.72.1` |


Updates `@cycjimmy/jsmpeg-player` from 6.1.2 to 6.1.6
- [Release notes](https://github.com/cycjimmy/jsmpeg-player/releases)
- [Changelog](https://github.com/cycjimmy/jsmpeg-player/blob/main/docs/CHANGELOG.md)
- [Commits](https://github.com/cycjimmy/jsmpeg-player/compare/v6.1.2...v6.1.6)

Updates `@hookform/resolvers` from 6.0.0 to 6.0.2
- [Release notes](https://github.com/react-hook-form/resolvers/releases)
- [Commits](https://github.com/react-hook-form/resolvers/compare/v6.0.0...v6.0.2)

Updates `apexcharts` from 8.4.1 to 8.5.0
- [Release notes](https://github.com/apexcharts/apexcharts.js/releases)
- [Commits](https://github.com/apexcharts/apexcharts.js/compare/v8.4.1...v8.5.0)

Updates `axios` from 1.20.0 to 1.21.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.20.0...v1.21.0)

Updates `framer-motion` from 14.6.0 to 14.7.1
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v14.6.0...v14.7.1)

Updates `hls.js` from 1.7.3 to 1.7.4
- [Release notes](https://github.com/video-dev/hls.js/releases)
- [Changelog](https://github.com/video-dev/hls.js/blob/master/docs/release-process.md)
- [Commits](https://github.com/video-dev/hls.js/compare/v1.7.3...v1.7.4)

Updates `i18next` from 26.5.5 to 26.5.11
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next/compare/v26.5.5...v26.5.11)

Updates `i18next-http-backend` from 4.0.4 to 4.0.6
- [Changelog](https://github.com/i18next/i18next-http-backend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/i18next-http-backend/compare/v4.0.4...v4.0.6)

Updates `lucide-react` from 1.61.0 to 1.64.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.64.0/packages/lucide-react)

Updates `react-apexcharts` from 2.1.1 to 2.1.2
- [Release notes](https://github.com/apexcharts/react-apexcharts/releases)
- [Commits](https://github.com/apexcharts/react-apexcharts/commits)

Updates `react-hook-form` from 7.90.0 to 7.91.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.90.0...v7.91.0)

Updates `react-i18next` from 17.1.1 to 17.1.9
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/i18next/react-i18next/compare/v17.1.1...v17.1.9)

Updates `react-router-dom` from 7.18.4 to 7.18.5
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/react-router-dom@7.18.5/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.18.5/packages/react-router-dom)

Updates `virtua` from 0.53.6 to 0.54.0
- [Release notes](https://github.com/inokawa/virtua/releases)
- [Commits](https://github.com/inokawa/virtua/compare/0.53.6...0.54.0)

Updates `@types/node` from 26.6.5 to 26.6.6
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `autoprefixer` from 10.6.1 to 10.6.2
- [Release notes](https://github.com/postcss/autoprefixer/releases)
- [Changelog](https://github.com/postcss/autoprefixer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/autoprefixer/compare/10.6.1...10.6.2)

Updates `postcss` from 8.5.31 to 8.5.32
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.31...8.5.32)

Updates `typescript-eslint` from 8.72.0 to 8.72.1
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.72.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: "@cycjimmy/jsmpeg-player"
  dependency-version: 6.1.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: "@hookform/resolvers"
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: apexcharts
  dependency-version: 8.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: axios
  dependency-version: 1.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: framer-motion
  dependency-version: 14.7.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: hls.js
  dependency-version: 1.7.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: i18next
  dependency-version: 26.5.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: i18next-http-backend
  dependency-version: 4.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: lucide-react
  dependency-version: 1.64.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-apexcharts
  dependency-version: 2.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: react-hook-form
  dependency-version: 7.91.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: react-i18next
  dependency-version: 17.1.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: react-router-dom
  dependency-version: 7.18.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: virtua
  dependency-version: 0.54.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: web-minor-patch
- dependency-name: "@types/node"
  dependency-version: 26.6.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: autoprefixer
  dependency-version: 10.6.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: postcss
  dependency-version: 8.5.32
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
- dependency-name: typescript-eslint
  dependency-version: 8.72.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: web-minor-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Wait for wizard requests in setup specs

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
2026-11-01 07:55:52 -06:00

268 lines
8.4 KiB
TypeScript

/**
* Setup wizard hardware tests -- HIGH tier.
*
* Covers the detector step's probed radio list and the models: payload it
* writes, the model-required deferral for onnx hardware, the hwaccel step's
* Auto option writing the preset derived from the chosen hardware, and the
* completion screen only restarting when a saved step requires it.
*/
import { test, expect } from "../../fixtures/frigate-test";
import type { Page } from "@playwright/test";
import { gotoDetectorStep, installFirstRun } from "../../helpers/setup-wizard";
const NVIDIA_HARDWARE = [
{
key: "onnx:nvidia",
detector: "onnx",
name: "NVIDIA GeForce RTX 3060",
units: [{ device: "onnx:0", label: "NVIDIA GeForce RTX 3060" }],
count: 1,
unlimited: true,
},
{
key: "cpu",
detector: "cpu",
name: "CPU",
units: [{ device: "cpu", label: "CPU" }],
count: 1,
unlimited: true,
},
];
type SavedConfig = {
config_data?: {
models?: { devices: string[]; path?: string }[];
detect?: { enabled?: boolean };
ffmpeg?: { hwaccel_args?: string | string[] };
};
};
async function captureSaves(page: Page): Promise<SavedConfig[]> {
const saves: SavedConfig[] = [];
await page.route("**/api/config/set**", (route) => {
saves.push(route.request().postDataJSON() as SavedConfig);
return route.fulfill({ json: { success: true, require_restart: true } });
});
return saves;
}
async function captureRestarts(page: Page): Promise<string[]> {
const calls: string[] = [];
await page.route("**/api/restart", (route) => {
calls.push(route.request().url());
return route.fulfill({ json: { success: true, message: "Restarting" } });
});
return calls;
}
test.describe("setup wizard hardware @high @mobile", () => {
test("lists probed hardware and writes a models config", async ({
frigateApp,
page,
}) => {
await installFirstRun(frigateApp, page, {
hwaccel: {
recommended: "vaapi",
available: [
{ key: "vaapi", presets: { any: "preset-vaapi" } },
{
key: "intel-qsv",
presets: {
h264: "preset-intel-qsv-h264",
h265: "preset-intel-qsv-h265",
},
},
],
},
});
const saves = await captureSaves(page);
await frigateApp.gotoAndWait("/", "text=Welcome to Frigate");
await gotoDetectorStep(page);
// the default hardware mock reports two Corals, an Intel GPU, and the CPU
await expect(
page.getByRole("radio", { name: /Coral EdgeTPU \(PCIe\) \(2\)/ }),
).toBeChecked();
await expect(page.getByText("Recommended")).toBeVisible();
await page.getByRole("button", { name: "Next" }).click();
await expect(page.getByText("Hardware Acceleration")).toBeVisible();
const detectorSave = saves.find((save) => save.config_data?.models);
expect(detectorSave?.config_data?.models).toEqual([
{ devices: ["edgetpu:pci:0"] },
]);
expect(detectorSave?.config_data?.detect).toEqual({ enabled: true });
// VAAPI decodes any codec, so one global value covers every camera
await expect(page.getByText("Will use VAAPI (Intel/AMD)")).toBeVisible();
await page.getByRole("button", { name: "Next" }).click();
await expect
.poll(
() =>
saves.find((save) => save.config_data?.ffmpeg)?.config_data?.ffmpeg,
)
.toEqual({
hwaccel_args: "preset-vaapi",
});
// the saved steps only take effect after a restart
const restarts = await captureRestarts(page);
await page.getByRole("button", { name: "Skip" }).click();
await expect(page.getByText("You're done!")).toBeVisible();
await expect(
page.getByText("Frigate needs to restart to apply your settings"),
).toBeVisible();
await page.getByRole("button", { name: "Apply & Restart" }).click();
await expect(page.getByText("Starting Frigate...")).toBeVisible();
await expect.poll(() => restarts).toHaveLength(1);
});
test("defers model setup for onnx hardware without Frigate+", async ({
frigateApp,
page,
}) => {
await installFirstRun(frigateApp, page, {
hardware: NVIDIA_HARDWARE,
});
const saves = await captureSaves(page);
await frigateApp.gotoAndWait("/", "text=Welcome to Frigate");
await gotoDetectorStep(page);
await expect(
page.getByRole("radio", { name: /NVIDIA GeForce RTX 3060/ }),
).toBeChecked();
await page
.getByRole("button", { name: "Continue without detection" })
.click();
// advances without touching the config
await expect(page.getByText("Hardware Acceleration")).toBeVisible();
expect(saves.filter((save) => save.config_data?.models)).toHaveLength(0);
// nothing derived and nothing saved, so finishing needs no restart
const restarts = await captureRestarts(page);
await expect(page.getByText("No supported video card found")).toBeVisible();
await page.getByRole("button", { name: "Next" }).click();
await page.getByRole("button", { name: "Skip" }).click();
await expect(page.getByText("You're done!")).toBeVisible();
await expect(
page.getByText("Frigate needs to restart to apply your settings"),
).toBeHidden();
await page.getByRole("button", { name: "Go to Live View" }).click();
// hands off without restarting, and the wizard does not come back
await expect(page.getByText("Welcome to Frigate")).toBeHidden();
expect(restarts).toHaveLength(0);
});
test("offers only the presets the hardware supports", async ({
frigateApp,
page,
}) => {
await installFirstRun(frigateApp, page, {
hardware: NVIDIA_HARDWARE,
hwaccel: {
recommended: "nvidia",
available: [{ key: "nvidia", presets: { any: "preset-nvidia" } }],
},
});
await captureSaves(page);
await frigateApp.gotoAndWait("/", "text=Welcome to Frigate");
await gotoDetectorStep(page);
await page
.getByRole("button", { name: "Continue without detection" })
.click();
await expect(page.getByText("Hardware Acceleration")).toBeVisible();
// an NVIDIA box has no business being offered Rockchip or Pi decoding
await expect(
page.getByRole("radio", { name: "CUDA (NVIDIA)" }),
).toBeVisible();
await expect(
page.getByRole("radio", { name: /Raspberry Pi/ }),
).toBeHidden();
await expect(page.getByRole("radio", { name: /Rockchip/ })).toBeHidden();
// Auto and None are always available
await expect(page.getByRole("radio", { name: "Auto" })).toBeVisible();
await expect(
page.getByRole("radio", { name: "None (software decoding)" }),
).toBeVisible();
});
test("a codec specific family falls back to h264 with no cameras", async ({
frigateApp,
page,
}) => {
await installFirstRun(frigateApp, page, {
hwaccel: {
recommended: "jetson",
available: [
{
key: "jetson",
presets: {
h264: "preset-jetson-h264",
h265: "preset-jetson-h265",
},
},
],
},
});
const saves = await captureSaves(page);
await frigateApp.gotoAndWait("/", "text=Welcome to Frigate");
await gotoDetectorStep(page);
await page.getByRole("button", { name: "Next" }).click();
await expect(page.getByText("Hardware Acceleration")).toBeVisible();
await expect(
page.getByRole("radio", { name: "NVIDIA Jetson" }),
).toBeVisible();
await page.getByRole("button", { name: "Next" }).click();
// no camera was added, so there is no codec to match
await expect
.poll(
() =>
saves.find((save) => save.config_data?.ffmpeg)?.config_data?.ffmpeg,
)
.toEqual({
hwaccel_args: "preset-jetson-h264",
});
});
test("None writes an explicit empty hwaccel list", async ({
frigateApp,
page,
}) => {
await installFirstRun(frigateApp, page);
const saves = await captureSaves(page);
await frigateApp.gotoAndWait("/", "text=Welcome to Frigate");
await gotoDetectorStep(page);
await page.getByRole("button", { name: "Next" }).click();
await expect(page.getByText("Hardware Acceleration")).toBeVisible();
await page.getByRole("radio", { name: "None (software decoding)" }).click();
await page.getByRole("button", { name: "Next" }).click();
await expect
.poll(
() =>
saves.find((save) => save.config_data?.ffmpeg)?.config_data?.ffmpeg,
)
.toEqual({ hwaccel_args: [] });
});
});