// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2010 Sprout Systems, Inc. and contributors. // portions copyright ©2011 Apple Inc. // License: Licensed under MIT license (see license.js) // ========================================================================== /*global equals, module, test */ /* Tests SplitView methods; specifically, the API that users of SplitView use (not the methods that they may override). The methods tested are: - getPositionForChild - adjustPositionForChild They are tested in several different ways, with child views configured in many different ways. We also run the entire test suite twice: once in each orientation. The numbers should be the same either way. In the ui tests, we test that they get applied properly. */ function setupTestSuite(layoutDirection) { var splitView, left, right, middleLeft, middleRight; module( "SplitView " + (layoutDirection === SC.HORIZONTAL_LAYOUT ? "Horizontal" : "Vertical") + " - Methods", { setup: function () { SC.RunLoop.begin(); // we test with no split divider because we want to easily calculate layout. splitView = SC.SplitView.create({ childViews: [ SC.View.create(SC.SplitChild, { canCollapse: YES, collapseAtSize: 50 }), SC.View.create(SC.SplitChild, { canCollapse: YES, collapseAtSize: 50 }) ], layout: { left: 0, top: 0, width: 500, height: 500 }, layoutDirection: layoutDirection, splitDividerView: null }); SC.RunLoop.end(); left = splitView.childViews[0]; right = splitView.childViews[1]; }, teardown: function () { } }); test("Initial positions are correct", function () { equals(splitView.childViews.length, 2, "SplitView has 2 children"); equals(splitView.getPositionForChild(left), 0, "Left should always be at 0"); equals(splitView.getPositionForChild(right), 250, "Right should be at 1/2: 50"); }); test("Can adjust position for a child", function () { var result = splitView.adjustPositionForChild(right, 100); equals(result, 100, "Result of adjustPositionForChild(right, 100)"); equals(left.get('position'), 0, "Left position (should always be 0)"); equals(left.get('size'), 100, "Left size"); equals(right.get('position'), 100, "Right position"); equals(right.get('size'), 400, "Right size"); }); test("SplitView - Methods: Minimum and Maximum widths and heights", function () { // first, test with the built-in minimum size var result = splitView.adjustPositionForChild(right, 80); equals(result, 100, "Result of adjustPositionForChild(right, 80)"); equals(left.get('position'), 0, "Left position (should always be 0)"); equals(left.get('size'), 100, "Left size"); equals(right.get('position'), 100, "Right position"); equals(right.get('size'), 400, "Right size"); // now, add a max and test that left.set('maximumSize', 150); result = splitView.adjustPositionForChild(right, 180); equals(result, 150, "Result of adjustPositionForChild(right, 180) when left's max size = 150"); equals(left.get('position'), 0, "Left position (should always be 0)"); equals(left.get('size'), 150, "Left size"); equals(right.get('position'), 150, "Right position"); equals(right.get('size'), 350, "Right size"); // and now go back to middle result = splitView.adjustPositionForChild(right, 130); equals(result, 130, "Result of adjustPositionForChild(right, 130) when left's max size = 150"); equals(left.get('position'), 0, "Left position (should always be 0)"); equals(left.get('size'), 130, "Left size"); equals(right.get('position'), 130, "Right position"); equals(right.get('size'), 370, "Right size"); }); test("SplitView - Methods: Collapsing a child", function () { var result = splitView.adjustPositionForChild(right, 40); // first was collapsed, so position of seconds is now at 0. equals(result, 0, "Result of adjustPositionForChild(right, 40)"); equals(left.get('position'), 0, "Left position (should always be 0)"); equals(left.get('size'), 0, "Left size after collapsing"); equals(right.get('position'), 0, "Right position"); equals(right.get('size'), 500, "Right size"); }); module( "SplitView 4-pane " + (layoutDirection === SC.HORIZONTAL_LAYOUT ? "Horizontal" : "Vertical") + " - Methods", { setup: function () { SC.RunLoop.begin(); // we test with no split divider because we want to easily calculate layout. splitView = SC.SplitView.create({ childViews: [ SC.View.create(SC.SplitChild, { canCollapse: YES, collapseAtSize: 50, autoResizeStyle: SC.RESIZE_MANUAL }), SC.View.create(SC.SplitChild, { autoResizeStyle: SC.RESIZE_AUTOMATIC }), SC.View.create(SC.SplitChild, { autoResizeStyle: SC.RESIZE_AUTOMATIC }), SC.View.create(SC.SplitChild, { autoResizeStyle: SC.FIXED_SIZE, canCollapse: YES, collapseAtSize: 50 }) ], layout: { left: 0, top: 0, width: 800, height: 800 }, layoutDirection: layoutDirection, splitDividerView: null }); SC.RunLoop.end(); left = splitView.childViews[0]; middleLeft = splitView.childViews[1]; middleRight = splitView.childViews[2]; right = splitView.childViews[3]; } }); function confirmPositions() { for (var i = 0; i < arguments.length; i++) { equals(splitView.childViews[i].get('position'), arguments[i]); } } test("Initial positions are correct", function () { // the left and right sides do not resize unless forced to; as such, they // stay at 100. confirmPositions(0, 100, 400, 700); }); test("Repositioning handles indirectness", function () { var result; // moving within available space works result = splitView.adjustPositionForChild(middleLeft, 200); equals(result, 200, "Moved to target position successfully."); confirmPositions(0, 200, 400, 700); // indirect being turned off for the next view, moving past min size // for middleLeft should still work because it is an immediate sibling result = splitView.adjustPositionForChild(middleLeft, 400); equals(result, 400, "Moved to 400"); confirmPositions(0, 400, 500, 700); // moving so far as to move the fourth view, however, should not work (it is fixed size) result = splitView.adjustPositionForChild(middleLeft, 700); equals(result, 500, "Limited to 500 due to minimum sizes and because last cannot move."); confirmPositions(0, 500, 600, 700); // changing last from fixed should not allow it through if indirect is not allowed right.set('autoResizeStyle', SC.RESIZE_AUTOMATIC); right.set('allowsIndirectAdjustments', NO); result = splitView.adjustPositionForChild(middleLeft, 700); equals(result, 500, "Limited to 500 due to minimum sizes and because last cannot move."); confirmPositions(0, 500, 600, 700); // but it should work if indirect _is_ allowed (rightmost should collapse) right.set('allowsIndirectAdjustments', YES); result = splitView.adjustPositionForChild(middleLeft, 700); equals(result, 600, "Limited to 600 due to minimum sizes and because last collapses."); confirmPositions(0, 600, 700, 800); }); test("Repositioning without compensation", function () { // first, disable all compensation left.set('compensatesForMovement', NO); middleLeft.set('compensatesForMovement', NO); middleRight.set('compensatesForMovement', NO); right.set('compensatesForMovement', NO); var result; // repositioning middle-left should fail because rightmost can't move. result = splitView.adjustPositionForChild(middleLeft, 800); equals(result, 100, "Failed to move to target because compensation is off."); confirmPositions(0, 100, 400, 700); // turning compensation on for second-to-right makes _it_ move to max middleRight.set('compensatesForMovement', YES); result = splitView.adjustPositionForChild(middleLeft, 800); equals(result, 300, "Moved to min width of middleRight"); confirmPositions(0, 300, 600, 700); }); test("Resizing split view", function () { SC.RunLoop.begin(); // note: we test both horizontal and vertical splitView.adjust('width', 1600); splitView.adjust('height', 1600); SC.RunLoop.end(); // should have resized the auto resizable parts confirmPositions(0, 100, 800, 1500); // manually resize left part; we're going to test that, when it gets small enough, // even the RESIZE_MANUAL will change sizes splitView.adjustPositionForChild(middleLeft, 300); // so now, just to be clear, the positions should be: confirmPositions(0, 300, 800, 1500); // so, if we now resize to _really really tiny_ SC.RunLoop.begin(); splitView.adjust('width', 400); splitView.adjust('height', 400); SC.RunLoop.end(); // we should see that even the RESIZE_MANUAL has resized. confirmPositions(0, 100, 200, 300); // and if we shrink further still... SC.RunLoop.begin(); splitView.adjust('width', 300); splitView.adjust('height', 300); SC.RunLoop.end(); // there should be change, because the left side collapses. confirmPositions(0, 0, 100, 200); // and if we shrink further still... SC.RunLoop.begin(); splitView.adjust('width', 200); splitView.adjust('height', 200); SC.RunLoop.end(); // there should be no change confirmPositions(0, 0, 100, 200); // and if we shrink further still, way beyond the smallest it can get... SC.RunLoop.begin(); splitView.adjust('width', 100); splitView.adjust('height', 100); SC.RunLoop.end(); // there should be no change confirmPositions(0, 0, 100, 200); }); test("Fitting to fill disabled", function () { splitView.set('shouldResizeChildrenToFit', NO); // so, first thing: Resize, and ensure things are where they started. SC.RunLoop.begin(); // note: we test both horizontal and vertical splitView.adjust('width', 1600); splitView.adjust('height', 1600); SC.RunLoop.end(); confirmPositions(0, 100, 400, 700); // now, move one, and see that compensation, etc. still works properly splitView.adjustPositionForChild(middleLeft, 500); confirmPositions(0, 500, 600, 700); // move back, and make sure compensation still took effect splitView.adjustPositionForChild(middleLeft, 100); confirmPositions(0, 100, 600, 700); // disable compensation and move again middleLeft.set('compensatesForMovement', NO); middleRight.set('compensatesForMovement', NO); right.set('compensatesForMovement', NO); splitView.adjustPositionForChild(middleLeft, 500); confirmPositions(0, 500, 1000, 1100); // disable indirect for last item and check that movement cannot occur right.set('allowsIndirectAdjustments', NO); var result = splitView.adjustPositionForChild(middleLeft, 700); equals(result, 500, "Should not be able to move (last does not allow indirect adjustments)"); confirmPositions(0, 500, 1000, 1100); result = splitView.adjustPositionForChild(middleLeft, 200); equals(result, 500, "Should not be able to move (last does not allow indirect adjustments)"); confirmPositions(0, 500, 1000, 1100); }); } setupTestSuite(SC.LAYOUT_HORIZONTAL); setupTestSuite(SC.LAYOUT_VERTICAL);