/** @babel */ import etch from 'etch'; import IncompatiblePackagesComponent from '../lib/incompatible-packages-component'; describe('IncompatiblePackagesComponent', () => { let packages, etchScheduler; beforeEach(() => { etchScheduler = etch.getScheduler(); packages = [ { name: 'incompatible-1', isCompatible() { return false; }, rebuild: function() { return new Promise(resolve => (this.resolveRebuild = resolve)); }, getBuildFailureOutput() { return null; }, path: '/Users/joe/.atom/packages/incompatible-1', metadata: { repository: 'https://github.com/atom/incompatible-1', version: '1.0.0' }, incompatibleModules: [ { name: 'x', version: '1.0.0', error: 'Expected version X, got Y' }, { name: 'y', version: '1.0.0', error: 'Expected version X, got Z' } ] }, { name: 'incompatible-2', isCompatible() { return false; }, rebuild() { return new Promise(resolve => (this.resolveRebuild = resolve)); }, getBuildFailureOutput() { return null; }, path: '/Users/joe/.atom/packages/incompatible-2', metadata: { repository: 'https://github.com/atom/incompatible-2', version: '1.0.0' }, incompatibleModules: [ { name: 'z', version: '1.0.0', error: 'Expected version X, got Y' } ] }, { name: 'compatible', isCompatible() { return true; }, rebuild() { throw new Error('Should not rebuild a compatible package'); }, getBuildFailureOutput() { return null; }, path: '/Users/joe/.atom/packages/b', metadata: { repository: 'https://github.com/atom/b', version: '1.0.0' }, incompatibleModules: [] } ]; }); describe('when packages have not finished loading', () => { it('delays rendering incompatible packages until the end of the tick', () => { waitsForPromise(async () => { let component = new IncompatiblePackagesComponent({ getActivePackages: () => [], getLoadedPackages: () => packages }); let { element } = component; expect( element.querySelectorAll('.incompatible-package').length ).toEqual(0); await etchScheduler.getNextUpdatePromise(); expect( element.querySelectorAll('.incompatible-package').length ).toBeGreaterThan(0); }); }); }); describe('when there are no incompatible packages', () => { it('does not render incompatible packages or the rebuild button', () => { waitsForPromise(async () => { expect(packages[2].isCompatible()).toBe(true); let compatiblePackages = [packages[2]]; let component = new IncompatiblePackagesComponent({ getActivePackages: () => compatiblePackages, getLoadedPackages: () => compatiblePackages }); let { element } = component; await etchScheduler.getNextUpdatePromise(); expect(element.querySelectorAll('.incompatible-package').length).toBe( 0 ); expect(element.querySelector('button')).toBeNull(); }); }); }); describe('when some packages previously failed to rebuild', () => { it('renders them with failed build status and error output', () => { waitsForPromise(async () => { packages[1].getBuildFailureOutput = function() { return 'The build failed'; }; let component = new IncompatiblePackagesComponent({ getActivePackages: () => packages, getLoadedPackages: () => packages }); let { element } = component; await etchScheduler.getNextUpdatePromise(); let packageElement = element.querySelector( '.incompatible-package:nth-child(2)' ); expect(packageElement.querySelector('.badge').textContent).toBe( 'Rebuild Failed' ); expect(packageElement.querySelector('pre').textContent).toBe( 'The build failed' ); }); }); }); describe('when there are incompatible packages', () => { it('renders incompatible packages and the rebuild button', () => { waitsForPromise(async () => { let component = new IncompatiblePackagesComponent({ getActivePackages: () => packages, getLoadedPackages: () => packages }); let { element } = component; await etchScheduler.getNextUpdatePromise(); expect( element.querySelectorAll('.incompatible-package').length ).toEqual(2); expect(element.querySelector('button')).not.toBeNull(); }); }); describe('when the "Rebuild All" button is clicked', () => { it("rebuilds every incompatible package, updating each package's view with status", () => { waitsForPromise(async () => { let component = new IncompatiblePackagesComponent({ getActivePackages: () => packages, getLoadedPackages: () => packages }); let { element } = component; jasmine.attachToDOM(element); await etchScheduler.getNextUpdatePromise(); component.refs.rebuildButton.dispatchEvent( new CustomEvent('click', { bubbles: true }) ); await etchScheduler.getNextUpdatePromise(); // view update expect(component.refs.rebuildButton.disabled).toBe(true); expect(packages[0].resolveRebuild).toBeDefined(); expect( element.querySelector('.incompatible-package:nth-child(1) .badge') .textContent ).toBe('Rebuilding'); expect( element.querySelector('.incompatible-package:nth-child(2) .badge') ).toBeNull(); packages[0].resolveRebuild({ code: 0 }); // simulate rebuild success await etchScheduler.getNextUpdatePromise(); // view update expect(packages[1].resolveRebuild).toBeDefined(); expect( element.querySelector('.incompatible-package:nth-child(1) .badge') .textContent ).toBe('Rebuild Succeeded'); expect( element.querySelector('.incompatible-package:nth-child(2) .badge') .textContent ).toBe('Rebuilding'); packages[1].resolveRebuild({ code: 12, stderr: 'This is an error from the test!' }); // simulate rebuild failure await etchScheduler.getNextUpdatePromise(); // view update expect( element.querySelector('.incompatible-package:nth-child(1) .badge') .textContent ).toBe('Rebuild Succeeded'); expect( element.querySelector('.incompatible-package:nth-child(2) .badge') .textContent ).toBe('Rebuild Failed'); expect( element.querySelector('.incompatible-package:nth-child(2) pre') .textContent ).toBe('This is an error from the test!'); }); }); it('displays a prompt to reload Atom when the packages finish rebuilding', () => { waitsForPromise(async () => { let component = new IncompatiblePackagesComponent({ getActivePackages: () => packages, getLoadedPackages: () => packages }); let { element } = component; jasmine.attachToDOM(element); await etchScheduler.getNextUpdatePromise(); // view update component.refs.rebuildButton.dispatchEvent( new CustomEvent('click', { bubbles: true }) ); expect(packages[0].resolveRebuild({ code: 0 })); await new Promise(global.setImmediate); expect(packages[1].resolveRebuild({ code: 0 })); await etchScheduler.getNextUpdatePromise(); // view update expect(component.refs.reloadButton).toBeDefined(); expect(element.querySelector('.alert').textContent).toMatch(/2 of 2/); spyOn(atom, 'reload'); component.refs.reloadButton.dispatchEvent( new CustomEvent('click', { bubbles: true }) ); expect(atom.reload).toHaveBeenCalled(); }); }); }); describe('when the "Package Settings" button is clicked', () => { it('opens the settings panel for the package', () => { waitsForPromise(async () => { let component = new IncompatiblePackagesComponent({ getActivePackages: () => packages, getLoadedPackages: () => packages }); let { element } = component; jasmine.attachToDOM(element); await etchScheduler.getNextUpdatePromise(); spyOn(atom.workspace, 'open'); element .querySelector('.incompatible-package:nth-child(2) button') .dispatchEvent(new CustomEvent('click', { bubbles: true })); expect(atom.workspace.open).toHaveBeenCalledWith( 'atom://config/packages/incompatible-2' ); }); }); }); }); });