Metadata
- Source
- FLUID-5633
- Type
- Bug
- Priority
- Major
- Status
- Closed
- Resolution
- Fixed
- Assignee
- Antranig Basman
- Reporter
- Antranig Basman
- Created
2015-04-17T16:36:45.962-0400 - Updated
2024-07-22T10:35:01.185-0400 - Versions
- N/A
- Fixed Versions
- N/A
- Component
-
- IoC Testing Framework
Description
The IoC Testing framework uses a private "ad hoc" scheme for allowing IoCSS-like syntax in event binding for test fixtures. Unfortunately this implementation is bugged - after the listener instance in a fixture sequence executes, the listener should be unbound - unfortunately, all the confused implementor has done is to unregister the distribution that would bind the listener again - rather than, in addition, removing the listener itself.
This emerged in work with the "first discovery tool" that had a sequence:
sequence: [{
listener: "gpii.tests.firstDiscovery.testInitButtonTops",
args: ["{firstDiscovery}", "{that}"],
priority: "last",
event: "\{gpii.tests.firstDiscovery.langTests firstDiscovery}.events.onButtonTopsReady"
}, {
func: "{firstDiscovery}.prefsEditorLoader.applier.change",
args: ["currentPanelNum", 3]
}, {
listener: "gpii.tests.firstDiscovery.testUnchangedButtonTops",
args: ["{firstDiscovery}", "{that}.buttonTops"],
event: "{firstDiscovery}.events.onPanelShown"
}, {
jQueryTrigger: "click",
element: "{firstDiscovery}.prefsEditorLoader.prefsEditor.gpii_firstDiscovery_panel_textSize.dom.increase"
}, {
func: "\{firstDiscovery}.prefsEditorLoader.applier.change",
args: ["currentPanelNum", 1]
}, {
listener: "gpii.tests.firstDiscovery.testChangedButtonTops",
args: ["{firstDiscovery}", "\{that}.buttonTops"],
event: "\{firstDiscovery}.events.onButtonTopsReady"
}]
The IoCSS syntax is used with the first element, as always, to avoid triggering premature construction of the tree and confusing the manually issued QUnit timeout. Unfortunately, the selfsame event fires as sequence point 6 - the initial listener is still bound and causes a failure
Uncaught TypeError: Cannot read property 'execute' of undefined
fluid.test.sequenceExecutor.that.execute @ IoCTestUtils.js:482
fluid.test.composeSimple @ IoCTestUtils.js:303
fluid.test.makeBinder.that.bind.wrapped @ IoCTestUtils.js:314
fluid.event.invokeListener @ infusion-custom.js:12900
In fact, the sequence has finished, but listeners to the final event are still synchronously executing - so there is time for one more trigger of "that.execute" which attempts to trigger the sequence onto the 7th position - in fact, on behalf of the first listener, which did not believe it was the test-finishing listener.
The faulty code is in fluid.test.decoders.event in IoCTestUtils.js and reads:
else if (analysed.path) {
var id;
bind = function (wrapped) {
var options = {};
fluid.set(options, ["listeners"].concat(analysed.path),{
listener: wrapped,
args: fixture.args,
namespace: fixture.namespace,
priority: fixture.priority });
id = fluid.pushDistributions(analysed.head, analysed.selector, [
{options: options, recordType: "distribution", priority: fluid.mergeRecordTypes.distribution}
] );
};
unbind = function () {
fluid.clearDistributions(analysed.head, id);
};
as is clear, the "unbind" action only revokes the distribution and does not take any action to eliminate the listener which the framework directed into the options via the fluid.set directive.
This is a little awkward since the listener gets bound declaratively and so cannot be unbound by instance. It seems that we could only resolve this by taking control of the listener namespace (we would have to advertise to fixture writers that this can not be controlled) and using it to set the listener into a uniquely guid-ed namespace in which we could then identify it.
In general this issue can't be solved before the FLUID-5249 work gets in and we gain the ability to write fluid.queryIoCSelector - since otherwise we could not discover the component holding the listener.
Comments
-
Antranig Basman commented
2018-02-20T10:31:57.393-0500 This was encountered again during work by the Astea team on the GPII's PSP survey dialog tests. These read:
sequence: [{ func: "{that}.app.keyIn", args: ["snapset_1a"] }, [ // Test closing the survey using the break-out link { func: "{that}.app.dialogManager.show", args: ["survey", gpii.tests.webview.getSurveyFixture()] }, { event: "{that gpii.app.surveyDialog}.events.onSurveyCreated", listener: "fluid.identity" }, { func: "{that}.app.dialogManager.survey.surveyDialog.executeCommand", args: [clickBreakOutLink] }, { event: "{that}.app.dialogManager.survey.surveyDialog.events.onSurveyClose", listener: "jqUnit.assert", args: ["Survey was closed by clicking on the break-out link"] } ], [ // Test that the survey will not close when clicking on a non-break-out link { func: "{that}.app.dialogManager.show", args: ["survey", gpii.tests.webview.getSurveyFixture()] }, { event: "{that gpii.app.surveyDialog}.events.onSurveyCreated", listener: "fluid.identity" }, { func: "{that}.app.dialogManager.survey.surveyDialog.executeCommand", args: [clickNonBreakOutLink] }, { func: "jqUnit.assertTrue", args: [ "Survey was not closed by clicking on a non-break-out link", "{that}.app.dialogManager.survey.surveyDialog.model.isShown" ] } ], [ // Test closing the survey using a close button within the content of the survey { func: "{that}.app.dialogManager.show", args: ["survey", gpii.tests.webview.getSurveyFixture()] }, { event: "{that gpii.app.surveyDialog}.events.onSurveyCreated", listener: "fluid.identity" }, { func: "{that}.app.dialogManager.survey.surveyDialog.executeCommand", args: [clickCloseButton] }, { event: "{that}.app.dialogManager.survey.surveyDialog.events.onSurveyClose", listener: "jqUnit.assert", args: ["Survey was closed by clicking on the close button within the content"] } ], [ // Test closing the survey when a DOM element with id "EndOfSurvey" element appears in the survey. { func: "{that}.app.dialogManager.show", args: ["survey", gpii.tests.webview.getSurveyFixture()] }, { event: "{that gpii.app.surveyDialog}.events.onSurveyCreated", listener: "fluid.identity" }, { func: "{that}.app.dialogManager.survey.surveyDialog.executeCommand", args: [addEndOfSurveyElement] }, { event: "{that}.app.dialogManager.survey.surveyDialog.events.onSurveyClose", listener: "jqUnit.assert", args: ["Survey was closed automatically when its end has been reached"] } ], [ // Test that the survey will not close if it does not need to close on submit { func: "{that}.app.dialogManager.show", args: ["survey", gpii.tests.webview.getSurveyFixture({closeOnSubmit: false})] }, { event: "{that gpii.app.surveyDialog}.events.onSurveyCreated", listener: "fluid.identity" }, { func: "{that}.app.dialogManager.survey.surveyDialog.executeCommand", args: [addEndOfSurveyElement] }, { func: "jqUnit.assertTrue", args: [ "Survey was not closed when its end has been reached as it is not configured to closeOnSubmit", "{that}.app.dialogManager.survey.surveyDialog.model.isShown" ] } ], { func: "{that}.app.keyOut" }]
In this case the multiple attempts to bind {that gpii.app.surveyDialog} accumulated and caused the usual sequence overrun as seen above. Time for a fix ...
-
Cindy Li commented
2018-02-20T20:30:28.588-0500 The pull request has been merged into the project repo master branch at 29c3e677e6405b0e288075cdf94d8936905d85af
-
Gregor Moss commented
2018-09-13T16:09:11.821-0400 I believe I'm experiencing this issue while working on tests for my localized UIO component in my FLUID-6300 branch
Here is the test sequence I'm trying to get working:
sequence: [{ event: "{prefsEditorBaseTest prefsEditor messageLoader}.events.onResourcesLoaded", listener: "jqUnit.assertEquals", args: ["defaultLocale is properly propagated to messageLoader", "fr", "{prefsEditor}.prefsEditorLoader.messageLoader.options.defaultLocale"] }, { event: "{prefsEditorBaseTest prefsEditor prefsEditorLoader prefsEditor}.events.onReady", listener: "fluid.tests.uiOptions.prefsEditorLocalizedTester.verifyPanelMessages", args: "{prefsEditor}" }, { funcName: "fluid.tests.uiOptions.prefsEditorLocalizedTester.verifySlidingPanelMessages", args: ["{prefsEditor}", "prefsEditor", "Préférences de l'utilisateur"] }, { func: "{prefsEditor}.events.onInterfaceLocaleChangeRequested.fire", args: ["es"] }, { event: "{prefsEditor messageLoader}.events.onResourcesLoaded", listener: "jqUnit.assertEquals", args: ["defaultLocale is properly propagated to messageLoader", "es", "{prefsEditor}.prefsEditorLoader.messageLoader.options.defaultLocale"] }]
-
Gregor Moss commented
2018-09-13T17:02:40.671-0400 I have captured my failing case in this branch: https://github.com/BlueSlug/infusion/tree/FLUID-5633
-
Antranig Basman commented
2018-09-17T20:33:41.899-0400 Further failure cases discovered by @@Gregor Moss
-
Justin Obara commented
2018-10-05T10:24:08.113-0400 Merged PR ( https://github.com/fluid-project/infusion/pull/935 ) into the project repo at bfbbf740eddd18ec17b604d0e4a785ec3033383d