How to Fix protractor-jasmine2-screenshot-reporter Not Saving Screenshots to the Required Folder
Set the reporter destination correctly, verify Jasmine hooks, and diagnose cleanup, paths, filters, and aborted runs.

If protractor-jasmine2-screenshot-reporter is not writing screenshots where you expect, set the output directory with dest when you construct HtmlScreenshotReporter. Then verify that the same reporter instance is initialized in beforeLaunch, registered in onPrepare, and finalized in afterLaunch.
The reporter’s dest option is the root directory for both screenshots and the generated HTML report. A missing directory should be created automatically according to the project README. Start with this minimal configuration:
var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
var reporter = new HtmlScreenshotReporter({
dest: 'target/screenshots',
filename: 'my-report.html'
});
exports.config = {
// ... your Protractor settings ...
beforeLaunch: function() {
return new Promise(function(resolve) {
reporter.beforeLaunch(resolve);
});
},
onPrepare: function() {
jasmine.getEnv().addReporter(reporter);
},
afterLaunch: function(exitCode) {
return new Promise(function(resolve) {
reporter.afterLaunch(resolve.bind(this, exitCode));
});
}
};
Compare your configuration with the project README. Make the destination change before creating the reporter; changing reporter.dest later is not the documented configuration path and may leave the original destination in use.
1. Confirm what “required folder” means
There are two paths to distinguish:

