diff --git a/src/__tests__/useObservable-layout.spec.ts b/src/__tests__/useObservable-layout.spec.ts
new file mode 100644
index 00000000..28dd0c77
--- /dev/null
+++ b/src/__tests__/useObservable-layout.spec.ts
@@ -0,0 +1,21 @@
+import * as React from 'react';
+import * as ReactDOM from 'react-dom';
+import { Subject } from 'rxjs';
+import { useObservable } from '..';
+import useIsomorphicLayoutEffect from '../useIsomorphicLayoutEffect';
+
+jest.mock('../useIsomorphicLayoutEffect');
+
+test('uses', async () => {
+ const subject = new Subject();
+ const container = document.createElement('div');
+
+ const Demo = ({ obs }) => {
+ const value = useObservable(obs);
+ return React.createElement(React.Fragment, {}, value);
+ };
+
+ expect(useIsomorphicLayoutEffect).toHaveBeenCalledTimes(0);
+ ReactDOM.render(React.createElement(Demo, { obs: subject }), container);
+ expect(useIsomorphicLayoutEffect).toHaveBeenCalledTimes(1);
+});
diff --git a/src/__tests__/useObservable.test.tsx b/src/__tests__/useObservable.test.tsx
index 6bba8c87..4166c986 100644
--- a/src/__tests__/useObservable.test.tsx
+++ b/src/__tests__/useObservable.test.tsx
@@ -1,7 +1,21 @@
+import * as React from 'react';
+import * as ReactDOM from 'react-dom';
import { act, renderHook } from 'react-hooks-testing-library';
import { Subject } from 'rxjs';
import { useObservable } from '..';
+let container: HTMLDivElement | null;
+
+beforeEach(() => {
+ container = document.createElement('div');
+ document.body.appendChild(container);
+});
+
+afterEach(() => {
+ document.body.removeChild(container!);
+ container = null;
+});
+
test('default initial value is undefined', () => {
const subject$ = new Subject();
const { result } = renderHook(() => useObservable(subject$));
@@ -32,4 +46,62 @@ test('returns the latest value of observables', () => {
expect(result.current).toBe(400);
});
-xtest('subscribes to observable only once', () => {});
+test('subscribes to observable only once', async () => {
+ const subject = new Subject();
+ const spy = jest.spyOn(subject, 'subscribe');
+
+ expect(spy).toHaveBeenCalledTimes(0);
+
+ const Demo = ({ obs }) => {
+ const value = useObservable(obs);
+ return <>{value}>;
+ };
+
+ ReactDOM.render(, container);
+
+ expect(spy).toHaveBeenCalledTimes(1);
+
+ await new Promise(r => setTimeout(r, 1));
+ act(() => {
+ subject.next('a');
+ });
+ await new Promise(r => setTimeout(r, 1));
+ act(() => {
+ subject.next('b');
+ });
+
+ expect(spy).toHaveBeenCalledTimes(1);
+});
+
+test('re-renders component as obsevable changes', async () => {
+ const subject = new Subject();
+
+ let cnt = 0;
+ const Demo = ({ obs }) => {
+ cnt++;
+ const value = useObservable(obs);
+ return <>{value}>;
+ };
+
+ ReactDOM.render(, container);
+
+ await new Promise(r => setTimeout(r, 1));
+ expect(cnt).toBe(1);
+ expect(container.innerHTML).toBe('');
+
+ act(() => {
+ subject.next('a');
+ });
+
+ await new Promise(r => setTimeout(r, 1));
+ expect(cnt).toBe(2);
+ expect(container.innerHTML).toBe('a');
+
+ act(() => {
+ subject.next('b');
+ });
+
+ await new Promise(r => setTimeout(r, 1));
+ expect(cnt).toBe(3);
+ expect(container.innerHTML).toBe('b');
+});