expectSideEffectsRefresh = () => {
			this.expectRequest(sUrlWithExpandLevels.replace("$apply=", `$apply=${sOptions}/`)
					+ "&$select=DescendantCount,DistanceFromRoot,DrillState,ID,Name"
					+ "&$count=true&$skip=0&$top=2", {
					"@odata.count" : "4",
					value : [{
						DescendantCount : "2",
						DistanceFromRoot : "0",
						DrillState : "expanded",
						ID : "1",
						Name : "Alpha"
					}, {
						DescendantCount : "0",
						DistanceFromRoot : "1",
						DrillState : "leaf",
						ID : "2",
						Name : "Beta"
					}]
				});
		}
******************************************************************************************
	// Scenario: Sorting or filtering a recursive hierarchy keeps the expand state, but not the
	// out-of-place nodes. "methods" ending with "#1" cause a full refresh and lose the expand
	// state, in all other cases it will be a side-effects refresh keeping it.
	// (1) Expand Alpha
	// (2) Create Gamma (out of place)
	// (3) Call the method (hierarchy unchanged, Alpha still expanded, Gamma no longer out of place)
	// (4) Check all contexts
	// JIRA: CPOUI5ODATAV4-2025
[
	"changeParameters#0", "changeParameters#1", "filter", "resume#0", "resume#1", "sort"
].forEach(function (sMethod) {
	QUnit.test(`Recursive Hierarchy: ${sMethod} & ExpandLevels`, async function (assert) {
		const oModel = this.createTeaBusiModel({autoExpandSelect : true});
		let sOptions = "";
		const sUrl = "EMPLOYEES?foo=bar"
			+ "&$apply=com.sap.vocabularies.Hierarchy.v1.TopLevels(HierarchyNodes=$root/EMPLOYEES"
			+ ",HierarchyQualifier='OrgChart',NodeProperty='ID',Levels=1)";
		const sUrlWithExpandLevels = sUrl.slice(0, -1)
			+ ",ExpandLevels=" + JSON.stringify([{NodeID : "1", Levels : 1}]) + ")";
		const sView = `
<t:Table id="table" rows="{path : '/EMPLOYEES',
		parameters : {
			foo : 'bar',
			$$aggregation : {
				hierarchyQualifier : 'OrgChart'
			}
		}}" threshold="0" visibleRowCount="2">
	<Text text="{= %{@$ui5.node.isExpanded} }"/>
	<Text text="{= %{@$ui5.node.level} }"/>
	<Text text="{Name}"/>
</t:Table>`;

		// 1 Alpha
		//   2 Beta
		//   3 Gamma (created)
		// 4 Delta
		const expectInitial = (sRequestUrl) => {
			this.expectRequest(sRequestUrl
					+ "&$select=DrillState,ID,Name&$count=true&$skip=0&$top=2", {
					"@odata.count" : "2",
					value : [
						{DrillState : "collapsed", ID : "1", Name : "Alpha"},
						{DrillState : "leaf", ID : "4", Name : "Delta"}
					]
				});
		};
		expectInitial(sUrl);

		await this.createView(assert, sView, oModel);

		const oTable = this.oView.byId("table");
		const oBinding = oTable.getBinding("rows");
		const oAlpha = oBinding.getCurrentContexts()[0];

		this.expectRequest("EMPLOYEES?foo=bar"
				+ "&$apply=descendants($root/EMPLOYEES,OrgChart,ID,filter(ID eq '1'),1)"
				+ "&$select=DrillState,ID,Name&$count=true&$skip=0&$top=2", {
				"@odata.count" : "1",
				value : [
					{DrillState : "leaf", ID : "2", Name : "Beta"}
				]
			});

		await Promise.all([
			oAlpha.expand(),
			this.waitForChanges(assert, "(1) expand Alpha")
		]);

		checkTable("after (1)", assert, oTable, [
			"/EMPLOYEES('1')",
			"/EMPLOYEES('2')",
			"/EMPLOYEES('4')"
		], [
			[true, 1, "Alpha"],
			[undefined, 2, "Beta"]
		]);

		this.expectRequest({
				method : "POST",
				url : "EMPLOYEES?foo=bar",
				payload : {
					"EMPLOYEE_2_MANAGER@odata.bind" : "EMPLOYEES('1')",
					Name : "Gamma"
				}
			}, {
				ID : "3",
				Name : "Gamma"
			});

		const oGamma = oBinding.create({
			"@$ui5.node.parent" : oAlpha,
			Name : "Gamma"
		}, /*bSkipRefresh