| 'use strict'; |
| |
| function assert_px_equals(observed, expected, description) { |
| assert_equals(observed.unit, 'px', |
| `Unexpected unit type for '${description}'`); |
| assert_approx_equals(observed.value, expected, 0.0001, |
| `Unexpected value for ${description}`); |
| } |
| |
| function CreateViewTimelineOpacityAnimation(test, target, options) { |
| const timeline_options = { |
| subject: target, |
| axis: 'block' |
| }; |
| if (options && 'timeline' in options) { |
| for (let key in options.timeline) { |
| timeline_options[key] = options.timeline[key]; |
| } |
| } |
| const animation_options = { |
| timeline: new ViewTimeline(timeline_options) |
| }; |
| if (options && 'animation' in options) { |
| for (let key in options.animation) { |
| animation_options[key] = options.animation[key]; |
| } |
| } |
| |
| const anim = |
| target.animate({ opacity: [0.3, 0.7] }, animation_options); |
| test.add_cleanup(() => { |
| anim.cancel(); |
| }); |
| return anim; |
| } |
| |
| // Verify that range specified in the options aligns with the active range of |
| // the animation. |
| // |
| // Sample call: |
| // await runTimelineBoundsTest(t, { |
| // timeline: { inset: [ CSS.percent(0), CSS.percent(20)] }, |
| // timing: { fill: 'both' } |
| // startOffset: 600, |
| // endOffset: 900 |
| // }); |
| async function runTimelineBoundsTest(t, options, message) { |
| const scrollOffsetProp = options.axis == 'block' ? 'scrollTop' : 'scrollLeft'; |
| container[scrollOffsetProp] = 0; |
| await waitForNextFrame(); |
| |
| const anim = |
| options.anim || |
| CreateViewTimelineOpacityAnimation(t, target, options); |
| if (options.timing) |
| anim.effect.updateTiming(options.timing); |
| |
| const timeline = anim.timeline; |
| await anim.ready; |
| |
| // Advance to the start offset, which triggers entry to the active phase. |
| container[scrollOffsetProp] = options.startOffset; |
| await waitForNextFrame(); |
| assert_equals(getComputedStyle(target).opacity, '0.3', |
| `Effect at the start of the active phase: ${message}`); |
| |
| // Advance to the midpoint of the animation. |
| container[scrollOffsetProp] = (options.startOffset + options.endOffset) / 2; |
| await waitForNextFrame(); |
| assert_equals(getComputedStyle(target).opacity,'0.5', |
| `Effect at the midpoint of the active range: ${message}`); |
| |
| // Advance to the end of the animation. |
| container[scrollOffsetProp] = options.endOffset; |
| await waitForNextFrame(); |
| assert_equals(getComputedStyle(target).opacity, '0.7', |
| `Effect is in the active phase at effect end time: ${message}`); |
| |
| // Return the animation so that we can continue testing with the same object. |
| return anim; |
| } |
| |
| // Sets the start and end range for a view timeline and ensures that the |
| // range aligns with expected values. |
| // |
| // Sample call: |
| // await runTimelineRangeTest(t, { |
| // rangeStart: { rangeName: 'cover', offset: CSS.percent(0) } , |
| // rangeEnd: { rangeName: 'cover', offset: CSS.percent(100) }, |
| // startOffset: 600, |
| // endOffset: 900 |
| // }); |
| async function runTimelineRangeTest(t, options) { |
| const rangeToString = range => { |
| const parts = []; |
| if (range.rangeName) |
| parts.push(range.rangeName); |
| if (range.offset) |
| parts.push(`${range.offset.value}%`); |
| return parts.join(' '); |
| }; |
| const range = |
| `${rangeToString(options.rangeStart)} to ` + |
| `${rangeToString(options.rangeEnd)}`; |
| |
| options.timeline = { |
| axis: options.axis || 'inline' |
| }; |
| options.animation = { |
| rangeStart: options.rangeStart, |
| rangeEnd: options.rangeEnd, |
| }; |
| options.timing = { |
| // Set fill to accommodate floating point precision errors at the |
| // endpoints. |
| fill: 'both' |
| }; |
| |
| return runTimelineBoundsTest(t, options, range); |
| } |
| |
| // Sets the Inset for a view timeline and ensures that the range aligns with |
| // expected values. |
| // |
| // Sample call: |
| // await runTimelineInsetTest(t, { |
| // inset: [ CSS.px(20), CSS.px(40) ] |
| // startOffset: 600, |
| // endOffset: 900 |
| // }); |
| async function runTimelineInsetTest(t, options) { |
| options.timeline = { |
| axis: 'inline', |
| inset: options.inset |
| }; |
| options.timing = { |
| // Set fill to accommodate floating point precision errors at the |
| // endpoints. |
| fill: 'both' |
| } |
| const length = options.inset.length; |
| const range = |
| (options.inset instanceof Array) ? options.inset.join(' ') |
| : options.inset; |
| return runTimelineBoundsTest(t, options, range); |
| } |