Skip to content

Commit d00250d

Browse files
authored
test: ドラッグで長いノートを追加するテストと、複数ノートを一度に歌詞編集するテストを追加 (#2561)
1 parent bd36e78 commit d00250d

File tree

3 files changed

+148
-43
lines changed

3 files changed

+148
-43
lines changed

tests/e2e/browser/song/ソング.spec.ts

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { test, expect, Page } from "@playwright/test";
22

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

56
test.beforeEach(gotoHome);
67

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

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

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

39-
// ノートの追加
40-
expect(await getCurrentNoteCount()).toBe(0);
41-
await sequencer.click({ position: { x: 107, y: 171 } });
42-
expect(await getCurrentNoteCount()).toBe(1);
43-
await sequencer.click({ position: { x: 200, y: 171 } });
44-
expect(await getCurrentNoteCount()).toBe(2);
45-
46-
// ノートの削除
47-
expect(await getCurrentNoteCount()).toBe(2);
48-
await sequencer.click({ position: { x: 107, y: 171 } });
49-
await page.keyboard.press("Delete");
50-
expect(await getCurrentNoteCount()).toBe(1);
51-
await sequencer.click({ position: { x: 200, y: 171 } });
52-
await page.keyboard.press("Delete");
53-
expect(await getCurrentNoteCount()).toBe(0);
40+
await test.step("ノートの追加", async () => {
41+
expect(await getCurrentNoteCount()).toBe(0);
42+
await sequencer.click({ position: { x: 100, y: 171 } });
43+
expect(await getCurrentNoteCount()).toBe(1);
44+
await sequencer.click({ position: { x: 200, y: 171 } });
45+
expect(await getCurrentNoteCount()).toBe(2);
46+
});
47+
48+
await test.step("ノートの削除", async () => {
49+
expect(await getCurrentNoteCount()).toBe(2);
50+
await sequencer.click({ position: { x: 100, y: 171 } });
51+
await page.keyboard.press("Delete");
52+
expect(await getCurrentNoteCount()).toBe(1);
53+
await sequencer.click({ position: { x: 200, y: 171 } });
54+
await page.keyboard.press("Delete");
55+
expect(await getCurrentNoteCount()).toBe(0);
56+
});
57+
});
58+
59+
test("ドラッグで長いノートを追加できる", async ({ page }) => {
60+
await navigateToSong(page);
61+
62+
const sequencer = page.getByLabel("シーケンサ");
63+
64+
await test.step("クリックで短いノートを追加", async () => {
65+
await sequencer.click({ position: { x: 100, y: 171 } });
66+
});
67+
68+
await test.step("ドラッグで長いノートを追加", async () => {
69+
const startPos = { x: 200, y: 171 };
70+
const endPos = { x: 400, y: 171 };
71+
await sequencer.hover({ position: startPos });
72+
await page.mouse.down();
73+
await page.mouse.move(endPos.x, endPos.y);
74+
await page.mouse.up();
75+
});
76+
77+
await test.step("ノートが2つ表示されるのを待ち、2つ目のノートが長いことを確認", async () => {
78+
const notes = sequencer.locator(".note");
79+
await expect(notes).toHaveCount(2);
80+
81+
const firstNoteBox = ensureNotNullish(await notes.nth(0).boundingBox());
82+
const secondNoteBox = ensureNotNullish(await notes.nth(1).boundingBox());
83+
expect(secondNoteBox.width).toBeGreaterThanOrEqual(firstNoteBox.width * 2);
84+
});
5485
});
Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,101 @@
1-
import { test, expect } from "@playwright/test";
1+
import { test, expect, Page, Locator } from "@playwright/test";
22

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

56
test.beforeEach(gotoHome);
67

