diff --git a/scripts/grdm.py b/scripts/grdm.py index 0497acd..619d9aa 100644 --- a/scripts/grdm.py +++ b/scripts/grdm.py @@ -6,6 +6,8 @@ import re import time import traceback +from urllib.parse import urljoin + from playwright.async_api import expect @@ -472,6 +474,41 @@ async def verify_property_folder_info( time.sleep(1) +async def goto_wiki_by_name(page, wikiname, transition_timeout=60000): + """サイドバーの Wiki リンク href(相対 URL 可)から遷移する。""" + wiki_link = page.locator(f'//*[contains(@class, "title-text")]//a[text()="{wikiname}"]') + href = await wiki_link.first.get_attribute('href') + assert href, f'Wiki "{wikiname}" のリンクが見つかりません' + url = urljoin(page.url, href) + try: + await page.goto(url, timeout=transition_timeout, wait_until='domcontentloaded') + except Exception as e: + # 編集モード中の遷移などで goto が中断されても、目的の Wiki に着いていれば続行する + if 'ERR_ABORTED' not in str(e): + raise + await expect(page.locator('#pageName')).to_have_text(wikiname, timeout=transition_timeout) + + +async def leave_edit_wiki_if_open(page, transition_timeout=60000): + """編集モードなら閲覧へ戻す。未保存確認が出た場合は破棄する。""" + modal = page.locator('#closeConfirmModal') + if not await page.locator('#mMenuBar').is_visible(): + return + if await modal.is_visible(): + await page.locator('#closeConfirmModal button.btn-danger').click() + await expect(modal).not_to_be_visible(timeout=transition_timeout) + await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout) + return + await page.locator('#revert-button').click() + try: + await expect(modal).to_be_visible(timeout=3000) + await page.locator('#closeConfirmModal button.btn-danger').click() + await expect(modal).not_to_be_visible(timeout=transition_timeout) + except AssertionError: + pass + await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout) + + async def open_wiki(page, wikiname, text, transition_timeout=60000): await page.locator(f'//*[contains(@class, "title-text")]//a[text()="{wikiname}"]').click() await expect(page.locator('//span[contains(@class, "title-text")]//b[contains(text(), "プロジェクトのWiki")]')).to_be_visible(timeout=transition_timeout) @@ -484,6 +521,194 @@ async def open_edit_wiki(page, transition_timeout=60000): await expect(page.locator('#mMenuBar')).to_be_visible(timeout=transition_timeout) await expect(page.locator('#mEditor .ProseMirror[contenteditable="true"]')).to_be_visible(timeout=transition_timeout) + +async def open_edit_wiki_collab(page, transition_timeout=60000): + """2タブ共同編集向け。タブ前面化と Milkdown 共同編集テンプレート待ちを含む。""" + await page.bring_to_front() + await open_edit_wiki(page, transition_timeout=transition_timeout) + await page.wait_for_timeout(500) + + +async def open_edit_wiki_after_close(page, transition_timeout=60000, settle_ms=2000, force_collab_rejoin=False): + """Close 後プレビューから「編集」を押す。 + + force_collab_rejoin=True のとき milkdown を外し connectCollab 再実行 path を通す。 + """ + if force_collab_rejoin: + await prepare_collab_rejoin_after_close(page) + await page.bring_to_front() + edit_button = page.locator('#editWysiwyg') + await expect(edit_button).to_be_visible(timeout=transition_timeout) + await wait_awareness_settle(page, ms=settle_ms) + await edit_button.scroll_into_view_if_needed() + await edit_button.click() + await expect(page.locator('#editWysiwyg')).not_to_be_visible(timeout=transition_timeout) + await expect(page.locator('#mMenuBar')).to_be_visible(timeout=transition_timeout) + await expect(page.locator('#mEditor .ProseMirror[contenteditable="true"]')).to_be_visible( + timeout=transition_timeout + ) + if force_collab_rejoin: + await expect_live_editing(page, transition_timeout=transition_timeout) + await wait_awareness_settle(page, ms=3000) + else: + await wait_awareness_settle(page, ms=1500) + + +async def expect_live_editing(page, transition_timeout=60000): + collab = page.locator('#collaborativeStatus') + await expect(collab).to_be_visible(timeout=transition_timeout) + await expect(collab).to_contain_text('Live editing mode', timeout=transition_timeout) + + +async def _open_collaborative_edit_on_page(page, transition_timeout=60000): + consent = page.locator('//button[text() = "同意する"]') + if await consent.count(): + await consent.click() + await open_edit_wiki_collab(page, transition_timeout=transition_timeout) + + +async def get_wiki_user_fullname(page): + fullname = await page.evaluate( + "() => (window.contextVars.currentUser || {}).fullname || ''" + ) + assert fullname, 'window.contextVars.currentUser.fullname が取得できません' + return fullname + + +def remote_collaborator_name_locator(page, name): + return page.locator('#mEditor .ProseMirror-yjs-cursor div').filter(has_text=name) + + +async def expect_remote_collaborator_name(page, name, visible=True, transition_timeout=60000): + locator = remote_collaborator_name_locator(page, name) + if visible: + await expect(locator.first).to_be_visible(timeout=transition_timeout) + else: + await expect(locator).to_have_count(0, timeout=transition_timeout) + + +async def wait_awareness_settle(page, ms=500): + await page.wait_for_timeout(ms) + + +async def nudge_collab_pages(sender, receiver, settle_ms=500): + """送信側→受信側の順にタブを前面化し、headless 2 タブ共同編集の Yjs 更新を促す。""" + await sender.bring_to_front() + await wait_awareness_settle(sender, ms=settle_ms) + await receiver.bring_to_front() + await wait_awareness_settle(receiver, ms=settle_ms) + + +async def get_meditor_milkdown_count(page): + return await page.evaluate( + "() => document.getElementById('mEditor').querySelectorAll('div.milkdown').length" + ) + + +async def prepare_collab_rejoin_after_close(page): + """A Close 後の再 Edit で milkdown を外し、connectCollab 再実行 path を通す。""" + if await get_meditor_milkdown_count(page) == 0: + return + await page.evaluate( + "() => document.getElementById('mEditor').querySelectorAll('div.milkdown').forEach(function (div) { div.remove(); })" + ) + await wait_awareness_settle(page, ms=500) + + +async def flush_collab_yjs(sender, receiver, rounds=8, settle_ms=500): + """B 追記後、Close 中タブ A の Y.Doc へ更新が届くまで B→A を繰り返し前面化する。""" + for _ in range(rounds): + await nudge_collab_pages(sender, receiver, settle_ms=settle_ms) + + +async def reopen_collab_edit_on_receiver(page, peer_page, transition_timeout=60000, settle_ms=2000): + """Close 中の page(A) を peer(B) の live Yjs へ再接続して再 Edit する。""" + await flush_collab_yjs(peer_page, page, rounds=4, settle_ms=500) + await open_edit_wiki_after_close( + page, + transition_timeout=transition_timeout, + settle_ms=settle_ms, + force_collab_rejoin=True, + ) + await expect_live_editing(page, transition_timeout=transition_timeout) + + +async def wait_for_collab_meditor_text( + page, + text, + peer_page=None, + transition_timeout=60000, + settle_ms=500, + stable_checks=1, + nudge_peer_ms=1000, +): + """共同編集で page の #mEditor に text が載るまでポーリングする。 + + 受信側 page を前面固定し、peer_page があれば定期的に短く前面化して Yjs 更新を促す。 + """ + import time + + await page.bring_to_front() + if peer_page is not None: + await nudge_collab_pages(peer_page, page, settle_ms=settle_ms) + content = page.locator('#mEditor') + deadline = time.monotonic() + transition_timeout / 1000 + last_error = None + consecutive = 0 + last_nudge = time.monotonic() + while time.monotonic() < deadline: + if peer_page is not None and time.monotonic() - last_nudge >= nudge_peer_ms / 1000: + await nudge_collab_pages(peer_page, page, settle_ms=settle_ms) + last_nudge = time.monotonic() + else: + await wait_awareness_settle(page, ms=settle_ms) + try: + await expect(content).to_contain_text(text, timeout=1000) + consecutive += 1 + if consecutive >= stable_checks: + return + except AssertionError as error: + last_error = error + consecutive = 0 + assert last_error is not None + raise last_error + + +async def open_collaborative_peer(page_a, transition_timeout=60000): + """同一ブラウザコンテキストで第2タブを開き、page_a と同じ Wiki の共同編集に参加する。""" + await expect_live_editing(page_a, transition_timeout=transition_timeout) + page_b = await page_a.context.new_page() + await page_b.goto(page_a.url, timeout=transition_timeout, wait_until='domcontentloaded') + await _open_collaborative_edit_on_page(page_b, transition_timeout=transition_timeout) + await expect_live_editing(page_b, transition_timeout=transition_timeout) + return page_b + + +async def open_fresh_collaborative_peer(live_peer_page, transition_timeout=60000): + """編集中 peer と同じ Wiki を新タブで共同編集参加する(live Y.Doc に参加)。""" + await expect_live_editing(live_peer_page, transition_timeout=transition_timeout) + new_page = await live_peer_page.context.new_page() + await new_page.goto(live_peer_page.url, timeout=transition_timeout, wait_until='domcontentloaded') + await _open_collaborative_edit_on_page(new_page, transition_timeout=transition_timeout) + await expect_live_editing(new_page, transition_timeout=transition_timeout) + await wait_awareness_settle(new_page, ms=2000) + return new_page + + +async def handoff_to_fresh_collab_peer(live_peer_page, required_text=None, transition_timeout=60000): + """A Close 後、live Y.Doc 参加用の新タブへ切り替え、旧 peer タブを閉じる。 + + 同一 B タブ継続では Playwright 入力が Yjs に届かないことがあるため、 + 手動で別ウィンドウを開く操作に相当する。 + """ + new_page = await open_fresh_collaborative_peer(live_peer_page, transition_timeout=transition_timeout) + if required_text is not None: + await expect(new_page.locator('#mEditor')).to_contain_text( + required_text, timeout=transition_timeout + ) + await live_peer_page.close() + return new_page + async def select_text_range(page, text, transition_timeout=60000): editor_locator = page.locator('#mEditor .ProseMirror[contenteditable="true"]') await editor_locator.focus() @@ -511,6 +736,48 @@ async def fill_text(page, text, transition_timeout=60000): await editor_locator.fill(text) await expect(editor_locator).to_have_text(text, timeout=transition_timeout) + +async def replace_wiki_text(page, text, transition_timeout=60000): + """全文置換(Close 確認テスト向け)。Milkdown 保存用 Markdown も更新する。""" + editor_locator = page.locator('#mEditor .ProseMirror[contenteditable="true"]') + await editor_locator.click() + await editor_locator.evaluate( + """ + (el, text) => { + el.focus(); + const range = document.createRange(); + range.selectNodeContents(el); + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + document.execCommand('delete', false, null); + document.execCommand('insertText', false, text); + } + """, + text, + ) + await expect(editor_locator).to_contain_text(text, timeout=transition_timeout) + + +async def append_wiki_text(page, text, transition_timeout=60000, type_delay=50): + """末尾に追記する。keyboard.type で ProseMirror / 保存用 Markdown を更新する。""" + await page.bring_to_front() + editor_locator = page.locator('#mEditor .ProseMirror[contenteditable="true"]') + await editor_locator.click() + await page.keyboard.press("ControlOrMeta+End") + await page.keyboard.press("Enter") + await page.keyboard.type(text, delay=type_delay) + await expect(editor_locator).to_contain_text(text, timeout=transition_timeout) + + +async def append_wiki_text_live(page, text, transition_timeout=60000): + """共同編集ライブ追記向け。keyboard.type で追記し Yjs 送信の余裕を取る。""" + await expect_live_editing(page, transition_timeout=transition_timeout) + await wait_awareness_settle(page, ms=500) + await append_wiki_text(page, text, transition_timeout=transition_timeout, type_delay=100) + await wait_awareness_settle(page, ms=3000) + await expect_live_editing(page, transition_timeout=transition_timeout) + async def click_wiki_menu_save(page, menu_list, transition_timeout=60000): for menu in menu_list: locator_by_id = page.locator(f'#{menu}') @@ -532,6 +799,14 @@ async def click_wiki_menu_save(page, menu_list, transition_timeout=60000): await page.locator('//input[@type="submit" and @value="保存"]').click() await expect(page.locator('//span[contains(@class, "title-text")]//b[contains(text(), "プロジェクトのWiki")]')).to_be_visible(timeout=transition_timeout) + +async def click_wiki_footer_save(page, transition_timeout=60000): + """編集フッターの「保存」で DB 保存し、閲覧モードへ遷移する。""" + async with page.expect_navigation(timeout=transition_timeout): + await page.locator('//input[@type="submit" and @value="保存"]').click() + await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout) + + async def set_text_color(color_input, r, g, b): r = max(0, min(255, r)) g = max(0, min(255, g)) @@ -585,6 +860,53 @@ async def click_table_menu_save(page, row_index, col_index, table_menu, transiti view_locator = page.locator('#mView .ProseMirror[contenteditable="false"]') await expect(page.locator('//span[contains(@class, "title-text")]//b[contains(text(), "プロジェクトのWiki")]')).to_be_visible(timeout=transition_timeout) +async def _dismiss_dialog_safe(dialog): + try: + await dialog.dismiss() + except Exception as e: + if 'already handled' not in str(e): + raise + + +async def expect_no_dialog(page, action, transition_timeout=60000): + """action 実行中に dialog が出ないことを確認する。""" + messages = [] + + async def on_dialog(dialog): + messages.append(dialog.message) + await _dismiss_dialog_safe(dialog) + + page.on('dialog', on_dialog) + try: + await action() + finally: + page.remove_listener('dialog', on_dialog) + + assert not messages, f'離脱警告が表示された: {messages}' + + +async def expect_beforeunload(page, action, transition_timeout=60000): + """action 実行で beforeunload が出ることを確認し dismiss する。""" + dialog_event = asyncio.Event() + captured = {} + + async def on_dialog(dialog): + captured['dialog'] = dialog + await _dismiss_dialog_safe(dialog) + dialog_event.set() + + page.on('dialog', on_dialog) + try: + await action() + await asyncio.wait_for(dialog_event.wait(), timeout=transition_timeout / 1000) + finally: + page.remove_listener('dialog', on_dialog) + + dialog = captured.get('dialog') + assert dialog is not None, 'beforeunload が表示されませんでした' + assert dialog.type == 'beforeunload', f'想定外のダイアログ: type={dialog.type}' + + async def click_and_expect_alert(page, action, expected_message, transition_timeout=60000): async with page.expect_event("dialog", timeout=transition_timeout*5) as dialog_info: await action() diff --git "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-Wiki\346\223\215\344\275\234-WikiDecoration.ipynb" "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-Wiki\346\223\215\344\275\234-WikiDecoration.ipynb" index a5c24d8..354dfc4 100644 --- "a/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-Wiki\346\223\215\344\275\234-WikiDecoration.ipynb" +++ "b/\343\203\206\343\202\271\343\203\210\346\211\213\351\240\206-Wiki\346\223\215\344\275\234-WikiDecoration.ipynb" @@ -6,12 +6,6 @@ "id": "56e3e33b-cbb9-484f-be9a-769c04926fb9", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:31.770736Z", - "iopub.status.busy": "2026-01-06T08:32:31.769517Z", - "iopub.status.idle": "2026-01-06T08:32:31.778717Z", - "shell.execute_reply": "2026-01-06T08:32:31.777725Z" - }, "lc_cell_meme": { "current": "f05363a8-0c25-11f0-98e9-5e0a5654d7bd-14-c2c3-a856-8c7b-03e6-653e-956c-acc8-ea3f-fa3a-173b", "history": [ @@ -78,12 +72,6 @@ "id": "f2397f2c-07d5-4548-8855-0024b98a7e18", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:32.013339Z", - "iopub.status.busy": "2026-01-06T08:32:32.013097Z", - "iopub.status.idle": "2026-01-06T08:32:32.022548Z", - "shell.execute_reply": "2026-01-06T08:32:32.021854Z" - }, "lc_cell_meme": { "current": "9a6a67cc-0c28-11f0-98e9-5e0a5654d7bd-12-fef2-2947-bb68-4605-cbe7-374c-f640-ff71-7091-011e", "execution_end_time": "2025-04-02T07:21:16.844Z", @@ -289,12 +277,6 @@ "id": "25e8c9ab-046c-4962-9ced-d4c9ada8f385", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:32.125796Z", - "iopub.status.busy": "2026-01-06T08:32:32.125579Z", - "iopub.status.idle": "2026-01-06T08:32:32.130933Z", - "shell.execute_reply": "2026-01-06T08:32:32.130260Z" - }, "lc_cell_meme": { "current": "4f1d97fa-0c26-11f0-98e9-5e0a5654d7bd-13-aec7-edd7-31c7-2760-8094-dfda-5fa2-bc22-46de-24ee", "execution_end_time": "2025-04-02T07:21:20.767Z", @@ -646,12 +628,6 @@ "id": "3779559e-3d71-4295-81c9-6494aafaf795", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:32.333661Z", - "iopub.status.busy": "2026-01-06T08:32:32.333421Z", - "iopub.status.idle": "2026-01-06T08:32:33.192006Z", - "shell.execute_reply": "2026-01-06T08:32:33.191262Z" - }, "lc_cell_meme": { "current": "9598145a-f29d-11ea-b359-0a58a9feac02-33-1540-66e7-e779-1196-efeb-205d-1efd-4009-783c-1463", "execution_end_time": "2024-03-26T10:16:58.586484Z", @@ -889,8 +865,10 @@ "import scripts.playwright\n", "importlib.reload(scripts.playwright)\n", "\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", "from scripts.playwright import *\n", - "from scripts import grdm\n", "\n", "await init_pw_context(close_on_fail=close_on_fail, last_path=default_result_path)" ] @@ -1022,12 +1000,6 @@ "id": "b4a3cb3a-2257-44e7-bc6d-e864df2b433a", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:33.401523Z", - "iopub.status.busy": "2026-01-06T08:32:33.400348Z", - "iopub.status.idle": "2026-01-06T08:32:52.456769Z", - "shell.execute_reply": "2026-01-06T08:32:52.455672Z" - }, "lc_cell_meme": { "current": "43b0be32-1c3a-11f0-a653-9281a4835edb-7-7d4e-9eb1-9bca-4f6c-c830-293a-bfdf", "execution_end_time": "2025-04-18T10:03:15.630Z", @@ -1214,12 +1186,6 @@ "id": "570378a2-83ee-4df9-a8f0-b747c37b61fa", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:52.685416Z", - "iopub.status.busy": "2026-01-06T08:32:52.684424Z", - "iopub.status.idle": "2026-01-06T08:32:56.611402Z", - "shell.execute_reply": "2026-01-06T08:32:56.610289Z" - }, "lc_cell_meme": { "current": "8a9be6c2-0c46-11f0-98e9-5e0a5654d7bd-11-1d40-14d8-c05a-8f00-ece7-add9-2c16-ff1c-350f-0f54", "execution_end_time": "2025-04-02T07:25:56.619Z", @@ -1415,12 +1381,6 @@ "id": "a726b808-e2a5-4ce4-9943-08e9d5a75e9d", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:56.848984Z", - "iopub.status.busy": "2026-01-06T08:32:56.847999Z", - "iopub.status.idle": "2026-01-06T08:32:59.600373Z", - "shell.execute_reply": "2026-01-06T08:32:59.599344Z" - }, "lc_cell_meme": { "current": "278c9b54-c9dc-11f0-9373-6a40bdb2b9ec-1-c03f", "execution_end_time": "2025-11-25T11:13:57.549Z", @@ -1483,7 +1443,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "13a0b9c9-239e-404a-8be0-23a4ec3ffdee", "metadata": { @@ -1532,12 +1491,6 @@ "id": "9661461a-4b98-4733-aa19-659e3d7eccde", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:32:59.835550Z", - "iopub.status.busy": "2026-01-06T08:32:59.834396Z", - "iopub.status.idle": "2026-01-06T08:33:00.430542Z", - "shell.execute_reply": "2026-01-06T08:33:00.429480Z" - }, "lc_cell_meme": { "current": "36bc17ee-c9dc-11f0-9373-6a40bdb2b9ec-1-5c64", "execution_end_time": "2025-11-25T11:13:58.073Z", @@ -1605,7 +1558,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "a40874a2-11f0-4f23-8d1d-059be1d8ed67", "metadata": { @@ -1654,12 +1606,6 @@ "id": "c85b95b7-02a0-4a81-bc75-fbd83807d2da", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:00.667408Z", - "iopub.status.busy": "2026-01-06T08:33:00.666793Z", - "iopub.status.idle": "2026-01-06T08:33:02.960416Z", - "shell.execute_reply": "2026-01-06T08:33:02.959219Z" - }, "lc_cell_meme": { "current": "b0835bb4-c9dc-11f0-9373-6a40bdb2b9ec-1-da98", "execution_end_time": "2025-11-25T11:14:00.618Z", @@ -1724,7 +1670,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "258c516d-36ca-4067-ad00-6b939798e12d", "metadata": { @@ -1773,12 +1718,6 @@ "id": "4475582c-6877-479c-a629-da52d875f928", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:03.209040Z", - "iopub.status.busy": "2026-01-06T08:33:03.208490Z", - "iopub.status.idle": "2026-01-06T08:33:05.735024Z", - "shell.execute_reply": "2026-01-06T08:33:05.734007Z" - }, "lc_cell_meme": { "current": "0bcdcfee-c9de-11f0-9373-6a40bdb2b9ec-1-872d", "execution_end_time": "2025-11-25T11:14:04.718Z", @@ -1845,7 +1784,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "b54636e5-38da-49dd-a697-edbbaaec394b", "metadata": { @@ -1889,12 +1827,6 @@ "id": "ee9fab1e-203e-4b8b-8038-60f71a35c724", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:06.024165Z", - "iopub.status.busy": "2026-01-06T08:33:06.023056Z", - "iopub.status.idle": "2026-01-06T08:33:06.353068Z", - "shell.execute_reply": "2026-01-06T08:33:06.352016Z" - }, "lc_cell_meme": { "current": "b78d2a82-c9de-11f0-9373-6a40bdb2b9ec-1-071e", "execution_end_time": "2025-11-25T11:14:04.874Z", @@ -1955,13 +1887,12 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", "\n", "await run_pw(_step)" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "9599f9b2-9d52-4bf1-aa6e-74a76fa68ef9", "metadata": { @@ -2020,12 +1951,6 @@ "id": "3794fd6b-cf38-419c-bb4f-d1008e47db1c", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:06.600598Z", - "iopub.status.busy": "2026-01-06T08:33:06.599560Z", - "iopub.status.idle": "2026-01-06T08:33:07.773253Z", - "shell.execute_reply": "2026-01-06T08:33:07.772184Z" - }, "lc_cell_meme": { "current": "5d42d7ba-c9df-11f0-9373-6a40bdb2b9ec-1-6844", "execution_end_time": "2025-11-25T11:14:06.253Z", @@ -2102,7 +2027,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "7aa155ec-7092-433b-9809-27c53aaee94c", "metadata": { @@ -2151,12 +2075,6 @@ "id": "3e2bdfc2-c517-4b86-b627-70bc7c4d19a3", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:08.035013Z", - "iopub.status.busy": "2026-01-06T08:33:08.034073Z", - "iopub.status.idle": "2026-01-06T08:33:08.237032Z", - "shell.execute_reply": "2026-01-06T08:33:08.236019Z" - }, "lc_cell_meme": { "current": "ee5e6714-c9df-11f0-9373-6a40bdb2b9ec-1-90ba", "execution_end_time": "2025-11-25T11:14:06.343Z", @@ -2225,7 +2143,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "c458cfb9-ea85-4e00-97d3-78cab02a0e41", "metadata": { @@ -2269,12 +2186,6 @@ "id": "de3cd35a-023a-4370-af40-4efc1af5776a", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:08.502787Z", - "iopub.status.busy": "2026-01-06T08:33:08.501577Z", - "iopub.status.idle": "2026-01-06T08:33:11.536037Z", - "shell.execute_reply": "2026-01-06T08:33:11.534993Z" - }, "lc_cell_meme": { "current": "155b778e-c9e1-11f0-9373-6a40bdb2b9ec-1-b024", "execution_end_time": "2025-11-25T11:14:09.992Z", @@ -2366,7 +2277,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "14383fc3-b784-4764-898c-82f9af1ef5dc", "metadata": { @@ -2435,12 +2345,6 @@ "id": "a11291b2-7190-4591-b1fe-ca4d4d1c4fe5", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:11.803093Z", - "iopub.status.busy": "2026-01-06T08:33:11.801654Z", - "iopub.status.idle": "2026-01-06T08:33:15.925740Z", - "shell.execute_reply": "2026-01-06T08:33:15.924682Z" - }, "lc_cell_meme": { "current": "999f136c-c9e5-11f0-9373-6a40bdb2b9ec-2-edad-cd82", "execution_end_time": "2025-12-16T04:44:28.181Z", @@ -2511,7 +2415,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki'])\n", "\n", @@ -2523,7 +2427,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "3ca5e516-3377-4339-a651-feb3feb3f2d9", "metadata": { @@ -2607,12 +2510,6 @@ "id": "32245346-f16f-40c5-8780-6516c77e1d94", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:16.213439Z", - "iopub.status.busy": "2026-01-06T08:33:16.212446Z", - "iopub.status.idle": "2026-01-06T08:33:19.413530Z", - "shell.execute_reply": "2026-01-06T08:33:19.412493Z" - }, "lc_cell_meme": { "current": "07a957d2-c9f0-11f0-9373-6a40bdb2b9ec-1-423c", "history": [ @@ -2697,7 +2594,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['italicWiki'])\n", "\n", @@ -2709,7 +2606,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "43311e22-2509-450c-903b-f5e43314bdcf", "metadata": { @@ -2788,12 +2684,6 @@ "id": "cb8b37e6-28fc-4559-9679-b949c82a1e83", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:19.726008Z", - "iopub.status.busy": "2026-01-06T08:33:19.724938Z", - "iopub.status.idle": "2026-01-06T08:33:22.960070Z", - "shell.execute_reply": "2026-01-06T08:33:22.959010Z" - }, "lc_cell_meme": { "current": "070e3d7e-c9f0-11f0-9373-6a40bdb2b9ec-1-f5e5", "history": [ @@ -2883,7 +2773,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['italicWiki'])\n", "\n", @@ -2895,7 +2785,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "6218cfe7-95f5-4ff7-ba69-02d20b233c22", "metadata": { @@ -2974,12 +2863,6 @@ "id": "c47fe73b-58eb-469b-8a01-8aa239b727f0", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:23.242024Z", - "iopub.status.busy": "2026-01-06T08:33:23.240843Z", - "iopub.status.idle": "2026-01-06T08:33:27.262466Z", - "shell.execute_reply": "2026-01-06T08:33:27.261381Z" - }, "lc_cell_meme": { "current": "59c41746-c9f0-11f0-9373-6a40bdb2b9ec-1-2776", "history": [ @@ -3064,7 +2947,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_strikethrough'])\n", "\n", @@ -3076,7 +2959,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "617dacbd-7ec6-4945-a8b2-5817482740c3", "metadata": { @@ -3155,12 +3037,6 @@ "id": "b84f742e-9cc1-4197-85dd-ebd4ed3e0242", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:27.545220Z", - "iopub.status.busy": "2026-01-06T08:33:27.544107Z", - "iopub.status.idle": "2026-01-06T08:33:31.387405Z", - "shell.execute_reply": "2026-01-06T08:33:31.386353Z" - }, "lc_cell_meme": { "current": "5b3ff374-c9f0-11f0-9373-6a40bdb2b9ec-1-f17f", "history": [ @@ -3245,7 +3121,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_strikethrough'])\n", "\n", @@ -3257,7 +3133,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "1b4e3d03-91ab-4567-a160-ac47a0c6b05c", "metadata": { @@ -3336,12 +3211,6 @@ "id": "3e827e71-3068-49f0-a538-d75994f9ea9f", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:31.673893Z", - "iopub.status.busy": "2026-01-06T08:33:31.672816Z", - "iopub.status.idle": "2026-01-06T08:33:35.905413Z", - "shell.execute_reply": "2026-01-06T08:33:35.904351Z" - }, "lc_cell_meme": { "current": "540dc56c-ca6e-11f0-9373-6a40bdb2b9ec-1-fcd1", "execution_end_time": "2025-11-26T02:54:54.168Z", @@ -3427,7 +3296,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_underlined'])\n", "\n", @@ -3439,7 +3308,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "d211c2d8-e313-40b0-89c1-ef6d3f2b29fc", "metadata": { @@ -3518,12 +3386,6 @@ "id": "a7d152f6-6284-4934-b745-bf58e0d7c1f0", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:36.198119Z", - "iopub.status.busy": "2026-01-06T08:33:36.197174Z", - "iopub.status.idle": "2026-01-06T08:33:39.396016Z", - "shell.execute_reply": "2026-01-06T08:33:39.394993Z" - }, "lc_cell_meme": { "current": "55287fbe-ca6e-11f0-9373-6a40bdb2b9ec-1-c7b0", "execution_end_time": "2025-11-26T02:54:57.599Z", @@ -3629,7 +3491,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_underlined'])\n", "\n", @@ -3641,7 +3503,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "b96cf2c2-693f-4eb4-a471-37d28bb6b3aa", "metadata": { @@ -3687,12 +3548,6 @@ "execution_count": null, "id": "68d38f1d-3031-42cd-bd55-acca9ecf3a95", "metadata": { - "execution": { - "iopub.execute_input": "2026-01-06T08:33:39.688963Z", - "iopub.status.busy": "2026-01-06T08:33:39.687941Z", - "iopub.status.idle": "2026-01-06T08:33:40.036052Z", - "shell.execute_reply": "2026-01-06T08:33:40.034989Z" - }, "lc_cell_meme": { "current": "b564ef88-eacc-11f0-88dd-aaa1b857283c", "history": [ @@ -3722,14 +3577,13 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.select_text_range(page, text)\n", "\n", "await run_pw(_step)" ] }, { - "attachments": {}, "cell_type": "markdown", "id": "3df661db-bc80-44be-bb40-35843cb12c6d", "metadata": { @@ -3828,12 +3682,6 @@ "id": "d9c03633-ad69-4947-b790-816ed5da8ae0", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:40.330637Z", - "iopub.status.busy": "2026-01-06T08:33:40.330388Z", - "iopub.status.idle": "2026-01-06T08:33:43.371651Z", - "shell.execute_reply": "2026-01-06T08:33:43.370792Z" - }, "lc_cell_meme": { "current": "55f47ce0-ca6e-11f0-9373-6a40bdb2b9ec-1-0191", "execution_end_time": "2025-11-26T02:55:01.182Z", @@ -3944,7 +3792,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "2379c306-8781-43c7-b1ed-ef06f21e4d04", "metadata": { @@ -4023,12 +3870,6 @@ "id": "8e7132f5-62c0-4960-b5ac-d9ccddd79cc0", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:43.674798Z", - "iopub.status.busy": "2026-01-06T08:33:43.673454Z", - "iopub.status.idle": "2026-01-06T08:33:46.524304Z", - "shell.execute_reply": "2026-01-06T08:33:46.523293Z" - }, "lc_cell_meme": { "current": "56b30a98-ca6e-11f0-9373-6a40bdb2b9ec-1-e903", "execution_end_time": "2025-11-26T02:55:04.549Z", @@ -4269,12 +4110,6 @@ "id": "c54bbd80-b64c-43b1-bbfa-92121f7787c2", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:46.829560Z", - "iopub.status.busy": "2026-01-06T08:33:46.828504Z", - "iopub.status.idle": "2026-01-06T08:33:47.015053Z", - "shell.execute_reply": "2026-01-06T08:33:47.014026Z" - }, "lc_cell_meme": { "current": "79092cee-ca73-11f0-9373-6a40bdb2b9ec-1-30dc", "history": [ @@ -4351,7 +4186,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "871f54f5-e8b4-4bb3-9faa-a2164261a941", "metadata": { @@ -4398,12 +4232,6 @@ "execution_count": null, "id": "f331fb26-47c8-4163-8dcb-281ff52743f0", "metadata": { - "execution": { - "iopub.execute_input": "2026-01-06T08:33:47.319997Z", - "iopub.status.busy": "2026-01-06T08:33:47.318909Z", - "iopub.status.idle": "2026-01-06T08:33:47.459636Z", - "shell.execute_reply": "2026-01-06T08:33:47.458589Z" - }, "lc_cell_meme": { "current": "ac97b9de-eacd-11f0-88dd-aaa1b857283c", "history": [ @@ -4440,7 +4268,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "f82fa05b-7cf6-4e11-858a-5a9f23bd199b", "metadata": { @@ -4514,12 +4341,6 @@ "id": "27a69196-58e6-4f75-9429-3884bc1598ab", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:47.773924Z", - "iopub.status.busy": "2026-01-06T08:33:47.773036Z", - "iopub.status.idle": "2026-01-06T08:33:54.872607Z", - "shell.execute_reply": "2026-01-06T08:33:54.871589Z" - }, "lc_cell_meme": { "current": "786a8242-ca73-11f0-9373-6a40bdb2b9ec-1-a238", "history": [ @@ -4600,7 +4421,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "244ae618-bee8-42db-8b27-bd7622aa6a12", "metadata": { @@ -4649,12 +4469,6 @@ "id": "e0c070a6-ceb9-4ce3-a415-7c98fadcd578", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:55.230497Z", - "iopub.status.busy": "2026-01-06T08:33:55.228987Z", - "iopub.status.idle": "2026-01-06T08:33:57.499861Z", - "shell.execute_reply": "2026-01-06T08:33:57.498801Z" - }, "lc_cell_meme": { "current": "7839f942-ca73-11f0-9373-6a40bdb2b9ec-1-2c81", "history": [ @@ -4716,7 +4530,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "de1912a1-cd5b-4175-9150-274ea1233d10", "metadata": { @@ -4765,12 +4578,6 @@ "id": "e8233f31-a856-4aaf-91ba-b05dbf9b887b", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:57.830841Z", - "iopub.status.busy": "2026-01-06T08:33:57.829677Z", - "iopub.status.idle": "2026-01-06T08:33:58.407144Z", - "shell.execute_reply": "2026-01-06T08:33:58.406093Z" - }, "lc_cell_meme": { "current": "7804308c-ca73-11f0-9373-6a40bdb2b9ec-1-ce82", "history": [ @@ -4827,7 +4634,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "28f9e887-f7a3-4088-a3bc-611d8290f5fa", "metadata": { @@ -4887,12 +4693,6 @@ "id": "34160e6c-a4a2-4ac1-ac00-ffb36a364f77", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:33:58.737681Z", - "iopub.status.busy": "2026-01-06T08:33:58.736646Z", - "iopub.status.idle": "2026-01-06T08:34:12.521007Z", - "shell.execute_reply": "2026-01-06T08:34:12.519766Z" - }, "lc_cell_meme": { "current": "c950e9d6-ca7c-11f0-9373-6a40bdb2b9ec-1-8d00", "history": [ @@ -4930,7 +4730,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "022b2f7f-f19c-4a9d-b849-344a0c912ed7", "metadata": { @@ -5009,12 +4808,6 @@ "id": "666cdfe9-53c3-4fda-b1cf-d1985db9ea24", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:12.845463Z", - "iopub.status.busy": "2026-01-06T08:34:12.845186Z", - "iopub.status.idle": "2026-01-06T08:34:12.988597Z", - "shell.execute_reply": "2026-01-06T08:34:12.987600Z" - }, "lc_cell_meme": { "current": "22beb1a4-dfab-11f0-99a8-12ab7e3bb6be-1-352b", "execution_end_time": "2025-12-23T04:47:32.385Z", @@ -5051,7 +4844,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "3d71556d-6b4c-4671-ab3f-0ef46a472715", "metadata": { @@ -5145,12 +4937,6 @@ "id": "e17a9b2b-989d-4091-981b-ab6a31ae79d2", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:13.326833Z", - "iopub.status.busy": "2026-01-06T08:34:13.326283Z", - "iopub.status.idle": "2026-01-06T08:34:15.629771Z", - "shell.execute_reply": "2026-01-06T08:34:15.629077Z" - }, "lc_cell_meme": { "current": "77a055b2-ca73-11f0-9373-6a40bdb2b9ec-1-77c4", "history": [ @@ -5231,7 +5017,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "674a1f67-f24e-4900-aa21-b1ac5609cd68", "metadata": { @@ -5280,12 +5065,6 @@ "id": "4e2f6371-f560-43e9-a2d8-4445cfd14cf5", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:15.987122Z", - "iopub.status.busy": "2026-01-06T08:34:15.986148Z", - "iopub.status.idle": "2026-01-06T08:34:19.334710Z", - "shell.execute_reply": "2026-01-06T08:34:19.333687Z" - }, "lc_cell_meme": { "current": "776d537e-ca73-11f0-9373-6a40bdb2b9ec-1-c059", "history": [ @@ -5340,7 +5119,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.click_wiki_menu_save(page, ['sort'])\n", "\n", " view_locator = page.locator('#mView .ProseMirror[contenteditable=\"false\"]')\n", @@ -5358,7 +5137,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "d6483e5c-7bb2-4c96-94f2-82cffab6dba2", "metadata": { @@ -5407,12 +5185,6 @@ "id": "f9f22935-d9fb-4725-803c-cd731c8558de", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:19.736126Z", - "iopub.status.busy": "2026-01-06T08:34:19.735026Z", - "iopub.status.idle": "2026-01-06T08:34:22.477669Z", - "shell.execute_reply": "2026-01-06T08:34:22.476388Z" - }, "lc_cell_meme": { "current": "7726e556-ca73-11f0-9373-6a40bdb2b9ec-1-b449", "history": [ @@ -5469,7 +5241,7 @@ "text = 'test クリック'\n", "async def _step(page):\n", " await grdm.open_wiki(page, new_wikiname, 'test')\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " \n", @@ -5480,7 +5252,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "c45f62df-e2a3-4b68-a6a7-393077f2d852", "metadata": { @@ -5524,12 +5295,6 @@ "id": "69d79f57-f387-4ef7-8330-9ba13a3814e5", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:22.832548Z", - "iopub.status.busy": "2026-01-06T08:34:22.831449Z", - "iopub.status.idle": "2026-01-06T08:34:23.507188Z", - "shell.execute_reply": "2026-01-06T08:34:23.506161Z" - }, "lc_cell_meme": { "current": "7726e6be-ca73-11f0-9373-6a40bdb2b9ec-1-bfdf", "history": [ @@ -5590,7 +5355,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "9373813d-b7b7-4d8d-9f9e-2889a53d73ea", "metadata": { @@ -5649,12 +5413,6 @@ "id": "c29b6ebe-1e48-4c10-bf74-227ccdf19d81", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:23.864056Z", - "iopub.status.busy": "2026-01-06T08:34:23.863442Z", - "iopub.status.idle": "2026-01-06T08:34:27.152986Z", - "shell.execute_reply": "2026-01-06T08:34:27.151721Z" - }, "lc_cell_meme": { "current": "761f6700-ca73-11f0-9373-6a40bdb2b9ec-1-7de2", "history": [ @@ -5721,7 +5479,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "cfb2f88e-9edb-4264-8163-df362b7c19e7", "metadata": { @@ -5770,12 +5527,6 @@ "id": "5cf4829e-9663-4ea5-8bb6-d5c7e66c2b9d", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:27.521137Z", - "iopub.status.busy": "2026-01-06T08:34:27.520098Z", - "iopub.status.idle": "2026-01-06T08:34:29.332811Z", - "shell.execute_reply": "2026-01-06T08:34:29.331966Z" - }, "lc_cell_meme": { "current": "74f9cf3c-ca73-11f0-9373-6a40bdb2b9ec-1-4880", "history": [ @@ -5841,7 +5592,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ff38f246-44b0-4c53-8bab-518369f25351", "metadata": { @@ -5895,12 +5645,6 @@ "id": "41f1d888-af36-459a-ae6a-8bbf8f7688b4", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:29.704197Z", - "iopub.status.busy": "2026-01-06T08:34:29.703950Z", - "iopub.status.idle": "2026-01-06T08:34:35.945768Z", - "shell.execute_reply": "2026-01-06T08:34:35.944698Z" - }, "lc_cell_meme": { "current": "8df53120-ca73-11f0-9373-6a40bdb2b9ec-1-e9f3", "history": [ @@ -5952,7 +5696,7 @@ "text = 'test 引用'\n", "async def _step(page):\n", " await grdm.open_wiki(page, new_wikiname, 'test')\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_quote'])\n", @@ -5965,7 +5709,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "29b65602-8abf-4478-9cf4-339a03e473ae", "metadata": { @@ -6009,12 +5752,6 @@ "id": "97f60680-a26f-4a02-9993-a2b9865d3b7d", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:36.312728Z", - "iopub.status.busy": "2026-01-06T08:34:36.311646Z", - "iopub.status.idle": "2026-01-06T08:34:41.813398Z", - "shell.execute_reply": "2026-01-06T08:34:41.812073Z" - }, "lc_cell_meme": { "current": "23c61f5e-cab8-11f0-9373-6a40bdb2b9ec-1-47e7", "history": [ @@ -6076,7 +5813,7 @@ "text = 'test コードブロック'\n", "async def _step(page):\n", " await grdm.open_wiki(page, new_wikiname, 'test')\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " count = await page.locator('blockquote').count()\n", " if count > 0:\n", " await page.locator('blockquote').evaluate_all(\"elements => elements.forEach(el => el.remove())\")\n", @@ -6092,7 +5829,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "20d8f4bb-9752-4841-bf0f-068ede461e55", "metadata": { @@ -6141,12 +5877,6 @@ "id": "762f2bd3-fa85-49f3-a33f-81dd96295f22", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:42.182876Z", - "iopub.status.busy": "2026-01-06T08:34:42.181522Z", - "iopub.status.idle": "2026-01-06T08:34:43.275401Z", - "shell.execute_reply": "2026-01-06T08:34:43.274283Z" - }, "lc_cell_meme": { "current": "c99752a6-cb3d-11f0-9373-6a40bdb2b9ec-1-9f47", "history": [ @@ -6201,7 +5931,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " editor_locator = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", " await editor_locator.click()\n", " count = await page.locator('pre:has(code)').count()\n", @@ -6214,7 +5944,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "782503d9-d029-4732-a7ea-986f815c77ff", "metadata": { @@ -6267,12 +5996,6 @@ "id": "94652d68-4038-4e50-9762-3a560414ca70", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:43.684579Z", - "iopub.status.busy": "2026-01-06T08:34:43.683540Z", - "iopub.status.idle": "2026-01-06T08:34:44.351220Z", - "shell.execute_reply": "2026-01-06T08:34:44.349681Z" - }, "lc_cell_meme": { "current": "cad00e88-cb3d-11f0-9373-6a40bdb2b9ec-1-5551", "history": [ @@ -6340,7 +6063,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "9bea9719-c76a-4ec2-9c90-2183f0105e85", "metadata": { @@ -6389,12 +6111,6 @@ "id": "2206981b-1ac7-4d41-8832-7fbdd8ba5324", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:44.721760Z", - "iopub.status.busy": "2026-01-06T08:34:44.720407Z", - "iopub.status.idle": "2026-01-06T08:34:47.952663Z", - "shell.execute_reply": "2026-01-06T08:34:47.951902Z" - }, "lc_cell_meme": { "current": "cb771138-cb3d-11f0-9373-6a40bdb2b9ec-1-95ca", "history": [ @@ -6461,7 +6177,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "8fa1a879-4513-479e-8fd2-0808ed9e28e9", "metadata": { @@ -6510,12 +6225,6 @@ "id": "1f39472c-0528-4d8a-b560-711a0eace27a", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:48.340804Z", - "iopub.status.busy": "2026-01-06T08:34:48.339468Z", - "iopub.status.idle": "2026-01-06T08:34:49.145648Z", - "shell.execute_reply": "2026-01-06T08:34:49.144797Z" - }, "lc_cell_meme": { "current": "cc06e696-cb3d-11f0-9373-6a40bdb2b9ec-1-b911", "history": [ @@ -6570,7 +6279,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " count = await page.locator('img[alt=\"非表示時文言\"]').count()\n", " if count > 0:\n", " await page.locator('img[alt=\"非表示時文言\"]').evaluate_all(\"elements => elements.forEach(el => el.remove())\")\n", @@ -6581,7 +6290,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "e14731a8-d8ae-45d3-b956-7b03258190f4", "metadata": { @@ -6633,12 +6341,6 @@ "id": "418f536e-c756-413c-9ff8-dee21c199192", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:49.534572Z", - "iopub.status.busy": "2026-01-06T08:34:49.534014Z", - "iopub.status.idle": "2026-01-06T08:34:50.237647Z", - "shell.execute_reply": "2026-01-06T08:34:50.236763Z" - }, "lc_cell_meme": { "current": "ccfc9384-cb3d-11f0-9373-6a40bdb2b9ec-1-76ce", "history": [ @@ -6706,7 +6408,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "6b39aa88-5272-4232-acbb-05858f818cea", "metadata": { @@ -6755,12 +6456,6 @@ "id": "0c07fe42-f706-4156-9639-a3ee1f139cb9", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:50.636126Z", - "iopub.status.busy": "2026-01-06T08:34:50.634924Z", - "iopub.status.idle": "2026-01-06T08:34:53.659041Z", - "shell.execute_reply": "2026-01-06T08:34:53.657908Z" - }, "lc_cell_meme": { "current": "ce1a6afc-cb3d-11f0-9373-6a40bdb2b9ec-1-5cc4", "history": [ @@ -6828,7 +6523,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "9d87e4ba-8454-4cc5-8464-4da62ebe958b", "metadata": { @@ -6880,12 +6574,6 @@ "id": "3b6c2d88-1f9f-4958-873f-8da0547b2427", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:54.054781Z", - "iopub.status.busy": "2026-01-06T08:34:54.053698Z", - "iopub.status.idle": "2026-01-06T08:34:57.556496Z", - "shell.execute_reply": "2026-01-06T08:34:57.555424Z" - }, "lc_cell_meme": { "current": "cf4b5896-cb3d-11f0-9373-6a40bdb2b9ec-1-d176", "history": [ @@ -6942,7 +6630,7 @@ "text = '番号付きリスト'\n", "\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " count = await page.locator('img[alt=\"非表示時文言\"]').count()\n", " if count > 0:\n", " await page.locator('img[alt=\"非表示時文言\"]').evaluate_all(\"elements => elements.forEach(el => el.remove())\")\n", @@ -6958,7 +6646,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "e523a255-3a3b-4475-bfcf-421ac48dcb55", "metadata": { @@ -7007,12 +6694,6 @@ "id": "40dcc880-8ea7-4c9d-b326-8509a9cc8994", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:34:57.962740Z", - "iopub.status.busy": "2026-01-06T08:34:57.961682Z", - "iopub.status.idle": "2026-01-06T08:35:01.512255Z", - "shell.execute_reply": "2026-01-06T08:35:01.511216Z" - }, "lc_cell_meme": { "current": "cfe99b50-cb3d-11f0-9373-6a40bdb2b9ec-1-03cd", "history": [ @@ -7069,7 +6750,7 @@ "text = '箇条書きリスト'\n", "\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " count = await page.locator('ol li p').count()\n", " if count > 0:\n", " await page.locator('ol li p').evaluate_all(\"elements => elements.forEach(el => el.remove())\")\n", @@ -7085,7 +6766,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ccbf5fff-b701-47f9-b9a4-0237784cd7db", "metadata": { @@ -7134,12 +6814,6 @@ "id": "718e92d3-fcfb-4a31-acc7-f6d60cc8c3c3", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:01.973952Z", - "iopub.status.busy": "2026-01-06T08:35:01.972688Z", - "iopub.status.idle": "2026-01-06T08:35:07.159695Z", - "shell.execute_reply": "2026-01-06T08:35:07.158728Z" - }, "lc_cell_meme": { "current": "b11f7bb4-cb73-11f0-93ae-6a40bdb2b9ec-1-69e1", "history": [ @@ -7196,7 +6870,7 @@ "text = 'test 見出し'\n", "\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " count = await page.locator('ul li p').count()\n", " if count > 0:\n", " await page.locator('ul li p').evaluate_all(\"elements => elements.forEach(el => el.remove())\")\n", @@ -7212,7 +6886,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "b2cdb4ae-7ab7-4abf-9036-6aaad1f24780", "metadata": { @@ -7261,12 +6934,6 @@ "id": "0fb6f9a9-c2d0-455d-91b5-c679a0a2cbc5", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:07.594388Z", - "iopub.status.busy": "2026-01-06T08:35:07.593346Z", - "iopub.status.idle": "2026-01-06T08:35:11.245642Z", - "shell.execute_reply": "2026-01-06T08:35:11.244293Z" - }, "lc_cell_meme": { "current": "29f2855e-cb74-11f0-93ae-6a40bdb2b9ec-1-315d", "history": [ @@ -7321,7 +6988,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['horizontal_rule'])\n", @@ -7334,7 +7001,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ed777362-b3d8-4b6b-97b3-05a6a26b7b3d", "metadata": { @@ -7383,12 +7049,6 @@ "id": "d7212592-810f-4f4c-a3cd-673fe88a48f3", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:11.679293Z", - "iopub.status.busy": "2026-01-06T08:35:11.678126Z", - "iopub.status.idle": "2026-01-06T08:35:16.564783Z", - "shell.execute_reply": "2026-01-06T08:35:16.563676Z" - }, "lc_cell_meme": { "current": "d736f100-cb74-11f0-93ae-6a40bdb2b9ec-1-229a", "history": [ @@ -7443,7 +7103,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " count = await page.locator('hr').count()\n", " if count > 0:\n", " await page.locator('hr').evaluate_all(\"elements => elements.forEach(el => el.remove())\")\n", @@ -7457,7 +7117,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "86604bcb-b952-4fd6-a980-31cef35bc169", "metadata": { @@ -7511,12 +7170,6 @@ "id": "a79504ca-ec7c-4e34-90a7-d75aa1b280ad", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:17.000013Z", - "iopub.status.busy": "2026-01-06T08:35:16.998908Z", - "iopub.status.idle": "2026-01-06T08:35:20.748531Z", - "shell.execute_reply": "2026-01-06T08:35:20.747266Z" - }, "lc_cell_meme": { "current": "4fdaf966-cb76-11f0-93ae-6a40bdb2b9ec-2-eb00-ce60", "history": [ @@ -7586,7 +7239,7 @@ " before_col_number = await col_locator.count()\n", " print(before_col_number)\n", "\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " row_index = 1\n", " col_index = 0\n", " await grdm.click_table_menu_save(page, row_index, col_index, \"前に列を挿入\")\n", @@ -7600,7 +7253,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "b2bc2872-a4a7-4505-a8fd-eef5c4f53e82", "metadata": { @@ -7654,12 +7306,6 @@ "id": "a89728dd-9773-48e0-8b04-76d77b7a5a75", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:21.181487Z", - "iopub.status.busy": "2026-01-06T08:35:21.180274Z", - "iopub.status.idle": "2026-01-06T08:35:25.124523Z", - "shell.execute_reply": "2026-01-06T08:35:25.123105Z" - }, "lc_cell_meme": { "current": "520358d0-cbff-11f0-93ae-6a40bdb2b9ec-2-8629-4bea", "execution_end_time": "2025-12-10T07:58:19.835Z", @@ -7730,7 +7376,7 @@ " before_col_number = await col_locator.count()\n", " print(before_col_number)\n", "\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " row_index = 1\n", " col_index = 1\n", " await grdm.click_table_menu_save(page, row_index, col_index, \"後に列を挿入\")\n", @@ -7744,7 +7390,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "942e7ade-2181-4c0e-b0ef-28f08ff2656a", "metadata": { @@ -7793,12 +7438,6 @@ "id": "f641f9d9-0a79-4430-9c83-b889759b8897", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:25.584730Z", - "iopub.status.busy": "2026-01-06T08:35:25.583753Z", - "iopub.status.idle": "2026-01-06T08:35:29.012899Z", - "shell.execute_reply": "2026-01-06T08:35:29.011803Z" - }, "lc_cell_meme": { "current": "0aab459c-d96a-11f0-806b-12ab7e3bb6be-1-8c87", "execution_end_time": "2025-12-15T04:56:00.761Z", @@ -7859,7 +7498,7 @@ " before_row_number = await row_locator.count()\n", " print(before_row_number)\n", "\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " row_index = 1\n", " col_index = 1\n", " await grdm.click_table_menu_save(page, row_index, col_index, \"前に行を挿入\")\n", @@ -7873,7 +7512,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "dadd8e11-5d86-4150-b0a0-2a91495f2089", "metadata": { @@ -7922,12 +7560,6 @@ "id": "bd27d9f2-c3c9-46af-af99-7fbc3033d077", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:29.465105Z", - "iopub.status.busy": "2026-01-06T08:35:29.464048Z", - "iopub.status.idle": "2026-01-06T08:35:32.939768Z", - "shell.execute_reply": "2026-01-06T08:35:32.938190Z" - }, "lc_cell_meme": { "current": "097447dc-d96a-11f0-806b-12ab7e3bb6be-1-6813", "execution_end_time": "2025-12-15T04:54:11.708Z", @@ -8023,7 +7655,7 @@ " before_row_number = await row_locator.count()\n", " print(before_row_number)\n", "\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " row_index = 2\n", " col_index = 3\n", " await grdm.click_table_menu_save(page, row_index, col_index, \"後に行を挿入\")\n", @@ -8037,7 +7669,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ce041b5d-e154-471e-81b2-5a8cc65c8959", "metadata": { @@ -8081,12 +7712,6 @@ "id": "68cb0481-4b81-4251-8041-b4c5fe515a1f", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:33.394418Z", - "iopub.status.busy": "2026-01-06T08:35:33.393963Z", - "iopub.status.idle": "2026-01-06T08:35:37.227870Z", - "shell.execute_reply": "2026-01-06T08:35:37.226582Z" - }, "lc_cell_meme": { "current": "5d0d14da-da25-11f0-806b-12ab7e3bb6be-1-8caf", "history": [ @@ -8146,7 +7771,7 @@ " before_row_number = await row_locator.count()\n", " print(before_row_number)\n", "\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " row_index = 1\n", " col_index = 4\n", " await grdm.click_table_menu_save(page, row_index, col_index, \"セルを削除\")\n", @@ -8160,7 +7785,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "8c11468b-ca74-4deb-b4bb-ec20ae989546", "metadata": { @@ -8209,12 +7833,6 @@ "id": "d8dcc897-025e-471c-b9ad-88be97678c1a", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:37.721098Z", - "iopub.status.busy": "2026-01-06T08:35:37.719745Z", - "iopub.status.idle": "2026-01-06T08:35:38.296611Z", - "shell.execute_reply": "2026-01-06T08:35:38.295493Z" - }, "lc_cell_meme": { "current": "5c96889c-da25-11f0-806b-12ab7e3bb6be-1-0bcd", "execution_end_time": "2025-12-16T04:46:21.167Z", @@ -8270,7 +7888,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " row_index = 0\n", " col_index = 1\n", " await grdm.click_table_menu_save(page, row_index, col_index, \"テーブルを削除\")\n", @@ -8280,7 +7898,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "39e8132c-e270-40a5-94da-b237872784cd", "metadata": { @@ -8329,12 +7946,6 @@ "id": "6dda328b-c2ce-43e7-a64e-539e2ef7087e", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:38.760552Z", - "iopub.status.busy": "2026-01-06T08:35:38.759770Z", - "iopub.status.idle": "2026-01-06T08:35:41.611142Z", - "shell.execute_reply": "2026-01-06T08:35:41.610091Z" - }, "lc_cell_meme": { "current": "5c227808-da25-11f0-806b-12ab7e3bb6be-1-c060", "execution_end_time": "2025-12-16T04:46:24.970Z", @@ -8390,7 +8001,7 @@ "outputs": [], "source": [ "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await page.locator(f'#mMenuBar span:has-text(\"help\")').click()\n", " await expect(page.locator('//h3[contains(@class, \"modal-title\") and text()=\"Wiki構文のヘルプ\"]')).to_be_visible(timeout=transition_timeout*2)\n", "\n", @@ -8399,7 +8010,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "c11b9cdd-bbe8-4bd1-bc1f-4d361d4c926b", "metadata": { @@ -8448,12 +8058,6 @@ "id": "55dd03ac-d3a1-48d6-82a8-d330b324f08b", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:42.085122Z", - "iopub.status.busy": "2026-01-06T08:35:42.084873Z", - "iopub.status.idle": "2026-01-06T08:35:46.866192Z", - "shell.execute_reply": "2026-01-06T08:35:46.865161Z" - }, "lc_cell_meme": { "current": "5bdaad48-da25-11f0-806b-12ab7e3bb6be-1-8231", "history": [ @@ -8617,7 +8221,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "495d4ea0-b9ee-4693-810b-059a4e4f1b21", "metadata": { @@ -8661,12 +8264,6 @@ "id": "cf8d6625-e940-4e5a-8d0d-2e436e71bc28", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:47.341330Z", - "iopub.status.busy": "2026-01-06T08:35:47.340285Z", - "iopub.status.idle": "2026-01-06T08:35:51.277149Z", - "shell.execute_reply": "2026-01-06T08:35:51.276041Z" - }, "lc_cell_meme": { "current": "150e508e-da2c-11f0-806b-12ab7e3bb6be-1-a872", "execution_end_time": "2025-12-16T04:46:33.637Z", @@ -8718,7 +8315,7 @@ "source": [ "text = 'test 太文字、取消線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_strikethrough'])\n", @@ -8731,7 +8328,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "4231623f-80fb-4dd1-afc6-99df23275a8c", "metadata": { @@ -8775,12 +8371,6 @@ "id": "0cfe93f8-9c7e-4418-ae7e-672589bcf47b", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:51.758700Z", - "iopub.status.busy": "2026-01-06T08:35:51.757491Z", - "iopub.status.idle": "2026-01-06T08:35:56.478953Z", - "shell.execute_reply": "2026-01-06T08:35:56.477897Z" - }, "lc_cell_meme": { "current": "14c12fc0-da2c-11f0-806b-12ab7e3bb6be-1-ea62", "execution_end_time": "2025-12-16T04:46:38.515Z", @@ -8847,7 +8437,7 @@ "source": [ "text = 'test 太文字、下線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_underlined'])\n", @@ -8860,7 +8450,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "9263b36e-78a2-4484-8154-a183e362f025", "metadata": { @@ -8909,12 +8498,6 @@ "id": "52e2d2ae-863a-47cf-942b-b1ad88b757dd", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:35:56.964811Z", - "iopub.status.busy": "2026-01-06T08:35:56.963729Z", - "iopub.status.idle": "2026-01-06T08:36:01.100961Z", - "shell.execute_reply": "2026-01-06T08:36:01.099885Z" - }, "lc_cell_meme": { "current": "1420c6fc-da2c-11f0-806b-12ab7e3bb6be-1-da78", "execution_end_time": "2025-12-16T04:46:43.086Z", @@ -8971,7 +8554,7 @@ "source": [ "text = 'test 太文字、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_color_text'])\n", @@ -8984,7 +8567,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "53bfbe43-d630-4732-afd8-7051d532e60a", "metadata": { @@ -9033,12 +8615,6 @@ "id": "f0f82173-fd0e-4f22-a464-0d5ac5408880", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:01.616805Z", - "iopub.status.busy": "2026-01-06T08:36:01.615731Z", - "iopub.status.idle": "2026-01-06T08:36:06.917911Z", - "shell.execute_reply": "2026-01-06T08:36:06.916893Z" - }, "lc_cell_meme": { "current": "138771dc-da2c-11f0-806b-12ab7e3bb6be-1-3114", "execution_end_time": "2025-12-16T04:46:47.581Z", @@ -9095,7 +8671,7 @@ "source": [ "text = 'test 斜体、取消線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['italicWiki', 'format_strikethrough'])\n", @@ -9108,7 +8684,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "ef9d9903-e3b1-4b03-ad47-7ba8b967d98f", "metadata": { @@ -9157,12 +8732,6 @@ "id": "4237d195-bd92-4386-86f8-3e245fc407e6", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:07.410564Z", - "iopub.status.busy": "2026-01-06T08:36:07.409657Z", - "iopub.status.idle": "2026-01-06T08:36:11.362030Z", - "shell.execute_reply": "2026-01-06T08:36:11.360763Z" - }, "lc_cell_meme": { "current": "1300ee64-da2c-11f0-806b-12ab7e3bb6be-1-1a20", "execution_end_time": "2025-12-16T04:46:51.982Z", @@ -9219,7 +8788,7 @@ "source": [ "text = 'test 斜体、下線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['italicWiki', 'format_underlined'])\n", @@ -9232,7 +8801,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "65c5b35a-e6b5-4652-bb75-12f23201e80a", "metadata": { @@ -9281,12 +8849,6 @@ "id": "0fdbb533-55f9-44cf-b88e-64e2729eb35f", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:11.863826Z", - "iopub.status.busy": "2026-01-06T08:36:11.862795Z", - "iopub.status.idle": "2026-01-06T08:36:16.608535Z", - "shell.execute_reply": "2026-01-06T08:36:16.607498Z" - }, "lc_cell_meme": { "current": "1244cffe-da2c-11f0-806b-12ab7e3bb6be-1-7aaf", "execution_end_time": "2025-12-16T04:46:56.706Z", @@ -9343,7 +8905,7 @@ "source": [ "text = 'test 斜体、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['italicWiki', 'format_color_text'])\n", @@ -9356,7 +8918,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "90847be1-7a31-4ab3-9426-cd7b91b01909", "metadata": { @@ -9405,12 +8966,6 @@ "id": "d61f56ff-fc29-4253-9934-6b2a064834f7", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:17.118061Z", - "iopub.status.busy": "2026-01-06T08:36:17.117146Z", - "iopub.status.idle": "2026-01-06T08:36:21.090996Z", - "shell.execute_reply": "2026-01-06T08:36:21.089917Z" - }, "lc_cell_meme": { "current": "11bab788-da2c-11f0-806b-12ab7e3bb6be-1-0efc", "execution_end_time": "2025-12-16T04:47:01.231Z", @@ -9462,7 +9017,7 @@ "source": [ "text = 'test 取消、下線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_strikethrough', 'format_underlined'])\n", @@ -9475,7 +9030,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "bfb8615b-6f6d-44b8-a281-dc178fa2a9f0", "metadata": { @@ -9519,12 +9073,6 @@ "id": "92afd576-2f98-475d-8928-d99b4b5a95b6", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:21.588155Z", - "iopub.status.busy": "2026-01-06T08:36:21.587273Z", - "iopub.status.idle": "2026-01-06T08:36:26.280061Z", - "shell.execute_reply": "2026-01-06T08:36:26.278962Z" - }, "lc_cell_meme": { "current": "11281cd4-da2c-11f0-806b-12ab7e3bb6be-1-aee2", "execution_end_time": "2025-12-16T04:47:05.981Z", @@ -9611,7 +9159,7 @@ "source": [ "text = 'test 取消、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_strikethrough', 'format_color_text'])\n", @@ -9624,7 +9172,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "d3d058a5-c222-4b84-8fd6-032254afcb01", "metadata": { @@ -9668,12 +9215,6 @@ "id": "cc200d11-93ec-405b-ad45-bc51686a23d1", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:26.782811Z", - "iopub.status.busy": "2026-01-06T08:36:26.781678Z", - "iopub.status.idle": "2026-01-06T08:36:31.006814Z", - "shell.execute_reply": "2026-01-06T08:36:31.005778Z" - }, "lc_cell_meme": { "current": "175e7ff2-dfaf-11f0-99a8-12ab7e3bb6be-1-6263", "history": [ @@ -9719,7 +9260,7 @@ "source": [ "text = 'test 下線、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['format_underlined', 'format_color_text'])\n", @@ -9732,7 +9273,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "0f4677e3-4fa4-4340-8348-75663545485c", "metadata": { @@ -9806,12 +9346,6 @@ "id": "a9b2c68f-db02-4a7f-8dbf-fc8b3aa0f28f", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:31.562190Z", - "iopub.status.busy": "2026-01-06T08:36:31.561120Z", - "iopub.status.idle": "2026-01-06T08:36:36.272406Z", - "shell.execute_reply": "2026-01-06T08:36:36.271282Z" - }, "lc_cell_meme": { "current": "1083a384-da2c-11f0-806b-12ab7e3bb6be-3-a1a8-7175-c69f", "execution_end_time": "2025-12-16T04:47:10.418Z", @@ -9868,7 +9402,7 @@ "source": [ "text = 'test 太文字、斜体、取消線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_strikethrough'])\n", @@ -9881,7 +9415,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "c0a61bdf-9523-412c-98c4-56bb47ee990e", "metadata": { @@ -9950,12 +9483,6 @@ "id": "ce10bf58-e44a-49ac-8268-74fe9c620d6e", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:36.801993Z", - "iopub.status.busy": "2026-01-06T08:36:36.801283Z", - "iopub.status.idle": "2026-01-06T08:36:41.037416Z", - "shell.execute_reply": "2026-01-06T08:36:41.036375Z" - }, "lc_cell_meme": { "current": "0fb8f3b4-da2c-11f0-806b-12ab7e3bb6be-1-7152", "execution_end_time": "2025-12-16T04:47:15.006Z", @@ -10112,7 +9639,7 @@ "source": [ "text = 'test 太文字、斜体、下線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_underlined'])\n", @@ -10125,7 +9652,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "29073b93-badb-4239-ab89-ae86c07c311c", "metadata": { @@ -10169,12 +9695,6 @@ "id": "fffa94cb-ac1a-4ea6-aba4-1edffe0d97eb", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:41.545737Z", - "iopub.status.busy": "2026-01-06T08:36:41.544491Z", - "iopub.status.idle": "2026-01-06T08:36:46.299226Z", - "shell.execute_reply": "2026-01-06T08:36:46.298196Z" - }, "lc_cell_meme": { "current": "e16d8ac6-da33-11f0-806b-12ab7e3bb6be-1-379e", "execution_end_time": "2025-12-16T04:47:19.576Z", @@ -10231,7 +9751,7 @@ "source": [ "text = 'test 太文字、斜体、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_color_text'])\n", @@ -10244,7 +9764,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "23107f65-b7f4-4e13-aad0-338cfb76ce45", "metadata": { @@ -10293,12 +9812,6 @@ "id": "574f2963-2c36-4790-9835-123361724b4e", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:46.825112Z", - "iopub.status.busy": "2026-01-06T08:36:46.824052Z", - "iopub.status.idle": "2026-01-06T08:36:51.016292Z", - "shell.execute_reply": "2026-01-06T08:36:51.015042Z" - }, "lc_cell_meme": { "current": "e0d53ac8-da33-11f0-806b-12ab7e3bb6be-1-558b", "execution_end_time": "2025-12-16T04:47:24.481Z", @@ -10355,7 +9868,7 @@ "source": [ "text = 'test 太文字、取消、下線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_strikethrough', 'format_underlined'])\n", @@ -10368,7 +9881,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "2ce056cc-b7cd-4104-a24c-026264114212", "metadata": { @@ -10417,12 +9929,6 @@ "id": "06f9d597-9dc5-4984-b1dc-1279ece9f4f0", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:51.541314Z", - "iopub.status.busy": "2026-01-06T08:36:51.540122Z", - "iopub.status.idle": "2026-01-06T08:36:56.521681Z", - "shell.execute_reply": "2026-01-06T08:36:56.520661Z" - }, "lc_cell_meme": { "current": "e000a3f8-da33-11f0-806b-12ab7e3bb6be-1-7ba4", "execution_end_time": "2025-12-16T04:47:29.408Z", @@ -10479,7 +9985,7 @@ "source": [ "text = 'test 太文字、取消、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_strikethrough', 'format_color_text'])\n", @@ -10492,7 +9998,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "dfce8a65-b0f9-4d23-b01e-4a04e299bc6f", "metadata": { @@ -10536,12 +10041,6 @@ "id": "8f907371-996d-4c26-b30c-d9ef5188da8b", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:36:57.053773Z", - "iopub.status.busy": "2026-01-06T08:36:57.053006Z", - "iopub.status.idle": "2026-01-06T08:37:01.329233Z", - "shell.execute_reply": "2026-01-06T08:37:01.328216Z" - }, "lc_cell_meme": { "current": "dfb029d2-da33-11f0-806b-12ab7e3bb6be-1-41fc", "execution_end_time": "2025-12-16T04:47:34.214Z", @@ -10603,7 +10102,7 @@ "source": [ "text = 'test 太文字、下線、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_underlined', 'format_color_text'])\n", @@ -10616,7 +10115,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "b8d22c2d-4a8c-4eb7-ac7a-cab45a5d2fb6", "metadata": { @@ -10665,12 +10163,6 @@ "id": "94824ec7-cf82-4a16-b325-00bd129e20cf", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:01.888229Z", - "iopub.status.busy": "2026-01-06T08:37:01.887088Z", - "iopub.status.idle": "2026-01-06T08:37:06.972687Z", - "shell.execute_reply": "2026-01-06T08:37:06.971294Z" - }, "lc_cell_meme": { "current": "df189b6c-da33-11f0-806b-12ab7e3bb6be-1-eaca", "execution_end_time": "2025-12-16T04:47:39.038Z", @@ -10727,7 +10219,7 @@ "source": [ "text = 'test 太文字、斜体、取消、下線'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_strikethrough', 'format_underlined'])\n", @@ -10740,7 +10232,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "bd5c83ab-0bfc-42bc-8436-caaf0356f83f", "metadata": { @@ -10789,12 +10280,6 @@ "id": "e968d8b4-c6ba-4f04-95d0-eaac8232e4ec", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:07.511988Z", - "iopub.status.busy": "2026-01-06T08:37:07.511054Z", - "iopub.status.idle": "2026-01-06T08:37:11.585558Z", - "shell.execute_reply": "2026-01-06T08:37:11.584235Z" - }, "lc_cell_meme": { "current": "de77c3e0-da33-11f0-806b-12ab7e3bb6be-1-93b9", "execution_end_time": "2025-12-16T04:47:44.016Z", @@ -10851,7 +10336,7 @@ "source": [ "text = 'test 太文字、斜体、取消、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_strikethrough', 'format_color_text'])\n", @@ -10864,7 +10349,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "cebb8382-5acd-4019-8903-d5773623197b", "metadata": { @@ -10913,12 +10397,6 @@ "id": "d2d058e1-5401-4a7d-b0a4-906b7ebcfe2c", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:12.155533Z", - "iopub.status.busy": "2026-01-06T08:37:12.154467Z", - "iopub.status.idle": "2026-01-06T08:37:17.062266Z", - "shell.execute_reply": "2026-01-06T08:37:17.060928Z" - }, "lc_cell_meme": { "current": "ddef3ffc-da33-11f0-806b-12ab7e3bb6be-1-4199", "execution_end_time": "2025-12-16T04:47:48.942Z", @@ -10975,7 +10453,7 @@ "source": [ "text = 'test 太文字、斜体、下線、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_underlined', 'format_color_text'])\n", @@ -10988,7 +10466,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "594fdc86-54e7-417c-a741-84a5683df078", "metadata": { @@ -11032,12 +10509,6 @@ "id": "c9537b85-b780-494d-ae7e-ecfc9b579a42", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:17.606601Z", - "iopub.status.busy": "2026-01-06T08:37:17.605682Z", - "iopub.status.idle": "2026-01-06T08:37:21.607193Z", - "shell.execute_reply": "2026-01-06T08:37:21.605843Z" - }, "lc_cell_meme": { "current": "dd3c0fc2-da33-11f0-806b-12ab7e3bb6be-1-ab9d", "execution_end_time": "2025-12-16T04:47:53.791Z", @@ -11099,7 +10570,7 @@ "source": [ "text = 'test 太文字、取消線、下線、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'format_strikethrough', 'format_underlined', 'format_color_text'])\n", @@ -11112,7 +10583,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "id": "89394919-a358-4203-9a00-abfd8828964d", "metadata": { @@ -11161,12 +10631,6 @@ "id": "e85d9053-db10-429c-a469-337dcd137edb", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:22.158498Z", - "iopub.status.busy": "2026-01-06T08:37:22.157260Z", - "iopub.status.idle": "2026-01-06T08:37:27.104670Z", - "shell.execute_reply": "2026-01-06T08:37:27.103626Z" - }, "lc_cell_meme": { "current": "dca02f12-da33-11f0-806b-12ab7e3bb6be-1-9523", "execution_end_time": "2025-12-16T04:47:58.911Z", @@ -11268,7 +10732,7 @@ "source": [ "text = 'test 太文字、斜体、取消線、下線、フォントカラーが赤'\n", "async def _step(page):\n", - " await grdm.open_edit_wiki(page)\n", + " await grdm.open_edit_wiki_collab(page)\n", " await grdm.fill_text(page, text)\n", " await grdm.select_text_range(page, text)\n", " await grdm.click_wiki_menu_save(page, ['strongWiki', 'italicWiki', 'format_strikethrough', 'format_underlined', 'format_color_text'])\n", @@ -11280,6 +10744,910 @@ "await run_pw(_step)" ] }, + { + "cell_type": "markdown", + "id": "b2e2b7f9", + "metadata": {}, + "source": [ + "## 本文を変更せず Close ボタンをクリックする\n", + "\n", + "- 確認ダイアログ(#closeConfirmModal)が表示されないこと\n", + "- 編集モードが終了し、閲覧モード(「編集」ボタンが表示されること)に戻ること\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ebbbb061", + "metadata": {}, + "outputs": [], + "source": [ + "async def _step(page):\n", + " # 前セルの保存後は閲覧モードに戻ることがある\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki_collab(page)\n", + "\n", + " await expect(page.locator('#mMenuBar')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')).to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 本文は変更しない → Close(閉じる)をクリック\n", + " await page.locator('#revert-button').click()\n", + "\n", + " # 確認ダイアログが出ないこと\n", + " await expect(page.locator('#closeConfirmModal')).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 閲覧モードに戻ったこと\n", + " await expect(page.locator('#mMenuBar')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditorFooter')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "9da14719", + "metadata": {}, + "source": [ + "## 本文を変更して Close ボタンをクリックする\n", + "\n", + "- 確認ダイアログ(#closeConfirmModal)が表示されること\n", + "- ダイアログに「編集内容は保存されていません。閉じる前に保存しますか?」が表示されること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c544549", + "metadata": {}, + "outputs": [], + "source": [ + "async def _step(page):\n", + " await grdm.open_edit_wiki(page)\n", + " await grdm.replace_wiki_text(page, '本文変更Closeテスト')\n", + "\n", + " await page.locator('#revert-button').click()\n", + "\n", + " modal = page.locator('#closeConfirmModal')\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + " await expect(modal).to_contain_text('未保存の変更')\n", + " await expect(modal).to_contain_text('編集内容は保存されていません。閉じる前に保存しますか?')\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "02cf3a4b", + "metadata": {}, + "source": [ + "## 確認ダイアログで「キャンセル」をクリックする\n", + "\n", + "- 確認ダイアログ(#closeConfirmModal)が閉じること\n", + "- 編集モードが継続すること(メニューバー・編集エリアが表示されたままであること)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7f425d6", + "metadata": {}, + "outputs": [], + "source": [ + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + "\n", + " # 「本文を変更して Close」直後はダイアログが開いたまま・編集モードのままなので、その場合は準備を省略\n", + " if not await modal.is_visible():\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki(page)\n", + " await grdm.replace_wiki_text(page, 'キャンセル後変更テスト')\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + "\n", + " await page.locator('#closeConfirmModal button.btn-default[data-dismiss=\"modal\"]').click()\n", + "\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 編集モードのまま\n", + " await expect(page.locator('#mMenuBar')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditorFooter')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#editWysiwyg')).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "46aad814", + "metadata": {}, + "source": [ + "## 確認ダイアログで「破棄」をクリックする\n", + "\n", + "- 確認ダイアログ(#closeConfirmModal)が閉じること\n", + "- 編集モードが終了し、閲覧モード(「編集」ボタンが表示されること)に戻ること\n", + "- 未保存の変更が保存されず、閲覧画面に反映されないこと" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1581d2a", + "metadata": {}, + "outputs": [], + "source": [ + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + "\n", + " if not await modal.is_visible():\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki(page)\n", + " await grdm.replace_wiki_text(page, '破棄Close変更テスト')\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + "\n", + " await page.locator('#closeConfirmModal button.btn-danger').click()\n", + "\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 閲覧モードに戻る(変更なし Close と同じ)\n", + " await expect(page.locator('#mMenuBar')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditorFooter')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 破棄されたこと(未保存の変更が閲覧画面に出ない)\n", + " await expect(page.locator('#wikiViewRender')).not_to_contain_text('破棄Close変更テスト', timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "a5d5496f", + "metadata": {}, + "source": [ + "## 確認ダイアログで「保存して閉じる」をクリックする\n", + "\n", + "- 確認ダイアログ(#closeConfirmModal)が閉じること\n", + "- 編集モードが終了し、閲覧モード(「編集」ボタンが表示されること)に戻ること\n", + "- 未保存の変更が保存され、閲覧画面(#wikiViewRender)に反映されること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcc9edc6", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " save_text = '保存して閉じる変更テスト'\n", + "\n", + " if not await modal.is_visible():\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await grdm.append_wiki_text(page, save_text)\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + "\n", + " async with page.expect_navigation(timeout=transition_timeout):\n", + " await page.locator('#closeConfirmModal button.btn-success').click()\n", + "\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 閲覧モードに戻る(変更なし Close・破棄 Close と同じ)\n", + " await expect(page.locator('#mMenuBar')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditorFooter')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 保存されたこと(破棄 Close の not_to_contain_text の逆)\n", + " await expect(page.locator('#wikiViewRender')).to_contain_text(save_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "7d85783f", + "metadata": {}, + "source": [ + "## 破棄後に再編集すると DB の保存済み本文が表示される\n", + "\n", + "- 編集モードで未保存の変更を加え、「破棄」で閉じること\n", + "- 閲覧画面に破棄した変更が反映されないこと\n", + "- 再度「編集」をクリックすると、DB に保存済みの本文(「保存して閉じる」で保存した `保存して閉じる変更テスト`)が編集エリアに表示されること\n", + "- 破棄した未保存の変更(`破棄再編集テスト`)は編集エリアに表示されないこと" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "991df6ff", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " saved_text = '保存して閉じる変更テスト' # 「保存して閉じる」で DB に保存済み\n", + " discard_text = '破棄再編集テスト' # 今回破棄する未保存の変更\n", + " editor = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + "\n", + " # 破棄フロー(「破棄」Close テストと同様)\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await expect(editor).to_contain_text(saved_text, timeout=transition_timeout)\n", + " await grdm.append_wiki_text(page, discard_text)\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + "\n", + " await page.locator('#closeConfirmModal button.btn-danger').click()\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 閲覧モードに戻り、破棄されたこと\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#wikiViewRender')).to_contain_text(saved_text, timeout=transition_timeout)\n", + " await expect(page.locator('#wikiViewRender')).not_to_contain_text(discard_text, timeout=transition_timeout)\n", + "\n", + " # 再編集 → DB の保存済み本文が表示される\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await expect(editor).to_contain_text(saved_text, timeout=transition_timeout)\n", + " await expect(editor).not_to_contain_text(discard_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "60d76ae5", + "metadata": {}, + "source": [ + "## 保存して閉じた後に再編集すると保存した内容が表示される\n", + "\n", + "- 編集モードで未保存の変更を加え、「保存して閉じる」で閉じること\n", + "- 閲覧画面(#wikiViewRender)に保存した変更(`保存して閉じる再編集テスト`)が反映されること\n", + "- 再度「編集」をクリックすると、保存した内容が編集エリアに表示されること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19e8366c", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " save_text = '保存して閉じる再編集テスト'\n", + " editor = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + "\n", + " # 「破棄後に再編集…」直後は編集モードのままなので、その場合は open_edit_wiki を省略\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki_collab(page)\n", + "\n", + " await grdm.append_wiki_text(page, save_text)\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + "\n", + " async with page.expect_navigation(timeout=transition_timeout):\n", + " await page.locator('#closeConfirmModal button.btn-success').click()\n", + "\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#wikiViewRender')).to_contain_text(save_text, timeout=transition_timeout)\n", + "\n", + " # 再編集 → 保存した内容が編集エリアに表示される\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await expect(editor).to_contain_text(save_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "b7c0dcf8", + "metadata": {}, + "source": [ + "## フッターの「保存」後に離脱警告が出ない\n", + "\n", + "- 編集モードで未保存の変更を加え、フッターの「保存」ボタン(Close 確認ダイアログとは別)で保存すること\n", + "- 保存によるページ遷移時に **beforeunload の離脱警告が出ない** こと\n", + "- 閲覧画面(#wikiViewRender)に保存した変更(`フッター保存テスト`)が反映されること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13bdf855", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " save_text = 'フッター保存テスト'\n", + "\n", + " # 「保存して閉じた後に再編集…」直後は編集モードのまま\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki_collab(page)\n", + "\n", + " await grdm.append_wiki_text(page, save_text)\n", + "\n", + " async def save_action():\n", + " async with page.expect_navigation(timeout=transition_timeout):\n", + " await page.locator('//input[@type=\"submit\" and @value=\"保存\"]').click()\n", + "\n", + " await grdm.expect_no_dialog(page, save_action, transition_timeout)\n", + "\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#wikiViewRender')).to_contain_text(save_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "c07c0937", + "metadata": {}, + "source": [ + "## 未保存のままページを離れようとすると離脱警告が出る\n", + "\n", + "- 編集モードで未保存の変更を加え、**保存しない** こと\n", + "- Close 確認ダイアログが出ることで、未保存状態であることを確認すること\n", + "- ページを離れようとすると **beforeunload の離脱警告** が表示されること(本テストでは `window.location.reload()` で発火)\n", + "- 警告で離脱をキャンセルすると **編集モードが維持** され、未保存の変更(`離脱警告未保存テスト`)が編集エリアに残ること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c01d9d1", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " unsaved_text = '離脱警告未保存テスト'\n", + " editor = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " modal = page.locator('#closeConfirmModal')\n", + "\n", + " # 前回失敗で Close 確認が残っていればキャンセル\n", + " if await modal.is_visible():\n", + " await page.locator('#closeConfirmModal button.btn-default[data-dismiss=\"modal\"]').click()\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 「フッター保存後に離脱警告が出ない」直後は編集モードのまま\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki_collab(page)\n", + "\n", + " await grdm.append_wiki_text(page, unsaved_text)\n", + " await expect(editor).to_contain_text(unsaved_text, timeout=transition_timeout)\n", + "\n", + " # 未保存であること(editModeOff と同じ dirty 判定)\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + " await page.locator('#closeConfirmModal button.btn-default[data-dismiss=\"modal\"]').click()\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " async def reload_action():\n", + " await page.evaluate('window.location.reload()')\n", + "\n", + " await grdm.expect_beforeunload(page, reload_action, transition_timeout)\n", + "\n", + " await expect(page.locator('#mMenuBar')).to_be_visible(timeout=transition_timeout)\n", + " await expect(editor).to_contain_text(unsaved_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "ca00ce90", + "metadata": {}, + "source": [ + "## 新規 Wiki 作成直後にリロードなしで入力できる\n", + "\n", + "- 新規 Wiki ページを追加し、作成によるページ遷移の直後であること(**追加の reload は行わない**)\n", + "- 作成直後はプレビューで開くため「編集」を押し、編集 UI(`#mMenuBar`・編集エリア)ですぐ入力できること\n", + "- 編集エリアに `新規作成直後入力テスト` を入力できること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08cd9815", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " create_immediate_wikiname = '新規作成直後テストWiki'\n", + " input_text = '新規作成直後入力テスト'\n", + " editor = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " modal = page.locator('#closeConfirmModal')\n", + " wiki_link = page.locator(f'//*[contains(@class, \"title-text\")]//a[text()=\"{create_immediate_wikiname}\"]')\n", + "\n", + " async def _open_create_immediate_wiki():\n", + " if await page.locator('#pageName').is_visible():\n", + " if (await page.locator('#pageName').inner_text()).strip() == create_immediate_wikiname:\n", + " return\n", + " await grdm.goto_wiki_by_name(page, create_immediate_wikiname, transition_timeout=transition_timeout)\n", + "\n", + " # 「離脱警告」テスト直後など編集モードの場合は閲覧へ\n", + " if await page.locator('#mMenuBar').is_visible():\n", + " if not await modal.is_visible():\n", + " await page.locator('#revert-button').click()\n", + " try:\n", + " await expect(modal).to_be_visible(timeout=3000)\n", + " await page.locator('#closeConfirmModal button.btn-danger').click()\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + " except AssertionError:\n", + " pass\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + "\n", + " # 再実行時は既存ページを削除してから新規作成\n", + " if await wiki_link.count() > 0:\n", + " await _open_create_immediate_wiki()\n", + " await expect(page.locator('#pageName')).to_have_text(create_immediate_wikiname, timeout=transition_timeout)\n", + " await page.locator('div[data-target=\"#deleteWiki\"]').click()\n", + " async with page.expect_navigation(timeout=transition_timeout):\n", + " await page.locator('#delete-wiki').click()\n", + "\n", + " await page.locator('div[data-target=\"#newWiki\"]').click()\n", + " await expect(page.locator('h3.modal-title', has_text='新規Wikiページを追加')).to_be_visible(timeout=transition_timeout)\n", + " await page.locator('input[name=\"addHierarchy\"][value=\"same\"]').check()\n", + " await page.fill('#data', create_immediate_wikiname)\n", + " async with page.expect_navigation(timeout=transition_timeout):\n", + " await page.locator('#add-wiki-submit').click()\n", + " await expect(page.locator('#pageName')).to_have_text(create_immediate_wikiname, timeout=transition_timeout)\n", + "\n", + " # 作成遷移直後(reload なし)。アプリは preview で開くので「編集」へ\n", + " await grdm.open_edit_wiki(page)\n", + "\n", + " await grdm.replace_wiki_text(page, input_text)\n", + " await expect(editor).to_contain_text(input_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "de50410a", + "metadata": {}, + "source": [ + "## 共同編集中は未保存変更があっても Close 確認ダイアログが出ない\n", + "\n", + "- 同一ユーザーで2タブを開き、`New Wiki` を共同編集する\n", + "- タブ A で未保存の変更を加えたうえで Close をクリックする\n", + "- 確認ダイアログ(`#closeConfirmModal`)が**表示されない**こと\n", + "- タブ A はプレビュー(閲覧)に戻ること(`#editWysiwyg` 表示・`#mMenuBar` 非表示)\n", + "- タブ B は編集モードのまま継続すること" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d061ee4a", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " unsaved_text = '共同編集Close未保存テスト'\n", + " modal = page.locator('#closeConfirmModal')\n", + " editor = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + "\n", + " # 「新規 Wiki 作成直後…」直後など: 編集モードのまま別 Wiki へ goto すると ERR_ABORTED になるため先に閲覧へ\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + "\n", + " on_new_wiki = (\n", + " await page.locator('#pageName').is_visible()\n", + " and (await page.locator('#pageName').inner_text()).strip() == new_wikiname\n", + " )\n", + " if not on_new_wiki:\n", + " await grdm.goto_wiki_by_name(page, new_wikiname, transition_timeout=transition_timeout)\n", + "\n", + " await grdm.open_edit_wiki_collab(page)\n", + "\n", + " page_b = await grdm.open_collaborative_peer(page, transition_timeout=transition_timeout)\n", + " try:\n", + " await grdm.append_wiki_text(page, unsaved_text)\n", + " await expect(editor).to_contain_text(unsaved_text, timeout=transition_timeout)\n", + "\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).not_to_be_visible(timeout=3000)\n", + "\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mMenuBar')).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#mEditorFooter')).not_to_be_visible(timeout=transition_timeout)\n", + "\n", + " await expect(page_b.locator('#mMenuBar')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page_b.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')).to_be_visible(timeout=transition_timeout)\n", + " finally:\n", + " await page_b.close()\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "eba04121", + "metadata": {}, + "source": [ + "## Close 後に再 Edit すると相手側に名前が再表示される\n", + "\n", + "- 同一ユーザーで2タブを開き、`New Wiki` を共同編集する\n", + "- タブ A が Close して共同編集セッションから抜ける\n", + "- タブ B の編集画面に、タブ A のユーザー名(`.ProseMirror-yjs-cursor` 内ラベル)が**表示されない**こと\n", + "- タブ A が再度「編集」を押して戻る\n", + "- タブ B の編集画面に、タブ A のユーザー名が**再表示される**こと" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf5e27c2", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " editor_a = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + "\n", + " on_new_wiki = (\n", + " await page.locator('#pageName').is_visible()\n", + " and (await page.locator('#pageName').inner_text()).strip() == new_wikiname\n", + " )\n", + " if not on_new_wiki:\n", + " await grdm.goto_wiki_by_name(page, new_wikiname, transition_timeout=transition_timeout)\n", + "\n", + " await grdm.open_edit_wiki_collab(page)\n", + " collaborator_name = await grdm.get_wiki_user_fullname(page)\n", + "\n", + " page_b = await grdm.open_collaborative_peer(page, transition_timeout=transition_timeout)\n", + " try:\n", + " await editor_a.click()\n", + " await page.keyboard.press('End')\n", + " await grdm.wait_awareness_settle(page_b)\n", + " await grdm.expect_remote_collaborator_name(\n", + " page_b, collaborator_name, visible=True, transition_timeout=transition_timeout\n", + " )\n", + "\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).not_to_be_visible(timeout=3000)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + "\n", + " await grdm.wait_awareness_settle(page_b)\n", + " await grdm.expect_remote_collaborator_name(\n", + " page_b, collaborator_name, visible=False, transition_timeout=transition_timeout\n", + " )\n", + "\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await editor_a.click()\n", + " await page.keyboard.press('End')\n", + " await grdm.wait_awareness_settle(page_b)\n", + " await grdm.expect_remote_collaborator_name(\n", + " page_b, collaborator_name, visible=True, transition_timeout=transition_timeout\n", + " )\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + " await grdm.leave_edit_wiki_if_open(page_b, transition_timeout=transition_timeout)\n", + " finally:\n", + " await page_b.close()\n", + "\n", + "await run_pw(_step)" + ] + }, + { + "cell_type": "markdown", + "id": "c2f8eef5", + "metadata": {}, + "source": [ + "## A が Close・B が保存した後、A 再 Edit で B の追記が表示される\n", + "\n", + "- 同一ユーザーで2タブを開き、`New Wiki` を共同編集する\n", + "- タブ A で `A追記Closeテスト` を**末尾に追記**し、Close して共同編集セッションから抜ける\n", + "- タブ B でも `B保存追記テスト` を**末尾に追記**し、フッターの「保存」で DB に保存する\n", + " - A・B とも `append_wiki_text`(キーボードで追記するのと同じ操作)\n", + "- タブ A が再度「編集」を押す\n", + "- タブ A の編集エリアに `B保存追記テスト` が表示されること\n", + "\n", + "**補足(何を確認しているか)**\n", + "\n", + "- 手動と同じ流れ: A Close → B 追記・保存 → A 再 Edit → 編集エリアを確認\n", + "- Close 中の A 画面(プレビュー)は更新されないため、**Close 中の `#mEditor` は見ない**\n", + "- 再 Edit では DB から読み直さない(共同編集 Close 後もライブ Y.Doc を使う)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20c0ef99", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " editor_a = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " text_a = 'A追記Closeテスト'\n", + " text_b = 'B保存追記テスト'\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + "\n", + " on_new_wiki = (\n", + " await page.locator('#pageName').is_visible()\n", + " and (await page.locator('#pageName').inner_text()).strip() == new_wikiname\n", + " )\n", + " if not on_new_wiki:\n", + " await grdm.goto_wiki_by_name(page, new_wikiname, transition_timeout=transition_timeout)\n", + "\n", + " # ① A・B で共同編集を開始\n", + " await grdm.open_edit_wiki_collab(page)\n", + " page_b = await grdm.open_collaborative_peer(page, transition_timeout=transition_timeout)\n", + " editor_b = page_b.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " try:\n", + " # ② タブ A で末尾に追記 → Close(ダイアログなし)\n", + " await grdm.append_wiki_text(page, text_a)\n", + " await expect(editor_a).to_contain_text(text_a, timeout=transition_timeout)\n", + "\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).not_to_be_visible(timeout=3000)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + "\n", + " # ③ タブ B で末尾に追記 → 保存\n", + " await grdm.append_wiki_text(page_b, text_b)\n", + " await expect(editor_b).to_contain_text(text_b, timeout=transition_timeout)\n", + " await grdm.click_wiki_footer_save(page_b, transition_timeout=transition_timeout)\n", + " await expect(page_b.locator('#wikiViewRender')).to_contain_text(text_b, timeout=transition_timeout)\n", + "\n", + " # ④ タブ A が再 Edit → B の追記が表示される(手動と同じ確認タイミング)\n", + " await page.bring_to_front()\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await expect(editor_a).to_contain_text(text_b, timeout=transition_timeout)\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + " await grdm.leave_edit_wiki_if_open(page_b, transition_timeout=transition_timeout)\n", + " await grdm.wait_awareness_settle(page, ms=1000)\n", + " finally:\n", + " await page_b.close()\n", + "\n", + "await run_pw(_step)\n" + ] + }, + { + "cell_type": "markdown", + "id": "cd1082bf", + "metadata": {}, + "source": [ + "## A が Close・B が編集中のとき、A 再 Edit で B のライブ内容が表示される\n", + "\n", + "- 同一ユーザーで2タブを開き、`New Wiki` を共同編集する\n", + "- タブ A で `A追記Closeライブテスト` を末尾に追記し、Close して共同編集セッションから抜ける\n", + "- タブ B は**保存せず**編集を続け、`B編集中追記テスト` を末尾に追記する\n", + "- タブ A が再度「編集」を押す → `Live editing mode` となり、B 側に A の名前が再表示されること\n", + "- 再 Edit 後、`#mEditor` に `A追記Closeライブテスト` と `B編集中追記テスト` が表示されること\n", + "\n", + "B が保存したケース(Step 13)との違い: 本 Step では **B は保存しない** 点です。\n", + "\n", + "**自動化補足:** A Close 後、Playwright から同一 B タブへ入力すると Yjs に届かないことがあるため、③ では `handoff_to_fresh_collab_peer` で live Y.Doc 参加用の新タブへ切り替える(手動で別ウィンドウを開く操作に相当)。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e58d78be", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " editor_a = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " text_a = 'A追記Closeライブテスト'\n", + " text_b = 'B編集中追記テスト'\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + "\n", + " on_new_wiki = (\n", + " await page.locator('#pageName').is_visible()\n", + " and (await page.locator('#pageName').inner_text()).strip() == new_wikiname\n", + " )\n", + " if not on_new_wiki:\n", + " await grdm.goto_wiki_by_name(page, new_wikiname, transition_timeout=transition_timeout)\n", + "\n", + " # ① A・B で共同編集を開始\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await grdm.wait_awareness_settle(page, ms=1000)\n", + " collaborator_name = await grdm.get_wiki_user_fullname(page)\n", + "\n", + " page_b = await grdm.open_collaborative_peer(page, transition_timeout=transition_timeout)\n", + " editor_b = page_b.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " try:\n", + " await editor_a.click()\n", + " await page.keyboard.press('End')\n", + " await grdm.wait_awareness_settle(page_b, ms=1000)\n", + " await grdm.expect_remote_collaborator_name(\n", + " page_b, collaborator_name, visible=True, transition_timeout=transition_timeout\n", + " )\n", + "\n", + " # ② タブ A で末尾に追記 → Close(ダイアログなし)\n", + " await grdm.append_wiki_text(page, text_a)\n", + " await expect(editor_a).to_contain_text(text_a, timeout=transition_timeout)\n", + " await page_b.bring_to_front()\n", + " await expect(editor_b).to_contain_text(text_a, timeout=transition_timeout)\n", + " await grdm.flush_collab_yjs(page, page_b, rounds=4, settle_ms=500)\n", + " await page.bring_to_front()\n", + " await grdm.wait_awareness_settle(page, ms=1000)\n", + "\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).not_to_be_visible(timeout=3000)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await grdm.wait_awareness_settle(page_b, ms=1000)\n", + " await grdm.expect_remote_collaborator_name(\n", + " page_b, collaborator_name, visible=False, transition_timeout=transition_timeout\n", + " )\n", + "\n", + " # A Close 後: 新タブで live Y.Doc に参加(Playwright 自動化向け workaround)\n", + " page_b = await grdm.handoff_to_fresh_collab_peer(\n", + " page_b, required_text=text_a, transition_timeout=transition_timeout\n", + " )\n", + " editor_b = page_b.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + "\n", + " # ③ タブ B は保存せず編集継続 → 末尾に追記\n", + " await grdm.append_wiki_text_live(page_b, text_b)\n", + " await expect(editor_b).to_contain_text(text_b, timeout=transition_timeout)\n", + "\n", + " # ④ タブ A が再 Edit → B の追記が表示される\n", + " await grdm.reopen_collab_edit_on_receiver(page, page_b, transition_timeout=transition_timeout)\n", + " await grdm.expect_remote_collaborator_name(\n", + " page_b, collaborator_name, visible=True, transition_timeout=transition_timeout\n", + " )\n", + " await expect(page.locator('#mEditor')).to_contain_text(text_a, timeout=transition_timeout)\n", + " await grdm.wait_for_collab_meditor_text(\n", + " page, text_b, peer_page=page_b, transition_timeout=transition_timeout, stable_checks=2\n", + " )\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + " await grdm.leave_edit_wiki_if_open(page_b, transition_timeout=transition_timeout)\n", + " await grdm.wait_awareness_settle(page, ms=1000)\n", + " finally:\n", + " await page_b.close()\n", + "\n", + "await run_pw(_step)\n" + ] + }, + { + "cell_type": "markdown", + "id": "3102a5b3", + "metadata": {}, + "source": [ + "## 両者 Close 後に再 Edit すると DB 保存済み内容が表示される\n", + "\n", + "- 同一ユーザーで2タブを開き、`New Wiki` を共同編集する\n", + "- タブ B で `DB保存追記テスト` を末尾に追記し、フッターの「保存」で DB に保存する\n", + "- タブ A・B とも `破棄Close未保存テスト` を末尾に追記する(**保存しない**)\n", + "- タブ B が Close して共同編集セッションから抜け、タブ B を閉じる\n", + "- タブ A が Close すると確認ダイアログが表示される(他の編集者がいないため)→ **破棄** で閉じる\n", + "- タブ A が再度「編集」を押す\n", + "- 編集エリアに `DB保存追記テスト` が表示されること\n", + "- 未保存の `破棄Close未保存テスト` は編集エリアに表示されないこと\n", + "\n", + "B が編集中のライブ内容を表示するケースとの違い: 本テストでは **両者が Close し、A は破棄 Close 後に DB から読み直す** 点です。\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "072e9697", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import scripts.grdm\n", + "grdm = importlib.reload(scripts.grdm)\n", + "\n", + "async def _step(page):\n", + " modal = page.locator('#closeConfirmModal')\n", + " editor_a = page.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " saved_text = 'DB保存追記テスト'\n", + " unsaved_text = '破棄Close未保存テスト'\n", + "\n", + " await grdm.leave_edit_wiki_if_open(page, transition_timeout=transition_timeout)\n", + "\n", + " on_new_wiki = (\n", + " await page.locator('#pageName').is_visible()\n", + " and (await page.locator('#pageName').inner_text()).strip() == new_wikiname\n", + " )\n", + " if not on_new_wiki:\n", + " await grdm.goto_wiki_by_name(page, new_wikiname, transition_timeout=transition_timeout)\n", + "\n", + " # ① A・B で共同編集を開始\n", + " await grdm.open_edit_wiki_collab(page)\n", + " page_b = await grdm.open_collaborative_peer(page, transition_timeout=transition_timeout)\n", + " editor_b = page_b.locator('#mEditor .ProseMirror[contenteditable=\"true\"]')\n", + " modal_b = page_b.locator('#closeConfirmModal')\n", + " try:\n", + " # ② B が DB に保存\n", + " await grdm.append_wiki_text(page_b, saved_text)\n", + " await grdm.click_wiki_footer_save(page_b, transition_timeout=transition_timeout)\n", + " await expect(page_b.locator('#wikiViewRender')).to_contain_text(saved_text, timeout=transition_timeout)\n", + "\n", + " # ③ 共同編集を再開し、未保存の変更を加える\n", + " if not await page.locator('#mMenuBar').is_visible():\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await grdm.open_edit_wiki_collab(page_b)\n", + " await grdm.expect_live_editing(page, transition_timeout=transition_timeout)\n", + " await grdm.expect_live_editing(page_b, transition_timeout=transition_timeout)\n", + "\n", + " await grdm.append_wiki_text(page, unsaved_text)\n", + " await grdm.append_wiki_text(page_b, unsaved_text)\n", + " await expect(editor_a).to_contain_text(unsaved_text, timeout=transition_timeout)\n", + " await expect(editor_b).to_contain_text(unsaved_text, timeout=transition_timeout)\n", + "\n", + " # ④ B が Close → タブ B を閉じる(A だけが残る)\n", + " await page_b.locator('#revert-button').click()\n", + " await expect(modal_b).not_to_be_visible(timeout=3000)\n", + " await expect(page_b.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " finally:\n", + " await page_b.close()\n", + " await grdm.wait_awareness_settle(page)\n", + "\n", + " # ⑤ A が Close(他編集者なし → 確認ダイアログ)→ 破棄\n", + " await page.locator('#revert-button').click()\n", + " await expect(modal).to_be_visible(timeout=transition_timeout)\n", + " await page.locator('#closeConfirmModal button.btn-danger').click()\n", + " await expect(modal).not_to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#editWysiwyg')).to_be_visible(timeout=transition_timeout)\n", + " await expect(page.locator('#wikiViewRender')).to_contain_text(saved_text, timeout=transition_timeout)\n", + " await expect(page.locator('#wikiViewRender')).not_to_contain_text(unsaved_text, timeout=transition_timeout)\n", + "\n", + " # ⑥ A が再 Edit → DB 保存済み内容が表示される\n", + " await grdm.open_edit_wiki_collab(page)\n", + " await expect(editor_a).to_contain_text(saved_text, timeout=transition_timeout)\n", + " await expect(editor_a).not_to_contain_text(unsaved_text, timeout=transition_timeout)\n", + "\n", + "await run_pw(_step)\n" + ] + }, { "cell_type": "markdown", "id": "fbd73c64-3b58-495a-b728-d689e3294911", @@ -11322,12 +11690,6 @@ "id": "355f6775-5345-4512-bf24-8224f623947a", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:27.674639Z", - "iopub.status.busy": "2026-01-06T08:37:27.673655Z", - "iopub.status.idle": "2026-01-06T08:37:35.171123Z", - "shell.execute_reply": "2026-01-06T08:37:35.170058Z" - }, "lc_cell_meme": { "current": "85f16d06-dfac-11f0-99a8-12ab7e3bb6be-1-7a78", "history": [ @@ -11437,12 +11799,6 @@ "id": "6c6b87d6-523d-41e5-bc2e-4598c6176102", "metadata": { "deletable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:35.746127Z", - "iopub.status.busy": "2026-01-06T08:37:35.745729Z", - "iopub.status.idle": "2026-01-06T08:37:37.463375Z", - "shell.execute_reply": "2026-01-06T08:37:37.462236Z" - }, "lc_cell_meme": { "current": "0d153210-80d6-11ed-95e1-0242ac120004-21-d3c9-8f37-5cd8-9428-1829-d342-e53a-e30a-e794-c796", "execution_end_time": "2025-01-20T12:22:52.866081Z", @@ -11743,12 +12099,6 @@ "metadata": { "deletable": true, "editable": true, - "execution": { - "iopub.execute_input": "2026-01-06T08:37:37.751576Z", - "iopub.status.busy": "2026-01-06T08:37:37.751285Z", - "iopub.status.idle": "2026-01-06T08:37:37.894950Z", - "shell.execute_reply": "2026-01-06T08:37:37.893323Z" - }, "lc_cell_meme": { "current": "41ca8840-0c28-11f0-98e9-5e0a5654d7bd-13-e116-9124-7b17-b85d-ecad-31de-f0f7-6f38-ea7a-6e50", "history": [ @@ -11864,17 +12214,21 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.9" + "version": "3.13.7" }, "lc_notebook_meme": { "current": "fdf30b38-0421-11ef-b901-9ee4ca18f90f",