summaryrefslogtreecommitdiff
path: root/spec/frontend/ide/lib/mirror_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ide/lib/mirror_spec.js')
-rw-r--r--spec/frontend/ide/lib/mirror_spec.js184
1 files changed, 184 insertions, 0 deletions
diff --git a/spec/frontend/ide/lib/mirror_spec.js b/spec/frontend/ide/lib/mirror_spec.js
new file mode 100644
index 00000000000..21bed5948f3
--- /dev/null
+++ b/spec/frontend/ide/lib/mirror_spec.js
@@ -0,0 +1,184 @@
+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 });
+ });
+ });
+ });
+});