From f4ef7936fcc70c82911f629a098a79d296ca4264 Mon Sep 17 00:00:00 2001 From: usounds <46260022+usounds@users.noreply.github.com> Date: Mon, 7 Sep 2026 21:43:50 +0900 Subject: [PATCH] =?UTF-8?q?fix=20:=20=E5=85=88=E8=AA=AD=E3=81=BF=E7=A6=81?= =?UTF-8?q?=E6=AD=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/pnpm-lock.yaml | 49 ++++-------- frontend/src/components/TagBadge.tsx | 1 + .../src/components/__tests__/Article.test.tsx | 9 ++- .../__tests__/ArticleListItem.test.tsx | 77 +++++++++++++++++++ .../components/__tests__/TagBadge.test.tsx | 5 +- .../src/components/bookmarkcard/Article.tsx | 1 + .../bookmarkcard/ArticleListItem.tsx | 1 + 7 files changed, 105 insertions(+), 38 deletions(-) create mode 100644 frontend/src/components/__tests__/ArticleListItem.test.tsx diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index ed2f977..b46a29d 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -250,7 +250,7 @@ importers: devDependencies: '@atcute/lex-cli': specifier: ^3.3.0 - version: 3.3.0(@atcute/cbor@2.3.6(@atcute/cid@2.4.2))(@atcute/cid@2.4.2)(prettier@3.9.6)(typescript@7.0.2) + version: 3.3.0(@atcute/cbor@2.3.6(@atcute/cid@2.4.2))(@atcute/cid@2.4.2)(typescript@7.0.2) '@next/eslint-plugin-next': specifier: ^16.3.4 version: 16.3.4(eslint@10.10.0(jiti@2.7.0)) @@ -289,7 +289,7 @@ importers: version: 8.69.0(eslint@10.10.0(jiti@2.7.0))(typescript@7.0.2) '@vitejs/plugin-react': specifier: ^6.1.1 - version: 6.1.1(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0)) + version: 6.1.1(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)) '@vitest/coverage-v8': specifier: 5.0.0 version: 5.0.0(vitest@5.0.0) @@ -337,10 +337,10 @@ importers: version: 7.0.2 vite: specifier: ^8.2.2 - version: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0) + version: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13) vitest: specifier: ^5.0.0 - version: 5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0)) + version: 5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)) packages: @@ -4121,11 +4121,6 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.9.6: - resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} - engines: {node: '>=14'} - hasBin: true - pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -4875,11 +4870,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} - hasBin: true - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -5003,7 +4993,7 @@ snapshots: transitivePeerDependencies: - typescript - '@atcute/lex-cli@3.3.0(@atcute/cbor@2.3.6(@atcute/cid@2.4.2))(@atcute/cid@2.4.2)(prettier@3.9.6)(typescript@7.0.2)': + '@atcute/lex-cli@3.3.0(@atcute/cbor@2.3.6(@atcute/cid@2.4.2))(@atcute/cid@2.4.2)(typescript@7.0.2)': dependencies: '@atcute/identity': 2.0.2(@atcute/lexicons@2.1.0)(typescript@7.0.2) '@atcute/identity-resolver': 2.0.1(@atcute/identity@2.0.2(@atcute/lexicons@2.1.0)(typescript@7.0.2))(@atcute/lexicons@2.1.0)(typescript@7.0.2) @@ -5015,8 +5005,6 @@ snapshots: '@optique/run': 1.2.5 picocolors: 1.1.1 valibot: 1.4.2(typescript@7.0.2) - optionalDependencies: - prettier: 3.9.6 transitivePeerDependencies: - '@atcute/cbor' - '@atcute/cid' @@ -6288,7 +6276,7 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 optionalDependencies: - vitest: 5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0)) + vitest: 5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)) '@testing-library/react@16.3.3(@testing-library/dom@10.4.1)(@types/react-dom@19.2.7(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: @@ -6700,10 +6688,10 @@ snapshots: d3-time-format: 4.1.0 internmap: 2.0.3 - '@vitejs/plugin-react@6.1.1(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0))': + '@vitejs/plugin-react@6.1.1(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13) '@vitest/coverage-v8@5.0.0(vitest@5.0.0)': dependencies: @@ -6715,7 +6703,7 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0)) + vitest: 5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)) '@vitest/istanbul-lib-coverage@1.0.1': {} @@ -6723,14 +6711,14 @@ snapshots: dependencies: '@vitest/istanbul-lib-coverage': 1.0.1 - '@vitest/mocker@5.0.0(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0))': + '@vitest/mocker@5.0.0(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.0 estree-walker: 3.0.3 magic-string: 1.2.3 optionalDependencies: - vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13) '@vitest/spy@5.0.0': {} @@ -8815,9 +8803,6 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.9.6: - optional: true - pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -9554,7 +9539,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0): + vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -9569,12 +9554,11 @@ snapshots: sass: 1.104.0 sugarss: 5.0.1(postcss@8.5.28) tsx: 4.23.13 - yaml: 2.9.0 - vitest@5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0)): + vitest@5.0.0(@types/node@26.4.1)(@vitest/coverage-v8@5.0.0)(jsdom@30.0.1(@noble/hashes@1.8.0))(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.0(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(vite@8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)) chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -9585,7 +9569,7 @@ snapshots: tinybench: 6.1.4 tinyexec: 1.3.0 tinyglobby: 0.2.17 - vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13)(yaml@2.9.0) + vite: 8.2.2(@types/node@26.4.1)(esbuild@0.28.2)(jiti@2.7.0)(sass@1.104.0)(sugarss@5.0.1(postcss@8.5.28))(tsx@4.23.13) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.4.1 @@ -9698,9 +9682,6 @@ snapshots: yallist@3.1.1: {} - yaml@2.9.0: - optional: true - yocto-queue@0.1.0: {} zeptomatch@2.1.0: diff --git a/frontend/src/components/TagBadge.tsx b/frontend/src/components/TagBadge.tsx index 26bb39c..c443bce 100644 --- a/frontend/src/components/TagBadge.tsx +++ b/frontend/src/components/TagBadge.tsx @@ -51,6 +51,7 @@ export const TagBadge: React.FC = ({ tags, locale }) => { > ({ // Mock dependencies vi.mock('next/link', () => ({ - default: ({ children, href }: { children: React.ReactNode; href: string }) => ( - {children} + default: ({ children, href, prefetch }: { children: React.ReactNode; href: string; prefetch?: boolean }) => ( + {children} ), })); @@ -108,6 +108,11 @@ describe('Article', () => { expect(screen.getByText('テスト記事')).toBeInTheDocument(); }); + it('記事詳細ページを先読みしない', () => { + render(
); + expect(screen.getByText('テスト記事').closest('a')).toHaveAttribute('data-prefetch', 'false'); + }); + it('ハンドルを表示する', () => { render(
); expect(screen.getByText(/user.bsky.social/)).toBeInTheDocument(); diff --git a/frontend/src/components/__tests__/ArticleListItem.test.tsx b/frontend/src/components/__tests__/ArticleListItem.test.tsx new file mode 100644 index 0000000..4957a40 --- /dev/null +++ b/frontend/src/components/__tests__/ArticleListItem.test.tsx @@ -0,0 +1,77 @@ +import { describe, expect, it, vi } from 'vitest'; +import { screen } from '@testing-library/react'; +import { render } from '../../test-utils'; +import { ArticleListItem } from '../bookmarkcard/ArticleListItem'; + +vi.mock('../bookmarkcard/ArticleListItem.module.scss', () => ({ + default: {}, +})); + +vi.mock('next/link', () => ({ + default: ({ children, href, prefetch }: { children: React.ReactNode; href: string; prefetch?: boolean }) => ( + {children} + ), +})); + +vi.mock('next-intl', () => ({ + useLocale: () => 'ja', + useMessages: () => ({ detail: { view: '詳細を見る' } }), +})); + +vi.mock('next/dynamic', () => ({ + default: () => ({ children }: { children: string }) => {children}, +})); + +vi.mock('@/components/BlurReveal', () => ({ + BlurReveal: ({ children }: { children: React.ReactNode }) =>
{children}
, +})); + +vi.mock('@/components/ModerationBadges', () => ({ + ModerationBadges: () => null, +})); + +vi.mock('@/components/TagBadge', () => ({ + TagBadge: () => null, +})); + +vi.mock('@/components/EditMenu', () => ({ + default: () => null, +})); + +vi.mock('@/components/TimeAgo', () => ({ + default: () => null, +})); + +vi.mock('@/components/Like', () => ({ + default: () => null, +})); + +vi.mock('@/components/ArticleImage', () => ({ + default: () => null, +})); + +vi.mock('lucide-react', () => ({ + Globe: () => null, + Users: () => null, +})); + +describe('ArticleListItem', () => { + it('記事詳細ページを先読みしない', () => { + render( + , + ); + + const link = screen.getByText('テスト記事').closest('a'); + expect(link).toHaveAttribute( + 'href', + '/ja/bookmark/details?uri=https%3A%2F%2Fexample.com%2Farticle', + ); + expect(link).toHaveAttribute('data-prefetch', 'false'); + }); +}); diff --git a/frontend/src/components/__tests__/TagBadge.test.tsx b/frontend/src/components/__tests__/TagBadge.test.tsx index 40f6f65..8f68c55 100644 --- a/frontend/src/components/__tests__/TagBadge.test.tsx +++ b/frontend/src/components/__tests__/TagBadge.test.tsx @@ -4,8 +4,8 @@ import { TagBadge } from '../TagBadge'; // Mock next/link vi.mock('next/link', () => ({ - default: ({ children, href }: { children: React.ReactNode; href: string }) => ( - {children} + default: ({ children, href, prefetch }: { children: React.ReactNode; href: string; prefetch?: boolean }) => ( + {children} ), })); @@ -59,6 +59,7 @@ describe('TagBadge', () => { await waitFor(() => { const link = screen.getByRole('link'); expect(link).toHaveAttribute('href', '/en/bookmark/search?tag=mytag'); + expect(link).toHaveAttribute('data-prefetch', 'false'); }); }); }); diff --git a/frontend/src/components/bookmarkcard/Article.tsx b/frontend/src/components/bookmarkcard/Article.tsx index 5985ad3..0f1b7b1 100644 --- a/frontend/src/components/bookmarkcard/Article.tsx +++ b/frontend/src/components/bookmarkcard/Article.tsx @@ -125,6 +125,7 @@ export function Article({
{title} diff --git a/frontend/src/components/bookmarkcard/ArticleListItem.tsx b/frontend/src/components/bookmarkcard/ArticleListItem.tsx index f5240a1..64be9f0 100644 --- a/frontend/src/components/bookmarkcard/ArticleListItem.tsx +++ b/frontend/src/components/bookmarkcard/ArticleListItem.tsx @@ -143,6 +143,7 @@ export function ArticleListItem({ {title} -- knotmirror 0.0.1