Testing & Mocking

Updated:

The primary function of Tecton is to create an environment in an iframe that matches the application in which it is embedded. connect establishes this relationship with the containing app and returns functionality exposed by it.

However, there are times when you might wish to run your application outside of the iframe.

Such as:

  • Running tests
  • Easy development/Continuous Integration

Passing any testOptions, or even an empty object to the testOptions property puts Tecton into test mode. Tecton, in test mode, will bypass any attempt to contact a parent application and only return stubbed functions from testOptions.

tecton.connect({
  testOptions: {}
});

The return value of connect is a promise containing all of the functions documented in this guide. Any of these functions that are relied upon must be stubbed out (setParams and paramsChanged, are still provided). These stubbed functions are what you pass to testOptions. If your app receives params from the containing app on bootup, those can also be passed to testOptions under the property initialParams.

testOptions Properties

You can use the testOptions to configure and override many aspects of your use of Tecton. Here are the type definitions along with some explanation of each property.

interface ITestOptions {
  actions?: Record<string, Function>;
  sources?: Record<string, Function>;
  outletContext?: string;
  initialParams?: Record<string, string | number | boolean>;
  loadElements?: boolean;
}

const defaultTestOptions: ITestOptions = {
    actions: undefined,
    sources: undefined,
    outletContext: undefined,
    initialParams: undefined,
    loadElements: false
};

Option Details

  • actions - Used to replace default action methods provided by Tecton.
  • sources - Use to replace default source methods provided by Tecton.
  • outletContext - An initial argument that provides the context of your app (e.g., account number).
  • initialParams - The values that are fed to the paramsChanged source method at the start-up of your app.
  • loadElements - Whether or not the elements are fetched and loaded. Defaults to false.

The elements are an initial HTTP request that can add time to testing, especially if you have a lot of tests.

Examples

The values here are for demonstration purposes, are not complete implementations, and likely do not apply to your application.

Below is an example of stubbing out an action and a source method, while turning off elements for testing.

tecton.connect({
  testOptions: {
    actions: {
      sendModal({ message, button1, button2 }) {
        let result = window.confirm(message);
        return Promise.resolve(result ? button1.actionName : button2.actionName);
      },
    },
    sources: {
      fetchPlatformData(endPoint) {
        return HypotheticalFixturesCatalog.get(endPoint);
      },
    },
    initialParams: {
      hasEnrolled: true,
      userId: 121,
    },
    loadElements: false,
  },
});

There are some creative ways to use this dynamically that will provide values based on your situation.

Conditional Options

You can specify a static config for "test mode" based on whether you are in an <iframe> or not.

When not in an <iframe>, window.parent === window.

tecton.connect({
  testOptions: window.parent === window ? { loadElements: false } : undefined,
});

Namespaced Globals

Using namespaced globals that can be passed from your test will give you more control over how to use stubbed methods for assertions in your test, and will allow you to choose values based on the situation.

tecton.connect({
  testOptions: App.TectonTestOptions,
});

it("shows form modal when feature is submitted", async () => {
  let wasCalled;
  App.TectonTestOptions = {
    actions: {
      showModal({ message }) {
        expect(message).to.equal("Form Submitted!");
        wasCalled = true;
      },
    },
  };
  await BootApp();
  await NavigateToFeature();
  await fillOutFormAndSubmit();
  expect(wasCalled).to.be.ok;
});