Skip to content

Commit

Permalink
feat: reachability test may be enabled/disabled via user-supplied fun…
Browse files Browse the repository at this point in the history
…ction (#513)

* feat: Add reachabilityShouldRun configuration
* fix: eventListenerCallbacks and fetch spec
* docs: Update README.md
* test: Add comment for fetch spec
  • Loading branch information
YimingIsCOLD committed Nov 7, 2021
1 parent 881c5cf commit 83c1e0d
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 25 deletions.
17 changes: 10 additions & 7 deletions README.md
Expand Up @@ -301,13 +301,14 @@ Describes the current generation of the `cellular` connection. It is an enum wit
#### `NetInfoConfiguration`
The configuration options for the library.

| Property | Type | Description |
| ---------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reachabilityUrl` | `string` | The URL to call to test if the internet is reachable. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityTest` | `(response: Response) => boolean` | A function which is passed the `Response` from calling the reachability URL. It should return `true` if the response indicates that the internet is reachable. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityShortTimeout` | `number` | The number of milliseconds between internet reachability checks when the internet was not previously detected. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityLongTimeout` | `number` | The number of milliseconds between internet reachability checks when the internet was previously detected. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityRequestTimeout` | `number` | The number of milliseconds that a reachability check is allowed to take before failing. Only used on platforms which do not supply internet reachability natively. |
| Property | Type | Default | Description
| ---------------------------- | --------------------------------- | ----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reachabilityUrl` | `string` | `https://clients3.google.com/generate_204` | The URL to call to test if the internet is reachable. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityTest` | `(response: Response) => boolean` | `Promise.resolve(response.status === 204)` | A function which is passed the `Response` from calling the reachability URL. It should return `true` if the response indicates that the internet is reachable. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityShortTimeout` | `number` | 5 seconds | The number of milliseconds between internet reachability checks when the internet was not previously detected. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityLongTimeout` | `number` | 60 seconds | The number of milliseconds between internet reachability checks when the internet was previously detected. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityRequestTimeout` | `number` | 15 seconds | The number of milliseconds that a reachability check is allowed to take before failing. Only used on platforms which do not supply internet reachability natively. |
| `reachabilityShouldRun` | `() => boolean` | `() => true` | A function which returns a boolean to determine if checkInternetReachability should be run.

### Methods

Expand All @@ -325,6 +326,7 @@ NetInfo.configure({
reachabilityLongTimeout: 60 * 1000, // 60s
reachabilityShortTimeout: 5 * 1000, // 5s
reachabilityRequestTimeout: 15 * 1000, // 15s
reachabilityShouldRun: () => true,
});
```

Expand Down Expand Up @@ -378,6 +380,7 @@ const YourComponent = () => {
reachabilityLongTimeout: 60 * 1000, // 60s
reachabilityShortTimeout: 5 * 1000, // 5s
reachabilityRequestTimeout: 15 * 1000, // 15s
reachabilityShouldRun: () => true,
});

// ...
Expand Down
100 changes: 87 additions & 13 deletions src/__tests__/eventListenerCallbacks.spec.ts
Expand Up @@ -7,30 +7,30 @@
* @format
*/

import fetchMock from 'jest-fetch-mock';
import NetInfo from '../index';
import NativeInterface from '../internal/nativeInterface';
import {DEVICE_CONNECTIVITY_EVENT} from '../internal/privateTypes';
import {NetInfoStateType, NetInfoCellularGeneration} from '../internal/types';

// Mock modules
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('jest-fetch-mock').enableMocks();
fetchMock.enableMocks();
jest.mock('../internal/nativeModule');
const mockNativeModule = jest.requireMock('../internal/nativeModule').default;

describe('react-native-community/netinfo', () => {
beforeEach(() => {
mockNativeModule.getCurrentState.mockResolvedValue({
type: NetInfoStateType.cellular,
isConnected: true,
isInternetReachable: true,
details: {
isConnectionExpensive: true,
cellularGeneration: NetInfoCellularGeneration['4g'],
},
});
beforeAll(() => {
mockNativeModule.getCurrentState.mockResolvedValue({
type: NetInfoStateType.cellular,
isConnected: true,
isInternetReachable: true,
details: {
isConnectionExpensive: true,
cellularGeneration: NetInfoCellularGeneration['4g'],
},
});
});

describe('@react-native-community/netinfo listener', () => {
describe('Event listener callbacks', () => {
it('should call the listener on listening', done => {
const listener = jest.fn();
Expand Down Expand Up @@ -254,5 +254,79 @@ describe('react-native-community/netinfo', () => {
expect(listener1).not.toBeCalled();
expect(listener2).toBeCalledWith(expectedConnectionInfo);
});

describe('with configuration options', () => {
beforeAll(() => {
// Prevent `_checkInternetReachability` from rescheduling.
jest.useFakeTimers();
});

beforeEach(() => {
fetchMock.resetMocks();
});

describe('reachabilityShouldRun', () => {
function dataProvider() {
return [
{
description: 'reachabilityShouldRun returns true',
configuration: {
reachabilityShouldRun: () => true,
},
expectedConnectionInfo: {
type: 'wifi',
isConnected: true,
details: {
isConnectionExpensive: true,
cellularGeneration: 'unknown',
},
},
expectedIsInternetReachable: null,
expectFetchToBeCalled: true,
},
{
description: 'reachabilityShouldRun returns false',
configuration: {
reachabilityShouldRun: () => false,
},
expectedConnectionInfo: {
type: 'wifi',
isConnected: true,
details: {
isConnectionExpensive: true,
cellularGeneration: 'unknown',
},
},
expectedIsInternetReachable: false,
expectFetchToBeCalled: false,
},
];
}

dataProvider().forEach(testCase => {
it(testCase.description, () => {
NetInfo.configure(testCase.configuration);

const listener = jest.fn();
NetInfo.addEventListener(listener);

NativeInterface.eventEmitter.emit(
DEVICE_CONNECTIVITY_EVENT,
testCase.expectedConnectionInfo,
);

expect(listener).toBeCalledWith({
...testCase.expectedConnectionInfo,
isInternetReachable: testCase.expectedIsInternetReachable,
});
expect(listener).toBeCalledTimes(1);

testCase.expectFetchToBeCalled
? expect(fetchMock).toHaveBeenCalled()
: expect(fetchMock).not.toHaveBeenCalled();
});
});
});
});
});
});
93 changes: 90 additions & 3 deletions src/__tests__/fetch.spec.ts
Expand Up @@ -7,17 +7,21 @@
* @format
*/

import fetchMock from 'jest-fetch-mock';
import NetInfo from '../index';
import NativeInterface from '../internal/nativeInterface';
import {NetInfoStateType, NetInfoCellularGeneration} from '../internal/types';
import {DEVICE_CONNECTIVITY_EVENT} from '../internal/privateTypes';

// Mock modules
// eslint-disable-next-line @typescript-eslint/no-var-requires
require('jest-fetch-mock').enableMocks();
fetchMock.enableMocks();
jest.mock('../internal/nativeModule');
const mockNativeModule = jest.requireMock('../internal/nativeModule').default;

beforeEach(() => {
mockNativeModule.getCurrentState.mockReset();
});

describe('@react-native-community/netinfo fetch', () => {
describe('with cellular data types', () => {
describe('4g cellular generation', () => {
Expand Down Expand Up @@ -316,7 +320,20 @@ describe('@react-native-community/netinfo fetch', () => {
it('will properly reject a promise if the connection request cannot be resolved', async () => {
const rejectionMessage = 'nope, no connection info for you';

mockNativeModule.getCurrentState.mockRejectedValue(rejectionMessage);
// Mock `_fetchCurrentState` in the State constructor.
mockNativeModule.getCurrentState.mockResolvedValueOnce({
type: NetInfoStateType.cellular,
isConnected: true,
isInternetReachable: true,
details: {
isConnectionExpensive: true,
cellularGeneration: NetInfoCellularGeneration['4g'],
},
});

mockNativeModule.getCurrentState.mockRejectedValue(
new Error(rejectionMessage),
);

try {
await NetInfo.fetch();
Expand All @@ -327,4 +344,74 @@ describe('@react-native-community/netinfo fetch', () => {
}
});
});

describe('with configuration options', () => {
beforeAll(() => {
// Prevent `_checkInternetReachability` from rescheduling.
jest.useFakeTimers();
});

beforeEach(() => {
fetchMock.resetMocks();
});

describe('reachabilityShouldRun', () => {
function dataProvider() {
return [
{
description: 'reachabilityShouldRun returns true',
configuration: {
reachabilityShouldRun: () => true,
},
expectedConnectionInfo: {
type: 'wifi',
isConnected: true,
details: {
isConnectionExpensive: true,
cellularGeneration: 'unknown',
},
},
expectedIsInternetReachable: null,
expectFetchToBeCalled: true,
},
{
description: 'reachabilityShouldRun returns false',
configuration: {
reachabilityShouldRun: () => false,
},
expectedConnectionInfo: {
type: 'wifi',
isConnected: true,
details: {
isConnectionExpensive: true,
cellularGeneration: 'unknown',
},
},
expectedIsInternetReachable: false,
expectFetchToBeCalled: false,
},
];
}

dataProvider().forEach(testCase => {
it(testCase.description, async () => {
mockNativeModule.getCurrentState.mockResolvedValue(
testCase.expectedConnectionInfo,
);

// Configure NetInfo.
NetInfo.configure(testCase.configuration);

await expect(NetInfo.fetch()).resolves.toEqual({
...testCase.expectedConnectionInfo,
isInternetReachable: testCase.expectedIsInternetReachable,
});

testCase.expectFetchToBeCalled
? expect(fetchMock).toHaveBeenCalled()
: expect(fetchMock).not.toHaveBeenCalled();
});
});
});
});
});
1 change: 1 addition & 0 deletions src/internal/defaultConfiguration.ts
Expand Up @@ -5,4 +5,5 @@ export default {
reachabilityShortTimeout: 5 * 1000, // 5s
reachabilityLongTimeout: 60 * 1000, // 60s
reachabilityRequestTimeout: 15 * 1000, // 15s
reachabilityShouldRun: (): boolean => true,
};
1 change: 1 addition & 0 deletions src/internal/defaultConfiguration.web.ts
Expand Up @@ -5,4 +5,5 @@ export default {
reachabilityShortTimeout: 5 * 1000, // 5s
reachabilityLongTimeout: 60 * 1000, // 60s
reachabilityRequestTimeout: 15 * 1000, // 15s
reachabilityShouldRun: (): boolean => true,
};
4 changes: 2 additions & 2 deletions src/internal/internetReachability.ts
Expand Up @@ -53,7 +53,7 @@ export default class InternetReachability {
this._currentTimeoutHandle = null;
}

if (expectsConnection) {
if (expectsConnection && this._configuration.reachabilityShouldRun()) {
// If we expect a connection, start the process for finding if we have one
// Set the state to "null" if it was previously false
if (!this._isInternetReachable) {
Expand All @@ -62,7 +62,7 @@ export default class InternetReachability {
// Start a network request to check for internet
this._currentInternetReachabilityCheckHandler = this._checkInternetReachability();
} else {
// If we don't expect a connection, just change the state to "false"
// If we don't expect a connection or don't run reachability check, just change the state to "false"
this._setIsInternetReachable(false);
}
};
Expand Down
1 change: 1 addition & 0 deletions src/internal/types.ts
Expand Up @@ -112,4 +112,5 @@ export interface NetInfoConfiguration {
reachabilityLongTimeout: number;
reachabilityShortTimeout: number;
reachabilityRequestTimeout: number;
reachabilityShouldRun: () => boolean;
}

0 comments on commit 83c1e0d

Please sign in to comment.