Common Problems and Solutions with the IoC Testing Framework

On This Page

This document records common issues and solutions when writing unit tests with the IoC testing framework.

Destroyed component error

Issue: If more than one event listeners were registered back to back in the test sequence, the destroyed component error would be thrown. In this example,

/** Component under test **/
fluid.defaults("fluid.tests.cat", {
    gradeNames: ["fluid.rendererComponent", "autoInit"],
});

/** Unit tests **/
fluid.defaults("fluid.tests.catTests", {
    gradeNames: ["fluid.test.testEnvironment", "autoInit"],
    components: {
        cat: {
            type: "fluid.tests.cat",
			...
        },
        catTester: {
            type: "fluid.tests.catTester"
        }
    }
});

fluid.tests.testDefault = function () {...};

fluid.defaults("fluid.tests.catTester", {
    gradeNames: ["fluid.test.testCaseHolder", "autoInit"],
    modules: [{
        ...
        tests: [{
            name: "Test the cat",
            sequence: [{
                listener: "{cat}.refreshView",
                priority: "last",
                event: "{catTests cat}.events.onCreate"
            }, {
                listener: "fluid.tests.testDefault",
                priority: "last",
                event: "{cat}.events.afterRender"
            }]
        }]
    }]
});

Note that two tests are to attach event listeners, line 29 - 35.

The second test fails with the error: Cannot add listener to destroyed event firer afterRender of component with typename fluid.tests.cat ...

The fact is the second listener was NOT attached to the {cat} component at all.

Solution 1: Get rid of one of the listeners using a different way. In this case, the first listener can be replaced by setting up the option "renderOnInit: true" for fluid.tests.cat, line 13.

/** Component under test **/
fluid.defaults("fluid.tests.cat", {
    gradeNames: ["fluid.rendererComponent", "autoInit"],
});

/** Unit tests **/
fluid.defaults("fluid.tests.catTests", {
    gradeNames: ["fluid.test.testEnvironment", "autoInit"],
    components: {
        cat: {
            type: "fluid.tests.cat",
			options: {
				renderOnInit: true
			}
        },
		....        
    }
});

fluid.tests.testDefault = function () {...};

fluid.defaults("fluid.tests.catTester", {
    gradeNames: ["fluid.test.testCaseHolder", "autoInit"],
    modules: [{
        ...
        tests: [{
            name: "Test the cat",
            sequence: [{
                listener: "fluid.tests.testDefault",
                priority: "last",
                event: "{cat}.events.afterRender"
            }]
        }]
    }]
});

Solution 2: Add another action in the test sequence in between attaching two listeners, if possible, such as the line 20 in the following example.

In this example, the order of how three tests are executed:

The first test runs to execute the listener registered for onCreate event -> The listener for afterRender in the third test is attached -> The second test runs -> The listener for afterRender event is executed.

/** Component under test **/
fluid.defaults("fluid.tests.cat", {
    gradeNames: ["fluid.rendererComponent", "autoInit"],
});

/** Unit tests **/
...

fluid.defaults("fluid.tests.catTester", {
    gradeNames: ["fluid.test.testCaseHolder", "autoInit"],
    modules: [{
        ...
        tests: [{
            name: "Test the cat",
            sequence: [{
                listener: "{cat}.refreshView",
                priority: "last",
                event: "{catTests cat}.events.onCreate"
            }, {
                func: "fluid.tests.action"
            }, {
                listener: "fluid.tests.testDefault",
                priority: "last",
                event: "{cat}.events.afterRender"
            }]
        }]
    }]
});

None of the tests are executed

Cause 1: The tested component is instantiated before fluid.test.testCaseHolder is ready.

Solution: Specify "createOnEvent: {testCaseHolder}.events.onTestCaseStart" at the instantiation of the component under test to ensure the testCaseHolder is ready at the instantiation of the tested component, line 7 in the following example.

/** Unit tests **/
fluid.defaults("fluid.tests.catTests", {
    gradeNames: ["fluid.test.testEnvironment", "autoInit"],
    components: {
        cat: {
            type: "fluid.tests.cat",
			createOnEvent: "{catTester}.events.onTestCaseStart",
			...
        },
        catTester: {
            type: "fluid.tests.catTester"
        }
    }
});

fluid.defaults("fluid.tests.catTester", {
    gradeNames: ["fluid.test.testCaseHolder", "autoInit"],
    ...
}); 

Cause 2: The instantiated component to be tested is not found in the first unit test.

Solution: Scope the tested component in more detail.

Note the use of "{catTests cat}" in the first test at line 30 in the following example.

/** Component under test **/
fluid.defaults("fluid.tests.cat", {
    gradeNames: ["fluid.rendererComponent", "autoInit"],
});

/** Unit tests **/
fluid.defaults("fluid.tests.catTests", {
    gradeNames: ["fluid.test.testEnvironment", "autoInit"],
    components: {
        cat: {
            type: "fluid.tests.cat",
			createOnEvent: "{catTester}.events.onTestCaseStart",
			...
        },
        catTester: {
            type: "fluid.tests.catTester"
        }
    }
});

fluid.defaults("fluid.tests.catTester", {
    gradeNames: ["fluid.test.testCaseHolder", "autoInit"],
    modules: [{
        ...
        tests: [{
			...
            sequence: [{
                listener: "fluid.tests.testDefault",
                priority: "last",
                event: "{catTests cat}.events.afterRender"
            }
			...]
        }]
    }]
});