From 17b5cdb9e8217d02b22110392747e584577f09f9 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Wed, 5 Jan 2022 21:05:05 +0800 Subject: [PATCH] feat: add a secret global flag to load graph progammtically (#3531) * feat: add a secret global flag to load graph from a user defined dir * fix: use LOGSEQ_OVERWRITE_OPEN_DIR env var to overwrite the openning graph dir * e2e: add a test for load & check saved graph data * fix: should also pass in process.env for testing fixtures * feat: new way to set open dir folder * fix: e2e * fix: remove playwright global flag check Co-authored-by: Tienson Qin --- .gitignore | 1 + e2e-tests/basic.spec.ts | 21 +++++++++++-- e2e-tests/fixtures.ts | 12 ++++++++ e2e-tests/utils.ts | 44 +++++++++++++++++++++++++++ resources/js/preload.js | 5 +-- src/electron/electron/core.cljs | 6 ++-- src/electron/electron/handler.cljs | 14 ++++----- src/main/frontend/fs/node.cljs | 9 +++++- src/main/frontend/handler/export.cljs | 7 ++++- src/main/frontend/util.cljc | 6 ++++ 10 files changed, 108 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index 09b9564d0d..60b12f58d7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ pom.xml.asc node_modules/ static/ +tmp .cpcache/ /src/gen diff --git a/e2e-tests/basic.spec.ts b/e2e-tests/basic.spec.ts index 95107d34ad..348cb7dc5f 100644 --- a/e2e-tests/basic.spec.ts +++ b/e2e-tests/basic.spec.ts @@ -1,5 +1,7 @@ import { expect } from '@playwright/test' -import { test } from './fixtures' +import fs from 'fs/promises' +import path from 'path' +import { test, graphDir } from './fixtures' import { randomString, createRandomPage, newBlock } from './utils' @@ -41,7 +43,7 @@ test('search', async ({ page }) => { }) test('create page and blocks', async ({ page }) => { - await createRandomPage(page) + const pageTitle = await createRandomPage(page) // do editing await page.fill(':nth-match(textarea, 1)', 'this is my first bullet') @@ -81,6 +83,21 @@ test('create page and blocks', async ({ page }) => { await page.keyboard.press('Escape') await page.waitForTimeout(500) expect(await page.$$('.ls-block')).toHaveLength(5) + + await page.waitForTimeout(500) + + const contentOnDisk = await fs.readFile( + path.join(graphDir, `pages/${pageTitle}.md`), + 'utf8' + ) + + expect(contentOnDisk.trim()).toEqual(` +- this is my first bullet +- this is my second bullet + - this is my third bullet + - continue editing test + continue +- test ok`.trim()) }) test('delete and backspace', async ({ page }) => { diff --git a/e2e-tests/fixtures.ts b/e2e-tests/fixtures.ts index 261782bc1d..4c1d6f0a19 100644 --- a/e2e-tests/fixtures.ts +++ b/e2e-tests/fixtures.ts @@ -1,9 +1,14 @@ +import fs from 'fs' +import path from 'path' import { test as base, expect, ConsoleMessage } from '@playwright/test'; import { ElectronApplication, Page, BrowserContext, _electron as electron } from 'playwright' +import { loadLocalGraph, randomString } from './utils'; let electronApp: ElectronApplication let context: BrowserContext let page: Page +let repoName = randomString(10) +export let graphDir = path.resolve(__dirname, '../tmp/e2e-graph', repoName) // NOTE: This is a console log watcher for error logs. const consoleLogWatcher = (msg: ConsoleMessage) => { @@ -19,9 +24,14 @@ base.beforeAll(async () => { return } + fs.mkdirSync(graphDir, { + recursive: true, + }); + electronApp = await electron.launch({ cwd: "./static", args: ["electron.js"], + locale: 'en', }) context = electronApp.context() await context.tracing.start({ screenshots: true, snapshots: true }); @@ -51,6 +61,8 @@ base.beforeAll(async () => { console.log('Page loaded!') await page.screenshot({ path: 'startup.png' }) }) + + await loadLocalGraph(page, graphDir); }) base.beforeEach(async () => { diff --git a/e2e-tests/utils.ts b/e2e-tests/utils.ts index 19e1bb957c..108f4c6592 100644 --- a/e2e-tests/utils.ts +++ b/e2e-tests/utils.ts @@ -33,6 +33,8 @@ export async function createRandomPage(page: Page) { await page.click('text=/.*New page: ".*/') // wait for textarea of first block await page.waitForSelector(':nth-match(textarea, 1)', { state: 'visible' }) + + return randomTitle; } /** @@ -101,6 +103,48 @@ export async function escapeToBlockEditor(page: Page): Promise { await page.waitForTimeout(500) } +export async function setMockedOpenDirPath( + page: Page, + path?: string +): Promise { + // set next open directory + await page.evaluate( + ([path]) => { + Object.assign(window, { + __MOCKED_OPEN_DIR_PATH__: path, + }) + }, + [path] + ) +} + +export async function loadLocalGraph(page: Page, path?: string): Promise { + const hasOpenButton = await page.$('#head >> .button >> text=Open') + await setMockedOpenDirPath(page, path); + if (hasOpenButton) { + await page.click('#head >> .button >> text=Open') + } else { + if (!(await page.$('.ls-left-sidebar-open'))) { + await page.click('.cp__header-left-menu.button') + } + await page.click('#left-sidebar >> #repo-switch') + await page.click('text=Add new graph') + await page.waitForSelector('h1:has-text("Open a local directory")') + await page.click('h1:has-text("Open a local directory")') + } + + setMockedOpenDirPath(page, ''); // reset it + + await page.waitForSelector(':has-text("Parsing files")', { + state: 'hidden', + timeout: 1000 * 60 * 5, + }) + + await page.waitForFunction('window.document.title != "Loading"') + + console.log('Graph loaded for ' + path) +} + export async function activateNewPage(page: Page) { await page.click('.ls-block >> nth=0') await page.waitForTimeout(500) diff --git a/resources/js/preload.js b/resources/js/preload.js index 5784c26f8e..7dc472f760 100644 --- a/resources/js/preload.js +++ b/resources/js/preload.js @@ -83,13 +83,14 @@ contextBridge.exposeInMainWorld('apis', { * * @param {string} html html file with embedded state */ - exportPublishAssets (html, customCSSPath, repoPath, assetFilenames) { + exportPublishAssets (html, customCSSPath, repoPath, assetFilenames, outputDir) { ipcRenderer.invoke( 'export-publish-assets', html, customCSSPath, repoPath, - assetFilenames + assetFilenames, + outputDir ) }, diff --git a/src/electron/electron/core.cljs b/src/electron/electron/core.cljs index e1639e5083..db43d700a2 100644 --- a/src/electron/electron/core.cljs +++ b/src/electron/electron/core.cljs @@ -68,12 +68,10 @@ (.unregisterProtocol protocol LSP_SCHEME) (.unregisterProtocol protocol "assets"))) -(defn- handle-export-publish-assets [_event html custom-css-path repo-path asset-filenames] +(defn- handle-export-publish-assets [_event html custom-css-path repo-path asset-filenames output-path] (p/let [app-path (. app getAppPath) asset-filenames (js->clj asset-filenames) - result (. dialog showOpenDialog (clj->js {:properties ["openDirectory" "createDirectory" "promptToCreate", "multiSelections"]})) - result (get (js->clj result) "filePaths") - root-dir (first result)] + root-dir (or output-path (handler/open-dir-dialog))] (when root-dir (let [static-dir (path/join root-dir "static") assets-from-dir (path/join repo-path "assets") diff --git a/src/electron/electron/handler.cljs b/src/electron/electron/handler.cljs index 4fd239694e..1a791a6221 100644 --- a/src/electron/electron/handler.cljs +++ b/src/electron/electron/handler.cljs @@ -139,11 +139,14 @@ (remove nil?))] (vec (cons {:path (utils/fix-win-path! path)} result)))) -(defmethod handle :openDir [^js window _messages] +(defn open-dir-dialog [] (p/let [result (.showOpenDialog dialog (bean/->js {:properties ["openDirectory" "createDirectory" "promptToCreate"]})) - result (get (js->clj result) "filePaths") - path (first result)] + result (get (js->clj result) "filePaths")] + (p/resolved (first result)))) + +(defmethod handle :openDir [^js window _messages] + (p/let [path (open-dir-dialog)] (if path (p/resolved (bean/->js (get-files path))) (p/rejected (js/Error "path empty"))))) @@ -269,10 +272,7 @@ (watcher/watch-dir! window dir))) (defmethod handle :openDialog [^js window messages] - (p/let [result (.showOpenDialog dialog (bean/->js - {:properties ["openDirectory"]})) - result (get (js->clj result) "filePaths")] - (p/resolved (first result)))) + (open-dir-dialog)) (defmethod handle :getLogseqDotDirRoot [] (utils/get-ls-dotdir-root)) diff --git a/src/main/frontend/fs/node.cljs b/src/main/frontend/fs/node.cljs index 0adc658693..fda487ce83 100644 --- a/src/main/frontend/fs/node.cljs +++ b/src/main/frontend/fs/node.cljs @@ -92,6 +92,13 @@ (error-handler error) (log/error :write-file-failed error))))))))) +(defn- open-dir [] + (p/let [dir-path (util/mocked-open-dir-path) + result (if dir-path + (ipc/ipc "getFiles" dir-path) + (ipc/ipc "openDir" {}))] + result)) + (defrecord Node [] protocol/Fs (mkdir! [this dir] @@ -124,7 +131,7 @@ (let [path (concat-path dir path)] (ipc/ipc "stat" path))) (open-dir [this ok-handler] - (ipc/ipc "openDir" {})) + (open-dir)) (get-files [this path-or-handle ok-handler] (ipc/ipc "getFiles" path-or-handle)) (watch-dir! [this dir] diff --git a/src/main/frontend/handler/export.cljs b/src/main/frontend/handler/export.cljs index 67a58b55ba..ed5067e426 100644 --- a/src/main/frontend/handler/export.cljs +++ b/src/main/frontend/handler/export.cljs @@ -106,7 +106,12 @@ html-str (str "data:text/html;charset=UTF-8," (js/encodeURIComponent raw-html-str))] (if (util/electron?) - (js/window.apis.exportPublishAssets raw-html-str (config/get-custom-css-path) (config/get-repo-dir repo) (clj->js asset-filenames)) + (js/window.apis.exportPublishAssets + raw-html-str + (config/get-custom-css-path) + (config/get-repo-dir repo) + (clj->js asset-filenames) + (util/mocked-open-dir-path)) (when-let [anchor (gdom/getElement "download-as-html")] (.setAttribute anchor "href" html-str) diff --git a/src/main/frontend/util.cljc b/src/main/frontend/util.cljc index 6e3d984eee..c477ee3e3d 100644 --- a/src/main/frontend/util.cljc +++ b/src/main/frontend/util.cljc @@ -71,6 +71,12 @@ (let [ua (string/lower-case js/navigator.userAgent)] (string/includes? ua " electron"))))) +#?(:cljs + (defn mocked-open-dir-path + "Mocked open DIR path for by-passing open dir in electron during testing. Nil if not given" + [] + (when (electron?) (. js/window -__MOCKED_OPEN_DIR_PATH__)))) + #?(:cljs (def nfs? (and (not (electron?)) (not (is-native-platform?)))))