Skip to content

Commit

Permalink
Merge pull request #870 from terrestris/csrf-headers-in-tests
Browse files Browse the repository at this point in the history
fix: mock CSRF meta elements in tests
  • Loading branch information
ahennr authored Jan 10, 2025
2 parents 3267174 + 367e8c4 commit 325f22b
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 34 deletions.
7 changes: 7 additions & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
global.fetch = jest.fn();

['_csrf_header', '_csrf'].forEach(csrfMeta => {
const meta = document.createElement('meta');
meta.setAttribute('name', csrfMeta);
meta.setAttribute('content', Math.floor(Math.random() * Date.now()).toString(36));
document.head.appendChild(meta);
});
6 changes: 5 additions & 1 deletion src/service/AuthService/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fetchSpy, {
successResponse
} from '../../spec/fetchSpy';
import AuthService from '.';
import CsrfUtil from '@terrestris/base-util/dist/CsrfUtil/CsrfUtil';

describe('AuthService', () => {
let fetchMock: jest.SpyInstance;
Expand All @@ -28,9 +29,12 @@ describe('AuthService', () => {

await service.logout();

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/sso/logout', {
credentials: 'same-origin',
headers: {},
headers: {
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'POST'
});
});
Expand Down
7 changes: 5 additions & 2 deletions src/service/CacheService/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fetchSpy, {
successResponse
} from '../../spec/fetchSpy';
import CacheService from '.';
import CsrfUtil from '@terrestris/base-util/dist/CsrfUtil/CsrfUtil';

describe('AppInfoService', () => {
let fetchMock: jest.SpyInstance;
Expand All @@ -27,9 +28,11 @@ describe('AppInfoService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.evictCache();

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/cache/evict', {
headers: {},
headers: {
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'POST'
});
});
Expand Down
19 changes: 11 additions & 8 deletions src/service/GenericEntityService/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import BaseEntity, { BaseEntityArgs } from '../../model/BaseEntity';
import fetchSpy, { failureResponse, successResponse } from '../../spec/fetchSpy';
import GenericService, { GenericEntityServiceOpts } from '.';
import CsrfUtil from '@terrestris/base-util/dist/CsrfUtil/CsrfUtil';

interface DummyEntityArgs extends BaseEntityArgs {
dummyField?: string;
Expand Down Expand Up @@ -204,11 +205,12 @@ describe('GenericService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.add({ dummyField: 'dummyValue' });

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy', {
body: '{\"dummyField\":\"dummyValue\"}',
headers: {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'POST'
});
Expand Down Expand Up @@ -236,7 +238,7 @@ describe('GenericService', () => {
fetchMock = fetchSpy(successResponse([]));

const resp = await service.delete(1);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy/1', {
headers: {},
method: 'DELETE'
Expand All @@ -259,11 +261,12 @@ describe('GenericService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.update({ id: 1, dummyField: 'dummyValue' });

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy/1', {
body: '{\"id\":1,\"dummyField\":\"dummyValue\"}',
headers: {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'PUT'
});
Expand Down Expand Up @@ -291,11 +294,12 @@ describe('GenericService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.updatePartial({ id: 1, dummyField: 'dummyValue' });

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy/1', {
body: '{\"id\":1,\"dummyField\":\"dummyValue\"}',
headers: {
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'PATCH'
});
Expand Down Expand Up @@ -367,6 +371,5 @@ describe('GenericService', () => {
await expect(service.setPublic(1)).rejects.toThrow();
});


});
});
13 changes: 10 additions & 3 deletions src/service/GenericFileService/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import BaseEntity, { BaseEntityArgs } from '../../model/BaseEntity';
import fetchSpy, { failureResponse, successResponse } from '../../spec/fetchSpy';
import GenericFileService, { GenericFileServiceOpts } from '.';
import CsrfUtil from '@terrestris/base-util/dist/CsrfUtil/CsrfUtil';

