Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/**/*
.expo/*
npm-debug.*
dist/
dist/
.DS_Store
116 changes: 64 additions & 52 deletions __tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -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");
});
});
49 changes: 43 additions & 6 deletions src/android.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
export const getAndroidVersion = async (storeURL: string = ''): Promise<string> => {
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<string> => {
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) => {
if (r.status === 200) {
return r.text();
}

throw new Error('androidStoreURL is invalid.');
throw new Error("androidStoreURL is invalid.");
});

const matches = response.match(/<span class="htlgb"><div class="IQ1z0d"><span class="htlgb">([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<string> => {
const androidAppVersionMatcher =
/<span class="htlgb"><div class="IQ1z0d"><span class="htlgb">([0-9]+\.?[0-9]*\.?[0-9]*)<\/span><\/div><\/span>/;

const androidAppVerion = await findOnAndroidPage(
storeURL,
androidAppVersionMatcher
);

return androidAppVerion;
};

export const getAndroidUpdatedDate = async (
storeURL: string = ""
): Promise<string> => {
const androidAppUpdatedDateMatcher =
/<span class="htlgb"><div class="IQ1z0d"><span class="htlgb">([A-Z][a-z]+ [0-9]{1,2}, [0-9]{4})<\/span><\/div><\/span>/;

const androidAppUpdatedDate = await findOnAndroidPage(
storeURL,
androidAppUpdatedDateMatcher
);

return androidAppUpdatedDate;
};
65 changes: 40 additions & 25 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<CheckVersionResponse> => {
const checkVersion = async (
params: CheckVersionParams
): Promise<CheckVersionResponse> => {
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;
}

Expand All @@ -73,6 +87,7 @@ const checkVersion = async (params: CheckVersionParams): Promise<CheckVersionRes
remote: remoteVersion,
result,
detail,
...(updatedAt ? { updatedAt } : {}),
};
};

Expand Down