Testing logo

Testing

Organization
RevenueCat
testing

Use this skill when testing a Google Play Billing integration. Covers license test accounts, static test responses, Play Console sandbox purchases, and subscription lifecycle acceleration for renewals, grace period, and account hold.

Overview

PublisherRevenueCat
Repositoryplay-billing-skills
Skill nametesting
Stars
58
Forks
0
Bundled files
Instructions only
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by RevenueCat on GitHub. Read the source before you install it.

Installation

Install the Testing AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/RevenueCat/play-billing-skills/tree/main/google-play/testing
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/RevenueCat/play-billing-skills.git /tmp/play-billing-skills
mkdir -p .claude/skills
cp -r /tmp/play-billing-skills/google-play/testing .claude/skills/testing
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Testing in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Testing on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Testing is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Testing Your Play Billing Integration

A billing build that runs on your laptop is not evidence that it works in production. Real users hit payment declines, pending cash payments, grace periods, and account holds. Use Google's license testers, Play Billing Lab, and the accelerated sandbox to exercise every state you claim to support before you release.

Phase 1: Discovery

Before you test anything, confirm the environment is wired up. Skipping a step here leads to purchase dialogs that charge real money or flows that never show test cards.

Run through this checklist:

  • License testers list: Play Console -> Settings -> License testing. The Gmail you test with must appear here. Testers are set at the developer account level, apply to every app you own, and propagate within minutes.
  • Test track upload: Your APK or AAB must sit on internal, closed, or open testing. The license tester benefit only activates after you have uploaded the app at least once. Internal testing ships in minutes and is the right default for billing work.
  • Signed in account: The license tester account must be on the test device. With several accounts, the purchase uses the account that downloaded the app, or the first account on the device if none did (for example a sideloaded debug build). Expand the purchase dialog to confirm which account is paying.
  • Play Billing Lab installed: Install the Play Billing Lab companion app from the Play Store on the test device. You need it for country overrides, trial resets, state transitions, and the response simulator.
  • enablePendingPurchases: every BillingClient that sets a purchases listener must call enablePendingPurchases(PendingPurchasesParams.newBuilder().enableOneTimeProducts().build()), or build() throws. Add enablePrepaidPlans() only if you sell prepaid plans and handle pending prepaid purchases.

If any item is missing, fix that first. License tester tooling is invisible otherwise.

Phase 2: Plan

Pick a strategy that matches what you changed. Running all 11 subscription test cases on every PR is wasteful. Running none is reckless.

Change typeMinimum coverage
New purchase flow or product catalogNew purchase, acknowledgment, entitlement grant
Subscription lifecycle logicRenewal, grace period, account hold, cancellation
Plan change or upgrade codeEach replacement mode you support, plus linkedPurchaseToken handling
RTDN or server integrationRenewal, grace, hold, revoke, refund notifications end to end
Error handling or retry pathsResponse simulator sweep: NETWORK_ERROR, ITEM_ALREADY_OWNED, USER_CANCELED, BILLING_UNAVAILABLE; for a lost service connection, force stop the Play Store app while connected
Pre release candidateFull 11 case suite plus one real payment on the cheapest SKU

Test product static responses

Inside the Play purchase dialog, license testers see five virtual instruments instead of real cards. Each one forces a deterministic outcome, so pick the one that matches the path you want to exercise.

Test instrumentResultUse when you are testing
Test card, always approvesImmediate success, BillingResponseCode.OKHappy path, acknowledgment, entitlement grant
Test card, always declinesImmediate failure, BillingResponseCode.ERRORDecline UI, error messaging, absence of entitlement grant
Slow test card, approves after a few minutesPending state, then success after minutesPending purchase handling, UI state, PurchasesUpdatedListener firing twice
Slow test card, declines after a few minutesPending state, then final failurePending decline path, cleanup of pending UI
Test card, approves then charges backSuccess, then a simulated chargeback initiated by the userChargeback and refund review handling, PendingRefundReviewNotification RTDN

Before you pick an instrument, decide what signal proves the test passed: a specific response code, a purchase state transition, an RTDN on your server, or an entitlement change in the app. Write it down first.

Pick a lifecycle scenario

If you are exercising the subscription state machine, choose one of these as your first target:

  • Renewal succeeds: cheapest scenario, verifies RTDN plumbing.
  • Grace period enter and recover: verifies you keep access up during grace and re grant after recovery.
  • Account hold enter and recover: verifies you revoke access during hold and restore after payment fix.
  • Pause and resume: only if your product allows pausing.
  • Upgrade with replacement mode: verifies linkedPurchaseToken handling on the server (the app only sees the new purchase token).

Phase 3: Execute

Step 1: Run a sandbox purchase

Open your app on the test device signed in with the license tester account.

  1. Trigger your normal product list query. Confirm prices render and the product appears.
  2. Launch the billing flow. Expect the Play purchase sheet to show the five test instruments rather than real cards.
  3. Pick "Test card, always approves".
  4. Confirm PurchasesUpdatedListener fires with BillingResponseCode.OK and a Purchase in the PURCHASED state.
  5. Acknowledge the purchase from your server or client path.
  6. Call queryPurchasesAsync and confirm the purchase is returned as active.
  7. Confirm your app grants the matching entitlement.

To prove your acknowledgment path works, repeat the flow but skip step 5 on purpose:

  1. Make the purchase.
  2. Do not acknowledge.
  3. Wait 3 minutes.
  4. Re query purchases and confirm Google has auto refunded and the entitlement is gone.

