MCPInstall

roblox-testing

Test, debug, or profile Roblox experiences. Use for Studio debugging, TestEZ, logging, connection cleanup, memory or network diagnostics, MicroProfiler, Scene Analysis, and Script Profiler.

Installs
330
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/nonlooped/roblox-suite --skill roblox-testing
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads roblox-testing automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

roblox-testing

Official sources:

Start with a reproducible failure and identify whether it occurs on the client, server, or both. Choose a debugging or profiling tool based on that evidence.

The debugging mindset

  1. Reproduce it. If you can't reproduce it, you can't fix it.
  2. Isolate it. Remove systems until the bug disappears; the last thing removed is the cause.
  3. Measure it. Use tools instead of guessing.
  4. Fix one thing at a time. Verify the fix and add a regression test if possible.
  5. Log defensively. Good logs make future debugging faster.

Logging discipline

Use print, warn, and error deliberately:

  • print for normal diagnostics.
  • warn for recoverable problems you should notice.
  • error for programming errors that should stop execution.

Include context in log messages:

warn(string.format("[DataStore] Save failed for %d: %s", userId, tostring(err)))

Avoid logging secrets, player data, or PII.

pcall and assertions

Wrap fallible calls, especially cloud services, HTTP, DataStores, Marketplace:

local ok, result = pcall(function()
    return someService:DoSomething()
end)
if not ok then
    warn("DoSomething failed:", result)
end

Use assert for internal invariants that should never fail:

assert(config.MaxSpeed > 0, "MaxSpeed must be positive")

Developer Console

Open with F9 in-game or in Studio play mode.

Tabs:

  • Log: client/server output, errors, warnings.
  • Memory: categorized memory usage.
  • Network: HTTP and service requests.
  • Server Stats: heartbeat, ping, data ping.
  • Script Profiler: record script CPU usage.
  • MicroProfiler: capture server dumps.

Toggle Client/Server views to see which side emitted output.

Unit testing with TestEZ

The standard Roblox testing framework is TestEZ. It supports nested describe/it blocks, lifecycle hooks, async tests, and a rich matcher API.

TestEZ example:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TestEZ = require(ReplicatedStorage.DevPackages.TestEZ)

local MathUtils = require(ReplicatedStorage.MathUtils)

describe("MathUtils", function()
    it("clamps values", function()
        expect(MathUtils.clamp(5, 0, 10)).to.equal(5)
        expect(MathUtils.clamp(-1, 0, 10)).to.equal(0)
        expect(MathUtils.clamp(11, 0, 10)).to.equal(10)
    end)
end)

TestEZ.TestBootstrap:run({ game.ReplicatedStorage.Tests })

For legacy in-Studio tests, TestService:Error(msg) can mark failures visibly in Studio output, but most projects should prefer TestEZ. The scripts folder contains a minimal TestRunner.lua shim only for environments where TestEZ is unavailable.

Luau type checking

Use the Luau language server (luau-lsp) or the Luau type checker in Studio to catch errors before runtime.

Best practices:

  • Add type annotations to module exports and pure functions.
  • Run luau-lsp analyze in CI or before committing.
  • Enable --!strict for new modules.
  • Do not over-type untyped engine APIs; prefer casts at boundaries.

Studio Debugger

Use Studio's built-in debugger for step-through debugging:

  • Set breakpoints by clicking the gutter next to a line number.
  • Run in Play mode and use the debugger controls to step over, into, or out.
  • Inspect the call stack, local variables, and upvalues in the debugger panel.
  • The debugger works in both client and server contexts when Studio runs both.

xpcall and debug.traceback

Use xpcall with debug.traceback to capture full stack traces from failures:

local ok, err = xpcall(function()
    riskyOperation()
end, debug.traceback)
if not ok then
    warn(err)
end

This is especially useful at top-level entry points, scheduled callbacks, and connection handlers where pcall alone discards the stack.

Connection cleanup

Leaked RBXScriptConnection objects are a common source of memory leaks and stale state. Prefer explicit cleanup patterns:

  • Use a Maid/Janitor-style collector:
local Maid = require(path.to.Maid)
local maid = Maid.new()

maid:GiveTask(workspace.ChildAdded:Connect(onChild))
maid:GiveTask(RunService.Heartbeat:Connect(onStep))

maid:Destroy() -- disconnects everything
  • Use :Once() for one-shot event handlers.
  • Use Instance.Destroying to trigger cleanup when an instance is removed:
obj.Destroying:Connect(function()
    cleanup()
end)
  • Always pair :Connect() with a matching :Disconnect() or destruction.

