Skip to content

Latest commit

 

History

History
680 lines (535 loc) · 15.8 KB

api.md

File metadata and controls

680 lines (535 loc) · 15.8 KB

API

intern

The global intern object is an instance of Executor. It is automatically created when Intern is imported or loaded via a script tag. This object is also the default export from the intern package:

import intern from 'intern';

configure

The configure method is used to configure the executor. It should be passed an object containing configuration properties.

intern.configure({
  suites: 'build/tests/**/*.js',
  environments: 'chrome'
});

configure may be called multiple times before testing is started. The final configuration will be resolved before any plugins or suites are loaded.

getPlugin

The getPlugin method returns any resources exported by a registered plugin. The main purpose of this method is to allow resources to be accessed in environments without a loader. For example, importing an interface with

import { suite, test } from 'intern/lib/interfaces/tdd';

will not work in a browser environment where a module loader is not available, but getPlugin will work in any environment since it doesn't depend on a loader.

const { suite, test } = intern.getPlugin('interfaces.tdd');

getPlugin is a generic function, so custom plugins can be typed:

import { PluginType } from 'tests/support/myPlugin';
const { foo, bar } = intern.getPlugin<PluginType>('myPlugin');

In the above example, the PluginType type is imported from a plugin and used for typing when retrieving plugin resources from Intern.

on

The on method is used to register listeners for Intern events.

intern.on('testStart', test => {
  console.log(`${test.id} has started`);
});

A listener listens for a certain event and is called with a specific payload. For example, listeners for testStart and testEnd events will be called with an instance of Test (or a Test-like object).

Intern provides a number of events that code can listen for:

Event Emitted when... Argument
error An error (not a test failure) has occurred while running tests. error
runStart Testing begins none
runEnd Testing ends none
suiteStart A suite starts. A suite with no parent indicates the start of a new session. suite
suiteEnd A suite ends suite
testStart A test starts test
testEnd A test ends. Check the error, skipped, and hasPassed properties for status. test

💡That the payloads passed to event listeners may or may not be actual instances of a particular class. For example, the testEnd listener may be passed a Test-like object rather than an actual instance of Test.

Event listeners may be asynchronous.

intern.on('testStart', test => {
  return new Promise(resolve => {
    const db = openDbConnection();
    // An async method to write to a db
    db.put(test, () => {
      resolve();
    });
  });
});

Multiple listeners may register for an event. They will be called sequentially in the order in which they were registered.

registerPlugin

registerPlugin, as it's name suggests, is used to register an extension with Intern. It's signature is

registerPlugin(name: string, init: PluginInitializer): void;

A PluginInitializer is just a callback that takes an optional options argument and returns any exported resources, or a Promise that resolves to resources.

intern.registerPlugin('foo', options => {
  return {
    doSomething() {
      // ...
    },
    doSomethingElse() {
      // ...
    }
  };
});

Since an initializer may return a promise, it can also be used to initialize asynchronous code during Intern's initialization process;

intern.registerPlugin(
  'myplugin',
  () =>
    new Promise(resolve => {
      asyncFunction.then(resolve);
    })
);

run

The run method initiates the testing process. It returns a promise that resolves when testing is complete. It will reject if there is an error during the testing process or if any tests fail.

Interfaces

Interfaces are the primary way that test writers interact with Intern. Intern provides 4 interfaces: object, bdd, tdd, and benchmark.

All interfaces support the same set of lifecycle methods:

  • before - Run before any tests
  • after - Run after all tests
  • beforeEach - Run before each test
  • afterEach - Run after each test

object

const { registerSuite } = intern.getPlugin('interface.object');

The object interface allows test suites to be created declaratively using a plain JavaScript object. Simple suites can just contain an object of test functions:

registerSuite('Suite name', {
  test1() {
    // do something
  },

  test2() {
    // do somthing
  }
});

Suites may also register lifecycle callbacks (beforeEach, afterEach, etc.). When these are used, tests must be contained under a tests property.

registerSuite('Suite name', {
  beforeEach() {
    // test setup
  },

  tests: {
    test1() {
      // do something
    },

    test2() {
      // do somthing
    }
  }
});

Suites may be nested.

registerSuite('Suite name', {
    test1() {
        // do something
    },

    test2() {
        // do somthing
    },

    'sub-suite': {
        subTest1() {
            // do something
        }

        subTest2() {
            // do something
        }
    }
});

tdd

const { suite, test, beforeEach } = intern.getPlugin('interface.tdd');

The tdd interface is callback-driven.

suite('Suite name', () => {
  beforeEach(() => {
    // test setup
  });

  test('test1', () => {
    // do something
  });

  test('test2', () => {
    // do something
  });
});

This interface is a bit more flexible than the object interface. For example, it allows multiple instances of a given lifecycle method to be registered. This can be useful when setting up shared functionality between suites:

function initSuite() {
  beforeEach(() => {
    // do common init
  });
}

suite('Suite', () => {
  initSuite();

  beforeEach(() => {
    // suite init
  });

  test('test1', () => {
    // ...
  });
});

suite('Other suite', () => {
  initSuite();

  test('test1', () => {
    // ...
  });
});

bdd

const { describe, it, beforeEach } = intern.getPlugin('interface.bdd');

