forked from logseq/logseq
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(e2e): fs testings - file create, rename, unlink
- Loading branch information
Showing
5 changed files
with
237 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import fsp from 'fs/promises'; | ||
import path from 'path'; | ||
import { expect } from '@playwright/test' | ||
import { test } from './fixtures'; | ||
import { searchPage, captureConsoleWithPrefix, closeSearchBox } from './utils'; | ||
|
||
test('create file on disk then delete', async ({ page, block, graphDir }) => { | ||
// Since have to wait for file watchers | ||
test.slow(); | ||
|
||
// Special page names: namespaced, chars require escaping, chars require unicode normalization, "%" chars, "%" with 2 hexdigests | ||
const testCases = [ | ||
{pageTitle: "User:John", fileName: "User:John"}, | ||
// invalid url decode escaping as %ff is not parsable but match the common URL encode regex | ||
{pageTitle: ":#%ff", fileName: ":#%ff"}, | ||
// valid url decode escaping | ||
{pageTitle: ":#%23", fileName: ":#%2523"}, | ||
{pageTitle: "@!#%", fileName: "@!#%"}, | ||
{pageTitle: "aàáâ", fileName: "aàáâ"}, | ||
{pageTitle: ":#%gggg", fileName: ":#%gggg"} | ||
] | ||
|
||
function getFullPath(fileName: string) { | ||
return path.join(graphDir, "pages", `${fileName}.md`); | ||
} | ||
|
||
// Test putting files on disk | ||
for (const {pageTitle, fileName} of testCases) { | ||
// Put the file on disk | ||
const filePath = getFullPath(fileName); | ||
await fsp.writeFile(filePath, `- content for ${pageTitle}`); | ||
await captureConsoleWithPrefix(page, "Parsing finished:", 5000) | ||
|
||
// Check that the page is created | ||
const results = await searchPage(page, pageTitle); | ||
const firstResultRow = await results[0].innerText() | ||
expect(firstResultRow).toContain(pageTitle); | ||
expect(firstResultRow).not.toContain("New"); | ||
await closeSearchBox(page); | ||
} | ||
|
||
// Test removing files on disk | ||
for (const {pageTitle, fileName} of testCases) { | ||
// Remove the file on disk | ||
const filePath = getFullPath(fileName); | ||
await fsp.unlink(filePath); | ||
await captureConsoleWithPrefix(page, "Delete page:", 5000); | ||
|
||
// Test that the page is deleted | ||
const results = await searchPage(page, pageTitle); | ||
const firstResultRow = await results[0].innerText() | ||
expect(firstResultRow).toContain("New"); | ||
await closeSearchBox(page); | ||
} | ||
}); | ||
|
||
test("Rename file on disk", async ({ page, block, graphDir }) => { | ||
// Since have to wait for file watchers | ||
test.slow(); | ||
|
||
const testCases = [ | ||
// Normal -> NameSpace | ||
{pageTitle: "User:John", fileName: "User:John", | ||
newPageTitle: "User/John", newFileName: "User___John"}, | ||
// NameSpace -> Normal | ||
{pageTitle: ":#/%23", fileName: ":#___%2523", | ||
newPageTitle: ":#%23", newFileName: ":#%2523"} | ||
] | ||
|
||
function getFullPath(fileName: string) { | ||
return path.join(graphDir, "pages", `${fileName}.md`); | ||
} | ||
|
||
// Test putting files on disk | ||
for (const {pageTitle, fileName} of testCases) { | ||
// Put the file on disk | ||
const filePath = getFullPath(fileName); | ||
await fsp.writeFile(filePath, `- content for ${pageTitle}`); | ||
await captureConsoleWithPrefix(page, "Parsing finished:", 5000) | ||
|
||
// Check that the page is created | ||
const results = await searchPage(page, pageTitle); | ||
const firstResultRow = await results[0].innerText() | ||
expect(firstResultRow).toContain(pageTitle); | ||
expect(firstResultRow).not.toContain("New"); | ||
await closeSearchBox(page); | ||
} | ||
|
||
// Test renaming files on disk | ||
for (const {pageTitle, fileName, newPageTitle, newFileName} of testCases) { | ||
// Rename the file on disk | ||
const filePath = getFullPath(fileName); | ||
const newFilePath = getFullPath(newFileName); | ||
await fsp.rename(filePath, newFilePath); | ||
await captureConsoleWithPrefix(page, "Parsing finished:", 5000); | ||
|
||
// Test that the page is renamed | ||
const results = await searchPage(page, newPageTitle); | ||
const firstResultRow = await results[0].innerText() | ||
expect(firstResultRow).toContain(newPageTitle); | ||
expect(firstResultRow).not.toContain(pageTitle); | ||
expect(firstResultRow).not.toContain("New"); | ||
await closeSearchBox(page); | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// This file is used to store basic functions that are used in other utils | ||
// Should have no dependency on other utils | ||
|
||
import * as process from 'process' | ||
|
||
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 const modKey = IsMac ? 'Meta' : 'Control' | ||
|
||
export function randomString(length: number) { | ||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
|
||
let result = ''; | ||
const charactersLength = characters.length; | ||
for (let i = 0; i < length; i++) { | ||
result += characters.charAt(Math.floor(Math.random() * charactersLength)); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
export function randomLowerString(length: number) { | ||
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; | ||
|
||
let result = ''; | ||
const charactersLength = characters.length; | ||
for (let i = 0; i < length; i++) { | ||
result += characters.charAt(Math.floor(Math.random() * charactersLength)); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
export function randomInt(min: number, max: number): number { | ||
return Math.floor(Math.random() * (max - min + 1) + min) | ||
} | ||
|
||
export function randomBoolean(): boolean { | ||
return Math.random() < 0.5; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { Page, Locator, ElementHandle } from '@playwright/test' | ||
import { randomString } from './basic' | ||
|
||
export async function createRandomPage(page: Page) { | ||
const randomTitle = randomString(20) | ||
|
||
// Click #search-button | ||
await page.click('#search-button') | ||
// Fill [placeholder="Search or create page"] | ||
await page.fill('[placeholder="Search or create page"]', randomTitle) | ||
// Click text=/.*New page: "new page".*/ | ||
await page.click('text=/.*New page: ".*/') | ||
// Wait for h1 to be from our new page | ||
await page.waitForSelector(`h1 >> text="${randomTitle}"`, { state: 'visible' }) | ||
// wait for textarea of first block | ||
await page.waitForSelector('textarea >> nth=0', { state: 'visible' }) | ||
|
||
return randomTitle; | ||
} | ||
|
||
export async function createPage(page: Page, page_name: string) {// Click #search-button | ||
await page.click('#search-button') | ||
// Fill [placeholder="Search or create page"] | ||
await page.fill('[placeholder="Search or create page"]', page_name) | ||
// Click text=/.*New page: "new page".*/ | ||
await page.click('text=/.*New page: ".*/') | ||
// wait for textarea of first block | ||
await page.waitForSelector('textarea >> nth=0', { state: 'visible' }) | ||
|
||
return page_name; | ||
} | ||
|
||
export async function searchAndJumpToPage(page: Page, pageTitle: string) { | ||
await page.click('#search-button') | ||
await page.type('[placeholder="Search or create page"]', pageTitle) | ||
await page.waitForSelector(`[data-page-ref="${pageTitle}"]`, { state: 'visible' }) | ||
page.click(`[data-page-ref="${pageTitle}"]`) | ||
await page.waitForNavigation() | ||
return pageTitle; | ||
} | ||
|
||
/** | ||
* type a search query into the search box | ||
* stop at the point where search box shows up | ||
* | ||
* @param page the pw page object | ||
* @param query the search query to type into the search box | ||
* @returns the HTML element for the search results ui | ||
*/ | ||
export async function searchPage(page: Page, query: string): Promise<ElementHandle<SVGElement | HTMLElement>[]>{ | ||
await page.click('#search-button') | ||
await page.waitForSelector('[placeholder="Search or create page"]') | ||
await page.type('[placeholder="Search or create page"]', query, { delay: 10 }) | ||
await page.waitForTimeout(2000) // wait longer for search contents to render | ||
|
||
return page.$$('#ui__ac-inner>div'); | ||
} | ||
|
||
export async function closeSearchBox(page: Page): Promise<void> { | ||
await page.keyboard.press("Escape") // escape (potential) search box typing | ||
await page.waitForTimeout(500) | ||
await page.keyboard.press("Escape") // escape modal | ||
} |
Oops, something went wrong.