@openui5/sap.ui.core 1.118.0 → 1.119.0

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.
Files changed (673) hide show
  1. package/.eslintrc.json +9 -0
  2. package/THIRDPARTY.txt +2 -2
  3. package/package.json +1 -1
  4. package/src/jquery.sap.global.js +1 -1
  5. package/src/jquery.sap.properties.js +1 -1
  6. package/src/jquery.sap.resources.js +1 -1
  7. package/src/jquery.sap.script.js +1 -1
  8. package/src/jquery.sap.storage.js +3 -3
  9. package/src/sap/base/Event.js +1 -1
  10. package/src/sap/base/Eventing.js +1 -1
  11. package/src/sap/base/config.js +1 -1
  12. package/src/sap/base/i18n/LanguageTag.js +1 -1
  13. package/src/sap/base/i18n/Localization.js +16 -1
  14. package/src/sap/base/i18n/ResourceBundle.js +5 -0
  15. package/src/sap/base/i18n/date/TimezoneUtils.js +1 -1
  16. package/src/sap/base/util/UriParameters.js +26 -19
  17. package/src/sap/base/util/restricted/_CancelablePromise.js +1 -1
  18. package/src/sap/base/util/restricted/_castArray.js +1 -1
  19. package/src/sap/base/util/restricted/_compact.js +1 -1
  20. package/src/sap/base/util/restricted/_curry.js +1 -1
  21. package/src/sap/base/util/restricted/_debounce.js +1 -1
  22. package/src/sap/base/util/restricted/_difference.js +1 -1
  23. package/src/sap/base/util/restricted/_differenceBy.js +1 -1
  24. package/src/sap/base/util/restricted/_differenceWith.js +1 -1
  25. package/src/sap/base/util/restricted/_flatMap.js +1 -1
  26. package/src/sap/base/util/restricted/_flatMapDeep.js +1 -1
  27. package/src/sap/base/util/restricted/_flatMapDepth.js +1 -1
  28. package/src/sap/base/util/restricted/_flatten.js +1 -1
  29. package/src/sap/base/util/restricted/_flattenDeep.js +1 -1
  30. package/src/sap/base/util/restricted/_flattenDepth.js +1 -1
  31. package/src/sap/base/util/restricted/_intersection.js +1 -1
  32. package/src/sap/base/util/restricted/_intersectionBy.js +1 -1
  33. package/src/sap/base/util/restricted/_intersectionWith.js +1 -1
  34. package/src/sap/base/util/restricted/_isEqual.js +1 -1
  35. package/src/sap/base/util/restricted/_isEqualWith.js +1 -1
  36. package/src/sap/base/util/restricted/_isNil.js +1 -1
  37. package/src/sap/base/util/restricted/_max.js +1 -1
  38. package/src/sap/base/util/restricted/_merge.js +1 -1
  39. package/src/sap/base/util/restricted/_mergeWith.js +1 -1
  40. package/src/sap/base/util/restricted/_min.js +1 -1
  41. package/src/sap/base/util/restricted/_omit.js +1 -1
  42. package/src/sap/base/util/restricted/_pick.js +1 -1
  43. package/src/sap/base/util/restricted/_pickBy.js +1 -1
  44. package/src/sap/base/util/restricted/_throttle.js +1 -1
  45. package/src/sap/base/util/restricted/_toArray.js +1 -1
  46. package/src/sap/base/util/restricted/_union.js +1 -1
  47. package/src/sap/base/util/restricted/_unionBy.js +1 -1
  48. package/src/sap/base/util/restricted/_unionWith.js +1 -1
  49. package/src/sap/base/util/restricted/_uniq.js +1 -1
  50. package/src/sap/base/util/restricted/_uniqBy.js +1 -1
  51. package/src/sap/base/util/restricted/_uniqWith.js +1 -1
  52. package/src/sap/base/util/restricted/_without.js +1 -1
  53. package/src/sap/base/util/restricted/_xor.js +1 -1
  54. package/src/sap/base/util/restricted/_xorBy.js +1 -1
  55. package/src/sap/base/util/restricted/_xorWith.js +1 -1
  56. package/src/sap/base/util/restricted/_zipObject.js +1 -1
  57. package/src/sap/base/util/restricted/_zipObjectDeep.js +1 -1
  58. package/src/sap/ui/Device.js +3 -3
  59. package/src/sap/ui/Global.js +4 -4
  60. package/src/sap/ui/base/BindingInfo.js +25 -3
  61. package/src/sap/ui/base/Event.js +1 -1
  62. package/src/sap/ui/base/EventProvider.js +1 -1
  63. package/src/sap/ui/base/Interface.js +1 -1
  64. package/src/sap/ui/base/ManagedObject.js +2 -2
  65. package/src/sap/ui/base/ManagedObjectMetadata.js +4 -3
  66. package/src/sap/ui/base/Metadata.js +3 -3
  67. package/src/sap/ui/base/Object.js +1 -1
  68. package/src/sap/ui/base/ObjectPool.js +1 -1
  69. package/src/sap/ui/core/.library +1 -1
  70. package/src/sap/ui/core/AccessKeysEnablement.js +2 -2
  71. package/src/sap/ui/core/BusyIndicator.js +1 -1
  72. package/src/sap/ui/core/Component.js +68 -51
  73. package/src/sap/ui/core/ComponentContainer.js +1 -1
  74. package/src/sap/ui/core/ComponentMetadata.js +1 -1
  75. package/src/sap/ui/core/ComponentSupport.js +1 -1
  76. package/src/sap/ui/core/Configuration.js +15 -167
  77. package/src/sap/ui/core/Control.js +2 -2
  78. package/src/sap/ui/core/Core.js +162 -93
  79. package/src/sap/ui/core/CustomData.js +1 -1
  80. package/src/sap/ui/core/CustomStyleClassSupport.js +3 -3
  81. package/src/sap/ui/core/DeclarativeSupport.js +1 -1
  82. package/src/sap/ui/core/Element.js +40 -4
  83. package/src/sap/ui/core/ElementMetadata.js +1 -1
  84. package/src/sap/ui/core/EnabledPropagator.js +1 -1
  85. package/src/sap/ui/core/EventBus.js +19 -2
  86. package/src/sap/ui/core/FocusHandler.js +3 -24
  87. package/src/sap/ui/core/Fragment.js +2 -2
  88. package/src/sap/ui/core/HTML.js +1 -1
  89. package/src/sap/ui/core/History.js +1 -1
  90. package/src/sap/ui/core/Icon.js +1 -1
  91. package/src/sap/ui/core/IndicationColorSupport.js +1 -1
  92. package/src/sap/ui/core/IntervalTrigger.js +1 -1
  93. package/src/sap/ui/core/InvisibleMessage.js +1 -1
  94. package/src/sap/ui/core/InvisibleRenderer.js +1 -1
  95. package/src/sap/ui/core/InvisibleText.js +2 -2
  96. package/src/sap/ui/core/Item.js +1 -1
  97. package/src/sap/ui/core/LabelEnablement.js +11 -4
  98. package/src/sap/ui/core/LayoutData.js +1 -1
  99. package/src/sap/ui/core/Lib.js +42 -42
  100. package/src/sap/ui/core/ListItem.js +1 -1
  101. package/src/sap/ui/core/LocalBusyIndicator.js +1 -1
  102. package/src/sap/ui/core/Locale.js +1 -1
  103. package/src/sap/ui/core/LocaleData.js +1 -1
  104. package/src/sap/ui/core/Manifest.js +1 -1
  105. package/src/sap/ui/core/Message.js +4 -4
  106. package/src/sap/ui/core/Messaging.js +4 -5
  107. package/src/sap/ui/core/Popup.js +3 -3
  108. package/src/sap/ui/core/RenderManager.js +15 -10
  109. package/src/sap/ui/core/Renderer.js +1 -1
  110. package/src/sap/ui/core/Rendering.js +1 -0
  111. package/src/sap/ui/core/ResizeHandler.js +15 -20
  112. package/src/sap/ui/core/ScrollBar.js +1 -1
  113. package/src/sap/ui/core/SeparatorItem.js +1 -1
  114. package/src/sap/ui/core/ShortcutHintsMixin.js +5 -5
  115. package/src/sap/ui/core/StashedControlSupport.js +4 -4
  116. package/src/sap/ui/core/StaticArea.js +66 -74
  117. package/src/sap/ui/core/Theming.js +71 -8
  118. package/src/sap/ui/core/Title.js +1 -1
  119. package/src/sap/ui/core/TooltipBase.js +1 -1
  120. package/src/sap/ui/core/UIArea.js +10 -9
  121. package/src/sap/ui/core/UIComponent.js +2 -2
  122. package/src/sap/ui/core/UIComponentMetadata.js +1 -1
  123. package/src/sap/ui/core/ValueStateSupport.js +1 -1
  124. package/src/sap/ui/core/VariantLayoutData.js +1 -1
  125. package/src/sap/ui/core/XMLComposite.js +4 -2
  126. package/src/sap/ui/core/XMLCompositeMetadata.js +1 -1
  127. package/src/sap/ui/core/_IconRegistry.js +2 -0
  128. package/src/sap/ui/core/cache/CacheManager.js +22 -16
  129. package/src/sap/ui/core/cache/LRUPersistentCache.js +13 -7
  130. package/src/sap/ui/core/date/UI5Date.js +1 -1
  131. package/src/sap/ui/core/delegate/ItemNavigation.js +3 -3
  132. package/src/sap/ui/core/delegate/ScrollEnablement.js +1 -1
  133. package/src/sap/ui/core/dnd/DragDropBase.js +1 -1
  134. package/src/sap/ui/core/dnd/DragDropInfo.js +6 -6
  135. package/src/sap/ui/core/dnd/DragInfo.js +4 -4
  136. package/src/sap/ui/core/dnd/DropInfo.js +6 -6
  137. package/src/sap/ui/core/format/TimezoneUtil.js +1 -1
  138. package/src/sap/ui/core/getCompatibilityVersion.js +64 -0
  139. package/src/sap/ui/core/hyphenation/Hyphenation.js +1 -1
  140. package/src/sap/ui/core/library.js +14 -9
  141. package/src/sap/ui/core/message/ControlMessageProcessor.js +4 -4
  142. package/src/sap/ui/core/message/Message.js +14 -13
  143. package/src/sap/ui/core/message/MessageManager.js +12 -13
  144. package/src/sap/ui/core/message/MessageMixin.js +2 -2
  145. package/src/sap/ui/core/message/MessageParser.js +1 -1
  146. package/src/sap/ui/core/message/MessageProcessor.js +2 -2
  147. package/src/sap/ui/core/message/MessageType.js +4 -4
  148. package/src/sap/ui/core/messagebundle_ar.properties +2 -2
  149. package/src/sap/ui/core/messagebundle_bg.properties +3 -3
  150. package/src/sap/ui/core/messagebundle_ca.properties +1 -1
  151. package/src/sap/ui/core/messagebundle_cs.properties +4 -4
  152. package/src/sap/ui/core/messagebundle_cy.properties +1 -1
  153. package/src/sap/ui/core/messagebundle_da.properties +3 -3
  154. package/src/sap/ui/core/messagebundle_de.properties +2 -2
  155. package/src/sap/ui/core/messagebundle_el.properties +10 -10
  156. package/src/sap/ui/core/messagebundle_en.properties +4 -4
  157. package/src/sap/ui/core/messagebundle_es.properties +17 -17
  158. package/src/sap/ui/core/messagebundle_fi.properties +1 -1
  159. package/src/sap/ui/core/messagebundle_fr.properties +21 -21
  160. package/src/sap/ui/core/messagebundle_hi.properties +2 -2
  161. package/src/sap/ui/core/messagebundle_hr.properties +6 -6
  162. package/src/sap/ui/core/messagebundle_hu.properties +10 -10
  163. package/src/sap/ui/core/messagebundle_id.properties +5 -5
  164. package/src/sap/ui/core/messagebundle_it.properties +57 -57
  165. package/src/sap/ui/core/messagebundle_iw.properties +5 -5
  166. package/src/sap/ui/core/messagebundle_kk.properties +1 -1
  167. package/src/sap/ui/core/messagebundle_ko.properties +6 -6
  168. package/src/sap/ui/core/messagebundle_lv.properties +5 -5
  169. package/src/sap/ui/core/messagebundle_ms.properties +5 -5
  170. package/src/sap/ui/core/messagebundle_nl.properties +12 -12
  171. package/src/sap/ui/core/messagebundle_no.properties +8 -8
  172. package/src/sap/ui/core/messagebundle_pl.properties +2 -2
  173. package/src/sap/ui/core/messagebundle_pt.properties +8 -8
  174. package/src/sap/ui/core/messagebundle_ro.properties +2 -2
  175. package/src/sap/ui/core/messagebundle_ru.properties +7 -7
  176. package/src/sap/ui/core/messagebundle_sk.properties +2 -2
  177. package/src/sap/ui/core/messagebundle_sl.properties +9 -9
  178. package/src/sap/ui/core/messagebundle_sv.properties +8 -8
  179. package/src/sap/ui/core/messagebundle_th.properties +18 -18
  180. package/src/sap/ui/core/messagebundle_tr.properties +5 -5
  181. package/src/sap/ui/core/messagebundle_uk.properties +8 -8
  182. package/src/sap/ui/core/messagebundle_vi.properties +1 -1
  183. package/src/sap/ui/core/messagebundle_zh_CN.properties +2 -2
  184. package/src/sap/ui/core/messagebundle_zh_TW.properties +24 -24
  185. package/src/sap/ui/core/mvc/HTMLView.js +1 -1
  186. package/src/sap/ui/core/mvc/JSONView.js +1 -1
  187. package/src/sap/ui/core/mvc/JSView.js +1 -1
  188. package/src/sap/ui/core/mvc/TemplateView.js +1 -1
  189. package/src/sap/ui/core/mvc/View.js +3 -3
  190. package/src/sap/ui/core/mvc/XMLView.js +1 -1
  191. package/src/sap/ui/core/plugin/DeclarativeSupport.js +1 -1
  192. package/src/sap/ui/core/plugin/LessSupport.js +3 -3
  193. package/src/sap/ui/core/plugin/TemplatingSupport.js +1 -1
  194. package/src/sap/ui/core/postmessage/Bus.js +1 -1
  195. package/src/sap/ui/core/postmessage/confirmationDialog.js +1 -1
  196. package/src/sap/ui/core/routing/async/Target.js +5 -4
  197. package/src/sap/ui/core/routing/sync/Target.js +3 -3
  198. package/src/sap/ui/core/rules/App.support.js +30 -1
  199. package/src/sap/ui/core/rules/Config.support.js +4 -0
  200. package/src/sap/ui/core/rules/CoreHelper.support.js +3 -3
  201. package/src/sap/ui/core/rules/Theming.support.js +4 -0
  202. package/src/sap/ui/core/search/OpenSearchProvider.js +1 -1
  203. package/src/sap/ui/core/search/SearchProvider.js +1 -1
  204. package/src/sap/ui/core/service/Service.js +1 -1
  205. package/src/sap/ui/core/service/ServiceFactory.js +1 -1
  206. package/src/sap/ui/core/service/ServiceFactoryRegistry.js +1 -1
  207. package/src/sap/ui/core/support/Plugin.js +1 -1
  208. package/src/sap/ui/core/support/Support.js +5 -3
  209. package/src/sap/ui/core/support/ToolsAPI.js +8 -4
  210. package/src/sap/ui/core/support/plugins/Breakpoint.js +4 -4
  211. package/src/sap/ui/core/support/plugins/ControlTree.js +31 -13
  212. package/src/sap/ui/core/support/plugins/Interaction.js +1 -1
  213. package/src/sap/ui/core/support/plugins/LocalStorage.js +1 -1
  214. package/src/sap/ui/core/support/plugins/Performance.js +1 -1
  215. package/src/sap/ui/core/support/plugins/Selector.js +2 -2
  216. package/src/sap/ui/core/support/plugins/TechInfo.js +1 -1
  217. package/src/sap/ui/core/support/plugins/Trace.js +1 -1
  218. package/src/sap/ui/core/support/plugins/ViewInfo.js +6 -4
  219. package/src/sap/ui/core/support/techinfo/TechnicalInfo.js +4 -2
  220. package/src/sap/ui/core/support/usage/EventBroadcaster.js +1 -1
  221. package/src/sap/ui/core/themes/base/base.less +275 -269
  222. package/src/sap/ui/core/themes/base/fonts/SAP-icons.ttf +0 -0
  223. package/src/sap/ui/core/themes/base/fonts/SAP-icons.woff2 +0 -0
  224. package/src/sap/ui/core/themes/base/global.less +8 -8
  225. package/src/sap/ui/core/theming/Parameters.js +4 -5
  226. package/src/sap/ui/core/theming/ThemeHelper.js +0 -1
  227. package/src/sap/ui/core/theming/ThemeManager.js +15 -14
  228. package/src/sap/ui/core/tmpl/DOMAttribute.js +1 -1
  229. package/src/sap/ui/core/tmpl/DOMElement.js +1 -1
  230. package/src/sap/ui/core/tmpl/HandlebarsTemplate.js +1 -1
  231. package/src/sap/ui/core/tmpl/Template.js +1 -1
  232. package/src/sap/ui/core/tmpl/TemplateControl.js +4 -2
  233. package/src/sap/ui/core/util/AsyncHintsHelper.js +1 -1
  234. package/src/sap/ui/core/util/Export.js +1 -1
  235. package/src/sap/ui/core/util/ExportCell.js +1 -1
  236. package/src/sap/ui/core/util/ExportColumn.js +1 -1
  237. package/src/sap/ui/core/util/ExportRow.js +1 -1
  238. package/src/sap/ui/core/util/ExportType.js +1 -1
  239. package/src/sap/ui/core/util/ExportTypeCSV.js +1 -1
  240. package/src/sap/ui/core/util/File.js +1 -1
  241. package/src/sap/ui/core/util/LibraryInfo.js +1 -1
  242. package/src/sap/ui/core/util/MockServer.js +1 -1
  243. package/src/sap/ui/core/util/PasteHelper.js +1 -1
  244. package/src/sap/ui/core/util/reflection/BaseTreeModifier.js +27 -4
  245. package/src/sap/ui/core/util/reflection/JsControlTreeModifier.js +55 -30
  246. package/src/sap/ui/core/util/reflection/XmlTreeModifier.js +54 -48
  247. package/src/sap/ui/core/util/serializer/HTMLViewSerializer.js +2 -2
  248. package/src/sap/ui/core/util/serializer/Serializer.js +3 -3
  249. package/src/sap/ui/core/util/serializer/ViewSerializer.js +27 -10
  250. package/src/sap/ui/core/util/serializer/XMLViewSerializer.js +2 -2
  251. package/src/sap/ui/core/util/serializer/delegate/Delegate.js +1 -1
  252. package/src/sap/ui/core/util/serializer/delegate/HTML.js +1 -1
  253. package/src/sap/ui/core/util/serializer/delegate/XML.js +1 -1
  254. package/src/sap/ui/core/webc/WebComponent.js +3 -3
  255. package/src/sap/ui/core/webc/WebComponentMetadata.js +1 -1
  256. package/src/sap/ui/core/ws/ReadyState.js +1 -1
  257. package/src/sap/ui/core/ws/SapPcpWebSocket.js +1 -1
  258. package/src/sap/ui/core/ws/WebSocket.js +1 -1
  259. package/src/sap/ui/debug/ControlTree.js +5 -5
  260. package/src/sap/ui/debug/DebugEnv.js +15 -6
  261. package/src/sap/ui/debug/PropertyList.js +3 -3
  262. package/src/sap/ui/dom/jquery/control.js +3 -4
  263. package/src/sap/ui/events/F6Navigation.js +2 -1
  264. package/src/sap/ui/model/ClientModel.js +33 -1
  265. package/src/sap/ui/model/ClientPropertyBinding.js +17 -1
  266. package/src/sap/ui/model/CompositeDataState.js +1 -1
  267. package/src/sap/ui/model/CompositeType.js +1 -1
  268. package/src/sap/ui/model/DataState.js +1 -1
  269. package/src/sap/ui/model/Filter.js +1 -1
  270. package/src/sap/ui/model/MetaModel.js +1 -1
  271. package/src/sap/ui/model/Model.js +1 -1
  272. package/src/sap/ui/model/SelectionModel.js +1 -1
  273. package/src/sap/ui/model/SimpleType.js +1 -1
  274. package/src/sap/ui/model/TreeAutoExpandMode.js +1 -1
  275. package/src/sap/ui/model/Type.js +1 -1
  276. package/src/sap/ui/model/json/JSONModel.js +2 -3
  277. package/src/sap/ui/model/message/MessageModel.js +3 -7
  278. package/src/sap/ui/model/odata/ODataAnnotations.js +1 -1
  279. package/src/sap/ui/model/odata/ODataMessageParser.js +1 -1
  280. package/src/sap/ui/model/odata/ODataMetaModel.js +1 -1
  281. package/src/sap/ui/model/odata/ODataMetadata.js +1 -1
  282. package/src/sap/ui/model/odata/ODataModel.js +1 -1
  283. package/src/sap/ui/model/odata/type/Boolean.js +1 -1
  284. package/src/sap/ui/model/odata/type/Byte.js +1 -1
  285. package/src/sap/ui/model/odata/type/Currency.js +1 -1
  286. package/src/sap/ui/model/odata/type/Date.js +1 -1
  287. package/src/sap/ui/model/odata/type/DateTime.js +1 -1
  288. package/src/sap/ui/model/odata/type/DateTimeBase.js +1 -1
  289. package/src/sap/ui/model/odata/type/DateTimeOffset.js +1 -1
  290. package/src/sap/ui/model/odata/type/DateTimeWithTimezone.js +1 -2
  291. package/src/sap/ui/model/odata/type/Decimal.js +1 -1
  292. package/src/sap/ui/model/odata/type/Double.js +1 -1
  293. package/src/sap/ui/model/odata/type/Guid.js +1 -1
  294. package/src/sap/ui/model/odata/type/Int.js +1 -1
  295. package/src/sap/ui/model/odata/type/Int16.js +1 -1
  296. package/src/sap/ui/model/odata/type/Int32.js +1 -1
  297. package/src/sap/ui/model/odata/type/Int64.js +1 -1
  298. package/src/sap/ui/model/odata/type/ODataType.js +2 -3
  299. package/src/sap/ui/model/odata/type/Raw.js +1 -1
  300. package/src/sap/ui/model/odata/type/SByte.js +1 -1
  301. package/src/sap/ui/model/odata/type/Single.js +1 -1
  302. package/src/sap/ui/model/odata/type/Stream.js +1 -1
  303. package/src/sap/ui/model/odata/type/String.js +1 -1
  304. package/src/sap/ui/model/odata/type/Time.js +1 -1
  305. package/src/sap/ui/model/odata/type/TimeOfDay.js +1 -1
  306. package/src/sap/ui/model/odata/type/Unit.js +1 -1
  307. package/src/sap/ui/model/odata/v2/Context.js +13 -5
  308. package/src/sap/ui/model/odata/v2/ODataAnnotations.js +1 -1
  309. package/src/sap/ui/model/odata/v2/ODataListBinding.js +85 -56
  310. package/src/sap/ui/model/odata/v2/ODataModel.js +20 -15
  311. package/src/sap/ui/model/odata/v2/ODataTreeBinding.js +1 -1
  312. package/src/sap/ui/model/odata/v4/Context.js +60 -10
  313. package/src/sap/ui/model/odata/v4/ODataBinding.js +13 -4
  314. package/src/sap/ui/model/odata/v4/ODataContextBinding.js +159 -34
  315. package/src/sap/ui/model/odata/v4/ODataListBinding.js +94 -24
  316. package/src/sap/ui/model/odata/v4/ODataMetaModel.js +1 -1
  317. package/src/sap/ui/model/odata/v4/ODataModel.js +10 -10
  318. package/src/sap/ui/model/odata/v4/ODataParentBinding.js +4 -2
  319. package/src/sap/ui/model/odata/v4/ODataPropertyBinding.js +10 -13
  320. package/src/sap/ui/model/odata/v4/lib/_AggregationCache.js +105 -25
  321. package/src/sap/ui/model/odata/v4/lib/_AggregationHelper.js +3 -5
  322. package/src/sap/ui/model/odata/v4/lib/_Cache.js +83 -24
  323. package/src/sap/ui/model/odata/v4/lib/_Helper.js +6 -20
  324. package/src/sap/ui/model/odata/v4/lib/_Requestor.js +3 -3
  325. package/src/sap/ui/model/odata/v4/lib/_V2MetadataConverter.js +1 -1
  326. package/src/sap/ui/model/resource/ResourceModel.js +1 -1
  327. package/src/sap/ui/model/type/Boolean.js +1 -1
  328. package/src/sap/ui/model/type/Currency.js +1 -1
  329. package/src/sap/ui/model/type/Date.js +1 -2
  330. package/src/sap/ui/model/type/DateInterval.js +1 -2
  331. package/src/sap/ui/model/type/DateTime.js +1 -1
  332. package/src/sap/ui/model/type/DateTimeInterval.js +1 -1
  333. package/src/sap/ui/model/type/FileSize.js +1 -1
  334. package/src/sap/ui/model/type/Float.js +1 -1
  335. package/src/sap/ui/model/type/Integer.js +1 -1
  336. package/src/sap/ui/model/type/String.js +1 -1
  337. package/src/sap/ui/model/type/Time.js +1 -1
  338. package/src/sap/ui/model/type/TimeInterval.js +1 -1
  339. package/src/sap/ui/model/type/Unit.js +1 -1
  340. package/src/sap/ui/model/xml/XMLModel.js +2 -2
  341. package/src/sap/ui/model/xml/XMLPropertyBinding.js +4 -2
  342. package/src/sap/ui/performance/BeaconRequest.js +8 -10
  343. package/src/sap/ui/qunit/qunit-coverage-istanbul.js +60 -6
  344. package/src/sap/ui/qunit/utils/ControlIterator.js +1 -1
  345. package/src/sap/ui/qunit/utils/MemoryLeakCheck.js +1 -1
  346. package/src/sap/ui/qunit/utils/waitForThemeApplied.js +16 -14
  347. package/src/sap/ui/test/BlanketReporterUI.view.xml +5 -2
  348. package/src/sap/ui/test/OpaPlugin.js +3 -3
  349. package/src/sap/ui/test/TestUtils.js +3 -3
  350. package/src/sap/ui/test/generic/TestBase.js +1 -1
  351. package/src/sap/ui/test/matchers/Descendant.js +1 -1
  352. package/src/sap/ui/test/matchers/Sibling.js +1 -1
  353. package/src/sap/ui/test/selectors/_LabelFor.js +3 -2
  354. package/src/sap/ui/test/starter/_setupAndStart.js +35 -11
  355. package/src/sap/ui/util/Storage.js +1 -1
  356. package/test/sap/ui/core/HTMLControl.html +94 -93
  357. package/test/sap/ui/core/HyphenationPlayground.html +10 -9
  358. package/test/sap/ui/core/Strings.view.xml +5 -1
  359. package/test/sap/ui/core/ThemeParameters.html +31 -30
  360. package/test/sap/ui/core/ValidateURL.html +10 -10
  361. package/test/sap/ui/core/demokit/sample/BusyIndicator/manifest.json +2 -1
  362. package/test/sap/ui/core/demokit/sample/Commands/manifest.json +2 -2
  363. package/test/sap/ui/core/demokit/sample/ControlBusyIndicator/manifest.json +2 -1
  364. package/test/sap/ui/core/demokit/sample/ControllerExtension/manifest.json +1 -0
  365. package/test/sap/ui/core/demokit/sample/FieldGroup/manifest.json +1 -0
  366. package/test/sap/ui/core/demokit/sample/Html/manifest.json +1 -0
  367. package/test/sap/ui/core/demokit/sample/Html/preserveDOM/manifest.json +1 -0
  368. package/test/sap/ui/core/demokit/sample/Html/static/manifest.json +1 -0
  369. package/test/sap/ui/core/demokit/sample/HyphenationAPI/C.controller.js +3 -3
  370. package/test/sap/ui/core/demokit/sample/Icon/manifest.json +2 -1
  371. package/test/sap/ui/core/demokit/sample/InvisibleMessage/InvisibleMessage.controller.js +4 -4
  372. package/test/sap/ui/core/demokit/sample/InvisibleMessage/manifest.json +2 -1
  373. package/test/sap/ui/core/demokit/sample/InvisibleText/manifest.json +2 -1
  374. package/test/sap/ui/core/demokit/sample/MessageManager/BasicODataMessages/manifest.json +1 -0
  375. package/test/sap/ui/core/demokit/sample/OpaAction/manifest.json +1 -0
  376. package/test/sap/ui/core/demokit/sample/OpaAutoWaitParams/OpaAutoWaitParams.js +1 -1
  377. package/test/sap/ui/core/demokit/sample/OpaAutoWaitParams/applicationUnderTest/manifest.json +2 -2
  378. package/test/sap/ui/core/demokit/sample/OpaAutoWaitParams/manifest.json +2 -1
  379. package/test/sap/ui/core/demokit/sample/OpaBusyIndicator/applicationUnderTest/manifest.json +2 -2
  380. package/test/sap/ui/core/demokit/sample/OpaBusyIndicator/manifest.json +2 -1
  381. package/test/sap/ui/core/demokit/sample/OpaById/applicationUnderTest/manifest.json +2 -2
  382. package/test/sap/ui/core/demokit/sample/OpaById/manifest.json +2 -1
  383. package/test/sap/ui/core/demokit/sample/OpaDynamicWait/applicationUnderTest/manifest.json +2 -2
  384. package/test/sap/ui/core/demokit/sample/OpaDynamicWait/manifest.json +2 -1
  385. package/test/sap/ui/core/demokit/sample/OpaGetStarted/manifest.json +2 -1
  386. package/test/sap/ui/core/demokit/sample/OpaMatchers/applicationUnderTest/manifest.json +2 -2
  387. package/test/sap/ui/core/demokit/sample/OpaMatchers/manifest.json +2 -1
  388. package/test/sap/ui/core/demokit/sample/OpaPageObject/applicationUnderTest/manifest.json +2 -2
  389. package/test/sap/ui/core/demokit/sample/OpaPageObject/manifest.json +2 -1
  390. package/test/sap/ui/core/demokit/sample/OpaStartup/iStartMyAppInAFrame/applicationUnderTest/manifest.json +2 -2
  391. package/test/sap/ui/core/demokit/sample/OpaStartup/iStartMyAppInAFrame/manifest.json +2 -1
  392. package/test/sap/ui/core/demokit/sample/OpaStartup/iStartMyUIComponent/applicationUnderTest/manifest.json +2 -2
  393. package/test/sap/ui/core/demokit/sample/OpaStartup/iStartMyUIComponent/manifest.json +2 -1
  394. package/test/sap/ui/core/demokit/sample/OpaStaticAreaControls/applicationUnderTest/manifest.json +2 -2
  395. package/test/sap/ui/core/demokit/sample/OpaStaticAreaControls/manifest.json +2 -1
  396. package/test/sap/ui/core/demokit/sample/OpaTestLibrary/applicationUnderTest/manifest.json +2 -2
  397. package/test/sap/ui/core/demokit/sample/OpaTestLibrary/manifest.json +2 -1
  398. package/test/sap/ui/core/demokit/sample/OpaURLParameters/iStartMyAppInAFrameWithURLParameters/applicationUnderTest/manifest.json +2 -2
  399. package/test/sap/ui/core/demokit/sample/OpaURLParameters/iStartMyAppInAFrameWithURLParameters/manifest.json +2 -1
  400. package/test/sap/ui/core/demokit/sample/OpaURLParameters/iStartMyUIComponentWithURLParameters/applicationUnderTest/manifest.json +2 -2
  401. package/test/sap/ui/core/demokit/sample/OpaURLParameters/iStartMyUIComponentWithURLParameters/manifest.json +2 -1
  402. package/test/sap/ui/core/demokit/sample/OpaWithSupportAssistant/manifest.json +2 -1
  403. package/test/sap/ui/core/demokit/sample/PatternMatching/manifest.json +2 -1
  404. package/test/sap/ui/core/demokit/sample/PatternMatching/patternApp/manifest.json +2 -2
  405. package/test/sap/ui/core/demokit/sample/RoutingFullscreen/manifest.json +2 -1
  406. package/test/sap/ui/core/demokit/sample/RoutingMasterDetail/manifest.json +2 -1
  407. package/test/sap/ui/core/demokit/sample/RoutingNestedComponent/manifest.json +2 -2
  408. package/test/sap/ui/core/demokit/sample/RoutingNestedComponent/reuse/categories/manifest.json +2 -1
  409. package/test/sap/ui/core/demokit/sample/RoutingNestedComponent/reuse/products/manifest.json +2 -1
  410. package/test/sap/ui/core/demokit/sample/RoutingNestedComponent/reuse/suppliers/manifest.json +2 -1
  411. package/test/sap/ui/core/demokit/sample/TargetsStandalone/manifest.json +2 -1
  412. package/test/sap/ui/core/demokit/sample/ThemeCustomClasses/ThemeCustomClasses.controller.js +3 -3
  413. package/test/sap/ui/core/demokit/sample/ThemeCustomClasses/manifest.json +1 -0
  414. package/test/sap/ui/core/demokit/sample/TypeCurrency/manifest.json +1 -0
  415. package/test/sap/ui/core/demokit/sample/TypeDateAsDate/manifest.json +1 -0
  416. package/test/sap/ui/core/demokit/sample/TypeDateAsString/manifest.json +1 -0
  417. package/test/sap/ui/core/demokit/sample/TypeDateTime/manifest.json +1 -0
  418. package/test/sap/ui/core/demokit/sample/TypeFileSize/manifest.json +1 -0
  419. package/test/sap/ui/core/demokit/sample/TypeFloat/manifest.json +1 -0
  420. package/test/sap/ui/core/demokit/sample/TypeInteger/manifest.json +1 -0
  421. package/test/sap/ui/core/demokit/sample/TypeTimeAsTime/manifest.json +1 -0
  422. package/test/sap/ui/core/demokit/sample/View/async/manifest.json +2 -1
  423. package/test/sap/ui/core/demokit/sample/View/preprocessor/manifest.json +2 -1
  424. package/test/sap/ui/core/demokit/sample/ViewTemplate/scenario/manifest.json +2 -1
  425. package/test/sap/ui/core/demokit/sample/XMLComposite/02/manifest.json +1 -0
  426. package/test/sap/ui/core/demokit/sample/common/Controller.js +3 -2
  427. package/test/sap/ui/core/demokit/sample/common/Helper.js +15 -2
  428. package/test/sap/ui/core/demokit/sample/common/pages/Any.js +3 -0
  429. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithPageObjects/applicationUnderTest/manifest.json +1 -0
  430. package/test/sap/ui/core/demokit/sample/gherkin/GherkinWithPageObjects/manifest.json +2 -1
  431. package/test/sap/ui/core/demokit/sample/matcher/BindingPath/manifest.json +2 -1
  432. package/test/sap/ui/core/demokit/sample/matcher/BindingPath/webapp/manifest.json +2 -2
  433. package/test/sap/ui/core/demokit/sample/matcher/Descendant/manifest.json +2 -1
  434. package/test/sap/ui/core/demokit/sample/matcher/Descendant/webapp/manifest.json +2 -2
  435. package/test/sap/ui/core/demokit/sample/matcher/I18NText/manifest.json +2 -1
  436. package/test/sap/ui/core/demokit/sample/matcher/I18NText/webapp/manifest.json +2 -2
  437. package/test/sap/ui/core/demokit/sample/matcher/LabelFor/manifest.json +2 -1
  438. package/test/sap/ui/core/demokit/sample/matcher/LabelFor/webapp/manifest.json +2 -2
  439. package/test/sap/ui/core/demokit/sample/odata/types/v2/DateTimeOffset/manifest.json +1 -0
  440. package/test/sap/ui/core/demokit/sample/odata/types/v4/Date/manifest.json +1 -0
  441. package/test/sap/ui/core/demokit/sample/odata/types/v4/TimeOfDay/manifest.json +1 -0
  442. package/test/sap/ui/core/demokit/sample/odata/v2/AutoExpand/AutoExpand.view.xml +6 -2
  443. package/test/sap/ui/core/demokit/sample/odata/v4/Ancestry/Main.view.xml +7 -3
  444. package/test/sap/ui/core/demokit/sample/odata/v4/DataAggregation/DataAggregation.controller.js +2 -2
  445. package/test/sap/ui/core/demokit/sample/odata/v4/DataAggregation/DataAggregation.view.xml +7 -4
  446. package/test/sap/ui/core/demokit/sample/odata/v4/DataAggregation/tests/expandPageCollapse.js +1 -1
  447. package/test/sap/ui/core/demokit/sample/odata/v4/DataAggregation/tests/filter.js +1 -1
  448. package/test/sap/ui/core/demokit/sample/odata/v4/DeepCreate/Opa.qunit.js +1 -1
  449. package/test/sap/ui/core/demokit/sample/odata/v4/Draft/Opa.qunit.js +3 -5
  450. package/test/sap/ui/core/demokit/sample/odata/v4/FieldGroups/Opa.qunit.js +4 -2
  451. package/test/sap/ui/core/demokit/sample/odata/v4/FlatDataAggregation/FlatDataAggregation.controller.js +6 -4
  452. package/test/sap/ui/core/demokit/sample/odata/v4/FlatDataAggregation/FlatDataAggregation.view.xml +6 -2
  453. package/test/sap/ui/core/demokit/sample/odata/v4/FlexibleColumnLayout/Opa.qunit.js +9 -16
  454. package/test/sap/ui/core/demokit/sample/odata/v4/GridTable/GridTable.view.xml +6 -2
  455. package/test/sap/ui/core/demokit/sample/odata/v4/HierarchyBindAction/Main.view.xml +7 -3
  456. package/test/sap/ui/core/demokit/sample/odata/v4/LateProperties/Opa.qunit.js +1 -1
  457. package/test/sap/ui/core/demokit/sample/odata/v4/ListBinding/Opa.qunit.js +1 -1
  458. package/test/sap/ui/core/demokit/sample/odata/v4/MultipleInlineCreationRowsGrid/Main.view.xml +5 -2
  459. package/test/sap/ui/core/demokit/sample/odata/v4/MultipleInlineCreationRowsGrid/Opa.qunit.js +4 -2
  460. package/test/sap/ui/core/demokit/sample/odata/v4/Products/Opa.qunit.js +1 -1
  461. package/test/sap/ui/core/demokit/sample/odata/v4/RecursiveHierarchy/RecursiveHierarchy.controller.js +29 -4
  462. package/test/sap/ui/core/demokit/sample/odata/v4/RecursiveHierarchy/RecursiveHierarchy.view.xml +30 -5
  463. package/test/sap/ui/core/demokit/sample/odata/v4/RecursiveHierarchy/SandboxModel.js +33 -6
  464. package/test/sap/ui/core/demokit/sample/odata/v4/RecursiveHierarchy/tests/createEdit.js +1 -1
  465. package/test/sap/ui/core/demokit/sample/odata/v4/RecursiveHierarchy/tests/pageExpandCollapse.js +1 -1
  466. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrderTP100_V2/Opa.qunit.js +1 -1
  467. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrderTP100_V4/Opa.qunit.js +1 -1
  468. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/pages/Main.js +9 -8
  469. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/ChangeContext.js +1 -1
  470. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/Create.js +1 -1
  471. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/CreateMultiple.js +1 -1
  472. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/CreateRelative.js +1 -1
  473. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/MessageHandling.js +1 -1
  474. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/TypeDeterminationAndDelete.js +8 -9
  475. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/WriteNonDeferredGroup.js +1 -1
  476. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrders/tests/additionalTargets.js +1 -1
  477. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrdersRTATest/tests/AdaptSalesOrdersTable.js +1 -1
  478. package/test/sap/ui/core/demokit/sample/odata/v4/SalesOrdersTemplate/Opa.qunit.js +1 -1
  479. package/test/sap/ui/core/demokit/sample/odata/v4/ServerDrivenPaging/Main.view.xml +5 -2
  480. package/test/sap/ui/core/demokit/sample/odata/v4/ServerDrivenPaging/pages/Main.js +4 -2
  481. package/test/sap/ui/core/demokit/sample/odata/v4/Sticky/Opa.qunit.js +1 -1
  482. package/test/sap/ui/core/demokit/tutorial/mockserver/01/webapp/manifest.json +1 -1
  483. package/test/sap/ui/core/demokit/tutorial/mockserver/02/webapp/manifest.json +1 -1
  484. package/test/sap/ui/core/demokit/tutorial/mockserver/03/webapp/manifest.json +1 -1
  485. package/test/sap/ui/core/demokit/tutorial/mockserver/04/webapp/manifest.json +1 -1
  486. package/test/sap/ui/core/demokit/tutorial/troubleshooting/01/webapp/manifest.json +1 -1
  487. package/test/sap/ui/core/internal/samples/composite/xmlcomposite/exTableWrapperOuterBinding/Test.controller.js +3 -2
  488. package/test/sap/ui/core/internal/samples/odata/v2/SalesOrders/Main.controller.js +1 -1
  489. package/test/sap/ui/core/internal/samples/odata/v2/SalesOrders/Main.view.xml +6 -3
  490. package/test/sap/ui/core/internal/samples/odata/v2/TreeTable/Main.view.xml +1 -1
  491. package/test/sap/ui/core/qunit/ControlDefinition.qunit.js +40 -20
  492. package/test/sap/ui/core/qunit/ControlRenderer.qunit.js +1 -1
  493. package/test/sap/ui/core/qunit/Core.qunit.js +5 -4
  494. package/test/sap/ui/core/qunit/Core_libraryTerminologies_integration.qunit.js +12 -11
  495. package/test/sap/ui/core/qunit/CustomStyleClassSupport.qunit.js +119 -117
  496. package/test/sap/ui/core/qunit/CustomThemeFallback.qunit.js +5 -17
  497. package/test/sap/ui/core/qunit/Declarative.qunit.js +37 -37
  498. package/test/sap/ui/core/qunit/Element_base.qunit.js +1 -1
  499. package/test/sap/ui/core/qunit/EventBus.qunit.js +4 -3
  500. package/test/sap/ui/core/qunit/FastNavigation.qunit.js +3 -2
  501. package/test/sap/ui/core/qunit/FieldGroup.qunit.js +9 -8
  502. package/test/sap/ui/core/qunit/FocusHandler.qunit.js +5 -4
  503. package/test/sap/ui/core/qunit/Fragment.qunit.js +12 -12
  504. package/test/sap/ui/core/qunit/Fragment_legacyAPIs.qunit.js +13 -12
  505. package/test/sap/ui/core/qunit/HTML.qunit.js +35 -35
  506. package/test/sap/ui/core/qunit/IconPool.qunit.js +6 -6
  507. package/test/sap/ui/core/qunit/InvisibleText.qunit.js +5 -4
  508. package/test/sap/ui/core/qunit/ManagedObject.qunit.js +3 -3
  509. package/test/sap/ui/core/qunit/PlaceAt.qunit.js +2 -2
  510. package/test/sap/ui/core/qunit/ScrollBar.qunit.js +3 -3
  511. package/test/sap/ui/core/qunit/StashedControlSupport.qunit.js +9 -9
  512. package/test/sap/ui/core/qunit/ThemeHelper.qunit.js +5 -4
  513. package/test/sap/ui/core/qunit/ThemeManager.qunit.js +47 -79
  514. package/test/sap/ui/core/qunit/ThemeParameters.qunit.js +40 -372
  515. package/test/sap/ui/core/qunit/ThemeParameters_legacyAPIs.qunit.js +686 -0
  516. package/test/sap/ui/core/qunit/TooltipBase.qunit.js +3 -2
  517. package/test/sap/ui/core/qunit/UIArea.qunit.js +10 -10
  518. package/test/sap/ui/core/qunit/analytics/testsuite4analytics.qunit.html +3 -3
  519. package/test/sap/ui/core/qunit/base/i18n/Localization.qunit.js +4 -3
  520. package/test/sap/ui/core/qunit/base/i18n/ResourceBundle.qunit.js +13 -3
  521. package/test/sap/ui/core/qunit/base/util/UriParameters.qunit.js +27 -1
  522. package/test/sap/ui/core/qunit/bootstrap/BootstrapCustomBootTaskPreloadCss.qunit.js +4 -4
  523. package/test/sap/ui/core/qunit/bootstrap/BootstrapWithCustomBootTask.beforeBootstrap.qunit.js +22 -21
  524. package/test/sap/ui/core/qunit/bootstrap/BootstrapWithCustomBootTask.qunit.js +4 -9
  525. package/test/sap/ui/core/qunit/bootstrap/CalendarClassLoadingWithCustomBootTaskAndPreload.qunit.js +19 -4
  526. package/test/sap/ui/core/qunit/bootstrap/CfgDefaults.qunit.js +3 -2
  527. package/test/sap/ui/core/qunit/bootstrap/CfgFromConfigAttribute.qunit.js +4 -3
  528. package/test/sap/ui/core/qunit/bootstrap/CfgFromGlobalObject.qunit.js +4 -3
  529. package/test/sap/ui/core/qunit/bootstrap/CfgFromTagAttributes.qunit.js +4 -3
  530. package/test/sap/ui/core/qunit/bootstrap/Configuration.qunit.js +2 -198
  531. package/test/sap/ui/core/qunit/bootstrap/Configuration_language_via_URL.qunit.js +210 -0
  532. package/test/sap/ui/core/qunit/bootstrap/ThemeVersion.qunit.js +33 -30
  533. package/test/sap/ui/core/qunit/bootstrap/testsuite.bootstrap.qunit.js +6 -0
  534. package/test/sap/ui/core/qunit/component/Component.qunit.js +12 -0
  535. package/test/sap/ui/core/qunit/component/ComponentSupport.qunit.js +6 -5
  536. package/test/sap/ui/core/qunit/component/Component_dependencyLoading.qunit.js +15 -9
  537. package/test/sap/ui/core/qunit/component/Component_dependencyLoading_unavoidablySync.qunit.js +10 -6
  538. package/test/sap/ui/core/qunit/component/Customizing.qunit.js +8 -7
  539. package/test/sap/ui/core/qunit/component/Customizing_disabled.qunit.js +6 -5
  540. package/test/sap/ui/core/qunit/component/Customizing_legacyAPIs.qunit.js +8 -7
  541. package/test/sap/ui/core/qunit/component/Customizing_multi.qunit.js +7 -6
  542. package/test/sap/ui/core/qunit/component/Customizing_unavoidablySync.qunit.js +5 -4
  543. package/test/sap/ui/core/qunit/component/Metadata.qunit.js +3 -3
  544. package/test/sap/ui/core/qunit/component/Models.qunit.js +103 -44
  545. package/test/sap/ui/core/qunit/component/UIComponent.qunit.js +20 -4
  546. package/test/sap/ui/core/qunit/component/UIComponent_unavoidablySync.qunit.js +5 -4
  547. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/component1/manifest.json +2 -1
  548. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/component2/manifest.json +1 -0
  549. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/component3/manifest.json +2 -1
  550. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/component4/manifest.json +1 -0
  551. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/component5/manifest.json +1 -1
  552. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/component6/manifest.json +1 -0
  553. package/test/sap/ui/core/qunit/component/testdata/dependencyLoading/componentVariant/manifest.json +1 -0
  554. package/test/sap/ui/core/qunit/component/testdata/v2asyncRootView/manifest.json +1 -1
  555. package/test/sap/ui/core/qunit/component/testdata/v2inline/Component.js +1 -1
  556. package/test/sap/ui/core/qunit/composite/XMLComposite.qunit.js +5 -5
  557. package/test/sap/ui/core/qunit/internal/1RingModels.qunit.html +4 -5
  558. package/test/sap/ui/core/qunit/internal/1RingModels.qunit.js +1 -0
  559. package/test/sap/ui/core/qunit/internal/AnnotationParser.qunit.html +4 -4
  560. package/test/sap/ui/core/qunit/internal/testsuite.models.qunit.js +19 -9
  561. package/test/sap/ui/core/qunit/jquery.sap.global-config.qunit.js +2 -4
  562. package/test/sap/ui/core/qunit/jquery.sap.ui.qunit.js +5 -4
  563. package/test/sap/ui/core/qunit/json/JSONModel.qunit.js +5 -9
  564. package/test/sap/ui/core/qunit/messages/Messaging.qunit.js +10 -5
  565. package/test/sap/ui/core/qunit/messages/messagesGeneral.qunit.js +6 -0
  566. package/test/sap/ui/core/qunit/messages/messagesGeneral_legacyAPIs.qunit.js +158 -0
  567. package/test/sap/ui/core/qunit/messages/messagesUsage.qunit.js +5 -4
  568. package/test/sap/ui/core/qunit/messages/testsuite.messaging.base.qunit.js +7 -0
  569. package/test/sap/ui/core/qunit/model/ClientPropertyBinding.qunit.js +47 -0
  570. package/test/sap/ui/core/qunit/mvc/AsyncXMLView.qunit.js +5 -3
  571. package/test/sap/ui/core/qunit/mvc/Controller.qunit.js +3 -3
  572. package/test/sap/ui/core/qunit/mvc/View.qunit.js +5 -1
  573. package/test/sap/ui/core/qunit/mvc/XMLView.qunit.js +6 -5
  574. package/test/sap/ui/core/qunit/mvc/testdata/TypedViewWithRendererRenderer.js +2 -2
  575. package/test/sap/ui/core/qunit/mvc/testdata/stashed/manifest.json +2 -1
  576. package/test/sap/ui/core/qunit/mvc/viewprocessing/ViewProcessing.qunit.js +4 -3
  577. package/test/sap/ui/core/qunit/mvc/viewprocessing/ViewProcessing_legacyAPIs.qunit.js +4 -3
  578. package/test/sap/ui/core/qunit/mvc_legacyAPIs/AsyncXMLView_legacyAPIs.qunit.js +5 -3
  579. package/test/sap/ui/core/qunit/mvc_legacyAPIs/XMLView_legacyAPIs.qunit.js +6 -5
  580. package/test/sap/ui/core/qunit/odata/ODataMessageParserNoFakeService.qunit.js +11 -7
  581. package/test/sap/ui/core/qunit/odata/ODataMetaModel.qunit.js +35 -0
  582. package/test/sap/ui/core/qunit/odata/_AnnotationHelperBasics.qunit.js +10 -4
  583. package/test/sap/ui/core/qunit/odata/data/ODataModelFakeService.js +1 -1
  584. package/test/sap/ui/core/qunit/odata/type/DateTimeBase.qunit.js +5 -0
  585. package/test/sap/ui/core/qunit/odata/type/ODataType.qunit.js +9 -0
  586. package/test/sap/ui/core/qunit/odata/v2/Context.qunit.js +12 -0
  587. package/test/sap/ui/core/qunit/odata/v2/ODataListBindingNoFakeService.qunit.js +422 -9
  588. package/test/sap/ui/core/qunit/odata/v2/ODataModel.integration.qunit.js +483 -33
  589. package/test/sap/ui/core/qunit/odata/v2/ODataModelNoFakeService.qunit.js +121 -2
  590. package/test/sap/ui/core/qunit/odata/v4/Context.qunit.js +95 -8
  591. package/test/sap/ui/core/qunit/odata/v4/ODataBinding.qunit.js +59 -13
  592. package/test/sap/ui/core/qunit/odata/v4/ODataContextBinding.qunit.js +355 -75
  593. package/test/sap/ui/core/qunit/odata/v4/ODataListBinding.qunit.js +152 -19
  594. package/test/sap/ui/core/qunit/odata/v4/ODataModel.integration.qunit.js +1253 -130
  595. package/test/sap/ui/core/qunit/odata/v4/ODataParentBinding.qunit.js +19 -9
  596. package/test/sap/ui/core/qunit/odata/v4/ODataPropertyBinding.qunit.js +6 -27
  597. package/test/sap/ui/core/qunit/odata/v4/data/metadata.json +3 -1
  598. package/test/sap/ui/core/qunit/odata/v4/data/metadata.xml +2 -2
  599. package/test/sap/ui/core/qunit/odata/v4/lib/_AggregationCache.qunit.js +172 -17
  600. package/test/sap/ui/core/qunit/odata/v4/lib/_AggregationHelper.qunit.js +7 -8
  601. package/test/sap/ui/core/qunit/odata/v4/lib/_Cache.qunit.js +185 -84
  602. package/test/sap/ui/core/qunit/odata/v4/lib/_Helper.qunit.js +2 -22
  603. package/test/sap/ui/core/qunit/opa/OpaPlugin.qunit.js +6 -4
  604. package/test/sap/ui/core/qunit/opa/selectors/_Selector.js +3 -2
  605. package/test/sap/ui/core/qunit/opa/selectors/_TableRowItem.js +4 -3
  606. package/test/sap/ui/core/qunit/rule/app/deprecatedJSViewUsage.qunit.js +4 -0
  607. package/test/sap/ui/core/qunit/rule/app/globalApiUsage.qunit.js +4 -0
  608. package/test/sap/ui/core/qunit/rule/app/jquerySapUsage.qunit.js +4 -0
  609. package/test/sap/ui/core/qunit/rule/app/syncXHR.qunit.js +4 -0
  610. package/test/sap/ui/core/qunit/rule/app/syncXHRBootstrap.qunit.js +4 -0
  611. package/test/sap/ui/core/qunit/rule/app/syncXHRBootstrapDebug.qunit.js +4 -0
  612. package/test/sap/ui/core/qunit/rule/app/syncXHRBootstrapDebugBeforeBootstrap.js +4 -0
  613. package/test/sap/ui/core/qunit/rule/config/asynchronousXMLViews.qunit.js +4 -1
  614. package/test/sap/ui/core/qunit/rule/misc/silentEventBus.qunit.js +8 -7
  615. package/test/sap/ui/core/qunit/rule/model/modelSupport.qunit.js +11 -2
  616. package/test/sap/ui/core/qunit/rule/testsuite.rule.qunit.js +18 -0
  617. package/test/sap/ui/core/qunit/test/starter/find/main.js +11 -8
  618. package/test/sap/ui/core/qunit/testsuites/testsuite.databinding.qunit.js +6 -0
  619. package/test/sap/ui/core/qunit/testsuites/testsuite.foundation.enablement.qunit.js +7 -1
  620. package/test/sap/ui/core/qunit/testsuites/testsuite.theming.qunit.js +21 -2
  621. package/test/sap/ui/core/qunit/util/XMLPreprocessor.qunit.js +26 -4
  622. package/test/sap/ui/core/qunit/util/jQuery.sap.Version.qunit.js +5 -5
  623. package/test/sap/ui/core/qunit/util/reflection/JsControlTreeModifier.qunit.js +30 -13
  624. package/test/sap/ui/core/qunit/util/reflection/XmlTreeModifier.qunit.js +40 -16
  625. package/test/sap/ui/core/qunit/util/support/TechnicalInfo.qunit.js +11 -10
  626. package/test/sap/ui/core/qunit/xml/XMLPropertyBinding.qunit.js +69 -8
  627. package/test/sap/ui/core/relnotes/changes-1.118.json +1 -34
  628. package/test/sap/ui/core/relnotes/changes-1.119.json +217 -0
  629. package/test/sap/ui/core/resources/fastnav.js +3 -2
  630. package/test/sap/ui/core/samples/ResponsiveDemo.html +3 -3
  631. package/test/sap/ui/core/samples/components/commands/manifest.json +2 -2
  632. package/test/sap/ui/core/samples/components/sample/manifest.json +2 -1
  633. package/test/sap/ui/core/samples/databinding/DatabindingMessages.html +1 -1
  634. package/test/sap/ui/core/samples/databinding/ODatabindingMessages.html +3 -3
  635. package/test/sap/ui/core/samples/databinding/UnitTable.view.xml +9 -2
  636. package/test/sap/ui/core/samples/formatting/manifest.json +2 -2
  637. package/test/sap/ui/core/samples/mvc/XMLViewAsync.html +62 -61
  638. package/test/sap/ui/core/samples/routing_legacyAPIs/AsyncViews.html +124 -123
  639. package/test/sap/ui/core/terminologies/App.controller.js +3 -2
  640. package/test/sap/ui/core/terminologies/App.view.xml +64 -64
  641. package/test/sap/ui/core/tmpl_legacyAPIs/TemplateSimple.html +38 -37
  642. package/test/sap/ui/core/util/PasteHelper.html +5 -4
  643. package/test/sap/ui/core/visual/images/ContextMenuSupport/windows/1600x1200/chrome/horizon/ltr/cozy/firstItem-contextMenu.ref.lnk +1 -1
  644. package/test/sap/ui/core/visual/images/ContextMenuSupport/windows/1600x1200/chrome/horizon/ltr/cozy/initial.ref.lnk +1 -1
  645. package/test/sap/ui/core/visual/images/ContextMenuSupport/windows/1600x1200/chrome/horizon/ltr/cozy/lastItem-contextMenu.ref.lnk +1 -1
  646. package/test/sap/ui/core/visual/images/ContextMenuSupport/windows/1600x1200/chrome/horizon/ltr/cozy/leftDownBtn-contextMenu.ref.lnk +1 -1
  647. package/test/sap/ui/core/visual/images/ContextMenuSupport/windows/1600x1200/chrome/horizon/ltr/cozy/myButtonSample-contextMenu.ref.lnk +1 -1
  648. package/test/sap/ui/core/visual/images/ContextMenuSupport/windows/1600x1200/chrome/horizon/ltr/cozy/rightDownBtn-contextMenu.ref.lnk +1 -1
  649. package/test/sap/ui/core/samples/databinding/DataBinding.html +0 -135
  650. package/test/sap/ui/core/samples/databinding/DataBindingCalculatedFields.html +0 -229
  651. package/test/sap/ui/core/samples/databinding/DataBindingCompositeTypes.html +0 -273
  652. package/test/sap/ui/core/samples/databinding/DataBindingFormat.html +0 -294
  653. package/test/sap/ui/core/samples/databinding/DataBindingList.html +0 -290
  654. package/test/sap/ui/core/samples/databinding/DataBindingListNamedModel.html +0 -290
  655. package/test/sap/ui/core/samples/databinding/DataBindingListXML.html +0 -280
  656. package/test/sap/ui/core/samples/databinding/DataBindingMasterDetail.html +0 -117
  657. package/test/sap/ui/core/samples/databinding/DataBindingMultiModel.html +0 -154
  658. package/test/sap/ui/core/samples/databinding/DataBindingResourceModel.html +0 -119
  659. package/test/sap/ui/core/samples/databinding/DataBindingSortingFiltering.html +0 -103
  660. package/test/sap/ui/core/samples/databinding/DataBindingTree.html +0 -166
  661. package/test/sap/ui/core/samples/databinding/DataBindingTreeFilter.html +0 -117
  662. package/test/sap/ui/core/samples/databinding/DataBindingTreeFilterXML.html +0 -103
  663. package/test/sap/ui/core/samples/databinding/DataBindingTreeLarge.html +0 -128
  664. package/test/sap/ui/core/samples/databinding/DataBindingTreeWithArrays.html +0 -132
  665. package/test/sap/ui/core/samples/databinding/DataBindingTwoWay.html +0 -158
  666. package/test/sap/ui/core/samples/databinding/DataBindingTwoWayTable.html +0 -141
  667. package/test/sap/ui/core/samples/databinding/DataBindingTypes.html +0 -265
  668. package/test/sap/ui/core/samples/databinding/DataBindingValidation.html +0 -195
  669. package/test/sap/ui/core/samples/databinding/DataBindingXML.html +0 -148
  670. package/test/sap/ui/core/samples/databinding/DataBindingXMLView.html +0 -53
  671. package/test/sap/ui/core/samples/databinding/testdata/ListBinding.view.xml +0 -9
  672. package/test/sap/ui/core/samples/databinding/testdata/test.view.json +0 -15
  673. package/test/sap/ui/core/samples/databinding/testdata/test.view.xml +0 -8
