...
 
Commits (89)
version: 2
jobs:
node:
test:
working_directory: ~/mobile-native
docker:
- image: circleci/node:10
......@@ -147,11 +147,6 @@ jobs:
name: Build release .ipa
command: fastlane buildrelease
working_directory: ios
branches:
only:
- /stable-*/
- /release-*/
- test/circle-ci
- run:
name: Upload to crashalytics
......@@ -174,11 +169,7 @@ jobs:
name: Upload to Testflight release
command: fastlane testflight
working_directory: ios
branches:
only:
- /stable-*/
- /release-*/
- test/circle-ci
sentry:
docker:
- image: getsentry/sentry-cli
......@@ -204,10 +195,16 @@ workflows:
version: 2
node-ios:
jobs:
- node
- test
- ios:
requires:
- node
- test
filters:
branches:
only:
- /^stable-*/
- /^test-*/
- test/circle-ci
- sentry:
requires:
- ios
......@@ -2,10 +2,10 @@
stages:
- test
- build
- e2e
- deploy
- i18n
- deploy
# Spec test
test:jest:
image: node:10.16.3
stage: test
......@@ -14,10 +14,12 @@ test:jest:
paths:
- node_modules/
- .jest/cache/
before_script:
- yarn install --frozen-lockfile
script:
- yarn install
- yarn test
# Upload new terms to poeditor
i18n:upload:
image: node:10.16.3
stage: i18n
......@@ -25,14 +27,15 @@ i18n:upload:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .jest/cache/
before_script:
- yarn install --frozen-lockfile
script:
- yarn install
- yarn locale upload --poeditor-key=${CI_POEDITOR_KEY} --overwrite=1
only:
refs:
- /^release-*/
# Upload new terms and remove the deleted
i18n:uploadsync:
image: node:10.16.3
stage: i18n
......@@ -40,53 +43,132 @@ i18n:uploadsync:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .jest/cache/
before_script:
- yarn install --frozen-lockfile
script:
- yarn install
- yarn locale upload --poeditor-key=${CI_POEDITOR_KEY} --overwrite=1 --sync_terms=1
only:
refs:
- /^stable-*/
- master
# Web dev version using cache and without sentry maps upload
build:android:
image: circleci/android:api-28-node
stage: build
cache:
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
- node_modules/
- android/vendor/bundle
- .gradle/caches
- .gradle/wrapper
- .android/build-cache/
before_script:
- 'sed -i ''s/^apply from: "..\/..\/node_modules\/\@sentry\/react-native\/sentry.gradle"//'' android/app/build.gradle'
- export ANDROID_SDK_HOME=$CI_PROJECT_DIR
- export GRADLE_USER_HOME="$CI_PROJECT_DIR/.gradle"
- sudo sysctl fs.inotify.max_user_watches=524288
- sudo sysctl -p
- yarn install --frozen-lockfile
- cd android
- bundle install --path=vendor/bundle
script:
- bundle exec fastlane assemble_build
- mv app/build/outputs/apk/release/app-release.apk ../Minds-$CI_COMMIT_REF_SLUG-dev.apk
artifacts:
name: "Minds APK"
paths:
- Minds-$CI_COMMIT_REF_SLUG-dev.apk
expire_in: 7 days
when: on_success
only:
refs:
- /^release-*/
# Web version (Higher version code)
build:androidproduction:
image: circleci/android:api-28-node
stage: build
before_script:
- export ANDROID_SDK_HOME=$CI_PROJECT_DIR
- export GRADLE_USER_HOME="$CI_PROJECT_DIR/.gradle"
- sudo sysctl fs.inotify.max_user_watches=524288
- sudo sysctl -p
- yarn install --frozen-lockfile
- cd android
- bundle install --path=vendor/bundle
script:
- yarn install
- bundle exec fastlane assemble_build
- mv app/build/outputs/apk/release/app-release.apk ../Minds-$CI_COMMIT_REF_SLUG.apk
artifacts:
name: "Minds APK"
paths:
- Minds-$CI_COMMIT_REF_SLUG.apk
expire_in: 7 days
when: on_success
only:
refs:
- /^stable-*/
- /^test-*/
# Play store version (Lowest version code)
build:androidproduction-playstore:
image: circleci/android:api-28-node
stage: build
before_script:
- 'sed -i ''s/^versionCode=/# versionCode=/'' android/gradle.properties'
- 'sed -i ''s/^## versionCode/versionCode/'' android/gradle.properties'
- export ANDROID_SDK_HOME=$CI_PROJECT_DIR
- export GRADLE_USER_HOME="$CI_PROJECT_DIR/.gradle"
- sudo sysctl fs.inotify.max_user_watches=524288
- sudo sysctl -p
- yarn install --frozen-lockfile
- cd android
- bundle install
- fastlane assemble_build
- cp app/build/outputs/apk/release/app-release.apk ../Minds-$CI_BUILD_REF_SLUG.apk
- bundle install --path=vendor/bundle
script:
- bundle exec fastlane assemble_build
- mv app/build/outputs/apk/release/app-release.apk ../Minds-$CI_COMMIT_REF_SLUG-play_store.apk
artifacts:
name: "Minds APK"
paths:
- Minds-$CI_BUILD_REF_SLUG.apk
- Minds-$CI_COMMIT_REF_SLUG-play_store.apk
expire_in: 7 days
when: on_success
only:
refs:
- /^stable-*/
- /^test-*/
deploy:s3:
# Deploy Web/PlayStore versions to s3 and browserstack
deploy:s3andbrowserstack:
image: minds/ci:latest
stage: deploy
script:
- echo "Upload Minds-$CI_BUILD_REF_SLUG.apk"
- aws s3 cp Minds-$CI_BUILD_REF_SLUG.apk s3://minds-repo/mobile/Minds-$CI_BUILD_REF_SLUG.apk
- echo "Upload Minds-$CI_COMMIT_REF_SLUG.apk"
- aws s3 cp Minds-$CI_COMMIT_REF_SLUG.apk s3://minds-repo/mobile/Minds-$CI_COMMIT_REF_SLUG.apk
- aws s3 cp Minds-$CI_COMMIT_REF_SLUG-play_store.apk s3://minds-repo/mobile/Minds-$CI_COMMIT_REF_SLUG-play_store.apk
- curl -u $CI_BROWSERSTACK_APIKEY -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@Minds-$CI_COMMIT_REF_SLUG.apk"
- curl -u $CI_BROWSERSTACK_APIKEY -X POST "https://api-cloud.browserstack.com/app-live/upload" -F "file=@Minds-$CI_COMMIT_REF_SLUG-play_store.apk"
dependencies:
- build:android
- build:androidproduction
- build:androidproduction-playstore
only:
refs:
- /^stable-*/
- /^test-*/
deploy:google_play:
image: minds/ci:latest
image: circleci/android:api-28-node
stage: deploy
before_script:
- cd android
- bundle install --path=vendor/bundle
- 'echo $ANDROID_PLAYSTORE_JSON | base64 --decode > app/play-store.json'
script:
- echo "Upload Minds-$CI_BUILD_REF_SLUG.apk"
- echo "Upload to the play store Minds-$CI_COMMIT_REF_SLUG-play_store.apk"
- bundle exec fastlane supply --apk ../Minds-$CI_COMMIT_REF_SLUG-play_store.apk --track beta
dependencies:
- build:android
- build:androidproduction-playstore
only:
refs:
- /^stable-*/
......
module.exports = {
"prettier.printWidth": 100,
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
semi: true,
bracketSpacing: true,
trailingComma: 'all',
};
......@@ -76,9 +76,10 @@ sqliteStorageProviderService.get();
apiService.clearCookies();
const mindsSettingsPromise = mindsService.getSettings();
// On app login (runs if the user login or if it is already logged in)
sessionService.onLogin(async () => {
const user = sessionService.getUser();
Sentry.configureScope(scope => {
......@@ -88,11 +89,9 @@ sessionService.onLogin(async () => {
logService.info('[App] Getting minds settings and onboarding progress');
// load minds settings and boosted content
await Promise.all([mindsService.getSettings(), boostedContentService.load()]);
await Promise.all([mindsSettingsPromise, boostedContentService.load()]);
logService.info('[App] updatting features');
// reload fatures on login
await featureService.updateFeatures();
// register device token into backend on login
......@@ -106,6 +105,7 @@ sessionService.onLogin(async () => {
NavigationService.navigate(sessionService.initialScreen);
// check onboarding progress and navigate if necessary
// commenting this to prevent that the app navigates to onboarding after login
stores.onboarding.getProgress();
// check update
......@@ -320,7 +320,7 @@ export default class App extends Component<Props, State> {
);
const tosModal = (
<TosModal user={stores.user} key="tosModal"/>
<TosModal user={stores.user} key="tosModal" />
)
return [ app, keychainModal, blockchainTransactionModal, tosModal];
......
......@@ -6,6 +6,7 @@
|-----------|------------------------------------------------------------------------------------------------------------------------------------|
| master | Approved code ready to merged into the next stable release. All tests should pass and be in a 'ready' state |
| stable/* | Stable builds, inherited from `release/*` branches. Fastlane automatically deploys these builds. |
| test/* | Release candidate builds, inherited from `release/*` branches. Fastlane automatically deploys these builds. |
| release/* | WIP builds. Run `fastlane run increment_version_number` upon creating the branch. |
| feat/* | New branches should be made for each Gitlab issue. Merge requests should be opened pointing towards the respective release branch. |
......@@ -54,5 +55,17 @@ Run the tests
You can use -c ios.sim.release for e2e test a production build
### Custom Release
Once the file is generated in the CI download the apk and run:
`yarn release-json path/file.apk`
This will update the release.json with this version data
Note: You have to update the change-log for the version!
Upload the file to s3 and that is it.
### _Copyright Minds 2018_
......@@ -144,6 +144,7 @@ exports[`Activity component renders correctly 1`] = `
},
}
}
testID=""
/>
<RemindAction
entity={
......
......@@ -14,6 +14,7 @@ exports[`Activity component renders correctly 1`] = `
},
]
}
testID="ActivityView"
>
<Pinned
entity={
......@@ -37,6 +38,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -97,6 +99,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -173,6 +176,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -217,6 +221,7 @@ exports[`Activity component renders correctly 1`] = `
}
}
onTranslate={[Function]}
testID=""
toggleEdit={[Function]}
/>
</View>
......@@ -277,6 +282,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -348,6 +354,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -415,6 +422,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -488,6 +496,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -554,6 +563,7 @@ exports[`Activity component renders correctly 1`] = `
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......
......@@ -37,6 +37,7 @@ exports[`Activity screen component renders correctly with an entity as param 2`]
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......@@ -88,6 +89,7 @@ exports[`Activity screen component renders correctly with an entity as param 2`]
"message": "Message",
"ownerObj": UserModel {
"__list": null,
"confirmEmail": [Function],
"guid": "824853017709780997",
"isOwner": [Function],
"subtype": false,
......
......@@ -13,12 +13,9 @@ exports[`Remind owner component renders correctly 1`] = `
}
}
>
<Icon
<Themed.Icon
color="rgb(70, 144, 214)"
name="repeat"
raised={false}
reverse={false}
reverseColor="white"
size={16}
style={
Object {
......@@ -26,7 +23,6 @@ exports[`Remind owner component renders correctly 1`] = `
"marginRight": 8,
}
}
underlayColor="white"
/>
<TouchableOpacity
activeOpacity={0.2}
......
......@@ -2,8 +2,11 @@ import 'react-native';
import React from 'react';
import { shallow } from 'enzyme';
import ForgotPassword from '../../src/auth/ForgotPassword';
import authService from '../../src/auth/AuthService';
import Button from '../../src/common/components/Button';
import Input from '../../src/common/components/Input';
jest.mock('../../src/auth/AuthService');
......@@ -32,12 +35,12 @@ describe('ForgotPassword component', () => {
// simulate user input
const render = wrapper.dive();
render.find('TextInput').forEach(child => {
render.find(Input).forEach(child => {
child.simulate('changeText', 'myFancyUsername');
});
// press send
await render.find('Button').at(1).simulate('press');
await render.find(Button).at(1).simulate('press');
// expect auth service login to be called once
expect(authService.forgot).toBeCalled();
......@@ -57,7 +60,7 @@ describe('ForgotPassword component', () => {
const render = wrapper.dive();
// press go back
await render.find('Button').at(0).simulate('press');
await render.find(Button).at(0).simulate('press');
// expect onLogin to be called once
expect(mockFn).toBeCalled();
......
......@@ -6,7 +6,6 @@ import { shallow } from 'enzyme';
import ForgotScreen from '../../src/auth/ForgotScreen';
jest.mock('../../src/auth/AuthService');
jest.mock('../../src/common/components/VideoBackground', () => 'VideoBackground');
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
......
......@@ -5,7 +5,8 @@ import { shallow } from 'enzyme';
import LoginForm from '../../src/auth/LoginForm';
import authService from '../../src/auth/AuthService';
import TextInput from '../../src/common/components/TextInput';
import Input from '../../src/common/components/Input';
import Button from '../../src/common/components/Button';
jest.mock('../../src/auth/AuthService');
......@@ -36,12 +37,12 @@ describe('LoginForm component', () => {
// simulate user input
const render = wrapper.dive();
render.find(TextInput).forEach(child => {
render.find(Input).forEach(child => {
child.simulate('changeText', 'data');
});
// press login
await render.find('Button').at(1).simulate('press');
await render.find(Button).at(0).simulate('press');
// check state
expect(wrapper.state().password).toEqual('data');
......
......@@ -2,6 +2,7 @@ import 'react-native';
import React from 'react';
import { Text, TouchableOpacity } from "react-native";
import { shallow } from 'enzyme';
import featuresService from '../../src/common/services/features.service';
import LoginScreen from '../../src/auth/LoginScreen';
......@@ -9,13 +10,16 @@ jest.mock('../../src/auth/AuthService');
jest.mock('../../src/auth/LoginForm', () => 'LoginForm');
jest.mock('../../src/auth/ForgotPassword', () => 'ForgotPassword');
jest.mock('../../src/common/components/VideoBackground', () => 'VideoBackground');
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
describe('LoginScreen component', () => {
beforeEach(() => {
featuresService.features = {'homepage-december-2019': false};
});
it('should renders correctly', () => {
const loginScreen = renderer.create(
<LoginScreen />
......@@ -25,7 +29,7 @@ describe('LoginScreen component', () => {
it('should shows login form component', async () => {
const wrapper = shallow(
<LoginScreen />
<LoginScreen hopFeatures={true} />
);
// search login form
......@@ -43,7 +47,7 @@ describe('LoginScreen component', () => {
};
const wrapper = shallow(
<LoginScreen navigation={navigation}/>
<LoginScreen navigation={navigation} hopFeatures={true} />
);
// search login form
......
......@@ -2,6 +2,7 @@ import 'react-native';
import React from 'react';
import { Alert } from "react-native";
import { shallow } from 'enzyme';
import { Button, CheckBox } from 'react-native-elements';
import RegisterForm from '../../src/auth/RegisterForm';
import authService from '../../src/auth/AuthService';
......@@ -9,6 +10,7 @@ import authService from '../../src/auth/AuthService';
jest.mock('../../src/auth/AuthService');
jest.mock('../../src/auth/UserStore');
Alert.alert = jest.fn();
// Note: test renderer must be required after react-native.
......@@ -24,7 +26,7 @@ describe('RegisterForm component', () => {
it('should renders correctly', () => {
const userStore = new UserStore();
const registerForm = renderer.create(
<RegisterForm user={userStore}/>
<RegisterForm user={userStore} />
).toJSON();
expect(registerForm).toMatchSnapshot();
});
......@@ -36,15 +38,15 @@ describe('RegisterForm component', () => {
const userStore = new UserStore();
const wrapper = shallow(
<RegisterForm user={userStore}/>
<RegisterForm user={userStore} />
);
const render = wrapper.dive();
// find the text inputs
let inputs = render.find('TextInput');
let inputs = render.find('Input');
// should have 4 inputs
// should have 3 inputs
expect(inputs.length).toBe(3);
// simulate user input
......@@ -52,20 +54,20 @@ describe('RegisterForm component', () => {
inputs.at(1).simulate('changeText', 'my@mail.com');
inputs.at(2).simulate('changeText', 'somepassword');
// simulate press checkbox
await render.find('CheckBox').at(1).simulate('press');
// update component (password confirmation is shown after the password field is set)
await wrapper.update();
// update the inputs search
inputs = render.find('TextInput');
inputs = render.find('Input');
// simulate user input for paddword confirmation
inputs.at(3).simulate('changeText', 'somepassword');
// simulate press checkbox
await render.find(CheckBox).at(0).simulate('press');
// simulate press register
await render.find('Button').at(1).simulate('press');
await render.find('Button').at(0).simulate('press');
// expect auth service register to be called once
expect(authService.register).toBeCalled();
......@@ -75,13 +77,13 @@ describe('RegisterForm component', () => {
const userStore = new UserStore();
const wrapper = shallow(
<RegisterForm user={userStore}/>
<RegisterForm user={userStore} />
);
const render = wrapper.dive();
// find the text inputs
let inputs = render.find('TextInput');
let inputs = render.find('Input');
// should have 4 inputs
expect(inputs.length).toBe(3);
......@@ -94,13 +96,13 @@ describe('RegisterForm component', () => {
await wrapper.update();
// update the inputs search
inputs = render.find('TextInput');
inputs = render.find('Input');
// simulate user input for paddword confirmation
inputs.at(3).simulate('changeText', 'ohNoItIsDifferent');
// simulate press register
await render.find('Button').at(1).simulate('press');
await render.find('Button').at(0).simulate('press');
// should call alert
expect(Alert.alert).toBeCalled();
......@@ -119,7 +121,7 @@ describe('RegisterForm component', () => {
const render = wrapper.dive();
// find the text inputs
let inputs = render.find('TextInput');
let inputs = render.find('Input');
// should have 4 inputs
expect(inputs.length).toBe(3);
......@@ -132,13 +134,13 @@ describe('RegisterForm component', () => {
await wrapper.update();
// update the inputs search
inputs = render.find('TextInput');
inputs = render.find('Input');
// simulate user input for paddword confirmation
inputs.at(3).simulate('changeText', 'somepassword');
// simulate press register
await render.find('Button').at(1).simulate('press');
await render.find('Button').at(0).simulate('press');
// should call alert
expect(Alert.alert).toBeCalled();
......
......@@ -5,7 +5,6 @@ import { shallow } from 'enzyme';
import RegisterScreen from '../../src/auth/RegisterScreen';
jest.mock('../../src/auth/RegisterForm', () => 'RegisterForm');
jest.mock('../../src/common/components/VideoBackground', () => 'VideoBackground');
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
......@@ -30,7 +29,7 @@ describe('RegisterScreen component', () => {
expect(registerForms.length).toBe(1);
});
it('should navigate on RegisterForm events', async () => {
it('should navigate on RegisterFormNew events', async () => {
const navigation = {
dispatch: jest.fn(),
......
......@@ -2,78 +2,146 @@
exports[`LoginScreen component should renders correctly 1`] = `
<View
onLayout={[Function]}
style={
Array [
Object {
"flex": 1,
},
Object {
"paddingBottom": 0,
"justifyContent": "center",
},
]
}
>
<VideoBackground />
<View
style={
Array [
Object {
"flex": 1,
"flex": 10,
"flexDirection": "row",
"justifyContent": "center",
"paddingBottom": 10,
"paddingHorizontal": 20,
"paddingTop": 20,
},
Object {
"padding": 10,
"backgroundColor": "#F5F5F5",
},
]
}
>
<View
style={
Object {
"opacity": 0,
"transform": Array [
Object {
"scale": 0.3,
},
],
}
Array [
Object {
"flex": 1,
},
Object {
"paddingTop": 10,
},
]
}
>
<Image
resizeMode="contain"
source={
Object {
"testUri": "../../../src/assets/logos/logo-white.png",
"testUri": "../../../src/assets/logos/bulb.png",
}
}
style={
Object {
"alignSelf": "center",
"height": 100,
"marginBottom": 30,
"width": 200,
"height": 59.51,
"marginTop": 10,
"width": 34.72,
}
}
/>
<LoginForm
onForgot={[Function]}
onLogin={[Function]}
/>
</View>
</View>
<View
style={
Array [
Object {
"flex": 2,
"flexDirection": "row",
"justifyContent": "center",
"paddingBottom": 20,
"paddingHorizontal": 20,
"paddingTop": 20,
},
Object {
"backgroundColor": "#EFEFEF",
},
]
}
>
<View
accessible={true}
focusable={true}
isTVSelectable={true}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"opacity": 0,
"transform": Array [
Object {
"translateY": 100,
},
],
"opacity": 1,
}
}
testID="registerButton"
>
<LoginForm
onForgot={[Function]}
onLogin={[Function]}
onRegister={[Function]}
/>
<View
style={
Object {
"alignContent": "center",
"alignItems": "center",
"flex": 1,
"flexDirection": "column",
"justifyContent": "center",
}
}
>
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 17,
"fontWeight": "500",
"lineHeight": 23,
},
Object {
"color": "#939397",
},
]
}
>
Don't have an account?
</Text>
<Text
style={
Array [
Object {
"fontFamily": "Roboto",
"fontSize": 28,
"fontWeight": "bold",
"lineHeight": 44,
},
Object {
"color": "#4F4F50",
},
]
}
>
Join Minds Now
</Text>
</View>
</View>
</View>
</View>
......
......@@ -6,33 +6,13 @@ exports[`RegisterScreen component should renders correctly 1`] = `
Array [
Object {
"flex": 1,
"justifyContent": "center",
},
Object {
"padding": 10,
},
]
}
>
<VideoBackground />
<View
style={
Object {
"opacity": 0,
"transform": Array [
Object {
"scale": 0.3,
},
],
}
}
>
<View>
<RegisterForm
onBack={[Function]}
onRegister={[Function]}
/>
</View>
</View>
<RegisterForm
onBack={[Function]}
onRegister={[Function]}
/>
</View>
`;
......@@ -80,6 +80,8 @@ exports[`blog card component should renders correctly 1`] = `
}
>
<Text
ellipsizeMode="tail"
numberOfLines={2}
style={
Array [
Object {
......@@ -88,6 +90,9 @@ exports[`blog card component should renders correctly 1`] = `
Object {
"fontWeight": "500",
},
Object {
"flex": 1,
},
]
}
>
......@@ -115,45 +120,159 @@ exports[`blog card component should renders correctly 1`] = `
<View
height={24}
style={
Array [
Object {
"backgroundColor": "transparent",
"height": 24,
"paddingBottom": 10,
"paddingRight": 10,
"paddingTop": 10,
"width": 24,
},
Object {
"borderRadius": 12,
Object {
"backgroundColor": "transparent",
"borderRadius": 17,
"height": 34,
"width": 34,
}
}
theme={
Object {
"colors": Object {
"disabled": "hsl(208, 8%, 90%)",
"divider": "#bcbbc1",
"error": "#ff190c",
"grey0": "#393e42",
"grey1": "#43484d",
"grey2": "#5e6977",
"grey3": "#86939e",
"grey4": "#bdc6cf",
"grey5": "#e1e8ee",
"greyOutline": "#bbb",
"platform": Object {
"android": Object {
"error": "#f44336",
"primary": "#2196f3",
"secondary": "#9C27B0",
"success": "#4caf50",
"warning": "#ffeb3b",
},
"ios": Object {
"error": "#ff3b30",
"primary": "#007aff",
"secondary": "#5856d6",
"success": "#4cd964",
"warning": "#ffcc00",
},
},
"primary": "#2089dc",
"searchBg": "#303337",
"secondary": "#8F0CE8",
"success": "#52c41a",
"warning": "#faad14",
},
undefined,
]
}
}
width={24}
>
<View
accessibilityIgnoresInvertColors={true}
style={
Array [
Object {
"backgroundColor": "#bdbdbd",
"borderRadius": 17,
"flex": 1,
"overflow": "hidden",
"position": "relative",
}
}
>
<Image
onLoad={[Function]}
style={
Array [
Object {
"bottom": 0,
"left": 0,
"position": "absolute",
"right": 0,
"top": 0,
},
Object {
"height": null,
"width": null,
},
]
}
testID="RNE__Image"
theme={
Object {
"colors": Object {
"disabled": "hsl(208, 8%, 90%)",
"divider": "#bcbbc1",
"error": "#ff190c",
"grey0": "#393e42",
"grey1": "#43484d",
"grey2": "#5e6977",
"grey3": "#86939e",
"grey4": "#bdc6cf",
"grey5": "#e1e8ee",
"greyOutline": "#bbb",
"platform": Object {
"android": Object {
"error": "#f44336",
"primary": "#2196f3",
"secondary": "#9C27B0",
"success": "#4caf50",
"warning": "#ffeb3b",
},
"ios": Object {
"error": "#ff3b30",
"primary": "#007aff",
"secondary": "#5856d6",
"success": "#4cd964",
"warning": "#ffcc00",
},
},
"primary": "#2089dc",
"searchBg": "#303337",
"secondary": "#8F0CE8",
"success": "#52c41a",
"warning": "#faad14",
},
}
}
/>
<View
accessibilityElementsHidden={false}
importantForAccessibility="yes"
pointerEvents="auto"
style={
Object {
"alignItems": "center",
"alignSelf": "stretch",
"backgroundColor": "rgba(0,0,0,0.2)",
"bottom": 0,
"flex": 1,
"justifyContent": "center",
"left": 0,
"opacity": 1,
"position": "absolute",
"right": 0,
"top": 0,
},
}
}
>
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "transparent",
"flex": 1,
"height": null,
"justifyContent": "center",
"width": null,
}
}
testID="RNE__Image__placeholder"
/>
</View>
<View
style={
Object {
"borderRadius": 12,
},
undefined,
]
}
/>
"flex": 1,
"height": null,
"width": null,
}
}
/>
</View>
</View>
<Text
numberOfLines={1}
......@@ -243,10 +362,12 @@ exports[`blog card component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......
......@@ -66,10 +66,12 @@ exports[`blog view screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -259,10 +261,12 @@ exports[`blog view screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -435,10 +439,12 @@ exports[`blog view screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -590,10 +596,12 @@ exports[`blog view screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -736,10 +744,12 @@ exports[`blog view screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -851,14 +861,10 @@ exports[`blog view screen component should renders correctly 1`] = `
}
}
>
<Icon
<Themed.Icon
color="#b0bec5"
name="public"
raised={false}
reverse={false}
reverseColor="white"
size={18}
underlayColor="white"
/>
<Text
style={
......@@ -880,15 +886,11 @@ exports[`blog view screen component should renders correctly 1`] = `
>
Attribution-NonCommerical CC BY-NC
</Text>
<Icon
<Themed.Icon
color="#4690D6"
name="share"
onPress={[Function]}
raised={false}
reverse={false}
reverseColor="white"
size={20}
underlayColor="white"
/>
</View>
<ForwardRef(_SafeAreaView)
......@@ -900,15 +902,12 @@ exports[`blog view screen component should renders correctly 1`] = `
}
}
>
<Icon
<Themed.Icon
color="#4690D6"
name="arrow-back"
onPress={[Function]}
raised={true}
reverse={false}
reverseColor="white"
size={22}
underlayColor="white"
/>
</ForwardRef(_SafeAreaView)>
</View>
......
......@@ -25,12 +25,9 @@ exports[`Boost action bar component renders correctly 1`] = `
}
}
>
<Icon
<Themed.Icon
color="rgb(96, 125, 139)"
name="bank"
raised={false}
reverse={false}
reverseColor="white"
size={20}
style={
Object {
......@@ -38,7 +35,6 @@ exports[`Boost action bar component renders correctly 1`] = `
}
}
type="material-community"
underlayColor="white"
/>
<Text
style={
......
......@@ -7,6 +7,7 @@ exports[`cature poster component should renders correctly 1`] = `
"flex": 1,
}
}
testID="capturePosterView"
>
<View
style={
......
......@@ -936,6 +936,7 @@ exports[`cature poster flags component should renders correctly for props false
"width": "100%",
}
}
testID="tagInput"
underlineColorAndroid="transparent"
value=""
/>
......@@ -2104,6 +2105,7 @@ exports[`cature poster flags component should renders correctly for props true 1
"width": "100%",
}
}
testID="tagInput"
underlineColorAndroid="transparent"
value=""
/>
......
......@@ -40,6 +40,7 @@ exports[`channel actions component should renders correctly 1`] = `
"padding": 4,
}
}
testID="MoreButton"
>
<Text
style={
......
......@@ -7,6 +7,7 @@ exports[`Channel screen component should renders correctly 1`] = `
"flex": 1,
}
}
testID="ChannelScreen"
>
<FeedList
emptyMessage={null}
......@@ -80,10 +81,12 @@ exports[`Channel screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -345,10 +348,12 @@ exports[`Channel screen component should renders correctly 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -471,15 +476,12 @@ exports[`Channel screen component should renders correctly 1`] = `
}
}
>
<Icon
<Themed.Icon
color="#4690D6"
name="arrow-back"
onPress={[Function]}
raised={true}
reverse={false}
reverseColor="white"
size={22}
underlayColor="white"
/>
</SafeAreaView>
<CaptureFab
......@@ -525,6 +527,7 @@ exports[`Channel screen component should renders correctly 1`] = `
},
}
}
testID="captureFab"
/>
</View>
`;
......@@ -536,6 +539,7 @@ exports[`Channel screen component should show closed channel message 1`] = `
"flex": 1,
}
}
testID="ChannelScreen"
>
<View>
<ChannelHeader
......@@ -606,10 +610,12 @@ exports[`Channel screen component should show closed channel message 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -892,10 +898,12 @@ exports[`Channel screen component should show closed channel message 1`] = `
],
"chat": true,
"city": "",
"confirmEmail": [Function],
"container_guid": "0",
"deleted": "0",
"disabled_boost": false,
"dob": "",
"email_confirmed": false,
"eth_wallet": "0x6fffffdadae350ddd5a1777d5a1777a4f39f0317",
"fb": false,
"feature_flags": false,
......@@ -968,15 +976,12 @@ exports[`Channel screen component should show closed channel message 1`] = `
}
}
>
<Icon
<Themed.Icon
color="#4690D6"
name="arrow-back"
onPress={[Function]}
raised={true}
reverse={false}
reverseColor="white"
size={22}
underlayColor="white"
/>
</SafeAreaView>
<CaptureFab
......@@ -1022,6 +1027,7 @@ exports[`Channel screen component should show closed channel message 1`] = `
},
}
}
testID="captureFab"
/>
</View>
`;
......@@ -152,6 +152,7 @@ exports[`channel header component owner should render correctly 1`] = `
>
<View
style={null}
testID="SubscribersView"
>
<Text>
SUBSCRIBERS
......@@ -161,7 +162,9 @@ exports[`channel header component owner should render correctly 1`] = `
</Text>
</View>
</View>
<View>
<View
testID="ViewsView"
>
<Text>
VIEWS
</Text>
......@@ -179,6 +182,7 @@ exports[`channel header component owner should render correctly 1`] = `
"flexDirection": "row",
}
}
testID="ChannelNameView"
>
<Text
ellipsizeMode="tail"
......@@ -234,6 +238,7 @@ exports[`channel header component owner should render correctly 1`] = `
"padding": 4,
}
}
testID="EditButton"
>
<Text
style={
......@@ -259,9 +264,21 @@ exports[`channel header component owner should render correctly 1`] = `
}
}
>
<Text
selectable={true}
/>
<View
style={
Object {
"height": undefined,
}
}
>
<Text
numberOfLines={0}
>
<Text
selectable={true}
/>
</Text>
</View>
</View>
</View>
<View
......
......@@ -93,6 +93,7 @@ exports[`channel subscribers component should render correctly 1`] = `
</View>
</View>
<RCTScrollView
ListFooterComponent={null}
data={
Array [
Object {
......
import {Alert} from 'react-native';
import remoteAction from '../../src/common/RemoteAction';
import connectivityService from '../../src/common/services/connectivity.service';
import { ApiError } from '../../src/common/services/api.service';
jest.mock('../../src/common/services/connectivity.service');
describe('remote action', () => {
Alert.alert = jest.fn();
beforeEach(() => {
Alert.alert.mockClear();
connectivityService.isConnected = true;
});
it('should not auto retry on generic error', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new Error('boom');
});
await remoteAction(action);
// should have been called
expect(action).toHaveBeenCalledTimes(1);
});
it('should auto retry on net error', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new TypeError('Network request failed');
});
await remoteAction(action);
// should have been called
expect(action).toHaveBeenCalledTimes(2);
});
it('should auto retry on net error n times', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new TypeError('Network request failed');
});
await remoteAction(action, '', 2);
// should have been called
expect(action).toHaveBeenCalledTimes(3);
});
it('should stop auto retry on success', async () => {
const action = jest.fn();
let tries = 0;
action.mockImplementation(async () => {
tries++;
if (tries > 1) {
return;
}
throw new TypeError('Network request failed');
});
await remoteAction(action, '', 2);
// should have been called
expect(action).toHaveBeenCalledTimes(2);
});
it('should show offline error message', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new TypeError('Network request failed');
});
connectivityService.isConnected = false;
await remoteAction(action, '', 0);
// should have been called
expect(action).toHaveBeenCalledTimes(1);
// should call alert with the correct messages
expect(Alert.alert.mock.calls[0][0]).toBe('Sorry!');
expect(Alert.alert.mock.calls[0][1]).toBe('No Internet Connection');
expect(Alert.alert.mock.calls[0][2][0].text).toBe('Ok');
expect(Alert.alert.mock.calls[0][2][1].text).toBe('Try again');
});
it('should show api errors message', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new ApiError('Some Error');
});
await remoteAction(action, '', 0);
// should have been called
expect(action).toHaveBeenCalledTimes(1);
// should call alert with the correct messages
expect(Alert.alert.mock.calls[0][0]).toBe('Sorry!');
expect(Alert.alert.mock.calls[0][1]).toBe('Some Error');
expect(Alert.alert.mock.calls[0][2][0].text).toBe('Ok');
expect(Alert.alert.mock.calls[0][2][1].text).toBe('Try again');
});
it('should show error message with retry on failure', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new TypeError('Network request failed');
});
await remoteAction(action, '', 0);
// should have been called
expect(action).toHaveBeenCalledTimes(1);
// should call alert with the correct messages
expect(Alert.alert.mock.calls[0][0]).toBe('Sorry!');
expect(Alert.alert.mock.calls[0][1]).toBe('Can\'t reach the server');
expect(Alert.alert.mock.calls[0][2][0].text).toBe('Ok');
expect(Alert.alert.mock.calls[0][2][1].text).toBe('Try again');
});
it('should call the action again if the user tap retry', async () => {
const action = jest.fn();
action.mockImplementation(async () => {
throw new TypeError('Network request failed');
});
await remoteAction(action, '', 0);
// should have been called
expect(action).toHaveBeenCalledTimes(1);
Alert.alert.mock.calls[0][2][1].onPress();
// should have been called again
expect(action).toHaveBeenCalledTimes(2);
});
});
import boostedContentService from "../../../src/common/services/boosted-content.service";
import FeedsService from "../../../src/common/services/feeds.service";
import blockListService from "../../../src/common/services/block-list.service";
jest.mock('../../../src/common/services/feeds.service');
jest.mock('../../../src/common/services/session.service');
jest.mock('../../../src/common/services/block-list.service');
/**
* Tests
*/
describe('Boosted content service', () => {
beforeEach(() => {
blockListService.has.mockClear();
});
it('should fetch the boosts from the server', async () => {
const fakeBoosts = [{guid: 1}, {guid: 2}, {guid: 3}];
blockListService.has.mockReturnValue(false);
const fakeBoosts = [
{guid: 1, ownerObj: {guid: 1}},
{guid: 2, ownerObj: {guid: 2}},
{guid: 3, ownerObj: {guid: 3}},
];
const result = fakeBoosts.map(e => {
e.boosted = true;
return e;
});
boostedContentService.feedsService.getEntities.mockResolvedValue(fakeBoosts);
boostedContentService.feedsService.fetchLocal.mockResolvedValue(true);
// load the boosts
await boostedContentService.load();
// should fetch the feed
expect(boostedContentService.feedsService.setEndpoint).toBeCalledWith('api/v2/boost/feed');
expect(boostedContentService.feedsService.setOffset).toBeCalledWith(0);
expect(boostedContentService.feedsService.setLimit).toBeCalledWith(12);
expect(boostedContentService.feedsService.fetchLocal).toBeCalled();
// should fetch the boosts entities
expect(boostedContentService.feedsService.getEntities).toBeCalled();
// the boosts should be stored in the boosts property
expect(boostedContentService.boosts).toStrictEqual(result);
});
it('should fetch the boosts and filter blocked', async () => {
blockListService.has
.mockReturnValueOnce(false)
.mockReturnValueOnce(true)
.mockReturnValueOnce(false)
.mockReturnValueOnce(false)
.mockReturnValueOnce(true)
.mockReturnValueOnce(false);
const fakeBoosts = [
{guid: 1, ownerObj: {guid: 1}},
{guid: 2, ownerObj: {guid: 2}},
{guid: 3, ownerObj: {guid: 3}},
];
const result = fakeBoosts
.map(e => {
e.boosted = true;
return e;
})
.filter(e => e.guid !== 2);
boostedContentService.feedsService.getEntities.mockResolvedValue(fakeBoosts);
boostedContentService.feedsService.fetchLocal.mockResolvedValue(true);
......@@ -25,17 +83,22 @@ describe('Boosted content service', () => {
expect(boostedContentService.feedsService.setLimit).toBeCalledWith(12);
expect(boostedContentService.feedsService.fetchLocal).toBeCalled();
// blocked should be called
expect( blockListService.has).toBeCalled();
// should fetch the boosts entities
expect(boostedContentService.feedsService.getEntities).toBeCalled();
// the boosts should be stored in the boosts property
expect(boostedContentService.boosts).toBe(fakeBoosts);
expect(boostedContentService.boosts).toStrictEqual(result);
});
it('should return next boost and start again when the end is reached', () => {
const fakeBoosts = [{guid: 1}, {guid: 2}, {guid: 3}];
blockListService.has.mockReturnValue(false);
boostedContentService.boosts = fakeBoosts;
// next
......
import service from '../../../src/common/services/deeplinks-router.service';
import { MINDS_DEEPLINK } from '../../../src/config/Config';
import navigationService from '../../../src/navigation/NavigationService';
import service from '../../../src/common/services/deeplinks-router.service';
/**
* Tests
......@@ -10,19 +7,43 @@ import navigationService from '../../../src/navigation/NavigationService';
describe('Deeplinks router service', () => {
navigationService.navigate = jest.fn();
beforeEach(() => {
navigationService.navigate.mockClear();
});
it('should add route', async () => {
expect(service.routes.length).toBe(12)
service.clearRoutes();
expect(service.routes.length).toBe(0);
service.add('crypto/:someparam', 'screen1');
service.add('myurl/:someparam1', 'screen2');
expect(service.routes.length).toBe(14);
service.add('twoparams/:someparam1/:someparam2', 'screen2');
expect(service.routes.length).toBe(3);
service.navigate('http://www.minds.com/crypto/somevalue');
expect(navigationService.navigate).toHaveBeenCalledWith('screen1', {someparam: 'somevalue'});
expect(navigationService.navigate).toHaveBeenCalledWith('screen1', {
someparam: 'somevalue',
});
service.navigate('http://www.minds.com/myurl/somevalue');
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {someparam1: 'somevalue'});
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
});
service.navigate('http://www.minds.com/twoparams/somevalue/somevalue1');
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
someparam2: 'somevalue1',
});
service.navigate(
'http://www.minds.com/twoparams/somevalue/somevalue1?other=1&other2=2',
);
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
someparam2: 'somevalue1',
other: '1',
other2: '2',
});
service.navigate('http://www.minds.com/myurl/somevalue?other=1');
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
other: '1',
});
});
});
\ No newline at end of file
});
import { toJS } from 'mobx';
import HashtagStore from '../../../src/common/stores/HashtagStore';
/**
* Tests
*/
describe('Hashtag store', () => {
let store;
beforeEach(() => {
store = new HashtagStore();
});
it('it should add the tag as suggested if it doesn\'t exist', () => {
const fakeTags = [
{
value: 'Minds',
type: 'user',
selected: false,
},
{
value: 'tag1',
type: 'user',
selected: false,
},
];
const expected = [
{
value: 'Minds',
type: 'user',
selected: false,
},
{
value: 'tag1',
type: 'user',
selected: false,
},
{
value: 'tag2',
selected: false,
},
];
store.setSuggested(fakeTags);
store.setHashtag('tag1');
expect(toJS(store.suggested)).toEqual(fakeTags);
store.setHashtag('tag2');
expect(toJS(store.suggested)).toEqual(expected);
});
});
......@@ -127,6 +127,7 @@ exports[`Messenger setup component should render correctly for unlock 1`] = `
"padding": 16,
}
}
testID="MessengerSetupText"
underlineColorAndroid="transparent"
/>
</View>
......
......@@ -492,6 +492,7 @@ exports[`notification component renders correctly for every type 5`] = `
some title
</Text>
</Text>
You have not been charged
</Text>
</View>
......
......@@ -52,6 +52,7 @@ exports[`renders correctly 1`] = `
some title
</Text>
</Text>
You have not been charged
</Text>
</View>
......
GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.0)
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
CFPropertyList (3.0.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
babosa (1.0.2)
claide (1.0.2)
babosa (1.0.3)
claide (1.0.3)
colored (1.2)
colored2 (3.1.2)
commander-fastlane (4.4.6)
......@@ -16,18 +16,18 @@ GEM
digest-crc (0.4.1)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.4)
dotenv (2.7.5)
emoji_regex (1.0.1)
excon (0.65.0)
faraday (0.15.4)
excon (0.71.1)
faraday (0.17.3)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
http-cookie (~> 1.0.0)
faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5)
fastlane (2.128.0)
fastimage (2.1.7)
fastlane (2.139.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0)
......@@ -36,13 +36,13 @@ GEM
commander-fastlane (>= 4.4.6, < 5.0.0)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 2.0)
excon (>= 0.45.0, < 1.0.0)
faraday (~> 0.9)
excon (>= 0.71.0, < 1.0.0)
faraday (~> 0.17)
faraday-cookie_jar (~> 0.0.6)
faraday_middleware (~> 0.9)
faraday_middleware (~> 0.13.1)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
google-api-client (>= 0.21.2, < 0.24.0)
google-api-client (>= 0.29.2, < 0.37.0)
google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0)
......@@ -52,7 +52,7 @@ GEM
multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0)
public_suffix (~> 2.0.0)
rubyzip (>= 1.2.2, < 2.0.0)
rubyzip (>= 1.3.0, < 2.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
slack-notifier (>= 2.0.0, < 3.0.0)
......@@ -61,46 +61,46 @@ GEM
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.8.1, < 2.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-api-client (0.23.9)
google-api-client (0.36.4)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.5, < 0.7.0)
googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
mime-types (~> 3.0)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.9)
google-cloud-core (1.3.0)
signet (~> 0.12)
google-cloud-core (1.4.1)
google-cloud-env (~> 1.0)
google-cloud-env (1.2.0)
google-cloud-env (1.3.0)
faraday (~> 0.11)
google-cloud-storage (1.16.0)
google-cloud-storage (1.25.0)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.23)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (>= 0.6.2, < 0.10.0)
googleauth (0.6.7)
googleauth (~> 0.9)
mini_mime (~> 1.0)
googleauth (0.10.0)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.7)
signet (~> 0.12)
highline (1.7.10)
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
json (2.2.0)
json (2.3.0)
jwt (2.1.0)
memoist (0.16.0)
mime-types (3.2.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2019.0331)
mini_magick (4.9.5)
multi_json (1.13.1)
memoist (0.16.2)
mini_magick (4.10.1)
mini_mime (1.0.2)
multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
nanaimo (0.2.6)
......@@ -114,14 +114,14 @@ GEM
uber (< 0.2.0)
retriable (3.1.2)
rouge (2.0.7)
rubyzip (1.2.3)
rubyzip (1.3.0)
security (0.1.3)
signet (0.11.0)
signet (0.12.0)
addressable (~> 2.3)
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.5)
simctl (1.6.7)
CFPropertyList
naturally
slack-notifier (2.3.2)
......@@ -130,7 +130,7 @@ GEM
unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.7.0)
tty-screen (0.7.0)
tty-spinner (0.9.1)
tty-spinner (0.9.2)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
......@@ -138,7 +138,7 @@ GEM
unf_ext (0.0.7.6)
unicode-display_width (1.6.0)
word_wrap (1.0.0)
xcodeproj (1.11.0)
xcodeproj (1.14.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
......@@ -156,4 +156,4 @@ DEPENDENCIES
fastlane
BUNDLED WITH
2.0.2
2.1.4
......@@ -137,6 +137,8 @@ android {
versionCode Integer.parseInt(project.versionCode)
versionName project.versionName
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60"
testBuildType System.getProperty('testBuildType', 'debug') // This will later be used to control the test apk build type
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
signingConfigs {
debug {
......@@ -245,6 +247,9 @@ dependencies {
implementation("com.github.bumptech.glide:annotations:${glideVersion}") {
exclude group: "com.android.support", module: "annotations"
}
androidTestImplementation('com.wix:detox:+') { transitive = true }
androidTestImplementation 'junit:junit:4.12'
}
// Run this once to be able to run the application with BUCK
......
package com.minds.mobile;
import com.wix.detox.Detox;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DetoxTest {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class, false, false);
@Test
public void runDetoxTests() {
Detox.runTests(mActivityRule);
}
}
\ No newline at end of file
......@@ -50,12 +50,13 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="mobile.minds.com" android:path="/"/>
<data android:pathPattern="/channels/..*"/>
android:host="www.minds.com" android:path="/"/>
<data android:pathPattern="/email-confirmation"/>
<!-- <data android:pathPattern="/channels/..*"/>
<data android:pathPattern="/newsfeed/..*"/>
<data android:pathPattern="/groups/profile/..*"/>
<data android:pathPattern="/wallet/..*"/>
<data android:pathPattern="/..*"/>
<data android:pathPattern="/..*"/> -->
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
......
......@@ -11,6 +11,7 @@ buildscript {
supportLibVersion = "28.0.0"
androidXCore = "1.0.2"
glideVersion = "4.7.1"
kotlinVersion = '1.3.10'
}
repositories {
google()
......@@ -19,6 +20,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.google.gms:google-services:4.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
......@@ -27,6 +29,10 @@ buildscript {
allprojects {
repositories {
mavenLocal()
maven {
// All of Detox' artifacts are provided via the npm module
url "$rootDir/../node_modules/detox/Detox-android"
}
maven {
url "https://github.com/jitsi/jitsi-maven-repository/raw/master/releases"
}
......@@ -56,6 +62,10 @@ subprojects {
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.supportLibVersion
defaultConfig {
minSdkVersion 21
}
}
}
}
......
json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
json_key_file("../android/app/play-store.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
package_name("com.minds.mobile") # e.g. com.krausefx.app
......@@ -21,11 +21,6 @@ or alternatively using `brew cask install fastlane`
fastlane android test
```
Runs all the tests
### android copy_secrets
```
fastlane android copy_secrets
```
Copy secrets
### android assemble_build
```
fastlane android assemble_build
......
Updated translations
Slovak added
Bug Fixes
\ No newline at end of file
Updated translations
Slovak added
Bug Fixes
\ No newline at end of file
The Crypto Social Network
★ Features. Newsfeed, Wallet, Groups, Blogs, Video, Images, Search, Channels, Videos, Images, Statuses, Rewards, Video Chat
★ Privacy. Chat securely with encrypted messenger. Be anonymous if you wish.
★ Contribute. Create popular original content that receives upvotes, comments and reminds. Gain new subscribers, refer contacts, check-in, develop code and more.
★ Earn. Each day we measure your contribution relative to the community and reward you with tokens.
★ Get Views. Exchange your tokens for views on your content and increase your chances of earning rewards. No algorithms or surveillance. 100% organic reach. 1 token = 1,000 views.
★ Sell Digital Services. Share exclusive digital content and other custom rewards to your supporters and earn tokens.
★ Open Source. Minds is free and open source which allows anyone to inspect, modify or share their version of the source code.
For support, questions, or more information, please visit:
https://minds.com/faq
Source code:
https://minds.org
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.