mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-29 00:20:04 +01:00
260 lines
7.7 KiB
TypeScript
260 lines
7.7 KiB
TypeScript
/*
|
|
This file is part of the Notesnook project (https://notesnook.com/)
|
|
|
|
Copyright (C) 2023 Streetwriters (Private) Limited
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import { Locator, Page } from "@playwright/test";
|
|
import { getTestId } from "../utils";
|
|
|
|
export class EditorModel {
|
|
private readonly page: Page;
|
|
private readonly title: Locator;
|
|
private readonly content: Locator;
|
|
private readonly tags: Locator;
|
|
private readonly tagInput: Locator;
|
|
private readonly focusModeButton: Locator;
|
|
private readonly normalModeButton: Locator;
|
|
private readonly darkModeButton: Locator;
|
|
private readonly lightModeButton: Locator;
|
|
private readonly enterFullscreenButton: Locator;
|
|
private readonly exitFullscreenButton: Locator;
|
|
private readonly wordCountText: Locator;
|
|
private readonly dateEditedText: Locator;
|
|
private readonly searchButton: Locator;
|
|
private readonly previewCancelButton: Locator;
|
|
private readonly previewRestoreButton: Locator;
|
|
private readonly previewNotice: Locator;
|
|
|
|
constructor(page: Page) {
|
|
this.page = page;
|
|
this.title = page.locator(getTestId("editor-title"));
|
|
this.content = page.locator(".ProseMirror");
|
|
this.tagInput = page.locator(getTestId("editor-tag-input"));
|
|
this.tags = page.locator(`${getTestId("tags")} > ${getTestId("tag")}`);
|
|
this.focusModeButton = page.locator(getTestId("Focus mode"));
|
|
this.normalModeButton = page.locator(getTestId("Normal mode"));
|
|
this.darkModeButton = page.locator(getTestId("Dark mode"));
|
|
this.lightModeButton = page.locator(getTestId("Light mode"));
|
|
this.enterFullscreenButton = page.locator(getTestId("Enter fullscreen"));
|
|
this.exitFullscreenButton = page.locator(getTestId("Exit fullscreen"));
|
|
this.wordCountText = page.locator(getTestId("editor-word-count"));
|
|
this.dateEditedText = page.locator(getTestId("editor-date-edited"));
|
|
this.searchButton = page.locator(getTestId("Search"));
|
|
this.previewNotice = page.locator(getTestId("preview-notice"));
|
|
this.previewCancelButton = page.locator(getTestId("preview-notice-cancel"));
|
|
this.previewRestoreButton = page.locator(
|
|
getTestId("preview-notice-restore")
|
|
);
|
|
}
|
|
|
|
async waitForLoading(title?: string, content?: string) {
|
|
await this.title.waitFor();
|
|
|
|
await this.page.waitForFunction(
|
|
({ expected }) => {
|
|
const titleInput = document.querySelector(
|
|
`[data-test-id="editor-title"]`
|
|
) as HTMLInputElement | null;
|
|
if (titleInput)
|
|
return expected !== undefined
|
|
? titleInput.value === expected
|
|
: titleInput.value.length > 0;
|
|
return false;
|
|
},
|
|
{ expected: title }
|
|
);
|
|
|
|
if (content !== undefined)
|
|
await this.content.locator(":scope", { hasText: content }).waitFor();
|
|
}
|
|
|
|
async waitForUnloading() {
|
|
await this.page.waitForURL(/#\/notes\/create\/\d+/gm);
|
|
await this.searchButton.waitFor({ state: "hidden" });
|
|
await this.page.locator(getTestId("tags")).waitFor({ state: "hidden" });
|
|
await this.wordCountText.waitFor({ state: "hidden" });
|
|
await this.waitForLoading("", "");
|
|
}
|
|
|
|
async waitForSaving() {
|
|
await this.page.waitForURL(/#\/notes\/?.+\/edit/gm);
|
|
await this.page.locator(getTestId("tags")).waitFor();
|
|
await this.searchButton.waitFor();
|
|
await this.wordCountText.waitFor();
|
|
}
|
|
|
|
async isUnloaded() {
|
|
return (
|
|
(await this.tagInput.isHidden()) &&
|
|
(await this.darkModeButton.isHidden()) &&
|
|
(await this.enterFullscreenButton.isHidden()) &&
|
|
(await this.wordCountText.isHidden())
|
|
);
|
|
}
|
|
|
|
async setTitle(text: string) {
|
|
await this.editAndWait(async () => {
|
|
await this.title.fill(text);
|
|
});
|
|
}
|
|
|
|
async typeTitle(text: string, delay = 0) {
|
|
await this.editAndWait(async () => {
|
|
await this.title.focus();
|
|
await this.title.press("End");
|
|
await this.title.type(text, { delay });
|
|
});
|
|
}
|
|
|
|
async setContent(text: string) {
|
|
await this.editAndWait(async () => {
|
|
await this.content.focus();
|
|
await this.content.type(text);
|
|
});
|
|
}
|
|
|
|
async clear() {
|
|
await this.editAndWait(async () => {
|
|
await this.selectAll();
|
|
await this.content.press("Backspace");
|
|
});
|
|
}
|
|
|
|
async editAndWait(action: () => Promise<void>) {
|
|
const oldDateEdited = await this.getDateEdited();
|
|
await action();
|
|
await this.page.waitForFunction(
|
|
({ oldDateEdited }) => {
|
|
const dateEditedText = document.querySelector(
|
|
`[data-test-id="editor-date-edited"]`
|
|
);
|
|
const timestampText = dateEditedText?.getAttribute("title");
|
|
if (!timestampText) return false;
|
|
const timestamp = parseInt(timestampText);
|
|
return timestamp > oldDateEdited;
|
|
},
|
|
{ oldDateEdited }
|
|
);
|
|
}
|
|
|
|
async getDateEdited() {
|
|
if (await this.dateEditedText.isHidden()) return 0;
|
|
|
|
const timestamp = await this.dateEditedText.getAttribute("title");
|
|
if (timestamp) return parseInt(timestamp);
|
|
return 0;
|
|
}
|
|
|
|
async selectAll() {
|
|
await this.content.focus();
|
|
await this.page.keyboard.press("Control+a");
|
|
await this.page.waitForTimeout(500);
|
|
}
|
|
|
|
async setTags(tags: string[]) {
|
|
for (const tag of tags) {
|
|
await this.tagInput.focus();
|
|
await this.tagInput.fill(tag);
|
|
await this.tagInput.press("Enter");
|
|
await this.tags
|
|
.locator(":scope", { hasText: new RegExp(`^${tag}$`) })
|
|
.waitFor();
|
|
}
|
|
}
|
|
|
|
async getTags() {
|
|
const tags: string[] = [];
|
|
const count = await this.tags.count();
|
|
for (let i = 0; i < count; ++i) {
|
|
const item = this.tags.nth(i);
|
|
const tag = await item.textContent();
|
|
if (tag) tags.push(tag);
|
|
}
|
|
return tags;
|
|
}
|
|
|
|
async getTitle() {
|
|
return this.title.inputValue();
|
|
}
|
|
|
|
async getContent(format: "html" | "text") {
|
|
return format === "html"
|
|
? await this.content.innerHTML()
|
|
: (await this.content.innerText()).trim().replace(/\n+/gm, "\n");
|
|
}
|
|
|
|
async enterFocusMode() {
|
|
await this.focusModeButton.click();
|
|
await this.normalModeButton.waitFor();
|
|
}
|
|
|
|
async exitFocusMode() {
|
|
await this.normalModeButton.click();
|
|
await this.focusModeButton.waitFor();
|
|
}
|
|
|
|
async isFocusMode() {
|
|
return await this.normalModeButton.isVisible();
|
|
}
|
|
|
|
async enterDarkMode() {
|
|
await this.darkModeButton.click();
|
|
await this.lightModeButton.waitFor();
|
|
}
|
|
|
|
async exitDarkMode() {
|
|
await this.lightModeButton.click();
|
|
await this.darkModeButton.waitFor();
|
|
}
|
|
|
|
async isDarkMode() {
|
|
return await this.lightModeButton.isVisible();
|
|
}
|
|
|
|
async enterFullscreen() {
|
|
await this.enterFullscreenButton.click();
|
|
await this.exitFullscreenButton.waitFor();
|
|
}
|
|
|
|
async exitFullscreen() {
|
|
await this.exitFullscreenButton.click();
|
|
await this.enterFullscreenButton.waitFor();
|
|
}
|
|
|
|
async isFullscreen() {
|
|
return await this.exitFullscreenButton.isVisible();
|
|
}
|
|
|
|
async cancelPreview() {
|
|
await this.previewCancelButton.click();
|
|
await this.previewNotice.waitFor({ state: "hidden" });
|
|
}
|
|
|
|
async restoreSession() {
|
|
await this.previewRestoreButton.click();
|
|
await this.previewNotice.waitFor({ state: "hidden" });
|
|
}
|
|
|
|
async getWordCount() {
|
|
return parseInt(
|
|
(await this.wordCountText.allInnerTexts())
|
|
.toString()
|
|
.replace(" words", "")
|
|
);
|
|
}
|
|
}
|