@@ -81,6 +81,110 @@ sap.ui.define([
81
81
  });
82
82
  }
83
83
 
84
+ /**
85
+ * Checks that the given list binding's _AggregationCache has a consistent state.
86
+ *
87
+ * @param {string} sTitle - A test title
88
+ * @param {object} assert - The QUnit assert object
89
+ * @param {sap.ui.model.odata.v4.ODataListBinding} oListBinding - A list binding
90
+ */
91
+ function checkAggregationCache(sTitle, assert, oListBinding) {
92
+ const aParentByLevel = [];
93
+
94
+ function checkCache(oCache) {
95
+ for (let i = 0, n = oCache.aElements.$created; i < n; i += 1) {
96
+ const oElement = oCache.aElements[i];
97
+ if (oElement) {
98
+ strictEqual("@$ui5.context.isTransient" in oElement, true, `created: ${i}`);
99
+ }
100
+ }
101
+ for (let i = oCache.aElements.$created, n = oCache.aElements.length; i < n; i += 1) {
102
+ const oElement = oCache.aElements[i];
103
+ if (oElement) {
104
+ strictEqual("@$ui5.context.isTransient" in oElement, false,
105
+ `not created: ${i}`);
106
+ }
107
+ }
108
+ strictEqual(oCache.aElements.$count === oCache.iLimit + oCache.iActiveElements, true,
109
+ `${oCache.aElements.$count} === ${oCache.iLimit} + ${oCache.iActiveElements}`);
110
+ }
111
+
112
+ function isKeepAlive(sPredicate) {
113
+ return oListBinding.getAllCurrentContexts()
114
+ .filter((oContext) => oContext.isEffectivelyKeptAlive())
115
+ .some((oContext) => oContext.getPath().endsWith(sPredicate));
116
+ }
117
+
118
+ function strictEqual(vActual, vExpected, sMyTitle) {
119
+ if (vActual !== vExpected) {
120
+ assert.strictEqual(vActual, vExpected, sMyTitle);
121
+ } // else: do not spam the output ;-)
122
+ }
123
+
124
+ function visitElements(aElements, bSkipByPredicate = false, iLevelOffset = 0) {
125
+ aElements.forEach((oElement) => {
126
+ const iIndex = _Helper.getPrivateAnnotation(oElement, "index");
127
+ // Note: "@$ui5.node.level" is outdated after #move!
128
+ const iLevel = oElement["@$ui5.node.level"] + iLevelOffset;
129
+ const oParent = aParentByLevel[iLevel];
130
+ const bPlaceholder = _Helper.hasPrivateAnnotation(oElement, "placeholder");
131
+
132
+ if (oParent) {
133
+ strictEqual(_Helper.getPrivateAnnotation(oElement, "parent"), oParent,
134
+ `${sTitle}: "parent" @ level ${iLevel}, index ${iIndex}`);
135
+ strictEqual(oParent.aElements.indexOf(oElement),
136
+ bPlaceholder
137
+ ? -1
138
+ : iIndex,
139
+ `${sTitle}: "index" @ level ${iLevel}, index ${iIndex}`);
140
+ } else {
141
+ assert.ok(false, `${sTitle}: no known parent for level ${iLevel}`);
142
+ }
143
+
144
+ if (!bPlaceholder && !bSkipByPredicate) {
145
+ const checkByPredicate = function (sKey) {
146
+ const sPredicate = _Helper.getPrivateAnnotation(oElement, sKey);
147
+ if (sPredicate === undefined) {
148
+ return;
149
+ }
150
+ strictEqual(oListBinding.oCache.aElements.$byPredicate[sPredicate],
151
+ oElement, `${sTitle}: ${sPredicate} in $byPredicate`);
152
+ };
153
+
154
+ checkByPredicate("predicate");
155
+ checkByPredicate("transientPredicate");
156
+ }
157
+
158
+ const oCache = _Helper.getPrivateAnnotation(oElement, "cache");
159
+ if (oCache) {
160
+ checkCache(oCache);
161
+ aParentByLevel[iLevel + 1] = oCache;
162
+ }
163
+
164
+ const aSpliced = _Helper.getPrivateAnnotation(oElement, "spliced");
165
+ if (aSpliced) {
166
+ visitElements(aSpliced, true, iLevel + 1 - aSpliced[0]["@$ui5.node.level"]);
167
+ }
168
+ });
169
+ }
170
+
171
+ const aElements = oListBinding.oCache.aElements;
172
+ strictEqual(aElements.length, aElements.$count, `${sTitle}: $count`);
173
+ for (const sPredicate in aElements.$byPredicate) {
174
+ const oElement = aElements.$byPredicate[sPredicate];
175
+ strictEqual(oElement["@$ui5.context.isDeleted"] || aElements.includes(oElement)
176
+ || isKeepAlive(sPredicate),
177
+ true, `${sTitle}: $byPredicate[${sPredicate}] in aElements`);
178
+ }
179
+
180
+ for (let i = 0, n = oListBinding.getAggregation().expandTo || 1; i <= n; i += 1) {
181
+ // Note: level 0 or 1 is used for initial placeholders of 1st level cache!
182
+ aParentByLevel[i] = oListBinding.oCache.oFirstLevel;
183
+ }
184
+ checkCache(oListBinding.oCache.oFirstLevel);
185
+ visitElements(aElements);
186
+ }
187
+
84
188
  /**
85
189
  * Checks that the given promise is rejected with a cancellation error.
86
190
  *
@@ -125,6 +229,10 @@ sap.ui.define([
125
229
  return oCell.getText ? oCell.getText() : oCell.getValue();
126
230
  });
127
231
  }), aExpectedContent, sTitle);
232
+
233
+ if (oListBinding.getAggregation() && oListBinding.getAggregation().hierarchyQualifier) {
234
+ checkAggregationCache(sTitle, assert, oListBinding);
235
+ }
128
236
  }
129
237
 
130
238
  /**
@@ -367,7 +475,7 @@ sap.ui.define([
367
475
 
368
476
  oDocument = XMLHelper.parse(
369
477
  '<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" xmlns:plugins="sap.m.plugins"'
370
- + ' xmlns:t="sap.ui.table"'
478
+ + ' xmlns:t="sap.ui.table" xmlns:trm="sap.ui.table.rowmodes"'
371
479
  + ' xmlns:template="http://schemas.sap.com/sapui5/extension/sap.ui.core.template/1">'
372
480
  + sViewXML
373
481
  + "</mvc:View>",
@@ -391,17 +499,28 @@ sap.ui.define([
391
499
  * @param {Document} oDocument The view as XML document
392
500
  */
