maybe?
Some checks failed
Playwright Tests / test (push) Failing after 1m4s

This commit is contained in:
parent b515ddfafe
commit 7d99907277
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
12 changed files with 942 additions and 133 deletions

BIN
.yarn/install-state.gz vendored

Binary file not shown.

@ -5,6 +5,10 @@
"@codemirror/language": "https://github.com/lishid/cm-language",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"asar": "^3.2.0",
"playwright": "^1.48.1",
"tmp": "^0.2.3",
"electron": "^33.0.2",
"typescript": "^5.6.3"
},
"version": "",
@ -14,8 +18,8 @@
"default": "./lib/index.js"
},
"./utils": {
"types": "./lib/utils.d.ts",
"default": "./lib/utils.js"
"types": "./lib/util.d.ts",
"default": "./lib/util.js"
},
"./fixture": {
"types": "./lib/fixtures.d.ts",
@ -31,8 +35,8 @@
},
"devDependencies": {
"@playwright/test": "^1.48.1",
"@types/tmp": "^0",
"obsidian": "latest",
"playwright": "^1.48.1",
"vitest": "^2.1.3"
},
"type": "module"

@ -1,10 +1,11 @@
import { ElectronApplication, JSHandle, Page } from "playwright";
import { ObsidianTestingConfig } from "./index.js";
import { App } from "obsidian";
import { ElectronApplication, Page } from "playwright";
import { ObsidianTestingConfig } from "./index";
// import { getFile } from "./util.js";
export interface ObsidianTestFixtures {
electronApp: ElectronApplication;
page: Page;
app: App;
obsidian: ObsidianTestingConfig;
appHandle: JSHandle<App>;
}