The bdd interface is identical to the tdd interface, it just renames the suite and test methods to describe and it.

describe('Thing', () => {
  beforeEach(() => {
    // test setup
  });

  it('should do A', () => {
    // do something
  });

  it('should do b', () => {
    // do something
  });
});

benchmark

const { registerSuite } = intern.getPlugin('interface.benchmark');

The benchmark interface is modified version of the object interface used to run performance benchmark tests. The two differences from object are:

  • Async tests must be wrapped in an async function as the standard mechanisms for handling async code don't work with benchmark tests. Note that this is not the same as the async keyword.
  • Two additional lifecycle methods are supported: beforeEachLoop and afterEachLoop. A benchmark suite will call each test function many times in a row to evaluate average performance. The standard beforeEach and afterEach run before and after a benchmark begins. The *Loop variations are run before and after each call of the test function.
registerSuite('Suite name', {
  beforeEach() {
    // test setup
  },

  beforeEachLoop() {
    // test function call setup
  },

  tests: {
    test1() {
      // do something
    },

    test2: async(dfd => {
      // do somthing
    })
  }
});

Assertions

Intern includes the chai assertion library, available to suites as the 'chai' plugin.

const { assert } = intern.getPlugin('chai');

registerSuite('Suite name', {
  test1() {
    assert.isNotNull(someValue);
  }
});

All three interfaces (assert, expect, and should) are exported by the chai plugin.

Suite

The Suite class manages a group of tests. It provides several properties and methods that may be useful during testing and in reporters.

error

The error property is set when a suite experienced an error. It can be used in reporters to determine whether a suite has failed.

intern.on('suiteEnd', suite => {
  if (suite.error) {
    console.log(`${suite.id} failed: ${suite.error}`);
  }
});

id

The id property is the complete ID of a suite.

intern.on('suiteEnd', suite => {
  console.log(`${suite.id} finished`);
});

name

The name property is the short name of a suite. This can be useful for reporters that generate structured reports, where a suite doesn‘t need to be referred to by its complete ID.

intern.on('suiteEnd', suite => {
  console.log(`${suite.name} finished`);
});

remote

The remote property is an instance of a Leadfoot Command object that is used to access a remote browser in functional test suites.

registerSuite('Suite', {
  before() {
    // Load a page before any tests start
    return this.remote.get('page.html');
  }
});

skip

The skip method is called to skip a suite. Any tests that have not been run will be marked as skipped.

registerSuite({
  before() {
    if (condition) {
      this.skip('Skipping because ...');
    }
  }
});

skipped

The skipped property is set when a suite has been skipped. It can be used in reporters to determine whether a suite has been skipped.

intern.on('suiteEnd', suite => {
  if (suite.skipped) {
    console.log(`${suite.id} was skipped: ${suite.skipped}`);
  }
});

timeElapsed

The timeElapsed property indicates the time required for the test to run in ms.

intern.on('suiteEnd', suite => {
  console.log(`${suite.id} ran in ${suite.timeElapsed} ms`);
});

Test

The Test class represents a single test. It provides several properties and methods that may be useful during testing and in reporters.

async

Call the async method in a test to return a Deferred object that can be used to manage an async test, and/or to adjust the test timeout.

test1() {
	// Test will timeout in 500ms
	const dfd = this.async(500);
	someAsyncOperation(error => {
		if (error) {
			dfd.reject(error);
		} else {
			dfd.resolve();
		}
	});
});

error

The error property is set when a test experienced an error. It can be used in reporters to determine whether a test has failed.

intern.on('testEnd', test => {
  if (test.error) {
    console.log(`${test.id} failed: ${test.error}`);
  }
});

hasPassed

The hasPassed property is set when a test has passed. It can be used in reporters to determine whether a test was run successfully.

intern.on('testEnd', test => {
  if (test.hasPassed) {
    console.log(`${test.id} passed`);
  }
});

id

The id property is the complete ID of a test.

intern.on('testEnd', test => {
  console.log(`${test.id} finished`);
});

name

The name property is the short name of a test. This can be useful for reporters that generate structured reports, where a test doesn‘t need to be referred to by its complete ID.

intern.on('testEnd', test => {
  console.log(`${test.name} finished`);
});

remote

The remote property is an instance of a Leadfoot Command object that is used to access a remote browser in functional tests.

registertest('test', {
  test1() {
    return this.remote
      .get('page.html')
      .findByCssSelector('.button')
      .click();
  }
});

skip

The skip method is called to skip a test.

registertest({
  test1() {
    if (condition) {
      this.skip('Skipping because ...');
    }
  }
});

skipped

The skipped property is set when a test has been skipped. It can be used in reporters to determine whether a test has been skipped.

intern.on('testEnd', test => {
  if (test.skipped) {
    console.log(`${test.id} was skipped: ${test.skipped}`);
  }
});

timeElapsed

The timeElapsed property indicates the time required for the test to run in ms.

intern.on('testEnd', test => {
  console.log(`${test.id} ran in ${test.timeElapsed} ms`);
});

timeout

Set the timeout property in a test to adjust the maximum time the test may take to run. If the test exceeds this time, it will fail. The default timeout is 30000 ms.

test1() {
	this.timeout = 500;
	// test
}

}