1
0
Эх сурвалжийг харах

test(e2e): emulate copy-to-clipboard when no webAPI permission

Junyi Du 3 жил өмнө
parent
commit
472f548d50

+ 46 - 18
e2e-tests/logseq_url.spec.ts

@@ -1,10 +1,16 @@
 import { expect } from '@playwright/test'
 import { test } from './fixtures'
-import { createRandomPage, lastBlock } from './utils'
+import { createRandomPage, lastBlock, captureConsoleWithPrefix, IsMac, IsLinux, queryPermission, doesClipboardItemExists } from './utils'
 
 test(
   "Logseq URLs (same graph)",
   async ({ page, block }) => {
+    let paste_key = IsMac ? 'Meta+v' : 'Control+v'
+    let IsWebAPIClipboardSupported = (
+        // @ts-ignore "clipboard-write" is not included in TS's type definition for permissionName
+        await queryPermission(page, "clipboard-write") && 
+        await doesClipboardItemExists(page)
+    )
     // create a page with identify block
     let identify_text = "URL redirect target"
     let page_title = await createRandomPage(page)
@@ -12,29 +18,51 @@ test(
 
     // paste current page's URL to another page, then redirect throught the URL
     await page.click('.ui__dropdown-trigger')
-    await page.locator("text=Copy page URL").click()
-    await createRandomPage(page)
-    await block.mustFill("") // to focus the editor
-    await page.keyboard.press("Meta+v")
+    if (!IsWebAPIClipboardSupported){
+        let promise_capture = captureConsoleWithPrefix(page, "Copy without `clipboard-write` permission:")
+        await page.locator("text=Copy page URL").click()
+        let copied_text = await promise_capture
+        await createRandomPage(page)
+        await block.mustFill(copied_text)
+    } else {
+        await page.locator("text=Copy page URL").click()
+        await createRandomPage(page)
+        await block.mustFill("") // to enter editing mode
+        await page.keyboard.press(paste_key)
+    }
     let cursor_locator = page.locator('textarea >> nth=0')
     expect(await cursor_locator.inputValue()).toContain("page=" + page_title)
     await cursor_locator.press("Enter")
-    await page.locator('a.external-link >> nth=0').click()
-    await page.waitForNavigation()
-    cursor_locator = await lastBlock(page)
-    expect(await cursor_locator.inputValue()).toBe(identify_text)
+    if (!IsLinux) { // FIXME: support Logseq URL on Linux (XDG)
+        page.locator('a.external-link >> nth=0').click()
+        await page.waitForNavigation()
+        await page.waitForTimeout(500)
+        cursor_locator = await lastBlock(page)
+        expect(await cursor_locator.inputValue()).toBe(identify_text)
+    }
 
     // paste the identify block's URL to another page, then redirect throught the URL
     await page.click('span.bullet >> nth=0', { button: "right" })
-    await page.locator("text=Copy block URL").click()
-    await createRandomPage(page)
-    await block.mustFill("") // to focus the editor
-    await page.keyboard.press("Meta+v")
+    if (!IsWebAPIClipboardSupported){
+        let promise_capture = captureConsoleWithPrefix(page, "Copy without `clipboard-write` permission:")
+        await page.locator("text=Copy block URL").click()
+        let copied_text = await promise_capture
+        await createRandomPage(page)
+        await block.mustFill(copied_text)
+    } else {
+        await page.locator("text=Copy block URL").click()
+        await createRandomPage(page)
+        await block.mustFill("") // to enter editing mode
+        await page.keyboard.press(paste_key)
+    }
     cursor_locator = page.locator('textarea >> nth=0')
     expect(await cursor_locator.inputValue()).toContain("block-id=")
     await cursor_locator.press("Enter")
-    await page.locator('a.external-link >> nth=0').click()
-    await page.waitForNavigation()
-    cursor_locator = await lastBlock(page)
-    expect(await cursor_locator.inputValue()).toBe(identify_text)
-  })
+    if (!IsLinux) { // FIXME: support Logseq URL on Linux (XDG)
+        page.locator('a.external-link >> nth=0').click()
+        await page.waitForNavigation()
+        await page.waitForTimeout(500)
+        cursor_locator = await lastBlock(page)
+        expect(await cursor_locator.inputValue()).toBe(identify_text)
+    }
+})

