obsidian-e2e 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -8
- package/dist/document-DunL2Moz.mjs +69 -0
- package/dist/document-DunL2Moz.mjs.map +1 -0
- package/dist/index.d.mts +16 -2
- package/dist/index.mjs +3 -2
- package/dist/matchers.d.mts +6 -0
- package/dist/matchers.mjs +30 -2
- package/dist/matchers.mjs.map +1 -1
- package/dist/test-context-BprSx6U1.mjs +1558 -0
- package/dist/test-context-BprSx6U1.mjs.map +1 -0
- package/dist/types-C4cj443K.d.mts +256 -0
- package/dist/vault-lock-CYyOdRP1.d.mts +136 -0
- package/dist/vitest.d.mts +1 -1
- package/dist/vitest.mjs +17 -176
- package/dist/vitest.mjs.map +1 -1
- package/package.json +4 -1
- package/dist/sandbox-Cz3rj_Rn.mjs +0 -728
- package/dist/sandbox-Cz3rj_Rn.mjs.map +0 -1
- package/dist/vault-lock-DarzOEzv.d.mts +0 -242
package/dist/vitest.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as acquireVaultRunLock, b as VaultSeedEntry, c as readVaultRunLockMarker, d as ObsidianFixtures, f as ObsidianTest, g as SharedVaultLockOptions, h as PluginTest, i as VaultRunLockState, l as CreateObsidianTestOptions, n as VaultRunLock, o as clearVaultRunLockMarker, p as PluginFixtures, r as VaultRunLockMetadata, s as inspectVaultRunLock, t as AcquireVaultRunLockOptions, u as CreatePluginTestOptions, y as VaultSeed } from "./vault-lock-CYyOdRP1.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/fixtures/create-obsidian-test.d.ts
|
|
4
4
|
declare function createObsidianTest(options: CreateObsidianTestOptions): ObsidianTest;
|
package/dist/vitest.mjs
CHANGED
|
@@ -1,157 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
3
|
-
import path from "node:path";
|
|
1
|
+
import { a as clearVaultRunLockMarker, d as createVaultApi, f as resolveFilesystemPath, i as acquireVaultRunLock, m as getClientInternals, o as inspectVaultRunLock, r as createBaseFixtures, s as readVaultRunLockMarker } from "./test-context-BprSx6U1.mjs";
|
|
2
|
+
import { t as createNoteDocument } from "./document-DunL2Moz.mjs";
|
|
4
3
|
import { test } from "vite-plus/test";
|
|
5
|
-
//#region src/fixtures/failure-artifacts.ts
|
|
6
|
-
const DEFAULT_ARTIFACTS_DIR = ".obsidian-e2e-artifacts";
|
|
7
|
-
function getFailureArtifactConfig(options) {
|
|
8
|
-
if (!options.captureOnFailure) return {
|
|
9
|
-
artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_ARTIFACTS_DIR),
|
|
10
|
-
capture: {
|
|
11
|
-
activeFile: true,
|
|
12
|
-
dom: true,
|
|
13
|
-
editorText: true,
|
|
14
|
-
screenshot: true,
|
|
15
|
-
tabs: true,
|
|
16
|
-
workspace: true
|
|
17
|
-
},
|
|
18
|
-
enabled: false
|
|
19
|
-
};
|
|
20
|
-
const overrides = options.captureOnFailure === true ? {} : options.captureOnFailure;
|
|
21
|
-
return {
|
|
22
|
-
artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_ARTIFACTS_DIR),
|
|
23
|
-
capture: {
|
|
24
|
-
activeFile: overrides.activeFile ?? true,
|
|
25
|
-
dom: overrides.dom ?? true,
|
|
26
|
-
editorText: overrides.editorText ?? true,
|
|
27
|
-
screenshot: overrides.screenshot ?? true,
|
|
28
|
-
tabs: overrides.tabs ?? true,
|
|
29
|
-
workspace: overrides.workspace ?? true
|
|
30
|
-
},
|
|
31
|
-
enabled: true
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function getFailureArtifactDirectory(artifactsDir, task) {
|
|
35
|
-
const suffix = task.id.split("_").at(-1) ?? "test";
|
|
36
|
-
return path.join(artifactsDir, `${sanitizeForPath(task.name)}-${suffix}`);
|
|
37
|
-
}
|
|
38
|
-
function registerFailureArtifacts(context, obsidian, options) {
|
|
39
|
-
const config = getFailureArtifactConfig(options);
|
|
40
|
-
if (!config.enabled) return;
|
|
41
|
-
context.onTestFailed(async () => {
|
|
42
|
-
const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, context.task);
|
|
43
|
-
await mkdir(artifactDirectory, { recursive: true });
|
|
44
|
-
await Promise.all([
|
|
45
|
-
captureJsonArtifact(artifactDirectory, "active-file.json", config.capture.activeFile, async () => ({ activeFile: await obsidian.dev.eval("app.workspace.getActiveFile()?.path ?? null") })),
|
|
46
|
-
captureTextArtifact(artifactDirectory, "dom.txt", config.capture.dom, async () => String(await obsidian.dev.dom({
|
|
47
|
-
inner: true,
|
|
48
|
-
selector: ".workspace"
|
|
49
|
-
}))),
|
|
50
|
-
captureJsonArtifact(artifactDirectory, "editor.json", config.capture.editorText, async () => ({ text: await obsidian.dev.eval("app.workspace.activeLeaf?.view?.editor?.getValue?.() ?? null") })),
|
|
51
|
-
captureScreenshotArtifact(artifactDirectory, config.capture.screenshot, obsidian),
|
|
52
|
-
captureJsonArtifact(artifactDirectory, "tabs.json", config.capture.tabs, () => obsidian.tabs()),
|
|
53
|
-
captureJsonArtifact(artifactDirectory, "workspace.json", config.capture.workspace, () => obsidian.workspace())
|
|
54
|
-
]);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
function registerPluginFailureArtifacts(context, plugin, options) {
|
|
58
|
-
const config = getFailureArtifactConfig(options);
|
|
59
|
-
if (!config.enabled) return;
|
|
60
|
-
context.onTestFailed(async () => {
|
|
61
|
-
const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, context.task);
|
|
62
|
-
await mkdir(artifactDirectory, { recursive: true });
|
|
63
|
-
await captureJsonArtifact(artifactDirectory, `${plugin.id}-data.json`, true, () => plugin.data().read());
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
async function captureJsonArtifact(artifactDirectory, filename, enabled, readValue) {
|
|
67
|
-
if (!enabled) return;
|
|
68
|
-
try {
|
|
69
|
-
const value = await readValue();
|
|
70
|
-
await writeFile(path.join(artifactDirectory, filename), `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
71
|
-
} catch (error) {
|
|
72
|
-
await writeFile(path.join(artifactDirectory, `${filename}.error.txt`), formatArtifactError(error), "utf8");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
async function captureScreenshotArtifact(artifactDirectory, enabled, obsidian) {
|
|
76
|
-
if (!enabled) return;
|
|
77
|
-
const screenshotPath = path.join(artifactDirectory, "screenshot.png");
|
|
78
|
-
try {
|
|
79
|
-
await obsidian.dev.screenshot(screenshotPath);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
await writeFile(path.join(artifactDirectory, "screenshot.error.txt"), formatArtifactError(error), "utf8");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async function captureTextArtifact(artifactDirectory, filename, enabled, readValue) {
|
|
85
|
-
if (!enabled) return;
|
|
86
|
-
try {
|
|
87
|
-
await writeFile(path.join(artifactDirectory, filename), await readValue(), "utf8");
|
|
88
|
-
} catch (error) {
|
|
89
|
-
await writeFile(path.join(artifactDirectory, `${filename}.error.txt`), formatArtifactError(error), "utf8");
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function formatArtifactError(error) {
|
|
93
|
-
return error instanceof Error ? `${error.name}: ${error.message}\n` : `${String(error)}\n`;
|
|
94
|
-
}
|
|
95
|
-
function sanitizeForPath(value) {
|
|
96
|
-
return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "test";
|
|
97
|
-
}
|
|
98
|
-
function createBaseFixtures(options, fixtureOptions = {}) {
|
|
99
|
-
const createVault = fixtureOptions.createVault ?? ((obsidian) => createVaultApi({ obsidian }));
|
|
100
|
-
return {
|
|
101
|
-
_vaultLock: [async ({}, use) => {
|
|
102
|
-
if (!options.sharedVaultLock) {
|
|
103
|
-
await use(null);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const lockClient = createObsidianClient(options);
|
|
107
|
-
await lockClient.verify();
|
|
108
|
-
const vaultLock = await acquireVaultRunLock({
|
|
109
|
-
...options.sharedVaultLock === true ? {} : options.sharedVaultLock,
|
|
110
|
-
vaultName: options.vault,
|
|
111
|
-
vaultPath: await lockClient.vaultPath()
|
|
112
|
-
});
|
|
113
|
-
await vaultLock.publishMarker(lockClient);
|
|
114
|
-
try {
|
|
115
|
-
await use(vaultLock);
|
|
116
|
-
} finally {
|
|
117
|
-
try {
|
|
118
|
-
await clearVaultRunLockMarker(lockClient);
|
|
119
|
-
} catch {}
|
|
120
|
-
await vaultLock.release();
|
|
121
|
-
}
|
|
122
|
-
}, { scope: "worker" }],
|
|
123
|
-
obsidian: async ({ _vaultLock, onTestFailed, task }, use) => {
|
|
124
|
-
const obsidian = createObsidianClient(options);
|
|
125
|
-
await obsidian.verify();
|
|
126
|
-
if (_vaultLock) await _vaultLock.publishMarker(obsidian);
|
|
127
|
-
registerFailureArtifacts({
|
|
128
|
-
onTestFailed,
|
|
129
|
-
task
|
|
130
|
-
}, obsidian, options);
|
|
131
|
-
try {
|
|
132
|
-
await use(obsidian);
|
|
133
|
-
} finally {
|
|
134
|
-
await getClientInternals(obsidian).restoreAll();
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
sandbox: async ({ obsidian }, use) => {
|
|
138
|
-
const sandbox = await createSandboxApi({
|
|
139
|
-
obsidian,
|
|
140
|
-
sandboxRoot: options.sandboxRoot ?? "__obsidian_e2e__",
|
|
141
|
-
testName: "test"
|
|
142
|
-
});
|
|
143
|
-
try {
|
|
144
|
-
await use(sandbox);
|
|
145
|
-
} finally {
|
|
146
|
-
await sandbox.cleanup();
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
vault: async ({ obsidian }, use) => {
|
|
150
|
-
await use(await createVault(obsidian));
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
//#endregion
|
|
155
4
|
//#region src/fixtures/create-obsidian-test.ts
|
|
156
5
|
function createObsidianTest(options) {
|
|
157
6
|
return test.extend(createBaseFixtures(options));
|
|
@@ -164,41 +13,33 @@ function createPluginTest(options) {
|
|
|
164
13
|
if (options.seedVault) await applyVaultSeed(obsidian, options.seedVault);
|
|
165
14
|
return createVaultApi({ obsidian });
|
|
166
15
|
} }),
|
|
167
|
-
plugin: async ({
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
registerPluginFailureArtifacts({
|
|
173
|
-
onTestFailed,
|
|
174
|
-
task
|
|
175
|
-
}, plugin, options);
|
|
176
|
-
try {
|
|
177
|
-
await use(plugin);
|
|
178
|
-
} finally {
|
|
179
|
-
if (!wasEnabled) await plugin.disable({ filter: options.pluginFilter });
|
|
180
|
-
}
|
|
16
|
+
plugin: async ({ _testContext }, use) => {
|
|
17
|
+
await use(await _testContext.plugin(options.pluginId, {
|
|
18
|
+
filter: options.pluginFilter,
|
|
19
|
+
seedData: options.seedPluginData
|
|
20
|
+
}));
|
|
181
21
|
}
|
|
182
22
|
};
|
|
183
23
|
return test.extend(fixtures);
|
|
184
24
|
}
|
|
185
25
|
async function applyVaultSeed(obsidian, seedVault) {
|
|
186
|
-
const
|
|
26
|
+
const vault = createVaultApi({ obsidian });
|
|
187
27
|
for (const [targetPath, value] of Object.entries(seedVault)) {
|
|
188
|
-
const resolvedPath =
|
|
189
|
-
const normalizedVaultRoot = path.resolve(vaultRoot);
|
|
190
|
-
if (resolvedPath !== normalizedVaultRoot && !resolvedPath.startsWith(`${normalizedVaultRoot}${path.sep}`)) throw new Error(`Seed path escapes the vault root: ${targetPath}`);
|
|
28
|
+
const resolvedPath = await resolveFilesystemPath(obsidian, "", targetPath);
|
|
191
29
|
await getClientInternals(obsidian).snapshotFileOnce(resolvedPath);
|
|
192
|
-
await
|
|
193
|
-
await writeSeedValue(resolvedPath, value);
|
|
30
|
+
await writeSeedValue(vault, targetPath, value);
|
|
194
31
|
}
|
|
195
32
|
}
|
|
196
|
-
async function writeSeedValue(
|
|
33
|
+
async function writeSeedValue(vault, targetPath, value) {
|
|
197
34
|
if (typeof value === "string") {
|
|
198
|
-
await
|
|
35
|
+
await vault.write(targetPath, value, { waitForContent: true });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if ("note" in value) {
|
|
39
|
+
await vault.write(targetPath, createNoteDocument(value.note).raw, { waitForContent: true });
|
|
199
40
|
return;
|
|
200
41
|
}
|
|
201
|
-
await
|
|
42
|
+
await vault.write(targetPath, `${JSON.stringify(value.json, null, 2)}\n`, { waitForContent: true });
|
|
202
43
|
}
|
|
203
44
|
//#endregion
|
|
204
45
|
export { acquireVaultRunLock, clearVaultRunLockMarker, createObsidianTest, createPluginTest, inspectVaultRunLock, readVaultRunLockMarker };
|
package/dist/vitest.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.mjs","names":["base","base"],"sources":["../src/fixtures/failure-artifacts.ts","../src/fixtures/base-fixtures.ts","../src/fixtures/create-obsidian-test.ts","../src/fixtures/create-plugin-test.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport type { TestContext } from \"vite-plus/test\";\n\nimport type { ObsidianClient, PluginHandle } from \"../core/types\";\nimport type { CreateObsidianTestOptions, FailureArtifactOptions } from \"./types\";\n\nconst DEFAULT_ARTIFACTS_DIR = \".obsidian-e2e-artifacts\";\n\ninterface FailureArtifactConfig {\n artifactsDir: string;\n capture: Required<FailureArtifactOptions>;\n enabled: boolean;\n}\n\nexport function getFailureArtifactConfig(\n options: Pick<CreateObsidianTestOptions, \"artifactsDir\" | \"captureOnFailure\">,\n): FailureArtifactConfig {\n if (!options.captureOnFailure) {\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_ARTIFACTS_DIR),\n capture: {\n activeFile: true,\n dom: true,\n editorText: true,\n screenshot: true,\n tabs: true,\n workspace: true,\n },\n enabled: false,\n };\n }\n\n const overrides = options.captureOnFailure === true ? {} : options.captureOnFailure;\n\n return {\n artifactsDir: path.resolve(options.artifactsDir ?? DEFAULT_ARTIFACTS_DIR),\n capture: {\n activeFile: overrides.activeFile ?? true,\n dom: overrides.dom ?? true,\n editorText: overrides.editorText ?? true,\n screenshot: overrides.screenshot ?? true,\n tabs: overrides.tabs ?? true,\n workspace: overrides.workspace ?? true,\n },\n enabled: true,\n };\n}\n\nexport function getFailureArtifactDirectory(\n artifactsDir: string,\n task: Pick<TestContext[\"task\"], \"id\" | \"name\">,\n): string {\n const suffix = task.id.split(\"_\").at(-1) ?? \"test\";\n return path.join(artifactsDir, `${sanitizeForPath(task.name)}-${suffix}`);\n}\n\nexport function registerFailureArtifacts(\n context: Pick<TestContext, \"onTestFailed\" | \"task\">,\n obsidian: ObsidianClient,\n options: Pick<CreateObsidianTestOptions, \"artifactsDir\" | \"captureOnFailure\">,\n): void {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return;\n }\n\n context.onTestFailed(async () => {\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, context.task);\n await mkdir(artifactDirectory, { recursive: true });\n\n await Promise.all([\n captureJsonArtifact(\n artifactDirectory,\n \"active-file.json\",\n config.capture.activeFile,\n async () => ({\n activeFile: await obsidian.dev.eval<string | null>(\n \"app.workspace.getActiveFile()?.path ?? null\",\n ),\n }),\n ),\n captureTextArtifact(artifactDirectory, \"dom.txt\", config.capture.dom, async () =>\n String(\n await obsidian.dev.dom({\n inner: true,\n selector: \".workspace\",\n }),\n ),\n ),\n captureJsonArtifact(\n artifactDirectory,\n \"editor.json\",\n config.capture.editorText,\n async () => ({\n text: await obsidian.dev.eval<string | null>(\n \"app.workspace.activeLeaf?.view?.editor?.getValue?.() ?? null\",\n ),\n }),\n ),\n captureScreenshotArtifact(artifactDirectory, config.capture.screenshot, obsidian),\n captureJsonArtifact(artifactDirectory, \"tabs.json\", config.capture.tabs, () =>\n obsidian.tabs(),\n ),\n captureJsonArtifact(artifactDirectory, \"workspace.json\", config.capture.workspace, () =>\n obsidian.workspace(),\n ),\n ]);\n });\n}\n\nexport function registerPluginFailureArtifacts(\n context: Pick<TestContext, \"onTestFailed\" | \"task\">,\n plugin: PluginHandle,\n options: Pick<CreateObsidianTestOptions, \"artifactsDir\" | \"captureOnFailure\">,\n): void {\n const config = getFailureArtifactConfig(options);\n\n if (!config.enabled) {\n return;\n }\n\n context.onTestFailed(async () => {\n const artifactDirectory = getFailureArtifactDirectory(config.artifactsDir, context.task);\n await mkdir(artifactDirectory, { recursive: true });\n await captureJsonArtifact(artifactDirectory, `${plugin.id}-data.json`, true, () =>\n plugin.data().read(),\n );\n });\n}\n\nasync function captureJsonArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<unknown>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n const value = await readValue();\n await writeFile(\n path.join(artifactDirectory, filename),\n `${JSON.stringify(value, null, 2)}\\n`,\n \"utf8\",\n );\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureScreenshotArtifact(\n artifactDirectory: string,\n enabled: boolean,\n obsidian: ObsidianClient,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n const screenshotPath = path.join(artifactDirectory, \"screenshot.png\");\n\n try {\n await obsidian.dev.screenshot(screenshotPath);\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, \"screenshot.error.txt\"),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nasync function captureTextArtifact(\n artifactDirectory: string,\n filename: string,\n enabled: boolean,\n readValue: () => Promise<string>,\n): Promise<void> {\n if (!enabled) {\n return;\n }\n\n try {\n await writeFile(path.join(artifactDirectory, filename), await readValue(), \"utf8\");\n } catch (error) {\n await writeFile(\n path.join(artifactDirectory, `${filename}.error.txt`),\n formatArtifactError(error),\n \"utf8\",\n );\n }\n}\n\nfunction formatArtifactError(error: unknown): string {\n return error instanceof Error ? `${error.name}: ${error.message}\\n` : `${String(error)}\\n`;\n}\n\nfunction sanitizeForPath(value: string): string {\n return (\n value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 60) || \"test\"\n );\n}\n","import type { TestContext } from \"vite-plus/test\";\n\nimport { createObsidianClient } from \"../core/client\";\nimport { getClientInternals } from \"../core/internals\";\nimport type { ObsidianClient, VaultApi } from \"../core/types\";\nimport { createSandboxApi } from \"../vault/sandbox\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { registerFailureArtifacts } from \"./failure-artifacts\";\nimport type { CreateObsidianTestOptions } from \"./types\";\nimport { acquireVaultRunLock, clearVaultRunLockMarker, type VaultRunLock } from \"./vault-lock\";\n\nexport const DEFAULT_SANDBOX_ROOT = \"__obsidian_e2e__\";\n\nexport interface BaseFixtureState {\n _vaultLock: VaultRunLock | null;\n}\n\ninterface BaseFixtureOptions {\n createVault?: (obsidian: ObsidianClient) => Promise<VaultApi> | VaultApi;\n}\n\nexport function createBaseFixtures(\n options: CreateObsidianTestOptions,\n fixtureOptions: BaseFixtureOptions = {},\n) {\n const createVault =\n fixtureOptions.createVault ?? ((obsidian: ObsidianClient) => createVaultApi({ obsidian }));\n\n return {\n _vaultLock: [\n // eslint-disable-next-line no-empty-pattern\n async ({}, use: (vaultLock: VaultRunLock | null) => Promise<void>) => {\n if (!options.sharedVaultLock) {\n await use(null);\n return;\n }\n\n const lockClient = createObsidianClient(options);\n await lockClient.verify();\n\n const lockOptions = options.sharedVaultLock === true ? {} : options.sharedVaultLock;\n const vaultLock = await acquireVaultRunLock({\n ...lockOptions,\n vaultName: options.vault,\n vaultPath: await lockClient.vaultPath(),\n });\n\n await vaultLock.publishMarker(lockClient);\n try {\n await use(vaultLock);\n } finally {\n try {\n await clearVaultRunLockMarker(lockClient);\n } catch {}\n\n await vaultLock.release();\n }\n },\n { scope: \"worker\" },\n ],\n // oxlint-disable-next-line no-empty-pattern\n obsidian: async (\n {\n _vaultLock,\n onTestFailed,\n task,\n }: Pick<BaseFixtureState & TestContext, \"_vaultLock\" | \"onTestFailed\" | \"task\">,\n use: (obsidian: ObsidianClient) => Promise<void>,\n ) => {\n const obsidian = createObsidianClient(options);\n\n await obsidian.verify();\n if (_vaultLock) {\n await _vaultLock.publishMarker(obsidian);\n }\n registerFailureArtifacts({ onTestFailed, task }, obsidian, options);\n\n try {\n await use(obsidian);\n } finally {\n await getClientInternals(obsidian).restoreAll();\n }\n },\n sandbox: async (\n { obsidian }: { obsidian: ObsidianClient },\n use: (sandbox: Awaited<ReturnType<typeof createSandboxApi>>) => Promise<void>,\n ) => {\n const sandbox = await createSandboxApi({\n obsidian,\n sandboxRoot: options.sandboxRoot ?? DEFAULT_SANDBOX_ROOT,\n testName: \"test\",\n });\n\n try {\n await use(sandbox);\n } finally {\n await sandbox.cleanup();\n }\n },\n vault: async (\n { obsidian }: { obsidian: ObsidianClient },\n use: (vault: VaultApi) => Promise<void>,\n ) => {\n await use(await createVault(obsidian));\n },\n };\n}\n","import { test as base } from \"vite-plus/test\";\n\nimport { createBaseFixtures, type BaseFixtureState } from \"./base-fixtures\";\nimport type { CreateObsidianTestOptions, ObsidianFixtures, ObsidianTest } from \"./types\";\n\nexport function createObsidianTest(options: CreateObsidianTestOptions): ObsidianTest {\n return base.extend<ObsidianFixtures & BaseFixtureState>(\n createBaseFixtures(options) as never,\n ) as ObsidianTest;\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { test as base } from \"vite-plus/test\";\nimport type { TestContext } from \"vite-plus/test\";\n\nimport { getClientInternals } from \"../core/internals\";\nimport type { ObsidianClient } from \"../core/types\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { createBaseFixtures, type BaseFixtureState } from \"./base-fixtures\";\nimport { registerPluginFailureArtifacts } from \"./failure-artifacts\";\nimport type {\n CreatePluginTestOptions,\n PluginFixtures,\n PluginTest,\n VaultSeed,\n VaultSeedEntry,\n} from \"./types\";\n\nexport function createPluginTest(options: CreatePluginTestOptions): PluginTest {\n const fixtures = {\n ...createBaseFixtures(options, {\n async createVault(obsidian) {\n if (options.seedVault) {\n await applyVaultSeed(obsidian, options.seedVault);\n }\n\n return createVaultApi({ obsidian });\n },\n }),\n plugin: async (\n {\n obsidian,\n onTestFailed,\n task,\n }: Pick<PluginFixtures & TestContext, \"obsidian\" | \"onTestFailed\" | \"task\">,\n use: (plugin: PluginFixtures[\"plugin\"]) => Promise<void>,\n ) => {\n const plugin = obsidian.plugin(options.pluginId);\n const wasEnabled = await plugin.isEnabled();\n\n if (!wasEnabled) {\n await plugin.enable({ filter: options.pluginFilter });\n }\n\n if (options.seedPluginData !== undefined) {\n await plugin.data().write(options.seedPluginData);\n }\n\n registerPluginFailureArtifacts({ onTestFailed, task }, plugin, options);\n\n try {\n await use(plugin);\n } finally {\n if (!wasEnabled) {\n await plugin.disable({ filter: options.pluginFilter });\n }\n }\n },\n };\n\n return base.extend<PluginFixtures & BaseFixtureState>(fixtures as never) as PluginTest;\n}\n\nasync function applyVaultSeed(obsidian: ObsidianClient, seedVault: VaultSeed): Promise<void> {\n const vaultRoot = await obsidian.vaultPath();\n\n for (const [targetPath, value] of Object.entries(seedVault)) {\n const resolvedPath = path.resolve(vaultRoot, ...targetPath.split(\"/\").filter(Boolean));\n const normalizedVaultRoot = path.resolve(vaultRoot);\n\n if (\n resolvedPath !== normalizedVaultRoot &&\n !resolvedPath.startsWith(`${normalizedVaultRoot}${path.sep}`)\n ) {\n throw new Error(`Seed path escapes the vault root: ${targetPath}`);\n }\n\n await getClientInternals(obsidian).snapshotFileOnce(resolvedPath);\n await mkdir(path.dirname(resolvedPath), { recursive: true });\n await writeSeedValue(resolvedPath, value);\n }\n}\n\nasync function writeSeedValue(resolvedPath: string, value: VaultSeedEntry): Promise<void> {\n if (typeof value === \"string\") {\n await writeFile(resolvedPath, value, \"utf8\");\n return;\n }\n\n await writeFile(resolvedPath, `${JSON.stringify(value.json, null, 2)}\\n`, \"utf8\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"vitest.mjs","names":["base","base"],"sources":["../src/fixtures/create-obsidian-test.ts","../src/fixtures/create-plugin-test.ts"],"sourcesContent":["import { test as base } from \"vite-plus/test\";\n\nimport { createBaseFixtures, type BaseFixtureState } from \"./base-fixtures\";\nimport type { CreateObsidianTestOptions, ObsidianFixtures, ObsidianTest } from \"./types\";\n\nexport function createObsidianTest(options: CreateObsidianTestOptions): ObsidianTest {\n return base.extend<ObsidianFixtures & BaseFixtureState>(\n createBaseFixtures(options) as never,\n ) as ObsidianTest;\n}\n","import { test as base } from \"vite-plus/test\";\n\nimport { getClientInternals } from \"../core/internals\";\nimport type { ObsidianClient, VaultApi } from \"../core/types\";\nimport { createNoteDocument } from \"../note/document\";\nimport { createVaultApi } from \"../vault/vault\";\nimport { resolveFilesystemPath } from \"../vault/paths\";\nimport { createBaseFixtures, type BaseFixtureState } from \"./base-fixtures\";\nimport type {\n CreatePluginTestOptions,\n PluginFixtures,\n PluginTest,\n VaultSeed,\n VaultSeedEntry,\n} from \"./types\";\n\nexport function createPluginTest(options: CreatePluginTestOptions): PluginTest {\n const fixtures = {\n ...createBaseFixtures(options, {\n async createVault(obsidian) {\n if (options.seedVault) {\n await applyVaultSeed(obsidian, options.seedVault);\n }\n\n return createVaultApi({ obsidian });\n },\n }),\n plugin: async (\n { _testContext }: Pick<BaseFixtureState, \"_testContext\">,\n use: (plugin: PluginFixtures[\"plugin\"]) => Promise<void>,\n ) => {\n await use(\n await _testContext.plugin(options.pluginId, {\n filter: options.pluginFilter,\n seedData: options.seedPluginData,\n }),\n );\n },\n };\n\n return base.extend<PluginFixtures & BaseFixtureState>(fixtures as never) as PluginTest;\n}\n\nasync function applyVaultSeed(obsidian: ObsidianClient, seedVault: VaultSeed): Promise<void> {\n const vault = createVaultApi({ obsidian });\n\n for (const [targetPath, value] of Object.entries(seedVault)) {\n const resolvedPath = await resolveFilesystemPath(obsidian, \"\", targetPath);\n await getClientInternals(obsidian).snapshotFileOnce(resolvedPath);\n await writeSeedValue(vault, targetPath, value);\n }\n}\n\nasync function writeSeedValue(\n vault: VaultApi,\n targetPath: string,\n value: VaultSeedEntry,\n): Promise<void> {\n if (typeof value === \"string\") {\n await vault.write(targetPath, value, {\n waitForContent: true,\n });\n return;\n }\n\n if (\"note\" in value) {\n await vault.write(targetPath, createNoteDocument(value.note).raw, {\n waitForContent: true,\n });\n return;\n }\n\n await vault.write(targetPath, `${JSON.stringify(value.json, null, 2)}\\n`, {\n waitForContent: true,\n });\n}\n"],"mappings":";;;;AAKA,SAAgB,mBAAmB,SAAkD;AACnF,QAAOA,KAAK,OACV,mBAAmB,QAAQ,CAC5B;;;;ACQH,SAAgB,iBAAiB,SAA8C;CAC7E,MAAM,WAAW;EACf,GAAG,mBAAmB,SAAS,EAC7B,MAAM,YAAY,UAAU;AAC1B,OAAI,QAAQ,UACV,OAAM,eAAe,UAAU,QAAQ,UAAU;AAGnD,UAAO,eAAe,EAAE,UAAU,CAAC;KAEtC,CAAC;EACF,QAAQ,OACN,EAAE,gBACF,QACG;AACH,SAAM,IACJ,MAAM,aAAa,OAAO,QAAQ,UAAU;IAC1C,QAAQ,QAAQ;IAChB,UAAU,QAAQ;IACnB,CAAC,CACH;;EAEJ;AAED,QAAOC,KAAK,OAA0C,SAAkB;;AAG1E,eAAe,eAAe,UAA0B,WAAqC;CAC3F,MAAM,QAAQ,eAAe,EAAE,UAAU,CAAC;AAE1C,MAAK,MAAM,CAAC,YAAY,UAAU,OAAO,QAAQ,UAAU,EAAE;EAC3D,MAAM,eAAe,MAAM,sBAAsB,UAAU,IAAI,WAAW;AAC1E,QAAM,mBAAmB,SAAS,CAAC,iBAAiB,aAAa;AACjE,QAAM,eAAe,OAAO,YAAY,MAAM;;;AAIlD,eAAe,eACb,OACA,YACA,OACe;AACf,KAAI,OAAO,UAAU,UAAU;AAC7B,QAAM,MAAM,MAAM,YAAY,OAAO,EACnC,gBAAgB,MACjB,CAAC;AACF;;AAGF,KAAI,UAAU,OAAO;AACnB,QAAM,MAAM,MAAM,YAAY,mBAAmB,MAAM,KAAK,CAAC,KAAK,EAChE,gBAAgB,MACjB,CAAC;AACF;;AAGF,OAAM,MAAM,MAAM,YAAY,GAAG,KAAK,UAAU,MAAM,MAAM,MAAM,EAAE,CAAC,KAAK,EACxE,gBAAgB,MACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "obsidian-e2e",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Vitest-first end-to-end test utilities for Obsidian plugins.",
|
|
5
5
|
"homepage": "https://github.com/chhoumann/obsidian-e2e#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
},
|
|
36
36
|
"./package.json": "./package.json"
|
|
37
37
|
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"yaml": "^2.8.2"
|
|
40
|
+
},
|
|
38
41
|
"devDependencies": {
|
|
39
42
|
"@changesets/cli": "^2.30.0",
|
|
40
43
|
"@types/node": "^25.3.5",
|