New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@dhis2/app-service-offline

Package Overview
Dependencies
Maintainers
15
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dhis2/app-service-offline - npm Package Compare versions

Comparing version 2.9.1 to 2.9.2

138

build/cjs/lib/__tests__/online-status.test.js
"use strict";
var _react = require("@testing-library/react");
var _reactHooks = require("@testing-library/react-hooks");
var _react2 = _interopRequireDefault(require("react"));
var _onlineStatus = require("../online-status");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function wait(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
}
beforeEach(() => {

@@ -172,2 +184,128 @@ jest.restoreAllMocks();

});
it('handles debounced state change when parent component rerenders during a debounce delay', async () => {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValueOnce(true);
const events = {};
window.addEventListener = jest.fn((event, cb) => events[event] = cb);
const TestComponent = () => {
const {
online
} = (0, _onlineStatus.useOnlineStatus)({
debounceDelay: 50
});
return /*#__PURE__*/_react2.default.createElement("div", {
"data-testid": "status"
}, online ? 'on' : 'off');
};
const {
rerender
} = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(TestComponent, null));
const {
getByTestId
} = _react.screen;
expect(getByTestId('status')).toHaveTextContent('on');
await (0, _reactHooks.act)(async () => {
// Multiple events in succession
events.offline(new Event('offline'));
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // Immediately, nothing should happen
expect(getByTestId('status')).toHaveTextContent('on'); // Rerender parent component
rerender( /*#__PURE__*/_react2.default.createElement(TestComponent, null)); // Final "offline" event should still resolve
await (0, _react.waitFor)(() => expect(getByTestId('status')).toHaveTextContent('off'));
});
it('handles debounced state change when debounce delay is changed during a delay', async () => {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValueOnce(true);
const events = {};
window.addEventListener = jest.fn((event, cb) => events[event] = cb);
const TestComponent = ({
options
}) => {
const {
online
} = (0, _onlineStatus.useOnlineStatus)(options);
return /*#__PURE__*/_react2.default.createElement("div", {
"data-testid": "status"
}, online ? 'on' : 'off');
};
const {
rerender
} = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(TestComponent, {
options: {
debounceDelay: 100
}
}));
const {
getByTestId
} = _react.screen;
expect(getByTestId('status')).toHaveTextContent('on');
await (0, _reactHooks.act)(async () => {
// Multiple events in succession
events.offline(new Event('offline'));
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // Immediately, nothing should happen
expect(getByTestId('status')).toHaveTextContent('on'); // Change debounce options
rerender( /*#__PURE__*/_react2.default.createElement(TestComponent, {
options: {
debounceDelay: 50
}
})); // Final "offline" event should still resolve
await (0, _react.waitFor)(() => expect(getByTestId('status')).toHaveTextContent('off'));
});
it('debounces consistently across rerenders', async () => {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValueOnce(true);
const events = {};
window.addEventListener = jest.fn((event, cb) => events[event] = cb);
const TestComponent = () => {
const {
online
} = (0, _onlineStatus.useOnlineStatus)({
debounceDelay: 100
});
return /*#__PURE__*/_react2.default.createElement("div", {
"data-testid": "status"
}, online ? 'on' : 'off');
};
const {
rerender
} = (0, _react.render)( /*#__PURE__*/_react2.default.createElement(TestComponent, null));
const {
getByTestId
} = _react.screen;
expect(getByTestId('status')).toHaveTextContent('on');
await (0, _reactHooks.act)(async () => {
// Multiple events in succession
events.offline(new Event('offline'));
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // wait a little bit - not long enough for debounce to resolve
await wait(50);
expect(getByTestId('status')).toHaveTextContent('on'); // Rerender parent component
rerender( /*#__PURE__*/_react2.default.createElement(TestComponent, null)); // Trigger more events
await (0, _reactHooks.act)(async () => {
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // wait a little more - long enough that the first debounced callbacks
// _would_ have resolved if there weren't the second set of events
await wait(60);
expect(getByTestId('status')).toHaveTextContent('on'); // wait long enough for second set of callbacks to resolve
await (0, _react.waitFor)(() => expect(getByTestId('status')).toHaveTextContent('off'));
});
});

6

build/cjs/lib/online-status.js

@@ -27,3 +27,3 @@ "use strict";

*/
function useOnlineStatus(options) {
function useOnlineStatus(options = {}) {
// initialize state to `navigator.onLine` value

@@ -34,3 +34,3 @@ const [online, setOnline] = (0, _react.useState)(navigator.onLine); // eslint-disable-next-line react-hooks/exhaustive-deps

type
}) => setOnline(type === 'online'), (options === null || options === void 0 ? void 0 : options.debounceDelay) || 1000), [options]); // on 'online' or 'offline' events, set state
}) => setOnline(type === 'online'), options.debounceDelay || 1000), [options.debounceDelay]); // on 'online' or 'offline' events, set state

