Skip to content

Browser adapter compatibility ​

This guide records how SahajLipi checks its reusable browser adapters in desktop browser engines. The adapter supports <textarea> and text/search inputs. The API reference covers attachment, configuration, and cleanup; the separate demo guide describes the playground controls.

The engine's Unicode behavior contracts and language-review records measure different things. Browser tests check editing and integration behavior. They do not establish Nepali linguistic accuracy.

Publication follow-up (2026-10-03): 0.1.0-alpha.2 is now published on npm, and its registry artifact matches the reviewed source. The release record documents current distribution verification. The dated browser runs below retain their original source-candidate and local-tarball scope.

Alpha.3 publication follow-up (2026-10-09): the verified npm 0.1.0-alpha.3 archive matches the reviewed source. Fresh registry-installed vanilla and React examples passed 9/9 desktop checks, separate from the unchanged dated preparation runs below. See the alpha.3 distribution record for package identity and scoped JavaScript/TypeScript/browser evidence.

Alpha.4 publication follow-up (2026-10-09): the verified npm 0.1.0-alpha.4 archive includes the 34 native forms and matches the reviewed source. Fresh registry-installed vanilla and uncontrolled React examples passed 9/9 checks, three in each desktop engine, with no failures, skips, flaky outcomes, retries or uncaught page errors. The alpha.4 distribution record and publication JSON identify the archive, actual consumer run and scope. Existing desktop-001 through desktop-007 records keep their original local-source/tarball results.

Run locally ​

The core engine and Node test suite run on Node.js 18 or later with no runtime dependencies. The browser test tooling requires Node.js 20 or later, npm, and Python 3. Playwright is a development dependency pinned to 1.63.0; the lockfile records the dependency versions.

From the repository root:

sh
npm ci
npx playwright install chromium firefox webkit
npm run test:browser

On Linux, install the browser system dependencies as well:

sh
npx playwright install --with-deps chromium firefox webkit

npm run test:browser first builds the installed-package developer examples; a direct npx playwright test call requires npm run examples:build beforehand. The builder uses pinned React, TypeScript, and esbuild development dependencies without adding runtime dependencies to SahajLipi.

The test configuration starts an isolated Python HTTP server on 127.0.0.1:4180 and stops it when the run finishes. Keep that port available: the configuration refuses to reuse a server already on port 4180, so stop the conflicting server before retrying. It does not depend on an already running demo server or change the demo's local port.

Run one engine while developing a regression:

sh
npm run test:browser -- --project=chromium

Use --project=firefox or --project=webkit for the other configured engines. The HTML report is written to playwright-report/; the JSON report is test-results/browser-results.json. Failure screenshots and traces are kept under test-results/. These generated outputs are ignored by Git. Open the latest local HTML report with:

sh
npm run test:browser:report

Run the Node checks separately:

sh
npm test
npm run benchmark -- --check

A browser test failure is an editing or integration regression to investigate; changing a linguistic benchmark's expected spelling does not resolve it.

Test surfaces and scope ​

browser/typing.spec.js exercises the adapters through a dedicated browser/fixtures/adapters.html page and the demo. The fixture is a test harness, not a package example or a public editor component. playwright.config.js specifies browser projects, the local server, and reporting.

The suite distinguishes normal keyboard actions from injected event contracts:

CoverageEvidence and boundary
Direct typing and word boundariesBrowser keyboard actions assert full consonant defaults, automatic internal conjuncts, explicit backtick half forms, the ra-ya joiner, Shift sounds, bindu/chandrabindu, displayed text, and caret behavior.
Digits and configurationKeyboard actions check Devanagari defaults, unchanged decimal periods, numeric address-cue restoration, editing, Latin engine configuration, English mode and excluded fields; paste contracts use injected events.
Early address cuesIncremental keyboard input checks literal rendering after email, HTTP(S), www., and domain cues.
Selection, Backspace, undo, and redoKeyboard and selection actions check the adapter's edit state, including crossing an address cue.
Candidates and mode switchesAdapter and demo actions check selection of alternatives and continuation in Nepali or English mode.
Managed fieldsThe fixture checks marked, excluded, and dynamically added supported fields, plus controller cleanup.
Paste and completed compositionInjected clipboard/composition events check the adapter event contract. These events do not exercise the operating system clipboard or a real IME.
Native-input fallbackInjected input events without beforeinput check active-vowel and mixed-paste handling and host input-listener notifications. They do not establish mobile keyboard or framework-controlled field behavior.

Use the test names and attached failure traces to identify exactly which flow failed. Assertions concern the selected software behavior; this is not a general browser support certification.

Installed-package developer examples ​

