import { Page, Locator, ElectronApplication } from '@playwright/test'; import NoteEditorScreen from './NoteEditor/NoteEditorScreen'; import activateMainMenuItem from '../util/activateMainMenuItem'; import Sidebar from './Sidebar'; import GoToAnything from './GoToAnything'; import setFilePickerResponse from '../util/setFilePickerResponse'; import NoteList from './NoteList'; import { expect } from '../util/test'; import ChangeAppLayoutScreen from './ChangeAppLayoutScreen'; import waitForNextWindowMatching from '../util/waitForNextWindowMatching'; import ChatPanel from './ChatPanel'; export default class MainScreen { public readonly newNoteButton: Locator; public readonly noteList: NoteList; public readonly sidebar: Sidebar; public readonly dialog: Locator; public readonly noteEditor: NoteEditorScreen; public readonly goToAnything: GoToAnything; public readonly changeLayoutScreen: ChangeAppLayoutScreen; public readonly chatPanel: ChatPanel; public constructor(private page: Page) { this.newNoteButton = page.locator('.new-note-button'); this.noteList = new NoteList(page); this.sidebar = new Sidebar(page, this); this.dialog = page.locator('.dialog-modal-layer'); this.noteEditor = new NoteEditorScreen(page); this.goToAnything = new GoToAnything(page, this); this.changeLayoutScreen = new ChangeAppLayoutScreen(page, this); this.chatPanel = new ChatPanel(page, this); } public async setup() { await this.waitFor(); const folder = await this.sidebar.createNewFolder('Test'); await folder.waitFor(); return this; } public async waitFor() { await this.noteList.waitFor(); } // Follows the steps a user would use to create a new note. public async createNewNote(title: string) { await this.waitFor(); // The new note button is only visible when a folder is selected -- wait for it explicitly. await this.newNoteButton.waitFor(); // Create the new note. Retry this -- creating new notes can sometimes fail if done just after // application startup. await expect.poll(async () => { await this.newNoteButton.click(); await expect(this.noteEditor.noteTitleInput).toHaveValue('', { timeout: 4_000 }); await expect(this.noteEditor.noteTitleInput).toHaveJSProperty('placeholder', 'Creating new note...', { timeout: 4_000 }); return true; }, { timeout: 10_000 }).toBe(true); // Fill the title await this.noteEditor.noteTitleInput.click(); await this.noteEditor.noteTitleInput.fill(title); // Wait for the title to reach the note list, otherwise a later sort can run // while the note is still "Untitled" and order the list unexpectedly. if (title !== '') { await this.noteList.getNoteItemByTitle(title).waitFor(); } return this.noteEditor; } public async openSettings(electronApp: ElectronApplication) { // Check both labels so this works on MacOS await activateMainMenuItem(electronApp, /^(Preferences\.\.\.|Options)$/); } public async openNewWindow(electronApp: ElectronApplication) { const pagePromise = waitForNextWindowMatching(/^Joplin -/, electronApp); await activateMainMenuItem(electronApp, 'Open in new window'); return pagePromise; } public async search(text: string) { const searchBar = this.page.getByPlaceholder('Search...'); await searchBar.fill(text); } private async importFromModule_(electronApp: ElectronApplication, moduleName: string, path: string) { await setFilePickerResponse(electronApp, [path]); await activateMainMenuItem(electronApp, moduleName, 'Import'); } public async importHtmlDirectory(electronApp: ElectronApplication, path: string) { return this.importFromModule_(electronApp, 'HTML - HTML document (Directory)', path); } public async importHtmlFile(electronApp: ElectronApplication, path: string) { return this.importFromModule_(electronApp, 'HTML - HTML document (File)', path); } public async pluginPanelLocator(pluginId: string) { return this.page.locator( `iframe[id^=${JSON.stringify(`plugin-view-${pluginId}`)}]`, ); } }