diff --git a/.gitignore b/.gitignore index 0963fb2..519eb0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/**/* .expo/* npm-debug.* -dist/ \ No newline at end of file +dist/ +.DS_Store \ No newline at end of file diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 3e08d94..72dce32 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,92 +1,104 @@ -import checkVersion, { compareVersion } from '../src'; -import {getIOSVersion} from '../src/ios'; -import {getAndroidVersion} from '../src/android'; +import checkVersion, { compareVersion } from "../src"; +import { getIOSVersion } from "../src/ios"; +import { getAndroidVersion } from "../src/android"; -require('jest-fetch-mock'); +require("jest-fetch-mock"); -describe('ios', () => { +describe("ios", () => { beforeEach(() => { jest.resetModules(); - jest.mock('react-native/Libraries/Utilities/Platform', () => ({ - OS: 'ios', + jest.mock("react-native/Libraries/Utilities/Platform", () => ({ + OS: "ios", select: () => null, })); }); - it('error pattern', async () => { + it("error pattern", async () => { try { await checkVersion({ - version: '1.0.0', + version: "1.0.0", }); } catch (e) { - expect(e.message).toBe('iosStoreURL is not set.'); + expect(e.message).toBe("iosStoreURL is not set."); } }); - // it('get version', async () => { - // const correctPattern = await getIOSVersion('https://itunes.apple.com/jp/app/pin-point/id1321198947'); - // expect(correctPattern).toEqual(expect.stringMatching(/[0-9]{1,}\.?[0-9]*\.?[0-9]*\.?/)); + it("get version", async () => { + const correctPattern = await getIOSVersion( + "https://itunes.apple.com/jp/app/pin-point/id1321198947" + ); + expect(correctPattern).toEqual( + expect.stringMatching(/[0-9]{1,}\.?[0-9]*\.?[0-9]*\.?/) + ); - // try { - // await getIOSVersion('https://itunes.apple.com/jp/app/pin-point/id13211989471111'); - // } catch (e) { - // expect(e).toHaveProperty('message'); - // } + try { + await getIOSVersion( + "https://itunes.apple.com/jp/app/pin-point/id13211989471111" + ); + } catch (e) { + expect(e).toHaveProperty("message"); + } - // try { - // await getIOSVersion(); - // } catch (e) { - // expect(e).toHaveProperty('message'); - // } - // }); + try { + await getIOSVersion(); + } catch (e) { + expect(e).toHaveProperty("message"); + } + }); }); -describe('android', () => { +describe("android", () => { beforeEach(() => { jest.resetModules(); - jest.mock('react-native/Libraries/Utilities/Platform', () => ({ - OS: 'android', + jest.mock("react-native/Libraries/Utilities/Platform", () => ({ + OS: "android", select: () => null, })); }); - it('error pattern', async () => { + it("error pattern", async () => { try { await checkVersion({ - version: '1.0.0', + version: "1.0.0", }); } catch (e) { - expect(e.message).toBe('androidStoreURL is not set.'); + expect(e.message).toBe("androidStoreURL is not set."); } }); - // it('get version', async () => { - // const correctPattern = await getAndroidVersion('https://play.google.com/store/apps/details?id=jp.ewaf.likedsearch.android'); - // expect(correctPattern).toEqual(expect.stringMatching(/[0-9]{1,}\.?[0-9]*\.?[0-9]*\.?/)); + it("get version", async () => { + const correctPattern = await getAndroidVersion( + "https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically" + ); + expect(correctPattern).toEqual( + expect.stringMatching(/[0-9]{1,}\.?[0-9]*\.?[0-9]*\.?/) + ); - // try { - // await getAndroidVersion('https://play.google.com/store/apps/details?id=jp.ewaf.likedsearch.android1111'); - // } catch (e) { - // expect(e).toHaveProperty('message'); - // } + try { + await getAndroidVersion( + "https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically1111" + ); + } catch (e) { + expect(e).toHaveProperty("message"); + } - // try { - // await getAndroidVersion(); - // } catch (e) { - // expect(e).toHaveProperty('message'); - // } - // }); + try { + await getAndroidVersion(); + } catch (e) { + expect(e).toHaveProperty("message"); + } + }); }); -describe('other', () => { - it('compare version', () => { - const remoteIsOld = compareVersion('1.1.0', '1.0.3'); - expect(remoteIsOld).toBe('old'); +describe("other", () => { + it("compare version", () => { + const remoteIsOld = compareVersion("1.1.0", "1.0.3"); + expect(remoteIsOld).toBe("old"); - const remoteIsNew = compareVersion('1.0.0', '1.1.0'); - expect(remoteIsNew).toBe('new'); + const remoteIsNew = compareVersion("1.0.0", "1.1.0"); + expect(remoteIsNew).toBe("new"); - const equal = compareVersion('1.1.0', '1.1.0'); - expect(equal).toBe('equal'); + const equal = compareVersion("1.1.0", "1.1.0"); + expect(equal).toBe("equal"); }); }); diff --git a/src/android.ts b/src/android.ts index 71f7098..7d4f76c 100644 --- a/src/android.ts +++ b/src/android.ts @@ -1,6 +1,15 @@ -export const getAndroidVersion = async (storeURL: string = ''): Promise => { - if (!storeURL.match(/^https?:\/\/play\.google\.com\/store\/apps\/details\?id=[0-9a-zA-Z.]+/)) { - throw new Error('androidStoreURL is invalid.'); +export const findOnAndroidPage = async ( + storeURL: string = "", + matcher: { + [Symbol.match](string: string): RegExpMatchArray | null; + } +): Promise => { + if ( + !storeURL.match( + /^https?:\/\/play\.google\.com\/store\/apps\/details\?id=[0-9a-zA-Z.]+/ + ) + ) { + throw new Error("androidStoreURL is invalid."); } const response = await fetch(storeURL).then((r) => { @@ -8,14 +17,42 @@ export const getAndroidVersion = async (storeURL: string = ''): Promise return r.text(); } - throw new Error('androidStoreURL is invalid.'); + throw new Error("androidStoreURL is invalid."); }); - const matches = response.match(/
([0-9]+\.?[0-9]*\.?[0-9]*)<\/span><\/div><\/span>/); + const matches = response.match(matcher); if (!matches) { - throw new Error('can\'t get android app version.'); + throw new Error("can't get matching android information."); } return matches[1]; }; + +export const getAndroidVersion = async ( + storeURL: string = "" +): Promise => { + const androidAppVersionMatcher = + /
([0-9]+\.?[0-9]*\.?[0-9]*)<\/span><\/div><\/span>/; + + const androidAppVerion = await findOnAndroidPage( + storeURL, + androidAppVersionMatcher + ); + + return androidAppVerion; +}; + +export const getAndroidUpdatedDate = async ( + storeURL: string = "" +): Promise => { + const androidAppUpdatedDateMatcher = + /
([A-Z][a-z]+ [0-9]{1,2}, [0-9]{4})<\/span><\/div><\/span>/; + + const androidAppUpdatedDate = await findOnAndroidPage( + storeURL, + androidAppUpdatedDateMatcher + ); + + return androidAppUpdatedDate; +}; diff --git a/src/index.ts b/src/index.ts index 41cd6e7..ac55230 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ -import { Platform } from 'react-native'; -import compareVersions from 'compare-versions'; -import { getIOSVersion } from './ios'; -import { getAndroidVersion } from './android'; +import { Platform } from "react-native"; +import compareVersions from "compare-versions"; +import { getIOSVersion } from "./ios"; +import { getAndroidUpdatedDate, getAndroidVersion } from "./android"; type CheckVersionParams = { country?: string; @@ -13,57 +13,71 @@ type CheckVersionParams = { type CheckVersionResponse = { local: string; remote: string; - result: 'new' | 'old' | 'equal'; - detail: 'remote > local' | 'remote < local' | 'remote === local'; + result: "new" | "old" | "equal"; + detail: "remote > local" | "remote < local" | "remote === local"; + updatedAt?: string; }; -export const compareVersion = (local: string, remote: string): CheckVersionResponse['result'] => { +export const compareVersion = ( + local: string, + remote: string +): CheckVersionResponse["result"] => { switch (compareVersions(local, remote)) { case -1: - return 'new'; + return "new"; case 1: - return 'old'; + return "old"; default: - return 'equal'; + return "equal"; } }; -const checkVersion = async (params: CheckVersionParams): Promise => { +const checkVersion = async ( + params: CheckVersionParams +): Promise => { if (!params.version) { - throw new Error('local version is not set.'); + throw new Error("local version is not set."); } /* check store url */ - if (Platform.OS === 'ios' && !params.iosStoreURL) { - throw new Error('iosStoreURL is not set.'); + if (Platform.OS === "ios" && !params.iosStoreURL) { + throw new Error("iosStoreURL is not set."); } - if (Platform.OS === 'android' && !params.androidStoreURL) { - throw new Error('androidStoreURL is not set.'); + if (Platform.OS === "android" && !params.androidStoreURL) { + throw new Error("androidStoreURL is not set."); } /* get version */ let remoteVersion: string; + /* get the date an android app was last updated */ + let updatedAt; + try { - remoteVersion = (Platform.OS === 'ios') - ? await getIOSVersion(params.iosStoreURL, params.country || 'jp') - : await getAndroidVersion(params.androidStoreURL); + remoteVersion = + Platform.OS === "ios" + ? await getIOSVersion(params.iosStoreURL, params.country || "jp") + : await getAndroidVersion(params.androidStoreURL); + updatedAt = + Platform.OS === "ios" + ? undefined + : await getAndroidUpdatedDate(params.androidStoreURL); } catch (e) { throw new Error(e.message); } const result = compareVersion(params.version, remoteVersion); - let detail: CheckVersionResponse['detail']; + let detail: CheckVersionResponse["detail"]; switch (result) { - case 'new': - detail = 'remote > local'; + case "new": + detail = "remote > local"; break; - case 'old': - detail = 'remote < local'; + case "old": + detail = "remote < local"; break; default: - detail = 'remote === local'; + detail = "remote === local"; break; } @@ -73,6 +87,7 @@ const checkVersion = async (params: CheckVersionParams): Promise