jsf.js_next_gen 4.1.0-beta.2 → 4.1.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AI_CONTRIBUTIONS.md +71 -0
- package/README.md +254 -78
- package/api-extractor.faces.json +38 -0
- package/dist/docs/assets/hierarchy.js +1 -1
- package/dist/docs/assets/navigation.js +1 -1
- package/dist/docs/assets/search.js +1 -1
- package/dist/docs/functions/faces.ajax.addOnError.html +2 -2
- package/dist/docs/functions/faces.ajax.addOnEvent.html +2 -2
- package/dist/docs/functions/faces.ajax.request.html +2 -2
- package/dist/docs/functions/faces.ajax.response.html +2 -2
- package/dist/docs/functions/faces.getClientWindow.html +2 -2
- package/dist/docs/functions/faces.getProjectStage.html +2 -2
- package/dist/docs/functions/faces.getViewState.html +1 -1
- package/dist/docs/functions/faces.push.close.html +1 -1
- package/dist/docs/functions/faces.push.init.html +6 -6
- package/dist/docs/functions/faces.push.open.html +1 -1
- package/dist/docs/functions/faces.util.chain.html +2 -2
- package/dist/docs/functions/myfaces.ab.html +3 -3
- package/dist/docs/functions/myfaces.onDomReady.html +1 -1
- package/dist/docs/functions/myfaces.reserveNamespace.html +1 -1
- package/dist/docs/hierarchy.html +1 -1
- package/dist/docs/index.html +292 -71
- package/dist/docs/interfaces/faces.AjaxData.html +6 -0
- package/dist/docs/interfaces/faces.AjaxError.html +18 -0
- package/dist/docs/interfaces/faces.AjaxEvent.html +8 -0
- package/dist/docs/interfaces/faces.ajax.RequestContext.html +6 -0
- package/dist/docs/interfaces/faces.ajax.RequestOptions.html +10 -0
- package/dist/docs/modules/faces.ajax.html +1 -1
- package/dist/docs/modules/faces.html +1 -1
- package/dist/docs/modules/faces.push.html +1 -1
- package/dist/docs/modules/faces.util.html +1 -1
- package/dist/docs/modules/myfaces.html +1 -1
- package/dist/docs/modules.html +1 -1
- package/dist/docs/types/faces.AjaxErrorStatus.html +2 -0
- package/dist/docs/types/faces.AjaxEventStatus.html +2 -0
- package/dist/docs/types/faces.ProjectStage.html +2 -0
- package/dist/docs/types/faces.ajax.OnErrorCallback.html +2 -0
- package/dist/docs/types/faces.ajax.OnEventCallback.html +2 -0
- package/dist/docs/types/faces.push.OnCloseHandler.html +2 -0
- package/dist/docs/types/faces.push.OnErrorHandler.html +2 -0
- package/dist/docs/types/faces.push.OnMessageHandler.html +2 -0
- package/dist/docs/types/faces.push.OnOpenHandler.html +2 -0
- package/dist/docs/variables/faces.contextpath.html +1 -1
- package/dist/docs/variables/faces.implversion.html +1 -1
- package/dist/docs/variables/faces.separatorchar.html +1 -1
- package/dist/docs/variables/faces.specversion.html +1 -1
- package/dist/docs/variables/myfaces.oam.html +1 -1
- package/dist/window/faces-development.js +1801 -499
- package/dist/window/faces-development.js.map +1 -1
- package/{target/api/_api.js → dist/window/faces.d.ts} +124 -151
- package/dist/window/faces.js +1 -1
- package/dist/window/faces.js.LICENSE.txt +0 -17
- package/dist/window/faces.js.map +1 -1
- package/dist/window/jsf-development.js +1806 -513
- package/dist/window/jsf-development.js.map +1 -1
- package/{target/src/main/typescript/api/_api.js → dist/window/jsf.d.ts} +125 -153
- package/dist/window/jsf.js +1 -1
- package/dist/window/jsf.js.LICENSE.txt +0 -17
- package/dist/window/jsf.js.map +1 -1
- package/package.json +22 -18
- package/scripts/build-dts.mjs +239 -0
- package/src/main/typescript/@types/definitions/index.d.ts +22 -122
- package/{target/test/frameworkBase/_ext/monadish/fixtures/test2.js → src/main/typescript/@types/definitions/modules.d.ts} +18 -2
- package/src/main/typescript/api/_api.ts +132 -29
- package/{target/test/frameworkBase/_ext/monadish/fixtures/test.js → src/main/typescript/api/_api_ae_stub.d.ts} +6 -2
- package/src/main/typescript/api/faces.ts +2 -2
- package/src/main/typescript/api/jsf.ts +15 -23
- package/src/main/typescript/impl/AjaxImpl.ts +15 -15
- package/src/main/typescript/impl/PushImpl.ts +139 -69
- package/src/main/typescript/impl/core/Const.ts +2 -2
- package/src/main/typescript/impl/i18n/Messages.ts +1 -1
- package/src/main/typescript/impl/util/Assertions.ts +1 -2
- package/src/main/typescript/impl/util/AsyncRunnable.ts +3 -4
- package/src/main/typescript/impl/util/ExtDomQuery.ts +19 -19
- package/src/main/typescript/impl/util/FileUtils.ts +30 -14
- package/src/main/typescript/impl/util/HiddenInputBuilder.ts +34 -34
- package/src/main/typescript/impl/util/Lang.ts +19 -22
- package/src/main/typescript/impl/util/XhrQueueController.ts +25 -3
- package/src/main/typescript/impl/xhrCore/ErrorData.ts +17 -12
- package/src/main/typescript/impl/xhrCore/EventData.ts +8 -7
- package/src/main/typescript/impl/xhrCore/IResponseProcessor.ts +3 -3
- package/src/main/typescript/impl/xhrCore/RequestDataResolver.ts +7 -6
- package/src/main/typescript/impl/xhrCore/Response.ts +3 -3
- package/src/main/typescript/impl/xhrCore/ResponseDataResolver.ts +0 -38
- package/src/main/typescript/impl/xhrCore/ResponseProcessor.ts +17 -15
- package/src/main/typescript/impl/xhrCore/XhrFormData.ts +72 -63
- package/src/main/typescript/impl/xhrCore/XhrRequest.ts +80 -134
- package/src/main/typescript/mona_dish_shim.ts +6 -2
- package/src/main/typescript/myfaces/OamSubmit.ts +10 -6
- package/src/main/typescript/test/api/JsfPushShimTest.spec.ts +126 -0
- package/src/main/typescript/test/api/MyFacesABTest.spec.ts +16 -0
- package/src/main/typescript/test/api/PushTypeCompatibility.ts +65 -0
- package/src/main/typescript/test/frameworkBase/LangTest.spec.ts +16 -0
- package/src/main/typescript/test/frameworkBase/_ext/monadish/DomQueryTest.spec.ts +1 -0
- package/src/main/typescript/test/frameworkBase/_ext/monadish/XmlQueryTest.spec.ts +16 -0
- package/src/main/typescript/test/frameworkBase/_ext/monadish/markups/tobago-with-header.ts +16 -0
- package/src/main/typescript/test/frameworkBase/_ext/monadish/markups/tobago-without-header.ts +16 -0
- package/src/main/typescript/test/frameworkBase/_ext/shared/StandardInits.ts +55 -9
- package/src/main/typescript/test/frameworkBase/_ext/shared/XmlResponses.ts +16 -0
- package/src/main/typescript/test/impl/AssertionsTest.spec.ts +168 -0
- package/src/main/typescript/test/impl/FileUtilsTest.spec.ts +126 -0
- package/src/main/typescript/test/impl/ImplTest.spec.ts +75 -1
- package/src/main/typescript/test/impl/ResponseDataResolverTest.spec.ts +62 -0
- package/src/main/typescript/test/impl/util/ExtDomQueryTest.spec.ts +91 -1
- package/src/main/typescript/test/impl/util/ExtLangTest.spec.ts +110 -0
- package/src/main/typescript/test/impl/util/HiddenInputBuilderTest.spec.ts +74 -0
- package/src/main/typescript/test/myfaces/OamSubmit.spec.ts +61 -1
- package/src/main/typescript/test/queue/AsynchronousQueueTest.spec.ts +191 -2
- package/src/main/typescript/test/xhrCore/ClientWindow.spec.ts +16 -0
- package/src/main/typescript/test/xhrCore/ErrorChainTest.spec.ts +14 -0
- package/src/main/typescript/test/xhrCore/FakeWebsocket.ts +21 -5
- package/src/main/typescript/test/xhrCore/RequestTest.spec.ts +363 -4
- package/src/main/typescript/test/xhrCore/ResponseTest.spec.ts +218 -4
- package/src/main/typescript/test/xhrCore/TobagoFileUploadTest.spec.ts +1 -1
- package/src/main/typescript/test/xhrCore/WebsocketTest.spec.ts +764 -0
- package/src/main/typescript/test/xhrCore/XhrFormDataTest.spec.ts +265 -62
- package/src/main/typescript/test/xhrCore/XhrRequestProgress.spec.ts +16 -0
- package/{target/src/main/typescript/test/xhrCore/FakeWebsocket.js → src/main/typescript/tsconfig.ae.json} +16 -23
- package/src/main/typescript/{tsconfig.json → tsconfig.dts.json} +11 -27
- package/src/main/typescript/tsconfig.test.json +17 -0
- package/tsconfig.api-extractor.json +17 -0
- package/.claude/settings.local.json +0 -16
- package/.github/workflows/codeql-analysis.yml +0 -83
- package/.github/workflows/nodejs.yml +0 -26
- package/.mocharc.json +0 -10
- package/.nyc_output/384344d4-4f46-455f-84c3-010f829098cb.json +0 -1
- package/.nyc_output/a0f90016-f4f9-4039-bb51-57f4f7050541.json +0 -1
- package/.nyc_output/db388b5d-0b79-4bce-afd2-001aaf6f0245.json +0 -1
- package/.nyc_output/processinfo/384344d4-4f46-455f-84c3-010f829098cb.json +0 -1
- package/.nyc_output/processinfo/a0f90016-f4f9-4039-bb51-57f4f7050541.json +0 -1
- package/.nyc_output/processinfo/db388b5d-0b79-4bce-afd2-001aaf6f0245.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/.nycrc +0 -6
- package/build.cmd +0 -1
- package/build.sh +0 -3
- package/mvnw +0 -286
- package/mvnw.cmd +0 -161
- package/plans for 4.0.1.txt +0 -8
- package/remap.ts +0 -51
- package/src/main/typescript/test/xhrCore/WebsocketTest.ts +0 -221
- package/target/api/_api.js.map +0 -1
- package/target/api/faces.js +0 -45
- package/target/api/faces.js.map +0 -1
- package/target/api/jsf.js +0 -56
- package/target/api/jsf.js.map +0 -1
- package/target/impl/AjaxImpl.js +0 -748
- package/target/impl/AjaxImpl.js.map +0 -1
- package/target/impl/PushImpl.js +0 -265
- package/target/impl/PushImpl.js.map +0 -1
- package/target/impl/core/Const.js +0 -177
- package/target/impl/core/Const.js.map +0 -1
- package/target/impl/core/ImplTypes.js +0 -38
- package/target/impl/core/ImplTypes.js.map +0 -1
- package/target/impl/i18n/Messages.js +0 -113
- package/target/impl/i18n/Messages.js.map +0 -1
- package/target/impl/util/Assertions.js +0 -101
- package/target/impl/util/Assertions.js.map +0 -1
- package/target/impl/util/AsyncRunnable.js +0 -78
- package/target/impl/util/AsyncRunnable.js.map +0 -1
- package/target/impl/util/ExtDomQuery.js +0 -306
- package/target/impl/util/ExtDomQuery.js.map +0 -1
- package/target/impl/util/FileUtils.js +0 -98
- package/target/impl/util/FileUtils.js.map +0 -1
- package/target/impl/util/HiddenInputBuilder.js +0 -83
- package/target/impl/util/HiddenInputBuilder.js.map +0 -1
- package/target/impl/util/IListener.js +0 -3
- package/target/impl/util/IListener.js.map +0 -1
- package/target/impl/util/Lang.js +0 -263
- package/target/impl/util/Lang.js.map +0 -1
- package/target/impl/util/XhrQueueController.js +0 -92
- package/target/impl/util/XhrQueueController.js.map +0 -1
- package/target/impl/xhrCore/ErrorData.js +0 -87
- package/target/impl/xhrCore/ErrorData.js.map +0 -1
- package/target/impl/xhrCore/EventData.js +0 -52
- package/target/impl/xhrCore/EventData.js.map +0 -1
- package/target/impl/xhrCore/IResponseProcessor.js +0 -3
- package/target/impl/xhrCore/IResponseProcessor.js.map +0 -1
- package/target/impl/xhrCore/RequestDataResolver.js +0 -186
- package/target/impl/xhrCore/RequestDataResolver.js.map +0 -1
- package/target/impl/xhrCore/ResonseDataResolver.js +0 -104
- package/target/impl/xhrCore/ResonseDataResolver.js.map +0 -1
- package/target/impl/xhrCore/Response.js +0 -186
- package/target/impl/xhrCore/Response.js.map +0 -1
- package/target/impl/xhrCore/ResponseDataResolver.js +0 -104
- package/target/impl/xhrCore/ResponseDataResolver.js.map +0 -1
- package/target/impl/xhrCore/ResponseProcessor.js +0 -468
- package/target/impl/xhrCore/ResponseProcessor.js.map +0 -1
- package/target/impl/xhrCore/XhrFormData.js +0 -163
- package/target/impl/xhrCore/XhrFormData.js.map +0 -1
- package/target/impl/xhrCore/XhrRequest.js +0 -433
- package/target/impl/xhrCore/XhrRequest.js.map +0 -1
- package/target/mona_dish_shim.js +0 -70
- package/target/mona_dish_shim.js.map +0 -1
- package/target/myfaces/OamSubmit.js +0 -128
- package/target/myfaces/OamSubmit.js.map +0 -1
- package/target/src/main/typescript/api/_api.js.map +0 -1
- package/target/src/main/typescript/api/faces.js +0 -45
- package/target/src/main/typescript/api/faces.js.map +0 -1
- package/target/src/main/typescript/api/jsf.js +0 -56
- package/target/src/main/typescript/api/jsf.js.map +0 -1
- package/target/src/main/typescript/impl/AjaxImpl.js +0 -748
- package/target/src/main/typescript/impl/AjaxImpl.js.map +0 -1
- package/target/src/main/typescript/impl/PushImpl.js +0 -265
- package/target/src/main/typescript/impl/PushImpl.js.map +0 -1
- package/target/src/main/typescript/impl/core/Const.js +0 -177
- package/target/src/main/typescript/impl/core/Const.js.map +0 -1
- package/target/src/main/typescript/impl/core/ImplTypes.js +0 -38
- package/target/src/main/typescript/impl/core/ImplTypes.js.map +0 -1
- package/target/src/main/typescript/impl/i18n/Messages.js +0 -113
- package/target/src/main/typescript/impl/i18n/Messages.js.map +0 -1
- package/target/src/main/typescript/impl/util/Assertions.js +0 -101
- package/target/src/main/typescript/impl/util/Assertions.js.map +0 -1
- package/target/src/main/typescript/impl/util/AsyncRunnable.js +0 -78
- package/target/src/main/typescript/impl/util/AsyncRunnable.js.map +0 -1
- package/target/src/main/typescript/impl/util/ExtDomQuery.js +0 -306
- package/target/src/main/typescript/impl/util/ExtDomQuery.js.map +0 -1
- package/target/src/main/typescript/impl/util/FileUtils.js +0 -98
- package/target/src/main/typescript/impl/util/FileUtils.js.map +0 -1
- package/target/src/main/typescript/impl/util/HiddenInputBuilder.js +0 -83
- package/target/src/main/typescript/impl/util/HiddenInputBuilder.js.map +0 -1
- package/target/src/main/typescript/impl/util/IListener.js +0 -3
- package/target/src/main/typescript/impl/util/IListener.js.map +0 -1
- package/target/src/main/typescript/impl/util/Lang.js +0 -263
- package/target/src/main/typescript/impl/util/Lang.js.map +0 -1
- package/target/src/main/typescript/impl/util/XhrQueueController.js +0 -92
- package/target/src/main/typescript/impl/util/XhrQueueController.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/ErrorData.js +0 -87
- package/target/src/main/typescript/impl/xhrCore/ErrorData.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/EventData.js +0 -52
- package/target/src/main/typescript/impl/xhrCore/EventData.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/IResponseProcessor.js +0 -3
- package/target/src/main/typescript/impl/xhrCore/IResponseProcessor.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/RequestDataResolver.js +0 -186
- package/target/src/main/typescript/impl/xhrCore/RequestDataResolver.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/Response.js +0 -186
- package/target/src/main/typescript/impl/xhrCore/Response.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/ResponseDataResolver.js +0 -104
- package/target/src/main/typescript/impl/xhrCore/ResponseDataResolver.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/ResponseProcessor.js +0 -468
- package/target/src/main/typescript/impl/xhrCore/ResponseProcessor.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/XhrFormData.js +0 -163
- package/target/src/main/typescript/impl/xhrCore/XhrFormData.js.map +0 -1
- package/target/src/main/typescript/impl/xhrCore/XhrRequest.js +0 -433
- package/target/src/main/typescript/impl/xhrCore/XhrRequest.js.map +0 -1
- package/target/src/main/typescript/mona_dish_shim.js +0 -70
- package/target/src/main/typescript/mona_dish_shim.js.map +0 -1
- package/target/src/main/typescript/myfaces/OamSubmit.js +0 -128
- package/target/src/main/typescript/myfaces/OamSubmit.js.map +0 -1
- package/target/src/main/typescript/test/api/MyFacesABTest.spec.js +0 -117
- package/target/src/main/typescript/test/api/MyFacesABTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/LangTest.spec.js +0 -123
- package/target/src/main/typescript/test/frameworkBase/LangTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/DomQueryTest.spec.js +0 -657
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/DomQueryTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/LangTest.spec.js +0 -107
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/LangTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/MappingProbes.js +0 -106
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/MappingProbes.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/MappingTest.spec.js +0 -39
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/MappingTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/MonadTest.spec.js +0 -153
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/MonadTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/XmlQueryTest.spec.js +0 -2
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/XmlQueryTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/markups/tobago-with-header.js +0 -925
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/markups/tobago-with-header.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/markups/tobago-without-header.js +0 -112
- package/target/src/main/typescript/test/frameworkBase/_ext/monadish/markups/tobago-without-header.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/shared/StandardInits.js +0 -728
- package/target/src/main/typescript/test/frameworkBase/_ext/shared/StandardInits.js.map +0 -1
- package/target/src/main/typescript/test/frameworkBase/_ext/shared/XmlResponses.js +0 -296
- package/target/src/main/typescript/test/frameworkBase/_ext/shared/XmlResponses.js.map +0 -1
- package/target/src/main/typescript/test/impl/ImplTest.spec.js +0 -225
- package/target/src/main/typescript/test/impl/ImplTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/impl/ImplTest_23.spec.js +0 -143
- package/target/src/main/typescript/test/impl/ImplTest_23.spec.js.map +0 -1
- package/target/src/main/typescript/test/impl/SeparatorCharsTest.spec.js +0 -106
- package/target/src/main/typescript/test/impl/SeparatorCharsTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/impl/util/ExtDomQueryTest.spec.js +0 -77
- package/target/src/main/typescript/test/impl/util/ExtDomQueryTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/myfaces/OamSubmit.spec.js +0 -118
- package/target/src/main/typescript/test/myfaces/OamSubmit.spec.js.map +0 -1
- package/target/src/main/typescript/test/myfaces/OnLoad.spec.js +0 -57
- package/target/src/main/typescript/test/myfaces/OnLoad.spec.js.map +0 -1
- package/target/src/main/typescript/test/myfaces/ReserveNamespace.spec.js +0 -60
- package/target/src/main/typescript/test/myfaces/ReserveNamespace.spec.js.map +0 -1
- package/target/src/main/typescript/test/queue/AsynchronousProbe.js +0 -93
- package/target/src/main/typescript/test/queue/AsynchronousProbe.js.map +0 -1
- package/target/src/main/typescript/test/queue/AsynchronousQueueTest.spec.js +0 -133
- package/target/src/main/typescript/test/queue/AsynchronousQueueTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/ClientWindow.spec.js +0 -101
- package/target/src/main/typescript/test/xhrCore/ClientWindow.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/ErrorChainTest.spec.js +0 -175
- package/target/src/main/typescript/test/xhrCore/ErrorChainTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/EventTests.spec.js +0 -184
- package/target/src/main/typescript/test/xhrCore/EventTests.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/FakeWebsocket.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/FileUploadTest.spec.js +0 -181
- package/target/src/main/typescript/test/xhrCore/FileUploadTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/NamespacesRequestTest.spec.js +0 -226
- package/target/src/main/typescript/test/xhrCore/NamespacesRequestTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/OamSubmitTest.spec.js +0 -199
- package/target/src/main/typescript/test/xhrCore/OamSubmitTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/RequestParamsTest.spec.js +0 -567
- package/target/src/main/typescript/test/xhrCore/RequestParamsTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/RequestTest.spec.js +0 -845
- package/target/src/main/typescript/test/xhrCore/RequestTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/RequestTest_23.spec.js +0 -382
- package/target/src/main/typescript/test/xhrCore/RequestTest_23.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/ResponseTest.spec.js +0 -667
- package/target/src/main/typescript/test/xhrCore/ResponseTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/ResponseTest23.spec.js +0 -367
- package/target/src/main/typescript/test/xhrCore/ResponseTest23.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/ShadowDomTest.spec.js +0 -123
- package/target/src/main/typescript/test/xhrCore/ShadowDomTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/TobagoFileUploadTest.spec.js +0 -147
- package/target/src/main/typescript/test/xhrCore/TobagoFileUploadTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/WebsocketTest.js +0 -207
- package/target/src/main/typescript/test/xhrCore/WebsocketTest.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/XhrFormDataTest.spec.js +0 -149
- package/target/src/main/typescript/test/xhrCore/XhrFormDataTest.spec.js.map +0 -1
- package/target/src/main/typescript/test/xhrCore/XhrRequestProgress.spec.js +0 -130
- package/target/src/main/typescript/test/xhrCore/XhrRequestProgress.spec.js.map +0 -1
- package/target/test/api/MyFacesABTest.spec.js +0 -117
- package/target/test/api/MyFacesABTest.spec.js.map +0 -1
- package/target/test/frameworkBase/LangTest.spec.js +0 -123
- package/target/test/frameworkBase/LangTest.spec.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/DomQueryTest.spec.js +0 -657
- package/target/test/frameworkBase/_ext/monadish/DomQueryTest.spec.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/LangTest.spec.js +0 -107
- package/target/test/frameworkBase/_ext/monadish/LangTest.spec.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/MappingProbes.js +0 -106
- package/target/test/frameworkBase/_ext/monadish/MappingProbes.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/MappingTest.spec.js +0 -39
- package/target/test/frameworkBase/_ext/monadish/MappingTest.spec.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/MonadTest.spec.js +0 -153
- package/target/test/frameworkBase/_ext/monadish/MonadTest.spec.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/XmlQueryTest.spec.js +0 -1
- package/target/test/frameworkBase/_ext/monadish/XmlQueryTest.spec.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/fixtures/test.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/fixtures/test2.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/markups/tobago-with-header.js +0 -925
- package/target/test/frameworkBase/_ext/monadish/markups/tobago-with-header.js.map +0 -1
- package/target/test/frameworkBase/_ext/monadish/markups/tobago-without-header.js +0 -112
- package/target/test/frameworkBase/_ext/monadish/markups/tobago-without-header.js.map +0 -1
- package/target/test/frameworkBase/_ext/shared/StandardInits.js +0 -728
- package/target/test/frameworkBase/_ext/shared/StandardInits.js.map +0 -1
- package/target/test/frameworkBase/_ext/shared/XmlResponses.js +0 -296
- package/target/test/frameworkBase/_ext/shared/XmlResponses.js.map +0 -1
- package/target/test/frameworkBase/_ext/shared/fixtures/js/tobago.js +0 -16
- package/target/test/frameworkBase/_ext/shared/fixtures/js/tobago.js.map +0 -1
- package/target/test/impl/ImplTest.spec.js +0 -225
- package/target/test/impl/ImplTest.spec.js.map +0 -1
- package/target/test/impl/ImplTest_23.spec.js +0 -143
- package/target/test/impl/ImplTest_23.spec.js.map +0 -1
- package/target/test/impl/SeparatorCharsTest.spec.js +0 -106
- package/target/test/impl/SeparatorCharsTest.spec.js.map +0 -1
- package/target/test/impl/util/ExtDomQueryTest.spec.js +0 -77
- package/target/test/impl/util/ExtDomQueryTest.spec.js.map +0 -1
- package/target/test/myfaces/OamSubmit.spec.js +0 -118
- package/target/test/myfaces/OamSubmit.spec.js.map +0 -1
- package/target/test/myfaces/OnLoad.spec.js +0 -57
- package/target/test/myfaces/OnLoad.spec.js.map +0 -1
- package/target/test/myfaces/ReserveNamespace.spec.js +0 -60
- package/target/test/myfaces/ReserveNamespace.spec.js.map +0 -1
- package/target/test/queue/AsynchronousProbe.js +0 -93
- package/target/test/queue/AsynchronousProbe.js.map +0 -1
- package/target/test/queue/AsynchronousQueueTest.spec.js +0 -133
- package/target/test/queue/AsynchronousQueueTest.spec.js.map +0 -1
- package/target/test/xhrCore/ClientWindow.spec.js +0 -101
- package/target/test/xhrCore/ClientWindow.spec.js.map +0 -1
- package/target/test/xhrCore/ErrorChainTest.spec.js +0 -175
- package/target/test/xhrCore/ErrorChainTest.spec.js.map +0 -1
- package/target/test/xhrCore/EventTests.spec.js +0 -184
- package/target/test/xhrCore/EventTests.spec.js.map +0 -1
- package/target/test/xhrCore/FakeWebsocket.js +0 -38
- package/target/test/xhrCore/FakeWebsocket.js.map +0 -1
- package/target/test/xhrCore/FileUploadTest.spec.js +0 -181
- package/target/test/xhrCore/FileUploadTest.spec.js.map +0 -1
- package/target/test/xhrCore/NamespacesRequestTest.spec.js +0 -226
- package/target/test/xhrCore/NamespacesRequestTest.spec.js.map +0 -1
- package/target/test/xhrCore/OamSubmitTest.spec.js +0 -199
- package/target/test/xhrCore/OamSubmitTest.spec.js.map +0 -1
- package/target/test/xhrCore/RequestParamsTest.spec.js +0 -567
- package/target/test/xhrCore/RequestParamsTest.spec.js.map +0 -1
- package/target/test/xhrCore/RequestTest.spec.js +0 -845
- package/target/test/xhrCore/RequestTest.spec.js.map +0 -1
- package/target/test/xhrCore/RequestTest_23.spec.js +0 -382
- package/target/test/xhrCore/RequestTest_23.spec.js.map +0 -1
- package/target/test/xhrCore/ResponseTest.spec.js +0 -667
- package/target/test/xhrCore/ResponseTest.spec.js.map +0 -1
- package/target/test/xhrCore/ResponseTest23.spec.js +0 -367
- package/target/test/xhrCore/ResponseTest23.spec.js.map +0 -1
- package/target/test/xhrCore/ShadowDomTest.spec.js +0 -123
- package/target/test/xhrCore/ShadowDomTest.spec.js.map +0 -1
- package/target/test/xhrCore/TobagoFileUploadTest.spec.js +0 -147
- package/target/test/xhrCore/TobagoFileUploadTest.spec.js.map +0 -1
- package/target/test/xhrCore/WebsocketTest.js +0 -207
- package/target/test/xhrCore/WebsocketTest.js.map +0 -1
- package/target/test/xhrCore/XhrFormDataTest.spec.js +0 -149
- package/target/test/xhrCore/XhrFormDataTest.spec.js.map +0 -1
- package/target/test/xhrCore/XhrRequestProgress.spec.js +0 -130
- package/target/test/xhrCore/XhrRequestProgress.spec.js.map +0 -1
- package/target/test/xhrCore/fixtures/addedViewHead1.js +0 -17
- package/target/test/xhrCore/fixtures/addedViewHead1.js.map +0 -1
- package/target/test/xhrCore/fixtures/addedViewHead2.js +0 -17
- package/target/test/xhrCore/fixtures/addedViewHead2.js.map +0 -1
- package/target/test/xhrCore/fixtures/addedViewHead3.js +0 -17
- package/target/test/xhrCore/fixtures/addedViewHead3.js.map +0 -1
- package/target/test/xhrCore/fixtures/nonce_script.js +0 -17
- package/target/test/xhrCore/fixtures/nonce_script.js.map +0 -1
- package/tsconfig.json +0 -9
- package/webpack.config.ts +0 -54
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
/*! Licensed to the Apache Software Foundation (ASF) under one or more
|
|
2
|
+
* contributor license agreements. See the NOTICE file distributed with
|
|
3
|
+
* this work for additional information regarding copyright ownership.
|
|
4
|
+
* The ASF licenses this file to you under the Apache License, Version 2.0
|
|
5
|
+
* (the "License"); you may not use this file except in compliance with
|
|
6
|
+
* the License. You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
// AI-generated: this file was created with assistance from Claude (Anthropic) — see AI_CONTRIBUTIONS.md
|
|
17
|
+
import {describe} from "mocha";
|
|
18
|
+
import * as sinon from "sinon";
|
|
19
|
+
import * as nise from "nise";
|
|
20
|
+
import {StandardInits} from "../frameworkBase/_ext/shared/StandardInits";
|
|
21
|
+
import {Implementation} from "../../impl/AjaxImpl";
|
|
22
|
+
|
|
23
|
+
import {expect} from "chai";
|
|
24
|
+
|
|
25
|
+
const defaultMyFaces = StandardInits.defaultMyFaces;
|
|
26
|
+
import {_Es2019Array, Lang} from "mona-dish";
|
|
27
|
+
import {FakeWebsocket} from "./FakeWebsocket";
|
|
28
|
+
import {MAX_RECONNECT_ATTEMPTS, REASON_EXPIRED, RECONNECT_INTERVAL} from "../../impl/core/Const";
|
|
29
|
+
const assertType = Lang.assertType;
|
|
30
|
+
|
|
31
|
+
declare var faces: any;
|
|
32
|
+
|
|
33
|
+
describe('Tests the jsf websocket client side api on high level (generic test without any myfaces dependencies', function () {
|
|
34
|
+
let oldFlatMap = null;
|
|
35
|
+
beforeEach(async function () {
|
|
36
|
+
let oldFlatMap = null;
|
|
37
|
+
let waitForResult = defaultMyFaces();
|
|
38
|
+
|
|
39
|
+
return waitForResult.then((close) => {
|
|
40
|
+
|
|
41
|
+
this.xhr = nise.fakeXhr.useFakeXMLHttpRequest();
|
|
42
|
+
this.requests = [];
|
|
43
|
+
this.xhr.onCreate = (xhr) => {
|
|
44
|
+
this.requests.push(xhr);
|
|
45
|
+
};
|
|
46
|
+
(global as any).XMLHttpRequest = this.xhr;
|
|
47
|
+
window.XMLHttpRequest = this.xhr;
|
|
48
|
+
|
|
49
|
+
this.jsfAjaxResponse = sinon.stub((global as any).faces.ajax, "response");
|
|
50
|
+
|
|
51
|
+
this.fakeWebsocket = new FakeWebsocket();
|
|
52
|
+
this.socket = sinon.stub(window, 'WebSocket').returns(this.fakeWebsocket);
|
|
53
|
+
(global as any).WebSocket = this.socket;
|
|
54
|
+
|
|
55
|
+
this.pushImpl = (global as any).PushImpl;
|
|
56
|
+
this.initSpy = sinon.spy(this.pushImpl, "init");
|
|
57
|
+
oldFlatMap =Array.prototype["flatMap"];
|
|
58
|
+
window["Es2019Array"] = _Es2019Array;
|
|
59
|
+
delete Array.prototype["flatMap"];
|
|
60
|
+
|
|
61
|
+
this.closeIt = () => {
|
|
62
|
+
(global as any).XMLHttpRequest = window.XMLHttpRequest = this.xhr.restore();
|
|
63
|
+
this.jsfAjaxResponse.restore();
|
|
64
|
+
this.socket.restore();
|
|
65
|
+
this.initSpy.restore();
|
|
66
|
+
delete (global as any).WebSocket;
|
|
67
|
+
Implementation.reset();
|
|
68
|
+
close();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
afterEach(function () {
|
|
75
|
+
this.closeIt();
|
|
76
|
+
if(oldFlatMap) {
|
|
77
|
+
Array.prototype["flatMap"] = oldFlatMap;
|
|
78
|
+
oldFlatMap = null;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("must register a channel", function (done: Function) {
|
|
83
|
+
// faces.push.init (Faces 4) includes onerror. PushImpl keeps the same signature
|
|
84
|
+
// so the JSF 2.3 compatibility shim can pass null for that callback.
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
faces.push.init("clientId1", "booga.ws", "mychannel",
|
|
88
|
+
() => { done(); }, // onopen
|
|
89
|
+
() => {}, // onmessage
|
|
90
|
+
() => {}, // onerror
|
|
91
|
+
() => {}, // onclose
|
|
92
|
+
"", // behaviorScripts
|
|
93
|
+
true // autoConnect
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(this.initSpy.called).to.be.true;
|
|
97
|
+
|
|
98
|
+
let calledArgs = this.initSpy?.getCall(0)?.args;
|
|
99
|
+
|
|
100
|
+
expect(calledArgs[0]).to.eq("clientId1");
|
|
101
|
+
expect(calledArgs[1]).to.eq("booga.ws");
|
|
102
|
+
expect(calledArgs[2]).to.eq("mychannel");
|
|
103
|
+
|
|
104
|
+
expect(assertType(calledArgs[3], "function")).to.be.true; // onopen
|
|
105
|
+
expect(assertType(calledArgs[4], "function")).to.be.true; // onmessage
|
|
106
|
+
expect(assertType(calledArgs[5], "function")).to.be.true; // onerror
|
|
107
|
+
expect(assertType(calledArgs[6], "function")).to.be.true; // onclose
|
|
108
|
+
expect(calledArgs[7]).to.eq(""); // behaviorScripts
|
|
109
|
+
expect(calledArgs[8]).to.be.true; // autoConnect
|
|
110
|
+
|
|
111
|
+
// implementation-level state
|
|
112
|
+
expect("clientId1" in this.pushImpl.components, "a component must be registered").to.be.true;
|
|
113
|
+
expect("booga.ws" in this.pushImpl.sockets, "a socket must be registered").to.be.true;
|
|
114
|
+
} finally {
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("callbacks must be called", function (done) {
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
let openCalled = false;
|
|
122
|
+
let closeCalled = false;
|
|
123
|
+
let messageCalled = false;
|
|
124
|
+
|
|
125
|
+
let msg = null;
|
|
126
|
+
let cnl = null;
|
|
127
|
+
new Promise((resolve) => {
|
|
128
|
+
faces.push.init("blarg", "booga.ws", "mychannel", () => {
|
|
129
|
+
openCalled = true;
|
|
130
|
+
this.fakeWebsocket._respond({data: '"booga"'});
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
(message: string, channel: string) => {
|
|
134
|
+
messageCalled = true;
|
|
135
|
+
msg = message;
|
|
136
|
+
cnl = channel;
|
|
137
|
+
resolve(() => true);
|
|
138
|
+
},
|
|
139
|
+
() => {},
|
|
140
|
+
() => {
|
|
141
|
+
closeCalled = true;
|
|
142
|
+
},
|
|
143
|
+
"",
|
|
144
|
+
true
|
|
145
|
+
);
|
|
146
|
+
}).then(() => {
|
|
147
|
+
expect(openCalled, "Open must have been called due to autoConnect").to.be.true;
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
expect(messageCalled, "on a server response the message must have been called").to.be.true;
|
|
152
|
+
expect(msg, "proper message must be passed").to.eq("booga");
|
|
153
|
+
expect(cnl, "proper message must be passed").to.eq("mychannel");
|
|
154
|
+
|
|
155
|
+
expect(closeCalled, "websocket still open").to.be.false;
|
|
156
|
+
|
|
157
|
+
faces.push.close("blarg");
|
|
158
|
+
expect(closeCalled, "websocket now closed").to.be.true;
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
done();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
it("manual open must work", function (done) {
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
let openCalled = false;
|
|
171
|
+
let closeCalled = false;
|
|
172
|
+
let messageCalled = false;
|
|
173
|
+
|
|
174
|
+
let msg = null;
|
|
175
|
+
let cnl = null;
|
|
176
|
+
new Promise((resolve) => {
|
|
177
|
+
faces.push.init("blarg", "booga.ws", "mychannel", () => {
|
|
178
|
+
openCalled = true;
|
|
179
|
+
this.fakeWebsocket._respond({data: '"booga"'});
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
(message: string, channel: string) => {
|
|
183
|
+
messageCalled = true;
|
|
184
|
+
msg = message;
|
|
185
|
+
cnl = channel;
|
|
186
|
+
resolve(() => true);
|
|
187
|
+
},
|
|
188
|
+
() => {},
|
|
189
|
+
() => {
|
|
190
|
+
closeCalled = true;
|
|
191
|
+
},
|
|
192
|
+
"",
|
|
193
|
+
false
|
|
194
|
+
);
|
|
195
|
+
faces.push.open("blarg");
|
|
196
|
+
}).then(() => {
|
|
197
|
+
expect(openCalled, "Open must have been called due to open").to.be.true;
|
|
198
|
+
|
|
199
|
+
expect(messageCalled, "on a server response the message must have been called").to.be.true;
|
|
200
|
+
expect(msg, "proper message must be passed").to.eq("booga");
|
|
201
|
+
expect(cnl, "proper message must be passed").to.eq("mychannel");
|
|
202
|
+
|
|
203
|
+
expect(closeCalled, "websocket still open").to.be.false;
|
|
204
|
+
|
|
205
|
+
faces.push.close("blarg");
|
|
206
|
+
expect(closeCalled, "websocket now closed").to.be.true;
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
done();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("must call onclose(-1) when WebSocket is not available", function () {
|
|
215
|
+
// Null both window and global so DQ.global().WebSocket is falsy regardless of which the impl reads
|
|
216
|
+
const savedWindow = (window as any).WebSocket;
|
|
217
|
+
const savedGlobal = (global as any).WebSocket;
|
|
218
|
+
(window as any).WebSocket = null;
|
|
219
|
+
(global as any).WebSocket = null;
|
|
220
|
+
|
|
221
|
+
let closeCalled = false;
|
|
222
|
+
let closeCode: any = null;
|
|
223
|
+
let closeChannel: any = null;
|
|
224
|
+
|
|
225
|
+
faces.push.init("blarg", "booga.ws", "nochannel",
|
|
226
|
+
() => {},
|
|
227
|
+
() => {},
|
|
228
|
+
() => {},
|
|
229
|
+
(code: number, channel: string) => { closeCalled = true; closeCode = code; closeChannel = channel; },
|
|
230
|
+
"",
|
|
231
|
+
false
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
(window as any).WebSocket = savedWindow;
|
|
235
|
+
(global as any).WebSocket = savedGlobal;
|
|
236
|
+
|
|
237
|
+
expect(closeCalled, "onclose must be called when WebSocket is unavailable").to.be.true;
|
|
238
|
+
expect(closeCode).to.eq(-1);
|
|
239
|
+
expect(closeChannel).to.eq("nochannel");
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it("must extract channelToken from the query-string part of the URL", function () {
|
|
243
|
+
faces.push.init("blarg", "ws://example.com/push?mytoken", "mychannel",
|
|
244
|
+
() => {}, () => {}, () => {}, () => {}, "", false
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
expect("mytoken" in this.pushImpl.sockets, "socket must be keyed by the query-string token").to.be.true;
|
|
248
|
+
expect(this.pushImpl.components["blarg"].channelToken).to.eq("mytoken");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("must be idempotent on repeated init with the same socketClientId", function () {
|
|
252
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
253
|
+
() => {}, () => {}, () => {}, () => {}, "", false
|
|
254
|
+
);
|
|
255
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
256
|
+
() => {}, () => {}, () => {}, () => {}, "", false
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
expect(Object.keys(this.pushImpl.sockets).length).to.eq(1);
|
|
260
|
+
expect(Object.keys(this.pushImpl.components).length).to.eq(1);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("must fan out onopen to all components sharing the same socket URL", function (done) {
|
|
264
|
+
let open1 = false;
|
|
265
|
+
let open2 = false;
|
|
266
|
+
|
|
267
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
268
|
+
() => { open1 = true; }, () => {}, () => {}, () => {}, "", false
|
|
269
|
+
);
|
|
270
|
+
faces.push.init("clientId2", "booga.ws", "mychannel",
|
|
271
|
+
() => { open2 = true; }, () => {}, () => {}, () => {}, "", false
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
faces.push.open("blarg");
|
|
275
|
+
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
expect(open1, "first component onopen must be called").to.be.true;
|
|
278
|
+
expect(open2, "second component onopen must be called").to.be.true;
|
|
279
|
+
done();
|
|
280
|
+
}, 20);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("must invoke registered behavior functions on a matching message", function (done) {
|
|
284
|
+
let behaviorCalled = false;
|
|
285
|
+
const behaviors = { "booga": [() => { behaviorCalled = true; }] };
|
|
286
|
+
|
|
287
|
+
new Promise<void>((resolve) => {
|
|
288
|
+
this.pushImpl.init("blarg", "booga.ws", "mychannel",
|
|
289
|
+
() => { this.fakeWebsocket._respond({data: '"booga"'}); },
|
|
290
|
+
() => { resolve(); },
|
|
291
|
+
null,
|
|
292
|
+
() => {},
|
|
293
|
+
behaviors,
|
|
294
|
+
true
|
|
295
|
+
);
|
|
296
|
+
}).then(() => {
|
|
297
|
+
expect(behaviorCalled, "behavior function must be invoked on matching message key").to.be.true;
|
|
298
|
+
done();
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it("must invoke onerror and reconnect on a reconnectable abnormal close", function (done) {
|
|
303
|
+
let errorCalled = false;
|
|
304
|
+
let closeCalled = false;
|
|
305
|
+
let errorCode: any = null;
|
|
306
|
+
let errorChannel: any = null;
|
|
307
|
+
|
|
308
|
+
new Promise<void>((resolve) => {
|
|
309
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
310
|
+
() => {
|
|
311
|
+
setTimeout(() => {
|
|
312
|
+
this.fakeWebsocket._close({code: 1006, reason: "abnormal"});
|
|
313
|
+
resolve();
|
|
314
|
+
}, 20);
|
|
315
|
+
},
|
|
316
|
+
() => {},
|
|
317
|
+
(code: number, channel: string) => { errorCalled = true; errorCode = code; errorChannel = channel; },
|
|
318
|
+
() => { closeCalled = true; },
|
|
319
|
+
"",
|
|
320
|
+
true
|
|
321
|
+
);
|
|
322
|
+
}).then(() => {
|
|
323
|
+
setTimeout(() => {
|
|
324
|
+
expect(errorCalled, "onerror must be called before reconnecting").to.be.true;
|
|
325
|
+
expect(closeCalled, "onclose must not be called while reconnecting").to.be.false;
|
|
326
|
+
expect(errorCode).to.eq(1006);
|
|
327
|
+
expect(errorChannel).to.eq("mychannel");
|
|
328
|
+
expect(this.socket.callCount, "a reconnect must create another WebSocket").to.be.greaterThan(1);
|
|
329
|
+
done();
|
|
330
|
+
}, RECONNECT_INTERVAL + 150);
|
|
331
|
+
});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("must use cumulative reconnect delays across consecutive failed reconnect attempts", function () {
|
|
335
|
+
const clock = sinon.useFakeTimers();
|
|
336
|
+
const firstSocket = new FakeWebsocket();
|
|
337
|
+
const secondSocket = new FakeWebsocket();
|
|
338
|
+
const thirdSocket = new FakeWebsocket();
|
|
339
|
+
|
|
340
|
+
try {
|
|
341
|
+
this.socket.resetBehavior();
|
|
342
|
+
this.socket.onCall(0).returns(firstSocket);
|
|
343
|
+
this.socket.onCall(1).returns(secondSocket);
|
|
344
|
+
this.socket.onCall(2).returns(thirdSocket);
|
|
345
|
+
|
|
346
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
347
|
+
() => {},
|
|
348
|
+
() => {},
|
|
349
|
+
() => {},
|
|
350
|
+
() => {},
|
|
351
|
+
"",
|
|
352
|
+
true
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
clock.tick(10);
|
|
356
|
+
expect(this.socket.callCount, "initial open must create one WebSocket").to.eq(1);
|
|
357
|
+
|
|
358
|
+
firstSocket._close({code: 1006, reason: "abnormal"});
|
|
359
|
+
expect(firstSocket.readyState, "first socket must be closed before reconnect").to.eq(3);
|
|
360
|
+
expect(this.pushImpl.sockets["booga.ws"].socket,
|
|
361
|
+
"closed socket reference must be cleared before first reconnect is scheduled").to.eq(null);
|
|
362
|
+
clock.tick(RECONNECT_INTERVAL - 1);
|
|
363
|
+
expect(this.socket.callCount, "first reconnect must wait one reconnect interval").to.eq(1);
|
|
364
|
+
clock.tick(1);
|
|
365
|
+
expect(this.socket.callCount, "first reconnect must create the second WebSocket").to.eq(2);
|
|
366
|
+
expect(this.pushImpl.sockets["booga.ws"].socket,
|
|
367
|
+
"first reconnect must store the replacement WebSocket").to.eq(secondSocket);
|
|
368
|
+
|
|
369
|
+
secondSocket._close({code: 1006, reason: "abnormal"});
|
|
370
|
+
expect(secondSocket.readyState, "second socket must be closed before reconnect").to.eq(3);
|
|
371
|
+
expect(this.pushImpl.sockets["booga.ws"].socket,
|
|
372
|
+
"closed socket reference must be cleared before second reconnect is scheduled").to.eq(null);
|
|
373
|
+
clock.tick((RECONNECT_INTERVAL * 2) - 1);
|
|
374
|
+
expect(this.socket.callCount, "second reconnect must wait two reconnect intervals").to.eq(2);
|
|
375
|
+
clock.tick(1);
|
|
376
|
+
expect(this.socket.callCount, "second reconnect must create the third WebSocket").to.eq(3);
|
|
377
|
+
expect(this.pushImpl.sockets["booga.ws"].socket,
|
|
378
|
+
"second reconnect must store the replacement WebSocket").to.eq(thirdSocket);
|
|
379
|
+
} finally {
|
|
380
|
+
clock.restore();
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("must not fire onopen again when a reconnect succeeds after a prior working connection", function () {
|
|
385
|
+
// Spec (Jakarta Faces 3+): "This will be invoked on the very first connection attempt."
|
|
386
|
+
// "This will not be invoked when the web socket auto-reconnects a broken connection
|
|
387
|
+
// after the first successful connection."
|
|
388
|
+
// Also verifies reconnectAttempts resets to 0 so a further drop can start a fresh cycle.
|
|
389
|
+
const clock = sinon.useFakeTimers();
|
|
390
|
+
const firstSocket = new FakeWebsocket();
|
|
391
|
+
// Plain object instead of FakeWebsocket: we manually fire onopen so there is no
|
|
392
|
+
// constructor setTimeout that fires at an uncontrolled point in fake-timer time.
|
|
393
|
+
const reconnectWs: any = {
|
|
394
|
+
readyState: 0,
|
|
395
|
+
onopen: () => {}, onmessage: () => {}, onclose: () => {}, onerror: () => {},
|
|
396
|
+
send() {},
|
|
397
|
+
close() { this.readyState = 3; this.onclose({}); }
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
this.socket.resetBehavior();
|
|
402
|
+
this.socket.onCall(0).returns(firstSocket);
|
|
403
|
+
this.socket.onCall(1).returns(reconnectWs);
|
|
404
|
+
|
|
405
|
+
let openCount = 0;
|
|
406
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
407
|
+
() => { openCount++; },
|
|
408
|
+
() => {}, () => {}, () => {},
|
|
409
|
+
"",
|
|
410
|
+
true
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
// initial connection succeeds — onopen must fire exactly once
|
|
414
|
+
clock.tick(10);
|
|
415
|
+
expect(openCount, "onopen must fire on the initial connect").to.eq(1);
|
|
416
|
+
|
|
417
|
+
// abnormal close → reconnect scheduled, reconnectAttempts increments to 1
|
|
418
|
+
firstSocket._close({code: 1006, reason: "abnormal"});
|
|
419
|
+
clock.tick(RECONNECT_INTERVAL); // fires open() → reconnectWs bound via bindCallbacks
|
|
420
|
+
|
|
421
|
+
// reconnect succeeds: manually trigger onopen on the newly-bound socket
|
|
422
|
+
reconnectWs.readyState = 1;
|
|
423
|
+
reconnectWs.onopen({});
|
|
424
|
+
|
|
425
|
+
expect(openCount, "onopen must not fire again on a successful reconnect").to.eq(1);
|
|
426
|
+
expect(this.pushImpl.sockets["booga.ws"].reconnectAttempts,
|
|
427
|
+
"reconnectAttempts must reset to 0 after successful reconnect").to.eq(0);
|
|
428
|
+
} finally {
|
|
429
|
+
clock.restore();
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it("must call onclose and stop reconnecting after MAX_RECONNECT_ATTEMPTS failed attempts", function () {
|
|
434
|
+
const clock = sinon.useFakeTimers();
|
|
435
|
+
// Create the initial socket AFTER installing fake timers so its constructor
|
|
436
|
+
// setTimeout is under fake-timer control — clock.tick(10) will fire onopen.
|
|
437
|
+
// All reconnect attempts return the same object; bindCallbacks() rebinds on each open().
|
|
438
|
+
const initialSocket = new FakeWebsocket();
|
|
439
|
+
this.socket.resetBehavior();
|
|
440
|
+
this.socket.returns(initialSocket);
|
|
441
|
+
|
|
442
|
+
let closeCalled = false;
|
|
443
|
+
let closeCode: any = null;
|
|
444
|
+
|
|
445
|
+
try {
|
|
446
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
447
|
+
() => {},
|
|
448
|
+
() => {},
|
|
449
|
+
() => {},
|
|
450
|
+
(code: number) => { closeCalled = true; closeCode = code; },
|
|
451
|
+
"",
|
|
452
|
+
true
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
// tick past FakeWebsocket constructor setTimeout so initial onopen fires (hasEverConnected = true)
|
|
456
|
+
clock.tick(10);
|
|
457
|
+
|
|
458
|
+
// drive MAX_RECONNECT_ATTEMPTS abnormal closes; each close schedules the next open
|
|
459
|
+
// and the tick fires it, leaving reconnectAttempts = MAX_RECONNECT_ATTEMPTS after the loop
|
|
460
|
+
for (let attempt = 1; attempt <= MAX_RECONNECT_ATTEMPTS; attempt++) {
|
|
461
|
+
initialSocket._close({code: 1006, reason: "abnormal"});
|
|
462
|
+
clock.tick(RECONNECT_INTERVAL * attempt);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
expect(closeCalled, "onclose must not fire while reconnect budget remains").to.be.false;
|
|
466
|
+
|
|
467
|
+
// this close tips reconnectAttempts over the limit → terminal path
|
|
468
|
+
initialSocket._close({code: 1006, reason: "abnormal"});
|
|
469
|
+
|
|
470
|
+
expect(closeCalled, "onclose must fire once all reconnect attempts are exhausted").to.be.true;
|
|
471
|
+
expect(closeCode).to.eq(1006);
|
|
472
|
+
} finally {
|
|
473
|
+
clock.restore();
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
it("must call onclose callback when server closes with REASON_EXPIRED", function (done) {
|
|
478
|
+
let closeCalled = false;
|
|
479
|
+
let closeCode: any = null;
|
|
480
|
+
|
|
481
|
+
new Promise<void>((resolve) => {
|
|
482
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
483
|
+
() => { this.fakeWebsocket._close({code: 1000, reason: REASON_EXPIRED}); },
|
|
484
|
+
() => {},
|
|
485
|
+
() => {},
|
|
486
|
+
(code: number) => { closeCalled = true; closeCode = code; resolve(); },
|
|
487
|
+
"",
|
|
488
|
+
true
|
|
489
|
+
);
|
|
490
|
+
}).then(() => {
|
|
491
|
+
expect(closeCalled, "onclose must be called on REASON_EXPIRED terminal close").to.be.true;
|
|
492
|
+
expect(closeCode).to.eq(1000);
|
|
493
|
+
done();
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it("must treat any close code 1000 as terminal and not reconnect", function (done) {
|
|
498
|
+
let closeCalled = false;
|
|
499
|
+
let errorCalled = false;
|
|
500
|
+
let closeCode: any = null;
|
|
501
|
+
const wsCallCount = this.socket.callCount;
|
|
502
|
+
|
|
503
|
+
new Promise<void>((resolve) => {
|
|
504
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
505
|
+
() => { this.fakeWebsocket._close({code: 1000, reason: "Normal Closure"}); },
|
|
506
|
+
() => {},
|
|
507
|
+
() => { errorCalled = true; },
|
|
508
|
+
(code: number) => { closeCalled = true; closeCode = code; resolve(); },
|
|
509
|
+
"",
|
|
510
|
+
true
|
|
511
|
+
);
|
|
512
|
+
}).then(() => {
|
|
513
|
+
expect(closeCalled, "onclose must be called for any 1000 terminal close").to.be.true;
|
|
514
|
+
expect(closeCode).to.eq(1000);
|
|
515
|
+
expect(errorCalled, "onerror must not be called for a normal terminal close").to.be.false;
|
|
516
|
+
expect(this.socket.callCount, "no reconnect WebSocket must be created after 1000").to.eq(wsCallCount + 1);
|
|
517
|
+
done();
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it("must treat close code 1008 (Policy Violation) as terminal and not reconnect", function (done) {
|
|
522
|
+
// 1008 = server rejected due to authorization/security failure.
|
|
523
|
+
// Reconnecting would hit the same rejection, so it must be treated as terminal:
|
|
524
|
+
// onclose fires, onerror does not, no new WebSocket is created.
|
|
525
|
+
let closeCalled = false;
|
|
526
|
+
let errorCalled = false;
|
|
527
|
+
let closeCode: any = null;
|
|
528
|
+
const wsCallCount = this.socket.callCount;
|
|
529
|
+
|
|
530
|
+
new Promise<void>((resolve) => {
|
|
531
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
532
|
+
() => { this.fakeWebsocket._close({code: 1008, reason: "Policy Violation"}); },
|
|
533
|
+
() => {},
|
|
534
|
+
() => { errorCalled = true; },
|
|
535
|
+
(code: number) => { closeCalled = true; closeCode = code; resolve(); },
|
|
536
|
+
"",
|
|
537
|
+
true
|
|
538
|
+
);
|
|
539
|
+
}).then(() => {
|
|
540
|
+
expect(closeCalled, "onclose must be called for a 1008 terminal close").to.be.true;
|
|
541
|
+
expect(closeCode).to.eq(1008);
|
|
542
|
+
expect(errorCalled, "onerror must not be called for a terminal close").to.be.false;
|
|
543
|
+
expect(this.socket.callCount, "no reconnect WebSocket must be created after 1008").to.eq(wsCallCount + 1);
|
|
544
|
+
done();
|
|
545
|
+
});
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
it("must treat failed first connection attempt as terminal and not reconnect", function () {
|
|
549
|
+
const firstSocket: any = {
|
|
550
|
+
readyState: 0,
|
|
551
|
+
onopen: () => {}, onmessage: () => {}, onclose: () => {}, onerror: () => {},
|
|
552
|
+
send() {},
|
|
553
|
+
close() { this.readyState = 3; this.onclose({}); }
|
|
554
|
+
};
|
|
555
|
+
this.socket.resetBehavior();
|
|
556
|
+
this.socket.returns(firstSocket);
|
|
557
|
+
|
|
558
|
+
let closeCalled = false;
|
|
559
|
+
let errorCalled = false;
|
|
560
|
+
let closeCode: any = null;
|
|
561
|
+
|
|
562
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
563
|
+
() => {},
|
|
564
|
+
() => {},
|
|
565
|
+
() => { errorCalled = true; },
|
|
566
|
+
(code: number) => { closeCalled = true; closeCode = code; },
|
|
567
|
+
"",
|
|
568
|
+
true
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
firstSocket.readyState = 3;
|
|
572
|
+
firstSocket.onclose({code: 1006, reason: "initial failure"});
|
|
573
|
+
|
|
574
|
+
expect(closeCalled, "onclose must be called when the first connection attempt fails").to.be.true;
|
|
575
|
+
expect(closeCode).to.eq(1006);
|
|
576
|
+
expect(errorCalled, "onerror must not be called for a failed first connection attempt").to.be.false;
|
|
577
|
+
expect(this.socket.callCount, "no reconnect WebSocket must be created after first-attempt failure").to.eq(1);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it("must fire onopen again when open() is called after a terminal close", function (done) {
|
|
581
|
+
// After any terminal close (1000, 1008, max retries, first-attempt failure),
|
|
582
|
+
// a subsequent explicit faces.push.open() must treat the new attempt as a
|
|
583
|
+
// fresh first connection — onopen fires again and the error/reconnect state is reset.
|
|
584
|
+
let openCount = 0;
|
|
585
|
+
let closeCount = 0;
|
|
586
|
+
|
|
587
|
+
new Promise<void>((resolve) => {
|
|
588
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
589
|
+
() => {
|
|
590
|
+
openCount++;
|
|
591
|
+
if (openCount === 1) {
|
|
592
|
+
// trigger terminal close from within onopen of first connection
|
|
593
|
+
this.fakeWebsocket._close({code: 1000, reason: "Normal"});
|
|
594
|
+
} else {
|
|
595
|
+
resolve();
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
() => {},
|
|
599
|
+
() => {},
|
|
600
|
+
() => { closeCount++; },
|
|
601
|
+
"",
|
|
602
|
+
true
|
|
603
|
+
);
|
|
604
|
+
}).then(() => {
|
|
605
|
+
expect(openCount, "onopen must fire twice — once per explicit connection").to.eq(2);
|
|
606
|
+
expect(closeCount, "onclose must fire exactly once for the terminal close").to.eq(1);
|
|
607
|
+
done();
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
// Create secondSocket here so its constructor timer fires ~10ms AFTER bindCallbacks()
|
|
611
|
+
// is called by the explicit open(), not 50ms before it.
|
|
612
|
+
setTimeout(() => {
|
|
613
|
+
const secondSocket = new FakeWebsocket();
|
|
614
|
+
this.socket.onCall(1).returns(secondSocket);
|
|
615
|
+
faces.push.open("blarg");
|
|
616
|
+
}, 50);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
it("must close existing sockets when PushImpl.reset() is called", function () {
|
|
620
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
621
|
+
() => {},
|
|
622
|
+
() => {},
|
|
623
|
+
() => {},
|
|
624
|
+
() => {},
|
|
625
|
+
"",
|
|
626
|
+
true
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
const closeSpy = sinon.spy(this.fakeWebsocket, "close");
|
|
630
|
+
|
|
631
|
+
this.pushImpl.reset();
|
|
632
|
+
|
|
633
|
+
expect(closeSpy.calledOnce, "reset must close the existing WebSocket").to.be.true;
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
it("must ignore late native onopen callback after reset tears down the channel registry", function () {
|
|
637
|
+
let openCalled = false;
|
|
638
|
+
|
|
639
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
640
|
+
() => { openCalled = true; },
|
|
641
|
+
() => {},
|
|
642
|
+
() => {},
|
|
643
|
+
() => {},
|
|
644
|
+
"",
|
|
645
|
+
true
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
this.pushImpl.reset();
|
|
649
|
+
|
|
650
|
+
expect(() => this.fakeWebsocket.onopen({})).not.to.throw();
|
|
651
|
+
expect(openCalled, "user onopen must have fired for the initial connection attempt").to.be.true;
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
it("must ignore pending onclose callback after reset tears down the channel registry", function () {
|
|
655
|
+
let closeCount = 0;
|
|
656
|
+
|
|
657
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
658
|
+
() => {},
|
|
659
|
+
() => {},
|
|
660
|
+
() => {},
|
|
661
|
+
() => { closeCount++; },
|
|
662
|
+
"",
|
|
663
|
+
true
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
this.pushImpl.reset();
|
|
667
|
+
const closeCountAfterReset = closeCount;
|
|
668
|
+
|
|
669
|
+
expect(() => this.fakeWebsocket._close({code: 1006, reason: "abnormal"})).not.to.throw();
|
|
670
|
+
expect(closeCount, "late onclose must not call component callbacks after reset").to.eq(closeCountAfterReset);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it("must ignore pending onmessage callback after reset tears down the channel registry", function () {
|
|
674
|
+
let messageCount = 0;
|
|
675
|
+
|
|
676
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
677
|
+
() => {},
|
|
678
|
+
() => { messageCount++; },
|
|
679
|
+
() => {},
|
|
680
|
+
() => {},
|
|
681
|
+
"",
|
|
682
|
+
true
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
this.pushImpl.reset();
|
|
686
|
+
|
|
687
|
+
expect(() => this.fakeWebsocket._respond({data: JSON.stringify("message")})).not.to.throw();
|
|
688
|
+
expect(messageCount, "late onmessage must not call component callbacks after reset").to.eq(0);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
it("must ignore native WebSocket error events", function () {
|
|
692
|
+
let errorCalled = false;
|
|
693
|
+
|
|
694
|
+
faces.push.init("blarg", "booga.ws", "mychannel",
|
|
695
|
+
() => {},
|
|
696
|
+
() => {},
|
|
697
|
+
() => { errorCalled = true; },
|
|
698
|
+
() => {},
|
|
699
|
+
"",
|
|
700
|
+
true
|
|
701
|
+
);
|
|
702
|
+
|
|
703
|
+
expect(() => this.fakeWebsocket._error({data: '{"code":1006}'})).not.to.throw();
|
|
704
|
+
expect(errorCalled, "Faces onerror is only fired from reconnectable close handling").to.be.false;
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
it("must remove stale components whose DOM element has been removed", function (done) {
|
|
708
|
+
const channelToken = "booga.ws"; // no '?' so token == full URL
|
|
709
|
+
|
|
710
|
+
new Promise<void>((resolve) => {
|
|
711
|
+
faces.push.init("nonexistent-id", "booga.ws", "mychannel",
|
|
712
|
+
() => { this.fakeWebsocket._respond({data: '"ping"'}); resolve(); },
|
|
713
|
+
() => {},
|
|
714
|
+
() => {},
|
|
715
|
+
() => {},
|
|
716
|
+
"",
|
|
717
|
+
true
|
|
718
|
+
);
|
|
719
|
+
}).then(() => {
|
|
720
|
+
expect(this.pushImpl.clientIdsByTokens[channelToken].length,
|
|
721
|
+
"stale component must be removed from clientIdsByTokens").to.eq(0);
|
|
722
|
+
done();
|
|
723
|
+
});
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
it("must close the socket when all components are gone after an error-close", function () {
|
|
727
|
+
const channelToken = "booga.ws";
|
|
728
|
+
|
|
729
|
+
faces.push.init("clientId_close_test", "booga.ws", "mychannel",
|
|
730
|
+
() => {},
|
|
731
|
+
() => {},
|
|
732
|
+
() => {},
|
|
733
|
+
() => {},
|
|
734
|
+
"",
|
|
735
|
+
true
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
// After push.init with autoConnect=true, Socket.open() has already assigned
|
|
739
|
+
// its handler to fakeWebsocket.onopen. Invoking it directly marks the socket
|
|
740
|
+
// as hasEverConnected=true, which is required for the subsequent abnormal close
|
|
741
|
+
// to take the reconnectable (non-terminal) path.
|
|
742
|
+
this.fakeWebsocket.onopen({});
|
|
743
|
+
|
|
744
|
+
// Remove the component from the registry so the channel has no valid
|
|
745
|
+
// components. notifyErrorAndPruneMissingComponents will splice the
|
|
746
|
+
// clientId out, leaving the array empty, then closeIfChannelHasNoComponents
|
|
747
|
+
// detects this and closes the socket.
|
|
748
|
+
delete this.pushImpl.components["clientId_close_test"];
|
|
749
|
+
|
|
750
|
+
const closeSpy = sinon.spy(this.fakeWebsocket, "close");
|
|
751
|
+
try {
|
|
752
|
+
// Abnormal close (1006) is reconnectable — goes through the
|
|
753
|
+
// notifyErrorAndPruneMissingComponents → closeIfChannelHasNoComponents path.
|
|
754
|
+
this.fakeWebsocket._close({code: 1006});
|
|
755
|
+
|
|
756
|
+
expect(this.pushImpl.clientIdsByTokens[channelToken].length,
|
|
757
|
+
"clientIds array must be empty after stale component pruning").to.eq(0);
|
|
758
|
+
expect(closeSpy.called || this.fakeWebsocket.readyState === 3,
|
|
759
|
+
"socket must be closed when channel has no remaining components").to.be.true;
|
|
760
|
+
} finally {
|
|
761
|
+
closeSpy.restore();
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
});
|