debian-mirror-gitlab/spec/frontend/captcha/apollo_captcha_link_spec.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

178 lines
5.1 KiB
JavaScript
Raw Normal View History

2022-04-04 11:22:00 +05:30
import { ApolloLink, Observable } from '@apollo/client/core';
2021-04-29 21:17:54 +05:30
import { apolloCaptchaLink } from '~/captcha/apollo_captcha_link';
import UnsolvedCaptchaError from '~/captcha/unsolved_captcha_error';
import { waitForCaptchaToBeSolved } from '~/captcha/wait_for_captcha_to_be_solved';
jest.mock('~/captcha/wait_for_captcha_to_be_solved');
describe('apolloCaptchaLink', () => {
const SPAM_LOG_ID = 'SPAM_LOG_ID';
const CAPTCHA_SITE_KEY = 'CAPTCHA_SITE_KEY';
const CAPTCHA_RESPONSE = 'CAPTCHA_RESPONSE';
const SUCCESS_RESPONSE = {
data: {
user: {
id: 3,
name: 'foo',
},
},
errors: [],
};
const NON_CAPTCHA_ERROR_RESPONSE = {
data: {
user: null,
},
errors: [
{
message: 'Something is severely wrong with your query.',
path: ['user'],
locations: [{ line: 2, column: 3 }],
extensions: {
message: 'Object not found',
type: 2,
},
},
],
};
const SPAM_ERROR_RESPONSE = {
data: {
user: null,
},
errors: [
{
message: 'Your Query was detected to be spam.',
path: ['user'],
locations: [{ line: 2, column: 3 }],
extensions: {
spam: true,
},
},
],
};
const CAPTCHA_ERROR_RESPONSE = {
data: {
user: null,
},
errors: [
{
message: 'This is an unrelated error, captcha should still work despite this.',
path: ['user'],
locations: [{ line: 2, column: 3 }],
},
{
message: 'You need to solve a Captcha.',
path: ['user'],
locations: [{ line: 2, column: 3 }],
extensions: {
spam: true,
needs_captcha_response: true,
captcha_site_key: CAPTCHA_SITE_KEY,
spam_log_id: SPAM_LOG_ID,
},
},
],
};
let link;
let mockLinkImplementation;
let mockContext;
const setupLink = (...responses) => {
mockLinkImplementation = jest.fn().mockImplementation(() => {
return Observable.of(responses.shift());
});
link = ApolloLink.from([apolloCaptchaLink, new ApolloLink(mockLinkImplementation)]);
};
function mockOperation() {
mockContext = jest.fn();
return { operationName: 'operation', variables: {}, setContext: mockContext };
}
2022-06-21 17:19:12 +05:30
it('successful responses are passed through', () => {
2021-04-29 21:17:54 +05:30
setupLink(SUCCESS_RESPONSE);
2022-06-21 17:19:12 +05:30
return new Promise((resolve) => {
link.request(mockOperation()).subscribe((result) => {
expect(result).toEqual(SUCCESS_RESPONSE);
expect(mockLinkImplementation).toHaveBeenCalledTimes(1);
expect(waitForCaptchaToBeSolved).not.toHaveBeenCalled();
resolve();
});
2021-04-29 21:17:54 +05:30
});
});
2022-06-21 17:19:12 +05:30
it('non-spam related errors are passed through', () => {
2021-04-29 21:17:54 +05:30
setupLink(NON_CAPTCHA_ERROR_RESPONSE);
2022-06-21 17:19:12 +05:30
return new Promise((resolve) => {
link.request(mockOperation()).subscribe((result) => {
expect(result).toEqual(NON_CAPTCHA_ERROR_RESPONSE);
expect(mockLinkImplementation).toHaveBeenCalledTimes(1);
expect(mockContext).not.toHaveBeenCalled();
expect(waitForCaptchaToBeSolved).not.toHaveBeenCalled();
resolve();
});
2021-04-29 21:17:54 +05:30
});
});
2022-06-21 17:19:12 +05:30
it('unresolvable spam errors are passed through', () => {
2021-04-29 21:17:54 +05:30
setupLink(SPAM_ERROR_RESPONSE);
2022-06-21 17:19:12 +05:30
return new Promise((resolve) => {
link.request(mockOperation()).subscribe((result) => {
expect(result).toEqual(SPAM_ERROR_RESPONSE);
expect(mockLinkImplementation).toHaveBeenCalledTimes(1);
expect(mockContext).not.toHaveBeenCalled();
expect(waitForCaptchaToBeSolved).not.toHaveBeenCalled();
resolve();
});
2021-04-29 21:17:54 +05:30
});
});
describe('resolvable spam errors', () => {
2022-06-21 17:19:12 +05:30
it('re-submits request with spam headers if the captcha modal was solved correctly', () => {
2021-04-29 21:17:54 +05:30
waitForCaptchaToBeSolved.mockResolvedValue(CAPTCHA_RESPONSE);
setupLink(CAPTCHA_ERROR_RESPONSE, SUCCESS_RESPONSE);
2022-06-21 17:19:12 +05:30
return new Promise((resolve) => {
link.request(mockOperation()).subscribe((result) => {
expect(result).toEqual(SUCCESS_RESPONSE);
expect(waitForCaptchaToBeSolved).toHaveBeenCalledWith(CAPTCHA_SITE_KEY);
expect(mockContext).toHaveBeenCalledWith({
headers: {
'X-GitLab-Captcha-Response': CAPTCHA_RESPONSE,
'X-GitLab-Spam-Log-Id': SPAM_LOG_ID,
},
});
expect(mockLinkImplementation).toHaveBeenCalledTimes(2);
resolve();
2021-04-29 21:17:54 +05:30
});
});
});
2022-06-21 17:19:12 +05:30
it('throws error if the captcha modal was not solved correctly', () => {
2021-04-29 21:17:54 +05:30
const error = new UnsolvedCaptchaError();
waitForCaptchaToBeSolved.mockRejectedValue(error);
setupLink(CAPTCHA_ERROR_RESPONSE, SUCCESS_RESPONSE);
2022-06-21 17:19:12 +05:30
return new Promise((resolve, reject) => {
link.request(mockOperation()).subscribe({
next: reject,
error: (result) => {
expect(result).toEqual(error);
expect(waitForCaptchaToBeSolved).toHaveBeenCalledWith(CAPTCHA_SITE_KEY);
expect(mockContext).not.toHaveBeenCalled();
expect(mockLinkImplementation).toHaveBeenCalledTimes(1);
resolve();
},
});
2021-04-29 21:17:54 +05:30
});
});
});
});