If the entitlement is still present after 3 minutes, your app is caching state without rechecking. Fix that before shipping.

Step 2: Accelerate the subscription lifecycle

Test subscriptions run on a compressed schedule automatically. You do not configure this.

Production renewal periodTest renewal period
Weekly5 minutes
Monthly5 minutes
Quarterly10 minutes
Semi annual15 minutes
Yearly30 minutes

Intermediate states compress too: free trial runs 3 minutes, grace period runs 5 minutes, account hold runs 10 minutes. Test subscriptions cancel after 6 renewals regardless of period, so plan accordingly.

To watch a full lifecycle in under 20 minutes:

  1. Start a new monthly subscription using the always approves test card.
  2. Wait 5 minutes for the first renewal. Confirm your server receives an RTDN with SUBSCRIPTION_RENEWED and the entitlement remains active.
  3. Open Play Billing Lab and trigger a payment failure at the next renewal.
  4. Verify the subscription enters grace period and your app still grants access.
  5. Wait 5 minutes. Grace expires, the subscription moves to account hold, your app revokes access.
  6. Wait 10 minutes. Account hold expires and the subscription cancels.
  7. Confirm RTDNs for SUBSCRIPTION_IN_GRACE_PERIOD, SUBSCRIPTION_ON_HOLD, and SUBSCRIPTION_CANCELED each landed.

Use Play Billing Lab to force specific transitions instead of waiting on timers when you only need to verify one state. It also lets you reset trial eligibility so you can rerun trial sign up on the same account.

Step 3: Exercise error paths with the response simulator

Play Billing Lab ships a response simulator that overrides the BillingResult of launchBillingFlow, acknowledgePurchase, consumeAsync, and queryProductDetailsAsync with a chosen positive response code. It cannot return negative codes such as SERVICE_DISCONNECTED, and it does not drop the service connection. Configure a rule, run the flow, confirm your app recovers.

Opt the test build in (PBL 7.1.1+), in a debug or test manifest only:

xml
<meta-data android:name="com.google.android.play.largest_release_audience.NONPRODUCTION" android:value="" />
<meta-data android:name="com.google.android.play.billingclient.enableBillingOverridesTesting" android:value="true" />

Open Play Billing Lab before your app, and confirm the Play Billing Lab status bar icon shows the connection.

Minimum response codes to cover:

  • Lost service connection (not simulated: force stop the Play Store app while connected): your app reconnects on the next call and retries.
  • NETWORK_ERROR on acknowledgePurchase: your app retries, because unacknowledged purchases refund in 3 days in production.
  • ITEM_ALREADY_OWNED on launchBillingFlow: your app refreshes purchases and messages the user correctly.
  • USER_CANCELED: your app returns to the previous screen without an error banner.
  • BILLING_UNAVAILABLE on connect: your app hides purchase options gracefully.

Step 4: Enable pending purchases

Pending purchases are mandatory for one time products. Configure your client once and then test with the slow approve card.

kotlin
val billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases(
        PendingPurchasesParams.newBuilder()
            .enableOneTimeProducts()
            // .enablePrepaidPlans() // only if you sell prepaid plans and handle pending prepaid purchases
            .build()
    )
    .build()

Guard entitlement grants by purchase state:

kotlin
when (purchase.purchaseState) {
    Purchase.PurchaseState.PURCHASED -> grantAndAcknowledge(purchase)
    Purchase.PurchaseState.PENDING -> showPendingUi(purchase)
    else -> Unit
}

Verify the pending to purchased transition delivers a second PurchasesUpdatedListener callback (or appears in queryPurchasesAsync() on resume), that a declined slow card never grants access after an app restart, and that your server processes ONE_TIME_PRODUCT_PURCHASED/SUBSCRIPTION_PURCHASED or ONE_TIME_PRODUCT_CANCELED/SUBSCRIPTION_PENDING_PURCHASE_CANCELED.

Step 5: One real payment before production

License tester cards do not exercise 3D Secure prompts, card verification, refund processing, or financial reporting. Before your first production push:

  1. Make one real purchase on your cheapest product using an account on your internal test track.
  2. Request a refund through Google Play. Verify the refund RTDN arrives and your app revokes access.
  3. Confirm the purchase and refund both appear in Play Console financial reports.

Common mistakes

  • Caching entitlements locally without revalidating against queryPurchasesAsync. The 3 minute auto refund window exposes this.
  • Granting access during PENDING state. The slow decline card exposes this.
  • Treating a restored subscription as a new purchase after a user cancels and resubscribes inside the same period.
  • Using CHARGE_PRORATED_PRICE on a downgrade. It will fail at runtime.
  • Revoking access the moment the user cancels, instead of at period end.
  • Revoking access during grace period, which is meant to preserve access while Google retries payment.

References

Frequently asked questions

What does the Testing AI skill do?

Use this skill when testing a Google Play Billing integration. Covers license test accounts, static test responses, Play Console sandbox purchases, and subscription lifecycle acceleration for renewals, grace period, and account hold.

Why use Testing on TypingMind?

Because you install it once and use it with any model. Testing is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Testing in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/RevenueCat/play-billing-skills/tree/main/google-play/testing. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Testing?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Testing?

As many as you like. As long as a model supports skills, you can use Testing with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Testing AI skill free?

Yes. It is published on GitHub by RevenueCat under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