Skip to content

Commit

Permalink
Development 2.2.2 (#73)
Browse files Browse the repository at this point in the history
* 2.2.2

* test update

* auth-test

* Add

* main

* up test

* Add test

* add toot

* Add test

* pushn

* test up

* Readme update

* fix
  • Loading branch information
potproject authored Sep 20, 2020
1 parent be30a5d commit ab8e8c4
Show file tree
Hide file tree
Showing 28 changed files with 2,800 additions and 112 deletions.
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ Mastodon client App for React Native (Expo)

マストドン用クライアントの React Native アプリです。

## インストール方法
## ScreenShots


<img width="180" heigth="360" src="https://github.com/potproject/ikuradon/blob/master/screenshots/ios_timeline.jpg?raw=true"> <img width="180" heigth="360" src="https://github.com/potproject/ikuradon/blob/master/screenshots/ios_notifications.jpg?raw=true"> <img width="180" heigth="360" src="https://github.com/potproject/ikuradon/blob/master/screenshots/ios_toot.jpg?raw=true"> <img width="180" heigth="360" src="https://github.com/potproject/ikuradon/blob/master/screenshots/ios_drawer.jpg?raw=true">

## install Guide

App Store、Google Play を通さない Expo アプリとして配布されています。

Expand Down Expand Up @@ -58,13 +63,6 @@ expo publish
- Misskey Support
- Movie Support

## ScreenShots

| | |
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| ![](https://github.com/potproject/ikuradon/blob/master/screenshots/ios_timeline.jpg?raw=true) | ![](https://github.com/potproject/ikuradon/blob/master/screenshots/ios_notifications.jpg?raw=true) |
| ![](https://github.com/potproject/ikuradon/blob/master/screenshots/ios_toot.jpg?raw=true) | ![](https://github.com/potproject/ikuradon/blob/master/screenshots/ios_drawer.jpg?raw=true) |

## Development

```
Expand Down
2 changes: 1 addition & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "ikuradon",
"description": "ikuradon - Mastodon Client App",
"slug": "potproject-ikuradon",
"version": "2.2.1",
"version": "2.2.2",
"platforms": [
"android",
"ios"
Expand Down
208 changes: 208 additions & 0 deletions app/actions/actioncreators/__tests__/appinit-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import { appInit } from "../appinit";

import * as Config from "../../actiontypes/config";
import * as AppInit from "../../actiontypes/appinit";
import * as PushNotification from "../../actiontypes/pushnotification";
import * as CurrentUser from "../../actiontypes/currentuser";

import Networking from "../../../services/Networking";
import NavigationService from "../../../services/NavigationService";

import * as RouterName from "../../../constants/RouterName";

import { getItem } from "../../../util/storage";
import { settingTheme } from "../../../util/theme";
import * as Session from "../../../util/session";

import ExampleAccount from "../../../example/account";
import ExampleInstance from "../../../example/instance";
import ExampleSession from "../../../example/session";
import ExampleCurrent from "../../../example/current";
import { initialState as initConfig } from "../../../reducers/config";

jest.mock("../../../util/storage");
jest.mock("../../../util/theme");
jest.mock("../../../util/session");
jest.mock("../../../util/push");
jest.mock("../../../services/NavigationService");
jest.mock("../../../services/Networking");


describe("Action/AppInit", () => {
it("appInit", async done => {
getItem
// CONST_Storage.Config
.mockImplementationOnce(() => initConfig)
// CONST_Storage.Push
.mockImplementationOnce(() => ({}));
Networking.fetch
// CONST_API.GET_CURRENT_USER
.mockImplementationOnce(() => ExampleAccount())
// CONST_API.GET_INSTANCE
.mockImplementationOnce(() => ExampleInstance());
Session.getDomainAndToken.mockImplementation(() => ExampleSession());
NavigationService.resetAndNavigate.mockImplementation((callback) => {
expect(callback).toEqual({ name: RouterName.Main });
done();
});
let action = appInit(()=>null);
let call = 0;
const { user_credentials, domain, access_token, instance } = ExampleCurrent();
await action((callback)=>{
try {
call === 0 && expect(callback).toEqual({ type: Config.CONFIG_LOAD, config: initConfig });
call === 1 && expect(callback).toEqual({ type: PushNotification.PUSHNOTIFICATION_LOAD, pushNotifications: {} });
call === 2 && expect(callback).toEqual({ type:CurrentUser.UPDATE_CURRENT_USER, user_credentials, domain, access_token, instance });
call === 3 && expect(callback).toEqual({ type:AppInit.APPINIT_COMPLETE });
call++;
} catch (e){
done(e);
}
});
getItem.mockReset();
Session.getDomainAndToken.mockReset();
Networking.fetch.mockReset();
NavigationService.resetAndNavigate.mockReset();
});
it("appInit config and push null", async done => {
getItem
// CONST_Storage.Config
.mockImplementationOnce(() => null)
// CONST_Storage.Push
.mockImplementationOnce(() => null);
Networking.fetch
// CONST_API.GET_CURRENT_USER
.mockImplementationOnce(() => ExampleAccount())
// CONST_API.GET_INSTANCE
.mockImplementationOnce(() => ExampleInstance());
Session.getDomainAndToken.mockImplementation(() => ExampleSession());
NavigationService.resetAndNavigate.mockImplementation((callback) => {
expect(callback).toEqual({ name: RouterName.Main });
done();
});
let action = appInit(()=>null);
let call = 0;
const { user_credentials, domain, access_token, instance } = ExampleCurrent();
await action((callback)=>{
try {
call === 0 && expect(callback).toEqual({ type:CurrentUser.UPDATE_CURRENT_USER, user_credentials, domain, access_token, instance });
call === 1 && expect(callback).toEqual({ type:AppInit.APPINIT_COMPLETE });
call++;
} catch (e){
done(e);
}
});
getItem.mockReset();
Session.getDomainAndToken.mockReset();
Networking.fetch.mockReset();
NavigationService.resetAndNavigate.mockReset();
});
it("appInit config.theme undefined", async done => {
let initConfigDeepCopy = JSON.parse(JSON.stringify(initConfig));
delete initConfigDeepCopy.theme;
getItem
// CONST_Storage.Config
.mockImplementationOnce(() => {
return initConfigDeepCopy;
})
// CONST_Storage.Push
.mockImplementationOnce(() => ({}));
Networking.fetch
// CONST_API.GET_CURRENT_USER
.mockImplementationOnce(() => ExampleAccount())
// CONST_API.GET_INSTANCE
.mockImplementationOnce(() => ExampleInstance());
Session.getDomainAndToken.mockImplementation(() => ExampleSession());
NavigationService.resetAndNavigate.mockImplementation((callback) => {
expect(callback).toEqual({ name: RouterName.Main });
done();
});
let action = appInit(()=>null);
let call = 0;
const { user_credentials, domain, access_token, instance } = ExampleCurrent();
await action((callback)=>{
try {
call === 0 && expect(callback).toEqual({ type: Config.CONFIG_LOAD, config: initConfigDeepCopy });
call === 1 && expect(callback).toEqual({ type: PushNotification.PUSHNOTIFICATION_LOAD, pushNotifications: {} });
call === 2 && expect(callback).toEqual({ type:CurrentUser.UPDATE_CURRENT_USER, user_credentials, domain, access_token, instance });
call === 3 && expect(callback).toEqual({ type:AppInit.APPINIT_COMPLETE });
call++;
} catch (e){
done(e);
}
});
getItem.mockReset();
Session.getDomainAndToken.mockReset();
Networking.fetch.mockReset();
NavigationService.resetAndNavigate.mockReset();
});
it("appInit domain&access_token null", async done => {
getItem
// CONST_Storage.Config
.mockImplementationOnce(() => initConfig)
// CONST_Storage.Push
.mockImplementationOnce(() => ({}));
Networking.fetch
// CONST_API.GET_CURRENT_USER
.mockImplementationOnce(() => ExampleAccount())
// CONST_API.GET_INSTANCE
.mockImplementationOnce(() => ExampleInstance());
Session.getDomainAndToken.mockImplementation(() => ({
domain: null,
access_token: null,
username: null,
avatar: null
}));
NavigationService.resetAndNavigate.mockImplementation((callback) => {
expect(callback).toEqual({ name: RouterName.Login });
done();
});
let action = appInit(()=>null);
let call = 0;
await action((callback)=>{
try {
call === 0 && expect(callback).toEqual({ type: Config.CONFIG_LOAD, config: initConfig });
call === 1 && expect(callback).toEqual({ type: PushNotification.PUSHNOTIFICATION_LOAD, pushNotifications: {} });
call === 2 && expect(callback).toEqual({ type:AppInit.APPINIT_COMPLETE });
call++;
} catch (e){
done(e);
}
});
getItem.mockReset();
Session.getDomainAndToken.mockReset();
Networking.fetch.mockReset();
NavigationService.resetAndNavigate.mockReset();
});
it("appInit Login Error", async done => {
getItem
// CONST_Storage.Config
.mockImplementationOnce(() => initConfig)
// CONST_Storage.Push
.mockImplementationOnce(() => ({}));
Networking.fetch.mockImplementation(() => {
throw new Error("Network Error");
});
Session.getDomainAndToken.mockImplementation(() => ExampleSession());
NavigationService.resetAndNavigate.mockImplementation((callback) => {
expect(callback).toEqual({ name: RouterName.Login });
done();
});
let action = appInit(()=>null);
let call = 0;
await action((callback)=>{
try {
call === 0 && expect(callback).toEqual({ type: Config.CONFIG_LOAD, config: initConfig });
call === 1 && expect(callback).toEqual({ type: PushNotification.PUSHNOTIFICATION_LOAD, pushNotifications: {} });
call === 2 && expect(callback).toEqual({ type:AppInit.APPINIT_COMPLETE });
call++;
} catch (e){
done(e);
}
});
getItem.mockReset();
Session.getDomainAndToken.mockReset();
Networking.fetch.mockReset();
NavigationService.resetAndNavigate.mockReset();
});
});
59 changes: 59 additions & 0 deletions app/actions/actioncreators/__tests__/authorize-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { getAccessTokenWithHomeAction } from "../authorize";

import ExampleAccount from "../../../example/account";
import ExampleInstance from "../../../example/instance";
import Networking from "../../../services/Networking";
import DropDownHolder from "../../../services/DropDownHolder";

jest.mock("../../../util/session");
jest.mock("../../../services/Networking");
jest.mock("../../../services/NavigationService");
jest.mock("../../../services/DropDownHolder", () => ({
error: jest.fn(),
success: jest.fn(),
}));

describe("Action/Authorize", () => {
it("getAccessTokenWithHomeAction", async done => {
let domain = "example.com";
let client_id = "CLIENT_ID";
let client_secret = "CLIENT_SECRET";
let code = "CODE";
Networking.fetch
// CONST_API.GET_OAUTH_ACCESSTOKEN
.mockImplementationOnce(() => ({ access_token: "ACCESS_TOKEN" }))
// CONST_API.GET_CURRENT_USER
.mockImplementationOnce(() => ExampleAccount())
// CONST_API.GET_INSTANCE
.mockImplementationOnce(() => ExampleInstance());
let action = getAccessTokenWithHomeAction(domain, client_id, client_secret, code);
await action(({ type, user_credentials, domain, access_token, instance }) => {
expect(type).toEqual("UPDATE_CURRENT_USER");
expect(user_credentials).toEqual(ExampleAccount());
expect(domain).toEqual("example.com");
expect(access_token).toEqual("ACCESS_TOKEN");
expect(instance).toEqual(ExampleInstance());
done();
});
Networking.fetch.mockClear();
});
it("getAccessTokenWithHomeAction Fail", async done => {
let domain = "example.com";
let client_id = "CLIENT_ID";
let client_secret = "CLIENT_SECRET";
let code = "CODE";
Networking.fetch
// CONST_API.GET_OAUTH_ACCESSTOKEN
.mockImplementation(() => {
throw new Error("Network Error");
});
DropDownHolder.error.mockImplementationOnce((title, message) => {
expect(message).toEqual("Network Error");
done();
});
let action = getAccessTokenWithHomeAction(domain, client_id, client_secret, code);
await action();
Networking.fetch.mockClear();
DropDownHolder.error.mockClear();
});
});
81 changes: 81 additions & 0 deletions app/actions/actioncreators/__tests__/config-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { allClear, setBackground, setBackgroundClear, setInvisibleTimeline, setTheme } from "../config";

import * as Config from "../../actiontypes/config";
import * as Main from "../../actiontypes/main";
import * as Streaming from "../../actiontypes/streaming";

import * as ImagePicker from "expo-image-picker";
import DropDownHolder from "../../../services/DropDownHolder";

jest.mock("../../../util/session");
jest.mock("../../../util/permission");
jest.mock("../../../services/NavigationService");
jest.mock("../../../services/DropDownHolder", () => ({
error: jest.fn(),
success: jest.fn(),
}));

jest.mock("expo-image-picker", () => ({
launchImageLibraryAsync: jest.fn(),
}));

const fileDataMock = {
"cancelled":false,
"height":1611,
"width":2148,
"uri":"file:///data/user/0/host.exp.exponent/cache/cropped1814158652.jpg"
};

const fileDataMockCancelled = {
"cancelled":false
};

describe("Action/Config", () => {
it("allClear", async done => {
let action = allClear();
let call = 0;
await action(({ type }) => {
call === 0 && expect(type).toBe(Config.CONFIG_RESET);
call === 1 && expect(type).toBe(Streaming.STREAM_ALLSTOP);
call === 2 && (expect(type).toBe(Main.ALLCLEAR_MASTOLIST) || done());
call++;
});
});
it("setBackground", async done => {
ImagePicker.launchImageLibraryAsync.mockImplementation(() => fileDataMock);
let action = setBackground();
await action(({ type, backgroundImage }) => {
expect(type).toBe(Config.SET_BACKGROUNDIMAGE);
expect(backgroundImage).toBe(fileDataMock.uri);
done();
});
ImagePicker.launchImageLibraryAsync.mockClear();
});
it("setBackground Canceled", async () => {
ImagePicker.launchImageLibraryAsync.mockImplementation(() => fileDataMockCancelled);
let action = setBackground();
await action(() => null);
ImagePicker.launchImageLibraryAsync.mockClear();
});
it("setBackground Error", async done => {
ImagePicker.launchImageLibraryAsync.mockImplementation(() => {
throw new Error("Network Error");
});
let action = setBackground();
DropDownHolder.error.mockImplementationOnce((title, message) => {
expect(message).toEqual("Network Error");
done();
});
await action(() => null);
ImagePicker.launchImageLibraryAsync.mockClear();
});
it("setBackgroundClear", () => {
expect(setBackgroundClear()).toEqual({ type: Config.DELETE_BACKGROUNDIMAGE });
});
it("setInvisibleTimeline", () => {
expect(setInvisibleTimeline("main", true)).toEqual({ type: Config.INVISIBLE_SETTING, invisible: { main: true } });
});
it("setTheme", () => {
expect(setTheme("mikugreen")).toEqual({ type: Config.CHANGE_THEME, theme: "mikugreen" });
});
});
Loading

0 comments on commit ab8e8c4

Please sign in to comment.