# Connecting a kit — each seam with the code that connects it

> Prints a kit's composition surface — every event, policy, setting, slot, contract, base, grant, extension member, action and page an app connects — each with the kit's own test app code that connects it and the tests that show it working; `--tests-for` prints those tests whole with the test app code they call.

<!-- id: local-connecting-a-kit · area: local · stability: stable · html: https://osysharp.com/reference/local/connecting-a-kit/ -->

## Summary        {#summary}

Once you have chosen a kit, `osy kits <kit> --surface` shows how to connect it — not as a description, but as working
code. For each seam an app connects, it prints the kit's own **test app** declaration that connects it, verbatim — the
`[On]` handler, the `policy` line, the `app.X = new …` setting, the contribution to a slot — and the **tests** that show
that seam working. Copy the shape; `--tests-for <seam>` prints the tests whole.

```console
$ osy kits Osysharp.SatisfactionSurveys --surface
Policies — your app defines these
  policy ManagesFeedback;  — your app defines it
    Who decides whether, when and for how long people are asked — the settings page.
    ── tests/model/app.osy:17 ──
    policy ManagesFeedback => IsOwner;
    shown by tests/ui.test.osy::the_owner_decides_whether_and_when_people_are_asked · …

Events — what happens; hear one with `[On] void H(TheEvent e)`
  [Event("Feedback answered")] FeedbackAnswered { Ask, Change }
    Somebody answered (`FeedbackChange.First`) or changed their answer (`Changed`).
    raised by ApplyFeedbackReply
    ── tests/model/app.osy:48 ──
    /// What the workshop does as customers answer: the answer is noted on the repair.
    [On]
    void RepairAnswered(FeedbackAnswered e) {
      if (e.Ask.About is Repair r) {
        new RepairNote { Repair = r, Says = (e.Change == FeedbackChange.First ? "answered " : "changed to ")
                                            + (e.Ask.Rating == FeedbackRating.Bad ? "bad" : "good") };
      }
    }
    shown by tests/answers.test.osy::a_finished_repair_asks_its_customer_and_one_click_answers · …
```

## Signature      {#signature}

```console
osy kits <kit> --surface            # every seam, each with its test app code and the tests that show it
osy kits <kit> --tests-for <seam>   # the tests for one seam, whole, with the test app code they call
  --offline                         # a kit not on this machine: do not fetch its examples from its release
  --project <dir>                   # where to look for kits (default: the current directory)
  --json                            # { seams: [{ kind, name, signature, doc, declaredAt, examples, tests, mustBeTested }] }
```

`<kit>` is a package name (`Osysharp.SatisfactionSurveys`), its last segment (`feedback`) or its directory in this repository. A
kit this project does not use yet is fetched from its newest release, so you can read it before writing the `use` line.

## Description    {#description}

### What the seams are    {#seams}

| kind | what your app writes | the example shown |
|---|---|---|
| **setting** | `app.Feedback = new FeedbackSetup { … }` | the test app's line; fields with no default are marked |
| **policy** | `policy ReadsFeedback => …;` — a question the kit asks, which your app answers with its own roles | the test app's definition |
| **base** | a type of your own derived from the kit's (`Customer : Party`) — required when the base is `abstract` | the test app's subtype |
| **grant** | `partial entity FeedbackAsk { security { allow create when IsStaff; } }` | the test app's grant |
| **event** | `[On] void H(TheEvent e) { … }` to react after the commit | the test app's handler; who raises it |
| **slot** | a component `: TheSlot` drawn where the kit's page draws the slot | the test app's contribution |
| **contract** | a class implementing the kit's interface, named in its setting | the test app's implementation |
| **extension** | nothing — a bridge adds these members to another kit's record | the tests that read them |
| **action** | nothing — an action the kit offers on a record | the test app code that runs it |
| **appPage** | a page at the route the kit links to (`appPage "/bag";`) | the test app's page |
| **page** · **hears** · **starts** | nothing — pages the kit serves, events it hears, what it starts by itself | — |
| **call** | the kit's functions your test app calls | the test app code that calls it |

