Test and lint adapters

Test files

test/unit/adapterTestUnit.js — contains the adapter unit tests. Unit tests cover the foundational components of the adapter: existing code and configurations in the adapter’s files. They also test most error conditions (such as missing required fields) within adapter.js.

test/integration/adapterTestIntegration.js — contains the adapter integration tests. Integration tests can be run in standalone stub mode (using mock data) or against a live instance of the external system. The only error conditions tested in integration tests are missing mock data and errors returned from the external system.

utils/testRunner.js — a utility for running tests without saving credentials in the test scripts. See Use the test runner below.

package.json — contains the test scripts test:unit, test:integration, test:cover, and test. You can adjust the log level on the test scripts here to get more detailed output during testing.

Run tests

These scripts should not be modified except to change the log level. They are used by pre-commit hooks and CI/CD pipelines.

CommandDescription
npm run test:unitRuns unit tests only.
npm run test:integrationRuns integration tests only.
npm run test:coverRuns tests and generates coverage information. Note: coverage of the adapter library itself may not be included.
npm run testRuns both unit and integration tests.

Use the test runner

The testRunner utility at utils/testRunner.js can run unit tests, standalone integration tests, and true integration tests without requiring credentials to be saved in the test scripts.

$node utils/testRunner.js

When running a true integration test, the runner prompts for credentials, edits the test script, runs the tests, and then restores the script.

The trade-off is that failing tests are harder to debug, because console output and logs are less readable when tests run through the test runner.

Edit test scripts to change log level

You can change the --LOG flag on the test scripts in package.json to control verbosity during testing.

  • error — logs only errors. Use this for clean baseline runs.
  • debug — logs HTTP request options and the response received. Use this when investigating failures.
  • trace — logs every step the adapter takes. This level is very verbose; use it only to isolate exactly where in the adapter a problem occurs.
1"scripts": {
2 "test:unit": "mocha test/unit/adapterTestUnit.js --LOG=error",
3 "test:integration": "mocha test/integration/adapterTestIntegration.js --LOG=error",
4 "test:cover": "nyc --reporter html --reporter text mocha --reporter dot test/*",
5 "test": "npm run test:unit && npm run test:integration"
6}

Read debug logs during testing

When the adapter runs at debug level, it writes several log entries that are useful for diagnosing issues. These entries appear both when running standalone tests and when the adapter is integrated withItential Platform.

OPTIONS — all HTTP call options. Authentication information is intentionally omitted. This is often the most useful log for diagnosing request issues.

REQUEST — the payload being sent to the external system.

CALL RETURN — the raw response received from the external system.

RESPONSE — the parsed response (first element only, if an array).

Example:

debug: Test-eai-connectorRest-performRequest: OPTIONS: {"hostname":"replace.hostorip.here","port":80,"path":"/oss-core-ws/rest/oci/site/1/cascadeDelete?fs=dynAttrs%2CderivedAttrs","method":"POST","headers":{"Content-Type":"application/json","Accept":"application/json"}}
debug: Test-eai-connectorRest-performRequest: REQUEST: {"name":"BERKELE1.updated","type":"oci/site"}

Save mock data from integration tests

When you run a true integration test (stub = false) with isSaveMockData = true in adapterTestIntegration.js, the adapter makes live calls to the external system and automatically saves the responses as mock data files. It also updates the relevant action.json entries to reference the new files.

If schema translation is active and return_raw is not set to true, the saved mock data will be the translated response. You will need to manually reverse the translation to produce accurate raw mock data. Setting return_raw: true in the request properties causes saveMockData to use the pre-translation response instead, which avoids this problem.

See Work with mock data for more detail on the saveMockData method and mock data file formats.

Unit tests

Generic unit tests

The following tests are consistent across all adapters. Do not modify them — they are replaced automatically when the adapter is migrated to a newer foundation.

TestDescription
ClassConfirms the adapter was instantiated with the correct properties.
Adapter BaseConfirms the adapter base exists.
Workflow FunctionsConfirms the expected workflow functions exist. Results are used in later tests.
PackageConfirms package.json exists, is valid JSON, and has been customized for this adapter.
PronghornConfirms pronghorn.json exists, has been customized, and that methods and parameters in adapter.js and pronghorn.json are in sync — reducing the risk of parameter mismatches inItential Platform workflow tasks.
Properties SchemaConfirms propertiesSchema.json exists and has been customized.
ErrorConfirms error.json exists.
Sample PropertiesConfirms sampleProperties.json exists.
ReadmeConfirms README.md exists and has been customized for the adapter.
ConnectConfirms the connect method exists.
HealthcheckConfirms the healthCheck method exists.
Check Action FilesConfirms the checkActionFiles method exists. Also validates all action files against the action schema and confirms that referenced files exist, preventing silent failures at runtime.
Encrypt PropertyConfirms the encryptProperty method exists and that base64 encoding and AES encryption work correctly.

A marker comment in the file separates the generic section (replaced on migration) from the customizable section below it:

1/*
2-----------------------------------------------------------------------
3-----------------------------------------------------------------------
4*** All code above this comment will be replaced during a migration ***
5******************* DO NOT REMOVE THIS COMMENT BLOCK ******************
6-----------------------------------------------------------------------
7-----------------------------------------------------------------------
8*/

