diff --git a/package-lock.json b/package-lock.json index 40570cc..f66e81d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -146,6 +146,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1839,6 +1840,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" }, @@ -1879,6 +1881,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=20.19.0" } @@ -2713,6 +2716,7 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -3484,8 +3488,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -3584,6 +3587,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3594,6 +3598,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -3662,6 +3667,7 @@ "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/types": "8.55.0", @@ -4029,6 +4035,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4491,6 +4498,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5057,8 +5065,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/dom-helpers": { "version": "5.2.1", @@ -5483,6 +5490,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5543,6 +5551,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -7246,6 +7255,7 @@ "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@acemir/cssom": "^0.9.28", "@asamuzakjp/dom-selector": "^6.7.6", @@ -7515,7 +7525,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -8115,6 +8124,7 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -8157,7 +8167,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -8173,7 +8182,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -8275,6 +8283,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -8315,6 +8324,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -8336,8 +8346,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-lifecycles-compat": { "version": "3.0.4", @@ -8546,6 +8555,7 @@ "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -9549,6 +9559,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9732,6 +9743,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -9875,6 +9887,7 @@ "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", @@ -10324,6 +10337,7 @@ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -10501,6 +10515,7 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -10791,6 +10806,7 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/renovate.json b/renovate.json index 5d34d1f..a1703bb 100644 --- a/renovate.json +++ b/renovate.json @@ -2,10 +2,15 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:base"], "enabledManagers": ["npm", "github-actions"], - "schedule": ["before 8am on Monday"], + "schedule": ["before 8pm on Sunday"], "rangeStrategy": "bump", "rebaseWhen": "behind-base-branch", "packageRules": [ + { + "matchPackageNames": ["eslint", "@eslint/js"], + "allowedVersions": "<10.0.0", + "description": "Block eslint 10 until eslint-plugin-react-hooks supports it" + }, { "matchPackagePatterns": ["*"], "matchUpdateTypes": ["minor", "patch", "pin", "digest"], diff --git a/src/components/__tests__/SimpleLayout.test.tsx b/src/components/__tests__/SimpleLayout.test.tsx index 37d8527..2bdd887 100644 --- a/src/components/__tests__/SimpleLayout.test.tsx +++ b/src/components/__tests__/SimpleLayout.test.tsx @@ -181,7 +181,7 @@ describe('SimpleLayout Component', () => { vi.mocked(geminiService.createGeminiService).mockReturnValue(mockService as any); - const consoleErrorSpy = vi.spyOn(console, 'error'); + const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); render(); const apiKeyInput = screen.getByLabelText('API Key'); @@ -211,7 +211,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '123456-7890', + account_number: '123457-7894', bank_code: '0800', amount: 1000, currency: 'CZK', @@ -244,7 +244,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 500, currency: 'CZK', @@ -277,7 +277,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '123-45', + account_number: '123-43', bank_code: '0800', amount: 250, currency: 'CZK', @@ -310,7 +310,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1-999', + account_number: '19-924', bank_code: '0800', amount: 100, currency: 'CZK', @@ -484,7 +484,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 500, currency: 'CZK', @@ -519,7 +519,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 1500, currency: 'CZK', @@ -554,7 +554,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 750, currency: 'CZK', @@ -589,7 +589,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 800, currency: 'CZK', @@ -624,7 +624,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 2000, currency: 'CZK', @@ -659,7 +659,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 600, currency: 'CZK', @@ -703,7 +703,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 500, currency: 'CZK', @@ -738,7 +738,7 @@ describe('SimpleLayout Component', () => { const mockService = createMockGeminiService({ text: 'Gemini API response', paymentData: { - account_number: '1234567890', + account_number: '1234567899', bank_code: '0800', amount: 500, currency: 'CZK', @@ -774,13 +774,13 @@ describe('SimpleLayout Component', () => { it('displays validation warning when validation fails', async () => { const mockService = createMockGeminiService({ text: JSON.stringify({ - account_number: '123456789', + account_number: '123', bank_code: '0100', amount: 1000, currency: 'CZK', }), paymentData: { - account_number: '123456789', + account_number: '123', bank_code: '0100', amount: 1000, currency: 'CZK', @@ -813,13 +813,13 @@ describe('SimpleLayout Component', () => { it('dismisses validation warning when close button is clicked', async () => { const mockService = createMockGeminiService({ text: JSON.stringify({ - account_number: '123456789', + account_number: '123', bank_code: '0100', amount: 1000, currency: 'CZK', }), paymentData: { - account_number: '123456789', + account_number: '123', bank_code: '0100', amount: 1000, currency: 'CZK', diff --git a/src/hooks/__tests__/useQRCodeShare.test.ts b/src/hooks/__tests__/useQRCodeShare.test.ts index 0263413..4b24790 100644 --- a/src/hooks/__tests__/useQRCodeShare.test.ts +++ b/src/hooks/__tests__/useQRCodeShare.test.ts @@ -135,14 +135,19 @@ describe('useQRCodeShare hook', () => { expect(mockShareOrDownloadQRCode).toHaveBeenCalledWith(svgElement, customFilename); }); - it('clears error when clearError is called', () => { + it('clears error when clearError is called', async () => { + mockShareOrDownloadQRCode.mockRejectedValue(new Error('test error')); + const { result } = renderHook(() => useQRCodeShare()); - // Manually set error state - act(() => { - result.current.shareQRCode(document.createElementNS('http://www.w3.org/2000/svg', 'svg')); + await act(async () => { + await result.current.shareQRCode( + document.createElementNS('http://www.w3.org/2000/svg', 'svg') + ); }); + expect(result.current.state.error).toBe('test error'); + act(() => { result.current.clearError(); }); diff --git a/src/test/setup.ts b/src/test/setup.ts index 1b9401e..e559cb8 100644 --- a/src/test/setup.ts +++ b/src/test/setup.ts @@ -6,6 +6,19 @@ import { beforeAll, afterEach, vi } from 'vitest'; beforeAll(() => { // Setup global test environment + // Fix NaN timeout warnings from Bootstrap transitions in jsdom. + // Bootstrap's Collapse/Transition reads CSS transitionDuration via getComputedStyle, + // which returns empty strings in jsdom. parseFloat('') → NaN → setTimeout(fn, NaN) + // triggers Node.js TimeoutNaNWarning. + const origSetTimeout = globalThis.setTimeout; + globalThis.setTimeout = ((handler: TimerHandler, timeout?: number, ...args: unknown[]) => { + return origSetTimeout( + handler, + typeof timeout === 'number' && Number.isNaN(timeout) ? 0 : timeout, + ...args + ); + }) as typeof globalThis.setTimeout; + // Mock window.matchMedia for mobile detection tests Object.defineProperty(window, 'matchMedia', { writable: true,