Skip to content

Commit

Permalink
WIP: add Example and TDD for ex.
Browse files Browse the repository at this point in the history
  • Loading branch information
MinaSamir11 committed Jan 19, 2021
1 parent 5ce72c3 commit adecd41
Show file tree
Hide file tree
Showing 61 changed files with 12,502 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Example/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
4 changes: 4 additions & 0 deletions Example/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: '@react-native-community',
};
73 changes: 73 additions & 0 deletions Example/.flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js

; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/

; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*

; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*

; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js

[untyped]
.*/node_modules/@react-native-community/cli/.*/.*

[include]

[libs]
node_modules/react-native/interface.js
node_modules/react-native/flow/

[options]
emoji=true

esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable

module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js

munge_underscores=true

module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError

[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error

[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import

[version]
^0.122.0
1 change: 1 addition & 0 deletions Example/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pbxproj -text
59 changes: 59 additions & 0 deletions Example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# CocoaPods
/ios/Pods/
6 changes: 6 additions & 0 deletions Example/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};
1 change: 1 addition & 0 deletions Example/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
16 changes: 16 additions & 0 deletions Example/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';

import ReviewApp from './src/screens/reviewApp';

const App = () => {
return (
<SafeAreaView style={styles.MainAppContainer}>
<ReviewApp />
</SafeAreaView>
);
};

const styles = StyleSheet.create({MainAppContainer: {flex: 1}});

export default App;
121 changes: 121 additions & 0 deletions Example/__mocks__/@react-native-async-storage/async-storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const asMock = {
__INTERNAL_MOCK_STORAGE__: {},

setItem: jest.fn(async (key, value, callback) => {
const setResult = await asMock.multiSet([[key, value]], undefined);

callback && callback(setResult);
return setResult;
}),

getItem: jest.fn(async (key, callback) => {
const getResult = await asMock.multiGet([key], undefined);

const result = getResult[0] ? getResult[0][1] : null;

callback && callback(null, result);
return result;
}),

removeItem: jest.fn((key, callback) => asMock.multiRemove([key], callback)),
mergeItem: jest.fn((key, value, callback) =>
asMock.multiMerge([[key, value]], callback),
),

clear: jest.fn(_clear),
getAllKeys: jest.fn(_getAllKeys),
flushGetRequests: jest.fn(),

multiGet: jest.fn(_multiGet),
multiSet: jest.fn(_multiSet),
multiRemove: jest.fn(_multiRemove),
multiMerge: jest.fn(_multiMerge),
useAsyncStorage: jest.fn((key) => {
return {
getItem: (...args) => asMock.getItem(key, ...args),
setItem: (...args) => asMock.setItem(key, ...args),
mergeItem: (...args) => asMock.mergeItem(key, ...args),
removeItem: (...args) => asMock.removeItem(key, ...args),
};
}),
};

async function _multiSet(keyValuePairs, callback) {
keyValuePairs.forEach((keyValue) => {
const key = keyValue[0];

asMock.__INTERNAL_MOCK_STORAGE__[key] = keyValue[1];
});
callback && callback(null);
return null;
}

async function _multiGet(keys, callback) {
const values = keys.map((key) => [
key,
asMock.__INTERNAL_MOCK_STORAGE__[key] || null,
]);
callback && callback(null, values);

return values;
}

async function _multiRemove(keys, callback) {
keys.forEach((key) => {
if (asMock.__INTERNAL_MOCK_STORAGE__[key]) {
delete asMock.__INTERNAL_MOCK_STORAGE__[key];
}
});

callback && callback(null);
return null;
}

async function _clear(callback) {
asMock.__INTERNAL_MOCK_STORAGE__ = {};

callback && callback(null);

return null;
}

async function _getAllKeys() {
return Object.keys(asMock.__INTERNAL_MOCK_STORAGE__);
}

async function _multiMerge(keyValuePairs, callback) {
keyValuePairs.forEach((keyValue) => {
const key = keyValue[0];
const value = JSON.parse(keyValue[1]);

const oldValue = JSON.parse(asMock.__INTERNAL_MOCK_STORAGE__[key]);

asMock.__INTERNAL_MOCK_STORAGE__[key] = JSON.stringify(
_deepMergeInto(oldValue, value),
);
});

callback && callback(null);
return null;
}

const _isObject = (obj) => typeof obj === 'object' && !Array.isArray(obj);
const _deepMergeInto = (oldObject, newObject) => {
const newKeys = Object.keys(newObject);
const mergedObject = oldObject;

newKeys.forEach((key) => {
const oldValue = mergedObject[key];
const newValue = newObject[key];

if (_isObject(oldValue) && _isObject(newValue)) {
mergedObject[key] = _deepMergeInto(oldValue, newValue);
} else {
mergedObject[key] = newValue;
}
});

return mergedObject;
};

module.exports = asMock;
4 changes: 4 additions & 0 deletions Example/__mocks__/react-native-in-app-review.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = {
RequestInAppReview: jest.fn(),
isAvailable: jest.fn(),
};
73 changes: 73 additions & 0 deletions Example/__tests__/useAppReview-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import {renderHook, act} from '@testing-library/react-hooks';
import useAppReview from '../src/screens/reviewApp/useAppReview';
import InAppReview from 'react-native-in-app-review';

describe('App Review Hook Behavoir', () => {
const currentDate = new Date('2021-01-10T11:01:58.135Z');
global.Date = class extends Date {
constructor(date) {
if (date) {
return super(date);
}

return currentDate;
}
};
afterAll(() => {
jest.resetModule();
});

beforeEach(() => {
jest.clearAllMocks();
});

it('should trigger InAppReview in cross platform in first time', async () => {
const expectItemSavedToAsync = ['in_App_Review', new Date().toString()];

const {result} = renderHook(() => useAppReview());

await act(() => result.current.onReview());
expect(AsyncStorage.getItem).toBeCalledWith('in_App_Review');
expect(AsyncStorage.setItem).toHaveBeenCalledWith(
...expectItemSavedToAsync,
);

expect(InAppReview.RequestInAppReview).toHaveBeenCalled();
});

it('should not trigger InAppReview before 15 days user already get InAppReview', async () => {
const expectedItem = '2021-01-05';
jest
.spyOn(AsyncStorage, 'getItem')
.mockReturnValueOnce(Promise.resolve(expectedItem));

const {result} = renderHook(() => useAppReview());

await act(() => result.current.onReview());
expect(AsyncStorage.getItem).toBeCalledWith('in_App_Review');

expect(InAppReview.RequestInAppReview).not.toHaveBeenCalled();
});

it('should trigger InAppReview after 15 days user get InAppReview and save Date to async Storage', async () => {
const expectedItem = '2021-01-26';
const expectItemSavedToAsync = ['in_App_Review', new Date().toString()];

jest
.spyOn(AsyncStorage, 'getItem')
.mockReturnValueOnce(Promise.resolve(expectedItem));

jest.spyOn(AsyncStorage, 'setItem');

const {result} = renderHook(() => useAppReview());

await act(() => result.current.onReview());

expect(AsyncStorage.getItem).toBeCalledWith('in_App_Review');
expect(AsyncStorage.setItem).toHaveBeenCalledWith(
...expectItemSavedToAsync,
);
expect(InAppReview.RequestInAppReview).toHaveBeenCalled();
});
});
Loading

0 comments on commit adecd41

Please sign in to comment.