Mirror: 🎩 A tiny but capable push & pull stream library for TypeScript and Flow
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add tests for WonkaJs timing functions. (#17)

This PR adds tests for some of the timing operators included in the `WonkaJs` module, specifically `delay`, `throttle`, `debounce`, and `sample`. Just chipping away at test coverage and having fun learning more `wonka` / observable-based programming 😅.

It also adds `*.rei` files to our pre-commit hook and `yarn refmt` script, which I missed in #15 😞.

authored by

Parker Ziegler and committed by
Phil Plückthun
806e71e7 21e02f2f

+343 -27
+320
__tests__/wonka_test.re
··· 1626 1626 ); 1627 1627 }); 1628 1628 }); 1629 + 1630 + describe("web operators", () => { 1631 + describe("delay", () => { 1632 + open Expect; 1633 + open! Expect.Operators; 1634 + 1635 + afterEach(() => Jest.useRealTimers()); 1636 + 1637 + it("should not emit values before specified delay", () => { 1638 + Jest.useFakeTimers(); 1639 + let a = Wonka.fromList([1, 2, 3]); 1640 + 1641 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1642 + let signals = [||]; 1643 + 1644 + let source = WonkaJs.delay(200, a) |> Wonka.take(3); 1645 + 1646 + source((. signal) => 1647 + switch (signal) { 1648 + | Start(x) => 1649 + talkback := x; 1650 + x(. Pull); 1651 + | Push(_) => 1652 + ignore(Js.Array.push(signal, signals)); 1653 + talkback^(. Pull); 1654 + | End => ignore(Js.Array.push(signal, signals)) 1655 + } 1656 + ); 1657 + 1658 + expect(signals) == [||]; 1659 + }); 1660 + 1661 + it("should emit values after specified delay", () => { 1662 + Jest.useFakeTimers(); 1663 + let a = Wonka.fromList([1, 2, 3]); 1664 + 1665 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1666 + let signals = [||]; 1667 + 1668 + let source = WonkaJs.delay(200, a) |> Wonka.take(3); 1669 + 1670 + source((. signal) => 1671 + switch (signal) { 1672 + | Start(x) => 1673 + talkback := x; 1674 + x(. Pull); 1675 + | Push(_) => 1676 + ignore(Js.Array.push(signal, signals)); 1677 + talkback^(. Pull); 1678 + | End => ignore(Js.Array.push(signal, signals)) 1679 + } 1680 + ); 1681 + 1682 + Jest.runTimersToTime(400); 1683 + 1684 + expect(signals) == [|Push(1), Push(2)|]; 1685 + }); 1686 + 1687 + it("should emit an End signal when the source has emitted all values", () => { 1688 + Jest.useFakeTimers(); 1689 + let a = Wonka.fromList([1, 2, 3]); 1690 + 1691 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1692 + let signals = [||]; 1693 + 1694 + let source = WonkaJs.delay(200, a) |> Wonka.take(3); 1695 + 1696 + source((. signal) => 1697 + switch (signal) { 1698 + | Start(x) => 1699 + talkback := x; 1700 + x(. Pull); 1701 + | Push(_) => 1702 + ignore(Js.Array.push(signal, signals)); 1703 + talkback^(. Pull); 1704 + | End => ignore(Js.Array.push(signal, signals)) 1705 + } 1706 + ); 1707 + 1708 + Jest.runTimersToTime(600); 1709 + 1710 + expect(signals) == [|Push(1), Push(2), Push(3), End|]; 1711 + }); 1712 + }); 1713 + 1714 + describe("throttle", () => { 1715 + open Expect; 1716 + open! Expect.Operators; 1717 + 1718 + afterEach(() => Jest.useRealTimers()); 1719 + 1720 + it( 1721 + "should not emit values before specified throttle (but include values on leading edge)", 1722 + () => { 1723 + Jest.useFakeTimers(); 1724 + let a = Wonka.interval(100); 1725 + 1726 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1727 + let signals = [||]; 1728 + 1729 + let source = WonkaJs.throttle((. _) => 600, a) |> Wonka.take(3); 1730 + 1731 + source((. signal) => 1732 + switch (signal) { 1733 + | Start(x) => 1734 + talkback := x; 1735 + x(. Pull); 1736 + | Push(_) => 1737 + ignore(Js.Array.push(signal, signals)); 1738 + talkback^(. Pull); 1739 + | End => ignore(Js.Array.push(signal, signals)) 1740 + } 1741 + ); 1742 + 1743 + Jest.runTimersToTime(400); 1744 + 1745 + expect(signals) == [|Push(0)|]; 1746 + }, 1747 + ); 1748 + 1749 + it("should throttle emissions by the specified throttle", () => { 1750 + Jest.useFakeTimers(); 1751 + let a = Wonka.interval(100); 1752 + 1753 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1754 + let signals = [||]; 1755 + 1756 + let source = WonkaJs.throttle((. _) => 600, a) |> Wonka.take(3); 1757 + 1758 + source((. signal) => 1759 + switch (signal) { 1760 + | Start(x) => 1761 + talkback := x; 1762 + x(. Pull); 1763 + | Push(_) => 1764 + ignore(Js.Array.push(signal, signals)); 1765 + talkback^(. Pull); 1766 + | End => ignore(Js.Array.push(signal, signals)) 1767 + } 1768 + ); 1769 + 1770 + Jest.runTimersToTime(1000); 1771 + 1772 + expect(signals) == [|Push(0), Push(7)|]; 1773 + }); 1774 + 1775 + it("should emit an End signal when the source has emitted all values", () => { 1776 + Jest.useFakeTimers(); 1777 + let a = Wonka.interval(100); 1778 + 1779 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1780 + let signals = [||]; 1781 + 1782 + let source = WonkaJs.throttle((. _) => 600, a) |> Wonka.take(3); 1783 + 1784 + source((. signal) => 1785 + switch (signal) { 1786 + | Start(x) => 1787 + talkback := x; 1788 + x(. Pull); 1789 + | Push(_) => 1790 + ignore(Js.Array.push(signal, signals)); 1791 + talkback^(. Pull); 1792 + | End => ignore(Js.Array.push(signal, signals)) 1793 + } 1794 + ); 1795 + 1796 + Jest.runTimersToTime(1500); 1797 + 1798 + expect(signals) == [|Push(0), Push(7), Push(14), End|]; 1799 + }); 1800 + }); 1801 + 1802 + describe("debounce", () => { 1803 + open Expect; 1804 + open! Expect.Operators; 1805 + 1806 + afterEach(() => Jest.useRealTimers()); 1807 + 1808 + it( 1809 + "should not emit values if emitted before the debounce specified by the duration selector", 1810 + () => { 1811 + Jest.useFakeTimers(); 1812 + let a = Wonka.fromList([1, 2, 3]); 1813 + 1814 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1815 + let signals = [||]; 1816 + 1817 + let source = WonkaJs.debounce((. _) => 1000, a) |> Wonka.take(3); 1818 + 1819 + source((. signal) => 1820 + switch (signal) { 1821 + | Start(x) => 1822 + talkback := x; 1823 + x(. Pull); 1824 + | Push(_) => 1825 + ignore(Js.Array.push(signal, signals)); 1826 + talkback^(. Pull); 1827 + | End => ignore(Js.Array.push(signal, signals)) 1828 + } 1829 + ); 1830 + 1831 + Jest.runTimersToTime(500); 1832 + 1833 + expect(signals) == [||]; 1834 + }, 1835 + ); 1836 + 1837 + it("should debounce emissions based on the duration selector", () => { 1838 + Jest.useFakeTimers(); 1839 + let a = Wonka.fromList([1, 2, 3]); 1840 + 1841 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1842 + let signals = [||]; 1843 + 1844 + let source = WonkaJs.debounce((. _) => 1000, a) |> Wonka.take(3); 1845 + 1846 + source((. signal) => 1847 + switch (signal) { 1848 + | Start(x) => 1849 + talkback := x; 1850 + x(. Pull); 1851 + | Push(_) => 1852 + ignore(Js.Array.push(signal, signals)); 1853 + talkback^(. Pull); 1854 + | End => ignore(Js.Array.push(signal, signals)) 1855 + } 1856 + ); 1857 + 1858 + Jest.runTimersToTime(2000); 1859 + 1860 + expect(signals) == [|Push(1), Push(2)|]; 1861 + }); 1862 + 1863 + it("should emit an End signal when the source has emitted all values", () => { 1864 + Jest.useFakeTimers(); 1865 + let a = Wonka.fromList([1, 2, 3]); 1866 + 1867 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1868 + let signals = [||]; 1869 + 1870 + let source = WonkaJs.debounce((. _) => 1000, a) |> Wonka.take(3); 1871 + 1872 + source((. signal) => 1873 + switch (signal) { 1874 + | Start(x) => 1875 + talkback := x; 1876 + x(. Pull); 1877 + | Push(_) => 1878 + ignore(Js.Array.push(signal, signals)); 1879 + talkback^(. Pull); 1880 + | End => ignore(Js.Array.push(signal, signals)) 1881 + } 1882 + ); 1883 + 1884 + Jest.runTimersToTime(3000); 1885 + 1886 + expect(signals) == [|Push(1), Push(2), Push(3), End|]; 1887 + }); 1888 + }); 1889 + 1890 + describe("sample", () => { 1891 + open Expect; 1892 + open! Expect.Operators; 1893 + 1894 + afterEach(() => Jest.useRealTimers()); 1895 + 1896 + it("should sample the last emitted value from a source", () => { 1897 + Jest.useFakeTimers(); 1898 + let a = Wonka.interval(50); 1899 + 1900 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1901 + let signals = [||]; 1902 + 1903 + let source = WonkaJs.sample(Wonka.interval(100), a); 1904 + 1905 + source((. signal) => 1906 + switch (signal) { 1907 + | Start(x) => 1908 + talkback := x; 1909 + x(. Pull); 1910 + | Push(_) => 1911 + ignore(Js.Array.push(signal, signals)); 1912 + talkback^(. Pull); 1913 + | End => ignore(Js.Array.push(signal, signals)) 1914 + } 1915 + ); 1916 + 1917 + Jest.runTimersToTime(200); 1918 + 1919 + expect(signals) == [|Push(1), Push(3)|]; 1920 + }); 1921 + 1922 + it("should emit an End signal when the source has emitted all values", () => { 1923 + Jest.useFakeTimers(); 1924 + let a = Wonka.interval(50); 1925 + 1926 + let talkback = ref((. _: Wonka_types.talkbackT) => ()); 1927 + let signals = [||]; 1928 + 1929 + let source = WonkaJs.sample(Wonka.interval(100), a) |> Wonka.take(3); 1930 + 1931 + source((. signal) => 1932 + switch (signal) { 1933 + | Start(x) => 1934 + talkback := x; 1935 + x(. Pull); 1936 + | Push(_) => 1937 + ignore(Js.Array.push(signal, signals)); 1938 + talkback^(. Pull); 1939 + | End => ignore(Js.Array.push(signal, signals)) 1940 + } 1941 + ); 1942 + 1943 + Jest.runTimersToTime(300); 1944 + 1945 + expect(signals) == [|Push(1), Push(3), Push(5), End|]; 1946 + }); 1947 + }); 1948 + });
+3 -3
package.json
··· 26 26 "terser:cjs": "terser --config-file .terser.config.json -o ./dist/wonka.js ./dist/wonka.js", 27 27 "terser": "run-p terser:es terser:cjs", 28 28 "prettier": "prettier --write ./dist/*.js", 29 - "refmt": "bsrefmt --in-place **/**/*.re", 29 + "refmt": "bsrefmt --in-place **/**/*.{re,rei}", 30 30 "prebundle": "rimraf ./dist", 31 31 "bundle": "microbundle --external none --no-compress --no-sourcemap --format es,cjs", 32 32 "postbundle": "run-s terser prettier", ··· 65 65 "terser": "^3.14.1" 66 66 }, 67 67 "lint-staged": { 68 - "*.re": [ 68 + "*.{re, rei}": [ 69 69 "bsrefmt --in-place", 70 70 "git add" 71 71 ] ··· 92 92 "maxSize": "9 kB" 93 93 } 94 94 ] 95 - } 95 + }
+1 -1
src/operators/wonka_operator_concatMap.rei
··· 1 1 open Wonka_types; 2 2 3 - let concatMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 3 + let concatMap: ((. 'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 4 4 let concat: (array(sourceT('a)), sinkT('a)) => unit; 5 5 let concatAll: (sourceT(sourceT('a)), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_filter.rei
··· 1 1 open Wonka_types; 2 2 3 - let filter: ((.'a) => bool, sourceT('a), sinkT('a)) => unit; 3 + let filter: ((. 'a) => bool, sourceT('a), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_map.rei
··· 1 1 open Wonka_types; 2 2 3 - let map: ((.'a) => 'b, sourceT('a), sinkT('b)) => unit; 3 + let map: ((. 'a) => 'b, sourceT('a), sinkT('b)) => unit;
+1 -1
src/operators/wonka_operator_mergeMap.rei
··· 1 1 open Wonka_types; 2 2 3 - let mergeMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 3 + let mergeMap: ((. 'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 4 4 let merge: (array(sourceT('a)), sinkT('a)) => unit; 5 5 let mergeAll: (sourceT(sourceT('a)), sinkT('a)) => unit; 6 6 let flatten: (sourceT(sourceT('a)), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_onEnd.rei
··· 1 1 open Wonka_types; 2 2 3 - let onEnd: ((.unit) => unit, sourceT('a), sinkT('a)) => unit; 3 + let onEnd: ((. unit) => unit, sourceT('a), sinkT('a)) => unit;
+2 -2
src/operators/wonka_operator_onPush.rei
··· 1 1 open Wonka_types; 2 2 3 - let onPush: ((.'a) => unit, sourceT('a), sinkT('a)) => unit; 4 - let tap: ((.'a) => unit, sourceT('a), sinkT('a)) => unit; 3 + let onPush: ((. 'a) => unit, sourceT('a), sinkT('a)) => unit; 4 + let tap: ((. 'a) => unit, sourceT('a), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_onStart.rei
··· 1 1 open Wonka_types; 2 2 3 - let onStart: ((.unit) => unit, sourceT('a), sinkT('a)) => unit; 3 + let onStart: ((. unit) => unit, sourceT('a), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_scan.rei
··· 1 1 open Wonka_types; 2 2 3 - let scan: ((.'b, 'a) => 'b, 'b, sourceT('a), sinkT('b)) => unit; 3 + let scan: ((. 'b, 'a) => 'b, 'b, sourceT('a), sinkT('b)) => unit;
+1 -1
src/operators/wonka_operator_skipWhile.rei
··· 1 1 open Wonka_types; 2 2 3 - let skipWhile: ((.'a) => bool, sourceT('a), sinkT('a)) => unit; 3 + let skipWhile: ((. 'a) => bool, sourceT('a), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_switchMap.rei
··· 1 1 open Wonka_types; 2 2 3 - let switchMap: ((.'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 3 + let switchMap: ((. 'a) => sourceT('b), sourceT('a), sinkT('b)) => unit; 4 4 let switchAll: (sourceT(sourceT('a)), sinkT('a)) => unit;
+1 -1
src/operators/wonka_operator_takeWhile.rei
··· 1 1 open Wonka_types; 2 2 3 - let takeWhile: ((.'a) => bool, sourceT('a), sinkT('a)) => unit; 3 + let takeWhile: ((. 'a) => bool, sourceT('a), sinkT('a)) => unit;
+2 -2
src/sinks/wonka_sink_subscribe.rei
··· 1 1 open Wonka_types; 2 2 3 - let subscribe: ((.'a) => unit, sourceT('a)) => subscriptionT; 4 - let forEach: ((.'a) => unit, sourceT('a)) => unit; 3 + let subscribe: ((. 'a) => unit, sourceT('a)) => subscriptionT; 4 + let forEach: ((. 'a) => unit, sourceT('a)) => unit;
+1 -1
src/sources/wonka_source_make.rei
··· 1 1 open Wonka_types; 2 2 3 - let make: ((.observerT('a)) => teardownT, sinkT('a)) => unit; 3 + let make: ((. observerT('a)) => teardownT, sinkT('a)) => unit;
+2 -2
src/sources/wonka_source_primitives.rei
··· 1 1 open Wonka_types; 2 2 3 - let empty: (sinkT('a)) => unit; 4 - let never: (sinkT('a)) => unit; 3 + let empty: sinkT('a) => unit; 4 + let never: sinkT('a) => unit;
+1 -1
src/web/wonka_operator_debounce.rei
··· 1 1 open Wonka_types; 2 2 3 - let debounce: ((.'a) => int, sourceT('a), sinkT('a)) => unit; 3 + let debounce: ((. 'a) => int, sourceT('a), sinkT('a)) => unit;
+1 -1
src/web/wonka_operator_throttle.rei
··· 1 1 open Wonka_types; 2 2 3 - let throttle: ((.'a) => int, sourceT('a), sinkT('a)) => unit; 3 + let throttle: ((. 'a) => int, sourceT('a), sinkT('a)) => unit;
+1 -5
src/web/wonka_source_fromListener.rei
··· 1 1 open Wonka_types; 2 2 3 3 let fromListener: 4 - ( 5 - ('event => unit) => unit, 6 - ('event => unit) => unit, 7 - sinkT('event) 8 - ) => unit; 4 + (('event => unit) => unit, ('event => unit) => unit, sinkT('event)) => unit;