Skip to content

Commit 24cae3c

Browse files
author
Krzysztof Borowy
committed
tests: add unit tests
1 parent 967bdc9 commit 24cae3c

File tree

9 files changed

+513
-41
lines changed

9 files changed

+513
-41
lines changed

babel.config.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
module.exports = {
2-
presets: ['@babel/preset-typescript'],
2+
presets: [
3+
'@babel/preset-typescript',
4+
[
5+
'@babel/preset-env',
6+
{
7+
targets: {
8+
node: 'current',
9+
},
10+
},
11+
],
12+
],
313
plugins: [
414
'@babel/proposal-class-properties',
515
'@babel/proposal-object-rest-spread',
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import AsyncStorage from '../src/AsyncStorage';
2+
3+
class StorageMock implements IStorageBackend<any> {
4+
getSingle = jest.fn();
5+
setSingle = jest.fn();
6+
getMany = jest.fn();
7+
setMany = jest.fn();
8+
removeSingle = jest.fn();
9+
removeMany = jest.fn();
10+
getKeys = jest.fn();
11+
dropStorage = jest.fn();
12+
}
13+
14+
describe('AsyncStorage', () => {
15+
const mockedStorage = new StorageMock();
16+
17+
beforeEach(() => {
18+
jest.resetAllMocks();
19+
});
20+
21+
describe('main API', () => {
22+
it('handles basic set/read/remove calls', async () => {
23+
const as = new AsyncStorage(mockedStorage, {
24+
logger: false,
25+
errorHandler: false,
26+
});
27+
28+
const key = 'myKey';
29+
const value = {
30+
name: 'Jerry',
31+
};
32+
33+
// get
34+
await as.get(key);
35+
expect(mockedStorage.getSingle).toBeCalledWith(key, null);
36+
37+
//set
38+
await as.set(key, value);
39+
expect(mockedStorage.setSingle).toBeCalledWith(key, value, null);
40+
41+
// remove
42+
await as.remove(key);
43+
expect(mockedStorage.removeSingle).toBeCalledWith(key, null);
44+
});
45+
46+
it('handles basic multi set/read/remove calls', async () => {
47+
const keys = ['key1', 'key2', 'key3'];
48+
const keyValues = [{key1: 'value1'}, {key2: 'value2'}, {key3: 'value3'}];
49+
50+
const as = new AsyncStorage(mockedStorage, {
51+
logger: false,
52+
errorHandler: false,
53+
});
54+
55+
// set
56+
await as.setMultiple(keyValues);
57+
expect(mockedStorage.setMany).toBeCalledWith(keyValues, null);
58+
59+
// get
60+
await as.getMultiple(keys);
61+
expect(mockedStorage.getMany).toBeCalledWith(keys, null);
62+
63+
// remove
64+
await as.removeMultiple(keys);
65+
expect(mockedStorage.removeMany).toBeCalledWith(keys, null);
66+
});
67+
68+
it('handles getKeys/clearStorage/instance calls', async () => {
69+
const asyncStorage = new AsyncStorage(mockedStorage, {
70+
logger: false,
71+
errorHandler: false,
72+
});
73+
74+
// instance
75+
expect(asyncStorage.instance()).toBe(mockedStorage);
76+
77+
//drop storage
78+
await asyncStorage.clearStorage();
79+
expect(mockedStorage.dropStorage).toBeCalledTimes(1);
80+
81+
// getKeys
82+
mockedStorage.getKeys.mockImplementationOnce(() => ['key1', 'key2']);
83+
const keys = await asyncStorage.getKeys();
84+
85+
expect(keys).toEqual(['key1', 'key2']);
86+
});
87+
88+
describe('utils', () => {
89+
it('uses logger when provided', async () => {
90+
const loggerFunc = jest.fn();
91+
92+
const as = new AsyncStorage(mockedStorage, {
93+
logger: loggerFunc,
94+
errorHandler: false,
95+
});
96+
97+
await as.get('key');
98+
expect(loggerFunc).toBeCalledTimes(1);
99+
});
100+
101+
it('uses error handler when provided', async () => {
102+
const errorHandler = jest.fn();
103+
104+
const error = new Error('Fatal!');
105+
mockedStorage.getSingle.mockImplementationOnce(async () => {
106+
throw error;
107+
});
108+
109+
const as = new AsyncStorage(mockedStorage, {
110+
errorHandler,
111+
logger: false,
112+
});
113+
114+
await as.get('key');
115+
116+
expect(errorHandler).toBeCalledTimes(1);
117+
expect(errorHandler.mock.calls[0][0]).toBe(error);
118+
});
119+
});
120+
});
121+
});

core/__tests__/core.test.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import Factory from '../src/';
2+
import {simpleLogger, simpleErrorHandler} from '../src/defaults';
3+
4+
describe('AsyncStorageFactory', () => {
5+
it('Throws when tried to instantiate', () => {
6+
expect(() => new Factory()).toThrow();
7+
});
8+
});
9+
10+
describe('SimpleLogger', () => {
11+
beforeAll(() => {
12+
jest.spyOn(console, 'log').mockImplementation();
13+
});
14+
15+
beforeEach(() => {
16+
console.log.mockReset();
17+
});
18+
19+
afterAll(() => {
20+
console.log.mockRestore();
21+
});
22+
23+
it('logs basic info about action', () => {
24+
const actionInfo: LoggerAction = {
25+
action: 'save-single',
26+
key: 'MyKey',
27+
value: 'MyValue',
28+
};
29+
30+
simpleLogger(actionInfo);
31+
32+
expect(console.log).toBeCalledTimes(1);
33+
34+
const callArgs = console.log.mock.calls[0][0];
35+
expect(callArgs).toContain('[AsyncStorage]');
36+
expect(callArgs).toContain(actionInfo.key);
37+
expect(callArgs).toContain(actionInfo.value);
38+
});
39+
40+
it('handles unknown action by logging it', () => {
41+
const actionInfo: LoggerAction = {
42+
// @ts-ignore need to handle unknown
43+
action: 'unknown-action',
44+
};
45+
46+
simpleLogger(actionInfo);
47+
48+
expect(console.log).toBeCalledTimes(1);
49+
50+
const callArgs = console.log.mock.calls;
51+
expect(callArgs[0][0]).toContain('unknown-action');
52+
});
53+
});
54+
55+
describe('SimpleErrorHandler', () => {
56+
beforeAll(() => {
57+
jest.spyOn(console, 'error').mockImplementation();
58+
});
59+
60+
beforeEach(() => {
61+
console.error.mockReset();
62+
});
63+
64+
afterAll(() => {
65+
console.error.mockRestore();
66+
});
67+
it('logs error when it is a string', () => {
68+
const errorMessage = 'Fatal!';
69+
70+
simpleErrorHandler(errorMessage);
71+
72+
expect(console.error).toBeCalledTimes(1);
73+
expect(console.error.mock.calls[0][0]).toEqual(errorMessage);
74+
});
75+
76+
it('logs error when it is an Error', () => {
77+
const error = new Error('Fatal!');
78+
79+
simpleErrorHandler(error);
80+
81+
expect(console.error).toBeCalledTimes(1);
82+
expect(console.error.mock.calls[0][0]).toEqual(error.message);
83+
});
84+
});

core/src/AsyncStorage.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
2929
}
3030
}
3131