browser/developer-examples.spec.js adds three consumer scenarios per engine:

  • Vanilla: marked-field conversion, candidate choices, Nepali/English switching, and English exclusions.
  • Vanilla: explicit teardown leaves subsequent text literal and removes its controls' behavior.
  • React: uncontrolled textarea state callbacks, candidate selection, modes, and effect cleanup/remount under development StrictMode.

tools/build-examples.js packs and installs the actual tarball in a standalone temporary app, copies the example source there, type-checks the React files, and bundles public package imports. It checks esbuild's module inputs to require the installed package and reject checkout source bypasses. These generated fixtures are ignored by Git. React's pinned version is 19.3.0; this checks the named uncontrolled-field recipe only. Framework-controlled fields, SSR/hydration, physical mobile keyboards, and assistive technology remain unverified. See integration recipes and release compatibility scope.

The separate desktop-003 record captures the later 51-check run (17 scenarios per engine), including the nine consumer checks. It records package and test source identities, installed-tarball checksum, environment, and outcomes. The 36- and 42-check records below remain historical and immutable; their totals describe their original runs.

Loanword suffix follow-up — 2026-10-01 ​

The desktop-004 record captures 57/57 passing checks: 19 scenarios in each of Chromium, Firefox and WebKit. Two added scenarios per engine check reviewed attached suffixes, the school spelling dropdown, Roman-source Backspace editing, address-cue restoration and English mode. Runtime and test source hashes identify this run; earlier desktop records retain their original scopes and counts.

A selected spelling survives ordinary punctuation and whitespace. A domain cue makes the Roman token literal; deleting that cue resumes its default spelling. This behavior was also confirmed against the pre-suffix adapter. It does not preserve the earlier candidate choice across a technical-token transition.

Native spelling follow-up — 2026-10-01 ​

The desktop-005 record captures 60/60 passing checks: 20 scenarios in each of Chromium, Firefox and WebKit. The added native-word scenario checks the four reviewed spellings, Roman-source Backspace editing, undo/redo and English mode. Installed-package JavaScript and TypeScript consumers passed for the 0.1.0-alpha.1 candidate; registry publication requires separate verification.

The record pins tested runtime, integration fixtures, package metadata and installed-tarball identity. The browser and adapter scope limits in this guide still apply. Earlier records retain their original tested sources and totals.

Full-consonant source candidate follow-up — 2026-10-03 ​

The desktop-006 record captures 66/66 passing checks for the unpublished 0.1.0-alpha.2 source candidate: 22 scenarios in each of Chromium, Firefox and WebKit. Each engine runs 19 typing scenarios and three installed-package integration scenarios. The final npm run test:browser run began at 2026-10-03T09:40:42.747Z on macOS arm64 with Node.js 22.22.3, Playwright 1.63.0, headless browsers, two workers, and no retries. It recorded zero failures, skips, flaky outcomes, or test/report errors.

ProjectEngine versionPassedFailedSkipped
chromium153.0.8010.1222/2200
firefox155.022/2200
webkit26.622/2200
Total22 scenarios × 3 projects66/6600

Keyboard scenarios check k → क, kr → क्र, kri → क्रि, and Backspace through the retained Roman spelling. The backtick scenario checks explicit half forms, a following independent vowel, the explicit joiner, word boundaries, and undo/redo. The demo setting scenario checks full/half conversion across marked fields, preservation of existing text and selection, and continuation in English mode. Its paste portion uses an injected clipboard event. The existing paste, composition, and native-input scenarios also use injected events; they do not exercise an operating system clipboard or an installed IME. See the consonant option and alpha.1 migration recipe.

The example builder packed and installed a local alpha.2 tarball, compiled the React example, and checked that both example bundles resolve installed public package exports. All nine installed vanilla/React browser checks passed. Separate npm run verify:package JavaScript and strict TypeScript checks passed for alpha.2. These checks establish local package integration; alpha.2 was unpublished at the time of those checks.

The record identifies the checkout based on 987e31f with SHA-256 hashes of runtime modules, declarations, demo, tests, configuration, and consumer source files. Its generated browser report and installed-example manifest have separate hashes. Later documentation edits are outside that source-hash scope and can change a later tarball; the recorded tarball is not asserted to match a later checkout. Desktop-001 through desktop-005 retain their original sources, outcomes, and counts. The desktop engine and integration limits below still apply; this run makes no mobile, OS clipboard, installed Safari, accessibility, or general linguistic-accuracy claim.

Native-form follow-up — 2026-10-09 ​

The desktop-007 record captures 69/69 passing checks: 23 scenarios in each of Chromium, Firefox and WebKit, with no failures, skips, flaky outcomes, retries or uncaught page errors. The recorded run used macOS arm64 with Node.js 22.22.3. The record includes the run timestamps and identifies all eight runtime/declaration files, test sources, the installed-example manifest and the actual local tarball used for that run.