- Destination root:
dest, supplied to the constructor. It contains the report and screenshot files. - Individual screenshot path: an optional
pathBuildercallback can place each screenshot in a nested or custom path.
If the report is present but images are missing, inspect pathBuilder. If neither exists, inspect construction and lifecycle hooks first. Also check the process working directory: dest: 'target/screenshots' is relative to the directory from which Protractor runs, not necessarily the directory containing your configuration file.
2. Verify the Jasmine and Protractor lifecycle
The reporter needs all three documented lifecycle stages:
beforeLaunchprepares or cleans the destination before the browser run.onPrepareadds the reporter to Jasmine’s environment so it receives spec events.afterLaunchwrites and closes the HTML report after the run.
Common wiring mistakes include creating one reporter object but registering another, omitting return from an asynchronous hook, or calling afterLaunch without waiting for its callback. Keep one shared instance:
var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
var reporter = new HtmlScreenshotReporter({
dest: 'target/screenshots',
filename: 'my-report.html'
});
exports.config = {
beforeLaunch: function() {
return new Promise(function(resolve) {
reporter.beforeLaunch(resolve);
});
},
onPrepare: function() {
jasmine.getEnv().addReporter(reporter);
},
afterLaunch: function(exitCode) {
return new Promise(function(resolve) {
reporter.afterLaunch(function() {
resolve(exitCode);
});
});
}
};
Run one deliberately failing spec and check whether a screenshot, the HTML report, or both are produced. That tells you which lifecycle stage is failing.
3. Inspect custom screenshot paths
The README documents pathBuilder for customizing screenshot paths. Its example uses the browser name and the spec’s full name; the default generates a random ID per spec. A callback that returns an unexpected relative path can make a screenshot appear to be missing when it was written under a nested directory.
Temporarily remove pathBuilder and use only dest. If screenshots then appear, add the callback back and log the exact path it returns. Check:
- Whether the callback returns a filename or a complete path.
- Whether path separators are valid on the operating system running Protractor.
- Whether spec names contain characters that your filesystem rejects.
- Whether the callback accidentally returns an empty, absolute, or parent-directory path.
4. Check cleanup and parallel workers
cleanDestination is enabled by default. The documented behavior removes and rebuilds the destination when Jasmine starts. This is useful for isolated runs but can delete files from another process when multiple workers share the same folder.
For parallel execution:
- Give each worker a unique
dest, such astarget/screenshots/worker-1. - Or disable cleanup for a shared destination only when your run strategy prevents stale files and name collisions.
- Follow the README’s parallel-run guidance: when
cleanDestinationis enabled, consider disabling summary and configuration output and settingreportTitletonull.
If files appear during the run and disappear at startup or when another worker begins, cleanup or concurrent writes are more likely than a capture failure.
5. Check capture and report filters
Screenshot capture and report inclusion are separate settings:
| Option | Effect | Diagnostic question |
|---|---|---|
captureOnlyFailedSpecs |
When enabled, captures screenshots only for specs that fail expectations. | Did the spec actually fail? |
reportOnlyFailedSpecs |
Controls which specs appear in the HTML report. | Is the screenshot absent, or only the report entry? |
| Skipped specs | Skipped tests do not execute browser steps. | Was there a browser session to capture? |
For a diagnostic run, disable failure-only capture and execute one normal spec plus one failing spec. Compare the resulting files before restoring your preferred filters.
6. Handle aborted test runs carefully
The project documentation states: “By default, no report is generated if an exception is thrown from within the test run.” An uncaught exception can therefore prevent final report generation even if earlier specs captured images.
The README shows calling reporter.jasmineDone() and reporter.afterLaunch() from an uncaughtException handler. Treat that as version-specific recovery guidance: preserve the original error, avoid hiding a failed build, and confirm that the handler matches your installed package and runner behavior.
process.on('uncaughtException', function(err) {
console.error(err);
// Use only if this matches your installed reporter version and runner.
reporter.jasmineDone();
reporter.afterLaunch(function() {
process.exitCode = 1;
});
});
7. Use a reproducible diagnostic checklist
- Print the current working directory with
process.cwd(). - Resolve the configured destination and confirm it is writable.
- Construct the reporter with the final
destvalue. - Remove
pathBuildertemporarily. - Set
captureOnlyFailedSpecs: falsefor the diagnostic run. - Run one passing and one failing spec.
- Check for both the PNG files and the HTML report.
- Re-enable custom paths, cleanup, filters, and parallel workers one at a time.
var path = require('path');
var fs = require('fs');
var destination = path.resolve(process.cwd(), 'target/screenshots');
console.log('Working directory:', process.cwd());
console.log('Screenshot destination:', destination);
console.log('Writable parent:', fs.existsSync(path.dirname(destination)));
var reporter = new HtmlScreenshotReporter({
dest: destination,
filename: 'my-report.html',
captureOnlyFailedSpecs: false
});
8. Or skip the browser setup
If you need a screenshot file rather than a Protractor test reporter, ScreenshotNeo provides a single HTTP request for PNG, JPEG, WebP, or PDF output. The API accepts a URL and returns the capture; see the ScreenshotNeo API documentation for the complete option list.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', buffer);
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. ScreenshotNeo also has an MCP server for AI agents, including Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf tools. The free plan includes 1,000 screenshots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
9. Troubleshooting common errors
| Symptom | Likely cause | Fix |
|---|---|---|
| No folder is created | dest was omitted, misspelled, or the process cannot write the parent directory. |
Set dest in the constructor, resolve the absolute path, and check permissions. |
| Files go to an unexpected location | A relative path is resolved from a different working directory. | Log process.cwd() or use an absolute destination during diagnosis. |
| Report exists, screenshots do not | pathBuilder returned an unexpected path or capture filtering excluded the spec. |
Remove pathBuilder and disable captureOnlyFailedSpecs temporarily. |
| Screenshots vanish between runs | cleanDestination: true removed them, possibly from another worker. |
Use per-worker folders or adjust cleanup for your concurrency model. |
| Only failed tests have images | captureOnlyFailedSpecs is enabled. |
Set it to false when every executed spec needs a screenshot. |
| Report is missing after a crash | An exception stopped finalization. | Inspect the original exception and apply the documented finalization handler only if compatible with your version. |
| Custom folders contain invalid names | Spec or browser names contain filesystem-incompatible characters. | Sanitize names in pathBuilder and log the returned path. |
10. Performance, reliability, and cost considerations
- Performance: Full browser startup and screenshot capture are slower than writing an already-rendered image. Keep diagnostic runs small, then restore parallelism after the destination is correct.
- Reliability: Unique output directories prevent workers from deleting or overwriting one another. Always wait for
beforeLaunchandafterLaunchcallbacks. - Storage: Cleanup prevents stale artifacts in isolated runs; disabling it requires a retention plan.
- Filtering: Failure-only capture reduces files, but it can make a passing spec appear to have no screenshot by design.
- API alternative: ScreenshotNeo’s cache hits and failed loads are not billed, and its response headers report verdict and billing status. Choose the API when you need repeatable URL captures without maintaining a Protractor browser lifecycle.
11. FAQ
Where does the reporter save screenshots by default?
The configured dest directory is the documented output root. If it is relative, resolve it from the Protractor process working directory.
Can I change reporter.dest after construction?
Configure the final destination in the options passed to new HtmlScreenshotReporter(options). A community troubleshooting report describes changing the property afterward as ineffective; treat constructor-time configuration as the reliable approach.
Why is the HTML report present but a spec image missing?
Check pathBuilder, captureOnlyFailedSpecs, skipped specs, and the actual filesystem path returned for that spec.
Does reportOnlyFailedSpecs control screenshot creation?
No. It controls report inclusion. Screenshot creation is affected by capture settings such as captureOnlyFailedSpecs and whether the spec executed.
What is the fastest way to capture a URL without Protractor?
Use ScreenshotNeo’s GET endpoint with an access key and URL. It returns an image or PDF and avoids configuring a browser runner and Jasmine reporter hooks.
For package behavior and option names, consult the maintainer README. It is the primary source for the destination, lifecycle, cleanup, filtering, and path configuration described here.