8+
function getSequencer(page: Page) {
9+
return page.getByLabel("シーケンサ");
10+
}
11+
12+
async function addNotes(page: Page, count: number) {
13+
await test.step(`ノートを${count}つ追加`, async () => {
14+
const sequencer = getSequencer(page);
15+
for (let i = 0; i < count; i++) {
16+
await sequencer.click({ position: { x: (i + 1) * 100, y: 171 } });
17+
}
18+
const notes = sequencer.locator(".note");
19+
await expect(notes).toHaveCount(count);
20+
});
21+
}
22+
23+
/** Locator の配列を x 座標でソートする */
24+
async function toSortedLocator(locators: Locator[]): Promise<Locator[]> {
25+
const locatorsWithPosition = await Promise.all(
26+
locators.map(async (locator) => ({
27+
locator,
28+
x: ensureNotNullish(await locator.boundingBox()).x,
29+
})),
30+
);
31+
locatorsWithPosition.sort((a, b) => a.x - b.x);
32+
return locatorsWithPosition.map(({ locator }) => locator);
33+
}
34+
35+
async function getSortedNotes(page: Page): Promise<Locator[]> {
36+
return await test.step("ノートをソートして取得", async () => {
37+
const sequencer = getSequencer(page);
38+
const notes = await sequencer.locator(".note").all();
39+
return toSortedLocator(notes);
40+
});
41+
}
42+
43+
async function getSortedNoteLylics(page: Page): Promise<string[]> {
44+
return await test.step("ノートをソートして歌詞を取得", async () => {
45+
const sequencer = getSequencer(page);
46+
const lyrics = await sequencer.locator(".note-lyric").all();
47+
const sortedLyrics = await toSortedLocator(lyrics);
48+
return Promise.all(
49+
sortedLyrics.map(async (lyric) =>
50+
ensureNotNullish(await lyric.textContent()),
51+
),
52+
);
53+
});
54+
}
55+
56+
async function editNoteLyric(page: Page, note: Locator, lyric: string) {
57+
await test.step("ノートをダブルクリックして歌詞を入力", async () => {
58+
await note.dblclick();
59+
60+
const sequencer = getSequencer(page);
61+
const lyricInput = sequencer.locator(".lyric-input");
62+
await expect(lyricInput).toBeVisible();
63+
await lyricInput.fill(lyric);
64+
await lyricInput.press("Enter");
65+
await expect(lyricInput).not.toBeVisible();
66+
});
67+
}
68+
769
test("ダブルクリックで歌詞を編集できる", async ({ page }) => {
870
await navigateToSong(page);
971

10-
const sequencer = page.getByLabel("シーケンサ");
11-
12-
const getCurrentNoteLyric = async () =>
13-
await sequencer.locator(".note-lyric").first().textContent();
72+
await addNotes(page, 1);
73+
const note = (await getSortedNotes(page))[0];
74+
const beforeLyric = (await getSortedNoteLylics(page))[0];
1475

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

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

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

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

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

38-
// 歌詞が変更されたことを確認
39-
const afterLyric = await getCurrentNoteLyric();
40-
expect(afterLyric).not.toEqual(beforeLyric);
41-
expect(afterLyric).toEqual("あ");
96+
await editNoteLyric(page, (await getSortedNotes(page))[0], "かきくけこ");
97+
await test.step("最後のノートに残りの文字が入力されていることを確認", async () => {
98+
const afterLyrics = await getSortedNoteLylics(page);
99+
expect(afterLyrics).toEqual(["か", "き", "くけこ"]);
100+
});
42101
});

tests/e2e/locators.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Page } from "@playwright/test";
1+
import { Locator, Page } from "@playwright/test";
2+
import { ensureNotNullish } from "@/helpers/errorHelper";
23

34
/**
45
* 最新のquasarダイアログのlocatorを取得する
@@ -14,3 +15,17 @@ export function getNewestQuasarDialog(page: Page) {
1415
export function getQuasarMenu(page: Page, menuName: string) {
1516
return page.getByRole("listitem").filter({ hasText: menuName });
1617
}
18+
19+
/** Locator の配列を x 座標でソートする */
20+
export async function fetchLocatorsSortedByX(
21+
locators: Locator[],
22+
): Promise<Locator[]> {
23+
const locatorsWithPosition = await Promise.all(
24+
locators.map(async (locator) => ({
25+
locator,
26+
x: ensureNotNullish(await locator.boundingBox()).x,
27+
})),
28+
);
29+
locatorsWithPosition.sort((a, b) => a.x - b.x);
30+
return locatorsWithPosition.map(({ locator }) => locator);
31+
}

0 commit comments

Comments
 (0)