Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gabriellsh committed Oct 7, 2024
1 parent 5f3d07c commit 3d7876b
Show file tree
Hide file tree
Showing 6 changed files with 683 additions and 0 deletions.
1 change: 1 addition & 0 deletions apps/meteor/.mocharc.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = {
'tests/unit/app/**/*.tests.js',
'tests/unit/app/**/*.tests.ts',
'tests/unit/lib/**/*.tests.ts',
'server/routes/avatar/**/*.spec.ts',
'tests/unit/lib/**/*.spec.ts',
'tests/unit/server/**/*.tests.ts',
'tests/unit/server/**/*.spec.ts',
Expand Down
87 changes: 87 additions & 0 deletions apps/meteor/server/routes/avatar/middlewares/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

const mocks = {
utils: {
userCanAccessAvatar: sinon.stub(),
renderSVGLetters: sinon.stub(),
},
};

const { protectAvatarsWithFallback } = proxyquire.noCallThru().load('./auth.ts', {
'../utils': mocks.utils,
});

describe('#protectAvatarsWithFallback()', () => {
const response = {
setHeader: sinon.spy(),
writeHead: sinon.spy(),
write: sinon.spy(),
end: sinon.spy(),
};
const next = sinon.spy();

afterEach(() => {
response.setHeader.resetHistory();
response.writeHead.resetHistory();
response.end.resetHistory();
next.resetHistory();

Object.values(mocks.utils).forEach((mock) => mock.reset());
});

it(`should write 404 to head if no url provided`, async () => {
await protectAvatarsWithFallback({}, response, next);
expect(next.called).to.be.false;
expect(response.setHeader.called).to.be.false;
expect(response.writeHead.calledWith(404)).to.be.true;
expect(response.end.calledOnce).to.be.true;
});

it(`should write 200 to head and write fallback to body (user avatar)`, async () => {
mocks.utils.renderSVGLetters.returns('fallback');

await protectAvatarsWithFallback({ url: '/jon' }, response, next);
expect(next.called).to.be.false;
expect(response.setHeader.called).to.be.false;

expect(response.writeHead.calledWith(200, { 'Content-Type': 'image/svg+xml' })).to.be.true;
expect(mocks.utils.renderSVGLetters.calledWith('jon')).to.be.true;
expect(response.write.calledWith('fallback')).to.be.true;

expect(response.end.calledOnce).to.be.true;
});

it(`should write 200 to head and write fallback to body (user avatar)`, async () => {
mocks.utils.renderSVGLetters.returns('fallback');

await protectAvatarsWithFallback({ url: '/jon' }, response, next);
expect(next.called).to.be.false;
expect(response.setHeader.called).to.be.false;
expect(response.writeHead.calledWith(200, { 'Content-Type': 'image/svg+xml' })).to.be.true;
expect(response.write.calledWith('fallback')).to.be.true;
expect(response.end.calledOnce).to.be.true;
});

it(`should write 200 to head and write fallback to body (room avatar)`, async () => {
mocks.utils.renderSVGLetters.returns('fallback');

await protectAvatarsWithFallback({ url: '/room/jon' }, response, next);
expect(next.called).to.be.false;
expect(response.setHeader.called).to.be.false;
expect(response.writeHead.calledWith(200, { 'Content-Type': 'image/svg+xml' })).to.be.true;
expect(response.write.calledWith('fallback')).to.be.true;
expect(response.end.calledOnce).to.be.true;
});

it(`should call next if user can access avatar`, async () => {
mocks.utils.userCanAccessAvatar.returns(true);
const request = { url: '/jon' };

await protectAvatarsWithFallback(request, response, next);
expect(mocks.utils.userCanAccessAvatar.calledWith(request)).to.be.true;
expect(next.called).to.be.true;
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

// const getCookie = sinon.stub();
class CookiesMock {
public get = (_key: any, value: any) => value;
}
const { handleBrowserVersionCheck, isIEOlderThan11 } = proxyquire.noCallThru().load('./browserVersion', {
'meteor/ostrio:cookies': {
Cookies: CookiesMock,
},
'../../../../app/utils/server/getURL': {
getURL: () => '',
},
});

describe('#isIEOlderThan11()', () => {
it('should return false if user agent is IE11', () => {
const userAgent = {
browser: {
name: 'IE',
version: '11.0',
},
};
expect(isIEOlderThan11(userAgent)).to.be.false;
});

it('should return true if user agent is IE < 11', () => {
const userAgent = {
browser: {
name: 'IE',
version: '10.0',
},
};
expect(isIEOlderThan11(userAgent)).to.be.true;
});
});

describe('#handleBrowserVersionCheck()', () => {
it('should call next if browser_version_check cookie is set to "bypass"', async () => {
const next = sinon.spy();
const request = {
headers: {
cookie: 'bypass',
},
};
handleBrowserVersionCheck(request as any, {} as any, next);

expect(next.calledOnce).to.be.true;
});

it('should call next if browser_version_check cookie is not set to "force" and user agent is not IE < 11', async () => {
const next = sinon.spy();
const request = {
headers: {
'cookie': 'anything',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36',
},
};
handleBrowserVersionCheck(request as any, {} as any, next);

expect(next.calledOnce).to.be.true;
});

it('should respond with Browser not supported', async () => {
const next = sinon.spy();
const request = {
headers: {
'cookie': 'anything',
'user-agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 7.0; InfoPath.3; .NET CLR 3.1.40767; Trident/6.0; en-IN)',
},
};

const response = {
setHeader: sinon.spy(),
write: sinon.spy(),
end: sinon.spy(),
};
handleBrowserVersionCheck(request as any, response as any, next);

expect(response.setHeader.calledWith('content-type', 'text/html; charset=utf-8')).to.be.true;
expect(response.write.calledWith(sinon.match('Browser not supported'))).to.be.true;
expect(response.end.calledOnce).to.be.true;
});
});
139 changes: 139 additions & 0 deletions apps/meteor/server/routes/avatar/room.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

const mocks = {
settingsGet: sinon.stub(),
findOneById: sinon.stub(),
utils: {
serveSvgAvatarInRequestedFormat: sinon.spy(),
wasFallbackModified: sinon.stub(),
setCacheAndDispositionHeaders: sinon.spy(),
serveAvatarFile: sinon.spy(),
},
avatarFindOneByRoomId: sinon.stub(),
getRoomName: sinon.stub(),
};

class CookiesMock {
public get = (_key: any, value: any) => value;
}

const { roomAvatar } = proxyquire.noCallThru().load('./room', {
'@rocket.chat/models': {
Rooms: {
findOneById: mocks.findOneById,
},
Avatars: {
findOneByRoomId: mocks.avatarFindOneByRoomId,
},
},
'../../../app/settings/server': {
settings: {
get: mocks.settingsGet,
},
},
'./utils': mocks.utils,
'../../lib/rooms/roomCoordinator': {
roomCoordinator: {
getRoomName: mocks.getRoomName,
},
},
'meteor/ostrio:cookies': {
Cookies: CookiesMock,
},
});

describe('#roomAvatar()', () => {
const response = {
setHeader: sinon.spy(),
writeHead: sinon.spy(),
end: sinon.spy(),
};
const next = sinon.spy();

afterEach(() => {
mocks.settingsGet.reset();
mocks.avatarFindOneByRoomId.reset();
mocks.findOneById.reset();

response.setHeader.resetHistory();
response.writeHead.resetHistory();
response.end.resetHistory();
next.resetHistory();

Object.values(mocks.utils).forEach((mock) => ('reset' in mock ? mock.reset() : mock.resetHistory()));
});

it(`should do nothing if url is not in request object`, async () => {
await roomAvatar({}, response, next);
expect(next.called).to.be.false;
expect(response.setHeader.called).to.be.false;
expect(response.writeHead.called).to.be.false;
expect(response.end.called).to.be.false;
});

it(`should write 404 if room is not found`, async () => {
mocks.findOneById.returns(null);
await roomAvatar({ url: '/' }, response, next);
expect(next.called).to.be.false;
expect(response.setHeader.called).to.be.false;
expect(response.writeHead.calledWith(404)).to.be.true;
expect(response.end.calledOnce).to.be.true;
});

it(`should serve avatar file if found`, async () => {
const request = { url: '/roomId' };

const file = { uploadedAt: new Date(0), type: 'image/png', size: 100 };

mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId' });
mocks.avatarFindOneByRoomId.withArgs('roomId').returns(file);

await roomAvatar(request, response, next);

expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true;
expect(mocks.utils.serveAvatarFile.calledWith(file, request, response, next)).to.be.true;
});

it(`should serve parent room avatar file if current room avatar is not found`, async () => {
const request = { url: '/roomId' };

const file = { uploadedAt: new Date(0), type: 'image/png', size: 100 };

mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId', prid: 'roomId2' });
mocks.findOneById.withArgs('roomId2').returns({ _id: 'roomId2' });
mocks.avatarFindOneByRoomId.withArgs('roomId2').returns(file);

await roomAvatar(request, response, next);

expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true;
expect(mocks.utils.serveAvatarFile.calledWith(file, request, response, next)).to.be.true;
});

it(`should write 304 if fallback content is not modified`, async () => {
const request = { url: '/roomId', headers: {} };

mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId' });
mocks.utils.wasFallbackModified.returns(false);
await roomAvatar(request, response, next);

expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true;
expect(response.writeHead.calledWith(304)).to.be.true;
expect(response.end.calledOnce).to.be.true;
});

it(`should serve svg fallback if no file found`, async () => {
const request = { url: '/roomId', headers: { cookie: 'userId' } };

mocks.utils.wasFallbackModified.returns(true);
mocks.findOneById.withArgs('roomId').returns({ _id: 'roomId' });
mocks.getRoomName.returns('roomName');

await roomAvatar(request, response, next);

expect(mocks.utils.setCacheAndDispositionHeaders.calledWith(request, response)).to.be.true;
expect(mocks.utils.serveSvgAvatarInRequestedFormat.calledWith({ nameOrUsername: 'roomName', req: request, res: response })).to.be.true;
});
});
Loading

0 comments on commit 3d7876b

Please sign in to comment.