Ghost Inspector Node.js Bindings
The official Node.js package and CLI for interacting with Ghost Inspector's API.
Jump to...
Installation
Our official Node.js package is available from npm, you can install it with the following command:
npm install ghost-inspector
In order to use the CLI, install the package globally:
npm install -g ghost-inspector
Quick Start
const GhostInspector = require('ghost-inspector')('[api-key]')
try {
const [results, passing, screenshotPassing] = await GhostInspector.executeTest(
'[test-id]',
options,
)
console.log('Passing: ', passing)
} catch (err) {
console.error(err)
}
CLI Usage
CLI quickstart:
❯ ghost-inspector test execute <testId> \
--browser firefox \
--ngrokTunnel localhost:8000 \
--myVariable "some variable" \
--errorOnFail
Exit status control for CI systems
Under an automated build environment it makes sense to have a command return a non-success status when things are failing. By default the CLI will always return a success (0
) status when executing tests or suites, however you can have the command fail for a non-passing test or suite status (--errorOnFail
), a non-passing screenshot status (--errorOnScreenshotFail
) or both when waiting for a result:
# exit with error code when failing
❯ ghost-inspector test execute <testId> --errorOnFail
# exit with error code when screenshot failing (will ignore `passing`)
❯ ghost-inspector test execute <testId> --errorOnScreenshotFail
# exit with error code if `passing` or `screenshotComparePassing` is `false`
❯ ghost-inspector test execute <testId> --errorOnFail --errorOnScreenshotFail
Creating a secure VPN tunnel with ngrok
The CLI has built-in support for ngrok to make it easier for you to run your tests against a locally-accessible application. In order to set up ngrok
you will need your access token from your ngrok account. To initiate a tunnel on execution use the --ngrokTunnel
parameter to specify your local endpoint, this can be a port on your local computer or a target on the local network:
❯ ghost-inspector test execute <testId> \
--ngrokTunnel localhost:8000 \
--ngrokToken '<my-ngrok-token>'
Note: --ngrokTunnel
option is not available when using --immediate
.
If you prefer you can also set the ngrok token using the environment variable NGROK_TOKEN
.
VPN tunnel URL variable
Once you trigger your execution the variable ngrokUrl
will be made available in your test with the URL of the tunnel. You can modify the name of this variable using the option --ngrokUrlVariable
, for instance you could set it to {{ appDomain }}
with the following example:
❯ ghost-inspector test execute <testId> \
--ngrokTunnel localhost:8000 \
--ngrokToken '<my-ngrok-token>'
--ngrokUrlVariable 'appDomain'
You can also set the ngrok URL to the start URL of your test or suite:
❯ ghost-inspector test execute <testId> \
--ngrokTunnel localhost:8000 \
--ngrokToken '<my-ngrok-token>'
--ngrokUrlVariable 'startUrl'
If you require additional configuration, you can use the ngrok configuration file for your system to customize your tunnel.
View all available commands for the CLI
❯ ghost-inspector --help
ghost-inspector <command>
Commands:
ghost-inspector folder <command> Manage folders within your Ghost Inspector account.
ghost-inspector organization <command> Access organization details.
ghost-inspector suite-result <command> Manage suite results within your Ghost Inspector account.
ghost-inspector suite <command> Manage suites within your Ghost Inspector account.
ghost-inspector test-result <command> Manage test results within your Ghost Inspector account.
ghost-inspector test-runner-ips Fetch a list of test runner IP addresses by region.
ghost-inspector test <command> Manage tests within your Ghost Inspector account.
Options:
--version Show version number [boolean]
--apiKey Your Ghost Inspector API key. [required]
--json Provide output in JSON format.
--help Show help [boolean]
By default all commands will provide human-readable output, but you can also return JSON by passing the flag --json
.
Note: your API key may be passed in through the environment (GHOST_INSPECTOR_API_KEY
) or as a parameter (--apiKey xxx
).
Node.js Client Usage
Every method is accessed via your GhostInspector
instance. Your API Key is passed in when the instance is created:
const GhostInspector = require('ghost-inspector')('[api-key]')
This package supports both callbacks and await
to receive data back from the method call. Note that when an error is encountered, it will be return as the first argument in the callback. However, if no callback is passed in, it is assumed that await
is being used and the method will throw an exception. This means that when using await
you should wrap your calls in a try/catch
block.
Methods
Jump to...
- Folders
- Suites
- Suite Results
- Tests
- Test Results
- Organization
GhostInspector.getFolders([callback])
Fetch an array of all the folders in your account.
try {
const folders = await GhostInspector.getFolders()
} catch (err) {
console.error(err)
}
GhostInspector.getFolders(function (err, folders) {
if (err) return console.error(err)
console.log(folders)
})
GhostInspector.createFolder(organizationId, folderName, [callback])
Create a folder within your organization.
try {
const folder = await GhostInspector.createFolder('[organization-id]', '[folder-name]')
} catch (err) {
console.error(err)
}
GhostInspector.createFolder('[organization-id]', '[folder-name]', function (err, folder) {
if (err) return console.error(err)
console.log(folder)
})
GhostInspector.updateFolder(folderId, folderName, [callback])
Update a folder name.
try {
const folder = await GhostInspector.updateFolder('[folder-id]', '[folder-name]')
} catch (err) {
console.error(err)
}
GhostInspector.updateFolder('[folder-id]', '[folder-name]', function (err, folder) {
if (err) return console.error(err)
console.log(folder)
})
GhostInspector.getFolder(folderId, [callback])
Fetch a single folder from your account.
try {
const folder = await GhostInspector.getFolder('[folder-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getFolder('[folder-id]', function (err, folder) {
if (err) return console.error(err)
console.log(folder)
})
GhostInspector.getFolderSuites(folderId, [callback])
Fetch an array of all the suites in a folder.
try {
const suites = await GhostInspector.getFolderSuites('[folder-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getFolderSuites('[folder-id]', function (err, suites) {
if (err) return console.error(err)
console.log(suites)
})
GhostInspector.createSuite(organizationId, suiteName, [callback])
Create a suite.
try {
const suites = await GhostInspector.createSuite('[organization-id]', '[suite-name]')
} catch (err) {
console.error(err)
}
GhostInspector.createSuite('[organization-id]', '[suite-name]', function (err, suites) {
if (err) return console.error(err)
console.log(suites)
})
GhostInspector.updateSuite(suiteId, updates, [callback])
Update a suite.
try {
const suites = await GhostInspector.updateSuite('[suite-id]', { name: 'My new suite name' })
} catch (err) {
console.error(err)
}
GhostInspector.updateSuite('[suite-id]', { name: 'My new suite name' }, function (err, suites) {
if (err) return console.error(err)
console.log(suites)
})
GhostInspector.getSuites([callback])
Fetch an array of all the suites in your account.
try {
const suites = await GhostInspector.getSuites()
} catch (err) {
console.error(err)
}
GhostInspector.getSuites(function (err, suites) {
if (err) return console.error(err)
console.log(suites)
})
GhostInspector.getSuite(suiteId, [callback])
Fetch a single suite from your account.
try {
const suite = await GhostInspector.getSuite('[suite-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getSuite('[suite-id]', function (err, suite) {
if (err) return console.error(err)
console.log(suite)
})
GhostInspector.getSuiteTests(suiteId, [callback])
Fetch an array of all the tests in a suite.
try {
const tests = await GhostInspector.getSuiteTests('[suite-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getSuiteTests('[suite-id]', function (err, tests) {
if (err) return console.error(err)
console.log(tests)
})
GhostInspector.getSuiteResults(suiteId, [options], [callback])
Fetch an array of suite results for a suite.
const options = {
count: 10,
offset: 0,
}
try {
const results = await GhostInspector.getSuiteResults('[suite-id]', options)
} catch (err) {
console.error(err)
}
GhostInspector.getSuiteResults('[suite-id]', options, function (err, results) {
if (err) return console.error(err)
console.log(results)
})
GhostInspector.executeSuite(suiteId, [options], [callback])
Execute all the tests in a suite and returns an array of results.
const options = {
startUrl: 'http://alternate.yourcompany.com',
}
try {
const [results, passing, screenshotPassing] = await GhostInspector.executeSuite(
'[suite-id]',
options,
)
} catch (err) {
console.error(err)
}
GhostInspector.executeSuite(
'[suite-id]',
options,
function (err, results, passing, screenshotPassing) {
if (err) return console.error(err)
console.log(passing === true ? 'Passed' : 'Failed')
console.log(results)
},
)
GhostInspector.duplicateSuite(suiteId, [options], [callback])
Execute all the tests in a suite and returns an array of results.
try {
const newSuite = await GhostInspector.duplicateSuite('[suite-id]')
} catch (err) {
console.error(err)
}
GhostInspector.duplicateSuite('[suite-id]', function (err, newSuite) {
if (err) return console.error(err)
console.log(newSuite)
})
GhostInspector.downloadSuiteSeleniumHtml(suiteId, dest, [callback])
Download a zip file of all tests in this suite in Selenium IDE .html format
try {
await GhostInspector.downloadSuiteSeleniumHtml('[suite-id]', 'suite.zip')
} catch (err) {
console.error(err)
}
GhostInspector.downloadSuiteSeleniumHtml('[suite-id]', 'suite.zip', function (err) {
if (err) return console.error(err)
console.log('File saved to suite.zip.')
})
GhostInspector.downloadSuiteSeleniumSide(suiteId, dest, [callback])
Download a file of all tests in this suite in Selenium IDE .side format
try {
await GhostInspector.downloadSuiteSeleniumSide('[suite-id]', 'suite.side')
} catch (err) {
console.error(err)
}
GhostInspector.downloadSuiteSeleniumSide('[suite-id]', 'suite.side', function (err) {
if (err) return console.error(err)
console.log('File saved to suite.side.')
})
GhostInspector.downloadSuiteSeleniumJson(suiteId, dest, [callback])
Download a zip file of all tests in this suite in Selenium JSON format
try {
await GhostInspector.downloadSuiteSeleniumJson('[suite-id]', 'suite.zip')
} catch (err) {
console.error(err)
}
GhostInspector.downloadSuiteSeleniumJson('[suite-id]', 'suite.zip', function (err) {
if (err) return console.error(err)
console.log('File saved to suite.zip.')
})
GhostInspector.downloadSuiteJson(suiteId, dest, [callback])
Download a file of all tests in this suite in Ghostinspector JSON format
const options = {
includeImports: true,
}
try {
await GhostInspector.downloadSuiteJson('[suite-id]', 'suite.zip', options)
} catch (err) {
console.error(err)
}
GhostInspector.downloadSuiteJson('[suite-id]', 'suite.zip', options, function (err) {
if (err) return console.error(err)
console.log('File saved to suite.zip.')
})
GhostInspector.downloadTestJson(testId, dest, [callback])
Download a single test in Ghostinspector JSON format
const options = {
includeImports: true,
}
try {
await GhostInspector.downloadTestJson('[test-id]', 'test.json', options)
} catch (err) {
console.error(err)
}
GhostInspector.downloadTestJson('[test-id]', 'test.json', options, function (err) {
if (err) return console.error(err)
console.log('File saved to test.json.')
})
GhostInspector.importTest(suiteId, test, [callback])
Import a test in JSON or HTML (Selenium IDE v1) format.
Note: For JSON, pass the JavaScript object to the client, for HTML pass the path to the file on disk.
const myJsonTest = require('my-test.json')
const importedTest = await GhostInspector.importTest('[suite-id]', myJsonTest)
console.log(importedTest)
GhostInspector.importTest('[suite-id]', '/path/to/my-test.html', function (err, importedTest) {
if (err) return console.error(err)
console.log(importedTest)
})
GhostInspector.getTests([callback])
Fetch an array of all the tests in your account.
try {
const tests = await GhostInspector.getTests()
} catch (err) {
console.error(err)
}
GhostInspector.getTests(function (err, tests) {
if (err) return console.error(err)
console.log(tests)
})
GhostInspector.getTest(testId, [callback])
Fetch a single test from your account.
try {
const test = await GhostInspector.getTest('[test-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getTest('[test-id]', function (err, test) {
if (err) return console.error(err)
console.log(test)
})
GhostInspector.deleteTest(testId, [callback])
Delete a test.
try {
const tests = await GhostInspector.deleteTest('[test-id]')
} catch (err) {
console.error(err)
}
GhostInspector.deleteTest('[test-id]', function (err, tests) {
if (err) return console.error(err)
console.log(tests)
})
GhostInspector.updateTest(testId, updates, [callback])
Update a test.
try {
const tests = await GhostInspector.updateTest('[test-id]', { name: 'My new test name' })
} catch (err) {
console.error(err)
}
GhostInspector.updateTest('[test-id]', { name: 'My new test name' }, function (err, tests) {
if (err) return console.error(err)
console.log(tests)
})
GhostInspector.getTestResults(testId, [options], [callback])
Fetch an array of test results for a test.
const options = {
count: 10,
offset: 0,
}
try {
const results = await GhostInspector.getTestResults('[test-id]', options)
} catch (err) {
console.error(err)
}
GhostInspector.getTestResults('[test-id]', options, function (err, results) {
if (err) return console.error(err)
console.log(results)
})
GhostInspector.getTestResultsRunning(testId, [callback])
Fetch an array of test results that are in progress for a test.
try {
const results = await GhostInspector.getTestResultsRunning('[test-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getTestResultsRunning('[test-id]', function (err, results) {
if (err) return console.error(err)
console.log(results)
})
GhostInspector.acceptTestScreenshot(testId, [callback])
Accept the current screenshot as the new baseline for a test. (Note: This method will throw/return an error if the test's screenshot is already passing, or if screenshot comparison is disabled.)
try {
const test = await GhostInspector.acceptTestScreenshot('[test-id]')
} catch (err) {
console.error(err)
}
GhostInspector.acceptTestScreenshot('[test-id]', function (err, test) {
if (err) return console.error(err)
console.log(test)
})
GhostInspector.duplicateTest(testId, [callback])
Create a duplicate copy of a test.
try {
const newTest = await GhostInspector.duplicateTest('[test-id]')
} catch (err) {
console.error(err)
}
GhostInspector.duplicateTest('[test-id]', function (err, newTest) {
if (err) return console.error(err)
console.log(newTest)
})
GhostInspector.executeTest(testId, [options], [callback])
Execute a single test in your account and return the result.
const options = {
startUrl: 'http://alternate.yourcompany.com',
}
try {
const [results, passing, screenshotPassing] = await GhostInspector.executeTest(
'[test-id]',
options,
)
} catch (err) {
console.error(err)
}
GhostInspector.executeTest(
'[test-id]',
options,
function (err, results, passing, screenshotPassing) {
if (err) return console.error(err)
console.log(passing === true ? 'Passed' : 'Failed')
console.log(results)
},
)
GhostInspector.executeTestOnDemand(organizationId, test, [options], [callback])
Execute an on-demand test against your organization.
const myTest = require('./my-test.json')
const options = {
immediate: false,
}
try {
const [result, passing, screenshotPassing] = await GhostInspector.executeTestOnDemand(
'[organization-id]',
myTest,
options,
)
} catch (err) {
console.error(err)
}
GhostInspector.executeTestOnDemand(
'[organization-id]',
myTest,
options,
function (err, result, passing, screenshotPassing) {
if (err) return console.error(err)
console.log(`Passing: ${result.passing}`)
},
)
GhostInspector.waitForTestResult(resultId, [options], [callback])
Poll for a result execution's completion.
const result = await GhostInspector.executeTest('[test-id]', { immediate: true })
const resultId = result._id
const options = {
pollInterval: 2000,
}
const result = await GhostInspector.waitForTestResult(resultId, options)
console.log(result.passing)
GhostInspector.waitForTestResult(resultId, options, function (err, result) {
if (err) console.error(err)
console.log(`Passing: ${result.passing}`)
})
GhostInspector.downloadTestSeleniumHtml(testId, dest, [callback])
Download a single test in Selenium IDE .html format
try {
await GhostInspector.downloadTestSeleniumHtml('[test-id]', 'test.html')
} catch (err) {
console.error(err)
}
GhostInspector.downloadTestSeleniumHtml('[test-id]', 'test.html', function (err) {
if (err) return console.error(err)
console.log('File saved to test.html.')
})
GhostInspector.downloadTestSeleniumSide(testId, dest, [callback])
Download a single test in Selenium IDE .side format
try {
await GhostInspector.downloadTestSeleniumSide('[test-id]', 'test.side')
} catch (err) {
console.error(err)
}
GhostInspector.downloadTestSeleniumSide('[test-id]', 'test.side', function (err) {
if (err) return console.error(err)
console.log('File saved to test.side.')
})
GhostInspector.downloadTestSeleniumJson(testId, dest, [callback])
Download a single test in Selenium JSON format
try {
await GhostInspector.downloadTestSeleniumJson('[test-id]', 'test.json')
} catch (err) {
console.error(err)
}
GhostInspector.downloadTestSeleniumJson('[test-id]', 'test.json', function (err) {
if (err) return console.error(err)
console.log('File saved to test.json.')
})
GhostInspector.getSuiteResult(suiteResultId, [callback])
Fetch a single suite result.
try {
const result = await GhostInspector.getSuiteResult('[suite-result-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getSuiteResult('[suite-result-id]', function (err, result) {
if (err) return console.error(err)
console.log(result)
})
GhostInspector.getSuiteResultTestResults(suiteResultId, [callback])
Fetch the test results in a single suite result.
try {
const results = await GhostInspector.getSuiteResultTestResults('[suite-result-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getSuiteResultTestResults('[suite-result-id]', function (err, results) {
if (err) return console.error(err)
console.log(results)
})
GhostInspector.getSuiteResultXUnit(suiteResultId, [callback])
Fetch an XML report (XUnit v2) for a single suite result.
try {
const xml = await GhostInspector.getSuiteResultXUnit('[suite-result-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getSuiteResultXUnit('[suite-result-id]', function (err, xml) {
if (err) return console.error(err)
console.log(xml)
})
GhostInspector.cancelSuiteResult(suiteResultId, [callback])
Cancel an in-progress suite result.
try {
const result = await GhostInspector.cancelSuiteResult('[suite-result-id]')
} catch (err) {
console.error(err)
}
GhostInspector.cancelSuiteResult('[suite-result-id]', function (err, result) {
if (err) return console.error(err)
console.log(result)
})
GhostInspector.getTestResult(testResultId, [callback])
Fetch a single test result.
try {
const result = await GhostInspector.getTestResult('[test-result-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getTestResult('[test-result-id]', function (err, result) {
if (err) return console.error(err)
console.log(result)
})
GhostInspector.cancelTestResult(testResultId, [callback])
Cancel an in-progress test result.
try {
const result = await GhostInspector.cancelTestResult('[test-result-id]')
} catch (err) {
console.error(err)
}
GhostInspector.cancelTestResult('[test-result-id]', function (err, result) {
if (err) return console.error(err)
console.log(result)
})
GhostInspector.getAllRunningTests(organizationId, [callback])
Fetch a list of the currently-executing results for the entire organization.
try {
const result = await GhostInspector.getAllRunningTests('[organization-id]')
} catch (err) {
console.error(err)
}
GhostInspector.getAllRunningTests('[organization-id]', function (err, result) {
if (err) return console.error(err)
console.log(result)
})
Contributing
If you've found that a feature is missing or you've found an issue, feel free to open a pull request or submit an issue.
Running tests
To run the unit tests:
npm run test-unit
You can also run the integration tests, however this will run against a Ghost Inspector suite (requires API key):
GHOST_INSPECTOR_API_KEY=xxx npm run test-integration