diff --git a/src/components/Sing/ScoreSequencer.vue b/src/components/Sing/ScoreSequencer.vue index 8b707c23cd..13e7bdb82d 100644 --- a/src/components/Sing/ScoreSequencer.vue +++ b/src/components/Sing/ScoreSequencer.vue @@ -204,7 +204,7 @@ import { PreviewMode, } from "@/sing/viewHelper"; import SequencerGrid from "@/components/Sing/SequencerGrid/Container.vue"; -import SequencerRuler from "@/components/Sing/SequencerRuler.vue"; +import SequencerRuler from "@/components/Sing/SequencerRuler/Container.vue"; import SequencerKeys from "@/components/Sing/SequencerKeys.vue"; import SequencerNote from "@/components/Sing/SequencerNote.vue"; import SequencerShadowNote from "@/components/Sing/SequencerShadowNote.vue"; diff --git a/src/components/Sing/SequencerRuler/Container.vue b/src/components/Sing/SequencerRuler/Container.vue new file mode 100644 index 0000000000..e30f5db34b --- /dev/null +++ b/src/components/Sing/SequencerRuler/Container.vue @@ -0,0 +1,63 @@ + + + diff --git a/src/components/Sing/SequencerRuler.vue b/src/components/Sing/SequencerRuler/Presentation.vue similarity index 74% rename from src/components/Sing/SequencerRuler.vue rename to src/components/Sing/SequencerRuler/Presentation.vue index 9ddae01849..8c078fb1c0 100644 --- a/src/components/Sing/SequencerRuler.vue +++ b/src/components/Sing/SequencerRuler/Presentation.vue @@ -62,60 +62,57 @@ diff --git a/src/components/Sing/SequencerRuler/index.stories.ts b/src/components/Sing/SequencerRuler/index.stories.ts new file mode 100644 index 0000000000..345415e841 --- /dev/null +++ b/src/components/Sing/SequencerRuler/index.stories.ts @@ -0,0 +1,73 @@ +import type { Meta, StoryObj } from "@storybook/vue3"; +import { fn, expect, Mock } from "@storybook/test"; +import { ref } from "vue"; + +import Presentation from "./Presentation.vue"; +import { UnreachableError } from "@/type/utility"; + +const meta: Meta = { + component: Presentation, + args: { + timeSignatures: [ + { + beats: 4, + beatType: 4, + measureNumber: 1, + }, + ], + sequencerZoomX: 0.25, + tpqn: 480, + offset: 0, + numMeasures: 32, + "onUpdate:playheadTicks": fn<(value: number) => void>(), + onDeselectAllNotes: fn(), + }, + render: (args) => ({ + components: { Presentation }, + setup() { + const playheadTicks = ref(0); + return { args, playheadTicks }; + }, + template: ``, + }), +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const MovePlayhead: Story = { + name: "再生位置を移動", + + play: async ({ canvasElement, args }) => { + const ruler = + canvasElement.querySelector(".sequencer-ruler"); + + if (!ruler) { + throw new UnreachableError("ruler is not found"); + } + + // userEvent.pointerは座標指定が上手くいかないので、MouseEventを使って手動でクリックをエミュレートする + const rect = ruler.getBoundingClientRect(); + const width = rect.width; + const event = new MouseEvent("click", { + bubbles: true, + cancelable: true, + clientX: rect.left + width / 2, + clientY: rect.top + rect.height, + }); + + ruler.dispatchEvent(event); + + await expect(args["onUpdate:playheadTicks"]).toHaveBeenCalled(); + + const onUpdateCallback = args["onUpdate:playheadTicks"] as Mock< + (value: number) => void + >; + const newTick = onUpdateCallback.mock.calls[0][0]; + + await expect(newTick).toBeGreaterThan(0); + await expect(args["onDeselectAllNotes"]).toHaveBeenCalled(); + }, +}; diff --git "a/tests/e2e/storybook/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210.spec.mts-snapshots/components-sing-sequencerruler--default-storybook-win32.png" "b/tests/e2e/storybook/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210.spec.mts-snapshots/components-sing-sequencerruler--default-storybook-win32.png" new file mode 100644 index 0000000000..38d7351162 Binary files /dev/null and "b/tests/e2e/storybook/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210.spec.mts-snapshots/components-sing-sequencerruler--default-storybook-win32.png" differ