32-
async get(key: string, opts?: StorageOptions): Promise<VAL | null> {
32+
async get(key: string, opts: StorageOptions = null): Promise<VAL | null> {
3333
let value = null;
3434
try {
3535
this.log({
@@ -44,7 +44,11 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
4444
return value;
4545
}
4646

47-
async set(key: string, value: VAL, opts?: StorageOptions): Promise<void> {
47+
async set(
48+
key: string,
49+
value: VAL,
50+
opts: StorageOptions = null,
51+
): Promise<void> {
4852
try {
4953
this.log({
5054
action: 'save-single',
@@ -59,7 +63,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
5963

6064
async getMultiple(
6165
keys: Array<string>,
62-
opts?: StorageOptions,
66+
opts: StorageOptions = null,
6367
): Promise<Array<VAL | null>> {
6468
let values: Array<VAL | null> = [];
6569

@@ -78,7 +82,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
7882

7983
async setMultiple(
8084
keyValues: Array<{[key: string]: VAL}>,
81-
opts?: StorageOptions,
85+
opts: StorageOptions = null,
8286
): Promise<void> {
8387
try {
8488
this.log({
@@ -91,7 +95,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
9195
}
9296
}
9397

94-
async remove(key: string, opts?: StorageOptions): Promise<void> {
98+
async remove(key: string, opts: StorageOptions = null): Promise<void> {
9599
try {
96100
this.log({
97101
action: 'delete-single',
@@ -105,7 +109,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
105109

106110
async removeMultiple(
107111
keys: Array<string>,
108-
opts?: StorageOptions,
112+
opts: StorageOptions = null,
109113
): Promise<void> {
110114
try {
111115
this.log({
@@ -118,7 +122,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
118122
}
119123
}
120124

121-
async getKeys(opts?: StorageOptions): Promise<Array<string>> {
125+
async getKeys(opts: StorageOptions = null): Promise<Array<string>> {
122126
let keys: Array<string> = [];
123127

124128
try {
@@ -133,7 +137,7 @@ class AsyncStorage<STR extends IStorageBackend, VAL = StorageModelType<STR>> {
133137
return keys;
134138
}
135139

136-
async clearStorage(opts?: StorageOptions): Promise<void> {
140+
async clearStorage(opts: StorageOptions = null): Promise<void> {
137141
try {
138142
this.log({
139143
action: 'drop',

core/types/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,4 @@ declare const console: any;
107107

108108
declare type StorageOptions = {
109109
[key: string]: any;
110-
};
110+
} | null;

jest.config.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const commonSettings = {
2+
transform: {
3+
'^.+\\.tsx?$': 'babel-jest',
4+
},
5+
globals: {
6+
__DEV__: true,
7+
},
8+
};
9+
10+
module.exports = {
11+
projects: [
12+
{
13+
...commonSettings,
14+
displayName: 'core',
15+
roots: ['<rootDir>/core', '<rootDir>/storages/**/'],
16+
testMatch: ['<rootDir>/core/__tests__/*{.,-}test.ts'],
17+
},
18+
],
19+
};

package.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,40 @@
1616
"author": "Krzysztof Borowy <dev@krizzu.dev>",
1717
"contributors": [],
1818
"homepage": "https://github.com/react-native-community/react-native-async-storage#readme",
19-
2019
"repository": {
2120
"type": "git",
2221
"url": "https://github.com/react-native-community/react-native-async-storage.git"
2322
},
2423
"scripts": {
2524
"build": "lerna run build",
2625
"clean": "lerna run clean",
27-
"test": "yarn test:lint && yarn test:types",
26+
"test": "yarn test:lint && yarn test:unit && yarn test:types",
2827
"test:lint": "eslint core/src/** storages/**/src",
29-
"test:types": "tsc --noEmit --declaration false -emitDeclarationOnly false"
28+
"test:types": "tsc --noEmit --declaration false -emitDeclarationOnly false",
29+
"test:unit": "jest"
3030
},
3131
"devDependencies": {
3232
"@babel/cli": "7.4.4",
3333
"@babel/core": "7.4.5",
3434
"@babel/plugin-proposal-class-properties": "7.4.4",
3535
"@babel/plugin-proposal-object-rest-spread": "7.4.4",
36+
"@babel/preset-env": "7.4.5",
3637
"@babel/preset-typescript": "7.3.3",
3738
"@react-native-community/eslint-config": "0.0.5",
39+
"@types/jest": "24.0.15",
40+
"babel-jest": "24.8.0",
3841
"eslint": "5.16.0",
42+
"jest": "24.8.0",
3943
"lerna": "3.15.0",
4044
"typescript": "3.5.2"
4145
},
42-
"license": "MIT",
4346
"keywords": [
4447
"react-native",
4548
"react native",
4649
"async storage",
4750
"asyncstorage",
4851
"async-storage",
4952
"react native storage"
50-
]
53+
],
54+
"license": "MIT"
5155
}

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"esModuleInterop": true
1717
},
1818
"include": [
19+
"@types/jest",
1920
"core/src/",
2021
"core/types/",
2122
"core/__tests__/",

0 commit comments

Comments
 (0)