diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2a5f96d8f..f986fbb4c 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -67,7 +67,7 @@ import { ScanProvider } from '../providers/scan/scan'; import { TouchIdProvider } from '../providers/touchid/touchid'; import { TxFormatProvider } from '../providers/tx-format/tx-format'; import { WalletProvider } from '../providers/wallet/wallet'; -import { LatestReleaseProvider } from '../providers/latestRelease/latestRelease'; +import { ReleaseProvider } from '../providers/release/release'; export function createTranslateLoader(http: Http) { return new TranslatePoHttpLoader(http, 'assets/i18n', '.po'); @@ -118,7 +118,7 @@ let providers: any = [ TouchIdProvider, TxFormatProvider, WalletProvider, - LatestReleaseProvider, + ReleaseProvider, { provide: ErrorHandler, useClass: IonicErrorHandler diff --git a/src/pages/home/home.ts b/src/pages/home/home.ts index 394aa7d4a..74f7b2ef8 100644 --- a/src/pages/home/home.ts +++ b/src/pages/home/home.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { NavController } from 'ionic-angular'; import { AddPage } from "../add/add"; import { ProfileProvider } from '../../providers/profile/profile'; -import { LatestReleaseProvider } from '../../providers/latestRelease/latestRelease'; +import { ReleaseProvider } from '../../providers/release/release'; @Component({ selector: 'page-home', @@ -14,19 +14,22 @@ export class HomePage { constructor( public navCtrl: NavController, private profile: ProfileProvider, - private latestRelease: LatestReleaseProvider, + private release: ReleaseProvider, ) { + this.release.getLatestAppVersion() + .catch((err) => { + console.log('Error:', err)}) + .then((version) => { + console.log('Current app version:',version); + var result = this.release.checkForUpdates(version); + console.log('Update available:', result.updateAvailable); + }); } ionViewDidLoad() { console.log('ionViewDidLoad HomePage'); this.wallets = this.profile.bind(); - this.latestRelease.checkLatestRelease().then((response) => { - console.log('New release available: ', response); - }).catch((error) => { - console.log('Latest Release error: ', error); - }); console.log('[home.ts:20]', this.wallets); //TODO } diff --git a/src/providers/latestRelease/latestRelease.spec.ts b/src/providers/latestRelease/latestRelease.spec.ts deleted file mode 100644 index f47ac117a..000000000 --- a/src/providers/latestRelease/latestRelease.spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { LatestReleaseProviderStub } from '../../../test-config/mocks/latestRelease'; - -describe('Latest Release Provider', () => { - var currentVersion: string; - var latestVersion: string; - - beforeEach(() => { - // Using the mock => 3.3.3 - latestVersion = LatestReleaseProviderStub.checkLatestRelease(null, null); - }); - - it('should check successfully the latest release of the app', () => { - expect(latestVersion).toBeDefined(); - }); - - it('should check unsuccessfully the current release format of the app', () => { - const result = LatestReleaseProviderStub.checkLatestRelease('V.3.3.3', '3.3.3'); - expect(result).toMatch('Cannot'); - expect(result).toMatch('version tag'); - }); - - it('should check unsuccessfully the latest release format of the app', () => { - const result = LatestReleaseProviderStub.checkLatestRelease('3.3.3', 'V.3.3.3'); - expect(result).toMatch('Cannot'); - expect(result).toMatch('release tag'); - }); - - it('should compare the current and latest version of the app with the same value', () => { - currentVersion = '3.3.3'; - const result = LatestReleaseProviderStub.checkLatestRelease(currentVersion, latestVersion); - expect(result).toBeFalsy(); - }); - - it('there should be a new version available', () => { - currentVersion = '3.2.3'; - const result = LatestReleaseProviderStub.checkLatestRelease(currentVersion, latestVersion); - expect(result).toBeTruthy(); - }); - - it('there should not be a new version available', () => { - currentVersion = '3.3.2'; - const result = LatestReleaseProviderStub.checkLatestRelease(currentVersion, latestVersion); - expect(result).toBeFalsy(); - }); -}); diff --git a/src/providers/latestRelease/latestRelease.ts b/src/providers/latestRelease/latestRelease.ts deleted file mode 100644 index bb437ca4c..000000000 --- a/src/providers/latestRelease/latestRelease.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Http } from '@angular/http'; -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/toPromise'; -import { AppProvider } from '../../providers/app/app'; - -@Injectable() -export class LatestReleaseProvider { - private LATEST_RELEASE_URL: string; - private appVersion: string; - - constructor(public http: Http, private app: AppProvider) { - console.log('Hello LatestRelease Provider'); - this.LATEST_RELEASE_URL = 'https://api.github.com/repos/bitpay/copay/releases/latest'; - this.appVersion = this.app.info.version; - } - - checkLatestRelease(): Promise { - return new Promise((resolve, reject) => { - let self = this; - - self.requestLatestRelease().then((release: any) => { - var currentVersion = this.appVersion; - var latestVersion = release.tag_name; - - if (!verifyTagFormat(currentVersion)) - reject('Cannot verify the format of version tag: ' + currentVersion); - if (!verifyTagFormat(latestVersion)) - reject('Cannot verify the format of latest release tag: ' + latestVersion); - - var current = formatTagNumber(currentVersion); - var latest = formatTagNumber(latestVersion); - - if (latest.major < current.major || (latest.major == current.major && latest.minor <= current.minor)) - resolve(false); - else - resolve(true); - - function verifyTagFormat(tag: string) { - var regex = /^v?\d+\.\d+\.\d+$/i; - return regex.exec(tag); - }; - - function formatTagNumber(tag: string) { - var formattedNumber = tag.replace(/^v/i, '').split('.'); - return { - major: +formattedNumber[0], - minor: +formattedNumber[1], - patch: +formattedNumber[2] - }; - }; - - }).catch((error) => { - console.log("Error: ", error); - reject(error); - }); - }); - } - - requestLatestRelease(): Promise { - return this.http.get(this.LATEST_RELEASE_URL) - .map((response) => response.json()) - .toPromise() - .catch((error) => console.log("Error", error)); - } -} diff --git a/src/providers/release/release.spec.ts b/src/providers/release/release.spec.ts new file mode 100644 index 000000000..f75800276 --- /dev/null +++ b/src/providers/release/release.spec.ts @@ -0,0 +1,88 @@ +import { TestBed, inject, async } from '@angular/core/testing'; +import { Http } from '@angular/http'; +import { AppProvider } from '../../providers/app/app'; +import { ReleaseProvider } from './release'; + +describe('Release Provider', () => { + let service: ReleaseProvider; + let currentAppVersion, latestAppVersion; + + class AppProviderMock { + private info: any; + constructor() { + this.info = { version: '1.1.1' }; + }; + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + ReleaseProvider, + { provide: Http }, + { provide: AppProvider, useClass: AppProviderMock }, + ] + }); + }); + + beforeEach(inject([ReleaseProvider], (releaseService: ReleaseProvider) => { + // Mocks + service = releaseService; + currentAppVersion = '1.1.1'; + latestAppVersion = '2.2.2'; + })); + + it('should get successfully the current app version', () => { + // Should return the AppProviderMock object + const appVersion = service.getCurrentAppVersion(); + + expect(appVersion).toBeDefined(); + expect(appVersion).toEqual(currentAppVersion); + }); + + it('should get successfully the latest app version', async(() => { + spyOn(service, 'getLatestAppVersion').and.returnValue(Promise.resolve(latestAppVersion)); + + service.getLatestAppVersion() + .catch((err) => expect(err).toBeNull) + .then((version) => { + expect(version).toBeDefined(); + expect(version).toEqual(latestAppVersion); + }); + })); + + it('should check unsuccessfully the current app version format', () => { + const result = service.checkForUpdates(latestAppVersion, 'V..3.3.3'); + + expect(result.updateAvailable).toBeNull; + expect(result.availabeVersion).toBeNull; + expect(result.error).toBeDefined(); + expect(result.error).toMatch('Cannot'); + expect(result.error).toMatch('version tag'); + }); + + it('should check unsuccessfully the latest app version format', () => { + const result = service.checkForUpdates('V..3.3.3', currentAppVersion); + + expect(result.updateAvailable).toBeNull; + expect(result.availabeVersion).toBeNull; + expect(result.error).toBeDefined(); + expect(result.error).toMatch('Cannot'); + expect(result.error).toMatch('release tag'); + }); + + it('should compare the current and latest app version with the same value', () => { + const result = service.checkForUpdates('1.1.1', '1.1.1'); + + expect(result.error).toBeNull; + expect(result.updateAvailable).toBeNull; + expect(result.availabeVersion).toBeNull; + }); + + it('should be a new version available', () => { + const result = service.checkForUpdates(latestAppVersion, currentAppVersion); + + expect(result.error).toBeNull; + expect(result.updateAvailable).toBeTruthy; + expect(result.availabeVersion).toEqual(latestAppVersion); + }); +}); diff --git a/src/providers/release/release.ts b/src/providers/release/release.ts new file mode 100644 index 000000000..911cf5acd --- /dev/null +++ b/src/providers/release/release.ts @@ -0,0 +1,72 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/toPromise'; +import { AppProvider } from '../../providers/app/app'; + +@Injectable() +export class ReleaseProvider { + private LATEST_RELEASE_URL: string; + private appVersion: string; + + constructor(public http: Http, private app: AppProvider) { + this.LATEST_RELEASE_URL = 'https://api.github.com/repos/bitpay/copay/releases/latest'; + this.appVersion = this.app.info.version; + } + + getCurrentAppVersion() { + return this.appVersion; + } + + getLatestAppVersion(): Promise { + return this.http.get(this.LATEST_RELEASE_URL) + .map((response) => response.json().tag_name) + .toPromise() + .catch((error) => (error)); + } + + checkForUpdates(latestVersion: string, currentVersion?: string) { + if (!currentVersion) currentVersion = this.appVersion; + + var result = { + updateAvailable: null, + availabeVersion: null, + error: null + }; + + if (!verifyTagFormat(currentVersion)) + setErrorAndReturn('Cannot verify the format of version tag: ' + currentVersion); + if(!verifyTagFormat(latestVersion)) + setErrorAndReturn('Cannot verify the format of latest release tag: ' + latestVersion); + + var current = formatTagNumber(currentVersion); + var latest = formatTagNumber(latestVersion); + + if (latest.major < current.major || (latest.major == current.major && latest.minor <= current.minor)) + return (result); + else { + result.updateAvailable = true; + result.availabeVersion = latestVersion; + return result; + } + + function verifyTagFormat(tag: string) { + var regex = /^v?\d+\.\d+\.\d+$/i; + return regex.exec(tag); + }; + + function formatTagNumber(tag: string) { + var formattedNumber = tag.replace(/^v/i, '').split('.'); + return { + major: +formattedNumber[0], + minor: +formattedNumber[1], + patch: +formattedNumber[2] + }; + }; + + function setErrorAndReturn(errorMsg: string) { + result.error = errorMsg; + return result; + } + }; +} diff --git a/test-config/mocks/latestRelease.ts b/test-config/mocks/latestRelease.ts deleted file mode 100644 index 51eb7ed1b..000000000 --- a/test-config/mocks/latestRelease.ts +++ /dev/null @@ -1,36 +0,0 @@ -export let LatestReleaseProviderStub = { - checkLatestRelease(currentVersion: string, latestVersion: string) { - if (!currentVersion || !latestVersion) return this.requestLatestRelease(); - - if (!verifyTagFormat(currentVersion)) - return ('Cannot verify the format of version tag: ' + currentVersion); - if (!verifyTagFormat(latestVersion)) - return ('Cannot verify the format of latest release tag: ' + latestVersion); - - var current = formatTagNumber(currentVersion); - var latest = formatTagNumber(latestVersion); - - if (latest.major < current.major || (latest.major == current.major && latest.minor <= current.minor)) - return false; - else - return true; - - function verifyTagFormat(tag: string) { - var regex = /^v?\d+\.\d+\.\d+$/i; - return regex.exec(tag); - }; - - function formatTagNumber(tag: string) { - var formattedNumber = tag.replace(/^v/i, '').split('.'); - return { - major: +formattedNumber[0], - minor: +formattedNumber[1], - patch: +formattedNumber[2] - }; - }; - }, - - requestLatestRelease() { - return '3.3.3'; - } -}