import { Assert, UnitTest } from '@ephox/bedrock-client'; import { Optional } from '@ephox/katamari'; import * as fc from 'fast-check'; import * as SliderModel from 'ephox/alloy/ui/slider/SliderModel'; interface TestData { readonly min: number; readonly max: number; readonly value: number; readonly stepSize: number; readonly snapToGrid: boolean; readonly rounded: boolean; readonly hasLedge: boolean; readonly hasRedge: boolean; } interface TestBounds { readonly left: number; readonly width: number; readonly right: number; } UnitTest.test('Atomic Test: ui.slider.SliderModelTest', () => { const maxNat = 10000000; // Math.fround only precise up to 7 digits const arb1Up = fc.nat({ max: maxNat }).map((n) => n + 1); const arbRanged = fc.nat({ max: maxNat }).chain((min) => arb1Up.chain((width) => { const max = min + width; return fc.float({ min: Math.fround(min - 1), max: Math.fround(max + 1), noNaN: true, noDefaultInfinity: true }).map(Math.fround).map((value) => ({ min, max, value })); })); const arbData = fc.tuple(arbRanged, arb1Up, fc.boolean(), fc.boolean(), fc.boolean()).map( (arr: [ { min: number; max: number; value: number }, number, boolean, boolean, boolean ]): TestData => ({ min: arr[0].min, max: arr[0].max, value: arr[0].value, stepSize: arr[1], snapToGrid: arr[2], rounded: true, // Difficult to test with this off hasLedge: arr[3], hasRedge: arr[4] }) ); const arbBounds = fc.nat({ max: maxNat }).chain((min) => arb1Up.map((width): TestBounds => ({ left: min, width, right: min + width }))); // Reducing never goes beyond min-1 fc.assert(fc.property(arbData, (data) => { const newValue = SliderModel.reduceBy(data.value, data.min, data.max, data.stepSize); Assert.eq('Checking value', true, newValue <= data.value && newValue >= data.min - 1); }), { verbose: true }); // Increasing never goes beyond max+1 fc.assert(fc.property(arbData, (data) => { const newValue = SliderModel.increaseBy(data.value, data.min, data.max, data.stepSize); Assert.eq('Checking value', true, newValue >= data.value && newValue <= data.max + 1); })); // Finding value of snapped always results in a factorable value fc.assert(fc.property(arbData, arbBounds, fc.nat({ max: maxNat }), (data, bounds, xValue) => { const args = { min: data.min, max: data.max, range: data.max - data.min, value: xValue, step: data.stepSize, snap: true, snapStart: Optional.none(), rounded: data.rounded, hasMinEdge: data.hasLedge, hasMaxEdge: data.hasRedge, minBound: bounds.left, maxBound: bounds.right, screenRange: bounds.width }; const newValue = SliderModel.findValueOf(args); const f = Math.abs((newValue - data.min) / data.stepSize); const actual = Math.floor(f) === f || newValue === data.min || newValue === data.max || newValue === data.min - 1 || newValue === data.max + 1; Assert.eq('Checking factors correctly', true, actual); })); // Finding value of snapped always results in a factorable value with a snap start fc.assert(fc.property(arbData, arbBounds, fc.nat({ max: maxNat }), fc.nat({ max: maxNat }), (data, bounds, xValue, snapOffset) => { const args = { min: data.min, max: data.max, range: data.max - data.min, value: xValue, step: data.stepSize, snap: true, snapStart: Optional.some(snapOffset + data.min), rounded: data.rounded, hasMinEdge: data.hasLedge, hasMaxEdge: data.hasRedge, minBound: bounds.left, maxBound: bounds.right, screenRange: bounds.width }; const newValue = SliderModel.findValueOf(args); const f = Math.abs((newValue - (data.min + snapOffset)) / data.stepSize); Assert.eq('Checking factors correctly: ' + newValue, true, Math.floor(f) === f || newValue === data.min || newValue === data.max || newValue === data.min - 1 || newValue === data.max + 1 ); })); // Finding value of any value always fits in the [min - 1, max + 1] range fc.assert(fc.property(arbData, arbBounds, fc.nat({ max: maxNat }), (data, bounds, xValue) => { const args = { min: data.min, max: data.max, range: data.max - data.min, value: xValue, step: data.stepSize, snap: data.snapToGrid, snapStart: Optional.none(), rounded: data.rounded, hasMinEdge: data.hasLedge, hasMaxEdge: data.hasRedge, minBound: bounds.left, maxBound: bounds.right, screenRange: bounds.width }; const newValue = SliderModel.findValueOf(args); Assert.eq( 'Assert within range: ' + newValue, true, newValue >= data.min - 1 && newValue <= data.max + 1 ); })); // Finding value of any value always fits in the [min - 1, max + 1] range with a snap start fc.assert(fc.property(arbData, arbBounds, fc.nat({ max: maxNat }), fc.nat({ max: maxNat }), (data, bounds, xValue, snapOffset) => { const args = { min: data.min, max: data.max, range: data.max - data.min, value: xValue, step: data.stepSize, snap: data.snapToGrid, snapStart: Optional.some(snapOffset + data.min <= data.max ? snapOffset + data.min : data.max), rounded: data.rounded, hasMinEdge: data.hasLedge, hasMaxEdge: data.hasRedge, minBound: bounds.left, maxBound: bounds.right, screenRange: bounds.width }; const newValue = SliderModel.findValueOf(args); Assert.eq( 'Assert within range: ' + newValue, true, newValue >= data.min - 1 && newValue <= data.max + 1 ); })); });