FunctionalJavascript tests silently pass without built JS artifacts, fail on tags
<!-- Please search existing work items before filing to avoid duplicates. -->
## Summary
FunctionalJavascript tests produce different results depending on whether the JS UI assets have been built (`npm run build`). The built `dist/` directories are not committed to the repository during normal development — they are only added in tag commits by `scripts/tag-release.sh` and immediately removed in the following "Back to dev." commit. This means if a contributor running FunctionalJavascript tests locally without first building the JS gets a fundamentally different browser environment than CI or a tagged release, with no warning that the environments differ.
The 1.4.2 tag failure (#3586521) is a concrete example: every branch MR went green, but the pipeline failed the moment the tag was created — because that was the first time the built MDX editor was present in the browser environment.
## Steps to reproduce
1. Write or run a FunctionalJavascript test that interacts with a field controlled by one of the built JS editors (MDX editor, JSON schema editor, default tools editor, CKEditor AI)
1. Run the test locally without first running `npm run build` → test passes, because the editor never loads and the raw form element is directly accessible
1. The same test runs in CI or on a tag, where assets are built → test fails with a cryptic Selenium error because it looks or has different DOM structure there.
## Expected result
Maybe we find a way there for example: FunctionalJavascript test failures caused by missing or changed JS build artifacts should be caught during normal branch development — not at tag creation time. We should have a way to detect this class of failure before a release is ever cut.
## Discussion / proposed solutions
This is a backlog item to gather community input. Options worth discussing:
**Option 1 — Document the requirement**
Add a note to the testing documentation stating that FunctionalJavascript tests require `npm run build` to be run for each UI directory (`ui/mdxeditor`, `ui/default-tools-editor`, `ui/json-schema-editor`, `modules/ai_ckeditor`) before executing tests locally.
**Option 2 — Run FunctionalJavascript tests on every branch push**
Currently they only trigger on MR creation or tagging. Running them on every push would catch regressions earlier (at the cost of more pipeline minutes).
**Option 3 — Add a base-class guard**
Have `BaseClassFunctionalJavascriptTests::setUp()` detect missing `dist/` directories and fail fast with a clear human-readable message instead of a cryptic Selenium error.
**Option 4 — Add a lightweight CI pre-check**
A quick job that verifies the built assets are present before phpunit jobs start, so failures point at the missing build step rather than the test itself.
## Future risk which may be mitigated by this issue
`AiProviderConfigurationElementTest::testPseudoOperationTypes` loads the `chat_with_tools` operation type, which renders an `ai_json_schema` element backed by `ui/json-schema-editor/dist`. Currently it only asserts `elementExists` on a select and is not affected. However, if test steps are ever added that fill in JSON schema editor content, they will hit the same trap. Any test interacting with content inside `ai_json_schema`, `ai_tools_library`, or any other element backed by a built UI should use a helper (like `fillMdxEditorField()`) rather than `fillField()` directly.
<!-- If this issue description was significantly AI-generated (entire sections, not autocomplete), please note it in a comment below. See https://www.drupal.org/docs/develop/issues/issue-procedures-and-etiquette/policy-on-the-use-of-ai-when-contributing-to-drupal -->
_AI disclosure: I used Claude Code to review, analyse, summarise, and surface gaps. The reasoning and positions are my own. I reviewed everything before posting._
issue