From a6edd50a5d292e29e6292754a7be95205ac7dbc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AC=E3=82=8B=E3=81=8D=E3=82=83=E3=81=A3=E3=81=A8?= Date: Fri, 28 Jun 2024 11:16:12 +0900 Subject: [PATCH 1/2] =?UTF-8?q?chore(docker-compose):=20=E6=8E=A8=E5=A5=A8?= =?UTF-8?q?=E3=81=AE=E5=90=8D=E5=89=8D=E3=81=AB=E3=81=99=E3=82=8B=20(#1409?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(docker-compose): 推奨の名前にする https://github.com/compose-spec/compose-spec/blob/5c18e329d5a15a15e4b636ed093b256b96615e33/spec.md#compose-file * yaml to yml * fix * fix --- .devcontainer/{docker-compose.yml => compose.yml} | 2 -- .devcontainer/devcontainer.json | 2 +- .dockerignore | 4 ++-- .github/workflows/dockle.yml | 2 +- .gitignore | 4 ++-- CONTRIBUTING.md | 2 +- docker-compose.local-db.yml => compose.local-db.yml | 2 -- docker-compose_example.yml => compose_example.yml | 2 -- packages/backend/test/{docker-compose.yml => compose.yml} | 2 -- 9 files changed, 7 insertions(+), 15 deletions(-) rename .devcontainer/{docker-compose.yml => compose.yml} (98%) rename docker-compose.local-db.yml => compose.local-db.yml (98%) rename docker-compose_example.yml => compose_example.yml (99%) rename packages/backend/test/{docker-compose.yml => compose.yml} (94%) diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/compose.yml similarity index 98% rename from .devcontainer/docker-compose.yml rename to .devcontainer/compose.yml index a52d086fb6fc..d02d2a8f4a89 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: app: build: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 344edbd65d93..7ea23e314ea4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "Misskey", - "dockerComposeFile": "docker-compose.yml", + "dockerComposeFile": "compose.yml", "service": "app", "workspaceFolder": "/workspace", "features": { diff --git a/.dockerignore b/.dockerignore index 1de0c7982bcd..7dbb06e1d0e6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,7 +7,7 @@ Dockerfile build/ built/ db/ -docker-compose.yml +.devcontainer/compose.yml node_modules/ packages/*/node_modules redis/ @@ -28,4 +28,4 @@ fluent-emojis/ .idea/ packages/*/.vscode/ -packages/backend/test/docker-compose.yml +packages/backend/test/compose.yml diff --git a/.github/workflows/dockle.yml b/.github/workflows/dockle.yml index 968971dd8d25..c3dba4213d31 100644 --- a/.github/workflows/dockle.yml +++ b/.github/workflows/dockle.yml @@ -22,7 +22,7 @@ jobs: sudo dpkg -i dockle.deb - run: | cp .config/docker_example.env .config/docker.env - cp ./docker-compose_example.yml ./docker-compose.yml + cp ./compose_example.yml ./compose.yml - run: | docker compose up -d web docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest diff --git a/.gitignore b/.gitignore index bdc14fea0aba..3466984cf648 100644 --- a/.gitignore +++ b/.gitignore @@ -35,8 +35,8 @@ coverage !/.config/example.yml !/.config/docker_example.yml !/.config/docker_example.env -docker-compose.yml -!/.devcontainer/docker-compose.yml +.devcontainer/compose.yml +!/.devcontainer/compose.yml # misskey /build diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dcb625626d6f..06c2d2f21daf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -165,7 +165,7 @@ cp .github/misskey/test.yml .config/ ``` Prepare DB/Redis for testing. ``` -docker compose -f packages/backend/test/docker-compose.yml up +docker compose -f packages/backend/test/compose.yaml up ``` Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`. diff --git a/docker-compose.local-db.yml b/compose.local-db.yml similarity index 98% rename from docker-compose.local-db.yml rename to compose.local-db.yml index 16ba4b49e179..3835cb23dbad 100644 --- a/docker-compose.local-db.yml +++ b/compose.local-db.yml @@ -1,5 +1,3 @@ -version: "3" - # このconfigは、 dockerでMisskey本体を起動せず、 redisとpostgresql などだけを起動します services: diff --git a/docker-compose_example.yml b/compose_example.yml similarity index 99% rename from docker-compose_example.yml rename to compose_example.yml index 5cebbe416467..75d0d3a59ca2 100644 --- a/docker-compose_example.yml +++ b/compose_example.yml @@ -1,5 +1,3 @@ -version: "3" - services: web: build: . diff --git a/packages/backend/test/docker-compose.yml b/packages/backend/test/compose.yml similarity index 94% rename from packages/backend/test/docker-compose.yml rename to packages/backend/test/compose.yml index f2d899075808..6593fc33dd6c 100644 --- a/packages/backend/test/docker-compose.yml +++ b/packages/backend/test/compose.yml @@ -1,5 +1,3 @@ -version: "3" - services: redistest: image: redis:7 From f1b1e2a7cca3d69eb6162d4c16746968d855ea40 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:57:20 +0900 Subject: [PATCH 2/2] fix(storybook): prevent infinite remount of component (#14101) * fix(storybook): prevent infinite remount of component * fix: disable flaky `.toMatch()` test --- packages/frontend/.storybook/preview.ts | 6 +- .../MkChannelFollowButton.stories.impl.ts | 6 -- .../components/MkClickerGame.stories.impl.ts | 12 ++- .../src/components/MkCwButton.stories.impl.ts | 10 --- .../src/components/global/MkA.stories.impl.ts | 2 - .../components/global/MkAd.stories.impl.ts | 87 +++++++------------ packages/frontend/src/scripts/test-utils.ts | 10 --- 7 files changed, 41 insertions(+), 92 deletions(-) diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts index 73ee007fb8b7..d000a282328f 100644 --- a/packages/frontend/.storybook/preview.ts +++ b/packages/frontend/.storybook/preview.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { FORCE_REMOUNT } from '@storybook/core-events'; +import { FORCE_RE_RENDER, FORCE_REMOUNT } from '@storybook/core-events'; import { addons } from '@storybook/preview-api'; import { type Preview, setup } from '@storybook/vue3'; import isChromatic from 'chromatic/isChromatic'; @@ -16,7 +16,7 @@ import '../src/style.scss'; const appInitialized = Symbol(); -let lastStory = null; +let lastStory: string | null = null; let moduleInitialized = false; let unobserve = () => {}; let misskeyOS = null; @@ -110,7 +110,7 @@ const preview = { }).catch(() => {}); Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => { initLocalStorage(); - channel.emit(FORCE_REMOUNT, { storyId: context.id }); + channel.emit(FORCE_RE_RENDER, { storyId: context.id }); }); } const story = Story(); diff --git a/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts index b99620da22f6..b9770670dcdd 100644 --- a/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts +++ b/packages/frontend/src/components/MkChannelFollowButton.stories.impl.ts @@ -12,14 +12,12 @@ import { expect, userEvent, within } from '@storybook/test'; import { channel } from '../../.storybook/fakes.js'; import { commonHandlers } from '../../.storybook/mocks.js'; import MkChannelFollowButton from './MkChannelFollowButton.vue'; -import { semaphore } from '@/scripts/test-utils.js'; import { i18n } from '@/i18n.js'; function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } -const s = semaphore(); export const Default = { render(args) { return { @@ -46,17 +44,13 @@ export const Default = { full: true, }, async play({ canvasElement }) { - await s.acquire(); - await sleep(1000); const canvas = within(canvasElement); const buttonElement = canvas.getByRole('button'); await expect(buttonElement).toHaveTextContent(i18n.ts.follow); await userEvent.click(buttonElement); await sleep(1000); await expect(buttonElement).toHaveTextContent(i18n.ts.unfollow); - await sleep(100); await userEvent.click(buttonElement); - s.release(); }, parameters: { layout: 'centered', diff --git a/packages/frontend/src/components/MkClickerGame.stories.impl.ts b/packages/frontend/src/components/MkClickerGame.stories.impl.ts index 8378010f8bf7..36313f965daa 100644 --- a/packages/frontend/src/components/MkClickerGame.stories.impl.ts +++ b/packages/frontend/src/components/MkClickerGame.stories.impl.ts @@ -8,7 +8,7 @@ import { StoryObj } from '@storybook/vue3'; import { HttpResponse, http } from 'msw'; import { action } from '@storybook/addon-actions'; -import { expect, within } from '@storybook/test'; +import { expect, userEvent, within } from '@storybook/test'; import { commonHandlers } from '../../.storybook/mocks.js'; import MkClickerGame from './MkClickerGame.vue'; @@ -41,12 +41,10 @@ export const Default = { await sleep(1000); const canvas = within(canvasElement); const count = canvas.getByTestId('count'); - // NOTE: flaky なので N/A も通しておく - await expect(count).toHaveTextContent(/^(0|N\/A)$/); - // FIXME: flaky - // const buttonElement = canvas.getByRole('button'); - // await userEvent.click(buttonElement); - // await expect(count).toHaveTextContent('1'); + await expect(count).toHaveTextContent('0'); + const buttonElement = canvas.getByRole('button'); + await userEvent.click(buttonElement); + await expect(count).toHaveTextContent('1'); }, parameters: { layout: 'centered', diff --git a/packages/frontend/src/components/MkCwButton.stories.impl.ts b/packages/frontend/src/components/MkCwButton.stories.impl.ts index 05c6001552ba..5d6ea56da9f9 100644 --- a/packages/frontend/src/components/MkCwButton.stories.impl.ts +++ b/packages/frontend/src/components/MkCwButton.stories.impl.ts @@ -11,13 +11,6 @@ import { expect, userEvent, within } from '@storybook/test'; import { file } from '../../.storybook/fakes.js'; import MkCwButton from './MkCwButton.vue'; import { i18n } from '@/i18n.js'; -import { semaphore } from '@/scripts/test-utils.js'; - -function sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -const s = semaphore(); export const Default = { render(args) { @@ -54,8 +47,6 @@ export const Default = { text: 'Some CW content', }, async play({ canvasElement }) { - await s.acquire(); - await sleep(1000); const canvas = within(canvasElement); const buttonElement = canvas.getByRole('button'); await expect(buttonElement).toHaveTextContent(i18n.ts._cw.show); @@ -63,7 +54,6 @@ export const Default = { await userEvent.click(buttonElement); await expect(buttonElement).toHaveTextContent(i18n.ts._cw.hide); await userEvent.click(buttonElement); - s.release(); }, parameters: { chromatic: { diff --git a/packages/frontend/src/components/global/MkA.stories.impl.ts b/packages/frontend/src/components/global/MkA.stories.impl.ts index c1d8cf0ca6b2..02e5a7f98c1c 100644 --- a/packages/frontend/src/components/global/MkA.stories.impl.ts +++ b/packages/frontend/src/components/global/MkA.stories.impl.ts @@ -35,12 +35,10 @@ export const Default = { // FIXME: 通るけどその後落ちるのでコメントアウト // await expect(a.href).toMatch(/^https?:\/\/.*#test$/); await userEvent.pointer({ keys: '[MouseRight]', target: a }); - await tick(); const menu = canvas.getByRole('menu'); await expect(menu).toBeInTheDocument(); await userEvent.click(a); a.blur(); - await tick(); await expect(menu).not.toBeInTheDocument(); }, args: { diff --git a/packages/frontend/src/components/global/MkAd.stories.impl.ts b/packages/frontend/src/components/global/MkAd.stories.impl.ts index aef26ab92d64..8c0b7ef52fc1 100644 --- a/packages/frontend/src/components/global/MkAd.stories.impl.ts +++ b/packages/frontend/src/components/global/MkAd.stories.impl.ts @@ -9,12 +9,6 @@ import { StoryObj } from '@storybook/vue3'; import MkAd from './MkAd.vue'; import { i18n } from '@/i18n.js'; -let lock: Promise | undefined; - -function sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - const common = { render(args) { return { @@ -37,56 +31,41 @@ const common = { }; }, async play({ canvasElement, args }) { - if (lock) { - console.warn('This test is unexpectedly running twice in parallel, fix it!'); - console.warn('See also: https://github.com/misskey-dev/misskey/issues/11267'); - await lock; + const canvas = within(canvasElement); + const a = canvas.getByRole('link'); + // FIXME: 通るけどその後落ちるのでコメントアウト + // await expect(a.href).toMatch(/^https?:\/\/.*#test$/); + const img = within(a).getByRole('img'); + await expect(img).toBeInTheDocument(); + let buttons = canvas.getAllByRole('button'); + await expect(buttons).toHaveLength(1); + const i = buttons[0]; + await expect(i).toBeInTheDocument(); + await userEvent.click(i); + await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back); + await expect(a).not.toBeInTheDocument(); + await expect(i).not.toBeInTheDocument(); + buttons = canvas.getAllByRole('button'); + const hasReduceFrequency = args.specify?.ratio !== 0; + await expect(buttons).toHaveLength(hasReduceFrequency ? 2 : 1); + const reduce = hasReduceFrequency ? buttons[0] : null; + const back = buttons[hasReduceFrequency ? 1 : 0]; + if (reduce) { + await expect(reduce).toBeInTheDocument(); + await expect(reduce).toHaveTextContent(i18n.ts._ad.reduceFrequencyOfThisAd); } - - let resolve: (value?: any) => void; - lock = new Promise(r => resolve = r); - - try { - // NOTE: sleep しないと何故か落ちる - await sleep(100); - const canvas = within(canvasElement); - const a = canvas.getByRole('link'); - // await expect(a.href).toMatch(/^https?:\/\/.*#test$/); - const img = within(a).getByRole('img'); - await expect(img).toBeInTheDocument(); - let buttons = canvas.getAllByRole('button'); - await expect(buttons).toHaveLength(1); - const i = buttons[0]; - await expect(i).toBeInTheDocument(); - await userEvent.click(i); - await expect(canvasElement).toHaveTextContent(i18n.ts._ad.back); - await expect(a).not.toBeInTheDocument(); - await expect(i).not.toBeInTheDocument(); - buttons = canvas.getAllByRole('button'); - const hasReduceFrequency = args.specify?.ratio !== 0; - await expect(buttons).toHaveLength(hasReduceFrequency ? 2 : 1); - const reduce = hasReduceFrequency ? buttons[0] : null; - const back = buttons[hasReduceFrequency ? 1 : 0]; - if (reduce) { - await expect(reduce).toBeInTheDocument(); - await expect(reduce).toHaveTextContent(i18n.ts._ad.reduceFrequencyOfThisAd); - } - await expect(back).toBeInTheDocument(); - await expect(back).toHaveTextContent(i18n.ts._ad.back); - await userEvent.click(back); - await waitFor(() => expect(canvas.queryByRole('img')).toBeTruthy()); - if (reduce) { - await expect(reduce).not.toBeInTheDocument(); - } - await expect(back).not.toBeInTheDocument(); - const aAgain = canvas.getByRole('link'); - await expect(aAgain).toBeInTheDocument(); - const imgAgain = within(aAgain).getByRole('img'); - await expect(imgAgain).toBeInTheDocument(); - } finally { - resolve!(); - lock = undefined; + await expect(back).toBeInTheDocument(); + await expect(back).toHaveTextContent(i18n.ts._ad.back); + await userEvent.click(back); + await waitFor(() => expect(canvas.queryByRole('img')).toBeTruthy()); + if (reduce) { + await expect(reduce).not.toBeInTheDocument(); } + await expect(back).not.toBeInTheDocument(); + const aAgain = canvas.getByRole('link'); + await expect(aAgain).toBeInTheDocument(); + const imgAgain = within(aAgain).getByRole('img'); + await expect(imgAgain).toBeInTheDocument(); }, args: { prefer: [], diff --git a/packages/frontend/src/scripts/test-utils.ts b/packages/frontend/src/scripts/test-utils.ts index a32315f4df58..52bb2d94e0e8 100644 --- a/packages/frontend/src/scripts/test-utils.ts +++ b/packages/frontend/src/scripts/test-utils.ts @@ -7,13 +7,3 @@ export async function tick(): Promise { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition await new Promise((globalThis.requestIdleCallback ?? setTimeout) as never); } - -/** - * @see https://github.com/misskey-dev/misskey/issues/11267 - */ -export function semaphore(counter = 0, waiting: (() => void)[] = []) { - return { - acquire: () => ++counter > 1 && new Promise(resolve => waiting.push(resolve)), - release: () => --counter && waiting.pop()?.(), - }; -}