@octoberswimmer/aer-sf-plugin
v0.0.5
Published
Salesforce CLI plugin that runs Apex tests and previews LWC components locally using aer.
Maintainers
Readme
@octoberswimmer/aer-sf-plugin
A Salesforce CLI plugin that runs Apex tests and previews Lightning Web Components locally using aer.
sf aer apex run testworks the same way as sf apex run test, but runs tests locally via aer test.
sf aer lightning dev componentworks the same way as sf lightning dev component, but previews LWC components
locally via aer server.
Requirements
- Salesforce CLI (
sf) - Node.js >= 18
- aer — the plugin will offer to download the right build for your platform on first use if it can't find one already (see Locating the aer binary below).
Install
From npm:
sf plugins install @octoberswimmer/aer-sf-pluginUsage
Apex tests
Run every test in the project:
sf aer apex run testRun one or more classes (passed to aer as --filter <ClassName>.*):
sf aer apex run test --class-names MyClassTest --class-names AccountServiceTestRun a single method:
sf aer apex run test --tests MyClassTest.testCoolFeatureJUnit output:
sf aer apex run test --result-format junit --output-dir test-resultsWith code coverage:
sf aer apex run test --code-coverage --output-dir test-resultsRun tests even when some classes have parse or type errors:
sf aer apex run test --skip-errorsLWC component preview
Select a component interactively and launch the preview:
sf aer lightning dev componentPreview a specific component by name:
sf aer lightning dev component --name myComponentOpen the component list in the browser instead of selecting interactively:
sf aer lightning dev component --client-selectThe development server uses aer server --watch to serve your project's
source directly (no staging), so changes to component HTML, CSS, and
JavaScript are reflected immediately via hot module replacement.
Locating the aer binary
When the plugin needs to invoke aer, it tries these sources in order:
- The
AER_BINenvironment variable, when it points to an executable file. - A copy previously downloaded by this plugin, stored under a platform-specific
data directory:
- Linux:
$XDG_DATA_HOME/aer-sf-plugin/aer-bin/(default~/.local/share/aer-sf-plugin/aer-bin/) - macOS:
~/Library/Application Support/aer-sf-plugin/aer-bin/ - Windows:
%LOCALAPPDATA%\aer-sf-plugin\aer-bin\
- Linux:
aerdiscovered onPATH.- If none of the above match and the terminal is interactive, the plugin asks for confirmation, then downloads the latest aer-dist release for your platform, extracts it into the data directory above, and uses it for that run and all later runs.
Update checks
Once the plugin has downloaded its own copy of aer, each subsequent run starts
a background GitHub query (rate-limited to one check every 12 hours) to see
whether a newer release has been published. The query runs in parallel with
staging and the test execution, so it does not slow tests down. After the test
run finishes, if a newer release is available you'll be prompted to install it.
Decline and the same version won't be re-offered until something newer ships.
The check is skipped entirely when:
AER_BINis set oraeris onPATH(i.e. the user manages their own copy).- The terminal is non-interactive (
--json, no TTY).
To force an update outside the 12-hour window, delete the contents of the
aer-bin/ directory (or the whole aer-sf-plugin/ directory) and rerun.
In non-interactive environments (CI, --json) the plugin will not prompt; set
AER_BIN or install aer on PATH ahead of time.
How source is staged
The plugin copies the project's Apex source into a temp directory before handing it to aer. Two things happen during staging.
sfdx-project.json replacements are applied
Salesforce CLI supports a replacements configuration that substitutes tokens
in source files at deploy time:
{
"replacements": [
{
"glob": "*.*",
"stringToReplace": "{NAMESPACE}",
"replaceWithFile": "config/namespace.txt"
}
]
}aer does not process replacements, so without staging, tokens like
{NAMESPACE} would remain literal in the loaded source and code such as
Label.get('{NAMESPACE}', labelName, language) would fail at runtime. The
plugin reads replacements from sfdx-project.json and applies them during
staging — stringToReplace or regexToReplace paired with either
replaceWithFile or replaceWithEnv. A single trailing newline is trimmed
from replaceWithFile contents, matching
@salesforce/source-deploy-retrieve.
Duplicate Apex class names across packageDirectories are resolved
If the same Apex class name appears in more than one packageDirectories
entry, sf project deploy start deploys the copies in full-path alphabetical
order, so the copy at the alphabetically-last full path is the one that ends
up in the org. aer test rejects this and errors on duplicates.
To match sf's behaviour, the plugin dedupes .cls / .cls-meta.xml /
.trigger / .trigger-meta.xml files by basename (case-insensitive). The
copy whose full path sorts alphabetically last is staged; the others are
discarded. Listing order in sfdx-project.json does not affect the outcome.
Flag compatibility with sf apex run test
| flag | behaviour |
| --- | --- |
| --class-names, --tests | translated to aer --filter |
| --result-format human\|junit\|json | passed through (tap falls back to human) |
| --output-dir | result files written here |
| --code-coverage | passed to aer as --coverage (JSON file) |
| --skip-errors | passed to aer as --skip-errors (display but skip parse/type errors so unaffected tests still run) |
| --test-level RunLocalTests, RunSpecifiedTests | runs locally |
| --test-level RunAllTestsInOrg | warns; falls back to running all local tests |
| --suite-names | warns; not yet implemented |
| --target-org, --wait, --poll-interval, --synchronous, --api-version, --concise, --detailed-coverage | accepted for compatibility; ignored (a warning is printed when any of these is supplied) |
Development
yarn install
yarn compile # tsc
yarn test # mocha unit tests
node bin/dev.js aer apex run test --helpLicense
This plugin is open source, licensed under BSD-3-Clause.
Note that aer itself is not open source — it is distributed as a binary under its own license.
