Document test procedures and show Community lint warnings

This commit is contained in:
vorotamoroz
2026-09-17 16:26:24 +00:00
parent 1c8db1a2b2
commit ce4eb7f9ac
5 changed files with 107 additions and 33 deletions
+4 -30
View File
@@ -29,18 +29,7 @@ npm run build
#### Community Review dependency installation #### Community Review dependency installation
Community Review installs dependencies independently before applying type-aware source rules. A successful installation with the npm version bundled with the repository's current Node.js CI does not prove that the lockfile is accepted by the scanner's npm version. After changing a dependency manifest or lockfile, follow the [npm 10 clean-installation check](test/README.md#npm-10-clean-installation-check) before the normal source and unit checks. The test guide records the command used by CI and the distinction between installation failures and source diagnostics.
After changing `package.json`, a workspace manifest, or `package-lock.json`, verify both installation paths:
```bash
npm ci --ignore-scripts
npx --yes npm@10.9.2 ci --ignore-scripts
```
The npm 10.9.2 command is the current project-side compatibility check for the Community Review installation path. Update this check when the scanner runtime changes.
If Community Review reports widespread TypeScript `error` types across unrelated external packages, confirm that dependency installation completed successfully before changing source imports, declarations, or lint rules. An installation failure can make every unresolved external type appear as downstream unsafe-type findings.
### Commands ### Commands
@@ -77,6 +66,8 @@ To facilitate development and testing, the build process can automatically copy
### Testing Infrastructure ### Testing Infrastructure
See the [test procedures](test/README.md) for clean-installation checks, local validation commands, and links to each runtime suite.
- **Vitest**: - **Vitest**:
- **Unit Tests** (`vitest.config.unit.ts`): Unit tests run in Node.js (excluding harnesses and integration tests). Unit tests should be `*.unit.spec.ts` and placed alongside the implementation file (e.g., `ChunkFetcher.unit.spec.ts`). Executed via `npm run test:unit`. - **Unit Tests** (`vitest.config.unit.ts`): Unit tests run in Node.js (excluding harnesses and integration tests). Unit tests should be `*.unit.spec.ts` and placed alongside the implementation file (e.g., `ChunkFetcher.unit.spec.ts`). Executed via `npm run test:unit`.
- **Integration Tests** (`vitest.config.integration.ts`): Tests run in Node.js against a real CouchDB instance. Integration tests should be `*.integration.spec.ts` or `*.integration.test.ts` and placed alongside the implementation file (e.g., `StreamingFetch.integration.spec.ts`). Executed via `npm run test:integration`. - **Integration Tests** (`vitest.config.integration.ts`): Tests run in Node.js against a real CouchDB instance. Integration tests should be `*.integration.spec.ts` or `*.integration.test.ts` and placed alongside the implementation file (e.g., `StreamingFetch.integration.spec.ts`). Executed via `npm run test:integration`.
@@ -209,24 +200,7 @@ Ordinary file saves and incoming reflection use that provenance even before a co
This policy is intentionally aligned with the conflict checkboxes and compatibility settings: automatic merge should remove avoidable prompts, but it must not silently choose between overlapping user intentions. This policy is intentionally aligned with the conflict checkboxes and compatibility settings: automatic merge should remove avoidable prompts, but it must not silently choose between overlapping user intentions.
### Multiple-device conflict regression tests The [multiple-device conflict test procedure](test/README.md#multiple-device-conflict-regression-tests) documents the five CouchDB-backed cases, execution steps, expected results, and coverage boundaries.
`src/serviceModules/FileHandler.multidevice.integration.spec.ts` tests the installed Commonlib package through LiveSync's shared file handler, the CLI `resolve` command dispatcher, and the shared conflict-resolution operations. Run it against the isolated CouchDB test service configured by `hostname`, `username`, and `password` in `.test.env`:
```bash
npm run test:integration -- src/serviceModules/FileHandler.multidevice.integration.spec.ts --maxWorkers=1
```
Each simulated device owns a separate real PouchDB database, `LiveSyncLocalDB` managers, file content, and provenance record. Devices first share one revision, edit while disconnected, and then replicate their Metadata and Chunks through real CouchDB. File reflection is deliberately delayed after replication to reproduce the interval in which the database has advanced but the file still contains older content. All edits use equal modification times, so the tests require revision and content checks rather than timestamp ordering.
The five cases cover:
- Three and four editing devices: every branch and its content reaches every device. Reprocessing unchanged files while conflicts exist makes no database writes. The CLI selects a non-winning revision, removes the other branches, and reflects the selected content. After resolution replicates, unchanged files from losing branches reflect the selected content without creating revisions or restoring conflicts.
- A genuine edit on a losing device after three-way resolution: the new revision extends that device's recorded branch, and both the selected result and the new edit remain readable on every replica.
- Four devices with missing provenance: a file matching the original historical ancestor becomes a fresh independent conflict, preserving both contents. Historical equality does not justify discarding it.
- Four devices with a compacted, unreadable recorded base: the remaining file is preserved as an independent conflict. In both uncertain-base cases, repeated processing after provenance loss creates no duplicates, and the CLI can select the independent root and propagate its resolution.
This is a service integration test, not a CLI subprocess or Obsidian runtime test. The file and provenance stores are in-memory fixtures; automatic conflict callbacks are observed without running interactive or automatic merge policies. PouchDB revision creation, chunk storage and retrieval, compaction, CouchDB replication, the CLI command dispatcher, and its resolution operations are real. CLI argument parsing, persistent host stores, file watchers, mobile suspension, and Obsidian dialogues remain covered separately or require their own runtime checks.
### File Structure Conventions ### File Structure Conventions
+1 -1
View File
@@ -277,7 +277,7 @@ Do not:
## Verification ## Verification
LiveSync also exercises three and four independently editing devices through real CouchDB, using the installed Commonlib package and the CLI conflict-resolution command dispatcher. These tests check unchanged losing files before and after resolution, genuine edits on a losing branch, missing provenance, compacted bases, independent-root deduplication, and propagation of the selected result. See the [multiple-device regression procedure and coverage boundaries](../devs.md#multiple-device-conflict-regression-tests). LiveSync also exercises three and four independently editing devices through real CouchDB, using the installed Commonlib package and the CLI conflict-resolution command dispatcher. These tests check unchanged losing files before and after resolution, genuine edits on a losing branch, missing provenance, compacted bases, independent-root deduplication, and propagation of the selected result. See the [multiple-device regression procedure and coverage boundaries](../test/README.md#multiple-device-conflict-regression-tests).
Commonlib owns the real-PouchDB and injected-boundary tests for revision ancestry, content preservation, provenance, independent branches, and repeated file events. LiveSync owns persistent host composition and actual Obsidian restart coverage. The focused `test:e2e:obsidian:stale-file-restart` scenario advances the local DB while old Vault bytes remain, persists pending file events, and restarts the same isolated profile. It requires an unchanged recorded file to reflect the DB without a new revision, an unknown file to remain on an independent branch alongside the DB content, and repeated processing after provenance loss to leave those branches unchanged. It uses real local storage and startup processing; transport replication and mobile lifecycle coverage are separate. Commonlib owns the real-PouchDB and injected-boundary tests for revision ancestry, content preservation, provenance, independent branches, and repeated file events. LiveSync owns persistent host composition and actual Obsidian restart coverage. The focused `test:e2e:obsidian:stale-file-restart` scenario advances the local DB while old Vault bytes remain, persists pending file events, and restarts the same isolated profile. It requires an unchanged recorded file to reflect the DB without a new revision, an unknown file to remain on an independent branch alongside the DB content, and repeated processing after provenance loss to leave those branches unchanged. It uses real local storage and startup processing; transport replication and mobile lifecycle coverage are separate.
+1 -1
View File
@@ -52,7 +52,7 @@ export default defineConfig(
"obsidianmd/rule-custom-message": "off", "obsidianmd/rule-custom-message": "off",
"no-console": "warn", "no-console": "warn",
"obsidianmd/no-unsupported-api": "error", "obsidianmd/no-unsupported-api": "error",
// Reject direct globalThis access even when routine checks use --quiet. // Treat direct globalThis access as an error so the CI gate rejects it.
"obsidianmd/no-global-this": "error", "obsidianmd/no-global-this": "error",
// Keep legacy type-safety debt visible while reserving errors for directory-review blockers. // Keep legacy type-safety debt visible while reserving errors for directory-review blockers.
"@typescript-eslint/no-unsafe-argument": "warn", "@typescript-eslint/no-unsafe-argument": "warn",
+1 -1
View File
@@ -23,7 +23,7 @@
"prettyNoWrite": "prettier --config ./.prettierrc.mjs \"**/*.js\" \"**/*.ts\" \"**/*.json\" ", "prettyNoWrite": "prettier --config ./.prettierrc.mjs \"**/*.js\" \"**/*.ts\" \"**/*.json\" ",
"precheck:compatibility": "npm run build", "precheck:compatibility": "npm run build",
"check:compatibility": "node utils/check-compatibility.js --file main.js --ios 15", "check:compatibility": "node utils/check-compatibility.js --file main.js --ios 15",
"check": "npm run tsc-check && npm run tsc-check:apps && npm run lint && npm run lint:community -- --quiet && npm run lint:community:tools && npm run svelte-check && npm run check:compatibility", "check": "npm run tsc-check && npm run tsc-check:apps && npm run lint && npm run lint:community && npm run lint:community:tools && npm run svelte-check && npm run check:compatibility",
"i18n:bake": "npm run i18n:yaml2json && npm run i18n:bakejson && npm run i18n:format", "i18n:bake": "npm run i18n:yaml2json && npm run i18n:bakejson && npm run i18n:format",
"i18n:bakejson": "tsx _tools/bakei18n.ts", "i18n:bakejson": "tsx _tools/bakei18n.ts",
"i18n:format": "prettier --config .prettierrc.mjs --write --log-level error 'src/common/messagesJson/*.json' 'src/common/messages/*.ts'", "i18n:format": "prettier --config .prettierrc.mjs --write --log-level error 'src/common/messagesJson/*.json' 'src/common/messages/*.ts'",
+100
View File
@@ -0,0 +1,100 @@
# Test procedures
Run the commands below from the repository root. Test ownership and source layout are described in the [development guide](../devs.md#testing-infrastructure).
## npm 10 clean-installation check
Run this check after changing `package.json`, a workspace manifest, or `package-lock.json`, including a Commonlib dependency update. A successful installation with the npm version bundled with Node.js does not prove that npm 10 accepts the lockfile.
The following sequence matches the installation steps in [unit-ci](../.github/workflows/unit-ci.yml). Use Node.js 24, as configured in that workflow:
```bash
npx --yes npm@10.9.4 ci --ignore-scripts --no-audit --no-fund
npm ci
```
Both commands must complete successfully without changing the lockfile. The first checks npm 10 lockfile compatibility; the second prepares the normal development installation, including lifecycle scripts, for the source checks and tests below. Keep the pinned npm version and command here aligned with CI. This project-side check does not establish the runtime version used by the external Community Review service or replace its authenticated review result.
If Community Review reports widespread TypeScript `error` types across unrelated external packages, first confirm that dependency installation completed successfully. An installation failure can leave external types unresolved and produce misleading source warnings.
## Source and unit checks
Run broad checks sequentially. These examples bound the Node.js heap and Vitest workers for machines with limited memory:
```bash
NODE_OPTIONS=--max-old-space-size=3072 npm run check
NODE_OPTIONS=--max-old-space-size=3072 npm run test:unit -- --maxWorkers=1
```
`npm run check` includes TypeScript, ESLint, the Community rules, Svelte checks, a production build, and bundle compatibility checks. Inspect installation and source-check failures before interpreting later test results. Add the relevant service or runtime suite for the boundary changed:
| Boundary | Procedure |
| --- | --- |
| Multiple-device file conflicts and stale-file protection | [CouchDB procedure below](#multiple-device-conflict-regression-tests) |
| Obsidian startup, file watching, persistence, and UI | [Real Obsidian E2E](e2e-obsidian/README.md) |
| CLI subprocesses, filesystem workflows, and P2P | [CLI Deno tests](../src/apps/cli/testdeno/test_dev_deno.md) and [test authoring](../src/apps/cli/testdeno/CONTRIBUTING_TESTS.md) |
| WebApp, WebPeer, and browser interoperability | [Browser application tests](browser-apps/README.md) |
## Community Review checks and CI confirmation
Before requesting review or merging source or dependency changes, run the project-side Community checks after dependency installation:
```bash
NODE_OPTIONS=--max-old-space-size=3072 npm run lint:community
NODE_OPTIONS=--max-old-space-size=3072 npm run lint:community:tools
```
The source check uses the official `eslint-plugin-obsidianmd` rules with the repository's [Community configuration](../eslint.community.config.mjs). Run it without `--quiet` so warnings remain visible. Review new warnings as well as errors, and distinguish existing warnings from those introduced by the change. A successful exit alone does not establish that the source has no warnings. The tooling check requires zero warnings.
The [unit-ci workflow](../.github/workflows/unit-ci.yml), in its `Unit Tests` job, runs the npm 10 installation check and then `npm run check`. That script includes `lint:community` and `lint:community:tools`, so source warnings are visible in the CI log as well as during local checks. Source errors fail the gate; source warnings remain visible for review without failing it. The explicit commands above can run these checks independently of the full source-check sequence.
After pushing, confirm that the `Unit Tests` job passed for the exact commit being reviewed, including its `Verify clean installation with npm 10` and `Run source checks` steps. For service-backed changes, also confirm the integration-test job and the relevant runtime checks. A successful run for an earlier commit does not validate later changes.
The local checks and CI use the project's installed rule versions and configured file scope. Record the authenticated external Community Review result separately when that review is required; the project-side checks do not replace it. When the external review reports additional findings, retain its relevant output and investigate differences in installation, type resolution, scope, or rules.
## Multiple-device conflict regression tests
### Preparation and execution
The suite is [FileHandler.multidevice.integration.spec.ts](../src/serviceModules/FileHandler.multidevice.integration.spec.ts). It exercises the installed Commonlib package through LiveSync's shared file handler, the CLI `resolve` command dispatcher, and the shared conflict-resolution operations.
Use a disposable CouchDB service. To use the repository's Docker fixture, set the following values in `.test.env` and ensure `.env` exists. The fixture uses the container name `couchdb-test` and host port `5989`:
```dotenv
hostname=http://127.0.0.1:5989/
username=admin
password=testpassword
```
Start the fixture, then run the focused suite:
```bash
npm run test:docker-couchdb:start
NODE_OPTIONS=--max-old-space-size=3072 npm run test:integration -- src/serviceModules/FileHandler.multidevice.integration.spec.ts --maxWorkers=1
```
The expected result is five passing tests. Each case creates a uniquely named remote database and removes it during teardown. Stop the fixture after the run, including when the test command fails:
```bash
npm run test:docker-couchdb:stop
```
When using an already running disposable CouchDB service, configure its endpoint and credentials in `.test.env` and run only the test command. The start and stop commands manage the repository's Docker fixture. This suite needs no Object Storage, P2P relay, or Obsidian application. It is also discovered by the existing integration-test CI job.
### Scenarios and expected results
Each simulated device owns a separate real PouchDB database, `LiveSyncLocalDB` managers, file content, and provenance record. Devices first share one revision, edit while disconnected, and then replicate their Metadata and Chunks through real CouchDB. File reflection is deliberately delayed after replication to reproduce the interval in which the database has advanced but the file still contains older content. All edits use equal modification times, so the tests require revision and content checks rather than timestamp ordering.
| Case | Setup and action | Required result |
| --- | --- | --- |
| Three editing devices | Replicate three conflicting edits, reprocess unchanged files, select a non-winning revision through CLI `resolve`, and replicate the resolution before reprocessing the other files. | All three contents are initially readable on every replica. Unchanged saves make no database writes. After resolution, all files and replicas converge to the selected revision without creating revisions or restoring conflicts. |
| Four editing devices | Repeat the same sequence with four independently edited branches. | All four contents are initially preserved, and the same unchanged-save and convergence guarantees hold. |
| A genuine edit on a losing device | After three-way resolution reaches its DB, a device adds content to its still-unreflected losing file, then saves and replicates it. | The new revision extends that device's recorded branch. The selected result and the new edit remain readable on every replica. |
| Missing provenance | After four-way resolution, remove a losing device's provenance record and set its file to the original historical ancestor's content. Save, remove provenance again, and repeat the save. | The file becomes one fresh independent root, distinct from the historical root. Both contents remain readable after replication, and repeated saves create no duplicates. CLI `resolve` can select the independent root and propagate its resolution. |
| Compacted base | After four-way resolution, compact a losing device's local DB and confirm that its recorded revision body is unavailable. Save the remaining file, then repeat after removing provenance. | The file is preserved as one independent conflict rather than discarded. Both contents remain readable on every replica, repeated saves create no duplicates, and CLI `resolve` can select the independent root and propagate its resolution. |
### Coverage boundaries
This is a service integration test, not a CLI subprocess or Obsidian runtime test. The file and provenance stores are in-memory fixtures; automatic conflict callbacks are observed without running interactive or automatic merge policies. PouchDB revision creation, chunk storage and retrieval, local compaction, CouchDB replication, the CLI command dispatcher, and its resolution operations are real.
Use the CLI and real-Obsidian procedures linked above for argument parsing, persistent host stores, file watchers, and dialogues. In particular, the real-Obsidian `stale-file-restart` scenario exercises persisted pending events and restart, and `folder-batch` exercises bulk Vault rename and deletion. These scenarios do not simulate a mobile operating system suspending the application.