393
501
  function xmlConvertGridTables(oDocument) {
394
- var oChildNode, aChildNodes, oColumn, oElement, i, j, aTableElements, oTemplate;
502
+ var oChildNode, aChildNodes, oColumn, oElement, i, j, aTableElements, oTemplate,
503
+ oRowMode, oFixedRowMode;
395
504
 
396
505
  aTableElements = oDocument.getElementsByTagNameNS("sap.ui.table", "Table");
397
506
  for (i = aTableElements.length - 1; i >= 0; i -= 1) {
398
507
  oElement = aTableElements[i];
399
508
 
509
+ if (oElement.hasAttribute("visibleRowCount")) {
510
+ oRowMode = document.createElementNS("sap.ui.table", "rowMode");
511
+ oElement.appendChild(oRowMode);
512
+ oFixedRowMode = document.createElementNS("sap.ui.table.rowmodes", "Fixed");
513
+ oFixedRowMode.setAttribute("rowCount", oElement.getAttribute("visibleRowCount"));
514
+ oRowMode.appendChild(oFixedRowMode);
515
+ oElement.removeAttribute("visibleRowCount");
516
+ }
517
+
400
518
  aChildNodes = oElement.childNodes;
401
519
  for (j = aChildNodes.length - 1; j >= 0; j -= 1) {
402
520
  oChildNode = aChildNodes[j];
403
521
  if (oChildNode.nodeType === Node.ELEMENT_NODE
404
- && oChildNode.localName !== "Column") {
522
+ && oChildNode.localName !== "Column"
523
+ && oChildNode.localName !== "rowMode") {
405
524
  oColumn = document.createElementNS("sap.ui.table", "Column");
406
525
  oElement.insertBefore(oColumn, oChildNode);
407
526
  oElement.removeChild(oChildNode);
@@ -532,7 +651,7 @@ sap.ui.define([
532
651
  // A list of expected requests with the properties method, url, headers, response
533
652
  this.aRequests = [];
534
653
 
535
- // If the "VisibleRowCountMode" of the sap.ui.table.* is "Auto", the table uses the
654
+ // If the "rowMode" of the sap.ui.table.* is "Auto", the table uses the
536
655
  // screen height (Device.resize.height) to compute the amount of contexts it requests
537
656
  // initially. Make sure that this is stable across devices.
538
657
  this._oSandbox.stub(Device.resize, "height").value(1000);
@@ -3257,6 +3376,65 @@ sap.ui.define([
3257
3376
  });
3258
3377
  });
3259
3378
 
3379
+ //*********************************************************************************************
3380
+ // Scenario: An ODCB for a BusinessPartner w/o cache is bound to "/SalesOrderList('1')". The
3381
+ // CompanyName is fetched late via requestProperty. Then the ODCB is bound to
3382
+ // "/SalesOrderList('2')", and requestProperty for the CompanyName must lead to another late
3383
+ // property request.
3384
+ // BCP: 2380079072
3385
+ QUnit.test("BCP: 2380079072", async function (assert) {
3386
+ const oModel = this.createSalesOrdersModel({autoExpandSelect : true});
3387
+ const sView = `
3388
+ <FlexBox id="form" binding="{SO_2_BP}">
3389
+ <Text id="bp" text="{BusinessPartnerID}"/>
3390
+ </FlexBox>`;
3391
+
3392
+ this.expectChange("bp");
3393
+
3394
+ await this.createView(assert, sView, oModel);
3395
+
3396
+ this.expectRequest("SalesOrderList('1')/SO_2_BP?$select=BusinessPartnerID",
3397
+ {BusinessPartnerID : "3"})
3398
+ .expectChange("bp", "3");
3399
+
3400
+ const oForm = this.oView.byId("form");
3401
+ oForm.setBindingContext(oModel.createBindingContext("/SalesOrderList('1')"));
3402
+
3403
+ await this.waitForChanges(assert, "1st bind");
3404
+
3405
+ this.expectRequest("SalesOrderList('1')/SO_2_BP?$select=BusinessPartnerID,CompanyName",
3406
+ {BusinessPartnerID : "3", CompanyName : "SAP"});
3407
+
3408
+ const oInnerBinding = oForm.getObjectBinding();
3409
+ const [sCompanyName1] = await Promise.all([
3410
+ oInnerBinding.getBoundContext().requestProperty("CompanyName"),
3411
+ this.waitForChanges(assert, "1st requestProperty")
3412
+ ]);
3413
+
3414
+ assert.strictEqual(sCompanyName1, "SAP");
3415
+
3416
+ this.expectRequest("SalesOrderList('2')?$select=SalesOrderID"
3417
+ + "&$expand=SO_2_BP($select=BusinessPartnerID)", {
3418
+ SalesOrderID : "2",
3419
+ SO_2_BP : {BusinessPartnerID : "4"}
3420
+ })
3421
+ .expectChange("bp", "4");
3422
+
3423
+ oForm.setBindingContext(oModel.bindContext("/SalesOrderList('2')").getBoundContext());
3424
+
3425
+ await this.waitForChanges(assert, "2nd bind");
3426
+
3427
+ this.expectRequest("SalesOrderList('2')/SO_2_BP?$select=BusinessPartnerID,CompanyName",
3428
+ {BusinessPartnerID : "4", CompanyName : "TECUM"});
3429
+
3430
+ const [sCompanyName2] = await Promise.all([
3431
+ oInnerBinding.getBoundContext().requestProperty("CompanyName"),
3432
+ this.waitForChanges(assert, "2nd requestProperty")
3433
+ ]);
3434
+
3435
+ assert.strictEqual(sCompanyName2, "TECUM");
3436
+ });
3437
+
3260
3438
  //*********************************************************************************************
3261
3439
  // Scenario: Return value context with data in cache, multiple context bindings w/o cache below,
3262
3440
  // multiple property bindings below these context bindings requesting their value late. One
@@ -8846,7 +9024,7 @@ sap.ui.define([
8846
9024
  } else if (i === 1) {
8847
9025
  that.oModel.resetChanges();
8848
9026
  } else if (i === 2) {
8849
- var oHeaderContext = oCreatedContext.getBinding().getHeaderContext();
9027
+ const oHeaderContext = oCreatedContext.getBinding().getHeaderContext();
8850
9028
 
8851
9029
  assert.throws(function () {
8852
9030
  // code under test (JIRA: CPOUI5ODATAV4-2014)
@@ -12550,6 +12728,16 @@ sap.ui.define([
12550
12728
  });
12551
12729
  });
12552
12730
 
12731
+ //*********************************************************************************************
12732
+ // Scenario: Enter an invalid value for worker-age for an ODataPropertyBinding and check that
12733
+ // parent Context.resetChanges() restores the value before.
12734
+ //*********************************************************************************************
12735
+ QUnit.test("reset invalid data state via context", function (assert) {
12736
+ return this.checkResetInvalidDataState(assert, function (oView) {
12737
+ return oView.byId("form").getBindingContext();
12738
+ });
12739
+ });
12740
+
12553
12741
  //*********************************************************************************************
12554
12742
  // Scenario: Enter an invalid value for worker-age for an ODataPropertyBinding and check that
12555
12743
  // ODataModel.resetChanges() restores the value before.
@@ -13214,7 +13402,11 @@ sap.ui.define([
13214
13402
  });
13215
13403
 
13216
13404
  //*********************************************************************************************
13217
- // Scenario: Call bound action on a context of a relative ListBinding
13405
+ // Scenario: Call bound action on a context of a relative ListBinding.
13406
+ //
13407
+ // Ensure that a Return Value Context is created and the structure of the path is same like the
13408
+ // binding parameter
13409
+ // JIRA: CPOUI5ODATAV4-2096
13218
13410
  QUnit.test("Read entity for a relative ListBinding, call bound action", function (assert) {
13219
13411
  var oModel = this.createTeaBusiModel(),
13220
13412
  that = this,
@@ -13240,15 +13432,24 @@ sap.ui.define([
13240
13432
  that.expectRequest({
13241
13433
  method : "POST",
13242
13434
  url : "TEAMS('42')/TEAM_2_EMPLOYEES('2')/"
13243
- + "com.sap.gateway.default.iwbep.tea_busi.v0001.AcChangeTeamOfEmployee",
13435
+ + "com.sap.gateway.default.iwbep.tea_busi.v0001.AcChangeTeamOfEmployee"
13436
+ + "?$expand=EMPLOYEE_2_TEAM($select=Team_Id)",
13244
13437
  payload : {TeamID : "TEAM_02"}
13245
- }, {ID : "2"});
13438
+ }, {
13439
+ EMPLOYEE_2_TEAM : {
13440
+ Team_Id : "TEAM_02"
13441
+ },
13442
+ ID : "2"
13443
+ });
13246
13444
  oAction.setParameter("TeamID", "TEAM_02");
13247
13445
 
13248
13446
  return Promise.all([
13249
13447
  // code under test
13250
- oAction.execute(),
13251
- // Note: no R.V.C. because path "/TEAMS('42')/TEAM_2_EMPLOYEES('2')" too long
13448
+ oAction.execute().then(function (oReturnValueContext) {
13449
+ assert.strictEqual(
13450
+ oReturnValueContext.getPath(),
13451
+ "/TEAMS('TEAM_02')/TEAM_2_EMPLOYEES('2')");
13452
+ }),
13252
13453
  that.waitForChanges(assert)
13253
13454
  ]);
13254
13455
  });
@@ -15105,16 +15306,16 @@ sap.ui.define([
15105
15306
  });
15106
15307
 
15107
15308
  //*********************************************************************************************
15108
- // Scenario: sap.ui.table.Table with VisibleRowCountMode="Auto" only calls ODLB.getContexts()
15309
+ // Scenario: sap.ui.table.Table with rowMode="Auto" only calls ODLB.getContexts()
15109
15310
  // after rendering (via setTimeout). This must not lead to separate requests for each table
15110
15311
  // cell resp. console errors due to data access via virtual context.
15111
15312
  // BCP 1770367083
15112
15313
  // Also tests that key properties are $select'ed for a sap.ui.table.Table with query options
15113
15314
  // different from $expand and $select in the binding parameters of the rows aggregation.
15114
- QUnit.test("sap.ui.table.Table with VisibleRowCountMode='Auto'", function (assert) {
15315
+ QUnit.test("sap.ui.table.Table with rowMode='Auto'", function (assert) {
15115
15316
  var sView = '\
15116
15317
  <t:Table id="table" rows="{path : \'/EMPLOYEES\', parameters : {$filter : \'AGE gt 42\'}}"\
15117
- visibleRowCountMode="Auto">\
15318
+ rowMode="Auto">\
15118
15319
  <t:Column>\
15119
15320
  <t:label>\
15120
15321
  <Label text="Name"/>\
@@ -20606,7 +20807,7 @@ sap.ui.define([
20606
20807
  });
20607
20808
 
20608
20809
  //*********************************************************************************************
20609
- // Scenario: sap.ui.table.Table with VisibleRowCountMode="Auto" and submit group 'API'
20810
+ // Scenario: sap.ui.table.Table with rowMode="Auto" and submit group 'API'
20610
20811
  // In the first step resume and immediately call submitBatch.
20611
20812
  // In the second step synchronously refresh with another group ID, change the filter and call
20612
20813
  // submitBatch. Check that the filter request is sent with this batch nevertheless.
@@ -20626,7 +20827,7 @@ sap.ui.define([
20626
20827
  var oListBinding,
20627
20828
  oModel = this.createTeaBusiModel({autoExpandSelect : true}),
20628
20829
  sView = '\
20629
- <t:Table id="table" visibleRowCountMode="Auto"\
20830
+ <t:Table id="table" rowMode="Auto"\
20630
20831
  rows="{path : \'/Equipments\', parameters : {$$groupId : \'api\'}, suspended : true}">\
20631
20832
  <t:Column>\
20632
20833
  <t:label>\
@@ -22006,8 +22207,7 @@ sap.ui.define([
22006
22207
  QUnit.test(sTitle, function (assert) {
22007
22208
  var oModel = this.createAggregationModel(),
22008
22209
  sView = '\
22009
- <t:Table fixedBottomRowCount="1" fixedRowCount="' + (bGrandTotalAtBottomOnly ? 0 : 1) + '"\
22010
- id="table" rows="{path : \'/BusinessPartners\', parameters : {\
22210
+ <t:Table id="table" rows="{path : \'/BusinessPartners\', parameters : {\
22011
22211
  $$aggregation : {\
22012
22212
  aggregate : {\
22013
22213
  SalesNumber : {grandTotal : true}\
@@ -22015,7 +22215,12 @@ sap.ui.define([
22015
22215
  grandTotalAtBottomOnly : ' + bGrandTotalAtBottomOnly + ',\
22016
22216
  group : {Country : {}}\
22017
22217
  }\
22018
- }}" threshold="0" visibleRowCount="' + (bGrandTotalAtBottomOnly ? 4 : 5) + '">\
22218
+ }}" threshold="0">\
22219
+ <t:rowMode>\
22220
+ <trm:Fixed rowCount="' + (bGrandTotalAtBottomOnly ? 4 : 5) + '"\
22221
+ fixedTopRowCount="' + (bGrandTotalAtBottomOnly ? 0 : 1) + '"\
22222
+ fixedBottomRowCount="1"/>\
22223
+ </t:rowMode>\
22019
22224
  <Text id="isExpanded" text="{= %{@$ui5.node.isExpanded} }"/>\
22020
22225
  <Text id="isTotal" text="{= %{@$ui5.node.isTotal} }"/>\
22021
22226
  <Text id="level" text="{= %{@$ui5.node.level} }"/>\
@@ -22431,7 +22636,7 @@ sap.ui.define([
22431
22636
  QUnit.test("Data Aggregation: grandTotalAtBottomOnly=true, just two rows", function (assert) {
22432
22637
  var oModel = this.createAggregationModel(),
22433
22638
  sView = '\
22434
- <t:Table fixedBottomRowCount="1" id="table" rows="{path : \'/BusinessPartners\', parameters : {\
22639
+ <t:Table id="table" rows="{path : \'/BusinessPartners\', parameters : {\
22435
22640
  $$aggregation : {\
22436
22641
  aggregate : {\
22437
22642
  SalesNumber : {grandTotal : true}\
@@ -22440,7 +22645,10 @@ sap.ui.define([
22440
22645
  groupLevels : [\'Country\',\'Region\'],\
22441
22646
  subtotalsAtBottomOnly : false\
22442
22647
  }\
22443
- }}" visibleRowCount="2">\
22648
+ }}">\
22649
+ <t:rowMode>\
22650
+ <trm:Fixed rowCount="2" fixedBottomRowCount="1"/>\
22651
+ </t:rowMode>\
22444
22652
  <Text id="isExpanded" text="{= %{@$ui5.node.isExpanded} }"/>\
22445
22653
  <Text id="isTotal" text="{= %{@$ui5.node.isTotal} }"/>\
22446
22654
  <Text id="level" text="{= %{@$ui5.node.level} }"/>\
@@ -23422,7 +23630,7 @@ sap.ui.define([
23422
23630
  oTable,
23423
23631
  sView = '\
23424
23632
  <Text id="count" text="{$count}"/>\
23425
- <t:Table fixedRowCount="1" firstVisibleRow="1" id="table" rows="{\
23633
+ <t:Table firstVisibleRow="1" id="table" rows="{\
23426
23634
  path : \'/BusinessPartners\',\
23427
23635
  parameters : {\
23428
23636
  $$aggregation : {\
@@ -23438,7 +23646,10 @@ sap.ui.define([
23438
23646
  $orderby : \'Region desc\'\
23439
23647
  },\
23440
23648
  filters : {path : \'AmountPerSale\', operator : \'GT\', value1 : 99}}"\
23441
- threshold="0" visibleRowCount="5">\
23649
+ threshold="0">\
23650
+ <t:rowMode>\
23651
+ <trm:Fixed rowCount="5" fixedTopRowCount="1"/>\
23652
+ </t:rowMode>\
23442
23653
  <Text id="country" text="{Country}"/>\
23443
23654
  <Text id="region" text="{Region}"/>\
23444
23655
  <Text id="salesNumber" text="{SalesNumber}"/>\
@@ -23526,7 +23737,7 @@ sap.ui.define([
23526
23737
  ],
23527
23738
  sView = '\
23528
23739
  <Text id="count" text="{$count}"/>\
23529
- <t:Table fixedRowCount="0" firstVisibleRow="1" id="table" rows="{\
23740
+ <t:Table firstVisibleRow="1" id="table" rows="{\
23530
23741
  path : \'/BusinessPartners\',\
23531
23742
  parameters : {\
23532
23743
  $$aggregation : {\
@@ -24596,6 +24807,10 @@ sap.ui.define([
24596
24807
  // The whole tree is expanded to two levels (JIRA: CPOUI5ODATAV4-2095).
24597
24808
  // Selection keeps a context implicitly alive (JIRA: CPOUI5ODATAV4-2053).
24598
24809
  // Ensure that unchanged $$aggregation is ignored (BCP: 2370045709).
24810
+ //
24811
+ // Retrieve "DrillState" property path via verbose ODLB#getAggregation & include it in the
24812
+ // downloadUrl
24813
+ // JIRA: CPOUI5ODATAV4-2275
24599
24814
  [false, true].forEach(function (bKeepAlive) {
24600
24815
  var sTitle = "Recursive Hierarchy: root is leaf; bKeepAlive=" + bKeepAlive;
24601
24816
 
@@ -24604,7 +24819,7 @@ sap.ui.define([
24604
24819
  = "/special/cases/Artists?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
24605
24820
  + "HierarchyNodes=$root/Artists,HierarchyQualifier='OrgChart'"
24606
24821
  + ",NodeProperty='_/NodeID',Levels=999)"
24607
- + "&$select=ArtistID,IsActiveEntity,_/DistanceFromRoot,_/NodeID"
24822
+ + "&$select=ArtistID,IsActiveEntity,_/DistanceFromRoot,_/DrillState,_/NodeID"
24608
24823
  + "&$expand=BestFriend($select=ArtistID,IsActiveEntity,Name)",
24609
24824
  oHeaderContext,
24610
24825
  oKeptAliveNode,
@@ -24674,11 +24889,12 @@ sap.ui.define([
24674
24889
  assert.deepEqual(oListBinding.getAggregation(/*bVerbose*/true), {
24675
24890
  hierarchyQualifier : "OrgChart",
24676
24891
  $DistanceFromRootProperty : "_/DistanceFromRoot",
24892
+ $DrillStateProperty : "_/DrillState",
24677
24893
  $NodeProperty : "_/NodeID"
24678
- }, "JIRA: CPOUI5ODATAV4-1961");
24894
+ }, "JIRA: CPOUI5ODATAV4-1961, CPOUI5ODATAV4-2275");
24679
24895
  // code under test
24680
24896
  assert.strictEqual(oListBinding.getDownloadUrl(), sExpectedDownloadUrl,
24681
- "JIRA: CPOUI5ODATAV4-1920");
24897
+ "JIRA: CPOUI5ODATAV4-1920, CPOUI5ODATAV4-2275");
24682
24898
 
24683
24899
  checkTable("root is leaf", assert, oTable, [
24684
24900
  "/Artists(ArtistID='0',IsActiveEntity=true)"
@@ -24740,7 +24956,8 @@ sap.ui.define([
24740
24956
  ]);
24741
24957
  }).then(function (aResults) {
24742
24958
  assert.strictEqual(aResults[0], "60");
24743
- assert.strictEqual(aResults[1], sExpectedDownloadUrl, "JIRA: CPOUI5ODATAV4-1920");
24959
+ assert.strictEqual(aResults[1], sExpectedDownloadUrl,
24960
+ "JIRA: CPOUI5ODATAV4-1920, CPOUI5ODATAV4-2275");
24744
24961
 
24745
24962
  that.expectRequest("Artists"
24746
24963
  + "?$select=ArtistID,IsActiveEntity,Messages,_/NodeID,defaultChannel"
@@ -25395,6 +25612,10 @@ sap.ui.define([
25395
25612
  //
25396
25613
  // Use relative ODLB with an initially suspended parent (JIRA: CPOUI5ODATAV4-1985 etc.)
25397
25614
  // Additionally, ODLB#getDownloadUrl is tested (JIRA: CPOUI5ODATAV4-1920. BCP: 2370011296).
25615
+ //
25616
+ // Ensure that a Return Value Context is created and the structure of the path is same like the
25617
+ // binding parameter
25618
+ // JIRA: CPOUI5ODATAV4-2096
25398
25619
  QUnit.test("Recursive Hierarchy: edit w/ currency", function (assert) {
25399
25620
  var sAction = "com.sap.gateway.default.iwbep.tea_busi.v0001.AcChangeTeamOfEmployee",
25400
25621
  oChild,
@@ -25469,9 +25690,9 @@ sap.ui.define([
25469
25690
  + "?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
25470
25691
  + "HierarchyNodes=$root/TEAMS('42')/TEAM_2_EMPLOYEES"
25471
25692
  + ",HierarchyQualifier='OrgChart',NodeProperty='ID',Levels=999)"
25472
- + "&$select=DistanceFromRoot,ID,MANAGER_ID,SALARY/BONUS_CURR"
25693
+ + "&$select=DistanceFromRoot,DrillState,ID,MANAGER_ID,SALARY/BONUS_CURR"
25473
25694
  + ",SALARY/YEARLY_BONUS_AMOUNT,TEAM_ID",
25474
- "JIRA: CPOUI5ODATAV4-1920");
25695
+ "JIRA: CPOUI5ODATAV4-1920, CPOUI5ODATAV4-2275");
25475
25696
 
25476
25697
  that.expectRequest("TEAMS('42')/TEAM_2_EMPLOYEES"
25477
25698
  + "?$apply=descendants($root/TEAMS('42')/TEAM_2_EMPLOYEES,OrgChart,ID"
@@ -25551,45 +25772,59 @@ sap.ui.define([
25551
25772
 
25552
25773
  that.expectRequest({
25553
25774
  method : "POST",
25554
- url : "TEAMS('42')/TEAM_2_EMPLOYEES('0')/" + sAction,
25555
- payload : {TeamID : "23"}
25775
+ url : "TEAMS('42')/TEAM_2_EMPLOYEES('0')/" + sAction
25776
+ + "?$expand=EMPLOYEE_2_TEAM($select=Team_Id)",
25777
+ payload : {TeamID : "TEAM_23"}
25556
25778
  }, {
25779
+ EMPLOYEE_2_TEAM : {
25780
+ Team_Id : "23"
25781
+ },
25557
25782
  ID : "0",
25558
25783
  MANAGER_ID : null,
25559
25784
  SALARY : { // "side effect"
25560
25785
  BONUS_CURR : "GBP",
25561
25786
  YEARLY_BONUS_AMOUNT : "23.23"
25562
25787
  },
25563
- TEAM_ID : "TEAM_23" // "side effect"
25788
+ TEAM_ID : "23" // "side effect"
25564
25789
  })
25565
25790
  .expectRequest({
25566
25791
  method : "POST",
25567
- url : "TEAMS('42')/TEAM_2_EMPLOYEES('1')/" + sAction,
25568
- payload : {TeamID : "42"}
25792
+ url : "TEAMS('42')/TEAM_2_EMPLOYEES('1')/" + sAction
25793
+ + "?$expand=EMPLOYEE_2_TEAM($select=Team_Id)",
25794
+ payload : {TeamID : "TEAM_42"}
25569
25795
  }, {
25796
+ EMPLOYEE_2_TEAM : {
25797
+ Team_Id : "42"
25798
+ },
25570
25799
  ID : "1",
25571
25800
  MANAGER_ID : "0",
25572
25801
  SALARY : { // "side effect"
25573
25802
  BONUS_CURR : "USD",
25574
25803
  YEARLY_BONUS_AMOUNT : "42.42"
25575
25804
  },
25576
- TEAM_ID : "TEAM_42" // "side effect"
25805
+ TEAM_ID : "42" // "side effect"
25577
25806
  });
25578
25807
 
25579
25808
  return Promise.all([
25580
25809
  oModel.bindContext(sAction + "(...)", oRoot)
25581
- .setParameter("TeamID", "23")
25810
+ .setParameter("TeamID", "TEAM_23")
25582
25811
  .execute()
25583
- .then(function (_oReturnValueContext) {
25584
- // Note: RVC has iGeneration === 2 instead of 0
25585
- //TODO assert.strictEqual(oReturnValueContext.getPath(), oRoot.getPath());
25812
+ .then(function (oReturnValueContext) {
25813
+ assert.strictEqual(oRoot.getPath(),
25814
+ "/TEAMS('42')/TEAM_2_EMPLOYEES('0')");
25815
+ assert.strictEqual(oReturnValueContext.getPath(),
25816
+ "/TEAMS('23')/TEAM_2_EMPLOYEES('0')");
25586
25817
  }),
25587
25818
  oModel.bindContext(sAction + "(...)", oChild)
25588
- .setParameter("TeamID", "42")
25819
+ .setParameter("TeamID", "TEAM_42")
25589
25820
  .execute()
25590
- .then(function (_oReturnValueContext) {
25821
+ .then(function (oReturnValueContext) {
25591
25822
  // Note: RVC has iGeneration === 2 instead of 0
25592
- //TODO assert.strictEqual(oReturnValueContext.getPath(), oChild.getPath());
25823
+ assert.notStrictEqual(oReturnValueContext, oChild);
25824
+ assert.strictEqual(oChild.getPath(),
25825
+ "/TEAMS('42')/TEAM_2_EMPLOYEES('1')");
25826
+ assert.strictEqual(oReturnValueContext.getPath(),
25827
+ "/TEAMS('42')/TEAM_2_EMPLOYEES('1')");
25593
25828
  }),
25594
25829
  that.waitForChanges(assert, "action")
25595
25830
  ]);
@@ -25598,8 +25833,8 @@ sap.ui.define([
25598
25833
  "/TEAMS('42')/TEAM_2_EMPLOYEES('0')",
25599
25834
  "/TEAMS('42')/TEAM_2_EMPLOYEES('1')"
25600
25835
  ], [
25601
- [true, 1, "0", "", "23.23", "GBP", "TEAM_23"],
25602
- [undefined, 2, "1", "0", "42.42", "USD", "TEAM_42"]
25836
+ [true, 1, "0", "", "23.23", "GBP", "23"],
25837
+ [undefined, 2, "1", "0", "42.42", "USD", "42"]
25603
25838
  ]);
25604
25839
  });
25605
25840
  });
@@ -25725,8 +25960,8 @@ sap.ui.define([
25725
25960
  + "?$apply=orderby(AGE%20desc)"
25726
25961
  + "/com.sap.vocabularies.Hierarchy.v1.TopLevels(HierarchyNodes=$root/EMPLOYEES"
25727
25962
  + ",HierarchyQualifier='OrgChart',NodeProperty='ID',Levels=999)"
25728
- + "&$select=AGE,DistanceFromRoot,ID,MANAGER_ID,Name",
25729
- "JIRA: CPOUI5ODATAV4-1920");
25963
+ + "&$select=AGE,DistanceFromRoot,DrillState,ID,MANAGER_ID,Name",
25964
+ "JIRA: CPOUI5ODATAV4-1920, CPOUI5ODATAV4-2275");
25730
25965
 
25731
25966
  that.expectChange("count", "24");
25732
25967
 
@@ -26203,8 +26438,8 @@ sap.ui.define([
26203
26438
  + "/orderby(AGE%20desc)"
26204
26439
  + "/com.sap.vocabularies.Hierarchy.v1.TopLevels(HierarchyNodes=$root/EMPLOYEES"
26205
26440
  + ",HierarchyQualifier='OrgChart',NodeProperty='ID',Levels=999)"
26206
- + "&$select=DistanceFromRoot,ID",
26207
- "JIRA: CPOUI5ODATAV4-1920");
26441
+ + "&$select=DistanceFromRoot,DrillState,ID",
26442
+ "JIRA: CPOUI5ODATAV4-1920, CPOUI5ODATAV4-2275");
26208
26443
 
26209
26444
  that.expectChange("count", "2");
26210
26445
 
@@ -26726,13 +26961,14 @@ sap.ui.define([
26726
26961
  }]
26727
26962
  });
26728
26963
 
26729
- // code under test
26730
- oXi.getBinding().getHeaderContext().requestSideEffects(["*"]);
26731
-
26732
26964
  // Note: side effect eventually destroys oBeta!
26733
26965
  oBeta = null;
26734
26966
 
26735
- return that.waitForChanges(assert, "request side effects");
26967
+ return Promise.all([
26968
+ // code under test
26969
+ oXi.getBinding().getHeaderContext().requestSideEffects(["*"]),
26970
+ that.waitForChanges(assert, "request side effects")
26971
+ ]);
26736
26972
  }).then(function () {
26737
26973
  checkTable("after request side effects", assert, oTable, [
26738
26974
  "/EMPLOYEES('2')",
@@ -27108,10 +27344,11 @@ sap.ui.define([
27108
27344
  }]
27109
27345
  });
27110
27346
 
27111
- // code under test
27112
- oAlpha.getBinding().getHeaderContext().requestSideEffects(["Name"]);
27113
-
27114
- return that.waitForChanges(assert, "request side effects");
27347
+ return Promise.all([
27348
+ // code under test
27349
+ oAlpha.getBinding().getHeaderContext().requestSideEffects(["Name"]),
27350
+ that.waitForChanges(assert, "request side effects")
27351
+ ]);
27115
27352
  }).then(function () {
27116
27353
  checkTable("after request side effects", assert, oTable, [
27117
27354
  "/EMPLOYEES('0')"
@@ -27314,10 +27551,11 @@ sap.ui.define([
27314
27551
  }]
27315
27552
  });
27316
27553
 
27317
- // code under test
27318
- oBeta.getBinding().getHeaderContext().requestSideEffects(["Name"]);
27319
-
27320
- return that.waitForChanges(assert, "request side effects");
27554
+ return Promise.all([
27555
+ // code under test
27556
+ oBeta.getBinding().getHeaderContext().requestSideEffects(["Name"]),
27557
+ that.waitForChanges(assert, "request side effects")
27558
+ ]);
27321
27559
  }).then(function () {
27322
27560
  checkTable("after request side effects", assert, oTable, [
27323
27561
  "/EMPLOYEES('0')",
@@ -28142,7 +28380,7 @@ sap.ui.define([
28142
28380
 
28143
28381
  //*********************************************************************************************
28144
28382
  // Scenario: Show the single root node of a recursive hierarchy, which happens to be a leaf.
28145
- // Create two new child nodes underneath.
28383
+ // Create two new child nodes ("Beta", "Gamma") underneath.
28146
28384
  // Note: The "_Friend" navigation property is misused in order to have an artist play the role
28147
28385
  // of a hierarchy directory. This way, a draft root object is available (as needed by real
28148
28386
  // services).
@@ -28150,9 +28388,14 @@ sap.ui.define([
28150
28388
  //
28151
28389
  // Create new child and cancel immediately (JIRA: CPOUI5ODATAV4-2272)
28152
28390
  // @odata.bind in POST relative to resource path (BCP: 2380119648)
28153
- // Delete the second child again. (JIRA: CPOUI5ODATAV4-2224)
28391
+ //
28392
+ // Move "Gamma" so that "Beta" becomes its parent, then move it back again. Collapse the root,
28393
+ // request a side effect for all rows, and expand the root again. Start a move, but cancel it.
28394
+ // Move "Beta" so that "Gamma" becomes its parent (no change to context's index, but a persisted
28395
+ // node (again) becomes "created persisted"). Observe property change events for "@odata.etag".
28396
+ // JIRA: CPOUI5ODATAV4-2226
28154
28397
  QUnit.test("Recursive Hierarchy: create new children", function (assert) {
28155
- var oChild, oListBinding, fnRespond, oRoot, oTable;
28398
+ var oBeta, oBetaCreated, oGamma, oGammaCreated, oListBinding, fnRespond, oRoot, oTable;
28156
28399
 
28157
28400
  const oModel = this.createSpecialCasesModel({autoExpandSelect : true});
28158
28401
  const sFriend = "/Artists(ArtistID='99',IsActiveEntity=false)/_Friend";
@@ -28163,22 +28406,22 @@ sap.ui.define([
28163
28406
  hierarchyQualifier : 'OrgChart'
28164
28407
  }
28165
28408
  }}" threshold="0" visibleRowCount="3">
28409
+ <Text text="{= %{@$ui5.context.isTransient} }"/>
28166
28410
  <Text text="{= %{@$ui5.node.isExpanded} }"/>
28167
28411
  <Text text="{= %{@$ui5.node.level} }"/>
28412
+ <Text id="etag" text="{= %{@odata.etag} }"/>
28168
28413
  <Text id="name" text="{Name}"/>
28169
28414
  </t:Table>`;
28170
28415
  const that = this;
28171
28416
 
28172
- this.expectRequest({
28173
- batchNo : 1,
28174
- url : sFriend.slice(1) + "?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
28175
- + "HierarchyNodes=$root" + sFriend
28176
- + ",HierarchyQualifier='OrgChart',NodeProperty='_/NodeID',Levels=1)"
28177
- + "&$select=ArtistID,IsActiveEntity,Name,_/DrillState,_/NodeID"
28178
- + "&$count=true&$skip=0&$top=3"
28179
- }, {
28417
+ this.expectRequest(sFriend.slice(1) + "?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
28418
+ + "HierarchyNodes=$root" + sFriend
28419
+ + ",HierarchyQualifier='OrgChart',NodeProperty='_/NodeID',Levels=1)"
28420
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DrillState,_/NodeID"
28421
+ + "&$count=true&$skip=0&$top=3", {
28180
28422
  "@odata.count" : "1",
28181
28423
  value : [{
28424
+ "@odata.etag" : "etag0.0",
28182
28425
  ArtistID : "0",
28183
28426
  IsActiveEntity : false,
28184
28427
  Name : "Alpha",
@@ -28190,6 +28433,7 @@ sap.ui.define([
28190
28433
  }
28191
28434
  }]
28192
28435
  })
28436
+ .expectChange("etag", ["etag0.0"])
28193
28437
  .expectChange("name", ["Alpha"]);
28194
28438
 
28195
28439
  return this.createView(assert, sView, oModel).then(function () {
@@ -28200,9 +28444,9 @@ sap.ui.define([
28200
28444
  checkTable("root is leaf", assert, oTable, [
28201
28445
  sFriend + "(ArtistID='0',IsActiveEntity=false)"
28202
28446
  ], [
28203
- [undefined, 1, "Alpha"],
28204
- ["", "", ""],
28205
- ["", "", ""]
28447
+ [undefined, undefined, 1, "etag0.0", "Alpha"],
28448
+ ["", "", "", "", ""],
28449
+ ["", "", "", "", ""]
28206
28450
  ]);
28207
28451
  assert.strictEqual(oRoot.getIndex(), 0);
28208
28452
 
@@ -28218,7 +28462,8 @@ sap.ui.define([
28218
28462
  }, /*bSkipRefresh*/true);
28219
28463
  oModel.resetChanges();
28220
28464
 
28221
- that.expectChange("name", [, "Beta"])
28465
+ that.expectChange("etag", [, undefined])
28466
+ .expectChange("name", [, "Beta"])
28222
28467
  .expectRequest({
28223
28468
  method : "POST",
28224
28469
  url : sFriend.slice(1),
@@ -28236,10 +28481,11 @@ sap.ui.define([
28236
28481
  }));
28237
28482
 
28238
28483
  // code under test
28239
- oChild = oListBinding.create({
28484
+ oBeta = oListBinding.create({
28240
28485
  "@$ui5.node.parent" : oRoot,
28241
28486
  Name : "Beta"
28242
28487
  }, /*bSkipRefresh*/true);
28488
+ oBetaCreated = oBeta.created();
28243
28489
 
28244
28490
  return Promise.all([
28245
28491
  checkCanceled(assert, oLostChild.created()),
@@ -28250,18 +28496,19 @@ sap.ui.define([
28250
28496
  sFriend + "(ArtistID='0',IsActiveEntity=false)",
28251
28497
  sFriend + "($uid=...)"
28252
28498
  ], [
28253
- [true, 1, "Alpha"],
28254
- [undefined, 2, "Beta"],
28255
- ["", "", ""]
28499
+ [undefined, true, 1, "etag0.0", "Alpha"],
28500
+ [true, undefined, 2, "", "Beta"],
28501
+ ["", "", "", "", ""]
28256
28502
  ]);
28257
- assert.strictEqual(oChild.getIndex(), 1);
28503
+ assert.strictEqual(oBeta.getIndex(), 1);
28258
28504
 
28259
- that.expectChange("name", [, "Beta: β"]);
28505
+ that.expectChange("etag", [, "etag1.0"])
28506
+ .expectChange("name", [, "Beta: β"]);
28260
28507
 
28261
28508
  fnRespond();
28262
28509
 
28263
28510
  return Promise.all([
28264
- oChild.created(),
28511
+ oBetaCreated,
28265
28512
  that.waitForChanges(assert, "respond")
28266
28513
  ]);
28267
28514
  }).then(function () {
@@ -28269,12 +28516,12 @@ sap.ui.define([
28269
28516
  sFriend + "(ArtistID='0',IsActiveEntity=false)",
28270
28517
  sFriend + "(ArtistID='1',IsActiveEntity=false)"
28271
28518
  ], [
28272
- [true, 1, "Alpha"],
28273
- [undefined, 2, "Beta: β"],
28274
- ["", "", ""]
28519
+ [undefined, true, 1, "etag0.0", "Alpha"],
28520
+ [false, undefined, 2, "etag1.0", "Beta: β"],
28521
+ ["", "", "", "", ""]
28275
28522
  ]);
28276
- assert.strictEqual(oChild.getIndex(), 1);
28277
- assert.deepEqual(oChild.getObject(), {
28523
+ assert.strictEqual(oBeta.getIndex(), 1);
28524
+ assert.deepEqual(oBeta.getObject(), {
28278
28525
  "@$ui5.context.isTransient" : false,
28279
28526
  "@$ui5.node.level" : 2,
28280
28527
  "@odata.etag" : "etag1.0",
@@ -28282,6 +28529,8 @@ sap.ui.define([
28282
28529
  IsActiveEntity : false,
28283
28530
  Name : "Beta: β"
28284
28531
  });
28532
+ assert.strictEqual(oBeta.isTransient(), false, "created persisted");
28533
+ assert.strictEqual(oBeta.created(), oBetaCreated);
28285
28534
 
28286
28535
  // code under test (JIRA: CPOUI5ODATAV4-2272)
28287
28536
  const oLostChild = oListBinding.create({
@@ -28290,7 +28539,8 @@ sap.ui.define([
28290
28539
  }, /*bSkipRefresh*/true);
28291
28540
  oModel.resetChanges();
28292
28541
 
28293
- that.expectChange("name", [, "Gamma", "Beta: β"])
28542
+ that.expectChange("etag", [, undefined, "etag1.0"])
28543
+ .expectChange("name", [, "Gamma", "Beta: β"])
28294
28544
  .expectRequest({
28295
28545
  method : "POST",
28296
28546
  url : sFriend.slice(1),
@@ -28304,58 +28554,555 @@ sap.ui.define([
28304
28554
  IsActiveEntity : false,
28305
28555
  Name : "Gamma: γ" // side effect
28306
28556
  })
28557
+ .expectChange("etag", [, "etag2.0"])
28307
28558
  .expectChange("name", [, "Gamma: γ"]);
28308
28559
 
28309
28560
  // code under test
28310
- oChild = oListBinding.create({
28561
+ oGamma = oListBinding.create({
28311
28562
  "@$ui5.node.parent" : oRoot,
28312
28563
  Name : "Gamma"
28313
28564
  }, /*bSkipRefresh*/true);
28565
+ oGammaCreated = oGamma.created();
28314
28566
 
28315
- assert.strictEqual(oChild.getIndex(), 1);
28567
+ assert.strictEqual(oGamma.getIndex(), 1);
28316
28568
 
28317
28569
  return Promise.all([
28318
28570
  checkCanceled(assert, oLostChild.created()),
28319
- oChild.created(),
28571
+ oGammaCreated,
28320
28572
  that.waitForChanges(assert, "create 2nd child")
28321
28573
  ]);
28322
28574
  }).then(function () {
28323
- checkTable("after creation", assert, oTable, [
28575
+ checkTable("after 2nd creation", assert, oTable, [
28324
28576
  sFriend + "(ArtistID='0',IsActiveEntity=false)",
28325
28577
  sFriend + "(ArtistID='2',IsActiveEntity=false)",
28326
28578
  sFriend + "(ArtistID='1',IsActiveEntity=false)"
28327
28579
  ], [
28328
- [true, 1, "Alpha"],
28329
- [undefined, 2, "Gamma: γ"],
28330
- [undefined, 2, "Beta: β"]
28580
+ [undefined, true, 1, "etag0.0", "Alpha"],
28581
+ [false, undefined, 2, "etag2.0", "Gamma: γ"],
28582
+ [false, undefined, 2, "etag1.0", "Beta: β"]
28331
28583
  ]);
28584
+ assert.strictEqual(oGamma.isTransient(), false, "created persisted");
28585
+ assert.strictEqual(oGamma.created(), oGammaCreated);
28332
28586
 
28333
- that.expectChange("name", [, "Beta: β"])
28334
- .expectRequest({
28335
- method : "DELETE",
28587
+ that.expectRequest({
28336
28588
  headers : {
28337
- "If-Match" : "etag2.0"
28589
+ "If-Match" : "etag2.0",
28590
+ Prefer : "return=minimal"
28338
28591
  },
28339
- url : "Artists(ArtistID='2',IsActiveEntity=false)"
28340
- });
28592
+ method : "PATCH",
28593
+ url : "Artists(ArtistID='2',IsActiveEntity=false)",
28594
+ payload : {
28595
+ "BestFriend@odata.bind" : "Artists(ArtistID='1',IsActiveEntity=false)"
28596
+ }
28597
+ }, null, {ETag : "etag2.1"}) // 204 No Content
28598
+ .expectChange("etag", [, "etag2.1"]) // Note: property changed before context moved
28599
+ .expectChange("etag", [, "etag1.0", "etag2.1"])
28600
+ .expectChange("name", [, "Beta: β", "Gamma: γ"]);
28601
+
28602
+ return Promise.all([
28603
+ // code under test
28604
+ oGamma.move({parent : oBeta}),
28605
+ that.waitForChanges(assert, "move")
28606
+ ]);
28607
+ }).then(function () {
28608
+ checkTable("after move", assert, oTable, [
28609
+ sFriend + "(ArtistID='0',IsActiveEntity=false)",
28610
+ sFriend + "(ArtistID='1',IsActiveEntity=false)",
28611
+ sFriend + "(ArtistID='2',IsActiveEntity=false)"
28612
+ ], [
28613
+ [undefined, true, 1, "etag0.0", "Alpha"],
28614
+ [false, true, 2, "etag1.0", "Beta: β"],
28615
+ [false, undefined, 3, "etag2.1", "Gamma: γ"]
28616
+ ]);
28617
+
28618
+ assert.strictEqual(oBeta.getIndex(), 1);
28619
+ assert.deepEqual(oBeta.getObject(), {
28620
+ "@$ui5.context.isTransient" : false,
28621
+ "@$ui5.node.isExpanded" : true,
28622
+ "@$ui5.node.level" : 2,
28623
+ "@odata.etag" : "etag1.0",
28624
+ ArtistID : "1",
28625
+ IsActiveEntity : false,
28626
+ Name : "Beta: β"
28627
+ });
28628
+ assert.strictEqual(oBeta.isTransient(), false, "created persisted");
28629
+ assert.strictEqual(oBeta.created(), oBetaCreated);
28630
+
28631
+ assert.strictEqual(oGamma.getIndex(), 2);
28632
+ assert.deepEqual(oGamma.getObject(), {
28633
+ "@$ui5.context.isTransient" : false,
28634
+ "@$ui5.node.level" : 3,
28635
+ "@odata.etag" : "etag2.1", // updated
28636
+ ArtistID : "2",
28637
+ IsActiveEntity : false,
28638
+ Name : "Gamma: γ"
28639
+ });
28640
+ assert.strictEqual(oGamma.isTransient(), false, "created persisted");
28641
+ assert.strictEqual(oGamma.created(), oGammaCreated, "unchanged");
28642
+
28643
+ //TODO assert.throws(function () {
28644
+ // // code under test
28645
+ // oRoot.move({parent : oGamma});
28646
+ // }, new Error("Unsupported parent context: " + oGamma));
28647
+
28648
+ that.expectRequest({
28649
+ headers : {
28650
+ "If-Match" : "etag2.1",
28651
+ Prefer : "return=minimal"
28652
+ },
28653
+ method : "PATCH",
28654
+ url : "Artists(ArtistID='2',IsActiveEntity=false)",
28655
+ payload : {
28656
+ "BestFriend@odata.bind" : "Artists(ArtistID='0',IsActiveEntity=false)"
28657
+ }
28658
+ }, null, {ETag : "etag2.2"}) // 204 No Content
28659
+ .expectChange("etag", [,, "etag2.2"]) // Note: property changed before context moved
28660
+ .expectChange("etag", [, "etag2.2", "etag1.0"])
28661
+ .expectChange("name", [, "Gamma: γ", "Beta: β"]);
28341
28662
 
28342
28663
  return Promise.all([
28343
28664
  // code under test
28344
- oChild.delete(),
28345
- that.waitForChanges(assert, "delete 2nd child")
28665
+ oGamma.move({parent : oRoot}),
28666
+ that.waitForChanges(assert, "move back")
28346
28667
  ]);
28347
28668
  }).then(function () {
28348
- checkTable("after deletion", assert, oTable, [
28669
+ checkTable("after move back", assert, oTable, [
28349
28670
  sFriend + "(ArtistID='0',IsActiveEntity=false)",
28671
+ sFriend + "(ArtistID='2',IsActiveEntity=false)",
28350
28672
  sFriend + "(ArtistID='1',IsActiveEntity=false)"
28351
28673
  ], [
28352
- [true, 1, "Alpha"],
28353
- [undefined, 2, "Beta: β"],
28354
- ["", "", ""]
28674
+ [undefined, true, 1, "etag0.0", "Alpha"],
28675
+ [false, undefined, 2, "etag2.2", "Gamma: γ"], // moved *before* all created rows
28676
+ [false, undefined, 2, "etag1.0", "Beta: β"]
28677
+ ]);
28678
+
28679
+ assert.strictEqual(oGamma.getIndex(), 1);
28680
+ assert.deepEqual(oGamma.getObject(), {
28681
+ "@$ui5.context.isTransient" : false,
28682
+ "@$ui5.node.level" : 2,
28683
+ "@odata.etag" : "etag2.2", // updated
28684
+ ArtistID : "2",
28685
+ IsActiveEntity : false,
28686
+ Name : "Gamma: γ"
28687
+ });
28688
+ assert.strictEqual(oGamma.isTransient(), false, "created persisted");
28689
+ assert.strictEqual(oGamma.created(), oGammaCreated, "unchanged");
28690
+
28691
+ assert.strictEqual(oBeta.getIndex(), 2);
28692
+ assert.deepEqual(oBeta.getObject(), {
28693
+ "@$ui5.context.isTransient" : false,
28694
+ "@$ui5.node.level" : 2,
28695
+ "@odata.etag" : "etag1.0",
28696
+ ArtistID : "1",
28697
+ IsActiveEntity : false,
28698
+ Name : "Beta: β"
28699
+ });
28700
+ assert.strictEqual(oBeta.isTransient(), false, "created persisted");
28701
+ assert.strictEqual(oBeta.created(), oBetaCreated);
28702
+
28703
+ // code under test
28704
+ oRoot.collapse();
28705
+
28706
+ return that.waitForChanges(assert, "collapse root");
28707
+ }).then(function () {
28708
+ checkTable("after collapse", assert, oTable, [
28709
+ sFriend + "(ArtistID='0',IsActiveEntity=false)"
28710
+ ], [
28711
+ [undefined, false, 1, "etag0.0", "Alpha"],
28712
+ ["", "", "", "", ""],
28713
+ ["", "", "", "", ""]
28714
+ ]);
28715
+
28716
+ that.expectRequest(sFriend.slice(1) + "?$select=ArtistID,IsActiveEntity,Name,_/NodeID"
28717
+ + "&$filter=ArtistID eq '0' and IsActiveEntity eq false", {
28718
+ value : [{
28719
+ "@odata.etag" : "etag0.1",
28720
+ ArtistID : "0",
28721
+ IsActiveEntity : false,
28722
+ Name : "Alpha #1", // "side effect"
28723
+ _ : null // not available w/ RAP for a non-hierarchical request
28724
+ }]
28725
+ })
28726
+ .expectChange("etag", ["etag0.1"])
28727
+ .expectChange("name", ["Alpha #1"]);
28728
+
28729
+ oBeta = oGamma = null; // Note: side effect eventually destroys these!
28730
+
28731
+ return Promise.all([
28732
+ // code under test
28733
+ oListBinding.getHeaderContext().requestSideEffects(["Name"]),
28734
+ that.waitForChanges(assert, "side effect: Name for all rows")
28735
+ ]);
28736
+ }).then(function () {
28737
+ that.expectRequest(sFriend.slice(1) + "?$apply=descendants($root" + sFriend
28738
+ + ",OrgChart,_/NodeID,filter(ArtistID eq '0' and IsActiveEntity eq false),1)"
28739
+ + "&$select=ArtistID,IsActiveEntity,Name,_/DrillState,_/NodeID"
28740
+ + "&$skip=0&$top=2", {
28741
+ value : [{ //TODO Gamma might not be $skip=0!
28742
+ "@odata.etag" : "etag2.3", // updated
28743
+ ArtistID : "2",
28744
+ IsActiveEntity : false,
28745
+ Name : "Gamma #1", // "side effect"
28746
+ _ : {
28747
+ DrillState : "leaf",
28748
+ NodeID : "2,false"
28749
+ }
28750
+ }, {
28751
+ "@odata.etag" : "etag1.3", // updated
28752
+ ArtistID : "1",
28753
+ IsActiveEntity : false,
28754
+ Name : "Beta #1", // "side effect"
28755
+ _ : {
28756
+ DrillState : "leaf",
28757
+ NodeID : "1,false"
28758
+ }
28759
+ }]
28760
+ })
28761
+ .expectChange("etag", [, "etag2.3", "etag1.3"])
28762
+ .expectChange("name", [, "Gamma #1", "Beta #1"]);
28763
+
28764
+ // code under test
28765
+ oRoot.expand();
28766
+
28767
+ return that.waitForChanges(assert, "expand root again");
28768
+ }).then(function () {
28769
+ checkTable("after expand root again", assert, oTable, [
28770
+ sFriend + "(ArtistID='0',IsActiveEntity=false)",
28771
+ sFriend + "(ArtistID='2',IsActiveEntity=false)",
28772
+ sFriend + "(ArtistID='1',IsActiveEntity=false)"
28773
+ ], [
28774
+ [undefined, true, 1, "etag0.1", "Alpha #1"],
28775
+ [undefined, undefined, 2, "etag2.3", "Gamma #1"],
28776
+ [undefined, undefined, 2, "etag1.3", "Beta #1"]
28777
+ ]);
28778
+ [, oGamma, oBeta] = oListBinding.getCurrentContexts();
28779
+
28780
+ assert.strictEqual(oGamma.getIndex(), 1);
28781
+ assert.deepEqual(oGamma.getObject(), {
28782
+ "@$ui5.node.level" : 2,
28783
+ "@odata.etag" : "etag2.3",
28784
+ ArtistID : "2",
28785
+ IsActiveEntity : false,
28786
+ Name : "Gamma #1",
28787
+ _ : {
28788
+ NodeID : "2,false"
28789
+ }
28790
+ });
28791
+ assert.strictEqual(oGamma.isTransient(), undefined, "persisted");
28792
+ assert.strictEqual(oGamma.created(), undefined);
28793
+
28794
+ assert.strictEqual(oBeta.getIndex(), 2);
28795
+ assert.deepEqual(oBeta.getObject(), {
28796
+ // "@$ui5.context.isTransient" deleted by #requestSideEffects/#expand
28797
+ "@$ui5.node.level" : 2,
28798
+ "@odata.etag" : "etag1.3",
28799
+ ArtistID : "1",
28800
+ IsActiveEntity : false,
28801
+ Name : "Beta #1",
28802
+ _ : {
28803
+ NodeID : "1,false"
28804
+ }
28805
+ });
28806
+ assert.strictEqual(oBeta.isTransient(), undefined, "persisted");
28807
+ assert.strictEqual(oBeta.created(), undefined);
28808
+
28809
+ return Promise.all([
28810
+ // code under test
28811
+ checkCanceled(assert, oGamma.move({parent : oBeta})),
28812
+ oModel.resetChanges()
28813
+ ]);
28814
+ }).then(function () {
28815
+ that.expectRequest({
28816
+ headers : {
28817
+ "If-Match" : "etag1.3",
28818
+ Prefer : "return=minimal"
28819
+ },
28820
+ method : "PATCH",
28821
+ url : "Artists(ArtistID='1',IsActiveEntity=false)",
28822
+ payload : {
28823
+ "BestFriend@odata.bind" : "Artists(ArtistID='2',IsActiveEntity=false)"
28824
+ }
28825
+ }, null, {ETag : "etag1.4"}) // 204 No Content
28826
+ .expectChange("etag", [,, "etag1.4"]);
28827
+
28828
+ return Promise.all([
28829
+ // code under test
28830
+ oBeta.move({parent : oGamma}), // Note: child's index does not change!
28831
+ that.waitForChanges(assert, "new parent already right before child")
28832
+ ]);
28833
+ }).then(function () {
28834
+ checkTable("after 'new parent already right before child'", assert, oTable, [
28835
+ sFriend + "(ArtistID='0',IsActiveEntity=false)",
28836
+ sFriend + "(ArtistID='2',IsActiveEntity=false)",
28837
+ sFriend + "(ArtistID='1',IsActiveEntity=false)"
28838
+ ], [
28839
+ [undefined, true, 1, "etag0.1", "Alpha #1"],
28840
+ [undefined, true, 2, "etag2.3", "Gamma #1"],
28841
+ [false, undefined, 3, "etag1.4", "Beta #1"]
28355
28842
  ]);
28843
+ const aCurrentContexts = oListBinding.getCurrentContexts();
28844
+ assert.strictEqual(oRoot, aCurrentContexts[0]);
28845
+ assert.strictEqual(oGamma, aCurrentContexts[1]);
28846
+ assert.strictEqual(oBeta, aCurrentContexts[2], "same instance");
28847
+
28848
+ assert.strictEqual(oGamma.getIndex(), 1);
28849
+ assert.deepEqual(oGamma.getObject(), {
28850
+ "@$ui5.node.isExpanded" : true,
28851
+ "@$ui5.node.level" : 2,
28852
+ "@odata.etag" : "etag2.3",
28853
+ ArtistID : "2",
28854
+ IsActiveEntity : false,
28855
+ Name : "Gamma #1",
28856
+ _ : {
28857
+ NodeID : "2,false"
28858
+ }
28859
+ });
28860
+ assert.strictEqual(oGamma.isTransient(), undefined, "persisted");
28861
+ assert.strictEqual(oGamma.created(), undefined);
28862
+
28863
+ assert.strictEqual(oBeta.getIndex(), 2); // unchanged by #move
28864
+ assert.deepEqual(oBeta.getObject(), {
28865
+ "@$ui5.context.isTransient" : false, // "moved"
28866
+ "@$ui5.node.level" : 3,
28867
+ "@odata.etag" : "etag1.4",
28868
+ ArtistID : "1",
28869
+ IsActiveEntity : false,
28870
+ Name : "Beta #1",
28871
+ _ : {
28872
+ NodeID : "1,false"
28873
+ }
28874
+ });
28875
+ assert.strictEqual(oBeta.isTransient(), false, "created persisted");
28876
+ assert.ok(oBeta.created() instanceof Promise);
28877
+
28878
+ return oBeta.created(); // to prove that it's not rejected
28356
28879
  });
28357
28880
  });
28358
28881
 
28882
+ //*********************************************************************************************
28883
+ // Scenario: Show the first level of a recursive hierarchy ("Alpha", "Omega"), expand "Alpha"
28884
+ // and "Beta" and collapse "Beta" again. Move "Alpha" so that "Omega" becomes its parent. Check
28885
+ // that its children are moved as well. Expand "Beta" again and check the level of its children.
28886
+ // "Alpha" is either moved as a node with children or first collapsed and later expanded.
28887
+ // JIRA: CPOUI5ODATAV4-2325
28888
+ [false, true].forEach((bMoveCollapsed) => {
28889
+ const sTitle = `Recursive Hierarchy: move node w/ children, collapsed=${bMoveCollapsed}`;
28890
+
28891
+ QUnit.test(sTitle, async function (assert) {
28892
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
28893
+ const sView = `
28894
+ <t:Table id="table" rows="{path : '/EMPLOYEES',
28895
+ parameters : {
28896
+ $$aggregation : {hierarchyQualifier : 'OrgChart'}
28897
+ }}" threshold="0" visibleRowCount="5">
28898
+ <Text text="{= %{@$ui5.node.isExpanded} }"/>
28899
+ <Text text="{= %{@$ui5.node.level} }"/>
28900
+ <Text id="id" text="{ID}"/>
28901
+ <Text text="{MANAGER_ID}"/>
28902
+ <Text text="{Name}"/>
28903
+ <Text text="{AGE}"/>
28904
+ </t:Table>`;
28905
+
28906
+ // 0 Alpha
28907
+ // 1 Beta
28908
+ // 1.1 Gamma
28909
+ // 1.2 Zeta
28910
+ // 2 Kappa
28911
+ // 3 Lambda
28912
+ // 9 Omega
28913
+ this.expectRequest("EMPLOYEES?$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels("
28914
+ + "HierarchyNodes=$root/EMPLOYEES,HierarchyQualifier='OrgChart'"
28915
+ + ",NodeProperty='ID',Levels=1)"
28916
+ + "&$select=AGE,DrillState,ID,MANAGER_ID,Name&$count=true&$skip=0&$top=5", {
28917
+ "@odata.count" : "2",
28918
+ value : [{
28919
+ AGE : 60,
28920
+ DrillState : "collapsed",
28921
+ ID : "0",
28922
+ MANAGER_ID : null,
28923
+ Name : "Alpha"
28924
+ }, {
28925
+ AGE : 69,
28926
+ DrillState : "leaf",
28927
+ ID : "9",
28928
+ MANAGER_ID : null,
28929
+ Name : "Omega"
28930
+ }]
28931
+ })
28932
+ .expectChange("id", ["0", "9"]);
28933
+
28934
+ await this.createView(assert, sView, oModel);
28935
+
28936
+ const oTable = this.oView.byId("table");
28937
+ checkTable("initial page", assert, oTable, [
28938
+ "/EMPLOYEES('0')",
28939
+ "/EMPLOYEES('9')"
28940
+ ], [
28941
+ [false, 1, "0", "", "Alpha", 60],
28942
+ [undefined, 1, "9", "", "Omega", 69],
28943
+ ["", "", "", "", "", ""],
28944
+ ["", "", "", "", "", ""],
28945
+ ["", "", "", "", "", ""]
28946
+ ]);
28947
+ const oAlpha = oTable.getRows()[0].getBindingContext();
28948
+ const oOmega = oTable.getRows()[1].getBindingContext();
28949
+
28950
+ this.expectRequest("EMPLOYEES?$apply=descendants($root/EMPLOYEES,OrgChart,ID"
28951
+ + ",filter(ID eq '0'),1)"
28952
+ + "&$select=AGE,DrillState,ID,MANAGER_ID,Name&$count=true&$skip=0&$top=5", {
28953
+ "@odata.count" : "3",
28954
+ value : [{
28955
+ AGE : 55,
28956
+ DrillState : "collapsed",
28957
+ ID : "1",
28958
+ MANAGER_ID : "0",
28959
+ Name : "Beta"
28960
+ }, {
28961
+ AGE : 56,
28962
+ DrillState : "leaf",
28963
+ ID : "2",
28964
+ MANAGER_ID : "0",
28965
+ Name : "Kappa"
28966
+ }, {
28967
+ AGE : 57,
28968
+ DrillState : "leaf",
28969
+ ID : "3",
28970
+ MANAGER_ID : "0",
28971
+ Name : "Lambda"
28972
+ }]
28973
+ })
28974
+ .expectChange("id", [, "1", "2", "3", "9"]);
28975
+
28976
+ oAlpha.expand();
28977
+
28978
+ await this.waitForChanges(assert, "expand 0 (Alpha)");
28979
+
28980
+ checkTable("after expand 0 (Alpha)", assert, oTable, [
28981
+ "/EMPLOYEES('0')",
28982
+ "/EMPLOYEES('1')",
28983
+ "/EMPLOYEES('2')",
28984
+ "/EMPLOYEES('3')",
28985
+ "/EMPLOYEES('9')"
28986
+ ], [
28987
+ [true, 1, "0", "", "Alpha", 60],
28988
+ [false, 2, "1", "0", "Beta", 55],
28989
+ [undefined, 2, "2", "0", "Kappa", 56],
28990
+ [undefined, 2, "3", "0", "Lambda", 57],
28991
+ [undefined, 1, "9", "", "Omega", 69]
28992
+ ]);
28993
+ const oBeta = oTable.getRows()[1].getBindingContext();
28994
+
28995
+ this.expectRequest("EMPLOYEES?$apply=descendants($root/EMPLOYEES,OrgChart,ID"
28996
+ + ",filter(ID eq '1'),1)"
28997
+ + "&$select=AGE,DrillState,ID,MANAGER_ID,Name&$count=true&$skip=0&$top=5", {
28998
+ "@odata.count" : "2",
28999
+ value : [{
29000
+ AGE : 41,
29001
+ DrillState : "leaf",
29002
+ ID : "1.1",
29003
+ MANAGER_ID : "1",
29004
+ Name : "Gamma"
29005
+ }, {
29006
+ AGE : 42,
29007
+ DrillState : "leaf",
29008
+ ID : "1.2",
29009
+ MANAGER_ID : "1",
29010
+ Name : "Zeta"
29011
+ }]
29012
+ })
29013
+ .expectChange("id", [,, "1.1", "1.2", "2"]);
29014
+
29015
+ oBeta.expand();
29016
+
29017
+ await this.waitForChanges(assert, "expand 1 (Beta)");
29018
+
29019
+ checkTable("after expand 1 (Beta)", assert, oTable, [
29020
+ "/EMPLOYEES('0')",
29021
+ "/EMPLOYEES('1')",
29022
+ "/EMPLOYEES('1.1')",
29023
+ "/EMPLOYEES('1.2')",
29024
+ "/EMPLOYEES('2')",
29025
+ "/EMPLOYEES('3')",
29026
+ "/EMPLOYEES('9')"
29027
+ ], [
29028
+ [true, 1, "0", "", "Alpha", 60],
29029
+ [true, 2, "1", "0", "Beta", 55],
29030
+ [undefined, 3, "1.1", "1", "Gamma", 41],
29031
+ [undefined, 3, "1.2", "1", "Zeta", 42],
29032
+ [undefined, 2, "2", "0", "Kappa", 56]
29033
+ ]);
29034
+
29035
+ this.expectChange("id", [,, "2", "3", "9"]);
29036
+
29037
+ oBeta.collapse();
29038
+
29039
+ await this.waitForChanges(assert, "collapse 1 (Beta)");
29040
+
29041
+ checkTable("after collapse 1 (Beta)", assert, oTable, [
29042
+ "/EMPLOYEES('0')",
29043
+ "/EMPLOYEES('1')",
29044
+ "/EMPLOYEES('2')",
29045
+ "/EMPLOYEES('3')",
29046
+ "/EMPLOYEES('9')"
29047
+ ], [
29048
+ [true, 1, "0", "", "Alpha", 60],
29049
+ [false, 2, "1", "0", "Beta", 55],
29050
+ [undefined, 2, "2", "0", "Kappa", 56],
29051
+ [undefined, 2, "3", "0", "Lambda", 57],
29052
+ [undefined, 1, "9", "", "Omega", 69]
29053
+ ]);
29054
+
29055
+ if (bMoveCollapsed) {
29056
+ this.expectChange("id", [, "9"]);
29057
+ oAlpha.collapse();
29058
+ }
29059
+
29060
+ this.expectEvents(assert, "sap.ui.model.odata.v4.ODataListBinding: /EMPLOYEES", [
29061
+ [, "change", {reason : "change"}]
29062
+ ])
29063
+ .expectRequest({
29064
+ headers : {
29065
+ Prefer : "return=minimal"
29066
+ },
29067
+ method : "PATCH",
29068
+ url : "EMPLOYEES('0')",
29069
+ payload : {
29070
+ "EMPLOYEE_2_MANAGER@odata.bind" : "EMPLOYEES('9')"
29071
+ }
29072
+ }) // 204 No Content
29073
+ .expectChange("id", bMoveCollapsed ? ["9", "0"] : ["9", "0", "1", "2", "3"]);
29074
+
29075
+ await Promise.all([
29076
+ oAlpha.move({parent : oOmega}),
29077
+ this.waitForChanges(assert, "move 0 (Alpha) to 9 (Omega)")
29078
+ ]);
29079
+
29080
+ if (bMoveCollapsed) {
29081
+ this.expectEvents(assert, "sap.ui.model.odata.v4.ODataListBinding: /EMPLOYEES", [
29082
+ [, "change", {reason : "change"}]
29083
+ ])
29084
+ .expectChange("id", [,, "1", "2", "3"]);
29085
+ oAlpha.expand();
29086
+
29087
+ await this.waitForChanges(assert, "expand 0 (Alpha)");
29088
+ }
29089
+
29090
+ checkTable("after move 0 (Alpha) to 9 (Omega)", assert, oTable, [
29091
+ "/EMPLOYEES('9')",
29092
+ "/EMPLOYEES('0')",
29093
+ "/EMPLOYEES('1')",
29094
+ "/EMPLOYEES('2')",
29095
+ "/EMPLOYEES('3')"
29096
+ ], [
29097
+ [true, 1, "9", "", "Omega", 69],
29098
+ [true, 2, "0", ""/*TODO "9"*/, "Alpha", 60],
29099
+ [false, 3, "1", "0", "Beta", 55],
29100
+ [undefined, 3, "2", "0", "Kappa", 56],
29101
+ [undefined, 3, "3", "0", "Lambda", 57]
29102
+ ]);
29103
+ });
29104
+ });
29105
+
28359
29106
  //*********************************************************************************************
28360
29107
  // Scenario: Show the single root node of a recursive hierarchy and expand it. Not all children
28361
29108
  // are loaded, but some placeholders remain. Create two new child nodes underneath the root.
@@ -28364,6 +29111,7 @@ sap.ui.define([
28364
29111
  //
28365
29112
  // Create new child and cancel immediately (JIRA: CPOUI5ODATAV4-2272)
28366
29113
  // Also delete instead of cancelling (JIRA: CPOUI5ODATAV4-2274)
29114
+ // Delete a created persisted child (JIRA: CPOUI5ODATAV4-2224)
28367
29115
  [false, true].forEach(function (bDelete) {
28368
29116
  const sTitle = `Recursive Hierarchy: create new children & placeholders, delete=${bDelete}`;
28369
29117
 
@@ -28522,6 +29270,7 @@ sap.ui.define([
28522
29270
  Name : "2nd new child"
28523
29271
  }
28524
29272
  }, {
29273
+ "@odata.etag" : "etag2.0",
28525
29274
  ArtistID : "12",
28526
29275
  IsActiveEntity : false,
28527
29276
  Name : "Second new child" // side effect
@@ -28620,6 +29369,46 @@ sap.ui.define([
28620
29369
  [undefined, 2, "4", "Epsilon"],
28621
29370
  [undefined, 2, "5", "Zeta"]
28622
29371
  ]);
29372
+ }).then(function () {
29373
+ that.expectChange("id", ["0", "12", "11"])
29374
+ .expectChange("name", ["Alpha", "Second new child", "First new child"]);
29375
+
29376
+ oTable.setFirstVisibleRow(0);
29377
+
29378
+ return that.waitForChanges(assert, "scroll to top");
29379
+ }).then(function () {
29380
+ const oCreatedPersisted = oTable.getRows()[1].getBindingContext();
29381
+ assert.strictEqual(oCreatedPersisted.isTransient(), false);
29382
+
29383
+ that.expectChange("id", [, "11", "1"])
29384
+ .expectChange("name", [, "First new child", "Beta"])
29385
+ .expectRequest({
29386
+ method : "DELETE",
29387
+ headers : {
29388
+ "If-Match" : "etag2.0"
29389
+ },
29390
+ url : "Artists(ArtistID='12',IsActiveEntity=false)"
29391
+ });
29392
+
29393
+ return Promise.all([
29394
+ // code under test (JIRA: CPOUI5ODATAV4-2224)
29395
+ oCreatedPersisted.delete(),
29396
+ that.waitForChanges(assert, "delete created persisted child")
29397
+ ]);
29398
+ }).then(function () {
29399
+ checkTable("after deletion of created persisted", assert, oTable, [
29400
+ "/Artists(ArtistID='0',IsActiveEntity=false)",
29401
+ "/Artists(ArtistID='11',IsActiveEntity=false)",
29402
+ "/Artists(ArtistID='1',IsActiveEntity=false)",
29403
+ "/Artists(ArtistID='2',IsActiveEntity=false)",
29404
+ "/Artists(ArtistID='3',IsActiveEntity=false)",
29405
+ "/Artists(ArtistID='4',IsActiveEntity=false)",
29406
+ "/Artists(ArtistID='5',IsActiveEntity=false)"
29407
+ ], [
29408
+ [true, 1, "0", "Alpha"],
29409
+ [undefined, 2, "11", "First new child"],
29410
+ [undefined, 2, "1", "Beta"]
29411
+ ]);
28623
29412
  });
28624
29413
  });
28625
29414
  });
@@ -29163,7 +29952,8 @@ sap.ui.define([
29163
29952
  // properly computed.
29164
29953
  // BCP 1870081505
29165
29954
  QUnit.test("bindElement called twice on table", function (assert) {
29166
- var oModel = this.createTeaBusiModel({autoExpandSelect : true}),
29955
+ var fnRespond,
29956
+ oModel = this.createTeaBusiModel({autoExpandSelect : true}),
29167
29957
  oTable,
29168
29958
  // Note: table must be "growing" otherwise it does not use ECD
29169
29959
  sView = '\
@@ -29195,24 +29985,88 @@ sap.ui.define([
29195
29985
  return that.waitForChanges(assert);
29196
29986
  }).then(function () {
29197
29987
  that.expectRequest("TEAMS('TEAM_01')?$select=Team_Id"
29198
- + "&$expand=TEAM_2_EMPLOYEES($select=ID,Name)", {
29199
- Team_Id : "TEAM_01",
29200
- TEAM_2_EMPLOYEES : [{
29201
- ID : "3",
29202
- Name : "Jonathan Smith"
29203
- }]
29204
- })
29205
- .expectChange("name", ["Jonathan Smith"]);
29988
+ + "&$expand=TEAM_2_EMPLOYEES($select=ID,Name)", new Promise(function (resolve) {
29989
+ fnRespond = resolve.bind(null, {
29990
+ Team_Id : "TEAM_01",
29991
+ TEAM_2_EMPLOYEES : [{
29992
+ ID : "3",
29993
+ Name : "Jonathan Smith"
29994
+ }]
29995
+ });
29996
+ }));
29206
29997
 
29207
29998
  // code under test
29208
29999
  oTable.bindElement("/TEAMS('TEAM_01')");
29209
30000
 
29210
- return that.waitForChanges(assert);
30001
+ return that.waitForChanges(assert, "request");
30002
+ }).then(function () {
30003
+ assert.strictEqual(oTable.getItems().length, 0, "All gone");
30004
+
30005
+ that.expectChange("name", ["Jonathan Smith"]);
30006
+
30007
+ fnRespond();
30008
+
30009
+ return that.waitForChanges(assert, "response");
29211
30010
  }).then(function () {
29212
- assert.strictEqual(oTable.getItems().length, 1, "The one entry is still displayed");
30011
+ assert.strictEqual(oTable.getItems().length, 1, "The one entry is displayed again");
29213
30012
  });
29214
30013
  });
29215
30014
 
30015
+ //*********************************************************************************************
30016
+ // Scenario: ManagedObject#setParent is called on a table to remove and add a parent. This
30017
+ // causes the list binding to be recreated. No diff must be used in order to avoid duplicate
30018
+ // data.
30019
+ // BCP: 2380130744
30020
+ QUnit.test("BCP: 2380130744", async function (assert) {
30021
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
30022
+ // Note: table must be "growing" otherwise it does not use ECD
30023
+ const sView = `
30024
+ <FlexBox id="form">
30025
+ <Table id="table" items="{/EMPLOYEES}" growing="true">
30026
+ <Text id="name" text="{Name}"/>
30027
+ </Table>
30028
+ </FlexBox>`;
30029
+
30030
+ this.expectRequest("EMPLOYEES?$select=ID,Name&$skip=0&$top=20", {
30031
+ value : [{
30032
+ ID : "3",
30033
+ Name : "Jonathan Smith"
30034
+ }]
30035
+ })
30036
+ .expectChange("name", ["Jonathan Smith"]);
30037
+
30038
+ await this.createView(assert, sView, oModel);
30039
+
30040
+ const oTable = this.oView.byId("table");
30041
+
30042
+ // code under test
30043
+ oTable.setParent(null);
30044
+
30045
+ await this.waitForChanges(assert, "remove parent");
30046
+
30047
+ assert.strictEqual(oTable.getBinding("items"), undefined);
30048
+ assert.strictEqual(oTable.getItems().length, 1);
30049
+ assert.strictEqual(oTable.getItems()[0].getCells()[0].getText(), "Jonathan Smith",
30050
+ "still there!");
30051
+
30052
+ this.expectRequest("EMPLOYEES?$select=ID,Name&$skip=0&$top=20", {
30053
+ value : [{
30054
+ ID : "2",
30055
+ Name : "Frederic Fall"
30056
+ }]
30057
+ })
30058
+ .expectChange("name", ["Frederic Fall"]);
30059
+
30060
+ // code under test
30061
+ oTable.setParent(this.oView.byId("form"));
30062
+
30063
+ await this.waitForChanges(assert, "restore parent");
30064
+
30065
+ checkTable("after restore parent", assert, oTable, ["/EMPLOYEES('2')"], [
30066
+ ["Frederic Fall"]
30067
+ ]);
30068
+ });
30069
+
29216
30070
  //*********************************************************************************************
29217
30071
  // Scenario: Update a property via a control and check that the control contains the value
29218
30072
  // afterwards. Reason: ManagedObject#updateModelProperty fetches the updated model value and
@@ -31517,17 +32371,32 @@ sap.ui.define([
31517
32371
  payload : {}
31518
32372
  }, {
31519
32373
  ArtistID : "2",
31520
- IsActiveEntity : false
31521
- });
32374
+ IsActiveEntity : false,
32375
+ Messages : [{
32376
+ message : "Some Message",
32377
+ numericSeverity : 3,
32378
+ target : "ArtistID",
32379
+ transition : false
32380
+ }]
32381
+ })
32382
+ .expectMessages([{
32383
+ message : "Some Message",
32384
+ targets : [
32385
+ "/Artists(ArtistID='1',IsActiveEntity=true)/BestFriend/" + sAction
32386
+ + "(...)/ArtistID"
32387
+ ],
32388
+ type : "Warning"
32389
+ }]);
31522
32390
 
31523
32391
  return Promise.all([
31524
32392
  that.oView.byId("action").getObjectBinding().execute(),
31525
32393
  that.waitForChanges(assert)
31526
32394
  ]);
31527
- }).then(function () {
32395
+ }).then(function ([oReturnValueContext]) {
31528
32396
  // TODO return value context not supported here
31529
32397
  // assert.strictEqual(aResults[0].getPath(),
31530
32398
  // "Artists(ArtistID='2',IsActiveEntity=false)");
32399
+ assert.strictEqual(oReturnValueContext, undefined);
31531
32400
  });
31532
32401
  });
31533
32402
 
@@ -31587,9 +32456,13 @@ sap.ui.define([
31587
32456
  });
31588
32457
 
31589
32458
  //*********************************************************************************************
31590
- // Scenario: Create entity for a relative ListBinding, save the new entity and call action
31591
- // import for the new non-transient entity
32459
+ // Scenario: Create entity for a relative ListBinding, save the new entity and call a bound
32460
+ // action for the new non-transient entity
31592
32461
  // JIRA: CPOUI5UISERVICESV3-1233
32462
+ //
32463
+ // Ensure that a Return Value Context is created and the structure of the path is same like the
32464
+ // binding parameter
32465
+ // JIRA: CPOUI5ODATAV4-2096
31593
32466
  QUnit.test("Create relative, save and call action", function (assert) {
31594
32467
  var oCreatedContext,
31595
32468
  oModel = this.createTeaBusiModel(),
@@ -31632,15 +32505,24 @@ sap.ui.define([
31632
32505
  that.expectRequest({
31633
32506
  method : "POST",
31634
32507
  url : "TEAMS('42')/TEAM_2_EMPLOYEES('7')/"
31635
- + "com.sap.gateway.default.iwbep.tea_busi.v0001.AcChangeTeamOfEmployee",
31636
- payload : {TeamID : "TEAM_02"}
31637
- }, {ID : "7"});
31638
- oAction.setParameter("TeamID", "TEAM_02");
32508
+ + "com.sap.gateway.default.iwbep.tea_busi.v0001.AcChangeTeamOfEmployee"
32509
+ + "?$expand=EMPLOYEE_2_TEAM($select=Team_Id)",
32510
+ payload : {TeamID : "02"}
32511
+ }, {
32512
+ EMPLOYEE_2_TEAM : {
32513
+ Team_Id : "02"
32514
+ },
32515
+ ID : "7"
32516
+ });
32517
+ oAction.setParameter("TeamID", "02");
31639
32518
 
31640
32519
  return Promise.all([
31641
32520
  // code under test
31642
- oAction.execute(),
31643
- // Note: no R.V.C. because path "/TEAMS('42')/TEAM_2_EMPLOYEES('7')" too long
32521
+ oAction.execute().then(function (oReturnValueContext) {
32522
+ assert.strictEqual(
32523
+ oReturnValueContext.getPath(),
32524
+ "/TEAMS('02')/TEAM_2_EMPLOYEES('7')");
32525
+ }),
31644
32526
  that.waitForChanges(assert)
31645
32527
  ]);
31646
32528
  });
@@ -38007,6 +38889,102 @@ sap.ui.define([
38007
38889
  });
38008
38890
  });
38009
38891
 
38892
+ //*********************************************************************************************
38893
+ // Scenario: Execute a bound action, this returns a return value context although the path
38894
+ // contains navigation properties.
38895
+ // JIRA: CPOUI5ODATAV4-2096
38896
+ [false, true].forEach(function (bInheritExpandSelect) {
38897
+ ["TEAM_01", "TEAM_02"].forEach(function (sTeamId) {
38898
+ ["1", "2"].forEach(function (sEmployeeId) {
38899
+ var sTitle = "CPOUI5ODATAV4-2096 - Bound Action with RVC, Team changed: "
38900
+ + (sTeamId === "TEAM_02") + ", EmployeeId changed: " + (sEmployeeId === "2")
38901
+ + ", bInheritExpandSelect: " + bInheritExpandSelect;
38902
+
38903
+ QUnit.test(sTitle, async function (assert) {
38904
+ var sChangeTeamAction
38905
+ = "com.sap.gateway.default.iwbep.tea_busi.v0001.AcChangeTeamOfEmployee",
38906
+ oModel = this.createTeaBusiModel({autoExpandSelect : true}),
38907
+ sRVCPath = "/TEAMS('" + sTeamId + "')/TEAM_2_EMPLOYEES('" + sEmployeeId + "')",
38908
+ sView = '\
38909
+ <Table id="teams" items="{path : \'/TEAMS\'}">\
38910
+ <Text id="teamId" text="{Team_Id}"/>\
38911
+ </Table>\
38912
+ <Table id="employees" items="{path : \'TEAM_2_EMPLOYEES\', parameters : {$$ownRequest : true}}">\
38913
+ <Input id="name" value="{Name}"/>\
38914
+ <Text id="team" text="{TEAM_ID}"/>\
38915
+ </Table>';
38916
+
38917
+ this.expectRequest("TEAMS?$select=Team_Id&$skip=0&$top=100", {
38918
+ value : [{Team_Id : "TEAM_01"}, {Team_Id : "TEAM_02"}]
38919
+ })
38920
+ .expectChange("teamId", ["TEAM_01", "TEAM_02"])
38921
+ .expectChange("name", [])
38922
+ .expectChange("team", []);
38923
+
38924
+ await this.createView(assert, sView, oModel);
38925
+
38926
+ this.expectRequest("TEAMS('TEAM_01')/TEAM_2_EMPLOYEES?$select=ID,Name,TEAM_ID"
38927
+ + "&$skip=0&$top=100", {
38928
+ value : [{ID : "1", Name : "Jonathan Smith", TEAM_ID : "TEAM_01"}]
38929
+ })
38930
+ .expectChange("name", ["Jonathan Smith"])
38931
+ .expectChange("team", ["TEAM_01"]);
38932
+
38933
+ this.oView.byId("employees").setBindingContext(
38934
+ this.oView.byId("teams").getBinding("items").getCurrentContexts()[0]);
38935
+
38936
+ await this.waitForChanges(assert);
38937
+
38938
+ const oResponse = {
38939
+ Age : "42",
38940
+ EMPLOYEE_2_TEAM : {
38941
+ Team_Id : sTeamId
38942
+ },
38943
+ ID : sEmployeeId
38944
+ };
38945
+
38946
+ if (bInheritExpandSelect) {
38947
+ oResponse["Name"] = "Jonathan Smith";
38948
+ oResponse["TEAM_ID"] = sTeamId;
38949
+ }
38950
+
38951
+ const oEmployeesBinding = this.oView.byId("employees").getBinding("items");
38952
+ const oEmployeeContext = oEmployeesBinding.getCurrentContexts()[0];
38953
+ const oActionBinding = this.oModel.bindContext(sChangeTeamAction + "(...)",
38954
+ oEmployeeContext, {
38955
+ $select : ["Age"],
38956
+ $$inheritExpandSelect : bInheritExpandSelect
38957
+ });
38958
+
38959
+ this.expectRequest({
38960
+ method : "POST",
38961
+ payload : {
38962
+ TeamID : sTeamId
38963
+ },
38964
+ url : "TEAMS('TEAM_01')/TEAM_2_EMPLOYEES('1')" + "/" + sChangeTeamAction
38965
+ + (bInheritExpandSelect
38966
+ ? "?$select=Age,ID,Name,TEAM_ID"
38967
+ : "?$select=Age,ID")
38968
+ + "&$expand=EMPLOYEE_2_TEAM($select=Team_Id)"
38969
+ }, oResponse);
38970
+
38971
+ if (sTeamId === "TEAM_02" && sEmployeeId === "1" && bInheritExpandSelect) {
38972
+ this.expectChange("team", ["TEAM_02"]);
38973
+ }
38974
+
38975
+ const [oReturnValueContext] = await Promise.all([
38976
+ oActionBinding
38977
+ .setParameter("TeamID", sTeamId)
38978
+ .execute(),
38979
+ this.waitForChanges(assert)
38980
+ ]);
38981
+
38982
+ assert.strictEqual(oReturnValueContext.getPath(), sRVCPath);
38983
+ });
38984
+ });
38985
+ });
38986
+ });
38987
+
38010
38988
  //*********************************************************************************************
38011
38989
  // Scenario: Delete an entity via the model. This must not stumble over bindings below a not-yet
38012
38990
  // destroyed context of an ODLB which is already unresolved (kept in mPreviousContextsByPath),
@@ -38425,6 +39403,40 @@ sap.ui.define([
38425
39403
  return this.createView(assert, sView, oModel);
38426
39404
  });
38427
39405
 
39406
+ //*********************************************************************************************
39407
+ // Scenario: Path reduction and change listener
39408
+ // "defaultChannel" has a reducible path. See that it is properly deregistered with the delete,
39409
+ // so that the refresh promise resolves.
39410
+ // BCP: 2370061110
39411
+ QUnit.test("BCP: 2370061110", async function (assert) {
39412
+ const oModel = this.createSpecialCasesModel({autoExpandSelect : true});
39413
+ const sView = `
39414
+ <FlexBox id="form" binding="{/Artists(ArtistID='1',IsActiveEntity=false)}">
39415
+ <Text id="defaultChannel" text="{_Publication/_Artist/defaultChannel}"/>
39416
+ </FlexBox>`;
39417
+
39418
+ this.expectRequest("Artists(ArtistID='1',IsActiveEntity=false)"
39419
+ + "?$select=ArtistID,IsActiveEntity,defaultChannel", {
39420
+ ArtistID : "1",
39421
+ IsActiveEntity : false,
39422
+ defaultChannel : "test"
39423
+ })
39424
+ .expectChange("defaultChannel", "test");
39425
+
39426
+ await this.createView(assert, sView, oModel);
39427
+
39428
+ this.expectChange("defaultChannel", null)
39429
+ .expectRequest("DELETE Artists(ArtistID='1',IsActiveEntity=false)");
39430
+
39431
+ const oContext = this.oView.byId("form").getBindingContext();
39432
+
39433
+ await Promise.all([
39434
+ oContext.delete(),
39435
+ oContext.getBinding().requestRefresh(),
39436
+ this.waitForChanges(assert, "delete")
39437
+ ]);
39438
+ });
39439
+
38428
39440
  //*********************************************************************************************
38429
39441
  // Scenario: Operation on reduceable path. The operation path will not be reduced, but the
38430
39442
  // reduced path must be used to access the binding parameter.
@@ -47771,6 +48783,54 @@ sap.ui.define([
47771
48783
  });
47772
48784
  });
47773
48785
 
48786
+ //*********************************************************************************************
48787
+ // Scenario: Refresh a binding with $$sharedRequest while a read request is pending.
48788
+ // BCP: 2370078660
48789
+ QUnit.test("BCP: 2370078660", async function (assert) {
48790
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true, sharedRequests : true});
48791
+ const sView = `
48792
+ <Table id="table" items="{path : '/TEAMS', suspended : true}">
48793
+ <Text id="name" text="{Name}"/>
48794
+ </Table>`;
48795
+
48796
+ this.expectChange("name", []);
48797
+
48798
+ await this.createView(assert, sView, oModel);
48799
+
48800
+ let fnResolve;
48801
+ const oResponsePromise = new Promise((resolve) => { fnResolve = resolve; });
48802
+ this.expectRequest("TEAMS?$select=Name,Team_Id&$skip=0&$top=100", oResponsePromise);
48803
+
48804
+ const oBinding = this.oView.byId("table").getBinding("items");
48805
+ oBinding.resume();
48806
+
48807
+ await this.waitForChanges(assert, "resume");
48808
+
48809
+ this.expectCanceledError(
48810
+ "Failed to get contexts for /sap/opu/odata4/IWBEP/TEA/default/IWBEP/TEA_BUSI/0001"
48811
+ + "/TEAMS with start index 0 and length 100",
48812
+ "Request is obsolete")
48813
+ .expectCanceledError(
48814
+ "Failed to get contexts for /sap/opu/odata4/IWBEP/TEA/default/IWBEP/TEA_BUSI/0001"
48815
+ + "/TEAMS with start index 0 and length 100",
48816
+ "Request is obsolete")
48817
+ .expectRequest("TEAMS?$select=Name,Team_Id&$skip=0&$top=100", {
48818
+ value : [
48819
+ {Team_Id : "1", Name : "Team #1"},
48820
+ {Team_Id : "2", Name : "Team #2"}
48821
+ ]
48822
+ })
48823
+ .expectChange("name", ["Team #1", "Team #2"]);
48824
+
48825
+ const oRefreshPromise = oBinding.requestRefresh();
48826
+ fnResolve(); // no need to give a result; it will be obsoleted anyway
48827
+
48828
+ await Promise.all([
48829
+ oRefreshPromise,
48830
+ this.waitForChanges(assert, "refresh while resume request is pending")
48831
+ ]);
48832
+ });
48833
+
47774
48834
  //*********************************************************************************************
47775
48835
  // Scenario: Absolute property bindings for $count
47776
48836
  // 1. Refresh a simple absolute property binding for $count.
@@ -51957,6 +53017,69 @@ sap.ui.define([
51957
53017
  });
51958
53018
  });
51959
53019
 
53020
+ //*********************************************************************************************
53021
+ // Scenario: A list of teams with an expanded list of employees. Create a team and show it in
53022
+ // the object page. This object page has another employee table w/ own requests. Immediately
53023
+ // (before it starts reading) create an employee in this list.
53024
+ // BCP: 2380101762
53025
+ QUnit.test("BCP: 2380101762", async function (assert) {
53026
+ const oModel = this.createTeaBusiModel({autoExpandSelect : true});
53027
+ const sView = `
53028
+ <Table id="teams" items="{/TEAMS}">
53029
+ <Text id="teamId" text="{Team_Id}"/>
53030
+ <List items="{path : 'TEAM_2_EMPLOYEES', templateShareable : true}">
53031
+ <CustomListItem>
53032
+ <Text text="{ID}"/>
53033
+ </CustomListItem>
53034
+ </List>
53035
+ </Table>
53036
+ <FlexBox id="objectPage">
53037
+ <Table id="employees" items="{path : 'TEAM_2_EMPLOYEES', parameters : {$$ownRequest : true}}">
53038
+ <Text id="employeeId" text="{ID}"/>
53039
+ </Table>
53040
+ </FlexBox>
53041
+ `;
53042
+ this.expectRequest("TEAMS?$select=Team_Id&$expand=TEAM_2_EMPLOYEES($select=ID)"
53043
+ + "&$skip=0&$top=100",
53044
+ {value : []})
53045
+ .expectChange("teamId", [])
53046
+ .expectChange("employeeId", []);
53047
+
53048
+ await this.createView(assert, sView, oModel);
53049
+
53050
+ this.expectChange("teamId", ["new"])
53051
+ .expectRequest({
53052
+ method : "POST",
53053
+ url : "TEAMS",
53054
+ payload : {Team_Id : "new", TEAM_2_EMPLOYEES : []}
53055
+ }, {Team_Id : "new", TEAM_2_EMPLOYEES : []});
53056
+
53057
+ const oTeamContext = this.oView.byId("teams").getBinding("items").create(
53058
+ {Team_Id : "new", TEAM_2_EMPLOYEES : []});
53059
+
53060
+ await Promise.all([
53061
+ oTeamContext,
53062
+ this.waitForChanges(assert, "create team")
53063
+ ]);
53064
+
53065
+ this.expectChange("employeeId", ["E1"])
53066
+ .expectRequest({
53067
+ method : "POST",
53068
+ url : "TEAMS('new')/TEAM_2_EMPLOYEES",
53069
+ payload : {ID : "E1"}
53070
+ }, {ID : "E1", Team_Id : "new"})
53071
+ // the binding does not get the data from the deep create using another binding
53072
+ .expectRequest("TEAMS('new')/TEAM_2_EMPLOYEES?$select=ID&$skip=0&$top=100",
53073
+ {value : []});
53074
+
53075
+ this.oView.byId("objectPage").setBindingContext(oTeamContext);
53076
+
53077
+ await Promise.all([
53078
+ this.oView.byId("employees").getBinding("items").create({ID : "E1"}, true),
53079
+ this.waitForChanges(assert, "create employee")
53080
+ ]);
53081
+ });
53082
+
51960
53083
  //*********************************************************************************************
51961
53084
  // Scenario:
51962
53085
  // (1) Binding for a part of a structural instance annotation works without binding the
@@ -53316,7 +54439,7 @@ sap.ui.define([
53316
54439
  // modify internal states of the binding. Calling ODLB#getLength afterwards works as expected.
53317
54440
  //
53318
54441
  // Simulate a possible infinite loop here.
53319
- // If a t:Table (with MDCTable wrapper) uses VisibleRowCountMode=Auto, then there is a "change"
54442
+ // If a t:Table (with MDCTable wrapper) uses rowMode=Auto, then there is a "change"
53320
54443
  // listener in RowMode#updateTable. It calls ODLB#getContexts (which calls fetchContexts ->
53321
54444
  // createContexts -> modifies bLengthFinal) and fires a "rowsUpdated" event, where another
53322
54445
  // listener in MDCTable#_handleUpdateFinished reacts on. That listener calls