# Manually Test the @storyblok/management-api-client Package

`@storyblok/management-api-client` is the Management API (MAPI) client. The key things to validate
manually are that the schema-aware `.withTypes()` integration correctly narrows story content, that
every define helper produces a valid creation payload, and that Zod schemas accept real API
responses.

## Automated e2e tests

The `@storyblok/mapi-integration-tests` package
(`packages/mapi-client/playground/integration-tests`) covers the full round-trip against a real
Storyblok space in `test/specs/mapi-round-trip.spec.e2e.ts`:

- Seeds components, datasources, internal tags, presets, and stories via the MAPI.
- Validates runtime values, type narrowing, nested bloks (two- and three-level), unwhitelisted
  bloks, and update round-trips.
- Validates MAPI Zod schemas (`componentSchema`, `storySchema`, `datasourceSchema`,
  `datasourceEntrySchema`) against real API responses.

Run manually:

```bash
pnpm --filter @storyblok/mapi-integration-tests test:e2e
```

### Prerequisites

- A `.env.qa-engineer-manual` file at the repo root with `STORYBLOK_TOKEN` and `STORYBLOK_SPACE_ID`.
- `@storyblok/management-api-client` must be built first.

## Fetch via MAPI client and check content types

`stories.get(storyId)` takes a numeric/string ID as its first positional argument — there is no
`getBySlug`. Fetch the ID from `stories.list` first:

```ts
import { createManagementApiClient } from "@storyblok/management-api-client";

const client = createManagementApiClient({
  personalAccessToken: process.env.STORYBLOK_TOKEN,
  spaceId,
});
const list = await client.stories.list({ query: { per_page: 100 } });
const story = list.data?.stories?.find((s) => s.slug === "home");
const result = await client.stories.get(story.id);
console.info(result.data?.story?.content);
```

## Push component JSONs via the CLI

To push `defineComponent` components, serialize the component objects to JSON and stage them under
`.storyblok/components/<space_id>/`:

```bash
node packages/cli/dist/index.mjs components push \
  --from qa-test \
  --space $STORYBLOK_SPACE_ID \
  --separate-files
```

**Always push components before stories.** The CLI validates that each story's `content.component`
(and any nested block components) exist in the space. Pushing stories first fails if the referenced
components are not yet present.

You can do the same with stories. **Story filename convention:** the CLI requires files named
`{slug}_{uuid}.json` where the part after the last `_` exactly matches `story.uuid` in the JSON. Use
hyphens (not underscores) in UUIDs. A mismatch causes Pass 2 of the push (reference mapping +
content update) to silently skip all stories.

## Known quirks

- **Stories require a content type component (`is_root: true`).** The MAPI rejects story creation
  with `"please select a content type component as your root component"` if the component used as
  the story root does not have `is_root: true`.
- **MAPI `stories.get` takes a positional ID, not an options object:** `client.stories.get(id)` —
  there is no `getBySlug`. The `list` response does not include `content`; call `get(id)` for full
  content.
- **MAPI client constructor uses `personalAccessToken`:**
  `createManagementApiClient({ personalAccessToken: '...', spaceId: ... })`.
- **Delete methods are `delete`:** Use `client.RESOURCE.delete(id)`.
- **Each story JSON must have a unique `id`.** If multiple story files share the same `id`, the
  CLI's manifest maps all of them to the same `old_id` entry, causing "slug already taken" errors.
