This commit is contained in:
parent fc5a65e9f7
commit 8bd31c526f
Signed by: tablet
GPG Key ID: 924A5F6AF051E87C
27 changed files with 2739 additions and 2636 deletions

2
.gitignore vendored

@ -1,2 +1,2 @@
node_modules node_modules
lib lib*

BIN
.yarn/install-state.gz vendored

Binary file not shown.

@ -1,47 +1,8 @@
{ {
"name": "obsidian-testing-framework", "name": "obsidian-testing-framework-parent",
"private": true,
"packageManager": "yarn@4.5.1", "packageManager": "yarn@4.5.1",
"dependencies": {
"@codemirror/language": "https://github.com/lishid/cm-language",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"typescript": "^5.6.3"
},
"version": "",
"files": [
"./bin/*",
"./lib/*"
],
"exports": {
".": {
"default": "./lib/index.js",
"types": "./lib/index.d.ts"
},
"./utils": {
"default": "./lib/utils.js",
"types": "./lib/utils.d.ts"
},
"./fixture": {
"default": "./lib/fixtures.js",
"types": "./lib/fixtures.d.ts"
}
},
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"scripts": {
"build": "tsc",
"lint": "tslint -c tslint.json src/**/*.ts",
"prepublish": "npm run build"
},
"devDependencies": {
"@playwright/test": "^1.48.1",
"@types/node": "^22.7.8",
"obsidian": "latest",
"playwright": "^1.48.1",
"vitest": "^2.1.3"
},
"workspaces": [ "workspaces": [
"./*" "./packages/*"
], ]
"type": "module"
} }

@ -0,0 +1,39 @@
{
"name": "obsidian-testing-framework",
"packageManager": "yarn@4.5.1",
"dependencies": {
"@codemirror/language": "https://github.com/lishid/cm-language",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.1",
"typescript": "^5.6.3"
},
"version": "",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./utils": {
"types": "./lib/utils.d.ts",
"default": "./lib/utils.js"
},
"./fixture": {
"types": "./lib/fixtures.d.ts",
"default": "./lib/fixtures.js"
}
},
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"scripts": {
"build": "tsc",
"lint": "tslint -c tslint.json src/**/*.ts",
"prepublish": "npm run build"
},
"devDependencies": {
"@playwright/test": "^1.48.1",
"obsidian": "latest",
"playwright": "^1.48.1",
"vitest": "^2.1.3"
},
"type": "module"
}

@ -1,6 +1,6 @@
import { App } from "obsidian"; import { App } from "obsidian";
import { ElectronApplication, Page } from "playwright"; import { ElectronApplication, Page } from "playwright";
import { ObsidianTestingConfig } from "src"; import { ObsidianTestingConfig } from "./index";
export interface ObsidianTestFixtures { export interface ObsidianTestFixtures {
electronApp: ElectronApplication; electronApp: ElectronApplication;

@ -43,7 +43,7 @@ const obsidianTestFixtures: Fixtures<
{ auto: true }, { auto: true },
], ],
app: [async ({ page }, run) => { app: [async ({ page }, run) => {
const app = await page.evaluate<App>("window.app"); const app: App = await page.evaluate("window.app");
await run(app); await run(app);
}, {auto: true}], }, {auto: true}],
obsidian: [{}, {option: true}] obsidian: [{}, {option: true}]

