diff --git a/frontend/jest.setup.ts b/frontend/jest.setup.ts
index b2ed640a4..f76fb5b23 100644
--- a/frontend/jest.setup.ts
+++ b/frontend/jest.setup.ts
@@ -191,6 +191,6 @@ global.fetch = jest.fn().mockImplementation((url: string) => {
return Promise.resolve({
ok: true,
status: 200,
- json: () => Promise.resolve({}),
+ json: () => Promise.resolve({ success: true, data: [] }),
});
});
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 0a6a8fc7a..50c0c0c00 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -129,7 +129,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -782,7 +781,6 @@
"integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1708,7 +1706,6 @@
"integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.27.1",
"@babel/helper-module-imports": "^7.27.1",
@@ -5358,7 +5355,8 @@
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -5536,7 +5534,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz",
"integrity": "sha512-FE5u0ezmi6y9OZEzlJfg37mqqf6ZDSF2V/NLjUyGrR9uTZ7Sb9F7bLNZ03S4XVUNRWGA7Ck4c1kK+YnuWjl+DA==",
"license": "MIT",
- "peer": true,
"dependencies": {
"undici-types": "~6.21.0"
}
@@ -5554,7 +5551,6 @@
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -5565,7 +5561,6 @@
"integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==",
"devOptional": true,
"license": "MIT",
- "peer": true,
"peerDependencies": {
"@types/react": "^19.2.0"
}
@@ -5695,7 +5690,6 @@
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
"dev": true,
"license": "BSD-2-Clause",
- "peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.62.0",
"@typescript-eslint/types": "5.62.0",
@@ -5942,7 +5936,6 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
- "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -6649,7 +6642,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.8.19",
"caniuse-lite": "^1.0.30001751",
@@ -7358,7 +7350,8 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/domexception": {
"version": "4.0.0",
@@ -7717,7 +7710,6 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -9762,7 +9754,6 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -11247,6 +11238,7 @@
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -11933,7 +11925,6 @@
}
],
"license": "MIT",
- "peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -11966,7 +11957,6 @@
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -12070,6 +12060,7 @@
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -12085,6 +12076,7 @@
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=10"
},
@@ -12204,7 +12196,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -12263,7 +12254,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@@ -12299,14 +12289,14 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/react-redux": {
"version": "9.2.0",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -12468,8 +12458,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -13432,7 +13421,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -13573,7 +13561,6 @@
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@@ -13806,7 +13793,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
"integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
"license": "Apache-2.0",
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -14065,7 +14051,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"license": "MIT",
- "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -14198,7 +14183,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
diff --git a/frontend/src/pages/AITagging/AITagging.tsx b/frontend/src/pages/AITagging/AITagging.tsx
index 187bda3df..e4bda4c52 100644
--- a/frontend/src/pages/AITagging/AITagging.tsx
+++ b/frontend/src/pages/AITagging/AITagging.tsx
@@ -35,7 +35,7 @@ export const AITagging = () => {
} else if (imagesError) {
dispatch(hideLoader());
} else if (imagesSuccess) {
- const images = imagesData?.data as Image[];
+ const images = (imagesData?.data ?? []) as Image[];
dispatch(setImages(images));
dispatch(hideLoader());
}
diff --git a/frontend/src/pages/Home/Home.tsx b/frontend/src/pages/Home/Home.tsx
index 83c9e5c83..ed5a7da31 100644
--- a/frontend/src/pages/Home/Home.tsx
+++ b/frontend/src/pages/Home/Home.tsx
@@ -40,7 +40,7 @@ export const Home = () => {
useEffect(() => {
if (!isSearchActive && isSuccess) {
- const images = data?.data as Image[];
+ const images = (data?.data ?? []) as Image[];
dispatch(setImages(images));
}
}, [data, isSuccess, dispatch, isSearchActive]);
diff --git a/frontend/src/pages/Home/MyFav.tsx b/frontend/src/pages/Home/MyFav.tsx
index 2afcb70e8..592c93ca9 100644
--- a/frontend/src/pages/Home/MyFav.tsx
+++ b/frontend/src/pages/Home/MyFav.tsx
@@ -42,7 +42,7 @@ export const MyFav = () => {
// Handle fetching lifecycle
useEffect(() => {
if (!isSearchActive && isSuccess) {
- const images = data?.data as Image[];
+ const images = (data?.data ?? []) as Image[];
dispatch(setImages(images));
}
}, [data, isSuccess, dispatch, isSearchActive]);
diff --git a/frontend/src/pages/__tests__/PageSanity.test.tsx b/frontend/src/pages/__tests__/PageSanity.test.tsx
index 453daa63d..9c68744df 100644
--- a/frontend/src/pages/__tests__/PageSanity.test.tsx
+++ b/frontend/src/pages/__tests__/PageSanity.test.tsx
@@ -1,4 +1,4 @@
-import { render, screen } from '@/test-utils';
+import { render, screen, act } from '@/test-utils';
import { Home } from '../Home/Home';
import Settings from '../SettingsPage/Settings';
@@ -15,8 +15,11 @@ describe('Page Sanity Tests', () => {
});
describe('Settings Page', () => {
- test('renders settings page sections', () => {
+ test('renders settings page sections', async () => {
render();
+ await act(async () => {
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ });
expect(screen.getByText('Folder Management')).toBeInTheDocument();
expect(screen.getByText('User Preferences')).toBeInTheDocument();
@@ -26,6 +29,6 @@ describe('Page Sanity Tests', () => {
screen.getByRole('button', { name: /Check for Updates/i }),
).toBeInTheDocument();
expect(screen.getByText('GPU Acceleration')).toBeInTheDocument();
- }); // Settings is expected to render synchronously.
+ });
});
});
diff --git a/frontend/src/pages/__tests__/SettingsPage.test.tsx b/frontend/src/pages/__tests__/SettingsPage.test.tsx
index 345edd456..f173afd19 100644
--- a/frontend/src/pages/__tests__/SettingsPage.test.tsx
+++ b/frontend/src/pages/__tests__/SettingsPage.test.tsx
@@ -1,19 +1,22 @@
-import { render, screen } from '@/test-utils';
+import { render, screen, act } from '@/test-utils';
import userEvent from '@testing-library/user-event';
import Settings from '../SettingsPage/Settings';
describe('Settings Page', () => {
// shared setup for all tests
- const setupTest = () => {
+ const setupTest = async () => {
const user = userEvent.setup();
render();
+ await act(async () => {
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ });
return { user };
};
describe('Interaction Sanity', () => {
describe('User Preferences Section', () => {
test('YOLO model dropdown opens and shows options', async () => {
- const { user } = setupTest();
+ const { user } = await setupTest();
const dropdownTrigger = screen.getByRole('button', {
name: /nano|small|medium/i,
@@ -28,7 +31,7 @@ describe('Settings Page', () => {
});
test('GPU Acceleration toggle changes state on click', async () => {
- const { user } = setupTest();
+ const { user } = await setupTest();
const gpuSwitch = screen.getByRole('switch');
expect(gpuSwitch).toHaveAttribute('aria-checked', 'false');
@@ -49,7 +52,7 @@ describe('Settings Page', () => {
test.each(buttonCases)(
'$label button does not crash when clicked',
async ({ name }) => {
- const { user } = setupTest();
+ const { user } = await setupTest();
const button = screen.getByRole('button', { name });
@@ -71,7 +74,7 @@ describe('Settings Page', () => {
test.each(yoloSelectionCases)(
'selecting $expectedText updates dropdown display',
async ({ selectOption, expectedText }) => {
- const { user } = setupTest();
+ const { user } = await setupTest();
const dropdownTrigger = screen.getByRole('button', { name: /nano/i });
expect(dropdownTrigger).toHaveTextContent('Nano');
@@ -88,7 +91,7 @@ describe('Settings Page', () => {
);
test('dropdown can be reopened after selection', async () => {
- const { user } = setupTest();
+ const { user } = await setupTest();
const dropdownTrigger = screen.getByRole('button', { name: /nano/i });
await user.click(dropdownTrigger);
@@ -102,7 +105,7 @@ describe('Settings Page', () => {
describe('GPU Acceleration Toggle', () => {
test('toggle cycles through ON/OFF states', async () => {
- const { user } = setupTest();
+ const { user } = await setupTest();
const gpuSwitch = screen.getByRole('switch');
expect(gpuSwitch).toHaveAttribute('aria-checked', 'false');
diff --git a/frontend/src/pages/__tests__/allPages.test.tsx b/frontend/src/pages/__tests__/allPages.test.tsx
index 9de439f6d..21b25b3dd 100644
--- a/frontend/src/pages/__tests__/allPages.test.tsx
+++ b/frontend/src/pages/__tests__/allPages.test.tsx
@@ -1,4 +1,4 @@
-import { render } from '@testing-library/react';
+import { render, act } from '@testing-library/react';
import { AITagging } from '@/pages/AITagging/AITagging';
import Album from '../Album/Album';
import { Home } from '@/pages/Home/Home';
@@ -23,7 +23,7 @@ const pages = [
describe('Page rendering tests', () => {
pages.forEach(({ path, Component }) => {
- test(`renders ${path} without crashing`, () => {
+ test(`renders ${path} without crashing`, async () => {
render(
@@ -35,6 +35,9 @@ describe('Page rendering tests', () => {
,
);
+ await act(async () => {
+ await new Promise((resolve) => setTimeout(resolve, 0));
+ });
});
});
});