Prefer task over spawn/delay

The task library is more predictable than legacy spawn, delay, and wait:

-- good
task.wait(1)
task.delay(1, callback)
task.spawn(coroutineOrFn)

-- avoid
spawn(callback)
delay(1, callback)
wait(1)

task.defer is useful for yielding to the next resumption cycle without opening a new thread.

Log rate limiting and secrets hygiene

  • Never log secrets, keys, user identifiers, or personal information.
  • Sanitize values before logging:
local function sanitize(value)
    if typeof(value) == "Instance" and value:IsA("Player") then
        return "Player(" .. tostring(value.UserId) .. ")"
    end
    return value
end
  • Rate-limit noisy logs to avoid flooding the console and network:
local lastLog = 0
local function throttledLog(message)
    local now = os.clock()
    if now - lastLog > 5 then
        lastLog = now
        warn(message)
    end
end

Network ownership

Incorrect network ownership causes jittery physics and replication lag. Visualize ownership and assign it explicitly:

-- Server
part:SetNetworkOwner(player)

-- Client-side visualization (debug only)
local ownershipLabel -- create BillboardGui or use DebugDraw

Use BasePart:GetNetworkOwner() to inspect ownership. Vehicles and held items should usually be owned by the controlling player.

DataStore retry pattern

For retry-safe reads, use bounded retries with exponential backoff and jitter. Do not use this generic loop to replay writes: a failed response can hide a committed write, and independently retried requests can execute out of order. See roblox-datastores for write reconciliation and per-key ordering.

local function readWithRetry(fn, maxAttempts)
    maxAttempts = maxAttempts or 5
    for attempt = 1, maxAttempts do
        local ok, result = pcall(fn)
        if ok then
            return true, result
        elseif attempt == maxAttempts then
            return false, result
        else
            warn("DataStore attempt " .. attempt .. " failed; retrying...")
            task.wait(2 ^ attempt * 0.1 + math.random() * 0.5)
        end
    end
end

Always call DataStores from the server and validate serialization before saving.

Memory snapshot comparison

Use the Developer Console Memory tab or Scene Analysis to compare snapshots:

  1. Capture a baseline snapshot in a stable state.
  2. Play through the action that may leak (spawn/despawn enemies, open/close UI).
  3. Return to the stable state and capture a second snapshot.
  4. Compare PlaceMemory, Luau heap, and instance counts.
  5. Investigate categories that did not return to baseline; look for unparented instances in Scene Analysis.

MicroProfiler

Open with Ctrl+F6 (⌘+F6) in Studio or the desktop client.

Use it to:

  • Find frame-time spikes.
  • Identify whether a bottleneck is script compute, physics, or rendering.
  • Capture server dumps from the Developer Console.
  • Add custom labels with debug.profilebegin/debug.profileend.

Key colors:

  • Orange: worker thread (scripts, physics, animations) bottleneck.
  • Blue: render thread bottleneck.
  • Red: GPU wait / render complexity.

Scene Analysis

Available in Studio under Window → Performance Summary → Scene Analysis.

Views:

  • Script memory: per-script Luau heap.
  • Unparented instances: potential memory leaks held by scripts.
  • Instance composition: counts by category.
  • Audio/Animation memory: asset memory usage.
  • Triangle composition: draw call breakdown.

Scene Analysis is a Studio UI tool; there is no public SceneAnalysisService API.

Script Profiler

Records CPU time per script. Use it when MicroProfiler points to scripts but you need to know which script.

Common bug categories

SymptomLikely causes
Script silently failsMissing pcall, error swallowed, wrong script context
Data not savingDataStore called from client, non-serializable value, no pcall
Remote not workingWrong side, handler not connected, argument mismatch
Lag spikesPathfinding every frame, too many particles, unbatched loops
Physics jitterWrong network ownership, assembly splits, conflicting constraints
NPCs stuckBlocked path not recomputed, bad agent params, streaming issues
UI doesn't updateProperty not replicated, wrong parent, layout order
Memory grows foreverLeaked connections, unparented instances, cached assets

Network debugging

  • Check Network tab in Developer Console for HTTP/DataStore failures.
  • Use Shift+F3 in-game for network debug stats.
  • Distinguish network ping (round-trip time) from data ping (replication queue).
  • Use Studio's beta Network Simulator for separate inbound/outbound latency, jitter, and packet loss. Enable New Device Simulator in Beta Features, restart Studio, then open Test → Device Simulator → Network. Select Apply to activate staged changes. Ideal Fiber still adds 8 ms each way; use all-zero custom values for a zero-added-delay baseline. See network simulation.

