Docs
July 10, 2026
Product

How we test our Medusa plugins

Every @gorgo plugin runs unit, integration, and contract tests against real provider APIs every day and is re-verified on the latest Medusa release, so your stores keep running reliably. Here is how the pipeline works.

How we test our Medusa plugins

When you install a payment or fulfillment plugin, you hand it your checkout, and a bug there costs real money. That is why testing for every package in the medusa-plugins monorepo is fully automated, from unit tests to daily checks against live provider APIs. This post covers the tests we run, how much of each plugin they cover, and how compatibility with the latest Medusa release is verified.

The repository currently holds 81 test files and 543 test cases across six plugins.

The types of tests and what they are for

Unit tests

Unit tests exercise a provider's logic in isolation, with no network and no database: status mapping, signature generation, receipt formatting, error parsing. Outbound HTTP is intercepted with MSW, which makes it easy to check how the plugin reacts to any provider response, including scenarios that are hard to reproduce by hand: a declined payment, a malformed webhook, a replayed event.

Integration tests

Integration tests live in separate packages and boot a full Medusa application with the plugin installed and a PostgreSQL database, using . A test database is created and dropped on every run. HTTP tests walk admin and store routes end to end; module tests call services directly. We borrowed part of the approach — the test layout and the database handling — from Medusa's own repository, where these tools are used to test the core.

Contract tests

Unit and integration tests mock the external service, so neither will notice a change on its side. Contract tests do the opposite: they call the provider's API (YooKassa, T-Kassa, Robokassa, ApiShip) and verify that the request and response shapes the plugin relies on still match reality.

In CI these tests run daily with active API keys. Any breaking change on the provider's side, be it a renamed field, a new status, or stricter validation, leads to test failures. Here, for example, is the check that will notice a new payment lifecycle status:

yookassa-sandbox.contract.spec.ts
1const KNOWN_STATUSES = [
2 "pending",
3 "waiting_for_capture",
4 "succeeded",
5 "canceled",
6] as const
7
8// ...
9
10let client: YooCheckout
11
12beforeAll(() => {
13 client = new YooCheckout({ shopId: SHOP_ID!, secretKey: SECRET_KEY! })
14})
15
16it("createPayment → getPayment → cancelPayment honours the documented lifecycle contract", async () => {
17 const idempotencyKey = `contract-no-receipt-${Date.now()}`
18 const payment = await sdkCall(() =>
19 client.createPayment(
20 {
21 amount: { value: "10.00", currency: "RUB" },
22 confirmation: { type: "redirect", return_url: "https://example.com/return" },
23 description: "medusa-plugin contract test (no receipt)",
24 metadata: { session_id: idempotencyKey, receip_tmp: "{}" },
25 },
26 idempotencyKey
27 )
28 )
29
30 expect(payment.id).toBeDefined()
31 expect(payment.status).toBeDefined()
32 expect(KNOWN_STATUSES).toContain(payment.status as any)
33 expect(payment.amount.value).toBe("10.00")
34 expect(payment.amount.currency).toBe("RUB")
35 expect(payment.confirmation).toBeDefined()
36 expect((payment.confirmation as any).confirmation_url).toMatch(/^https:\/\//)
37 // ...
38})

Plugin test coverage

Coverage varies. Payment plugins are tested most deeply, with unit, integration, and contract tests, because a payment bug is the most expensive kind. has the largest codebase and the largest test suite. The plugin is in development: for now it has only a basic smoke test.

Here are the current numbers for each plugin. The percentages are estimates of testing depth, not exact line coverage.

PluginUnitIntegrationContractCoverageBadge
88114~90%Tested with Medusa
76115~90%Tested with Medusa
6074~85%Tested with Medusa
1498019~80%Tested with Medusa
0210~60%Tested with Medusa
010~5%Tested with Medusa

What's behind the "Tested with Medusa" badge

The badge in each plugin's README updates automatically. Every morning the workflow runs the following steps:

  1. Reads the latest version from npm.
  2. Compares it with the version each plugin was last verified against.
  3. Updates the dependencies in every lagging plugin install to the new Medusa version.
  4. Runs the full test suite of all plugins.
  5. Regenerates the badge only for the plugins whose tests passed, and opens a pull request with all the updates.

Plugins are isolated from each other: if one breaks on a new Medusa release, it is excluded from the update while the rest keep being tested.

Here is what that looks like in practice. On June 25 the morning run picked up the fresh Medusa v2.17.1 and updated and tested all six plugins in about ten minutes. Five passed, and failed to build: the new version dropped the field from the type. The plugin stayed on its previous verified version, and the breakage is visible in pull request #358.

Pull request #358: five plugins tested on Medusa v2.17.1, 1c excluded from the update

The badge itself is a JSON file in the repository, rendered by shields.io. A in it means the plugin's tests actually passed on that version:

.badges/medusa-payment-yookassa.json
1{
2 "schemaVersion": 1,
3 "label": "Tested with Medusa",
4 "message": "v2.17.1",
5 "color": "green"
6}

Schedule and triggers

Three GitHub Actions workflows drive the automation:

WorkflowTriggersWhat it does
Daily 04:00 UTC, every PR/push to or manualUnit, integration, and contract tests
Daily 06:00 UTC or manualVerify against the latest Medusa, refresh badges, open a PR
Push to Version and publish changed packages via Changesets

On pull requests, runs tests only for the plugins that changed. The nightly run and manual runs test everything.

The shape of the repository

1medusa-plugins/
2├── examples/ # example Medusa projects with the plugins integrated, always on the latest Medusa
3├── integration-tests/ # Medusa installs with integration and contract tests, one per plugin
4├── packages/ # plugin npm packages, unit tests next to the code
5├── .badges/ # "Tested with Medusa" JSON per plugin
6├── scripts/ # update to a new Medusa and rebuild badges
7├── .github/workflows/ # test, update-medusa-version, publish
8└── ...

Support and the Medusa community on Telegram

All the tests are public, browse them in the gorgojs/medusa-plugins repository and read about the plugins in the documentation. Ask questions and report bugs in the Gorgo support chat or the Medusa Telegram community. Issues and Pull Requests are always welcome.