This commit is contained in:
parent
b515ddfafe
commit
7d99907277
BIN
.yarn/install-state.gz
vendored
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": []
|
||||
}
|
Loading…
Reference in New Issue
Block a user