@ -0,0 +1,114 @@
import {
_electron,
_electron as electron,
ElectronApplication,
Page,
} from "playwright";
import {expect} from "vitest"
import { App, TFile, Vault } from "obsidian";
import { execSync } from "child_process";
import path from "path";
import { EOL } from "os";
type RawOptions = NonNullable<Parameters<typeof _electron.launch>[0]>;
export type TestOptions = Omit<RawOptions, "executablePath"> & {
vault: string;
};
export class ObsidianTester {
#loadPromise: Promise<void>;
public electronApp: ElectronApplication | null = null;
public page: Page;
public app: App;
constructor(options: Partial<TestOptions & { vault: string }>) {
const args = [...(options.args || [])];
if (options.vault)
args.push(`obsidian://open?vault=${encodeURI(options.vault)}`);
this.#loadPromise = new Promise((res, rej) => {
electron
.launch({
...options,
args,
executablePath: ObsidianTester.getExe(),
})
.then((v) => {
this.postInit(v).then(() => {
res();
});
})
.catch((e) => rej(e));
});
}
public get vault(): Vault {
return this.app.vault
}
public async doWithApp(
callback: (app: App) => Promise<unknown>
): Promise<unknown> {
await this.#loadPromise;
return await callback(this.app);
}
public async doWithVault(
callback: (vault: Vault) => Promise<unknown>
): Promise<unknown> {
await this.#loadPromise;
return await callback(this.app.vault);
}
public async assertFileEquals(path: string, expectedContent: string, cached: boolean = true) {
await this.#loadPromise;
const fileContent = await this.readFile(path, cached);
expect(fileContent).toEqual(this.normalizeEOL(expectedContent));
}
public async assertLineEquals(path: string, lineNumber: number, expectedContent: string, cached: boolean = true) {
await this.#loadPromise;
const fileContent = await this.readFile(path, cached);
expect(fileContent.split("\n")[lineNumber]).toEqual(this.normalizeEOL(expectedContent));
}
public async assertLinesEqual(filePath: string, start: number, end: number, expected: string, cached: boolean = true) {
await this.#loadPromise;
const fileContent = await this.readFile(filePath, cached);
const lines = fileContent.split("\n").slice(start, end);
const expectedLines = this.normalizeEOL(expected).split("\n");
expect(lines.every((l, i) => l == expectedLines[i])).toEqual(true);
}
public getFile(file: string): TFile {
let f = this.app.vault.getFileByPath(file);
if(!f) {
throw new Error("File does not exist in vault.");
}
return f;
}
normalizeEOL(str: string): string {
return str.split(/\r\n|\r|\n/).join("\n");
}
async readFile(path: string, cached: boolean = true): Promise<string> {
await this.#loadPromise;
const file = this.getFile(path);
return this.normalizeEOL(await (cached ? this.app.vault.cachedRead(file) : this.app.vault.read(file)));
}
private async postInit(electronApp: ElectronApplication) {
this.electronApp = electronApp;
this.page = await this.electronApp.firstWindow();
this.app = await this.page.evaluate<App>("window.app");
}
public static getExe(): string {
if (process.platform == "win32") {
return path.join(process.env.LOCALAPPDATA!, "Obsidian", "Obsidian.exe");
}
if (process.platform == "darwin") {
throw new Error("use a non-toy operating system, dumbass");
}
return execSync("command -v obsidian").toString();
}
}

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ES6",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"lib": [ "lib": [
@ -8,7 +8,7 @@
"DOM", "DOM",
"ES2018" "ES2018"
], ],
"outDir": "lib", "outDir": "packages/obsidian-testing-framework/lib",
"baseUrl": ".", "baseUrl": ".",
"strict": true, "strict": true,
"alwaysStrict": true, "alwaysStrict": true,
@ -37,5 +37,5 @@
"typings/**/*", "typings/**/*",
"src/**/*" "src/**/*"
], ],
"exclude": ["test-project/**/*"] "exclude": ["packages/test-project/**/*.ts"]
} }

@ -1,5 +1,5 @@
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
import {test} from "obsidian-testing-framework" import {test} from "../../lib.not"
test('something', async ({ page }) => { test('something', async ({ page }) => {
expect(page).toHaveURL(/obsidian\.md/i); expect(page).toHaveURL(/obsidian\.md/i);
}); });

@ -13,7 +13,7 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"obsidian-testing-framework": "workspace:^" "obsidian-testing-framework": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.48.1", "@playwright/test": "^1.48.1",

@ -1,5 +1,5 @@
import { defineConfig, devices } from '@playwright/test'; import { defineConfig, devices } from '@playwright/test';
import { ObsidianTestingConfig } from 'obsidian-testing-framework'; import * as fix from "obsidian-testing-framework/fixture";
/** /**
* Read environment variables from file. * Read environment variables from file.

5157
yarn.lock

File diff suppressed because it is too large Load Diff