The new desktop keyboard scenario selects the mahila, shanta and angrejharuko alternatives, then exercises editing, undo and English mode. The existing installed vanilla consumer also checks the mahila alternative. These tests accompany the 34-key native-form batch; they do not certify every listed form through every editor event. The previous 66-check desktop-006 record remains unchanged.

EngineScenariosPassedBrowser version
Chromium2323153.0.8010.12
Firefox2323155.0
WebKit232326.6
Total6969Recorded headless builds

A separate npm run verify:package passed JavaScript public-import, option and isolation checks, strict TypeScript NodeNext core without DOM, DOM and Bundler consumers, and execution of the emitted core tutorial in Node. Those package checks are outside the 69 browser count. The local installed package contains 13 allowlisted files and still carries the existing alpha.2 manifest version; it is modified unreleased source, not the published npm alpha.2 artifact. Its tarball checksum identifies the exact archive used during the recorded run.

These selected headless desktop flows retain the existing scope limits: injected clipboard/composition events do not establish OS clipboard or physical IME behavior, and the React example remains an uncontrolled textarea in development StrictMode. No controlled-field, mobile, assistive-technology or representative linguistic-accuracy result is added.

Desktop engine matrix ​

Playwright projectBrowser under testStatus evidence
chromiumPlaywright's Chromium buildInspect the recorded local run below or the matching GitHub Actions report.
firefoxPlaywright's Firefox buildInspect the recorded local run below or the matching GitHub Actions report.
webkitPlaywright's WebKit buildInspect the recorded local run below or the matching GitHub Actions report.

A passing result applies to the named engine build, platform, source revision, and tests in that run. Playwright WebKit is not the installed Safari application. Results from one operating system do not establish results on another, even for the same project name. A skipped case is not a pass.

Recorded run — 2026-09-27 ​

The committed desktop-001 record contains the dated test outcomes, individual test names, source hashes, environment, and limits. npm run test:browser began at 2026-09-27T12:06:12.781Z on macOS arm64 (darwin, OS release 25.6.0) with Node.js 22.22.3, Playwright 1.63.0, headless browsers, two workers, and no retries:

ProjectEngine versionPassedFailedSkipped
chromium153.0.8010.1212/1200
firefox155.012/1200
webkit26.612/1200
Total12 scenarios × 3 projects36/3600

The run recorded no flaky outcomes. These are automated desktop-engine results on this platform; Ubuntu CI results belong to their own workflow run. Keyboard actions come from Playwright. The three synthetic-event scenarios cover paste, composition, and the native-input fallback without establishing real clipboard or IME behavior.

The source identity is a modified working tree based on commit 995909554efa84691f5a481a0d27def58e308d2f, identified by SHA-256 hashes of the production modules, demo, spec, fixture, Playwright configuration, package manifests, lockfile, and browser workflow. Production source and linguistic benchmark files were unchanged from that base. Separate checks of the same source passed 212 Node tests and 125 seed behavior contracts; two existing exploratory cases remain outside the benchmark gate.

A separate negative control removed address preservation in a throwaway copy: the intermediate-address keyboard test failed once as expected. This shows that the named regression test detects that removed behavior; it does not prove that every possible editing defect is detected. The working tree's production code was unchanged by that check.

Verify the recorded source identity ​

The immutable merged commit 660d088ed60410feb0c6ad4c43d33214c24296f9 contains the files matching desktop-001. Archive it before reproducing this historical run so later engine, demo, or spec changes cannot silently replace the recorded source. The hash check below covers each recorded file:

sh
BROWSER_RECORDED_DIR=$(mktemp -d)
git archive 660d088ed60410feb0c6ad4c43d33214c24296f9 | tar -x -C "$BROWSER_RECORDED_DIR"
cd "$BROWSER_RECORDED_DIR"
node --input-type=module <<'NODE'
import { readFileSync } from 'node:fs';
import { createHash } from 'node:crypto';

const report = JSON.parse(readFileSync('browser/reports/desktop-001.json', 'utf8'));
const mismatches = [];
for (const [path, expected] of Object.entries(report.source.fileSha256)) {
  const actual = createHash('sha256').update(readFileSync(path)).digest('hex');
  if (actual !== expected) mismatches.push(path);
}
if (mismatches.length) throw new Error(`Recorded source differs: ${mismatches.join(', ')}`);
console.log('All recorded source hashes match.');
NODE

Then run the local setup commands above from that archived directory and compare project counts, engine versions, and platform with the record. Return to your working checkout afterward. Browser binaries are chosen by the pinned Playwright version and platform. A later source change or a different environment needs its own dated result; do not overwrite this record to match a new outcome.

The full raw JSON/HTML outputs are generated files, not committed records. The compact record preserves their recorded JSON hash and relevant outcomes, while local report files can be replaced by the next test run. GitHub Actions report artifacts have the retention period described below.