@@ -41,3 +41,3 @@ (0, _react.useEffect)(() => {

return () => {
updateState.cancel();
updateState.flush();
window.removeEventListener('online', updateState);

@@ -44,0 +44,0 @@ window.removeEventListener('offline', updateState);

@@ -0,3 +1,12 @@

import { render, screen, waitFor } from '@testing-library/react';
import { act, renderHook } from '@testing-library/react-hooks';
import React from 'react';
import { useOnlineStatus } from '../online-status';
function wait(ms) {
return new Promise(resolve => {
setTimeout(() => resolve(), ms);
});
}
beforeEach(() => {

@@ -168,2 +177,128 @@ jest.restoreAllMocks();

});
it('handles debounced state change when parent component rerenders during a debounce delay', async () => {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValueOnce(true);
const events = {};
window.addEventListener = jest.fn((event, cb) => events[event] = cb);
const TestComponent = () => {
const {
online
} = useOnlineStatus({
debounceDelay: 50
});
return /*#__PURE__*/React.createElement("div", {
"data-testid": "status"
}, online ? 'on' : 'off');
};
const {
rerender
} = render( /*#__PURE__*/React.createElement(TestComponent, null));
const {
getByTestId
} = screen;
expect(getByTestId('status')).toHaveTextContent('on');
await act(async () => {
// Multiple events in succession
events.offline(new Event('offline'));
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // Immediately, nothing should happen
expect(getByTestId('status')).toHaveTextContent('on'); // Rerender parent component
rerender( /*#__PURE__*/React.createElement(TestComponent, null)); // Final "offline" event should still resolve
await waitFor(() => expect(getByTestId('status')).toHaveTextContent('off'));
});
it('handles debounced state change when debounce delay is changed during a delay', async () => {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValueOnce(true);
const events = {};
window.addEventListener = jest.fn((event, cb) => events[event] = cb);
const TestComponent = ({
options
}) => {
const {
online
} = useOnlineStatus(options);
return /*#__PURE__*/React.createElement("div", {
"data-testid": "status"
}, online ? 'on' : 'off');
};
const {
rerender
} = render( /*#__PURE__*/React.createElement(TestComponent, {
options: {
debounceDelay: 100
}
}));
const {
getByTestId
} = screen;
expect(getByTestId('status')).toHaveTextContent('on');
await act(async () => {
// Multiple events in succession
events.offline(new Event('offline'));
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // Immediately, nothing should happen
expect(getByTestId('status')).toHaveTextContent('on'); // Change debounce options
rerender( /*#__PURE__*/React.createElement(TestComponent, {
options: {
debounceDelay: 50
}
})); // Final "offline" event should still resolve
await waitFor(() => expect(getByTestId('status')).toHaveTextContent('off'));
});
it('debounces consistently across rerenders', async () => {
jest.spyOn(navigator, 'onLine', 'get').mockReturnValueOnce(true);
const events = {};
window.addEventListener = jest.fn((event, cb) => events[event] = cb);
const TestComponent = () => {
const {
online
} = useOnlineStatus({
debounceDelay: 100
});
return /*#__PURE__*/React.createElement("div", {
"data-testid": "status"
}, online ? 'on' : 'off');
};
const {
rerender
} = render( /*#__PURE__*/React.createElement(TestComponent, null));
const {
getByTestId
} = screen;
expect(getByTestId('status')).toHaveTextContent('on');
await act(async () => {
// Multiple events in succession
events.offline(new Event('offline'));
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // wait a little bit - not long enough for debounce to resolve
await wait(50);
expect(getByTestId('status')).toHaveTextContent('on'); // Rerender parent component
rerender( /*#__PURE__*/React.createElement(TestComponent, null)); // Trigger more events
await act(async () => {
events.online(new Event('online'));
events.offline(new Event('offline'));
}); // wait a little more - long enough that the first debounced callbacks
// _would_ have resolved if there weren't the second set of events
await wait(60);
expect(getByTestId('status')).toHaveTextContent('on'); // wait long enough for second set of callbacks to resolve
await waitFor(() => expect(getByTestId('status')).toHaveTextContent('off'));
});
});

@@ -16,3 +16,3 @@ import debounce from 'lodash/debounce';

*/
export function useOnlineStatus(options) {
export function useOnlineStatus(options = {}) {
// initialize state to `navigator.onLine` value

@@ -23,3 +23,3 @@ const [online, setOnline] = useState(navigator.onLine); // eslint-disable-next-line react-hooks/exhaustive-deps

type
}) => setOnline(type === 'online'), (options === null || options === void 0 ? void 0 : options.debounceDelay) || 1000), [options]); // on 'online' or 'offline' events, set state
}) => setOnline(type === 'online'), options.debounceDelay || 1000), [options.debounceDelay]); // on 'online' or 'offline' events, set state

@@ -30,3 +30,3 @@ useEffect(() => {

return () => {
updateState.cancel();
updateState.flush();
window.removeEventListener('online', updateState);

@@ -33,0 +33,0 @@ window.removeEventListener('offline', updateState);

{
"name": "@dhis2/app-service-offline",
"description": "A runtime service for online/offline detection and offline caching",
"version": "2.9.1",
"version": "2.9.2",
"main": "./build/cjs/index.js",

@@ -36,7 +36,10 @@ "module": "./build/es/index.js",

"peerDependencies": {
"@dhis2/app-service-alerts": "2.9.1",
"@dhis2/app-service-alerts": "2.9.2",
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6"
},
"dependencies": {
"lodash": "^4.17.21"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc