Files
mattermostest/src/app/serverViewState.test.js

508 lines
19 KiB
JavaScript

// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {MattermostServer} from 'common/servers/MattermostServer';
import ServerManager from 'common/servers/serverManager';
import {URLValidationStatus} from 'common/utils/constants';
import {getDefaultViewsForConfigServer} from 'common/views/View';
import {ServerInfo} from 'main/server/serverInfo';
import ModalManager from 'main/views/modalManager';
import {getLocalURLString, getLocalPreload} from 'main/utils';
import MainWindow from 'main/windows/mainWindow';
import ViewManager from 'main/views/viewManager';
import {ServerViewState} from './serverViewState';
jest.mock('electron', () => ({
ipcMain: {
on: jest.fn(),
handle: jest.fn(),
emit: jest.fn(),
},
}));
jest.mock('common/servers/serverManager', () => ({
setViewIsOpen: jest.fn(),
getAllServers: jest.fn(),
hasServers: jest.fn(),
addServer: jest.fn(),
editServer: jest.fn(),
removeServer: jest.fn(),
getServer: jest.fn(),
getView: jest.fn(),
getLastActiveTabForServer: jest.fn(),
getServerLog: jest.fn(),
lookupViewByURL: jest.fn(),
getOrderedServers: jest.fn(),
}));
jest.mock('common/servers/MattermostServer', () => ({
MattermostServer: jest.fn(),
}));
jest.mock('common/views/View', () => ({
getDefaultViewsForConfigServer: jest.fn(),
}));
jest.mock('main/server/serverInfo', () => ({
ServerInfo: jest.fn(),
}));
jest.mock('main/views/modalManager', () => ({
addModal: jest.fn(),
}));
jest.mock('main/utils', () => ({
getLocalPreload: jest.fn(),
getLocalURLString: jest.fn(),
}));
jest.mock('main/windows/mainWindow', () => ({
get: jest.fn(),
show: jest.fn(),
}));
jest.mock('main/views/viewManager', () => ({
getView: jest.fn(),
showById: jest.fn(),
}));
const tabs = [
{
name: 'view-1',
order: 0,
isOpen: false,
},
{
name: 'view-2',
order: 2,
isOpen: true,
},
{
name: 'view-3',
order: 1,
isOpen: true,
},
];
const servers = [
{
id: 'server-1',
name: 'server-1',
url: 'http://server-1.com',
tabs,
},
];
describe('app/serverViewState', () => {
describe('switchServer', () => {
const serverViewState = new ServerViewState();
const views = new Map([
['view-1', {id: 'view-1'}],
['view-2', {id: 'view-2'}],
['view-3', {id: 'view-3'}],
]);
beforeEach(() => {
jest.useFakeTimers();
const server1 = {
id: 'server-1',
};
const server2 = {
id: 'server-2',
};
ServerManager.getServer.mockImplementation((name) => {
switch (name) {
case 'server-1':
return server1;
case 'server-2':
return server2;
default:
return undefined;
}
});
ServerManager.getServerLog.mockReturnValue({debug: jest.fn(), error: jest.fn()});
ViewManager.getView.mockImplementation((viewId) => views.get(viewId));
});
afterEach(() => {
jest.resetAllMocks();
});
afterAll(() => {
jest.runOnlyPendingTimers();
jest.clearAllTimers();
jest.useRealTimers();
});
it('should do nothing if cannot find the server', () => {
serverViewState.switchServer('server-3');
expect(ViewManager.showById).not.toBeCalled();
});
it('should show first open view in order when last active not defined', () => {
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-3'});
serverViewState.switchServer('server-1');
expect(ViewManager.showById).toHaveBeenCalledWith('view-3');
});
it('should show last active view of chosen server', () => {
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-2'});
serverViewState.switchServer('server-2');
expect(ViewManager.showById).toHaveBeenCalledWith('view-2');
});
it('should wait for view to exist if specified', () => {
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-3'});
views.delete('view-3');
serverViewState.switchServer('server-1', true);
expect(ViewManager.showById).not.toBeCalled();
jest.advanceTimersByTime(200);
expect(ViewManager.showById).not.toBeCalled();
views.set('view-3', {});
jest.advanceTimersByTime(200);
expect(ViewManager.showById).toBeCalledWith('view-3');
});
});
describe('showNewServerModal', () => {
const serverViewState = new ServerViewState();
let serversCopy;
beforeEach(() => {
getLocalURLString.mockReturnValue('/some/index.html');
getLocalPreload.mockReturnValue('/some/preload.js');
MainWindow.get.mockReturnValue({});
serversCopy = JSON.parse(JSON.stringify(servers));
ServerManager.getAllServers.mockReturnValue([]);
ServerManager.addServer.mockImplementation(() => {
const newServer = {
id: 'server-1',
name: 'new-server',
url: 'http://new-server.com',
tabs,
};
serversCopy = [
...serversCopy,
newServer,
];
return newServer;
});
ServerManager.hasServers.mockReturnValue(Boolean(serversCopy.length));
ServerManager.getServerLog.mockReturnValue({debug: jest.fn(), error: jest.fn()});
getDefaultViewsForConfigServer.mockImplementation((server) => ({
...server,
tabs,
}));
});
it('should add new server to the config', async () => {
const data = {
name: 'new-server',
url: 'http://new-server.com',
};
const promise = Promise.resolve(data);
ModalManager.addModal.mockReturnValue(promise);
serverViewState.showNewServerModal();
await promise;
expect(ServerManager.addServer).toHaveBeenCalledWith(data);
expect(serversCopy).toContainEqual(expect.objectContaining({
id: 'server-1',
name: 'new-server',
url: 'http://new-server.com',
tabs,
}));
// TODO: For some reason jest won't recognize this as being called
//expect(spy).toHaveBeenCalledWith('server-1', true);
});
});
describe('handleEditServerModal', () => {
const serverViewState = new ServerViewState();
let serversCopy;
beforeEach(() => {
getLocalURLString.mockReturnValue('/some/index.html');
getLocalPreload.mockReturnValue('/some/preload.js');
MainWindow.get.mockReturnValue({});
serversCopy = JSON.parse(JSON.stringify(servers));
ServerManager.getServer.mockImplementation((id) => {
if (id !== serversCopy[0].id) {
return undefined;
}
return {...serversCopy[0], toUniqueServer: jest.fn()};
});
ServerManager.editServer.mockImplementation((id, server) => {
if (id !== serversCopy[0].id) {
return;
}
const newServer = {
...serversCopy[0],
...server,
};
serversCopy = [newServer];
});
ServerManager.getAllServers.mockReturnValue(serversCopy.map((server) => ({...server, toUniqueServer: jest.fn()})));
});
it('should do nothing when the server cannot be found', () => {
serverViewState.showEditServerModal(null, 'bad-server');
expect(ModalManager.addModal).not.toBeCalled();
});
it('should edit the existing server', async () => {
const promise = Promise.resolve({
name: 'new-server',
url: 'http://new-server.com',
});
ModalManager.addModal.mockReturnValue(promise);
serverViewState.showEditServerModal(null, 'server-1');
await promise;
expect(serversCopy).not.toContainEqual(expect.objectContaining({
id: 'server-1',
name: 'server-1',
url: 'http://server-1.com',
tabs,
}));
expect(serversCopy).toContainEqual(expect.objectContaining({
id: 'server-1',
name: 'new-server',
url: 'http://new-server.com',
tabs,
}));
});
});
describe('handleRemoveServerModal', () => {
const serverViewState = new ServerViewState();
let serversCopy;
beforeEach(() => {
getLocalURLString.mockReturnValue('/some/index.html');
getLocalPreload.mockReturnValue('/some/preload.js');
MainWindow.get.mockReturnValue({});
serversCopy = JSON.parse(JSON.stringify(servers));
ServerManager.getServer.mockImplementation(() => {
return serversCopy[0];
});
ServerManager.removeServer.mockImplementation(() => {
serversCopy = [];
});
ServerManager.getOrderedServers.mockReturnValue(serversCopy);
});
it('should remove the existing server', async () => {
const promise = Promise.resolve(true);
ModalManager.addModal.mockReturnValue(promise);
serverViewState.showRemoveServerModal(null, 'server-1');
await promise;
expect(serversCopy).not.toContainEqual(expect.objectContaining({
id: 'server-1',
name: 'server-1',
url: 'http://server-1.com',
tabs,
}));
});
it('should not remove the existing server when clicking Cancel', async () => {
const promise = Promise.resolve(false);
ModalManager.addModal.mockReturnValue(promise);
expect(serversCopy).toContainEqual(expect.objectContaining({
id: 'server-1',
name: 'server-1',
url: 'http://server-1.com',
tabs,
}));
serverViewState.showRemoveServerModal(null, 'server-1');
await promise;
expect(serversCopy).toContainEqual(expect.objectContaining({
id: 'server-1',
name: 'server-1',
url: 'http://server-1.com',
tabs,
}));
});
});
describe('handleServerURLValidation', () => {
const serverViewState = new ServerViewState();
beforeEach(() => {
MattermostServer.mockImplementation(({url}) => ({url}));
ServerInfo.mockImplementation(({url}) => ({
fetchConfigData: jest.fn().mockImplementation(() => ({
serverVersion: '7.8.0',
siteName: 'Mattermost',
siteURL: url,
})),
}));
});
afterEach(() => {
jest.resetAllMocks();
});
it('should return Missing when you get no URL', async () => {
const result = await serverViewState.handleServerURLValidation({});
expect(result.status).toBe(URLValidationStatus.Missing);
});
it('should return Invalid when you pass in invalid characters', async () => {
const result = await serverViewState.handleServerURLValidation({}, '!@#$%^&*()!@#$%^&*()');
expect(result.status).toBe(URLValidationStatus.Invalid);
});
it('should include HTTPS when missing', async () => {
const result = await serverViewState.handleServerURLValidation({}, 'server.com');
expect(result.status).toBe(URLValidationStatus.OK);
expect(result.validatedURL).toBe('https://server.com/');
});
it('should correct typos in the protocol', async () => {
const result = await serverViewState.handleServerURLValidation({}, 'htpst://server.com');
expect(result.status).toBe(URLValidationStatus.OK);
expect(result.validatedURL).toBe('https://server.com/');
});
it('should replace HTTP with HTTPS when applicable', async () => {
const result = await serverViewState.handleServerURLValidation({}, 'http://server.com');
expect(result.status).toBe(URLValidationStatus.OK);
expect(result.validatedURL).toBe('https://server.com/');
});
it('should generate a warning when the server already exists', async () => {
ServerManager.lookupViewByURL.mockReturnValue({server: {id: 'server-1', url: new URL('https://server.com')}});
const result = await serverViewState.handleServerURLValidation({}, 'https://server.com');
expect(result.status).toBe(URLValidationStatus.URLExists);
expect(result.validatedURL).toBe('https://server.com/');
});
it('should generate a warning if the server exists when editing', async () => {
ServerManager.lookupViewByURL.mockReturnValue({server: {name: 'Server 1', id: 'server-1', url: new URL('https://server.com')}});
const result = await serverViewState.handleServerURLValidation({}, 'https://server.com', 'server-2');
expect(result.status).toBe(URLValidationStatus.URLExists);
expect(result.validatedURL).toBe('https://server.com/');
expect(result.existingServerName).toBe('Server 1');
});
it('should not generate a warning if editing the same server', async () => {
ServerManager.lookupViewByURL.mockReturnValue({server: {name: 'Server 1', id: 'server-1', url: new URL('https://server.com')}});
const result = await serverViewState.handleServerURLValidation({}, 'https://server.com', 'server-1');
expect(result.status).toBe(URLValidationStatus.OK);
expect(result.validatedURL).toBe('https://server.com/');
});
it('should attempt HTTP when HTTPS fails, and generate a warning', async () => {
ServerInfo.mockImplementation(({url}) => ({
fetchConfigData: jest.fn().mockImplementation(() => {
if (url.startsWith('https:')) {
return undefined;
}
return {
serverVersion: '7.8.0',
siteName: 'Mattermost',
siteURL: url,
};
}),
}));
const result = await serverViewState.handleServerURLValidation({}, 'http://server.com');
expect(result.status).toBe(URLValidationStatus.Insecure);
expect(result.validatedURL).toBe('http://server.com/');
});
it('should show a warning when the ping request times out', async () => {
ServerInfo.mockImplementation(() => ({
fetchConfigData: jest.fn().mockImplementation(() => {
throw new Error();
}),
}));
const result = await serverViewState.handleServerURLValidation({}, 'https://not-server.com');
expect(result.status).toBe(URLValidationStatus.NotMattermost);
expect(result.validatedURL).toBe('https://not-server.com/');
});
it('should update the users URL when the Site URL is different', async () => {
ServerInfo.mockImplementation(() => ({
fetchConfigData: jest.fn().mockImplementation(() => {
return {
serverVersion: '7.8.0',
siteName: 'Mattermost',
siteURL: 'https://mainserver.com/',
};
}),
}));
const result = await serverViewState.handleServerURLValidation({}, 'https://server.com');
expect(result.status).toBe(URLValidationStatus.URLUpdated);
expect(result.validatedURL).toBe('https://mainserver.com/');
});
it('should warn the user when the Site URL is different but unreachable', async () => {
ServerInfo.mockImplementation(({url}) => ({
fetchConfigData: jest.fn().mockImplementation(() => {
if (url === 'https://mainserver.com/') {
return undefined;
}
return {
serverVersion: '7.8.0',
siteName: 'Mattermost',
siteURL: 'https://mainserver.com/',
};
}),
}));
const result = await serverViewState.handleServerURLValidation({}, 'https://server.com');
expect(result.status).toBe(URLValidationStatus.URLNotMatched);
expect(result.validatedURL).toBe('https://server.com/');
});
it('should warn the user when the Site URL already exists as another server', async () => {
ServerManager.lookupViewByURL.mockReturnValue({server: {name: 'Server 1', id: 'server-1', url: new URL('https://mainserver.com')}});
ServerInfo.mockImplementation(() => ({
fetchConfigData: jest.fn().mockImplementation(() => {
return {
serverVersion: '7.8.0',
siteName: 'Mattermost',
siteURL: 'https://mainserver.com',
};
}),
}));
const result = await serverViewState.handleServerURLValidation({}, 'https://server.com');
expect(result.status).toBe(URLValidationStatus.URLExists);
expect(result.validatedURL).toBe('https://mainserver.com/');
expect(result.existingServerName).toBe('Server 1');
});
});
describe('handleCloseView', () => {
const serverViewState = new ServerViewState();
it('should close the specified view and switch to the next open view', () => {
ServerManager.getView.mockReturnValue({server: {id: 'server-1'}});
ServerManager.getLastActiveTabForServer.mockReturnValue({id: 'view-2'});
serverViewState.handleCloseView(null, 'view-3');
expect(ServerManager.setViewIsOpen).toBeCalledWith('view-3', false);
expect(ViewManager.showById).toBeCalledWith('view-2');
});
});
describe('handleOpenView', () => {
const serverViewState = new ServerViewState();
it('should open the specified view', () => {
serverViewState.handleOpenView(null, 'view-1');
expect(ViewManager.showById).toBeCalledWith('view-1');
});
});
});