gitlab-org--gitlab-foss/spec/frontend/ide/lib/mirror_spec.js

184 lines
5.1 KiB
JavaScript

import createDiff from '~/ide/lib/create_diff';
import {
canConnect,
createMirror,
SERVICE_NAME,
PROTOCOL,
MSG_CONNECTION_ERROR,
SERVICE_DELAY,
} from '~/ide/lib/mirror';
import { getWebSocketUrl } from '~/lib/utils/url_utility';
jest.mock('~/ide/lib/create_diff', () => jest.fn());
const TEST_PATH = '/project/ide/proxy/path';
const TEST_DIFF = {
patch: 'lorem ipsum',
toDelete: ['foo.md'],
};
const TEST_ERROR = 'Something bad happened...';
const TEST_SUCCESS_RESPONSE = {
data: JSON.stringify({ error: { code: 0 }, payload: { status_code: 200 } }),
};
const TEST_ERROR_RESPONSE = {
data: JSON.stringify({ error: { code: 1, Message: TEST_ERROR }, payload: { status_code: 200 } }),
};
const TEST_ERROR_PAYLOAD_RESPONSE = {
data: JSON.stringify({
error: { code: 0 },
payload: { status_code: 500, error_message: TEST_ERROR },
}),
};
const buildUploadMessage = ({ toDelete, patch }) =>
JSON.stringify({
code: 'EVENT',
namespace: '/files',
event: 'PATCH',
payload: { diff: patch, delete_files: toDelete },
});
describe('ide/lib/mirror', () => {
describe('canConnect', () => {
it('can connect if the session has the expected service', () => {
const result = canConnect({ services: ['test1', SERVICE_NAME, 'test2'] });
expect(result).toBe(true);
});
it('cannot connect if the session does not have the expected service', () => {
const result = canConnect({ services: ['test1', 'test2'] });
expect(result).toBe(false);
});
});
describe('createMirror', () => {
const origWebSocket = global.WebSocket;
let mirror;
let mockWebSocket;
beforeEach(() => {
mockWebSocket = {
close: jest.fn(),
send: jest.fn(),
};
global.WebSocket = jest.fn().mockImplementation(() => mockWebSocket);
mirror = createMirror();
});
afterEach(() => {
global.WebSocket = origWebSocket;
});
const waitForConnection = (delay = SERVICE_DELAY) => {
const wait = new Promise(resolve => {
setTimeout(resolve, 10);
});
jest.advanceTimersByTime(delay);
return wait;
};
const connectPass = () => waitForConnection().then(() => mockWebSocket.onopen());
const connectFail = () => waitForConnection().then(() => mockWebSocket.onerror());
const sendResponse = msg => {
mockWebSocket.onmessage(msg);
};
describe('connect', () => {
let connection;
beforeEach(() => {
connection = mirror.connect(TEST_PATH);
});
it('waits before creating web socket', () => {
// ignore error when test suite terminates
connection.catch(() => {});
return waitForConnection(SERVICE_DELAY - 10).then(() => {
expect(global.WebSocket).not.toHaveBeenCalled();
});
});
it('is canceled when disconnected before finished waiting', () => {
mirror.disconnect();
return waitForConnection(SERVICE_DELAY).then(() => {
expect(global.WebSocket).not.toHaveBeenCalled();
});
});
describe('when connection is successful', () => {
beforeEach(connectPass);
it('connects to service', () => {
const expectedPath = `${getWebSocketUrl(TEST_PATH)}?service=${SERVICE_NAME}`;
return connection.then(() => {
expect(global.WebSocket).toHaveBeenCalledWith(expectedPath, [PROTOCOL]);
});
});
it('disconnects when connected again', () => {
const result = connection
.then(() => {
// https://gitlab.com/gitlab-org/gitlab/issues/33024
// eslint-disable-next-line promise/no-nesting
mirror.connect(TEST_PATH).catch(() => {});
})
.then(() => {
expect(mockWebSocket.close).toHaveBeenCalled();
});
return result;
});
});
describe('when connection fails', () => {
beforeEach(connectFail);
it('rejects with error', () => {
return expect(connection).rejects.toEqual(new Error(MSG_CONNECTION_ERROR));
});
});
});
describe('upload', () => {
let state;
beforeEach(() => {
state = { changedFiles: [] };
createDiff.mockReturnValue(TEST_DIFF);
const connection = mirror.connect(TEST_PATH);
return connectPass().then(() => connection);
});
it('creates a diff from the given state', () => {
const result = mirror.upload(state);
sendResponse(TEST_SUCCESS_RESPONSE);
return result.then(() => {
expect(createDiff).toHaveBeenCalledWith(state);
expect(mockWebSocket.send).toHaveBeenCalledWith(buildUploadMessage(TEST_DIFF));
});
});
it.each`
response | description
${TEST_ERROR_RESPONSE} | ${'error in error'}
${TEST_ERROR_PAYLOAD_RESPONSE} | ${'error in payload'}
`('rejects if response has $description', ({ response }) => {
const result = mirror.upload(state);
sendResponse(response);
return expect(result).rejects.toEqual({ message: TEST_ERROR });
});
});
});
});