What Fidelic can run
Your org is the real answer, and one command gives it to you. This is the general shape: what works, and where it differs from a real org.
The words on this page
- Works
- Your real Apex runs, and behaves as the org would.
- Mostly works
- Your real Apex runs, but something listed beside it is modelled rather than really done, or one corner of it is refused. The row says which.
- Not supported
- Refused by name, with a reason and a file and line. Never silently wrong.
| Capability | Status | Where it differs from a real org |
|---|---|---|
| Database operations insert, update, delete, upsert and partial success | Mostly works | Savepoints and Database.merge are not supported. Database.query is. Everything else behaves as the org does. |
| Async jobs Queueable, @future, Schedulable, Batchable | Works | Jobs run inline as soon as the transaction commits, instead of being queued for later. |
| HTTP callouts HttpRequest and HttpResponse | Works | Callouts return whatever you register with POST /__emulator__/callouts. Nothing reaches the network, and a callout with no matching mock throws System.CalloutException rather than opening a socket. |
| Schema and describe describe calls and permission checks | Mostly works | Describe answers only for the objects and fields you retrieved — it refuses rather than guessing. Permission checks always answer yes, because we do not model users. |
| Custom Settings and Metadata reads of both | Works | Org-default values only. Per-user and per-profile overrides are not modelled. |
| Managed packages their objects, and their Apex | Mostly works | Your code can read and write a managed package's objects and fields — include them in your retrieval and they behave like any other object. It cannot call the package's Apex, which is not in your repo, and the package's own triggers and validation do not run here. |
| Events and email EventBus.publish and Messaging.sendEmail | Works | Events and emails are captured so you can assert on them, and never actually sent. |
| Crypto the Crypto namespace | Mostly works | Random numbers are seeded so your tests repeat. Hashing, signatures and encryption are not supported. |
Anything not listed is refused rather than guessed at: you get the file, the line, and the construct we do not support. Refusing is the point — a wrong answer you cannot see is worse than a gap you can plan around.
Your Apex test classes
Fidelic runs simple test classes. Not your suite — a fraction of it, and the fraction is published here rather than described. A test class runs if what it does is inside the capabilities above; most real test classes do something that is not.
Measured over 793 test classes and 7,518 @isTest methods in five open-source
Salesforce codebases, pinned at a commit:
- 125 of 793 test classes (15%) ran every method end to end with nothing refused.
- 760 of 7,518 methods (10%) ran and reported a result — 617 passed, 143 failed.
- Everything else was refused by name, with the file, the line and the construct. Nothing was skipped quietly and nothing was reported as passing because it did not run.
On those 143 failures. A failure means the assertion compared two values and they differed — sometimes this emulator diverging from a real org, sometimes a test that depends on org state we do not model, like profiles or record types. We have not split those two and will not guess at the split.
An ambiguous error counts against us, not against your test. Only a
message carrying the runner's own Assertion Failed prefix is scored as a
failure. Everything else is scored as our refusal even when it surfaces inside your
test — a query exception because we carry no schema for ApexClass, or a
wrong-arity call because method overloading is not modelled. Counting those the other
way would have made this page look better by several points, which is why it does not.
| Codebase | Classes that run clean | Methods with a result |
|---|---|---|
| Salesforce apex-recipes 61 classes, 322 methods | 2 of 61 | 15 of 322 |
| Declarative Lookup Rollup Summaries 66 classes, 838 methods | 0 of 66 | 1 of 838 |
| Education Data Architecture 288 classes, 2,357 methods | 114 of 288 | 706 of 2,357 |
| fflib sample code 10 classes, 16 methods | 0 of 10 | 0 of 16 |
| Nonprofit Success Pack 368 classes, 3,985 methods | 9 of 368 | 38 of 3,985 |
The spread is the useful part. EDA runs 114 of 288 classes clean; NPSP runs 9 of 368. Whether your suite is nearer one end or the other depends on your code, not on us — which is why the next section exists.
One more number, because leaving it out would make this page look better than the product is: of the classes our analyzer says it can run, 60% still refuse once actually run. We publish the measured result, not the prediction, and we are closing that gap in the open.
Point it at your own classes:
curl -s localhost:8080/__emulator__/testrun # what would run
curl -sX POST localhost:8080/__emulator__/testrun # run it The GET costs nothing and tells you how much of your suite is even visible before you spend a run on it. A run where any method failed returns HTTP 417, so a CI step sees it without parsing the body.
The answer for your org
A general table cannot tell you whether your code runs; that depends on what your triggers actually do. Point the analyzer at your metadata and it grades every trigger you have, naming the reason for each refusal:
docker run --rm -v "$PWD/mdapi":/mdapi:ro \
--entrypoint /sfapex fidelic/emulator coverage --report /mdapi Nothing leaves your machine — it reads local files and makes no network calls. The report is plain text, built for pasting into a channel.
Your coverage report uses more precise words for the same ideas — EXECUTE, SIMULATED, UNRESOLVED — and defines each one alongside the numbers behind this page.