A **bridge** that completes the kit with another is listed first: it arrives by itself in an app that uses both
([Bridges — a package that arrives when an app uses the two it completes](https://osysharp.com/reference/project/bridges/)).

### Which test shows a seam    {#which-test}

The mapping is derived, never written by hand. Each test's names are followed through the test app's declarations and
the kit's — a test calls the test app's `FinishRepair`, which calls the kit's `AskForFeedback`, … which raises
`FeedbackAnswered` — and a test that reaches the seam in at most four steps shows it. The nearest come first; a test that
also reaches what the test app's code LEAVES BEHIND (the record a handler creates, the contribution a slot draws) comes
before one that only touches the seam.

Two things a test does without naming them count too. A test that opens a page by its address —
`Ui.Visit("/orders/" + id)` for `[Route("/orders/{id}")]` — reaches that page and everything it draws. And a setting is
shown by a test that asserts a value the test app gave it: the test app's `AppName = "Studio"`, read back in
`Assert.Equal("1 thing waiting for you in Studio", …)`, because a setting is usually read by work the kit delivers after
the commit, which no test calls by name.

An abstract base the kit completes itself — the shared half of two connectors it ships — is the kit's own plumbing, not
a seam: an app declares a connector and never derives the base, so it is listed only where the test app does.

A seam no test shows is said to be one — `no test shows it` — and `osy kits check` reports it as `KIT_SEAM_UNTESTED`,
which `osy publish` refuses ([Checking a kit composes — osy kits check](https://osysharp.com/reference/local/checking-a-kit/)).

### The tests for one seam    {#tests-for}

`--tests-for <seam>` prints the seam, the test app code that connects it, then up to three tests whole — the one that
shows the outcome first — and the test app's own declarations those tests call, so the arrange step is visible:

```console
$ osy kits Osysharp.SatisfactionSurveys --tests-for FeedbackAnswered
[Event("Feedback answered")] FeedbackAnswered { Ask, Change } (event of Osysharp.SatisfactionSurveys)

── tests/model/app.osy:48 — the test app fills it ──
[On]
void RepairAnswered(FeedbackAnswered e) { … }

── tests/answers.test.osy:9 — the test ──
[Test(Workshop)]
void a_finished_repair_asks_its_customer_and_one_click_answers() {
  Finish("city bike");
  …
  Assert.Equal(["answered good"], NotesOn("city bike"));
  …
}

── tests/workshop.test.osy:… — the test app's NotesOn, which the test calls ──
…
```

### Where the examples come from    {#examples}

In a repository that holds the kit, from its directory: the test app named by `tests "…";` in its `package.osy`. For a
kit fetched from GitHub, from **`examples.zip`**, the second file of every release — `osy publish` uploads the test app
and its tests beside `package.zip`. They are not inside the package on purpose: a package's address is the hash of what
an app compiles, and a test is not compiled into anyone's app. The examples are cached beside the package, so a kit is
fetched once. A release published before kits shipped their tests says so, naming the file it did not find.

## See also       {#see-also}
- [Finding a kit, and learning one from its tests](https://osysharp.com/reference/local/finding-a-kit/) — `osy kits find`: kits by what they do; `osy kits <kit>`: its purpose and every test
- [Composing kits — what they give together, and what is left for you](https://osysharp.com/reference/local/composing-kits/) — `osy compose`: what kits give together and what is left for you
- [Checking a kit composes — osy kits check](https://osysharp.com/reference/local/checking-a-kit/) — `osy kits check`: `KIT_SEAM_UNTESTED`
- [[Event] — what happens to a record, declared once](https://osysharp.com/reference/function/event/) · [[On] — hear an event, after the commit that raised it](https://osysharp.com/reference/function/on/) — events, and hearing one
- [Slot (child content)](https://osysharp.com/reference/ui/slots/) · [[Slot] and contributions — a place on a page that other kits, and the app, add to](https://osysharp.com/reference/ui/contributions/) — slots, and contributing to one
- [settings a package asks its app for (app settings)](https://osysharp.com/reference/config/app-settings/) — `app.X = new …`