+ 36 - 1
e2e-tests/utils.ts

@@ -1,11 +1,12 @@
 import { Page, Locator } from 'playwright'
-import { expect } from '@playwright/test'
+import { expect, ConsoleMessage } from '@playwright/test'
 import * as process from 'process'
 import { Block } from './types'
 
 export const IsMac = process.platform === 'darwin'
 export const IsLinux = process.platform === 'linux'
 export const IsWindows = process.platform === 'win32'
+export const IsCI = process.env.CI === 'true'
 
 export function randomString(length: number) {
   const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -234,3 +235,37 @@ export function systemModifier(shortcut: string): string {
     return shortcut
   }
 }
+
+export async function captureConsoleWithPrefix(page: Page, prefix: string, timeout: number=3000): Promise<string> {
+  return new Promise((resolve, reject) => {
+    let console_handler = (msg: ConsoleMessage) => {
+      let text = msg.text()
+      if (text.startsWith(prefix)) {
+        page.removeListener('console', console_handler)
+        resolve(text.substring(prefix.length))
+      }
+    }
+    page.on('console', console_handler)
+    setTimeout(reject.bind("timeout"), timeout)
+  })
+}
+
+export async function queryPermission(page: Page, permission: PermissionName): Promise<boolean> {
+  // Check if WebAPI clipboard supported
+  return await page.evaluate(async (eval_permission: PermissionName): Promise<boolean> => {
+    if (typeof navigator.permissions == "undefined")
+        return Promise.resolve(false);
+    return navigator.permissions.query({
+      name: eval_permission 
+    }).then((result: PermissionStatus): boolean => {
+      return (result.state == "granted" || result.state == "prompt")
+   })
+  }, permission)
+}
+
+export async function doesClipboardItemExists(page: Page): Promise<boolean> {
+  // Check if WebAPI clipboard supported
+  return await page.evaluate((): boolean => {
+    return typeof ClipboardItem !== "undefined"
+  })
+}

+ 21 - 17
src/main/frontend/utils.js

@@ -1,6 +1,8 @@
 import path from 'path/path.js'
+
+// TODO split the capacitor abilities to a separate file for capacitor APIs
 import { StatusBar, Style } from '@capacitor/status-bar'
-import { Clipboard } from '@capacitor/clipboard';
+import { Clipboard as CapacitorClipboard } from '@capacitor/clipboard'
 
 if (typeof window === 'undefined') {
   global.window = {}
@@ -242,8 +244,19 @@ export const getClipText = (cb, errorHandler) => {
   })
 }
 
+// TODO split the capacitor clipboard to a separate file for capacitor APIs
 export const writeClipboard = (text, isHtml) => {
-    if (typeof navigator.permissions !== "undefined") {
+    if (typeof navigator.permissions == "undefined") {
+        CapacitorClipboard.write({ string: text });
+        return
+    }
+    navigator.permissions.query({
+        name: "clipboard-write"
+    }).then((result) => {
+        if (typeof ClipboardItem === 'undefined' || (result.state != "granted" && result.state != "prompt")){
+            console.debug("Copy without `clipboard-write` permission:", text)
+            return
+        }
         let blob = new Blob([text], {
             type: ["text/plain"]
         });
@@ -259,21 +272,12 @@ export const writeClipboard = (text, isHtml) => {
                 ["text/html"]: blob
             })];
         }
-        navigator.permissions.query({
-            name: "clipboard-write"
-        }).then((result) => {
-            if (result.state == "granted" || result.state == "prompt") {
-                navigator.clipboard.write(data).then(() => {
-                    /* success */
-                }).catch(e => {
-                    console.log(e, "fail")
-                })
-            }
-        })} else {
-            Clipboard.write({
-                string: text
-            });
-        }
+        navigator.clipboard.write(data).then(() => {
+            /* success */
+        }).catch(e => {
+            console.log(e, "fail")
+        })
+    })
 }
 
 export const toPosixPath = (input) => {