interface DummyEntityArgs extends BaseEntityArgs {
dummyField?: string;
Expand Down Expand Up @@ -114,10 +115,12 @@ describe('GenericFileService', () => {

const body = new FormData();
body.append('file', file);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy/upload', {
body: body,
headers: {},
headers: {
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'POST'
});
});
Expand All @@ -131,9 +134,12 @@ describe('GenericFileService', () => {
const body = new FormData();
body.append('file', file);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy/uploadToFileSystem', {
body: body,
headers: {},
headers: {
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'POST'
});
});
Expand Down Expand Up @@ -161,6 +167,7 @@ describe('GenericFileService', () => {

await service.delete('db5f69fa-e8f6-42a6-a305-d2555d7d4d08');

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/dummy/db5f69fa-e8f6-42a6-a305-d2555d7d4d08', {
headers: {},
method: 'DELETE'
Expand Down
4 changes: 2 additions & 2 deletions src/service/ImageFileService/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ImageFile from '../../model/ImageFile';
import { getCsrfTokenHeader } from '../../security/getCsrfTokenHeader';
import { getBearerTokenHeader } from '../../security/getBearerTokenHeader';
import GenericFileService, { GenericFileServiceOpts } from '../GenericFileService';

export class ImageFileService<T extends ImageFile> extends GenericFileService<T> {
Expand All @@ -15,7 +15,7 @@ export class ImageFileService<T extends ImageFile> extends GenericFileService<T>
const response = await fetch(`${this.basePath}/${fileUuid}/thumbnail`, {
method: 'GET',
headers: {
...getCsrfTokenHeader()
...getBearerTokenHeader(this.keycloak),
},
...fetchOpts
});
Expand Down
54 changes: 36 additions & 18 deletions src/service/PermissionService/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import fetchSpy, {
successResponse
} from '../../spec/fetchSpy';
import PermissionService from '.';
import CsrfUtil from '@terrestris/base-util/dist/CsrfUtil/CsrfUtil';

describe('PermissionService', () => {
let fetchMock: jest.SpyInstance;
Expand Down Expand Up @@ -482,10 +483,12 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.setUserInstancePermission(1909, 10, 'ADMIN');
const csrfHeaderValue = CsrfUtil.getCsrfValue();

expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/instance/user/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue,
'Content-Type': 'application/json'
},
body: '{\"permission\":\"ADMIN\"}',
Expand All @@ -511,11 +514,12 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.setGroupInstancePermission(1909, 10, 'ADMIN');

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/instance/group/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfHeaderValue
},
body: '{\"permission\":\"ADMIN\"}',
method: 'POST'
Expand All @@ -540,11 +544,12 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.setUserClassPermission(1909, 10, 'ADMIN');

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/class/user/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfHeaderValue
},
body: '{\"permission\":\"ADMIN\"}',
method: 'POST'
Expand All @@ -569,11 +574,12 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.setGroupClassPermission(1909, 10, 'ADMIN');

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/class/group/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'Content-Type': 'application/json'
'Content-Type': 'application/json',
'X-XSRF-TOKEN': csrfHeaderValue
},
body: '{\"permission\":\"ADMIN\"}',
method: 'POST'
Expand All @@ -599,9 +605,11 @@ describe('PermissionService', () => {

await service.deleteUserInstancePermission(1909, 10);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/instance/user/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -626,9 +634,11 @@ describe('PermissionService', () => {

await service.deleteGroupInstancePermission(1909, 10);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/instance/group/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -652,10 +662,11 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.deleteUserClassPermission(1909, 10);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/class/user/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -680,9 +691,11 @@ describe('PermissionService', () => {

await service.deleteGroupClassPermission(1909, 10);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/class/group/10', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -706,10 +719,11 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.deleteUserInstancePermissions(1909);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/instance/user', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -733,10 +747,11 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.deleteGroupInstancePermissions(1909);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/instance/group', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -760,10 +775,11 @@ describe('PermissionService', () => {
fetchMock = fetchSpy(successResponse([]));

await service.deleteUserClassPermissions(1909);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/class/user', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand All @@ -788,9 +804,11 @@ describe('PermissionService', () => {

await service.deleteGroupClassPermissions(1909);

const csrfHeaderValue = CsrfUtil.getCsrfValue();
expect(fetchMock).toHaveBeenCalledWith('/1909/permissions/class/group', {
headers: {
Authorization: 'Bearer ThisIsNotAValidBearerToken'
Authorization: 'Bearer ThisIsNotAValidBearerToken',
'X-XSRF-TOKEN': csrfHeaderValue
},
method: 'DELETE'
});
Expand Down

0 comments on commit 325f22b

Please sign in to comment.