Skip to content

Commit

Permalink
test: ドラッグで長いノートを追加するテストと、複数ノートを一度に歌詞編集するテストを追加 (#2561)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hiroshiba authored Mar 2, 2025
1 parent bd36e78 commit d00250d
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 43 deletions.
63 changes: 47 additions & 16 deletions tests/e2e/browser/song/ソング.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { test, expect, Page } from "@playwright/test";

import { gotoHome, navigateToSong } from "../../navigators";
import { ensureNotNullish } from "@/helpers/errorHelper";

test.beforeEach(gotoHome);

Expand All @@ -18,7 +19,7 @@ test("再生ボタンを押して再生できる", async ({ page }) => {

const sequencer = page.getByLabel("シーケンサ");

await sequencer.click({ position: { x: 107, y: 171 } }); // ノートを追加
await sequencer.click({ position: { x: 100, y: 171 } }); // ノートを追加
const beforePosition = await getCurrentPlayhead(page); // 再生ヘッドの初期位置
await page.getByText("play_arrow").click(); // 再生ボタンを押す
await page.waitForTimeout(3000);
Expand All @@ -36,19 +37,49 @@ test("ノートを追加・削除できる", async ({ page }) => {
const getCurrentNoteCount = async () =>
await sequencer.locator(".note").count();

// ノートの追加
expect(await getCurrentNoteCount()).toBe(0);
await sequencer.click({ position: { x: 107, y: 171 } });
expect(await getCurrentNoteCount()).toBe(1);
await sequencer.click({ position: { x: 200, y: 171 } });
expect(await getCurrentNoteCount()).toBe(2);

// ノートの削除
expect(await getCurrentNoteCount()).toBe(2);
await sequencer.click({ position: { x: 107, y: 171 } });
await page.keyboard.press("Delete");
expect(await getCurrentNoteCount()).toBe(1);
await sequencer.click({ position: { x: 200, y: 171 } });
await page.keyboard.press("Delete");
expect(await getCurrentNoteCount()).toBe(0);
await test.step("ノートの追加", async () => {
expect(await getCurrentNoteCount()).toBe(0);
await sequencer.click({ position: { x: 100, y: 171 } });
expect(await getCurrentNoteCount()).toBe(1);
await sequencer.click({ position: { x: 200, y: 171 } });
expect(await getCurrentNoteCount()).toBe(2);
});

await test.step("ノートの削除", async () => {
expect(await getCurrentNoteCount()).toBe(2);
await sequencer.click({ position: { x: 100, y: 171 } });
await page.keyboard.press("Delete");
expect(await getCurrentNoteCount()).toBe(1);
await sequencer.click({ position: { x: 200, y: 171 } });
await page.keyboard.press("Delete");
expect(await getCurrentNoteCount()).toBe(0);
});
});

test("ドラッグで長いノートを追加できる", async ({ page }) => {
await navigateToSong(page);

const sequencer = page.getByLabel("シーケンサ");

await test.step("クリックで短いノートを追加", async () => {
await sequencer.click({ position: { x: 100, y: 171 } });
});

await test.step("ドラッグで長いノートを追加", async () => {
const startPos = { x: 200, y: 171 };
const endPos = { x: 400, y: 171 };
await sequencer.hover({ position: startPos });
await page.mouse.down();
await page.mouse.move(endPos.x, endPos.y);
await page.mouse.up();
});

await test.step("ノートが2つ表示されるのを待ち、2つ目のノートが長いことを確認", async () => {
const notes = sequencer.locator(".note");
await expect(notes).toHaveCount(2);

const firstNoteBox = ensureNotNullish(await notes.nth(0).boundingBox());
const secondNoteBox = ensureNotNullish(await notes.nth(1).boundingBox());
expect(secondNoteBox.width).toBeGreaterThanOrEqual(firstNoteBox.width * 2);
});
});
111 changes: 85 additions & 26 deletions tests/e2e/browser/song/歌詞.spec.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,101 @@
import { test, expect } from "@playwright/test";
import { test, expect, Page, Locator } from "@playwright/test";

import { gotoHome, navigateToSong } from "../../navigators";
import { ensureNotNullish } from "@/helpers/errorHelper";

test.beforeEach(gotoHome);

function getSequencer(page: Page) {
return page.getByLabel("シーケンサ");
}

async function addNotes(page: Page, count: number) {
await test.step(`ノートを${count}つ追加`, async () => {
const sequencer = getSequencer(page);
for (let i = 0; i < count; i++) {
await sequencer.click({ position: { x: (i + 1) * 100, y: 171 } });
}
const notes = sequencer.locator(".note");
await expect(notes).toHaveCount(count);
});
}

/** Locator の配列を x 座標でソートする */
async function toSortedLocator(locators: Locator[]): Promise<Locator[]> {
const locatorsWithPosition = await Promise.all(
locators.map(async (locator) => ({
locator,
x: ensureNotNullish(await locator.boundingBox()).x,
})),
);
locatorsWithPosition.sort((a, b) => a.x - b.x);
return locatorsWithPosition.map(({ locator }) => locator);
}

async function getSortedNotes(page: Page): Promise<Locator[]> {
return await test.step("ノートをソートして取得", async () => {
const sequencer = getSequencer(page);
const notes = await sequencer.locator(".note").all();
return toSortedLocator(notes);
});
}

async function getSortedNoteLylics(page: Page): Promise<string[]> {
return await test.step("ノートをソートして歌詞を取得", async () => {
const sequencer = getSequencer(page);
const lyrics = await sequencer.locator(".note-lyric").all();
const sortedLyrics = await toSortedLocator(lyrics);
return Promise.all(
sortedLyrics.map(async (lyric) =>
ensureNotNullish(await lyric.textContent()),
),
);
});
}

async function editNoteLyric(page: Page, note: Locator, lyric: string) {
await test.step("ノートをダブルクリックして歌詞を入力", async () => {
await note.dblclick();

const sequencer = getSequencer(page);
const lyricInput = sequencer.locator(".lyric-input");
await expect(lyricInput).toBeVisible();
await lyricInput.fill(lyric);
await lyricInput.press("Enter");
await expect(lyricInput).not.toBeVisible();
});
}

test("ダブルクリックで歌詞を編集できる", async ({ page }) => {
await navigateToSong(page);

const sequencer = page.getByLabel("シーケンサ");

const getCurrentNoteLyric = async () =>
await sequencer.locator(".note-lyric").first().textContent();
await addNotes(page, 1);
const note = (await getSortedNotes(page))[0];
const beforeLyric = (await getSortedNoteLylics(page))[0];

// ノートを追加し、表示されるまで待つ
await sequencer.click({ position: { x: 107, y: 171 } });
await page.waitForSelector(".note");
await editNoteLyric(page, note, "あ");

// ノートの歌詞を取得
const note = sequencer.locator(".note").first();
const beforeLyric = await getCurrentNoteLyric();
await test.step("歌詞が変更されていることを確認", async () => {
const afterLyric = await getSortedNoteLylics(page);
expect(afterLyric[0]).not.toEqual(beforeLyric);
expect(afterLyric[0]).toEqual("あ");
});
});

// ノートをダブルクリックし、入力フィールドが表示されるまで待つ
await note.dblclick();
await page.waitForSelector(".lyric-input");
test("複数ノートの歌詞を一度に編集できる", async ({ page }) => {
await navigateToSong(page);

// 歌詞を入力し、Enterキーを押す
const lyricInput = sequencer.locator(".lyric-input");
await lyricInput.fill("あ");
await lyricInput.press("Enter");
await addNotes(page, 3);

// 変更が反映されるまで待つ
await page.waitForFunction(() => {
const lyricElement = document.querySelector(".note-lyric");
return lyricElement && lyricElement.textContent === "あ";
await editNoteLyric(page, (await getSortedNotes(page))[0], "あいう");
await test.step("全てのノートの歌詞が変更されていることを確認", async () => {
const afterLyrics = await getSortedNoteLylics(page);
expect(afterLyrics).toEqual(["あ", "い", "う"]);
});

// 歌詞が変更されたことを確認
const afterLyric = await getCurrentNoteLyric();
expect(afterLyric).not.toEqual(beforeLyric);
expect(afterLyric).toEqual("あ");
await editNoteLyric(page, (await getSortedNotes(page))[0], "かきくけこ");
await test.step("最後のノートに残りの文字が入力されていることを確認", async () => {
const afterLyrics = await getSortedNoteLylics(page);
expect(afterLyrics).toEqual(["か", "き", "くけこ"]);
});
});
17 changes: 16 additions & 1 deletion tests/e2e/locators.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Page } from "@playwright/test";
import { Locator, Page } from "@playwright/test";
import { ensureNotNullish } from "@/helpers/errorHelper";

/**
* 最新のquasarダイアログのlocatorを取得する
Expand All @@ -14,3 +15,17 @@ export function getNewestQuasarDialog(page: Page) {
export function getQuasarMenu(page: Page, menuName: string) {
return page.getByRole("listitem").filter({ hasText: menuName });
}

/** Locator の配列を x 座標でソートする */
export async function fetchLocatorsSortedByX(
locators: Locator[],
): Promise<Locator[]> {
const locatorsWithPosition = await Promise.all(
locators.map(async (locator) => ({
locator,
x: ensureNotNullish(await locator.boundingBox()).x,
})),
);
locatorsWithPosition.sort((a, b) => a.x - b.x);
return locatorsWithPosition.map(({ locator }) => locator);
}

0 comments on commit d00250d

Please sign in to comment.