mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-11 04:48:44 +03:00
357 lines
13 KiB
JavaScript
357 lines
13 KiB
JavaScript
const path = require('path');
|
|
const Package = require('../src/package');
|
|
const ThemePackage = require('../src/theme-package');
|
|
const { mockLocalStorage } = require('./spec-helper');
|
|
|
|
describe('Package', function() {
|
|
const build = (constructor, packagePath) =>
|
|
new constructor({
|
|
path: packagePath,
|
|
packageManager: atom.packages,
|
|
config: atom.config,
|
|
styleManager: atom.styles,
|
|
notificationManager: atom.notifications,
|
|
keymapManager: atom.keymaps,
|
|
commandRegistry: atom.command,
|
|
grammarRegistry: atom.grammars,
|
|
themeManager: atom.themes,
|
|
menuManager: atom.menu,
|
|
contextMenuManager: atom.contextMenu,
|
|
deserializerManager: atom.deserializers,
|
|
viewRegistry: atom.views
|
|
});
|
|
|
|
const buildPackage = packagePath => build(Package, packagePath);
|
|
|
|
const buildThemePackage = themePath => build(ThemePackage, themePath);
|
|
|
|
describe('when the package contains incompatible native modules', function() {
|
|
beforeEach(function() {
|
|
atom.packages.devMode = false;
|
|
mockLocalStorage();
|
|
});
|
|
|
|
afterEach(() => (atom.packages.devMode = true));
|
|
|
|
it('does not activate it', function() {
|
|
const packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve('packages/package-with-incompatible-native-module');
|
|
const pack = buildPackage(packagePath);
|
|
expect(pack.isCompatible()).toBe(false);
|
|
expect(pack.incompatibleModules[0].name).toBe('native-module');
|
|
expect(pack.incompatibleModules[0].path).toBe(
|
|
path.join(packagePath, 'node_modules', 'native-module')
|
|
);
|
|
});
|
|
|
|
it('detects the package as incompatible even if .node file is loaded conditionally', function() {
|
|
const packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve(
|
|
'packages/package-with-incompatible-native-module-loaded-conditionally'
|
|
);
|
|
const pack = buildPackage(packagePath);
|
|
expect(pack.isCompatible()).toBe(false);
|
|
expect(pack.incompatibleModules[0].name).toBe('native-module');
|
|
expect(pack.incompatibleModules[0].path).toBe(
|
|
path.join(packagePath, 'node_modules', 'native-module')
|
|
);
|
|
});
|
|
|
|
it("utilizes _atomModuleCache if present to determine the package's native dependencies", function() {
|
|
let packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve('packages/package-with-ignored-incompatible-native-module');
|
|
let pack = buildPackage(packagePath);
|
|
expect(pack.getNativeModuleDependencyPaths().length).toBe(1); // doesn't see the incompatible module
|
|
expect(pack.isCompatible()).toBe(true);
|
|
|
|
packagePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/package-with-cached-incompatible-native-module')
|
|
);
|
|
pack = buildPackage(packagePath);
|
|
expect(pack.isCompatible()).toBe(false);
|
|
});
|
|
|
|
it('caches the incompatible native modules in local storage', function() {
|
|
const packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve('packages/package-with-incompatible-native-module');
|
|
expect(buildPackage(packagePath).isCompatible()).toBe(false);
|
|
expect(global.localStorage.getItem.callCount).toBe(1);
|
|
expect(global.localStorage.setItem.callCount).toBe(1);
|
|
|
|
expect(buildPackage(packagePath).isCompatible()).toBe(false);
|
|
expect(global.localStorage.getItem.callCount).toBe(2);
|
|
expect(global.localStorage.setItem.callCount).toBe(1);
|
|
});
|
|
|
|
it('logs an error to the console describing the problem', function() {
|
|
const packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve('packages/package-with-incompatible-native-module');
|
|
|
|
spyOn(console, 'warn');
|
|
spyOn(atom.notifications, 'addFatalError');
|
|
|
|
buildPackage(packagePath).activateNow();
|
|
|
|
expect(atom.notifications.addFatalError).not.toHaveBeenCalled();
|
|
expect(console.warn.callCount).toBe(1);
|
|
expect(console.warn.mostRecentCall.args[0]).toContain(
|
|
'it requires one or more incompatible native modules (native-module)'
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('::rebuild()', function() {
|
|
beforeEach(function() {
|
|
atom.packages.devMode = false;
|
|
mockLocalStorage();
|
|
});
|
|
|
|
afterEach(() => (atom.packages.devMode = true));
|
|
|
|
it('returns a promise resolving to the results of `apm rebuild`', function() {
|
|
const packagePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/package-with-index')
|
|
);
|
|
const pack = buildPackage(packagePath);
|
|
const rebuildCallbacks = [];
|
|
spyOn(pack, 'runRebuildProcess').andCallFake(callback =>
|
|
rebuildCallbacks.push(callback)
|
|
);
|
|
|
|
const promise = pack.rebuild();
|
|
rebuildCallbacks[0]({
|
|
code: 0,
|
|
stdout: 'stdout output',
|
|
stderr: 'stderr output'
|
|
});
|
|
|
|
waitsFor(done =>
|
|
promise.then(function(result) {
|
|
expect(result).toEqual({
|
|
code: 0,
|
|
stdout: 'stdout output',
|
|
stderr: 'stderr output'
|
|
});
|
|
done();
|
|
})
|
|
);
|
|
});
|
|
|
|
it('persists build failures in local storage', function() {
|
|
const packagePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/package-with-index')
|
|
);
|
|
const pack = buildPackage(packagePath);
|
|
|
|
expect(pack.isCompatible()).toBe(true);
|
|
expect(pack.getBuildFailureOutput()).toBeNull();
|
|
|
|
const rebuildCallbacks = [];
|
|
spyOn(pack, 'runRebuildProcess').andCallFake(callback =>
|
|
rebuildCallbacks.push(callback)
|
|
);
|
|
|
|
pack.rebuild();
|
|
rebuildCallbacks[0]({ code: 13, stderr: 'It is broken' });
|
|
|
|
expect(pack.getBuildFailureOutput()).toBe('It is broken');
|
|
expect(pack.getIncompatibleNativeModules()).toEqual([]);
|
|
expect(pack.isCompatible()).toBe(false);
|
|
|
|
// A different package instance has the same failure output (simulates reload)
|
|
const pack2 = buildPackage(packagePath);
|
|
expect(pack2.getBuildFailureOutput()).toBe('It is broken');
|
|
expect(pack2.isCompatible()).toBe(false);
|
|
|
|
// Clears the build failure after a successful build
|
|
pack.rebuild();
|
|
rebuildCallbacks[1]({ code: 0, stdout: 'It worked' });
|
|
|
|
expect(pack.getBuildFailureOutput()).toBeNull();
|
|
expect(pack2.getBuildFailureOutput()).toBeNull();
|
|
});
|
|
|
|
it('sets cached incompatible modules to an empty array when the rebuild completes (there may be a build error, but rebuilding *deletes* native modules)', function() {
|
|
const packagePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/package-with-incompatible-native-module')
|
|
);
|
|
const pack = buildPackage(packagePath);
|
|
|
|
expect(pack.getIncompatibleNativeModules().length).toBeGreaterThan(0);
|
|
|
|
const rebuildCallbacks = [];
|
|
spyOn(pack, 'runRebuildProcess').andCallFake(callback =>
|
|
rebuildCallbacks.push(callback)
|
|
);
|
|
|
|
pack.rebuild();
|
|
expect(pack.getIncompatibleNativeModules().length).toBeGreaterThan(0);
|
|
rebuildCallbacks[0]({ code: 0, stdout: 'It worked' });
|
|
expect(pack.getIncompatibleNativeModules().length).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('theme', function() {
|
|
let [editorElement, theme] = [];
|
|
|
|
beforeEach(function() {
|
|
editorElement = document.createElement('atom-text-editor');
|
|
jasmine.attachToDOM(editorElement);
|
|
});
|
|
|
|
afterEach(() =>
|
|
waitsForPromise(function() {
|
|
if (theme != null) {
|
|
return Promise.resolve(theme.deactivate());
|
|
}
|
|
})
|
|
);
|
|
|
|
describe('when the theme contains a single style file', function() {
|
|
it('loads and applies css', function() {
|
|
expect(getComputedStyle(editorElement).paddingBottom).not.toBe(
|
|
'1234px'
|
|
);
|
|
const themePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/theme-with-index-css')
|
|
);
|
|
theme = buildThemePackage(themePath);
|
|
theme.activate();
|
|
expect(getComputedStyle(editorElement).paddingTop).toBe('1234px');
|
|
});
|
|
|
|
it('parses, loads and applies less', function() {
|
|
expect(getComputedStyle(editorElement).paddingBottom).not.toBe(
|
|
'1234px'
|
|
);
|
|
const themePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/theme-with-index-less')
|
|
);
|
|
theme = buildThemePackage(themePath);
|
|
theme.activate();
|
|
expect(getComputedStyle(editorElement).paddingTop).toBe('4321px');
|
|
});
|
|
});
|
|
|
|
describe('when the theme contains a package.json file', () =>
|
|
it('loads and applies stylesheets from package.json in the correct order', function() {
|
|
expect(getComputedStyle(editorElement).paddingTop).not.toBe('101px');
|
|
expect(getComputedStyle(editorElement).paddingRight).not.toBe('102px');
|
|
expect(getComputedStyle(editorElement).paddingBottom).not.toBe('103px');
|
|
|
|
const themePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/theme-with-package-file')
|
|
);
|
|
theme = buildThemePackage(themePath);
|
|
theme.activate();
|
|
expect(getComputedStyle(editorElement).paddingTop).toBe('101px');
|
|
expect(getComputedStyle(editorElement).paddingRight).toBe('102px');
|
|
expect(getComputedStyle(editorElement).paddingBottom).toBe('103px');
|
|
}));
|
|
|
|
describe('when the theme does not contain a package.json file and is a directory', () =>
|
|
it('loads all stylesheet files in the directory', function() {
|
|
expect(getComputedStyle(editorElement).paddingTop).not.toBe('10px');
|
|
expect(getComputedStyle(editorElement).paddingRight).not.toBe('20px');
|
|
expect(getComputedStyle(editorElement).paddingBottom).not.toBe('30px');
|
|
|
|
const themePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/theme-without-package-file')
|
|
);
|
|
theme = buildThemePackage(themePath);
|
|
theme.activate();
|
|
expect(getComputedStyle(editorElement).paddingTop).toBe('10px');
|
|
expect(getComputedStyle(editorElement).paddingRight).toBe('20px');
|
|
expect(getComputedStyle(editorElement).paddingBottom).toBe('30px');
|
|
}));
|
|
|
|
describe('reloading a theme', function() {
|
|
beforeEach(function() {
|
|
const themePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/theme-with-package-file')
|
|
);
|
|
theme = buildThemePackage(themePath);
|
|
theme.activate();
|
|
});
|
|
|
|
it('reloads without readding to the stylesheets list', function() {
|
|
expect(theme.getStylesheetPaths().length).toBe(3);
|
|
theme.reloadStylesheets();
|
|
expect(theme.getStylesheetPaths().length).toBe(3);
|
|
});
|
|
});
|
|
|
|
describe('events', function() {
|
|
beforeEach(function() {
|
|
const themePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/theme-with-package-file')
|
|
);
|
|
theme = buildThemePackage(themePath);
|
|
theme.activate();
|
|
});
|
|
|
|
it('deactivated event fires on .deactivate()', function() {
|
|
let spy;
|
|
theme.onDidDeactivate((spy = jasmine.createSpy()));
|
|
waitsForPromise(() => Promise.resolve(theme.deactivate()));
|
|
runs(() => expect(spy).toHaveBeenCalled());
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('.loadMetadata()', function() {
|
|
let [packagePath, metadata] = [];
|
|
|
|
beforeEach(function() {
|
|
packagePath = __guard__(atom.project.getDirectories()[0], x =>
|
|
x.resolve('packages/package-with-different-directory-name')
|
|
);
|
|
metadata = atom.packages.loadPackageMetadata(packagePath, true);
|
|
});
|
|
|
|
it('uses the package name defined in package.json', () =>
|
|
expect(metadata.name).toBe('package-with-a-totally-different-name'));
|
|
});
|
|
|
|
describe('the initialize() hook', function() {
|
|
it('gets called when the package is activated', function() {
|
|
const packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve('packages/package-with-deserializers');
|
|
const pack = buildPackage(packagePath);
|
|
pack.requireMainModule();
|
|
const { mainModule } = pack;
|
|
spyOn(mainModule, 'initialize');
|
|
expect(mainModule.initialize).not.toHaveBeenCalled();
|
|
pack.activate();
|
|
expect(mainModule.initialize).toHaveBeenCalled();
|
|
expect(mainModule.initialize.callCount).toBe(1);
|
|
});
|
|
|
|
it('gets called when a deserializer is used', function() {
|
|
const packagePath = atom.project
|
|
.getDirectories()[0]
|
|
.resolve('packages/package-with-deserializers');
|
|
const pack = buildPackage(packagePath);
|
|
pack.requireMainModule();
|
|
const { mainModule } = pack;
|
|
spyOn(mainModule, 'initialize');
|
|
pack.load();
|
|
expect(mainModule.initialize).not.toHaveBeenCalled();
|
|
atom.deserializers.deserialize({ deserializer: 'Deserializer1', a: 'b' });
|
|
expect(mainModule.initialize).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|
|
|
|
function __guard__(value, transform) {
|
|
return typeof value !== 'undefined' && value !== null
|
|
? transform(value)
|
|
: undefined;
|
|
}
|