const {shell} = require('electron') const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./helpers/async-spec-helpers') // eslint-disable-line no-unused-vars const main = require('../lib/main') const AboutView = require('../lib/components/about-view') const UpdateView = require('../lib/components/update-view') const MockUpdater = require('./mocks/updater') describe('UpdateView', () => { let aboutElement let updateManager let workspaceElement let scheduler beforeEach(async () => { let storage = {} spyOn(window.localStorage, 'setItem').andCallFake((key, value) => { storage[key] = value }) spyOn(window.localStorage, 'getItem').andCallFake((key) => { return storage[key] }) workspaceElement = atom.views.getView(atom.workspace) await atom.packages.activatePackage('about') spyOn(atom.autoUpdater, 'getState').andReturn('idle') spyOn(atom.autoUpdater, 'checkForUpdate') spyOn(atom.autoUpdater, 'platformSupportsUpdates').andReturn(true) }) describe('when the About page is open', () => { beforeEach(async () => { jasmine.attachToDOM(workspaceElement) await atom.workspace.open('atom://about') aboutElement = workspaceElement.querySelector('.about') updateManager = main.model.state.updateManager scheduler = AboutView.getScheduler() }) describe('when the updates are not supported by the platform', () => { beforeEach(async () => { atom.autoUpdater.platformSupportsUpdates.andReturn(false) updateManager.resetState() await scheduler.getNextUpdatePromise() }) it('hides the auto update UI and shows the update instructions link', async () => { expect(aboutElement.querySelector('.about-update-action-button')).not.toBeVisible() expect(aboutElement.querySelector('.about-auto-updates')).not.toBeVisible() }) it('opens the update instructions page when the instructions link is clicked', async () => { spyOn(shell, 'openExternal') let link = aboutElement.querySelector('.app-unsupported .about-updates-instructions') link.click() let args = shell.openExternal.mostRecentCall.args expect(shell.openExternal).toHaveBeenCalled() expect(args[0]).toContain('installing-atom') }) }) describe('when updates are supported by the platform', () => { beforeEach(async () => { atom.autoUpdater.platformSupportsUpdates.andReturn(true) updateManager.resetState() await scheduler.getNextUpdatePromise() }) it('shows the auto update UI', () => { expect(aboutElement.querySelector('.about-updates')).toBeVisible() }) it('shows the correct panels when the app checks for updates and there is no update available', async () => { expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() MockUpdater.checkForUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible() expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible() MockUpdater.updateNotAvailable() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).toBeVisible() expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() }) it('shows the correct panels when the app checks for updates and encounters an error', async () => { expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() MockUpdater.checkForUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible() expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible() spyOn(atom.autoUpdater, 'getErrorMessage').andReturn('an error message') MockUpdater.updateError() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-update-error')).toBeVisible() expect(aboutElement.querySelector('.app-error-message').textContent).toBe('an error message') expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') }) it('shows the correct panels and button states when the app checks for updates and an update is downloaded', async () => { expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') MockUpdater.checkForUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-up-to-date')).not.toBeVisible() expect(aboutElement.querySelector('.app-checking-for-updates')).toBeVisible() expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') MockUpdater.downloadUpdate() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() expect(aboutElement.querySelector('.app-downloading-update')).toBeVisible() // TODO: at some point it would be nice to be able to cancel an update download, and then this would be a cancel button expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') MockUpdater.finishDownloadingUpdate('42.0.0') await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-downloading-update')).not.toBeVisible() expect(aboutElement.querySelector('.app-update-available-to-install')).toBeVisible() expect(aboutElement.querySelector('.app-update-available-to-install .about-updates-version').textContent).toBe('42.0.0') expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Restart and install') }) it('opens the release notes for the downloaded release when the release notes link are clicked', async () => { MockUpdater.finishDownloadingUpdate('1.2.3') await scheduler.getNextUpdatePromise() spyOn(shell, 'openExternal') let link = aboutElement.querySelector('.app-update-available-to-install .about-updates-release-notes') link.click() let args = shell.openExternal.mostRecentCall.args expect(shell.openExternal).toHaveBeenCalled() expect(args[0]).toContain('/v1.2.3') }) it('executes checkForUpdate() when the check for update button is clicked', () => { let button = aboutElement.querySelector('.about-update-action-button') button.click() expect(atom.autoUpdater.checkForUpdate).toHaveBeenCalled() }) it('executes restartAndInstallUpdate() when the restart and install button is clicked', async () => { spyOn(atom.autoUpdater, 'restartAndInstallUpdate') MockUpdater.finishDownloadingUpdate('42.0.0') await scheduler.getNextUpdatePromise() let button = aboutElement.querySelector('.about-update-action-button') button.click() expect(atom.autoUpdater.restartAndInstallUpdate).toHaveBeenCalled() }) it("starts in the same state as atom's AutoUpdateManager", async () => { atom.autoUpdater.getState.andReturn('downloading') updateManager.resetState() await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.app-checking-for-updates')).not.toBeVisible() expect(aboutElement.querySelector('.app-downloading-update')).toBeVisible() expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(true) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Check now') }) describe('when core.automaticallyUpdate is toggled', () => { beforeEach(async () => { expect(atom.config.get('core.automaticallyUpdate')).toBe(true) atom.autoUpdater.checkForUpdate.reset() }) it('shows the auto update UI', async () => { expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true) expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Atom will check for updates automatically') atom.config.set('core.automaticallyUpdate', false) await scheduler.getNextUpdatePromise() expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(false) expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Automatic updates are disabled please check manually') }) it('updates config and the UI when the checkbox is used to toggle', async () => { expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true) aboutElement.querySelector('.about-auto-updates input').click() await scheduler.getNextUpdatePromise() expect(atom.config.get('core.automaticallyUpdate')).toBe(false) expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(false) expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Automatic updates are disabled please check manually') aboutElement.querySelector('.about-auto-updates input').click() await scheduler.getNextUpdatePromise() expect(atom.config.get('core.automaticallyUpdate')).toBe(true) expect(aboutElement.querySelector('.about-auto-updates input').checked).toBe(true) expect(aboutElement.querySelector('.about-default-update-message')).toBeVisible() expect(aboutElement.querySelector('.about-default-update-message').textContent).toBe('Atom will check for updates automatically') }) describe('checking for updates', function () { afterEach(() => { this.updateView = null }) it('checks for update when the about page is shown', () => { expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled() this.updateView = new UpdateView({ updateManager: updateManager, availableVersion: '9999.0.0', viewUpdateReleaseNotes: () => {} }) expect(atom.autoUpdater.checkForUpdate).toHaveBeenCalled() }) it('does not check for update when the about page is shown and the update manager is not in the idle state', () => { atom.autoUpdater.getState.andReturn('downloading') updateManager.resetState() expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled() this.updateView = new UpdateView({ updateManager: updateManager, availableVersion: '9999.0.0', viewUpdateReleaseNotes: () => {} }) expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled() }) it('does not check for update when the about page is shown and auto updates are turned off', () => { atom.config.set('core.automaticallyUpdate', false) expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled() this.updateView = new UpdateView({ updateManager: updateManager, availableVersion: '9999.0.0', viewUpdateReleaseNotes: () => {} }) expect(atom.autoUpdater.checkForUpdate).not.toHaveBeenCalled() }) }) }) }) }) describe('when the About page is not open and an update is downloaded', () => { it('should display the new version when it is opened', async () => { MockUpdater.finishDownloadingUpdate('42.0.0') jasmine.attachToDOM(workspaceElement) await atom.workspace.open('atom://about') aboutElement = workspaceElement.querySelector('.about') updateManager = main.model.state.updateManager scheduler = AboutView.getScheduler() expect(aboutElement.querySelector('.app-update-available-to-install')).toBeVisible() expect(aboutElement.querySelector('.app-update-available-to-install .about-updates-version').textContent).toBe('42.0.0') expect(aboutElement.querySelector('.about-update-action-button').disabled).toBe(false) expect(aboutElement.querySelector('.about-update-action-button').textContent).toBe('Restart and install') }) }) })