feat: Add tests for challenge>buildUserUpdate
This commit is contained in:
committed by
mrugesh mohapatra
parent
75190d3a43
commit
953e1b2e11
@ -74,10 +74,14 @@ const jsProjects = [
|
|||||||
'aa2e6f85cab2ab736c9a9b24'
|
'aa2e6f85cab2ab736c9a9b24'
|
||||||
];
|
];
|
||||||
|
|
||||||
function buildUserUpdate(user, challengeId, _completedChallenge, timezone) {
|
export function buildUserUpdate(
|
||||||
|
user,
|
||||||
|
challengeId,
|
||||||
|
_completedChallenge,
|
||||||
|
timezone
|
||||||
|
) {
|
||||||
const { files } = _completedChallenge;
|
const { files } = _completedChallenge;
|
||||||
let completedChallenge = {};
|
let completedChallenge = {};
|
||||||
|
|
||||||
if (jsProjects.includes(challengeId)) {
|
if (jsProjects.includes(challengeId)) {
|
||||||
completedChallenge = {
|
completedChallenge = {
|
||||||
..._completedChallenge,
|
..._completedChallenge,
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
/* global describe xdescribe it expect */
|
/* global describe xdescribe it expect */
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual, first, find } from 'lodash';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { mockReq, mockRes } from 'sinon-express-mock';
|
import { mockReq, mockRes } from 'sinon-express-mock';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
buildUserUpdate,
|
||||||
buildChallengeUrl,
|
buildChallengeUrl,
|
||||||
createChallengeUrlResolver,
|
createChallengeUrlResolver,
|
||||||
createRedirectToCurrentChallenge,
|
createRedirectToCurrentChallenge,
|
||||||
@ -11,48 +12,144 @@ import {
|
|||||||
isValidChallengeCompletion
|
isValidChallengeCompletion
|
||||||
} from '../boot/challenge';
|
} from '../boot/challenge';
|
||||||
|
|
||||||
const firstChallengeUrl = '/learn/the/first/challenge';
|
import {
|
||||||
const requestedChallengeUrl = '/learn/my/actual/challenge';
|
firstChallengeUrl,
|
||||||
const mockChallenge = {
|
requestedChallengeUrl,
|
||||||
id: '123abc',
|
mockChallenge,
|
||||||
block: 'actual',
|
mockFirstChallenge,
|
||||||
superBlock: 'my',
|
mockUser,
|
||||||
dashedName: 'challenge'
|
mockApp,
|
||||||
};
|
mockGetFirstChallenge,
|
||||||
const mockFirstChallenge = {
|
firstChallengeQuery,
|
||||||
id: '456def',
|
mockCompletedChallenge,
|
||||||
block: 'first',
|
mockCompletedChallenges
|
||||||
superBlock: 'the',
|
} from './fixtures';
|
||||||
dashedName: 'challenge'
|
|
||||||
};
|
|
||||||
const mockUser = {
|
|
||||||
username: 'camperbot',
|
|
||||||
currentChallengeId: '123abc'
|
|
||||||
};
|
|
||||||
const mockApp = {
|
|
||||||
models: {
|
|
||||||
Challenge: {
|
|
||||||
find() {
|
|
||||||
return firstChallengeUrl;
|
|
||||||
},
|
|
||||||
findById(id, cb) {
|
|
||||||
return id === mockChallenge.id
|
|
||||||
? cb(null, mockChallenge)
|
|
||||||
: cb(new Error('challenge not found'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const mockGetFirstChallenge = () => firstChallengeUrl;
|
|
||||||
const firstChallengeQuery = {
|
|
||||||
// first challenge of the first block of the first superBlock
|
|
||||||
where: { challengeOrder: 0, superOrder: 1, order: 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('boot/challenge', () => {
|
describe('boot/challenge', () => {
|
||||||
xdescribe('backendChallengeCompleted');
|
xdescribe('backendChallengeCompleted');
|
||||||
|
|
||||||
xdescribe('buildUserUpdate');
|
describe('buildUserUpdate', () => {
|
||||||
|
it('returns an Object with a nested "completedChallenges" property', () => {
|
||||||
|
const result = buildUserUpdate(
|
||||||
|
mockUser,
|
||||||
|
'123abc',
|
||||||
|
mockCompletedChallenge,
|
||||||
|
'UTC'
|
||||||
|
);
|
||||||
|
expect(result).toHaveProperty('updateData.$set.completedChallenges');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preserves file contents if the completed challenge is a JS Project', () => {
|
||||||
|
const jsChallengeId = 'aa2e6f85cab2ab736c9a9b24';
|
||||||
|
const completedChallenge = {
|
||||||
|
...mockCompletedChallenge,
|
||||||
|
completedDate: Date.now(),
|
||||||
|
id: jsChallengeId
|
||||||
|
};
|
||||||
|
const result = buildUserUpdate(
|
||||||
|
mockUser,
|
||||||
|
jsChallengeId,
|
||||||
|
completedChallenge,
|
||||||
|
'UTC'
|
||||||
|
);
|
||||||
|
const firstCompletedChallenge = first(
|
||||||
|
result.updateData.$set.completedChallenges
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(firstCompletedChallenge).toEqual(completedChallenge);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preserves the original completed date of a challenge', () => {
|
||||||
|
const completedChallengeId = 'aaa48de84e1ecc7c742e1124';
|
||||||
|
const completedChallenge = {
|
||||||
|
...mockCompletedChallenge,
|
||||||
|
completedDate: Date.now(),
|
||||||
|
id: completedChallengeId
|
||||||
|
};
|
||||||
|
const originalCompletion = find(
|
||||||
|
mockCompletedChallenges,
|
||||||
|
x => x.id === completedChallengeId
|
||||||
|
).completedDate;
|
||||||
|
const result = buildUserUpdate(
|
||||||
|
mockUser,
|
||||||
|
completedChallengeId,
|
||||||
|
completedChallenge,
|
||||||
|
'UTC'
|
||||||
|
);
|
||||||
|
|
||||||
|
const firstCompletedChallenge = first(
|
||||||
|
result.updateData.$set.completedChallenges
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(firstCompletedChallenge.completedDate).toEqual(originalCompletion);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not attempt to update progressTimestamps for a previously completed challenge', () => {
|
||||||
|
const completedChallengeId = 'aaa48de84e1ecc7c742e1124';
|
||||||
|
const completedChallenge = {
|
||||||
|
...mockCompletedChallenge,
|
||||||
|
completedDate: Date.now(),
|
||||||
|
id: completedChallengeId
|
||||||
|
};
|
||||||
|
const { updateData } = buildUserUpdate(
|
||||||
|
mockUser,
|
||||||
|
completedChallengeId,
|
||||||
|
completedChallenge,
|
||||||
|
'UTC'
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasProgressTimestamps =
|
||||||
|
'$push' in updateData && 'progressTimestamps' in updateData.$push;
|
||||||
|
expect(hasProgressTimestamps).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('provides a progressTimestamps update for new challenge completion', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
const { updateData } = buildUserUpdate(
|
||||||
|
mockUser,
|
||||||
|
'123abc',
|
||||||
|
mockCompletedChallenge,
|
||||||
|
'UTC'
|
||||||
|
);
|
||||||
|
expect(updateData).toHaveProperty('$push');
|
||||||
|
expect(updateData.$push).toHaveProperty('progressTimestamps');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes repeat completions from the completedChallenges array', () => {
|
||||||
|
const completedChallengeId = 'aaa48de84e1ecc7c742e1124';
|
||||||
|
const completedChallenge = {
|
||||||
|
...mockCompletedChallenge,
|
||||||
|
completedDate: Date.now(),
|
||||||
|
id: completedChallengeId
|
||||||
|
};
|
||||||
|
const {
|
||||||
|
updateData: {
|
||||||
|
$set: { completedChallenges }
|
||||||
|
}
|
||||||
|
} = buildUserUpdate(
|
||||||
|
mockUser,
|
||||||
|
completedChallengeId,
|
||||||
|
completedChallenge,
|
||||||
|
'UTC'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(completedChallenges.length).toEqual(
|
||||||
|
mockCompletedChallenges.length
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds newly completed challenges to the completedChallenges array', () => {
|
||||||
|
const {
|
||||||
|
updateData: {
|
||||||
|
$set: { completedChallenges }
|
||||||
|
}
|
||||||
|
} = buildUserUpdate(mockUser, '123abc', mockCompletedChallenge, 'UTC');
|
||||||
|
|
||||||
|
expect(completedChallenges.length).toEqual(
|
||||||
|
mockCompletedChallenges.length + 1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('buildChallengeUrl', () => {
|
describe('buildChallengeUrl', () => {
|
||||||
it('resolves the correct Url for the provided challenge', () => {
|
it('resolves the correct Url for the provided challenge', () => {
|
||||||
@ -122,6 +219,7 @@ describe('boot/challenge', () => {
|
|||||||
|
|
||||||
expect(result).toEqual(firstChallengeUrl);
|
expect(result).toEqual(firstChallengeUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns the learn base if no challenges found', async () => {
|
it('returns the learn base if no challenges found', async () => {
|
||||||
const result = await getFirstChallenge(createMockChallengeModel(false));
|
const result = await getFirstChallenge(createMockChallengeModel(false));
|
||||||
|
|
||||||
@ -212,7 +310,7 @@ describe('boot/challenge', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
xdescribe('modernChallengeCompleted', () => {});
|
xdescribe('modernChallengeCompleted');
|
||||||
|
|
||||||
xdescribe('projectCompleted');
|
xdescribe('projectCompleted');
|
||||||
|
|
||||||
|
83
api-server/server/boot_tests/fixtures.js
Normal file
83
api-server/server/boot_tests/fixtures.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
export const firstChallengeUrl = '/learn/the/first/challenge';
|
||||||
|
export const requestedChallengeUrl = '/learn/my/actual/challenge';
|
||||||
|
export const mockChallenge = {
|
||||||
|
id: '123abc',
|
||||||
|
block: 'actual',
|
||||||
|
superBlock: 'my',
|
||||||
|
dashedName: 'challenge'
|
||||||
|
};
|
||||||
|
export const mockFirstChallenge = {
|
||||||
|
id: '456def',
|
||||||
|
block: 'first',
|
||||||
|
superBlock: 'the',
|
||||||
|
dashedName: 'challenge'
|
||||||
|
};
|
||||||
|
export const mockCompletedChallenge = {
|
||||||
|
id: '890xyz',
|
||||||
|
challengeType: 0,
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
contents: 'file contents',
|
||||||
|
key: 'indexfile',
|
||||||
|
name: 'index',
|
||||||
|
path: 'index.file',
|
||||||
|
ext: 'file'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
completedDate: Date.now()
|
||||||
|
};
|
||||||
|
export const mockCompletedChallenges = [
|
||||||
|
{
|
||||||
|
id: 'bd7123c8c441eddfaeb5bdef',
|
||||||
|
completedDate: 1538052380328.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '587d7dbd367417b2b2512bb4',
|
||||||
|
completedDate: 1547472893032.0,
|
||||||
|
files: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'aaa48de84e1ecc7c742e1124',
|
||||||
|
completedDate: 1541678430790.0,
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
contents:
|
||||||
|
"function palindrome(str) {\n const clean = str.replace(/[\\W_]/g, '').toLowerCase()\n const revStr = clean.split('').reverse().join('');\n return clean === revStr;\n}\n\n\n\npalindrome(\"eye\");\n",
|
||||||
|
ext: 'js',
|
||||||
|
path: 'index.js',
|
||||||
|
name: 'index',
|
||||||
|
key: 'indexjs'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5a24c314108439a4d4036164',
|
||||||
|
completedDate: 1543845124143.0,
|
||||||
|
files: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export const mockUser = {
|
||||||
|
username: 'camperbot',
|
||||||
|
currentChallengeId: '123abc',
|
||||||
|
timezone: 'UTC',
|
||||||
|
completedChallenges: mockCompletedChallenges
|
||||||
|
};
|
||||||
|
export const mockApp = {
|
||||||
|
models: {
|
||||||
|
Challenge: {
|
||||||
|
find() {
|
||||||
|
return firstChallengeUrl;
|
||||||
|
},
|
||||||
|
findById(id, cb) {
|
||||||
|
return id === mockChallenge.id
|
||||||
|
? cb(null, mockChallenge)
|
||||||
|
: cb(new Error('challenge not found'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const mockGetFirstChallenge = () => firstChallengeUrl;
|
||||||
|
export const firstChallengeQuery = {
|
||||||
|
// first challenge of the first block of the first superBlock
|
||||||
|
where: { challengeOrder: 0, superOrder: 1, order: 0 }
|
||||||
|
};
|
Reference in New Issue
Block a user