Load time debugging

Measure load time:

local start = os.clock()
game.Loaded:Connect(function()
    print("Loaded in", os.clock() - start)
end)

Run this from a LocalScript in ReplicatedFirst. It starts timing when ReplicatedFirst replicates and stops when game.Loaded fires, so it excludes the time to connect to the server and load the avatar. Load time as players experience it, from clicking Play to the world rendering, is longer. Enable Print Join Size Breakdown in Studio Settings → Network to see the largest replicated instances.

Scripts

  • scripts/TestRunner.lua: a minimal TestEZ fallback with nested suites, lifecycle hooks, matchers, async support, and TestService integration.
  • scripts/Logger.lua: a structured logger with level filtering and guarded formatting.
  • scripts/DebugDraw.lua: utility for drawing rays, points, and boxes in 3D for visual debugging.

How to proceed

  1. Reproduce the issue reliably.
  2. Check logs and errors in the Developer Console.
  3. Determine client vs server scope.
  4. Use MicroProfiler/Script Profiler for performance issues.
  5. Use Scene Analysis for memory leaks and scene composition.
  6. Add targeted logging or tests to confirm the fix.
  7. Verify on low-end devices and with network simulation when relevant.
  8. Compare memory snapshots before and after suspected leaks.
<!-- catalog:references:start -->

Reference index

  • common-bugs-and-fixes.md: Trace a symptom to likely causes and a focused fix.
  • debugging-tools.md: Inspect logs, breakpoints, stack traces, or runtime state.
  • network-simulation.md: Reproduce latency, jitter, or packet-loss problems in Studio.
  • performance-profiling.md: Find CPU, GPU, memory, or load-time bottlenecks.
  • testing-patterns.md: Write unit tests, mock dependencies, or test client-server flows.
<!-- catalog:references:end -->

FAQ

What does the roblox-testing skill do?

Test, debug, or profile Roblox experiences. Use for Studio debugging, TestEZ, logging, connection cleanup, memory or network diagnostics, MicroProfiler, Scene Analysis, and Script Profiler.

How do I install roblox-testing?

Run npx skills add https://github.com/nonlooped/roblox-suite --skill roblox-testing in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/roblox-testing/ (personal) or .claude/skills/roblox-testing/ (project).

Which AI agents can use roblox-testing?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is roblox-testing safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains roblox-testing?

It is published by nonlooped in nonlooped/roblox-suite. It has 330 recorded installs.

More from nonlooped/roblox-suite

View all →

roblox-vfx

nonlooped/roblox-suite

Build or optimize Roblox particles, beams, trails, and highlights. Use for emitter shapes, flipbooks, one-shot bursts, animation-marker effects, distance culling, and overdraw.

Frontend & Design685 installs

roblox-animation

nonlooped/roblox-suite

Build or debug Roblox character animations, IK poses, animation-marker events, and UI or object tweens. Use for locomotion, emotes, motion blending, and timed effects.

Frontend & Design414 installs

roblox-user-interfaces

nonlooped/roblox-suite

Open the skill to read its SKILL.md instructions.

339 installs

roblox

nonlooped/roblox-suite

Open the skill to read its SKILL.md instructions.

322 installs

roblox-mcp

nonlooped/roblox-suite

Connect an AI client to Roblox Studio through MCP. Use for connection setup, Studio tools, multiple Studio windows, playtesting, or combining MCP with Script Sync.

AI & Agents321 installs

roblox-networking

nonlooped/roblox-suite

Design or review Roblox client-server communication. Use for remotes, bindables, replication, network ownership, input validation, rate limiting, and exploit defenses.

Backend & APIs315 installs

Popular testing & qa skills

View category →

tdd

mattpocock/skills

Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.

Testing & QA1.2M installs

grilling

mattpocock/skills

Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.

Testing & QA996.2K installs

migrate-to-shoehorn

mattpocock/skills

Migrate test files from as type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace as in tests, or needs partial test data.

Testing & QA484.1K installs

run-train

lllllllama/rigorpilot-skills

Rigor Train skill for deep learning research repositories. Use when a documented or selected training command should be run conservatively for startup verification, short-run verification, full kickoff, or resume, with command, config, seed, log, checkpoint, status, and metric evidence written to standardized trainoutputs/. Do not use for environment setup, exploratory sweeps, speculative idea implementation, or end-to-end orchestration.

Testing & QA337.8K installs

test-driven-development

obra/superpowers

Use when implementing any feature or bugfix, before writing implementation code

Testing & QA261.8K installs

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work

Testing & QA216.8K installs