mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-09-21 16:08:24 +03:00
524 lines
15 KiB
JavaScript
524 lines
15 KiB
JavaScript
/* globals assert */
|
|
|
|
const path = require('path');
|
|
const fs = require('fs-plus');
|
|
const url = require('url');
|
|
const { EventEmitter } = require('events');
|
|
const temp = require('temp').track();
|
|
const sandbox = require('sinon').createSandbox();
|
|
const dedent = require('dedent');
|
|
|
|
const AtomWindow = require('../../src/main-process/atom-window');
|
|
const { emitterEventPromise } = require('../async-spec-helpers');
|
|
|
|
describe('AtomWindow', function() {
|
|
let sinon, app, service;
|
|
|
|
beforeEach(function() {
|
|
sinon = sandbox;
|
|
app = new StubApplication(sinon);
|
|
service = new StubRecoveryService(sinon);
|
|
});
|
|
|
|
afterEach(function() {
|
|
sinon.restore();
|
|
});
|
|
|
|
describe('creating a real window', function() {
|
|
let resourcePath, windowInitializationScript, atomHome;
|
|
let original;
|
|
|
|
this.timeout(10 * 1000);
|
|
|
|
beforeEach(async function() {
|
|
original = {
|
|
ATOM_HOME: process.env.ATOM_HOME,
|
|
ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT:
|
|
process.env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT
|
|
};
|
|
|
|
resourcePath = path.resolve(__dirname, '../..');
|
|
|
|
windowInitializationScript = require.resolve(
|
|
path.join(resourcePath, 'src/initialize-application-window')
|
|
);
|
|
|
|
atomHome = await new Promise((resolve, reject) => {
|
|
temp.mkdir('launch-', (err, rootPath) => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve(rootPath);
|
|
}
|
|
});
|
|
});
|
|
|
|
await new Promise((resolve, reject) => {
|
|
const config = dedent`
|
|
'*':
|
|
core:
|
|
automaticallyUpdate: false
|
|
welcome:
|
|
showOnStartup: false
|
|
`;
|
|
|
|
fs.writeFile(
|
|
path.join(atomHome, 'config.cson'),
|
|
config,
|
|
{ encoding: 'utf8' },
|
|
err => {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve();
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
process.env.ATOM_HOME = atomHome;
|
|
process.env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT = 'true';
|
|
});
|
|
|
|
afterEach(async function() {
|
|
process.env.ATOM_HOME = original.ATOM_HOME;
|
|
process.env.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT =
|
|
original.ATOM_DISABLE_SHELLING_OUT_FOR_ENVIRONMENT;
|
|
});
|
|
|
|
it('creates a real, properly configured BrowserWindow', async function() {
|
|
const w = new AtomWindow(app, service, {
|
|
resourcePath,
|
|
windowInitializationScript,
|
|
headless: true,
|
|
extra: 'extra-load-setting'
|
|
});
|
|
const { browserWindow } = w;
|
|
|
|
assert.isFalse(browserWindow.isVisible());
|
|
assert.isTrue(browserWindow.getTitle().startsWith('Pulsar'));
|
|
|
|
const settings = JSON.parse(browserWindow.loadSettingsJSON);
|
|
assert.strictEqual(settings.userSettings, 'stub-config');
|
|
assert.strictEqual(settings.extra, 'extra-load-setting');
|
|
assert.strictEqual(settings.resourcePath, resourcePath);
|
|
assert.strictEqual(settings.atomHome, atomHome);
|
|
assert.isFalse(settings.devMode);
|
|
assert.isFalse(settings.safeMode);
|
|
assert.isFalse(settings.clearWindowState);
|
|
|
|
await emitterEventPromise(browserWindow, 'ready-to-show');
|
|
|
|
assert.strictEqual(
|
|
browserWindow.webContents.getURL(),
|
|
url.format({
|
|
protocol: 'file',
|
|
pathname: `${resourcePath.replace(/\\/g, '/')}/static/index.html`,
|
|
slashes: true
|
|
})
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('launch behavior', function() {
|
|
if (process.platform === 'darwin') {
|
|
it('sets titleBarStyle to "hidden" for a custom title bar on non-spec windows', function() {
|
|
app.config['core.titleBar'] = 'custom';
|
|
|
|
const { browserWindow: w0 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow
|
|
});
|
|
assert.strictEqual(w0.options.titleBarStyle, 'hidden');
|
|
|
|
const { browserWindow: w1 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
isSpec: true
|
|
});
|
|
assert.isUndefined(w1.options.titleBarStyle);
|
|
});
|
|
|
|
it('sets titleBarStyle to "hiddenInset" for a custom inset title bar on non-spec windows', function() {
|
|
app.config['core.titleBar'] = 'custom-inset';
|
|
|
|
const { browserWindow: w0 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow
|
|
});
|
|
assert.strictEqual(w0.options.titleBarStyle, 'hiddenInset');
|
|
|
|
const { browserWindow: w1 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
isSpec: true
|
|
});
|
|
assert.isUndefined(w1.options.titleBarStyle);
|
|
});
|
|
it('sets frame to "false" for a hidden title bar on non-spec windows', function() {
|
|
app.config['core.titleBar'] = 'hidden';
|
|
|
|
const { browserWindow: w0 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow
|
|
});
|
|
assert.isFalse(w0.options.frame);
|
|
|
|
const { browserWindow: w1 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
isSpec: true
|
|
});
|
|
assert.isUndefined(w1.options.frame);
|
|
});
|
|
} else {
|
|
it('sets frame to "false" for a hidden title bar on non-spec windows', function() {
|
|
app.config['core.titleBar'] = 'hidden';
|
|
|
|
const { browserWindow: w0 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow
|
|
});
|
|
assert.isFalse(w0.options.frame);
|
|
|
|
const { browserWindow: w1 } = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
isSpec: true
|
|
});
|
|
assert.isUndefined(w1.options.frame);
|
|
});
|
|
}
|
|
|
|
it('opens initial locations', async function() {
|
|
const locationsToOpen = [
|
|
{
|
|
pathToOpen: 'file.txt',
|
|
initialLine: 1,
|
|
initialColumn: 2,
|
|
isDirectory: false,
|
|
hasWaitSession: false
|
|
},
|
|
{
|
|
pathToOpen: '/directory',
|
|
initialLine: null,
|
|
initialColumn: null,
|
|
isDirectory: true,
|
|
hasWaitSession: false
|
|
}
|
|
];
|
|
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
assert.deepEqual(w.projectRoots, ['/directory']);
|
|
|
|
const loadPromise = emitterEventPromise(w, 'window:loaded');
|
|
w.browserWindow.emit('window:loaded');
|
|
await loadPromise;
|
|
|
|
assert.deepEqual(w.browserWindow.sent, [
|
|
['message', 'open-locations', locationsToOpen]
|
|
]);
|
|
});
|
|
|
|
it('does not open an initial null location', async function() {
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen: [{ pathToOpen: null }]
|
|
});
|
|
|
|
const loadPromise = emitterEventPromise(w, 'window:loaded');
|
|
w.browserWindow.emit('window:loaded');
|
|
await loadPromise;
|
|
|
|
assert.lengthOf(w.browserWindow.sent, 0);
|
|
});
|
|
|
|
it('does not open initial locations in spec mode', async function() {
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen: [{ pathToOpen: 'file.txt' }],
|
|
isSpec: true
|
|
});
|
|
|
|
const loadPromise = emitterEventPromise(w, 'window:loaded');
|
|
w.browserWindow.emit('window:loaded');
|
|
await loadPromise;
|
|
|
|
assert.lengthOf(w.browserWindow.sent, 0);
|
|
});
|
|
|
|
it('focuses the webView for specs', function() {
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
isSpec: true
|
|
});
|
|
|
|
assert.isTrue(w.browserWindow.behavior.focusOnWebView);
|
|
});
|
|
});
|
|
|
|
describe('project root tracking', function() {
|
|
it('knows when it has no roots', function() {
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow
|
|
});
|
|
assert.isFalse(w.hasProjectPaths());
|
|
});
|
|
|
|
it('is initialized from directories in the initial locationsToOpen', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'file.txt', exists: true, isFile: true },
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'new-file.txt' },
|
|
{ pathToOpen: null }
|
|
];
|
|
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
|
|
assert.deepEqual(w.projectRoots, ['directory0', 'directory1']);
|
|
assert.isTrue(w.loadSettings.hasOpenFiles);
|
|
assert.deepEqual(w.loadSettings.initialProjectRoots, [
|
|
'directory0',
|
|
'directory1'
|
|
]);
|
|
assert.isTrue(w.hasProjectPaths());
|
|
});
|
|
|
|
it('is updated synchronously by openLocations', async function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'file.txt', isFile: true },
|
|
{ pathToOpen: 'directory1', isDirectory: true },
|
|
{ pathToOpen: 'directory0', isDirectory: true },
|
|
{ pathToOpen: 'directory0', isDirectory: true },
|
|
{ pathToOpen: 'new-file.txt' }
|
|
];
|
|
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow
|
|
});
|
|
assert.deepEqual(w.projectRoots, []);
|
|
|
|
const promise = w.openLocations(locationsToOpen);
|
|
assert.deepEqual(w.projectRoots, ['directory0', 'directory1']);
|
|
w.resolveLoadedPromise();
|
|
await promise;
|
|
});
|
|
|
|
it('is updated by setProjectRoots', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true }
|
|
];
|
|
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
assert.deepEqual(w.projectRoots, ['directory0']);
|
|
assert.deepEqual(w.loadSettings.initialProjectRoots, ['directory0']);
|
|
|
|
w.setProjectRoots(['directory1', 'directory0', 'directory2']);
|
|
assert.deepEqual(w.projectRoots, [
|
|
'directory0',
|
|
'directory1',
|
|
'directory2'
|
|
]);
|
|
assert.deepEqual(w.loadSettings.initialProjectRoots, [
|
|
'directory0',
|
|
'directory1',
|
|
'directory2'
|
|
]);
|
|
});
|
|
|
|
it('never reports that it owns the empty path', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true },
|
|
{ pathToOpen: null }
|
|
];
|
|
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
assert.isFalse(w.containsLocation({ pathToOpen: null }));
|
|
});
|
|
|
|
it('discovers an exact path match', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true }
|
|
];
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
|
|
assert.isTrue(w.containsLocation({ pathToOpen: 'directory0' }));
|
|
assert.isFalse(w.containsLocation({ pathToOpen: 'directory2' }));
|
|
});
|
|
|
|
it('discovers the path of a file within any project root', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true }
|
|
];
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
|
|
assert.isTrue(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory0/file-0.txt'),
|
|
exists: true,
|
|
isFile: true
|
|
})
|
|
);
|
|
assert.isTrue(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory0/deep/file-0.txt'),
|
|
exists: true,
|
|
isFile: true
|
|
})
|
|
);
|
|
assert.isFalse(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory2/file-9.txt'),
|
|
exists: true,
|
|
isFile: true
|
|
})
|
|
);
|
|
assert.isFalse(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory2/deep/file-9.txt'),
|
|
exists: true,
|
|
isFile: true
|
|
})
|
|
);
|
|
});
|
|
|
|
it('reports that it owns nonexistent paths within a project root', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true }
|
|
];
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
|
|
assert.isTrue(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory0/file-1.txt'),
|
|
exists: false
|
|
})
|
|
);
|
|
assert.isTrue(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory1/subdir/file-0.txt'),
|
|
exists: false
|
|
})
|
|
);
|
|
});
|
|
|
|
it('never reports that it owns directories within a project root', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true }
|
|
];
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
|
|
assert.isFalse(
|
|
w.containsLocation({
|
|
pathToOpen: path.join('directory0/subdir-0'),
|
|
exists: true,
|
|
isDirectory: true
|
|
})
|
|
);
|
|
});
|
|
|
|
it('checks a full list of paths and reports if it owns all of them', function() {
|
|
const locationsToOpen = [
|
|
{ pathToOpen: 'directory0', exists: true, isDirectory: true },
|
|
{ pathToOpen: 'directory1', exists: true, isDirectory: true }
|
|
];
|
|
const w = new AtomWindow(app, service, {
|
|
browserWindowConstructor: StubBrowserWindow,
|
|
locationsToOpen
|
|
});
|
|
|
|
assert.isTrue(
|
|
w.containsLocations([
|
|
{ pathToOpen: 'directory0' },
|
|
{
|
|
pathToOpen: path.join('directory1/file-0.txt'),
|
|
exists: true,
|
|
isFile: true
|
|
}
|
|
])
|
|
);
|
|
assert.isFalse(
|
|
w.containsLocations([
|
|
{ pathToOpen: 'directory2' },
|
|
{ pathToOpen: 'directory0' }
|
|
])
|
|
);
|
|
assert.isFalse(
|
|
w.containsLocations([
|
|
{ pathToOpen: 'directory2' },
|
|
{ pathToOpen: 'directory1' }
|
|
])
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
class StubApplication {
|
|
constructor(sinon) {
|
|
this.config = {
|
|
'core.titleBar': 'native',
|
|
get: key => this.config[key] || null
|
|
};
|
|
this.configFile = {
|
|
get() {
|
|
return 'stub-config';
|
|
}
|
|
};
|
|
|
|
this.removeWindow = sinon.spy();
|
|
this.saveCurrentWindowOptions = sinon.spy();
|
|
}
|
|
}
|
|
|
|
class StubRecoveryService {
|
|
constructor(sinon) {
|
|
this.didCloseWindow = sinon.spy();
|
|
this.didCrashWindow = sinon.spy();
|
|
}
|
|
}
|
|
|
|
class StubBrowserWindow extends EventEmitter {
|
|
constructor(options) {
|
|
super();
|
|
this.options = options;
|
|
this.sent = [];
|
|
this.behavior = {
|
|
focusOnWebView: false
|
|
};
|
|
|
|
this.webContents = new EventEmitter();
|
|
this.webContents.send = (...args) => {
|
|
this.sent.push(args);
|
|
};
|
|
this.webContents.setVisualZoomLevelLimits = () => {};
|
|
}
|
|
|
|
loadURL() {}
|
|
|
|
focusOnWebView() {
|
|
this.behavior.focusOnWebView = true;
|
|
}
|
|
}
|