import { ApproxStructure, Assertions, GeneralSteps, Logger, Step, Waiter } from '@ephox/agar'; import { UnitTest } from '@ephox/bedrock-client'; import { Class, Css, Traverse } from '@ephox/sugar'; import * as Behaviour from 'ephox/alloy/api/behaviour/Behaviour'; import { Sliding } from 'ephox/alloy/api/behaviour/Sliding'; import * as GuiFactory from 'ephox/alloy/api/component/GuiFactory'; import { Container } from 'ephox/alloy/api/ui/Container'; import * as GuiSetup from 'ephox/alloy/test/GuiSetup'; UnitTest.asynctest('SlidingTest', (success, failure) => { const slidingStyles = [ '.test-sliding-closed { visibility: hidden; opacity: 0; }', '.test-sliding-open { visibility: visible; opacity: 1; }', '.test-sliding-width-growing { transition: width 0.9s ease, opacity 0.6s linear 0.3s }', '.test-sliding-width-shrinking { transition: opacity 0.9s ease, width 0.6s linear 0.3s, visibility 0s linear 0.9s }' ]; GuiSetup.setup((store, _doc, _body) => GuiFactory.build( Container.sketch({ dom: { styles: { 'overflow-x': 'hidden', 'background': 'blue', 'max-width': '300px', 'height': '20px' } }, components: [ { dom: { tag: 'div', styles: { width: '20px', height: '10px', transition: 'width 0.1s ease' } } } ], containerBehaviours: Behaviour.derive([ Sliding.config({ closedClass: 'test-sliding-closed', openClass: 'test-sliding-open', shrinkingClass: 'test-sliding-width-shrinking', growingClass: 'test-sliding-width-growing', dimension: { property: 'width' }, onShrunk: store.adder('onShrunk'), onStartShrink: store.adder('onStartShrink'), onGrown: store.adder('onGrown'), onStartGrow: store.adder('onStartGrow') }) ]) }) ), (doc, _body, _gui, component, store) => { const sIsNotGrowing = Step.sync(() => { Assertions.assertEq('Ensuring stopped growing', false, Class.has(component.element, 'test-sliding-width-growing')); }); const sIsNotShrinking = Step.sync(() => { Assertions.assertEq('Ensuring stopped shrinking', false, Class.has(component.element, 'test-sliding-width-shrinking')); }); const sGrowingSteps = (label: string) => Logger.t( label, GeneralSteps.sequence([ store.sAssertEq('On start growing', [ 'onStartGrow' ]), Assertions.sAssertStructure( 'Checking structure', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.not('test-sliding-width-shrinking'), arr.has('test-sliding-width-growing'), arr.not('test-sliding-closed'), arr.has('test-sliding-open') ], styles: { width: str.is('300px') } })), component.element ), Waiter.sTryUntil( 'Waiting for animation to stop (growing)', sIsNotGrowing, 10, 4000 ), Step.sync(() => { Assertions.assertEq('Checking hasGrown = true', true, Sliding.hasGrown(component)); }), store.sAssertEq('After finished growing', [ 'onStartGrow', 'onGrown' ]), store.sClear ]) ); const sShrinkingSteps = (label: string) => Logger.t( label, GeneralSteps.sequence([ store.sAssertEq('On start shrinking', [ 'onStartShrink' ]), Assertions.sAssertStructure( 'Checking structure', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('test-sliding-width-shrinking'), arr.not('test-sliding-width-growing'), arr.has('test-sliding-closed'), arr.not('test-sliding-open') ], styles: { width: str.is('0px') } })), component.element ), Waiter.sTryUntil( label + '\nWaiting for animation to stop (shrinking)', sIsNotShrinking, 10, 4000 ), Step.sync(() => { Assertions.assertEq('Checking hasGrown = false', false, Sliding.hasGrown(component)); }), store.sAssertEq('After finished shrinking', [ 'onStartShrink', 'onShrunk' ]), store.sClear ]) ); return [ GuiSetup.mAddStyles(doc, slidingStyles), Assertions.sAssertStructure( 'Checking initial structure', ApproxStructure.build((s, _str, arr) => s.element('div', { classes: [ arr.has('test-sliding-closed') ] })), component.element ), store.sClear, Step.sync(() => { Sliding.grow(component); }), sGrowingSteps('Sliding.grow'), Step.sync(() => { Sliding.shrink(component); }), sShrinkingSteps('Sliding.shrink'), Step.sync(() => { Sliding.toggleGrow(component); }), sGrowingSteps('Sliding.toggleGrow (from shrunk)'), Step.sync(() => { Sliding.toggleGrow(component); }), sShrinkingSteps('Sliding.toggleGrow (from grown)'), Step.sync(() => { Sliding.toggleGrow(component); }), sGrowingSteps('Sliding.toggleGrow (from shrunk)'), Step.sync(() => { Sliding.immediateShrink(component); }), // Steps are different because there should be no animation store.sAssertEq('On start shrinking', [ 'onStartShrink', 'onShrunk' ]), Assertions.sAssertStructure( 'Checking structure of immediate shrink', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.not('test-sliding-width-shrinking'), arr.not('test-sliding-width-growing'), arr.not('test-sliding-open'), arr.has('test-sliding-closed') ], styles: { width: str.is('0px') } })), component.element ), Step.sync(() => { Assertions.assertEq('Checking hasGrown = false (immediateShrink)', false, Sliding.hasGrown(component)); }), store.sClear, Step.sync(() => { // test firing a transitionend inside Traverse.firstChild(component.element).each((child) => { Css.set(child, 'width', '10px'); }); }), Step.wait(150), store.sAssertEq('After child has transitioned width', []), store.sClear, Step.sync(() => { Sliding.toggleGrow(component); Sliding.toggleGrow(component); }), Waiter.sTryUntil( 'toggleGrow x 2 in quick succession', store.sAssertEq('Two toggles (one after the other) should fire all events even though no transitioning occurs', [ 'onStartGrow', 'onStartShrink', 'onShrunk' ]), 10, 4000 ), store.sClear, Step.sync(() => { Sliding.immediateGrow(component); }), Logger.t( 'Sliding.immediateGrow()', GeneralSteps.sequence([ store.sAssertEq('Finished growing', [ 'onStartGrow', 'onGrown' ]), Assertions.sAssertStructure( 'Checking structure', ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.not('test-sliding-width-shrinking'), arr.not('test-sliding-width-growing'), arr.not('test-sliding-closed'), arr.has('test-sliding-open') ], styles: { width: str.is('300px') } })), component.element ), Step.sync(() => { Assertions.assertEq('Checking hasGrown = true', true, Sliding.hasGrown(component)); }), store.sClear ]) ), GuiSetup.mRemoveStyles ]; }, success, failure); });