[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-jetbrains-mps-tests":3,"mdc--j4db5o-key":32,"related-repo-jetbrains-mps-tests":1688,"related-org-jetbrains-mps-tests":1766},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":19,"repoUrl":20,"updatedAt":21,"license":22,"forks":23,"topics":24,"repo":27,"sourceUrl":30,"mdContent":31},"mps-tests","write and modify MPS model tests","Use when writing or modifying tests inside MPS `@tests` models — `NodesTestCase` (typesystem, constraints, scopes, dataflow, generator output), `EditorTestCase` (intentions, actions, keystrokes, side-transforms, completion), `MigrationTestCase` (migration scripts), `BTestCase` (plain JUnit on hand-written Java\u002FKotlin runtime), inline annotations such as `has error` \u002F `has type` \u002F `ScopesTest`, label-based `node\u003Clabel>` cross-references, caret markers, and running tests via MCP \u002F in MPS. Reach for this skill whenever the task involves authoring or fixing tests in a `tests`-stereotype model, or interpreting failures from one.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},"jetbrains","JetBrains","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fjetbrains.png",[12,16],{"name":13,"slug":14,"type":15},"QA","qa","tag",{"name":17,"slug":18,"type":15},"Testing","testing",1650,"https:\u002F\u002Fgithub.com\u002FJetBrains\u002FMPS","2026-07-20T05:56:49.396279",null,311,[25,26],"domain-specific-language","dsl",{"repoUrl":20,"stars":19,"forks":23,"topics":28,"description":29},[25,26],"JetBrains Meta programming System","https:\u002F\u002Fgithub.com\u002FJetBrains\u002FMPS\u002Ftree\u002FHEAD\u002Fplugins\u002Fmcp-tools\u002Fresources\u002Fjetbrains\u002Fmps\u002Fagents\u002Fmcp\u002Fskills\u002Fmps-tests","---\nname: mps-tests\ndescription: Use when writing or modifying tests inside MPS `@tests` models — `NodesTestCase` (typesystem, constraints, scopes, dataflow, generator output), `EditorTestCase` (intentions, actions, keystrokes, side-transforms, completion), `MigrationTestCase` (migration scripts), `BTestCase` (plain JUnit on hand-written Java\u002FKotlin runtime), inline annotations such as `has error` \u002F `has type` \u002F `ScopesTest`, label-based `node\u003Clabel>` cross-references, caret markers, and running tests via MCP \u002F in MPS. Reach for this skill whenever the task involves authoring or fixing tests in a `tests`-stereotype model, or interpreting failures from one.\ntype: reference\n---\n\n# Writing Tests in MPS Models\n\nMPS ships a dedicated **test language** — `jetbrains.mps.lang.test` — for testing language artefacts (typesystem, scopes, constraints, dataflow, editor, generator, migrations). Plain JUnit-style tests against runtime classes use `jetbrains.mps.baseLanguage.unitTest` (the `BTestCase` concept).\n\nA test is a **root node** living in a model whose **stereotype is `tests`** (pass `modelName: \"\u003Cname>@tests\"` to `mps_mcp_create_model`; the on-disk file ends in `@tests.mps`). See [aspect-model-stereotypes.md](..\u002Fmps-mcp-workflow\u002Freferences\u002Faspect-model-stereotypes.md) for all model identifiers. The test model lives in a Solution module carrying the **`tests` facet**, not in the language module itself, so it can depend on the language under test plus arbitrary runtime libraries.\n\nThis skill is the reference for *what to put in a test model* and *what each test type means*. For the mechanics of creating\u002Fmodifying nodes via MCP, see `mps-model-manipulation` and the `mps_mcp_*` tool docs. Documentation: \u003Chttps:\u002F\u002Fwww.jetbrains.com\u002Fhelp\u002Fmps\u002Ftesting-languages.html>. Source: `plugins\u002Fmps-testing\u002Flanguages\u002Flang.test\u002F`.\n\n## Critical Directives\n\n- The test model **must** carry stereotype `tests` (file name `…@tests.mps`). Without it, roots compile but are not discovered as JUnit tests.\n- Used languages on a test model: `jetbrains.mps.lang.test`, `jetbrains.mps.baseLanguage.unitTest`, the language(s) under test, plus `jetbrains.mps.baseLanguage`, `jetbrains.mps.baseLanguage.collections`, `jetbrains.mps.lang.smodel`, `jetbrains.mps.lang.text` as needed by assertion code.\n- The containing Solution must carry the **`tests` facet**. Languages and Generators don't compile the test classes, so the test root must live in this dedicated Solution. Create it via `mps_mcp_create_module(type=\"solution\", …, facets=\"[\\\"tests\\\"]\")`; the response is self-describing — `{\"data\":{\"kind\":\"Solution\",\"facets\":[\"java\",\"tests\"],\"loadExtensions\":\"NotAvailable\",…}}` confirms the kind without a follow-up call. For an existing Solution, attach the facet via `mps_mcp_update_module_facet(facetType=\"tests\", enabled=true)` and verify with `mps_mcp_get_project_structure(startingPoint=\"…\")` (its `facets` array will include `\"tests\"`).\n- The `testMethods` role declares `NodesTestMethod`, which is **abstract** — instantiate `SimpleNodeTest` (`c:8585453e-6bfb-4d80-98de-b16074f1d86c\u002F1225978065297`). Inserting raw `NodesTestMethod` fails with `\"Abstract concept instance detected\"`.\n- Inside snippets, `TestNodeAnnotation` labels are **only** resolvable via `TestNodeReference` from test-method bodies. For *in-snippet* references (e.g. setting `RoutineCall.routine`) use the target node's own `name` property (resolved through the language's scope) or a persistent `r:` node ref, never the label name.\n- Prefer `invoke action \u003CActionId>` over raw `press \u003Cchord>` for Enter\u002FTab\u002Fetc. in `EditorTestCase` — `PressKeyStatement` may bypass the named-action dispatcher used by the production editor. Editor actions live in `r:9832fb5f-2578-4b58-8014-a5de79da988e(jetbrains.mps.ide.editor.actions)`.\n- For an empty list role, target `empty_\u003Crole>` for the caret — *not* `refNodeList_\u003Crole>` (the latter is the populated wrapper cell).\n- Never edit `test_gen\u002F` or `classes_gen\u002F` — those are regenerated.\n\n## Common-Path Workflow\n\nWhen asked to \"write tests\" for an MPS language feature:\n\n1. **Decide the test type.** Typesystem \u002F scope \u002F constraint → `NodesTestCase`. Intention \u002F action \u002F keystroke → `EditorTestCase`. Migration → `MigrationTestCase`. Runtime helper → `BTestCase`. Generator output equivalence → `NodesTestCase` + `assertNodesMatch`. See `references\u002Ftest-types.md`.\n2. **Find or create the test model.** Prefer extending an existing `@tests` model in the language's adjacent test Solution; only create a new one if no suitable Solution exists.\n3. **Add the test root** with `mps_mcp_create_root_node` using the concept ref from `references\u002Fconcept-identifiers.md`, then populate `nodes` \u002F `code` \u002F etc. with `mps_mcp_update_node`. Use `mps_mcp_parse_java_and_insert` to drop a Java\u002FBaseLanguage snippet into a `TestNode`.\n4. **Mark assertions** using the appropriate annotation concept (see `references\u002Fnodes-test-case.md` and `references\u002Feditor-test-case.md`). For prototypes, open the model in MPS and use the Alt+Enter intentions (\"Add Node Operations Test Annotation\", \"Add Test Node Label\", \"Mark Caret Position\") — they create the right annotations without hand-building blueprints.\n5. **Validate** with `mps_mcp_check_root_node_problems` on the new root.\n6. **Run.** Register a `JUnit Tests` config via `mps_mcp_create_run_configuration` (pass the test root's reference) and launch it with `execute_run_configuration`, or ask the user to run it in MPS.\n\n## Where Test Models Live\n\n| Where | When |\n|---|---|\n| **Test aspect** of the language (`testAspect` model under `\u003Clang>\u002F`) | Quick, language-local checks; cannot run in a fresh MPS instance from outside the language. |\n| **Dedicated test Solution** with `@tests` model | Recommended for anything serious. Runs out-of-process; can be wired into the build\u002FCI. |\n\nIf the only goal is plain JUnit on hand-written Java\u002FKotlin (no MPS-specific assertions), prefer a regular module test source root rather than a `@tests` model — see `mps-distribution-build` for how `BTestCase`-based MPS test modules are packaged.\n\n## Related Skills\n\n- `mps-model-manipulation` — the smodel \u002F closures \u002F collections reference for assertion bodies.\n- `mps-node-editing` — MCP recipes for inserting children and harvesting persistent refs (used heavily by the `ScopesTest` staged-construction recipe).\n- `mps-aspect-typesystem` — when the system-under-test is the typesystem; `has error\u002Ftype` annotations here verify those rules.\n- `mps-aspect-constraints` — when validating `can-be` \u002F scope \u002F validator rules from the constraints aspect.\n- `mps-aspect-migrations` — for migration scripts being exercised by `MigrationTestCase`.\n- `mps-aspect-intentions` and `mps-aspect-editor-menus-and-keymaps` — when an `EditorTestCase` exercises intentions, side transforms, or keymapped actions.\n- `mps-build-language` and `mps-distribution-build` — when wiring a `@tests` Solution into the build pipeline (test-only `BuildProject`).\n- `mps-quotations` — for tests that use quotation snippets.\n\n## Reference Index\n\n- Open `references\u002Ftest-model-setup.md` when bootstrapping a new `@tests` model — required stereotype, used languages, Solution kind, optional `TestInfo` root, and the choice between the language's `testAspect` and a dedicated test Solution. Includes the canonical example test Solutions in this repo.\n- Open `references\u002Ftest-types.md` for the test-type cheat sheet (concept refs and what each tests). Use to decide which root concept to instantiate.\n- Open `references\u002Fnodes-test-case.md` when authoring or modifying a `NodesTestCase` — section layout (`nodes`, `test methods`, `utility methods`, `accessMode`), inline assertion annotations (`has error`, `has type`, `has typesystem error`, `has expected type`, `has type in`), labelled-node assertions inside test methods, and the namespace separation between labels and scope-resolved references.\n- Open `references\u002Fscopes-test.md` when writing **declarative** scope assertions (`ScopesTest` + `ScopesExpectedNode`) — where to attach the annotation, the exact-set semantics, the JSON blueprint, the stage-construction recipe for resolving expected refs, and why declarative scope tests beat imperative ones.\n- Open `references\u002Feditor-test-case.md` when writing an `EditorTestCase` — root layout (`before` \u002F `result` \u002F `code`), the `AnonymousCellAnnotation` caret marker, the cell-ID convention for auto-generated editors (`property_\u003Cname>`, `refNodeList_\u003Crole>`, `empty_\u003Crole>`, `refNode_\u003Crole>`, constant\u002Fcollection cells), the editor-driving statements (`type \"...\"`, `press`, `invoke action`, `invoke intention`, `invoke quick-fix`), the editor expressions usable inside `code` (`EditorComponentExpression` → `getEditorComponent()`, `IsIntentionApplicableExpression` → `isIntentionApplicable()`, `ProjectExpression` → `getProject()`, `ModelExpression` → model of the edited node), and the side-transform \u002F completion testing pattern.\n- Open `references\u002Fgenerator-and-migration-tests.md` when validating generator output (`NodesTestCase` + `assertNodesMatch`) or testing a migration script (`MigrationTestCase` — `inputNodes`, `outputNodes`, `migration` refs, `option`s including `StableIdOption`). Lists the four-child structure of `MigrationTestCase` and the \"Generate Output from Input\" intention.\n- Open `references\u002Fbtestcase.md` when writing plain JUnit-style tests against hand-written Java\u002FKotlin — the `BTestCase` annotation, `TestMethod` \u002F `BeforeTest` \u002F `AfterTest`, and the available assertion concepts.\n- Open `references\u002Frunning-tests.md` when launching tests — inside MPS (right-click → Run tests), from the command line via the Ant pipeline, or from an agent via `mps_mcp_create_run_configuration` + `execute_run_configuration`. Covers in-process vs separate-MPS-instance, and `mps_mcp_check_root_node_problems` as a fast pre-run gate.\n- Open `references\u002Fcommon-failures.md` when a test won't run, runs but doesn't fail when expected, fails for the wrong reason, or generates a misleading `outputNodes`. Includes the abstract-concept gotcha, label-vs-name confusion, `press VK_ENTER` vs `invoke action Insert`, `replace_node_child` ref invalidation, and `ScopesExpectedNode.ref` not being scope-resolved.\n- Open `references\u002Fconcept-identifiers.md` for the validated FQN+concept-ref table covering `jetbrains.mps.lang.test` (every concept used by the skill — `NodesTestCase`, `SimpleNodeTest`, `TestNode`, `TestNodeAnnotation`, `AnonymousCellAnnotation`, the annotation\u002Fcheck operations, the editor-driving statements, `ScopesTest`\u002F`ScopesExpectedNode`, etc.) and `jetbrains.mps.baseLanguage.unitTest`.\n",{"data":33,"body":35},{"name":4,"description":6,"type":34},"reference",{"type":36,"children":37},"root",[38,47,86,156,209,216,569,575,580,804,810,896,923,929,1083,1089],{"type":39,"tag":40,"props":41,"children":43},"element","h1",{"id":42},"writing-tests-in-mps-models",[44],{"type":45,"value":46},"text","Writing Tests in MPS Models",{"type":39,"tag":48,"props":49,"children":50},"p",{},[51,53,59,61,68,70,76,78,84],{"type":45,"value":52},"MPS ships a dedicated ",{"type":39,"tag":54,"props":55,"children":56},"strong",{},[57],{"type":45,"value":58},"test language",{"type":45,"value":60}," — ",{"type":39,"tag":62,"props":63,"children":65},"code",{"className":64},[],[66],{"type":45,"value":67},"jetbrains.mps.lang.test",{"type":45,"value":69}," — for testing language artefacts (typesystem, scopes, constraints, dataflow, editor, generator, migrations). Plain JUnit-style tests against runtime classes use ",{"type":39,"tag":62,"props":71,"children":73},{"className":72},[],[74],{"type":45,"value":75},"jetbrains.mps.baseLanguage.unitTest",{"type":45,"value":77}," (the ",{"type":39,"tag":62,"props":79,"children":81},{"className":80},[],[82],{"type":45,"value":83},"BTestCase",{"type":45,"value":85}," concept).",{"type":39,"tag":48,"props":87,"children":88},{},[89,91,96,98,109,111,117,119,125,127,133,135,142,144,154],{"type":45,"value":90},"A test is a ",{"type":39,"tag":54,"props":92,"children":93},{},[94],{"type":45,"value":95},"root node",{"type":45,"value":97}," living in a model whose ",{"type":39,"tag":54,"props":99,"children":100},{},[101,103],{"type":45,"value":102},"stereotype is ",{"type":39,"tag":62,"props":104,"children":106},{"className":105},[],[107],{"type":45,"value":108},"tests",{"type":45,"value":110}," (pass ",{"type":39,"tag":62,"props":112,"children":114},{"className":113},[],[115],{"type":45,"value":116},"modelName: \"\u003Cname>@tests\"",{"type":45,"value":118}," to ",{"type":39,"tag":62,"props":120,"children":122},{"className":121},[],[123],{"type":45,"value":124},"mps_mcp_create_model",{"type":45,"value":126},"; the on-disk file ends in ",{"type":39,"tag":62,"props":128,"children":130},{"className":129},[],[131],{"type":45,"value":132},"@tests.mps",{"type":45,"value":134},"). See ",{"type":39,"tag":136,"props":137,"children":139},"a",{"href":138},"..\u002Fmps-mcp-workflow\u002Freferences\u002Faspect-model-stereotypes.md",[140],{"type":45,"value":141},"aspect-model-stereotypes.md",{"type":45,"value":143}," for all model identifiers. The test model lives in a Solution module carrying the ",{"type":39,"tag":54,"props":145,"children":146},{},[147,152],{"type":39,"tag":62,"props":148,"children":150},{"className":149},[],[151],{"type":45,"value":108},{"type":45,"value":153}," facet",{"type":45,"value":155},", not in the language module itself, so it can depend on the language under test plus arbitrary runtime libraries.",{"type":39,"tag":48,"props":157,"children":158},{},[159,161,167,169,174,176,182,184,190,192,199,201,207],{"type":45,"value":160},"This skill is the reference for ",{"type":39,"tag":162,"props":163,"children":164},"em",{},[165],{"type":45,"value":166},"what to put in a test model",{"type":45,"value":168}," and ",{"type":39,"tag":162,"props":170,"children":171},{},[172],{"type":45,"value":173},"what each test type means",{"type":45,"value":175},". For the mechanics of creating\u002Fmodifying nodes via MCP, see ",{"type":39,"tag":62,"props":177,"children":179},{"className":178},[],[180],{"type":45,"value":181},"mps-model-manipulation",{"type":45,"value":183}," and the ",{"type":39,"tag":62,"props":185,"children":187},{"className":186},[],[188],{"type":45,"value":189},"mps_mcp_*",{"type":45,"value":191}," tool docs. Documentation: ",{"type":39,"tag":136,"props":193,"children":197},{"href":194,"rel":195},"https:\u002F\u002Fwww.jetbrains.com\u002Fhelp\u002Fmps\u002Ftesting-languages.html",[196],"nofollow",[198],{"type":45,"value":194},{"type":45,"value":200},". Source: ",{"type":39,"tag":62,"props":202,"children":204},{"className":203},[],[205],{"type":45,"value":206},"plugins\u002Fmps-testing\u002Flanguages\u002Flang.test\u002F",{"type":45,"value":208},".",{"type":39,"tag":210,"props":211,"children":213},"h2",{"id":212},"critical-directives",[214],{"type":45,"value":215},"Critical Directives",{"type":39,"tag":217,"props":218,"children":219},"ul",{},[220,248,296,360,418,477,520,548],{"type":39,"tag":221,"props":222,"children":223},"li",{},[224,226,231,233,238,240,246],{"type":45,"value":225},"The test model ",{"type":39,"tag":54,"props":227,"children":228},{},[229],{"type":45,"value":230},"must",{"type":45,"value":232}," carry stereotype ",{"type":39,"tag":62,"props":234,"children":236},{"className":235},[],[237],{"type":45,"value":108},{"type":45,"value":239}," (file name ",{"type":39,"tag":62,"props":241,"children":243},{"className":242},[],[244],{"type":45,"value":245},"…@tests.mps",{"type":45,"value":247},"). Without it, roots compile but are not discovered as JUnit tests.",{"type":39,"tag":221,"props":249,"children":250},{},[251,253,258,260,265,267,273,274,280,281,287,288,294],{"type":45,"value":252},"Used languages on a test model: ",{"type":39,"tag":62,"props":254,"children":256},{"className":255},[],[257],{"type":45,"value":67},{"type":45,"value":259},", ",{"type":39,"tag":62,"props":261,"children":263},{"className":262},[],[264],{"type":45,"value":75},{"type":45,"value":266},", the language(s) under test, plus ",{"type":39,"tag":62,"props":268,"children":270},{"className":269},[],[271],{"type":45,"value":272},"jetbrains.mps.baseLanguage",{"type":45,"value":259},{"type":39,"tag":62,"props":275,"children":277},{"className":276},[],[278],{"type":45,"value":279},"jetbrains.mps.baseLanguage.collections",{"type":45,"value":259},{"type":39,"tag":62,"props":282,"children":284},{"className":283},[],[285],{"type":45,"value":286},"jetbrains.mps.lang.smodel",{"type":45,"value":259},{"type":39,"tag":62,"props":289,"children":291},{"className":290},[],[292],{"type":45,"value":293},"jetbrains.mps.lang.text",{"type":45,"value":295}," as needed by assertion code.",{"type":39,"tag":221,"props":297,"children":298},{},[299,301,310,312,318,320,326,328,334,336,342,344,350,352,358],{"type":45,"value":300},"The containing Solution must carry the ",{"type":39,"tag":54,"props":302,"children":303},{},[304,309],{"type":39,"tag":62,"props":305,"children":307},{"className":306},[],[308],{"type":45,"value":108},{"type":45,"value":153},{"type":45,"value":311},". Languages and Generators don't compile the test classes, so the test root must live in this dedicated Solution. Create it via ",{"type":39,"tag":62,"props":313,"children":315},{"className":314},[],[316],{"type":45,"value":317},"mps_mcp_create_module(type=\"solution\", …, facets=\"[\\\"tests\\\"]\")",{"type":45,"value":319},"; the response is self-describing — ",{"type":39,"tag":62,"props":321,"children":323},{"className":322},[],[324],{"type":45,"value":325},"{\"data\":{\"kind\":\"Solution\",\"facets\":[\"java\",\"tests\"],\"loadExtensions\":\"NotAvailable\",…}}",{"type":45,"value":327}," confirms the kind without a follow-up call. For an existing Solution, attach the facet via ",{"type":39,"tag":62,"props":329,"children":331},{"className":330},[],[332],{"type":45,"value":333},"mps_mcp_update_module_facet(facetType=\"tests\", enabled=true)",{"type":45,"value":335}," and verify with ",{"type":39,"tag":62,"props":337,"children":339},{"className":338},[],[340],{"type":45,"value":341},"mps_mcp_get_project_structure(startingPoint=\"…\")",{"type":45,"value":343}," (its ",{"type":39,"tag":62,"props":345,"children":347},{"className":346},[],[348],{"type":45,"value":349},"facets",{"type":45,"value":351}," array will include ",{"type":39,"tag":62,"props":353,"children":355},{"className":354},[],[356],{"type":45,"value":357},"\"tests\"",{"type":45,"value":359},").",{"type":39,"tag":221,"props":361,"children":362},{},[363,365,371,373,379,381,386,388,394,396,402,404,409,411,417],{"type":45,"value":364},"The ",{"type":39,"tag":62,"props":366,"children":368},{"className":367},[],[369],{"type":45,"value":370},"testMethods",{"type":45,"value":372}," role declares ",{"type":39,"tag":62,"props":374,"children":376},{"className":375},[],[377],{"type":45,"value":378},"NodesTestMethod",{"type":45,"value":380},", which is ",{"type":39,"tag":54,"props":382,"children":383},{},[384],{"type":45,"value":385},"abstract",{"type":45,"value":387}," — instantiate ",{"type":39,"tag":62,"props":389,"children":391},{"className":390},[],[392],{"type":45,"value":393},"SimpleNodeTest",{"type":45,"value":395}," (",{"type":39,"tag":62,"props":397,"children":399},{"className":398},[],[400],{"type":45,"value":401},"c:8585453e-6bfb-4d80-98de-b16074f1d86c\u002F1225978065297",{"type":45,"value":403},"). Inserting raw ",{"type":39,"tag":62,"props":405,"children":407},{"className":406},[],[408],{"type":45,"value":378},{"type":45,"value":410}," fails with ",{"type":39,"tag":62,"props":412,"children":414},{"className":413},[],[415],{"type":45,"value":416},"\"Abstract concept instance detected\"",{"type":45,"value":208},{"type":39,"tag":221,"props":419,"children":420},{},[421,423,429,431,436,438,444,446,451,453,459,461,467,469,475],{"type":45,"value":422},"Inside snippets, ",{"type":39,"tag":62,"props":424,"children":426},{"className":425},[],[427],{"type":45,"value":428},"TestNodeAnnotation",{"type":45,"value":430}," labels are ",{"type":39,"tag":54,"props":432,"children":433},{},[434],{"type":45,"value":435},"only",{"type":45,"value":437}," resolvable via ",{"type":39,"tag":62,"props":439,"children":441},{"className":440},[],[442],{"type":45,"value":443},"TestNodeReference",{"type":45,"value":445}," from test-method bodies. For ",{"type":39,"tag":162,"props":447,"children":448},{},[449],{"type":45,"value":450},"in-snippet",{"type":45,"value":452}," references (e.g. setting ",{"type":39,"tag":62,"props":454,"children":456},{"className":455},[],[457],{"type":45,"value":458},"RoutineCall.routine",{"type":45,"value":460},") use the target node's own ",{"type":39,"tag":62,"props":462,"children":464},{"className":463},[],[465],{"type":45,"value":466},"name",{"type":45,"value":468}," property (resolved through the language's scope) or a persistent ",{"type":39,"tag":62,"props":470,"children":472},{"className":471},[],[473],{"type":45,"value":474},"r:",{"type":45,"value":476}," node ref, never the label name.",{"type":39,"tag":221,"props":478,"children":479},{},[480,482,488,490,496,498,504,505,511,513,519],{"type":45,"value":481},"Prefer ",{"type":39,"tag":62,"props":483,"children":485},{"className":484},[],[486],{"type":45,"value":487},"invoke action \u003CActionId>",{"type":45,"value":489}," over raw ",{"type":39,"tag":62,"props":491,"children":493},{"className":492},[],[494],{"type":45,"value":495},"press \u003Cchord>",{"type":45,"value":497}," for Enter\u002FTab\u002Fetc. in ",{"type":39,"tag":62,"props":499,"children":501},{"className":500},[],[502],{"type":45,"value":503},"EditorTestCase",{"type":45,"value":60},{"type":39,"tag":62,"props":506,"children":508},{"className":507},[],[509],{"type":45,"value":510},"PressKeyStatement",{"type":45,"value":512}," may bypass the named-action dispatcher used by the production editor. Editor actions live in ",{"type":39,"tag":62,"props":514,"children":516},{"className":515},[],[517],{"type":45,"value":518},"r:9832fb5f-2578-4b58-8014-a5de79da988e(jetbrains.mps.ide.editor.actions)",{"type":45,"value":208},{"type":39,"tag":221,"props":521,"children":522},{},[523,525,531,533,538,540,546],{"type":45,"value":524},"For an empty list role, target ",{"type":39,"tag":62,"props":526,"children":528},{"className":527},[],[529],{"type":45,"value":530},"empty_\u003Crole>",{"type":45,"value":532}," for the caret — ",{"type":39,"tag":162,"props":534,"children":535},{},[536],{"type":45,"value":537},"not",{"type":45,"value":539}," ",{"type":39,"tag":62,"props":541,"children":543},{"className":542},[],[544],{"type":45,"value":545},"refNodeList_\u003Crole>",{"type":45,"value":547}," (the latter is the populated wrapper cell).",{"type":39,"tag":221,"props":549,"children":550},{},[551,553,559,561,567],{"type":45,"value":552},"Never edit ",{"type":39,"tag":62,"props":554,"children":556},{"className":555},[],[557],{"type":45,"value":558},"test_gen\u002F",{"type":45,"value":560}," or ",{"type":39,"tag":62,"props":562,"children":564},{"className":563},[],[565],{"type":45,"value":566},"classes_gen\u002F",{"type":45,"value":568}," — those are regenerated.",{"type":39,"tag":210,"props":570,"children":572},{"id":571},"common-path-workflow",[573],{"type":45,"value":574},"Common-Path Workflow",{"type":39,"tag":48,"props":576,"children":577},{},[578],{"type":45,"value":579},"When asked to \"write tests\" for an MPS language feature:",{"type":39,"tag":581,"props":582,"children":583},"ol",{},[584,646,664,728,753,770],{"type":39,"tag":221,"props":585,"children":586},{},[587,592,594,600,602,607,609,615,617,622,624,629,631,637,639,645],{"type":39,"tag":54,"props":588,"children":589},{},[590],{"type":45,"value":591},"Decide the test type.",{"type":45,"value":593}," Typesystem \u002F scope \u002F constraint → ",{"type":39,"tag":62,"props":595,"children":597},{"className":596},[],[598],{"type":45,"value":599},"NodesTestCase",{"type":45,"value":601},". Intention \u002F action \u002F keystroke → ",{"type":39,"tag":62,"props":603,"children":605},{"className":604},[],[606],{"type":45,"value":503},{"type":45,"value":608},". Migration → ",{"type":39,"tag":62,"props":610,"children":612},{"className":611},[],[613],{"type":45,"value":614},"MigrationTestCase",{"type":45,"value":616},". Runtime helper → ",{"type":39,"tag":62,"props":618,"children":620},{"className":619},[],[621],{"type":45,"value":83},{"type":45,"value":623},". Generator output equivalence → ",{"type":39,"tag":62,"props":625,"children":627},{"className":626},[],[628],{"type":45,"value":599},{"type":45,"value":630}," + ",{"type":39,"tag":62,"props":632,"children":634},{"className":633},[],[635],{"type":45,"value":636},"assertNodesMatch",{"type":45,"value":638},". See ",{"type":39,"tag":62,"props":640,"children":642},{"className":641},[],[643],{"type":45,"value":644},"references\u002Ftest-types.md",{"type":45,"value":208},{"type":39,"tag":221,"props":647,"children":648},{},[649,654,656,662],{"type":39,"tag":54,"props":650,"children":651},{},[652],{"type":45,"value":653},"Find or create the test model.",{"type":45,"value":655}," Prefer extending an existing ",{"type":39,"tag":62,"props":657,"children":659},{"className":658},[],[660],{"type":45,"value":661},"@tests",{"type":45,"value":663}," model in the language's adjacent test Solution; only create a new one if no suitable Solution exists.",{"type":39,"tag":221,"props":665,"children":666},{},[667,672,674,680,682,688,690,696,698,703,705,711,713,719,721,727],{"type":39,"tag":54,"props":668,"children":669},{},[670],{"type":45,"value":671},"Add the test root",{"type":45,"value":673}," with ",{"type":39,"tag":62,"props":675,"children":677},{"className":676},[],[678],{"type":45,"value":679},"mps_mcp_create_root_node",{"type":45,"value":681}," using the concept ref from ",{"type":39,"tag":62,"props":683,"children":685},{"className":684},[],[686],{"type":45,"value":687},"references\u002Fconcept-identifiers.md",{"type":45,"value":689},", then populate ",{"type":39,"tag":62,"props":691,"children":693},{"className":692},[],[694],{"type":45,"value":695},"nodes",{"type":45,"value":697}," \u002F ",{"type":39,"tag":62,"props":699,"children":701},{"className":700},[],[702],{"type":45,"value":62},{"type":45,"value":704}," \u002F etc. with ",{"type":39,"tag":62,"props":706,"children":708},{"className":707},[],[709],{"type":45,"value":710},"mps_mcp_update_node",{"type":45,"value":712},". Use ",{"type":39,"tag":62,"props":714,"children":716},{"className":715},[],[717],{"type":45,"value":718},"mps_mcp_parse_java_and_insert",{"type":45,"value":720}," to drop a Java\u002FBaseLanguage snippet into a ",{"type":39,"tag":62,"props":722,"children":724},{"className":723},[],[725],{"type":45,"value":726},"TestNode",{"type":45,"value":208},{"type":39,"tag":221,"props":729,"children":730},{},[731,736,738,744,745,751],{"type":39,"tag":54,"props":732,"children":733},{},[734],{"type":45,"value":735},"Mark assertions",{"type":45,"value":737}," using the appropriate annotation concept (see ",{"type":39,"tag":62,"props":739,"children":741},{"className":740},[],[742],{"type":45,"value":743},"references\u002Fnodes-test-case.md",{"type":45,"value":168},{"type":39,"tag":62,"props":746,"children":748},{"className":747},[],[749],{"type":45,"value":750},"references\u002Feditor-test-case.md",{"type":45,"value":752},"). For prototypes, open the model in MPS and use the Alt+Enter intentions (\"Add Node Operations Test Annotation\", \"Add Test Node Label\", \"Mark Caret Position\") — they create the right annotations without hand-building blueprints.",{"type":39,"tag":221,"props":754,"children":755},{},[756,761,762,768],{"type":39,"tag":54,"props":757,"children":758},{},[759],{"type":45,"value":760},"Validate",{"type":45,"value":673},{"type":39,"tag":62,"props":763,"children":765},{"className":764},[],[766],{"type":45,"value":767},"mps_mcp_check_root_node_problems",{"type":45,"value":769}," on the new root.",{"type":39,"tag":221,"props":771,"children":772},{},[773,778,780,786,788,794,796,802],{"type":39,"tag":54,"props":774,"children":775},{},[776],{"type":45,"value":777},"Run.",{"type":45,"value":779}," Register a ",{"type":39,"tag":62,"props":781,"children":783},{"className":782},[],[784],{"type":45,"value":785},"JUnit Tests",{"type":45,"value":787}," config via ",{"type":39,"tag":62,"props":789,"children":791},{"className":790},[],[792],{"type":45,"value":793},"mps_mcp_create_run_configuration",{"type":45,"value":795}," (pass the test root's reference) and launch it with ",{"type":39,"tag":62,"props":797,"children":799},{"className":798},[],[800],{"type":45,"value":801},"execute_run_configuration",{"type":45,"value":803},", or ask the user to run it in MPS.",{"type":39,"tag":210,"props":805,"children":807},{"id":806},"where-test-models-live",[808],{"type":45,"value":809},"Where Test Models Live",{"type":39,"tag":811,"props":812,"children":813},"table",{},[814,833],{"type":39,"tag":815,"props":816,"children":817},"thead",{},[818],{"type":39,"tag":819,"props":820,"children":821},"tr",{},[822,828],{"type":39,"tag":823,"props":824,"children":825},"th",{},[826],{"type":45,"value":827},"Where",{"type":39,"tag":823,"props":829,"children":830},{},[831],{"type":45,"value":832},"When",{"type":39,"tag":834,"props":835,"children":836},"tbody",{},[837,872],{"type":39,"tag":819,"props":838,"children":839},{},[840,867],{"type":39,"tag":841,"props":842,"children":843},"td",{},[844,849,851,857,859,865],{"type":39,"tag":54,"props":845,"children":846},{},[847],{"type":45,"value":848},"Test aspect",{"type":45,"value":850}," of the language (",{"type":39,"tag":62,"props":852,"children":854},{"className":853},[],[855],{"type":45,"value":856},"testAspect",{"type":45,"value":858}," model under ",{"type":39,"tag":62,"props":860,"children":862},{"className":861},[],[863],{"type":45,"value":864},"\u003Clang>\u002F",{"type":45,"value":866},")",{"type":39,"tag":841,"props":868,"children":869},{},[870],{"type":45,"value":871},"Quick, language-local checks; cannot run in a fresh MPS instance from outside the language.",{"type":39,"tag":819,"props":873,"children":874},{},[875,891],{"type":39,"tag":841,"props":876,"children":877},{},[878,883,884,889],{"type":39,"tag":54,"props":879,"children":880},{},[881],{"type":45,"value":882},"Dedicated test Solution",{"type":45,"value":673},{"type":39,"tag":62,"props":885,"children":887},{"className":886},[],[888],{"type":45,"value":661},{"type":45,"value":890}," model",{"type":39,"tag":841,"props":892,"children":893},{},[894],{"type":45,"value":895},"Recommended for anything serious. Runs out-of-process; can be wired into the build\u002FCI.",{"type":39,"tag":48,"props":897,"children":898},{},[899,901,906,908,914,916,921],{"type":45,"value":900},"If the only goal is plain JUnit on hand-written Java\u002FKotlin (no MPS-specific assertions), prefer a regular module test source root rather than a ",{"type":39,"tag":62,"props":902,"children":904},{"className":903},[],[905],{"type":45,"value":661},{"type":45,"value":907}," model — see ",{"type":39,"tag":62,"props":909,"children":911},{"className":910},[],[912],{"type":45,"value":913},"mps-distribution-build",{"type":45,"value":915}," for how ",{"type":39,"tag":62,"props":917,"children":919},{"className":918},[],[920],{"type":45,"value":83},{"type":45,"value":922},"-based MPS test modules are packaged.",{"type":39,"tag":210,"props":924,"children":926},{"id":925},"related-skills",[927],{"type":45,"value":928},"Related Skills",{"type":39,"tag":217,"props":930,"children":931},{},[932,942,961,980,999,1016,1041,1072],{"type":39,"tag":221,"props":933,"children":934},{},[935,940],{"type":39,"tag":62,"props":936,"children":938},{"className":937},[],[939],{"type":45,"value":181},{"type":45,"value":941}," — the smodel \u002F closures \u002F collections reference for assertion bodies.",{"type":39,"tag":221,"props":943,"children":944},{},[945,951,953,959],{"type":39,"tag":62,"props":946,"children":948},{"className":947},[],[949],{"type":45,"value":950},"mps-node-editing",{"type":45,"value":952}," — MCP recipes for inserting children and harvesting persistent refs (used heavily by the ",{"type":39,"tag":62,"props":954,"children":956},{"className":955},[],[957],{"type":45,"value":958},"ScopesTest",{"type":45,"value":960}," staged-construction recipe).",{"type":39,"tag":221,"props":962,"children":963},{},[964,970,972,978],{"type":39,"tag":62,"props":965,"children":967},{"className":966},[],[968],{"type":45,"value":969},"mps-aspect-typesystem",{"type":45,"value":971}," — when the system-under-test is the typesystem; ",{"type":39,"tag":62,"props":973,"children":975},{"className":974},[],[976],{"type":45,"value":977},"has error\u002Ftype",{"type":45,"value":979}," annotations here verify those rules.",{"type":39,"tag":221,"props":981,"children":982},{},[983,989,991,997],{"type":39,"tag":62,"props":984,"children":986},{"className":985},[],[987],{"type":45,"value":988},"mps-aspect-constraints",{"type":45,"value":990}," — when validating ",{"type":39,"tag":62,"props":992,"children":994},{"className":993},[],[995],{"type":45,"value":996},"can-be",{"type":45,"value":998}," \u002F scope \u002F validator rules from the constraints aspect.",{"type":39,"tag":221,"props":1000,"children":1001},{},[1002,1008,1010,1015],{"type":39,"tag":62,"props":1003,"children":1005},{"className":1004},[],[1006],{"type":45,"value":1007},"mps-aspect-migrations",{"type":45,"value":1009}," — for migration scripts being exercised by ",{"type":39,"tag":62,"props":1011,"children":1013},{"className":1012},[],[1014],{"type":45,"value":614},{"type":45,"value":208},{"type":39,"tag":221,"props":1017,"children":1018},{},[1019,1025,1026,1032,1034,1039],{"type":39,"tag":62,"props":1020,"children":1022},{"className":1021},[],[1023],{"type":45,"value":1024},"mps-aspect-intentions",{"type":45,"value":168},{"type":39,"tag":62,"props":1027,"children":1029},{"className":1028},[],[1030],{"type":45,"value":1031},"mps-aspect-editor-menus-and-keymaps",{"type":45,"value":1033}," — when an ",{"type":39,"tag":62,"props":1035,"children":1037},{"className":1036},[],[1038],{"type":45,"value":503},{"type":45,"value":1040}," exercises intentions, side transforms, or keymapped actions.",{"type":39,"tag":221,"props":1042,"children":1043},{},[1044,1050,1051,1056,1058,1063,1065,1071],{"type":39,"tag":62,"props":1045,"children":1047},{"className":1046},[],[1048],{"type":45,"value":1049},"mps-build-language",{"type":45,"value":168},{"type":39,"tag":62,"props":1052,"children":1054},{"className":1053},[],[1055],{"type":45,"value":913},{"type":45,"value":1057}," — when wiring a ",{"type":39,"tag":62,"props":1059,"children":1061},{"className":1060},[],[1062],{"type":45,"value":661},{"type":45,"value":1064}," Solution into the build pipeline (test-only ",{"type":39,"tag":62,"props":1066,"children":1068},{"className":1067},[],[1069],{"type":45,"value":1070},"BuildProject",{"type":45,"value":359},{"type":39,"tag":221,"props":1073,"children":1074},{},[1075,1081],{"type":39,"tag":62,"props":1076,"children":1078},{"className":1077},[],[1079],{"type":45,"value":1080},"mps-quotations",{"type":45,"value":1082}," — for tests that use quotation snippets.",{"type":39,"tag":210,"props":1084,"children":1086},{"id":1085},"reference-index",[1087],{"type":45,"value":1088},"Reference Index",{"type":39,"tag":217,"props":1090,"children":1091},{},[1092,1127,1138,1220,1253,1420,1496,1537,1569,1619],{"type":39,"tag":221,"props":1093,"children":1094},{},[1095,1097,1103,1105,1110,1112,1118,1120,1125],{"type":45,"value":1096},"Open ",{"type":39,"tag":62,"props":1098,"children":1100},{"className":1099},[],[1101],{"type":45,"value":1102},"references\u002Ftest-model-setup.md",{"type":45,"value":1104}," when bootstrapping a new ",{"type":39,"tag":62,"props":1106,"children":1108},{"className":1107},[],[1109],{"type":45,"value":661},{"type":45,"value":1111}," model — required stereotype, used languages, Solution kind, optional ",{"type":39,"tag":62,"props":1113,"children":1115},{"className":1114},[],[1116],{"type":45,"value":1117},"TestInfo",{"type":45,"value":1119}," root, and the choice between the language's ",{"type":39,"tag":62,"props":1121,"children":1123},{"className":1122},[],[1124],{"type":45,"value":856},{"type":45,"value":1126}," and a dedicated test Solution. Includes the canonical example test Solutions in this repo.",{"type":39,"tag":221,"props":1128,"children":1129},{},[1130,1131,1136],{"type":45,"value":1096},{"type":39,"tag":62,"props":1132,"children":1134},{"className":1133},[],[1135],{"type":45,"value":644},{"type":45,"value":1137}," for the test-type cheat sheet (concept refs and what each tests). Use to decide which root concept to instantiate.",{"type":39,"tag":221,"props":1139,"children":1140},{},[1141,1142,1147,1149,1154,1156,1161,1162,1168,1169,1175,1176,1182,1184,1190,1191,1197,1198,1204,1205,1211,1212,1218],{"type":45,"value":1096},{"type":39,"tag":62,"props":1143,"children":1145},{"className":1144},[],[1146],{"type":45,"value":743},{"type":45,"value":1148}," when authoring or modifying a ",{"type":39,"tag":62,"props":1150,"children":1152},{"className":1151},[],[1153],{"type":45,"value":599},{"type":45,"value":1155}," — section layout (",{"type":39,"tag":62,"props":1157,"children":1159},{"className":1158},[],[1160],{"type":45,"value":695},{"type":45,"value":259},{"type":39,"tag":62,"props":1163,"children":1165},{"className":1164},[],[1166],{"type":45,"value":1167},"test methods",{"type":45,"value":259},{"type":39,"tag":62,"props":1170,"children":1172},{"className":1171},[],[1173],{"type":45,"value":1174},"utility methods",{"type":45,"value":259},{"type":39,"tag":62,"props":1177,"children":1179},{"className":1178},[],[1180],{"type":45,"value":1181},"accessMode",{"type":45,"value":1183},"), inline assertion annotations (",{"type":39,"tag":62,"props":1185,"children":1187},{"className":1186},[],[1188],{"type":45,"value":1189},"has error",{"type":45,"value":259},{"type":39,"tag":62,"props":1192,"children":1194},{"className":1193},[],[1195],{"type":45,"value":1196},"has type",{"type":45,"value":259},{"type":39,"tag":62,"props":1199,"children":1201},{"className":1200},[],[1202],{"type":45,"value":1203},"has typesystem error",{"type":45,"value":259},{"type":39,"tag":62,"props":1206,"children":1208},{"className":1207},[],[1209],{"type":45,"value":1210},"has expected type",{"type":45,"value":259},{"type":39,"tag":62,"props":1213,"children":1215},{"className":1214},[],[1216],{"type":45,"value":1217},"has type in",{"type":45,"value":1219},"), labelled-node assertions inside test methods, and the namespace separation between labels and scope-resolved references.",{"type":39,"tag":221,"props":1221,"children":1222},{},[1223,1224,1230,1232,1237,1239,1244,1245,1251],{"type":45,"value":1096},{"type":39,"tag":62,"props":1225,"children":1227},{"className":1226},[],[1228],{"type":45,"value":1229},"references\u002Fscopes-test.md",{"type":45,"value":1231}," when writing ",{"type":39,"tag":54,"props":1233,"children":1234},{},[1235],{"type":45,"value":1236},"declarative",{"type":45,"value":1238}," scope assertions (",{"type":39,"tag":62,"props":1240,"children":1242},{"className":1241},[],[1243],{"type":45,"value":958},{"type":45,"value":630},{"type":39,"tag":62,"props":1246,"children":1248},{"className":1247},[],[1249],{"type":45,"value":1250},"ScopesExpectedNode",{"type":45,"value":1252},") — where to attach the annotation, the exact-set semantics, the JSON blueprint, the stage-construction recipe for resolving expected refs, and why declarative scope tests beat imperative ones.",{"type":39,"tag":221,"props":1254,"children":1255},{},[1256,1257,1262,1264,1269,1271,1277,1278,1284,1285,1290,1292,1298,1300,1306,1307,1312,1313,1318,1319,1325,1327,1333,1334,1340,1341,1347,1348,1354,1355,1361,1363,1368,1369,1375,1377,1383,1384,1390,1391,1397,1398,1404,1405,1411,1412,1418],{"type":45,"value":1096},{"type":39,"tag":62,"props":1258,"children":1260},{"className":1259},[],[1261],{"type":45,"value":750},{"type":45,"value":1263}," when writing an ",{"type":39,"tag":62,"props":1265,"children":1267},{"className":1266},[],[1268],{"type":45,"value":503},{"type":45,"value":1270}," — root layout (",{"type":39,"tag":62,"props":1272,"children":1274},{"className":1273},[],[1275],{"type":45,"value":1276},"before",{"type":45,"value":697},{"type":39,"tag":62,"props":1279,"children":1281},{"className":1280},[],[1282],{"type":45,"value":1283},"result",{"type":45,"value":697},{"type":39,"tag":62,"props":1286,"children":1288},{"className":1287},[],[1289],{"type":45,"value":62},{"type":45,"value":1291},"), the ",{"type":39,"tag":62,"props":1293,"children":1295},{"className":1294},[],[1296],{"type":45,"value":1297},"AnonymousCellAnnotation",{"type":45,"value":1299}," caret marker, the cell-ID convention for auto-generated editors (",{"type":39,"tag":62,"props":1301,"children":1303},{"className":1302},[],[1304],{"type":45,"value":1305},"property_\u003Cname>",{"type":45,"value":259},{"type":39,"tag":62,"props":1308,"children":1310},{"className":1309},[],[1311],{"type":45,"value":545},{"type":45,"value":259},{"type":39,"tag":62,"props":1314,"children":1316},{"className":1315},[],[1317],{"type":45,"value":530},{"type":45,"value":259},{"type":39,"tag":62,"props":1320,"children":1322},{"className":1321},[],[1323],{"type":45,"value":1324},"refNode_\u003Crole>",{"type":45,"value":1326},", constant\u002Fcollection cells), the editor-driving statements (",{"type":39,"tag":62,"props":1328,"children":1330},{"className":1329},[],[1331],{"type":45,"value":1332},"type \"...\"",{"type":45,"value":259},{"type":39,"tag":62,"props":1335,"children":1337},{"className":1336},[],[1338],{"type":45,"value":1339},"press",{"type":45,"value":259},{"type":39,"tag":62,"props":1342,"children":1344},{"className":1343},[],[1345],{"type":45,"value":1346},"invoke action",{"type":45,"value":259},{"type":39,"tag":62,"props":1349,"children":1351},{"className":1350},[],[1352],{"type":45,"value":1353},"invoke intention",{"type":45,"value":259},{"type":39,"tag":62,"props":1356,"children":1358},{"className":1357},[],[1359],{"type":45,"value":1360},"invoke quick-fix",{"type":45,"value":1362},"), the editor expressions usable inside ",{"type":39,"tag":62,"props":1364,"children":1366},{"className":1365},[],[1367],{"type":45,"value":62},{"type":45,"value":395},{"type":39,"tag":62,"props":1370,"children":1372},{"className":1371},[],[1373],{"type":45,"value":1374},"EditorComponentExpression",{"type":45,"value":1376}," → ",{"type":39,"tag":62,"props":1378,"children":1380},{"className":1379},[],[1381],{"type":45,"value":1382},"getEditorComponent()",{"type":45,"value":259},{"type":39,"tag":62,"props":1385,"children":1387},{"className":1386},[],[1388],{"type":45,"value":1389},"IsIntentionApplicableExpression",{"type":45,"value":1376},{"type":39,"tag":62,"props":1392,"children":1394},{"className":1393},[],[1395],{"type":45,"value":1396},"isIntentionApplicable()",{"type":45,"value":259},{"type":39,"tag":62,"props":1399,"children":1401},{"className":1400},[],[1402],{"type":45,"value":1403},"ProjectExpression",{"type":45,"value":1376},{"type":39,"tag":62,"props":1406,"children":1408},{"className":1407},[],[1409],{"type":45,"value":1410},"getProject()",{"type":45,"value":259},{"type":39,"tag":62,"props":1413,"children":1415},{"className":1414},[],[1416],{"type":45,"value":1417},"ModelExpression",{"type":45,"value":1419}," → model of the edited node), and the side-transform \u002F completion testing pattern.",{"type":39,"tag":221,"props":1421,"children":1422},{},[1423,1424,1430,1432,1437,1438,1443,1445,1450,1451,1457,1458,1464,1465,1471,1473,1479,1481,1487,1489,1494],{"type":45,"value":1096},{"type":39,"tag":62,"props":1425,"children":1427},{"className":1426},[],[1428],{"type":45,"value":1429},"references\u002Fgenerator-and-migration-tests.md",{"type":45,"value":1431}," when validating generator output (",{"type":39,"tag":62,"props":1433,"children":1435},{"className":1434},[],[1436],{"type":45,"value":599},{"type":45,"value":630},{"type":39,"tag":62,"props":1439,"children":1441},{"className":1440},[],[1442],{"type":45,"value":636},{"type":45,"value":1444},") or testing a migration script (",{"type":39,"tag":62,"props":1446,"children":1448},{"className":1447},[],[1449],{"type":45,"value":614},{"type":45,"value":60},{"type":39,"tag":62,"props":1452,"children":1454},{"className":1453},[],[1455],{"type":45,"value":1456},"inputNodes",{"type":45,"value":259},{"type":39,"tag":62,"props":1459,"children":1461},{"className":1460},[],[1462],{"type":45,"value":1463},"outputNodes",{"type":45,"value":259},{"type":39,"tag":62,"props":1466,"children":1468},{"className":1467},[],[1469],{"type":45,"value":1470},"migration",{"type":45,"value":1472}," refs, ",{"type":39,"tag":62,"props":1474,"children":1476},{"className":1475},[],[1477],{"type":45,"value":1478},"option",{"type":45,"value":1480},"s including ",{"type":39,"tag":62,"props":1482,"children":1484},{"className":1483},[],[1485],{"type":45,"value":1486},"StableIdOption",{"type":45,"value":1488},"). Lists the four-child structure of ",{"type":39,"tag":62,"props":1490,"children":1492},{"className":1491},[],[1493],{"type":45,"value":614},{"type":45,"value":1495}," and the \"Generate Output from Input\" intention.",{"type":39,"tag":221,"props":1497,"children":1498},{},[1499,1500,1506,1508,1513,1515,1521,1522,1528,1529,1535],{"type":45,"value":1096},{"type":39,"tag":62,"props":1501,"children":1503},{"className":1502},[],[1504],{"type":45,"value":1505},"references\u002Fbtestcase.md",{"type":45,"value":1507}," when writing plain JUnit-style tests against hand-written Java\u002FKotlin — the ",{"type":39,"tag":62,"props":1509,"children":1511},{"className":1510},[],[1512],{"type":45,"value":83},{"type":45,"value":1514}," annotation, ",{"type":39,"tag":62,"props":1516,"children":1518},{"className":1517},[],[1519],{"type":45,"value":1520},"TestMethod",{"type":45,"value":697},{"type":39,"tag":62,"props":1523,"children":1525},{"className":1524},[],[1526],{"type":45,"value":1527},"BeforeTest",{"type":45,"value":697},{"type":39,"tag":62,"props":1530,"children":1532},{"className":1531},[],[1533],{"type":45,"value":1534},"AfterTest",{"type":45,"value":1536},", and the available assertion concepts.",{"type":39,"tag":221,"props":1538,"children":1539},{},[1540,1541,1547,1549,1554,1555,1560,1562,1567],{"type":45,"value":1096},{"type":39,"tag":62,"props":1542,"children":1544},{"className":1543},[],[1545],{"type":45,"value":1546},"references\u002Frunning-tests.md",{"type":45,"value":1548}," when launching tests — inside MPS (right-click → Run tests), from the command line via the Ant pipeline, or from an agent via ",{"type":39,"tag":62,"props":1550,"children":1552},{"className":1551},[],[1553],{"type":45,"value":793},{"type":45,"value":630},{"type":39,"tag":62,"props":1556,"children":1558},{"className":1557},[],[1559],{"type":45,"value":801},{"type":45,"value":1561},". Covers in-process vs separate-MPS-instance, and ",{"type":39,"tag":62,"props":1563,"children":1565},{"className":1564},[],[1566],{"type":45,"value":767},{"type":45,"value":1568}," as a fast pre-run gate.",{"type":39,"tag":221,"props":1570,"children":1571},{},[1572,1573,1579,1581,1586,1588,1594,1596,1602,1603,1609,1611,1617],{"type":45,"value":1096},{"type":39,"tag":62,"props":1574,"children":1576},{"className":1575},[],[1577],{"type":45,"value":1578},"references\u002Fcommon-failures.md",{"type":45,"value":1580}," when a test won't run, runs but doesn't fail when expected, fails for the wrong reason, or generates a misleading ",{"type":39,"tag":62,"props":1582,"children":1584},{"className":1583},[],[1585],{"type":45,"value":1463},{"type":45,"value":1587},". Includes the abstract-concept gotcha, label-vs-name confusion, ",{"type":39,"tag":62,"props":1589,"children":1591},{"className":1590},[],[1592],{"type":45,"value":1593},"press VK_ENTER",{"type":45,"value":1595}," vs ",{"type":39,"tag":62,"props":1597,"children":1599},{"className":1598},[],[1600],{"type":45,"value":1601},"invoke action Insert",{"type":45,"value":259},{"type":39,"tag":62,"props":1604,"children":1606},{"className":1605},[],[1607],{"type":45,"value":1608},"replace_node_child",{"type":45,"value":1610}," ref invalidation, and ",{"type":39,"tag":62,"props":1612,"children":1614},{"className":1613},[],[1615],{"type":45,"value":1616},"ScopesExpectedNode.ref",{"type":45,"value":1618}," not being scope-resolved.",{"type":39,"tag":221,"props":1620,"children":1621},{},[1622,1623,1628,1630,1635,1637,1642,1643,1648,1649,1654,1655,1660,1661,1666,1668,1673,1675,1680,1682,1687],{"type":45,"value":1096},{"type":39,"tag":62,"props":1624,"children":1626},{"className":1625},[],[1627],{"type":45,"value":687},{"type":45,"value":1629}," for the validated FQN+concept-ref table covering ",{"type":39,"tag":62,"props":1631,"children":1633},{"className":1632},[],[1634],{"type":45,"value":67},{"type":45,"value":1636}," (every concept used by the skill — ",{"type":39,"tag":62,"props":1638,"children":1640},{"className":1639},[],[1641],{"type":45,"value":599},{"type":45,"value":259},{"type":39,"tag":62,"props":1644,"children":1646},{"className":1645},[],[1647],{"type":45,"value":393},{"type":45,"value":259},{"type":39,"tag":62,"props":1650,"children":1652},{"className":1651},[],[1653],{"type":45,"value":726},{"type":45,"value":259},{"type":39,"tag":62,"props":1656,"children":1658},{"className":1657},[],[1659],{"type":45,"value":428},{"type":45,"value":259},{"type":39,"tag":62,"props":1662,"children":1664},{"className":1663},[],[1665],{"type":45,"value":1297},{"type":45,"value":1667},", the annotation\u002Fcheck operations, the editor-driving statements, ",{"type":39,"tag":62,"props":1669,"children":1671},{"className":1670},[],[1672],{"type":45,"value":958},{"type":45,"value":1674},"\u002F",{"type":39,"tag":62,"props":1676,"children":1678},{"className":1677},[],[1679],{"type":45,"value":1250},{"type":45,"value":1681},", etc.) and ",{"type":39,"tag":62,"props":1683,"children":1685},{"className":1684},[],[1686],{"type":45,"value":75},{"type":45,"value":208},{"items":1689,"total":1765},[1690,1706,1715,1724,1734,1744,1757],{"slug":1691,"name":1691,"fn":1692,"description":1693,"org":1694,"tags":1695,"stars":19,"repoUrl":20,"updatedAt":1705},"mps-aspect-accessories","configure JetBrains MPS module dependencies","Wire MPS module and model dependencies, used languages, used devkits, extended languages, runtime solutions, accessory models, and language\u002Fdependency versions. Use when adding\u002Fremoving module dependencies, importing languages or devkits into a model, declaring runtime solutions, or shipping accessory content visible to consumers without explicit import.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1696,1699,1702],{"name":1697,"slug":1698,"type":15},"Architecture","architecture",{"name":1700,"slug":1701,"type":15},"Configuration","configuration",{"name":1703,"slug":1704,"type":15},"Engineering","engineering","2026-07-17T06:06:57.311661",{"slug":1707,"name":1707,"fn":1708,"description":1709,"org":1710,"tags":1711,"stars":19,"repoUrl":20,"updatedAt":1714},"mps-aspect-actions","define and edit MPS node factories","Use when defining or editing MPS node factories (the \"actions\" aspect) — `NodeFactories` roots, per-concept `NodeFactory` setup functions that initialize a freshly created node and optionally copy data from a replaced `sampleNode`, plus the actions aspect's `CopyPasteHandlers` and `PasteWrappers` roots. Reach for this skill when a substitution, side transform, completion replacement, or `add new initialized(...)` should preserve fields from the node it is replacing, or when defaults set in a constructor are not enough.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1712,1713],{"name":1697,"slug":1698,"type":15},{"name":1703,"slug":1704,"type":15},"2026-07-17T06:04:48.066901",{"slug":1716,"name":1716,"fn":1717,"description":1718,"org":1719,"tags":1720,"stars":19,"repoUrl":20,"updatedAt":1723},"mps-aspect-behavior","define and edit MPS concept behavior","Use when defining or editing MPS `ConceptBehavior` — per-concept methods (non-virtual \u002F virtual \u002F abstract \u002F static \u002F virtual static), constructors, virtual dispatch (MRO), super and interface-default calls (`super\u003CInterface>.method`), overriding methods from `lang.core.behavior` interfaces such as `ScopeProvider.getScope` \u002F `INamedConcept.getName` \u002F `BaseConcept.getPresentation`, calling sibling methods (`LocalBehaviorMethodCall`) and behavior methods from other aspects via `node.method(...)`. Reach for this skill whenever the task involves authoring or modifying `\u003Clang>\u002FlanguageModels\u002Fbehavior.mps`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1721,1722],{"name":1697,"slug":1698,"type":15},{"name":1703,"slug":1704,"type":15},"2026-07-13T06:45:21.757084",{"slug":988,"name":988,"fn":1725,"description":1726,"org":1727,"tags":1728,"stars":19,"repoUrl":20,"updatedAt":1733},"define JetBrains MPS language constraints","Use when defining or editing MPS language constraints — property validators \u002F setters \u002F getters, referent search scopes (imperative or inherited via `ScopeProvider.getScope`), `referentSetHandler` side effects, default-scope blocks, `canBeChild` \u002F `canBeParent` \u002F `canBeAncestor` \u002F `canBeRoot` placement rules, `defaultConcreteConcept` for abstract concepts, `set \u003Cread-only>` and `{name}` aliasing, and scope helpers (`SimpleRoleScope`, `ListScope`, `CompositeScope`, `HidingByNameScope`). Reach for this skill whenever the task involves authoring or modifying `\u003Clang>\u002FlanguageModels\u002Fconstraints.mps`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1729,1730],{"name":1697,"slug":1698,"type":15},{"name":1731,"slug":1732,"type":15},"Code Analysis","code-analysis","2026-07-23T05:41:33.639365",{"slug":1735,"name":1735,"fn":1736,"description":1737,"org":1738,"tags":1739,"stars":19,"repoUrl":20,"updatedAt":1743},"mps-aspect-dataflow","define and debug MPS dataflow builders","Use when defining or debugging MPS dataflow builders for a concept — control\u002Fdata flow declarations that drive reachability analysis and variable-use checking. Covers DataFlowBuilderDeclaration, BuilderBlock, emit instructions (code for, jump, ifjump, label, read, write, ret, mayBeUnreachable), positions (AfterPosition, BeforePosition, LabelPosition), the jetbrains.mps.lang.dataFlow language, the NodeParameter implicit, BL+smodel usage inside builder bodies, and IBuilderMode for advanced analyses such as nullable\u002Fnon-null tracking.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1740],{"name":1741,"slug":1742,"type":15},"Data Analysis","data-analysis","2026-07-13T06:45:19.114674",{"slug":1745,"name":1745,"fn":1746,"description":1747,"org":1748,"tags":1749,"stars":19,"repoUrl":20,"updatedAt":1756},"mps-aspect-editor","define MPS editor layouts","Use when creating or changing MPS editor definitions — the overall workflow from scaffolding a `ConceptEditorDeclaration` through componentizing reusable `EditorComponentDeclaration`s, refining cell models and cell layouts, applying style sheets and indent-layout style items, wiring smart references, leveraging inheritance via super-concepts and interfaces, inspecting (`print_node_json`, `show_node_representation`) and validating (`check_root_node_problems`). Covers `jetbrains.mps.lang.editor` cell models (`CellModel_RefNode`\u002F`CellModel_RefNodeList`\u002F`CellModel_RefCell`\u002F`CellModel_Property`\u002F`CellModel_Constant`), layout choices, and JSON blueprints for common editor shapes. For the non-layout side (action maps, keymaps, transformation\u002Fsubstitute menus) use `mps-aspect-editor-menus-and-keymaps`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1750,1753],{"name":1751,"slug":1752,"type":15},"Design","design",{"name":1754,"slug":1755,"type":15},"UI Components","ui-components","2026-07-23T05:41:56.638151",{"slug":1031,"name":1031,"fn":1758,"description":1759,"org":1760,"tags":1761,"stars":19,"repoUrl":20,"updatedAt":1764},"author MPS editor menus and keymaps","Use when authoring the **non-layout** parts of the MPS editor aspect — what happens when the user types, presses a key, triggers completion, pastes, or invokes a context action. Covers action maps (`CellActionMapDeclaration`), cell keymaps (`CellKeyMapDeclaration`), transformation menus (`TransformationMenu_Default` \u002F `_Named` \u002F `_Contribution`), substitute menus (`SubstituteMenu_Default` \u002F `SubstituteMenu` \u002F contributions), side transforms (LEFT\u002FRIGHT), legacy cell menus, paste wrappers and copy-paste handlers (in the actions language), completion styling, reference presentation, two-step deletion, and the editor selection API. Trigger terms: `actionMap`, `keyMap`, `delete_action_id`, `transformationMenu`, `substituteMenu`, `Ctrl+Space`, `Ctrl+Alt+B`, side transform, paste wrapper, completion styling, `PasteWrappers`, `CopyPasteHandlers`. For the **layout** side (cells, layouts, style sheets) use `mps-aspect-editor` instead.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1762,1763],{"name":1703,"slug":1704,"type":15},{"name":1754,"slug":1755,"type":15},"2026-07-23T05:41:49.666535",31,{"items":1767,"total":1851},[1768,1774,1779,1784,1789,1793,1798,1803,1812,1822,1830,1841],{"slug":1691,"name":1691,"fn":1692,"description":1693,"org":1769,"tags":1770,"stars":19,"repoUrl":20,"updatedAt":1705},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1771,1772,1773],{"name":1697,"slug":1698,"type":15},{"name":1700,"slug":1701,"type":15},{"name":1703,"slug":1704,"type":15},{"slug":1707,"name":1707,"fn":1708,"description":1709,"org":1775,"tags":1776,"stars":19,"repoUrl":20,"updatedAt":1714},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1777,1778],{"name":1697,"slug":1698,"type":15},{"name":1703,"slug":1704,"type":15},{"slug":1716,"name":1716,"fn":1717,"description":1718,"org":1780,"tags":1781,"stars":19,"repoUrl":20,"updatedAt":1723},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1782,1783],{"name":1697,"slug":1698,"type":15},{"name":1703,"slug":1704,"type":15},{"slug":988,"name":988,"fn":1725,"description":1726,"org":1785,"tags":1786,"stars":19,"repoUrl":20,"updatedAt":1733},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1787,1788],{"name":1697,"slug":1698,"type":15},{"name":1731,"slug":1732,"type":15},{"slug":1735,"name":1735,"fn":1736,"description":1737,"org":1790,"tags":1791,"stars":19,"repoUrl":20,"updatedAt":1743},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1792],{"name":1741,"slug":1742,"type":15},{"slug":1745,"name":1745,"fn":1746,"description":1747,"org":1794,"tags":1795,"stars":19,"repoUrl":20,"updatedAt":1756},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1796,1797],{"name":1751,"slug":1752,"type":15},{"name":1754,"slug":1755,"type":15},{"slug":1031,"name":1031,"fn":1758,"description":1759,"org":1799,"tags":1800,"stars":19,"repoUrl":20,"updatedAt":1764},{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1801,1802],{"name":1703,"slug":1704,"type":15},{"name":1754,"slug":1755,"type":15},{"slug":1804,"name":1804,"fn":1805,"description":1806,"org":1807,"tags":1808,"stars":19,"repoUrl":20,"updatedAt":1811},"mps-aspect-generation-plan","modify MPS generation plans","Use when defining or modifying an MPS generation plan — explicit ordering of generators, checkpoints for cross-model reference resolution, forks for parallel branches, IncludePlan composition, conditional PlanContribution activation, ParameterEquals\u002FConceptListSelector fork selectors, and InitModelAttributes for targetFacet routing. Apply when working with @genplan models, the jetbrains.mps.lang.generator.plan language, attaching plans via DevKits or the Custom generation facet, or debugging cross-model mapping label resolution.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1809,1810],{"name":1697,"slug":1698,"type":15},{"name":1703,"slug":1704,"type":15},"2026-07-13T06:44:59.507855",{"slug":1813,"name":1813,"fn":1814,"description":1815,"org":1816,"tags":1817,"stars":19,"repoUrl":20,"updatedAt":1821},"mps-aspect-generator","define JetBrains MPS generator rules","Use when defining or modifying MPS generators — author a generator module, add or edit root\u002Freduction\u002Fweaving\u002Fpattern mapping rules, attach template macros ($COPY_SRC, $LOOP, $IF, $PROPERTY, $REF, $SWITCH, $MAP_SRC, $WEAVE, $INSERT, $LABEL, $TRACE, $VAR), wire mapping labels, build template switches, write pre\u002Fpost mapping scripts, navigate `genContext`, or debug \"rule didn't fire\", missing references, empty output, infinite reduction loops, and generated-Java compile failures.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1818,1819,1820],{"name":1697,"slug":1698,"type":15},{"name":1731,"slug":1732,"type":15},{"name":1703,"slug":1704,"type":15},"2026-07-17T06:06:58.042999",{"slug":1024,"name":1024,"fn":1823,"description":1824,"org":1825,"tags":1826,"stars":19,"repoUrl":20,"updatedAt":1829},"define and edit MPS intentions","Use when defining or editing MPS intentions (the Alt+Enter context-action aspect) — adding `IntentionDeclaration` roots, parameterized or surround-with variants, description\u002FisApplicable\u002Fexecute blocks, child-filter functions, factory-initialized AST splicing, or debugging why an intention is not offered. Lives in the language's `intentions` model and uses `jetbrains.mps.lang.intentions`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1827,1828],{"name":1697,"slug":1698,"type":15},{"name":1703,"slug":1704,"type":15},"2026-07-23T05:41:48.692899",{"slug":1007,"name":1007,"fn":1831,"description":1832,"org":1833,"tags":1834,"stars":19,"repoUrl":20,"updatedAt":1840},"author and debug MPS migration scripts","Use when authoring or debugging MPS migration scripts that upgrade user models after a language definition changes — covers jetbrains.mps.lang.migration (MigrationScript class-based, PureMigrationScript declarative, MoveConcept\u002FMoveContainmentLink\u002FMoveReferenceLink\u002FMoveProperty, ordering via OrderDependency, data exchange via putData\u002FgetData, RefactoringLog, ConceptMigrationReference) and jetbrains.mps.lang.script Enhancement Scripts (MigrationScript with MigrationScriptPart_Instance, ExtractInterfaceMigration, FactoryMigrationScriptPart, CommentMigrationScriptPart) — when a model needs version-gated upgrade, concept rename or removal, link or property rename, instance-level transformation, or composition of migration steps.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1835,1838],{"name":1836,"slug":1837,"type":15},"Debugging","debugging",{"name":1839,"slug":1470,"type":15},"Migration","2026-07-13T06:45:20.372122",{"slug":1842,"name":1842,"fn":1843,"description":1844,"org":1845,"tags":1846,"stars":19,"repoUrl":20,"updatedAt":1850},"mps-aspect-structure-concepts","define concepts in MPS structure aspect","Define concepts, interface concepts, enumerations, and constrained data types in an MPS language's `structure` aspect. Covers smart-reference detection, alias rules, cardinality, INamedConcept usage, bulk creation, and the full `mps_mcp_alter_structure` \u002F `mps_mcp_query_structure` reference. Use when authoring or modifying a language's structure model.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":9},[1847],{"name":1848,"slug":1849,"type":15},"Data Modeling","data-modeling","2026-07-23T05:41:30.705975",188]