@ -1,10 +1,13 @@
import { App } from "obsidian";
import { test as base } from "@playwright/test";
import { _electron as electron } from "playwright";
import { Fixtures } from "@playwright/test";
import { execSync } from "child_process";
import path from "path";
import { ObsidianTestFixtures } from "./fixtures";
import { extractAll } from "asar";
import { ObsidianTestFixtures } from "./fixtures.js";
import tmp from "tmp";
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
import { getApp, waitForIndexingComplete } from "./util.js";
export interface ObsidianTestingConfig {
vault?: string;
@ -12,41 +15,79 @@ export interface ObsidianTestingConfig {
export function getExe(): string {
if (process.platform == "win32") {
return path.join(process.env.LOCALAPPDATA!, "Obsidian", "Obsidian.exe");
return path.join(
process.env.LOCALAPPDATA!,
"Obsidian",
"Resources",
"obsidian.asar"
);
}
if (process.platform == "darwin") {
throw new Error("use a non-toy operating system, dumbass");
}
return execSync("command -v obsidian").toString();
return execSync("/usr/lib/obsidian/obsidian.asar").toString();
}
const obsidianTestFixtures: Fixtures<
ObsidianTestFixtures
> = {
const obsidianTestFixtures: Fixtures<ObsidianTestFixtures> = {
electronApp: [
async ({ obsidian: {vault} }, run) => {
async ({ obsidian: { vault } }, run) => {
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = "true";
let mainFile = path.join(tmp.tmpdir, "obsidian");
let electronFile = path.join(tmp.tmpdir, "electron");
const packageJsonFile = path.join(tmp.tmpdir, "obsidian", "package.json");
console.log("hello", getExe(), vault, mainFile);
try {
rmSync(mainFile, { recursive: true });
rmSync(electronFile, { recursive: true });
mkdirSync(electronFile);
mkdirSync(mainFile);
} catch (e) {}
extractAll(getExe(), mainFile);
extractAll(path.join(path.dirname(getExe()), "app.asar"), electronFile);
renameSync(
path.join(mainFile, "main.js"),
path.join(mainFile, "index.js")
);
const packageJson = JSON.parse(readFileSync(packageJsonFile).toString());
// packageJson.main = "app.js";
writeFileSync(packageJsonFile, JSON.stringify(packageJson));
const electronApp = await electron.launch({
executablePath: getExe(),
args: [!!vault && `obsidian://open?vault=${encodeURI(vault)}`].filter(a => !!a) as string[],
timeout: 10000,
cwd: mainFile,
args: [
path.join(path.dirname(getExe()), "app.asar"),
!!vault && `obsidian://open?vault=${encodeURI(vault)}`,
].filter((a) => !!a) as string[],
});
electronApp.waitForEvent("window");
electronApp.on("console", async (msg) => {
console.log(
...(await Promise.all(msg.args().map((a) => a.jsonValue())))
);
});
await run(electronApp);
await electronApp.close();
},
{ auto: true },
{ timeout: 60000 },
],
page: [
async ({ electronApp }, run) => {
const page = await electronApp.firstWindow();
await page.waitForEvent("load")
await page.waitForLoadState("domcontentloaded");
await waitForIndexingComplete(await getApp(page));
page.on("console", async (msg) => {
console.log(
...(await Promise.all(msg.args().map((a) => a.jsonValue())))
);
});
await run(page);
await electronApp.close();
},
{}
{ timeout: 30000 },
],
app: [async ({ page }, run) => {
const app: App = await page.evaluate("window.app");
await run(app);
}, {auto: true}],
obsidian: [{}, {option: true}]
obsidian: [{}, { option: true }],
};
// @ts-ignore some error about a string type now having `undefined` as part of it's union
export const test = base.extend<ObsidianTestFixtures>(obsidianTestFixtures);

@ -1,41 +1,45 @@
import { App, TFile } from "obsidian";
import { expect } from "vitest";
import { JSHandle, Page } from "playwright";
import { expect } from "@playwright/test";
// type TestArgs = Parameters<Parameters<typeof test>[2]>[0];
export async function assertFileEquals(
app: App,
page: Page,
path: string,
expectedContent: string,
cached: boolean = true
) {
const fileContent = await readFile(app, path, cached);
const fileContent = await readFile(page, path, cached);
expect(fileContent).toEqual(normalizeEOL(expectedContent));
}
export async function assertLineEquals(
app: App,
page: Page,
path: string,
lineNumber: number,
expectedContent: string,
cached: boolean = true
) {
const fileContent = await readFile(app, path, cached);
const fileContent = await readFile(page, path, cached);
expect(fileContent.split("\n")[lineNumber]).toEqual(
normalizeEOL(expectedContent)
);
}
export async function getApp(page: Page): Promise<JSHandle<App>> {
return await page.evaluateHandle("window.app");
}
export async function assertLinesEqual(
app: App,
page: Page,
filePath: string,
start: number,
end: number,
expected: string,
cached: boolean = true
) {
const fileContent = await readFile(app, filePath, cached);
const fileContent = await readFile(page, filePath, cached);
const lines = fileContent.split("\n").slice(start, end);
const expectedLines = normalizeEOL(expected).split("\n");
expect(lines.every((l, i) => l == expectedLines[i])).toEqual(true);
@ -53,10 +57,45 @@ function normalizeEOL(str: string): string {
return str.split(/\r\n|\r|\n/).join("\n");
}
async function readFile(app: App, path: string, cached: boolean = true): Promise<string> {
const file = getFile(app, path);
export async function readFile(
app: Page,
path: string,
cached: boolean = true
): Promise<string> {
return normalizeEOL(
await (cached ? app.vault.cachedRead(file) : app.vault.read(file))
await doWithApp(app, (a) => {
const file = getFile(a, path);
return cached ? a.vault.cachedRead(file) : a.vault.read(file);
})
);
}
export async function doWithApp<T = unknown>(
page: Page,
callback: (a: App) => T | Promise<T>
): Promise<T> {
const cbStr = callback.toString();
await page.exposeFunction("__callback", callback)
return await page.evaluate<T, string>(async (cb) => {
console.log("bye", Object.keys(app));
const func = new Function(`return (${cb})(window.app)`)
return await func();
}, cbStr);
}
export function waitForIndexingComplete(appHandle: JSHandle<App>) {
return appHandle.evaluate(() => {
return new Promise(res2 => {
// let resolved = false;
app.metadataCache.on("resolved", () => {
res2(null);
// resolved = true;
});
// setTimeout(() => !resolved && rej2("timeout"), 10000);
});
});
}
export const pageUtils = {
getFile,
}

@ -2,12 +2,13 @@
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"moduleResolution": "Node",
"lib": [
"es2015",
"DOM",
"ESNext.Disposable"
],
"outDir": "lib",
"baseUrl": ".",
"strict": true,

@ -1,5 +1,6 @@
import {App} from "obsidian";
declare global {
// const app: App;
var app: App;
var __callback: <T>(app: App) => T;
}
export {}

@ -1,9 +1,22 @@
import { expect } from '@playwright/test';
import {test} from "obsidian-testing-framework"
import {doWithApp, getApp} from "obsidian-testing-framework/utils";
test('something', async ({ page }) => {
expect(page).toHaveURL(/obsidian\.md/i);
console.log(page.url());
expect(/obsidian\.md/i.test(page.url())).toBeTruthy()
});
test("idk", async({app}) => {
let thing = app.metadataCache.getFirstLinkpathDest("Welcome", ".");
expect(thing?.basename).toEqual("Welcome");
test("idk", async({page}) => {
console.log("idk")
let what = await doWithApp(page,async (app) => {
console.log("hi", Object.keys(app), (app.metadataCache));
let thing = app.metadataCache.getFirstLinkpathDest("Welcome", "/");
console.log("THING", thing);
await new Promise(res => setTimeout(res, 5000))
console.log(thing?.path);
const what = {...thing};
delete what.parent;
delete what.vault;
return what;
});
expect(what.basename).toEqual("Welcome")
})

@ -20,9 +20,9 @@ export default defineConfig<ObsidianTestFixtures>({
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
retries: 1,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
workers: 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
@ -32,46 +32,14 @@ export default defineConfig<ObsidianTestFixtures>({
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
obsidian: {
vault: "test-framework-tester"
}
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
// webServer: {

@ -18,5 +18,5 @@
"linkStrength": 1,
"linkDistance": 250,
"scale": 1,
"close": true
"close": false
}

@ -1,40 +1,20 @@
{
"main": {
"id": "c2fe4c323d36fc5e",
"id": "930871bd163b9a7a",
"type": "split",
"children": [
{
"id": "8298a75d0a6318ad",
"id": "634dfa4a86e61f7f",
"type": "tabs",
"children": [
{
"id": "c166e51cf23ccba4",
"id": "b123fea9f84365d8",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Welcome.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Welcome"
}
}
]
},
{
"id": "ba8373549c03c775",
"type": "tabs",
"children": [
{
"id": "95e0d337b44eab37",
"type": "leaf",
"state": {
"type": "graph",
"type": "empty",
"state": {},
"icon": "lucide-git-fork",
"title": "Graph view"
"icon": "lucide-file",
"title": "New tab"
}
}
]
@ -43,15 +23,15 @@
"direction": "vertical"
},
"left": {
"id": "15ee0403a7a614b4",
"id": "a21ebe5947a5c71f",
"type": "split",
"children": [
{
"id": "f297c8bc39873aa8",
"id": "32175daed5963aa7",
"type": "tabs",
"children": [
{
"id": "cee48933474ae820",
"id": "868b1c060db3a110",
"type": "leaf",
"state": {
"type": "file-explorer",
@ -63,7 +43,7 @@
}
},
{
"id": "a5eb514f5fbe0a9d",
"id": "4bc75e71b51e11b0",
"type": "leaf",
"state": {
"type": "search",
@ -80,7 +60,7 @@
}
},
{
"id": "2ea1b4740307baf6",
"id": "6d851af11dfb13da",
"type": "leaf",
"state": {
"type": "bookmarks",
@ -96,20 +76,19 @@
"width": 300
},
"right": {
"id": "9da40e5b7fceeacd",
"id": "5d6a3e51ae6c758f",
"type": "split",
"children": [
{
"id": "2e127fb9abc8dd11",
"id": "1c37035be69547e5",
"type": "tabs",
"children": [
{
"id": "21b5909f77e5cae0",
"id": "33ec4bd3963497ab",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "Welcome.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
@ -119,25 +98,24 @@
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks for Welcome"
"title": "Backlinks"
}
},
{
"id": "bc9d35775b8807b0",
"id": "2487192d0b99fdd8",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"file": "Welcome.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links from Welcome"
"title": "Outgoing links"
}
},
{
"id": "982543d44de11473",
"id": "fec498f9a6d0f797",
"type": "leaf",
"state": {
"type": "tag",
@ -150,15 +128,13 @@
}
},
{
"id": "52f3666280022d63",
"id": "5e98b7f33c5bb964",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "Welcome.md"
},
"state": {},
"icon": "lucide-list",
"title": "Outline of Welcome"
"title": "Outline"
}
}
]
@ -178,8 +154,6 @@
"command-palette:Open command palette": false
}
},
"active": "c166e51cf23ccba4",
"lastOpenFiles": [
"Welcome.md"
]
"active": "b123fea9f84365d8",
"lastOpenFiles": []
}

777
yarn.lock

File diff suppressed because it is too large Load Diff