Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
# node-runtime @abap2ui5/node-runtime + the ABAP apps, transpiled in the job
# (open-abap-core fetched with git, cached by its commit)
# cap2ui5 a CAP project + @cap2ui5/cds-plugin + the JS apps
# plus abaplint over the ABAP apps. Each backend run takes seconds; the
# install dominates.
# plus abaplint over the ABAP apps, and the frontend suite against the two
# in-process frontends: the agent client and the Adaptive Cards renderer
# (renderers/adaptive-cards/, with its golden cards). Each backend run takes
# seconds; the install dominates.
# The frontend job runs the frontend suite against the UI5 SPA of abap2UI5
# (the commit the spec is derived from, app/webapp only) in Chromium - the
# test job skips that test, it has no browser and no checkout - and records
# the reports of the UI5 SPA and the agent client.
# the reports of the UI5 SPA, the agent client and the Adaptive Cards renderer.
name: ci

on:
Expand Down Expand Up @@ -56,14 +58,16 @@ jobs:
run: npm ci --prefix conformance/hosts/cap2ui5 --no-audit --no-fund
- name: abaplint (ABAP conformance apps)
run: npm run lint:abap
- name: npm test (both backends)
- name: npm test (both backends, agent client, Adaptive Cards renderer)
run: npm test
- name: generated sections are up to date
run: npm run generate && git diff --exit-code
- name: backend suite report - node-runtime
if: ${{ !cancelled() }}
run: node scripts/run-conformance.mjs node-runtime --json report-node-runtime.json
run: node scripts/run-conformance.mjs node-runtime --json report-node-runtime.json --expected
- name: backend suite report - cap2ui5
if: ${{ !cancelled() }}
run: node scripts/run-conformance.mjs cap2ui5 --json report-cap2ui5.json
run: node scripts/run-conformance.mjs cap2ui5 --json report-cap2ui5.json --expected
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() && matrix.node == '22' }}
with:
Expand Down Expand Up @@ -101,6 +105,9 @@ jobs:
- name: frontend suite report - agent client
if: ${{ !cancelled() }}
run: node conformance/backend/bin/abap2ui5-conformance.mjs frontend --adapter agent --json > report-frontend-agent.json || true
- name: frontend suite report - Adaptive Cards renderer
if: ${{ !cancelled() }}
run: node conformance/backend/bin/abap2ui5-conformance.mjs frontend --adapter adaptive-cards --json > report-frontend-adaptive-cards.json || true
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: ${{ !cancelled() }}
with:
Expand Down
27 changes: 18 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ down, and the spec records what the implementations do.
`spec/README.md#sources`. A statement you cannot trace to code is a
proposal - say so, or leave it out.
- **Accidental behaviour is an implementation note, not a rule.** When the
reference does something odd (draft ids that repeat after a leave, the URL
reflected into a 500 body), write it under *Implementation note* - another
implementation must not have to copy it.
reference does something odd (draft ids that repeat after a leave), write
it under *Implementation note* - another implementation must not have to
copy it. When the maintainer turns such a note into a rule the reference
breaks (the URL reflected into a 500 body, revision 0.3), the rule gets its
check and the reference's failure is pinned (below).
- **A rule a backend can break gets a check.** New MUST/SHOULD for backends ->
a check in `conformance/backend/lib/checks/`, its id on the spec's
*Checked by* line, `node scripts/gen-check-list.mjs`. `npm test` fails when
Expand Down Expand Up @@ -48,7 +50,12 @@ down, and the spec records what the implementations do.
`traffic/`; record again after changing a check or an app.
- **Generated sections are generated.** `conformance/backend/README.md`
(check list), `profiles/portable.md` (between the `portable:*` markers,
from `profiles/portable-v1.json`) - run `npm run generate`.
from `profiles/portable-v1.json`), `renderers/adaptive-cards/README.md`
(the mapping table, from `mapping.mjs`) - run `npm run generate`.
- **Known failures of a reference are pinned, not hidden.** A backend check
the reference backends fail goes into `test/lib/expected.mjs` with the
place of its fix; the tests fail when it starts to pass (unpin it, record
again) as well as when another check fails.
- **`profiles/semantic.md` is the normative snapshot v1** (moved from
abap2UI5/mcp-server `docs/agent-snapshot.md`). Changes to the snapshot
shape are made here first; implementations follow.
Expand All @@ -65,7 +72,8 @@ down, and the spec records what the implementations do.
| `profiles/` | UI5, portable (v1 + `portable-v1.json` + coverage) and semantic profiles |
| `schema/` | JSON Schemas 2020-12 |
| `conformance/backend/` | the backend suite - the published package's entry (`index.mjs`, `bin/`) |
| `conformance/frontend/` | the frontend suite - `lib/` (scripted backend `mock.mjs`, runner, response builders, `checks/`), `adapters/` (`ui5` Playwright + the boot page, `agent` + the vendored mcp-server client, `webcomponent`, `headless` stub) |
| `conformance/frontend/` | the frontend suite - `lib/` (scripted backend `mock.mjs`, runner, response builders, `checks/`), `adapters/` (`ui5` Playwright + the boot page, `agent` + the vendored mcp-server client, `webcomponent`, `adaptive-cards` (in process, the renderer below), `headless` stub) |
| `renderers/adaptive-cards/` | a prototype portable renderer: response -> Adaptive Card 1.5 and `Action.Submit` payload -> request (`render.mjs`, `mapping.mjs` - the control table the README's mapping section is generated from, `submit.mjs`, `host.mjs`, `demo.mjs`), golden cards in `golden/` (`UPDATE_GOLDEN=1 node --test test/adaptive-cards.test.mjs` rewrites them) |
| `conformance/apps/` | the conformance apps (ABAP + cap2UI5) and their abaplint config |
| `conformance/hosts/` | `node-runtime` (build + serve) and `cap2ui5` (a CAP project) reference hosts |
| `traffic/` | recorded traffic per backend: `suite.json`, `ui5-frontend.json`, `agent-client.json` |
Expand All @@ -80,7 +88,8 @@ recorded traffic, cross-backend equality, docs links and anchors, the
portable profile, the conformance apps' abapGit format, the CLI, the
full backend suite against both reference backends (`PROTOCOL_SKIP_BACKENDS=1`
skips those; the cap2UI5 run skips itself when its host is not installed),
and the frontend suite against the agent client (always) and the UI5 SPA
and the frontend suite against the agent client and the Adaptive Cards
renderer (always, golden cards included) and the UI5 SPA
(when an abap2UI5 checkout and a Chromium are there;
`PROTOCOL_SKIP_BROWSER=1` skips it, `PROTOCOL_REQUIRE_BROWSER=1` fails
without them). CI runs the same on Node 22 and 24, and the UI5 SPA in a
Expand All @@ -89,8 +98,8 @@ has browsers already - point `CHROMIUM_BIN` at one.

## Style

ES modules, Node 22+, no runtime dependencies in `conformance/backend/`
and `conformance/frontend/` (the browser adapters import `playwright-core`
lazily). English, ASCII in source files - the vendored copies under
ES modules, Node 22+, no runtime dependencies in `conformance/backend/`,
`conformance/frontend/` and `renderers/` (the browser adapters import
`playwright-core` lazily). English, ASCII in source files - the vendored copies under
`conformance/frontend/adapters/vendor/` are byte-equal to upstream and
exempt. Markdown wrapped at ~78 columns.
50 changes: 50 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,56 @@

## Unreleased

- **Specification revision 0.3 - the maintainer's decisions** on the ten
open questions ([spec/open-questions.md](spec/open-questions.md), each now
"Decided (revision 0.3)" with its rationale):
- NEST/NEST2 stay tolerated-not-rendered by portable renderers; portable
*apps* must not use them - the abap2UI5 linter's portable rule
(`profiles/portable.md` section 2).
- A backend MUST NOT reflect request data it did not validate into the
error body (`spec/errors.md`); new backend check **`error.no-reflection`**
(MUST). Both reference backends (abap2UI5 1.146.0 via
`@abap2ui5/node-runtime`, cap2UI5 on it) fail it - the URL is reflected
verbatim by [H] `request_context_info`; the fix is made in abap2UI5
core. Pinned as an expected failure in `test/lib/expected.mjs`; the
suite traffic is recorded again (`counts.fail` 1 on both).
- Message box details shown expanded (the UI5 frontend is being fixed),
one roundtrip at a time with the client queueing (`spec/transport.md`),
`sap-contextid` kept by every HTTP frontend - as they were.
- **`portable-v1.json` separates the client API from the wire**: a new
`actions` object with `actions.api` (the `follow_up_action( )` names a
portable app may call) and `actions.wire` (what a renderer receives:
`VIEW_SLOTS`, `ROUTER` with its `routerOptions`, the names folded into
`ROUTER` - `foldedIntoRouter` - and the `T_CUSTOM` / `.eF` names).
Additive: `frontendActions` stays as it was (`allowed` = `actions.api`),
the profile stays version 1; consumers that copy the file (the Web
Components frontend) keep working and re-copy it to read the new key.
Schema, `scripts/render-portable.mjs` (a generated table in
`profiles/portable.md` section 6) and `scripts/gen-portable-profile.mjs`
follow.
- **Adaptive Cards renderer prototype** (`renderers/adaptive-cards/`,
export `@abap2ui5/protocol/renderers/adaptive-cards`): an abap2UI5
response (portable profile) -> an Adaptive Card 1.5, and an
`Action.Submit` payload -> the next protocol request (event, arguments,
the model delta of the changed inputs, whose ids are binding paths). All
65 controls of portable profile v1 mapped (the README's mapping table is
generated from `mapping.mjs`), unknown controls as placeholders listed in
`unsupported`, a minimal card host speaking the protocol over HTTP, a demo
for the designer, golden cards of recorded traffic. Pure Node, built on
the vendored mcp-server `viewxml` / `snapshot` modules.
- **Frontend adapter `adaptive-cards`** (in process): the renderer passes
every one of the 65 checks of the portable profile it can be driven
through (16 skipped: URL, DOM, focus, title, model edits; UI5 and semantic
profiles). Pinned in `test/frontend.test.mjs`; CI uploads its report.
- **Agent client re-vendored** at abap2UI5/mcp-server `a4d9f07` (PR #44):
it now follows every frontend rule that applies - 61 pass, 0 fail, 0
warn, 20 skip (was 5 MUST failures and 3 warnings at `ea4e9fa`); the pin
in `test/frontend.test.mjs` follows. The Web Components frontend at its
main `410d607` measures 68 pass / 0 fail / 13 skip, with
`model.number-and-boolean` failing intermittently (RESULTS.md).
- The UI5 SPA pin accepts `portable.box-details` passing (its fix is under
way); CI checks that `npm run generate` leaves no diff.

- **Frontend conformance suite** (`abap2ui5-conformance frontend --adapter
ui5|agent|webcomponent [--profile core|portable|ui5|semantic]`, library
`runFrontendSuite`, also at `@abap2ui5/protocol/frontend`): a scripted
Expand Down
39 changes: 26 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,12 @@ repository writes it down.
backend the backend suite - plays the frontend over HTTP (implemented)
frontend the frontend suite - plays the backend, adapters for (implemented)
the UI5 SPA (Playwright), the agent client, the
Web Components frontend
Web Components frontend, the Adaptive Cards renderer
apps the conformance apps: ABAP classes + cap2UI5 twins
hosts the two reference backends, started with the apps deployed
renderers/
adaptive-cards a portable renderer without a browser: response -> Adaptive
Card 1.5, Action.Submit -> request (prototype)
traffic/ real traffic of both reference backends and three frontends
```

Expand All @@ -45,22 +48,28 @@ source file and method it was derived from ([spec/README.md](spec/README.md#sour

## Status

- **Protocol 2**, specification revision 0.2, derived from abap2UI5 1.146.0
(commit `b812079`).
- **Backend suite: 75 checks** (61 MUST, 14 SHOULD; 68 core, 7 UI5 profile).
Green against both reference backends - `node-runtime` 75/75,
`cap2ui5` 74/75 with one SHOULD warning ([conformance/RESULTS.md](conformance/RESULTS.md)).
- **Schemas** validate all 334 recorded requests, 320 responses and 18 agent
- **Protocol 2**, specification revision 0.3, derived from abap2UI5 1.146.0
(commit `b812079`); the maintainer decided the ten open questions
([spec/open-questions.md](spec/open-questions.md)).
- **Backend suite: 76 checks** (62 MUST, 14 SHOULD; 69 core, 7 UI5 profile).
Both reference backends pass every check but `error.no-reflection`, new in
revision 0.3 (the request URL reflected into the 500 body; fixed in
abap2UI5 core, pinned until the runtime release carries it) -
`node-runtime` 75/76, `cap2ui5` 74/76 with one SHOULD warning
([conformance/RESULTS.md](conformance/RESULTS.md)).
- **Schemas** validate all 336 recorded requests, 320 responses and 18 agent
snapshots, checked by the shipped validator and by ajv.
- **Portable profile v1** filled from a census of 247 core apps (73.7 % by
controls, 64.8 % run unchanged).
- **Frontend suite: 81 checks** (66 MUST, 15 SHOULD; 66 core, 8 portable,
4 UI5, 3 semantic), scripted from the recorded traffic. The official UI5
SPA passes every MUST but one - message box details stay empty on OpenUI5
>= 1.120; the agent client fails 5 MUSTs (no PROTOCOL check, no
`sap-contextid`, overlapping acts, popups kept across an app change, error
markup stripped) ([conformance/RESULTS.md](conformance/RESULTS.md#frontend-suite)).
- Decisions still open for the maintainer: [spec/open-questions.md](spec/open-questions.md).
>= 1.120 (fix under way); the agent client (mcp-server `a4d9f07`) and the
Adaptive Cards renderer pass every check that applies to them (61 and 65);
the Web Components frontend 68 of 68, with one intermittent failure ([conformance/RESULTS.md](conformance/RESULTS.md#frontend-suite)).
- **Adaptive Cards renderer** (prototype, [renderers/adaptive-cards/](renderers/adaptive-cards/README.md)):
all 65 portable controls mapped onto Adaptive Cards 1.5, the way back from
an `Action.Submit` to the next request, golden cards of recorded traffic.
- Not yet run against an ABAP system.

## Run the backend suite
Expand All @@ -87,6 +96,7 @@ Options, the library API and the check list:
```bash
npx abap2ui5-conformance frontend --adapter ui5 # the UI5 SPA (ABAP2UI5_HOME=<abap2UI5 checkout>) in Chromium
npx abap2ui5-conformance frontend --adapter agent # the agent client of abap2UI5/mcp-server
npx abap2ui5-conformance frontend --adapter adaptive-cards # the Adaptive Cards renderer of this package
```

Adapters, options and the check list:
Expand All @@ -96,11 +106,14 @@ Adapters, options and the check list:

```bash
npm test # schemas, traffic, docs, portable profile, CLI, both backends,
# the frontend suite (agent client; UI5 SPA with a checkout + Chromium)
# the frontend suite (agent client, Adaptive Cards renderer;
# UI5 SPA with a checkout + Chromium), the golden cards
# (PROTOCOL_SKIP_BACKENDS=1 / PROTOCOL_SKIP_BROWSER=1 skip the slow parts)
npm run record # re-record traffic/ from both backends
npm run lint:abap # abaplint over the ABAP conformance apps
npm run generate # regenerate the check list and the portable-profile sections
npm run generate # regenerate the check lists, the portable-profile sections and
# the Adaptive Cards mapping table
npm run demo:adaptive-cards -- slots.popup-destroy 0 1 # a recorded response as card JSON
```

Node 22 or later. The package has no runtime dependencies; the dev
Expand Down
4 changes: 2 additions & 2 deletions conformance/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ swapped independently:

| Suite | Plays | Tests | Status |
|---|---|---|---|
| [backend/](backend/README.md) | the frontend | a backend, over HTTP, against the conformance apps | implemented - 75 checks, `abap2ui5-conformance backend` |
| [frontend/](frontend/README.md) | the backend | a frontend, by scripted responses (recorded traffic + synthetic edge cases), through an adapter per frontend | implemented - 81 checks, `abap2ui5-conformance frontend --adapter ui5\|agent\|webcomponent` |
| [backend/](backend/README.md) | the frontend | a backend, over HTTP, against the conformance apps | implemented - 76 checks, `abap2ui5-conformance backend` |
| [frontend/](frontend/README.md) | the backend | a frontend, by scripted responses (recorded traffic + synthetic edge cases), through an adapter per frontend | implemented - 81 checks, `abap2ui5-conformance frontend --adapter ui5\|agent\|webcomponent\|adaptive-cards` |

The **conformance apps** ([apps/](apps/README.md)) are what a backend serves
for the backend suite: small apps with exactly specified behaviour, shipped
Expand Down
Loading
Loading