Specific unit tests

The Adapter Builder generates three tests for every API method in adapter.js. These tests can be customized to extend coverage.

Test 1 — method exists. Confirms the method is defined as a function on the adapter:

1describe('#createTenant', () => {
2 it('should have a createTenant function', (done) => {
3 try {
4 assert.equal(true, typeof a.createTenant === 'function');
5 done();
6 } catch (error) {
7 log.error(`Test Failure: ${error}`);
8 done(error);
9 }
10 }).timeout(attemptTimeout);
11});

Test 2 — required parameter error. Confirms the adapter returns the correct error when a required parameter is missing. runErrorAsserts is a private helper that validates the error object structure:

1describe('#createTenant', () => {
2 it('should error if - missing tenant name', (done) => {
3 try {
4 a.createTenant(null, null, (data, error) => {
5 try {
6 const displayE = 'tenantName is required';
7 runErrorAsserts(data, error, 'AD.300', 'test-apic-adapter-createTenant', displayE);
8 done();
9 } catch (err) {
10 log.error(`Test Failure: ${err}`);
11 done(err);
12 }
13 });
14 } catch (error) {
15 log.error(`Adapter Exception: ${error}`);
16 done(error);
17 }
18 }).timeout(attemptTimeout);
19});

Test 3 — schema validation failure. Confirms the adapter returns the correct error when data fails Ajv validation (for example, a missing required field or a value of the wrong type):

1describe('#createDevice', () => {
2 it('should error on create a device - no name', (done) => {
3 try {
4 const device = { ipAddress: '10.10.10.1' };
5 a.createDevice(device, (data, error) => {
6 try {
7 const displayE = 'Schema validation failed on should have required property \'.name\'';
8 runErrorAsserts(data, error, 'AD.312', 'Test-sevone-translatorUtil-buildJSONEntity', displayE);
9 done();
10 } catch (err) {
11 log.error(`Test Failure: ${err}`);
12 done(err);
13 }
14 });
15 } catch (error) {
16 log.error(`Adapter Exception: ${error}`);
17 done(error);
18 }
19 }).timeout(attemptTimeout);
20});

Adding tests or test data

Do not modify anything above the migration marker — those changes will be lost on the next migration. Below the marker, you can:

  • Add additional assert statements to existing tests.
  • Add request data to existing tests.
  • Add new tests for additional error conditions, using test doubles or additional mock data files.
  • Add unit and integration tests for any methods you add manually to adapter.js.

Integration tests

Generic integration tests

The following integration tests are consistent across all adapters. Do not modify them — they are replaced automatically when the adapter is migrated.

TestDescription
ClassConfirms the adapter was instantiated with the correct properties.
ConnectConfirms the connect method succeeds both without a health check and with a startup health check.
HealthcheckConfirms the healthCheck method succeeds.

The same migration marker applies here as in the unit test file.

Specific integration tests

The Adapter Builder generates an integration test for every API method. These tests can be customized to extend coverage. Two private helpers are available: runCommonAsserts validates a successful response, and runErrorAsserts validates an error response.

Without mock data — when no mock data file exists for a call, the stub test expects an error. When running integrated, the test expects a successful response:

1describe('#createTenant', () => {
2 it('should work if integrated but since no mockdata should error when run standalone', (done) => {
3 try {
4 a.createTenant(tenantName, null, (data, error) => {
5 try {
6 if (stub) {
7 const displayE = 'Error 400 received on request';
8 runErrorAsserts(data, error, 'AD.500', 'test-apic-connectorRest-handleEndResponse', displayE);
9 } else {
10 runCommonAsserts(data, error);
11 }
12 saveMockData('poc-apic', 'createTenant', 'default', data);
13 done();
14 } catch (err) {
15 log.error(`Test Failure: ${err}`);
16 done(err);
17 }
18 });
19 } catch (error) {
20 log.error(`Adapter Exception: ${error}`);
21 done(error);
22 }
23 }).timeout(attemptTimeout);
24});

With mock data — when mock data is available, the stub test validates the response against the expected field values in the mock file:

1describe('#createTenant', () => {
2 it('should work if integrated or standalone with mockdata', (done) => {
3 try {
4 a.createTenant(tenantName, null, (data, error) => {
5 try {
6 if (stub) {
7 runCommonAsserts(data, error);
8 assert.equal('string', data.response.description);
9 assert.equal('string', data.response.ImportTaskId);
10 assert.equal('object', typeof data.response.SnapshotTaskDetail);
11 } else {
12 runCommonAsserts(data, error);
13 }
14 saveMockData('poc-apic', 'createTenant', 'default', data);
15 done();
16 } catch (err) {
17 log.error(`Test Failure: ${err}`);
18 done(err);
19 }
20 });
21 } catch (error) {
22 log.error(`Adapter Exception: ${error}`);
23 done(error);
24 }
25 }).timeout(attemptTimeout);
26});

Intelligent integration testing

Every adapter method has a generated integration test, but the generated tests apply only basic intelligence. Integration tests often need to run in a specific order — for example, creating a resource before retrieving, updating, or deleting it — and many tests depend on data from prior steps, or on the existence of related resources.

Adapters built with the Adapter Builder take these dependencies into account based on the information provided during the build. Where the builder can infer the correct test order and data dependencies, it does so automatically.