Digit follow-up — 2026-09-27 ​

The separate desktop-002 record measures the digit-default change and retains desktop-001 unchanged. npm run test:browser began at 2026-09-27T13:55:31.892Z on macOS arm64 (darwin, OS release 25.6.0) with Node.js 22.22.3, Playwright 1.63.0, headless browsers, two workers, and no retries:

ProjectEngine versionPassedFailedSkipped
chromium153.0.8010.1214/1400
firefox155.014/1400
webkit26.614/1400
Total14 scenarios × 3 projects42/4200

There were no flaky outcomes. Two appended scenarios cover digit typing/editing, periods in decimals, restoration of numeric address prefixes, the configured Latin engine, English mode, excluded fields, and injected paste. Existing decimal assertions now use the explicitly chosen Devanagari default; these counts are selected editing regressions under that policy, not an accuracy comparison on unchanged linguistic labels. The digit benchmark record separately discloses seven revised numeric expectations and historical Latin compatibility.

The source is a modified working tree based on 660d088ed60410feb0c6ad4c43d33214c24296f9, pinned by source, demo, spec, fixture, configuration, dependency, and workflow hashes. The production changes are src/index.js and its type declarations; the DOM adapter, lexicon, phonetic rules, and address scanner are unchanged. Separate checks passed 227/227 Node tests and 133/133 revised seed contracts. The explicit Latin engine also retains 125/125 historical contracts. The desktop and seed records measure separate test surfaces.

A negative control removed digit conversion in a throwaway copy; the named numeric-keyboard test failed once in Chromium as expected. The working source was unchanged. This demonstrates detection of that removed behavior only.

Verify the digit-run source identity ​

Use a checkout or archive matching desktop-002, then verify its hashes before reproducing the browser run. A later source or test change needs a separate dated record. From that matching source directory:

sh
node --input-type=module <<'NODE'
import { readFileSync } from 'node:fs';
import { createHash } from 'node:crypto';
const report = JSON.parse(readFileSync('browser/reports/desktop-002.json', 'utf8'));
for (const [path, expected] of Object.entries(report.source.fileSha256)) {
  const actual = createHash('sha256').update(readFileSync(path)).digest('hex');
  if (actual !== expected) throw new Error('Recorded source differs: ' + path);
}
console.log('All desktop-002 source hashes match.');
NODE

Run the local setup commands at the beginning of this guide from that directory. Compare the resulting individual outcomes, project counts, engine versions, and platform against desktop-002. The original 36-check run remains reproducible through its immutable archive commands above. Both records have the same desktop-engine and injected-event limits; neither establishes OS clipboard, real IME, mobile device, installed Safari, assistive technology, or framework-controlled input support.

GitHub Actions and reports ​

The dedicated browser workflow runs Chromium, Firefox, and WebKit as separate Ubuntu jobs using Node.js 22. It runs on pull requests and pushes to main; each job installs its own browser and Linux dependencies. The existing Node workflow keeps the engine and seed-contract checks on Node.js 18, 20, 22, and 24.

Open the workflow run associated with the pull request's exact head commit. Inspect each engine job's test summary; download browser-results-chromium, browser-results-firefox, or browser-results-webkit from the run's Artifacts section. Each artifact includes that job's HTML/JSON reports and collected failure traces/screenshots. Uploaded artifacts are retained for 14 days. CI artifacts are operational evidence with limited retention, not immutable linguistic benchmark records. A permanently documented run must record its source identity and environment separately.

The JSON report is useful for inspecting pass, failure, skip, retry, and duration data. The HTML report shows the tested flows and any collected traces. Browser timings are test diagnostics, not a throughput or transliteration performance benchmark. Automatic retries are disabled so a failing input flow cannot be hidden by an eventually passing retry.

An old green main badge does not establish that a new pull request passes. Verify the checks on the intended source commit before merging. The browser workflow defines its checks; repository protection settings determine which checks block a merge.

Not established by these tests ​

  • Real phone keyboards, Android or iOS devices, or mobile IME behavior.
  • Native operating system clipboard permissions and clipboard integration.
  • Real composition input from an installed IME; only the injected event contract is automated here.
  • Screen readers, other assistive technology, or accessibility conformance.
  • Installed Chrome, Firefox, or Safari application support on every operating system.
  • Framework-controlled field integration, such as React state reconciliation.
  • contenteditable, rich-text editors, or input types outside text/search and textarea.

For a browser issue, report the browser/application version, operating system, input surface, exact key or event sequence, expected and actual Unicode text, caret/selection, mode, and whether the reproduction uses a real keyboard, real clipboard, or injected events. Include a minimal reproduction when possible. The contribution guide explains how to add a focused regression.

Open source. Nepali first. Experimental developer alpha on npm.