ghost-inspector / node-ghost-inspector

Ghost Inspector CLl & API Library for Node.js
https://ghostinspector.com/docs/api/
MIT License
28 stars 6 forks source link

Ghost Inspector Node.js Bindings

CircleCI

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]')

// execute a test
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...


GhostInspector.getFolders([callback])

Fetch an array of all the folders in your account.

// Example using await
try {
  const folders = await GhostInspector.getFolders()
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const folder = await GhostInspector.createFolder('[organization-id]', '[folder-name]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const folder = await GhostInspector.updateFolder('[folder-id]', '[folder-name]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const folder = await GhostInspector.getFolder('[folder-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const suites = await GhostInspector.getFolderSuites('[folder-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
GhostInspector.getFolderSuites('[folder-id]', function (err, suites) {
  if (err) return console.error(err)
  console.log(suites)
})

GhostInspector.createSuite(organizationId, suiteName, [callback])

Create a suite.

// Example using await
try {
  const suites = await GhostInspector.createSuite('[organization-id]', '[suite-name]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const suites = await GhostInspector.updateSuite('[suite-id]', { name: 'My new suite name' })
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const suites = await GhostInspector.getSuites()
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const suite = await GhostInspector.getSuite('[suite-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const tests = await GhostInspector.getSuiteTests('[suite-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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,
}

// Example using await
try {
  const results = await GhostInspector.getSuiteResults('[suite-id]', options)
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Optionally override the start URL of all tests in this suite (for this run only)
const options = {
  startUrl: 'http://alternate.yourcompany.com',
}

// Example using await
try {
  const [results, passing, screenshotPassing] = await GhostInspector.executeSuite(
    '[suite-id]',
    options,
  )
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const newSuite = await GhostInspector.duplicateSuite('[suite-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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

// Example using await
try {
  await GhostInspector.downloadSuiteSeleniumHtml('[suite-id]', 'suite.zip')
} catch (err) {
  console.error(err)
}

// Example using a callback
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

// Example using await
try {
  await GhostInspector.downloadSuiteSeleniumSide('[suite-id]', 'suite.side')
} catch (err) {
  console.error(err)
}

// Example using a callback
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

// Example using await
try {
  await GhostInspector.downloadSuiteSeleniumJson('[suite-id]', 'suite.zip')
} catch (err) {
  console.error(err)
}

// Example using a callback
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

// Example using await
const options = {
  includeImports: true,
}

try {
  await GhostInspector.downloadSuiteJson('[suite-id]', 'suite.zip', options)
} catch (err) {
  console.error(err)
}

// Example using a callback
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,
}

// Example using await
try {
  await GhostInspector.downloadTestJson('[test-id]', 'test.json', options)
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// JSON example (using async)
const myJsonTest = require('my-test.json')
const importedTest = await GhostInspector.importTest('[suite-id]', myJsonTest)
console.log(importedTest)

// HTML example (using callback)
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.

// Example using await
try {
  const tests = await GhostInspector.getTests()
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const test = await GhostInspector.getTest('[test-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
GhostInspector.getTest('[test-id]', function (err, test) {
  if (err) return console.error(err)
  console.log(test)
})

GhostInspector.deleteTest(testId, [callback])

Delete a test.

// Example using await
try {
  const tests = await GhostInspector.deleteTest('[test-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
GhostInspector.deleteTest('[test-id]', function (err, tests) {
  if (err) return console.error(err)
  console.log(tests)
})

GhostInspector.updateTest(testId, updates, [callback])

Update a test.

// Example using await
try {
  const tests = await GhostInspector.updateTest('[test-id]', { name: 'My new test name' })
} catch (err) {
  console.error(err)
}

// Example using a callback
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,
}

// Example using await
try {
  const results = await GhostInspector.getTestResults('[test-id]', options)
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const results = await GhostInspector.getTestResultsRunning('[test-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.)

// Example using await
try {
  const test = await GhostInspector.acceptTestScreenshot('[test-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const newTest = await GhostInspector.duplicateTest('[test-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Optionally override the start URL of the test (for this run only)
const options = {
  startUrl: 'http://alternate.yourcompany.com',
}

// Example using await
try {
  const [results, passing, screenshotPassing] = await GhostInspector.executeTest(
    '[test-id]',
    options,
  )
} catch (err) {
  console.error(err)
}

// Example using a callback
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')

// Wait for the result to finish execution before returning
const options = {
  immediate: false,
}

// Example using await
try {
  const [result, passing, screenshotPassing] = await GhostInspector.executeTestOnDemand(
    '[organization-id]',
    myTest,
    options,
  )
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// First, we execute a test using immediate=1 to get a result ID
const result = await GhostInspector.executeTest('[test-id]', { immediate: true })
const resultId = result._id

const options = {
  pollInterval: 2000, // default is 5000 (5 seconds)
}
// Example using await
const result = await GhostInspector.waitForTestResult(resultId, options)
console.log(result.passing)

// Example using a callback
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

// Example using await
try {
  await GhostInspector.downloadTestSeleniumHtml('[test-id]', 'test.html')
} catch (err) {
  console.error(err)
}

// Example using a callback
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

// Example using await
try {
  await GhostInspector.downloadTestSeleniumSide('[test-id]', 'test.side')
} catch (err) {
  console.error(err)
}

// Example using a callback
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

// Example using await
try {
  await GhostInspector.downloadTestSeleniumJson('[test-id]', 'test.json')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const result = await GhostInspector.getSuiteResult('[suite-result-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const results = await GhostInspector.getSuiteResultTestResults('[suite-result-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const xml = await GhostInspector.getSuiteResultXUnit('[suite-result-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const result = await GhostInspector.cancelSuiteResult('[suite-result-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const result = await GhostInspector.getTestResult('[test-result-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const result = await GhostInspector.cancelTestResult('[test-result-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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.

// Example using await
try {
  const result = await GhostInspector.getAllRunningTests('[organization-id]')
} catch (err) {
  console.error(err)
}

// Example using a callback
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