-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get user post ranks and top ranked whys#208 #263
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// https://github.com/EnCiv/civil-pursuit/issues/208 | ||
|
||
import { MongoMemoryServer } from 'mongodb-memory-server'; | ||
import { Mongo } from '@enciv/mongo-collections'; | ||
import { ObjectId } from 'mongodb'; | ||
import Rankings from '../../models/rankings'; | ||
import Points from '../../models/points'; | ||
import getUserPostRanksAndTopRankedWhys from '../get-user-post-ranks-and-top-ranked-whys'; | ||
|
||
let memoryServer; | ||
let db; | ||
|
||
const synuser = { synuser: { id: new ObjectId().toString() } }; | ||
|
||
beforeAll(async () => { | ||
memoryServer = await MongoMemoryServer.create(); | ||
const uri = memoryServer.getUri(); | ||
await Mongo.connect(uri); | ||
db = Mongo.db; | ||
Rankings.setCollectionProps(); | ||
Points.setCollectionProps(); | ||
}); | ||
|
||
afterAll(async () => { | ||
await Mongo.disconnect(); | ||
await memoryServer.stop(); | ||
}); | ||
|
||
beforeEach(async () => { | ||
jest.spyOn(console, 'error').mockImplementation(() => {}); | ||
}); | ||
|
||
afterEach(async () => { | ||
console.error.mockRestore(); | ||
}); | ||
|
||
test('User not logged in', async () => { | ||
const callback = jest.fn(); | ||
await getUserPostRanksAndTopRankedWhys.call({}, 'discussion1', 1, ['id1', 'id2'], callback); | ||
expect(callback).toHaveBeenCalledWith(undefined); | ||
expect(console.error).toHaveBeenCalledWith(expect.stringMatching(/no user logged in/)); | ||
}); | ||
|
||
test('10 points in ids, nothing ranked', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of making new ids here, every time the test is run, generate 10 (use console.info) and then copy them into an array here. I'm learning that in the expect statements, what's expected needs to be more visible, meaning .objectToMatch({...}) so that when we look at the code in the test we can see what's expected. -- We are missing things by not looking at it. |
||
const ids = Array.from({ length: 10 }, () => new ObjectId().toString()); | ||
|
||
const callback = jest.fn(); | ||
await getUserPostRanksAndTopRankedWhys.call(synuser, 'discussion1', 1, ids, callback); | ||
|
||
expect(callback).toHaveBeenCalledWith({ ranks: [], whys: [] }); | ||
}); | ||
|
||
test('5 have 2 why mosts, 2 have why leasts, 1 has 1 why most, 1 has 1 why least – nothing ranked', async () => { | ||
const ids = Array.from({ length: 10 }, () => new ObjectId().toString()); | ||
|
||
await db.collection('points').insertMany([ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this works, but it would be shorter and clearer to say Points.insertMany |
||
...ids.slice(0, 5).flatMap(id => [ | ||
{ _id: new ObjectId(), parentId: id, category: 'most', title: `Why Most 1 for ${id}`, userId: '123456' }, | ||
{ _id: new ObjectId(), parentId: id, category: 'most', title: `Why Most 2 for ${id}`, userId: '123456' }, | ||
]), | ||
...ids.slice(5, 7).flatMap(id => [ | ||
{ _id: new ObjectId(), parentId: id, category: 'least', title: `Why Least 1 for ${id}`, userId: '123456' }, | ||
{ _id: new ObjectId(), parentId: id, category: 'least', title: `Why Least 2 for ${id}`, userId: '123456' }, | ||
]), | ||
{ _id: new ObjectId(), parentId: ids[7], category: 'most', title: `Why Most for ${ids[7]}`, userId: '123456' }, | ||
{ _id: new ObjectId(), parentId: ids[8], category: 'least', title: `Why Least for ${ids[8]}`, userId: '123456' }, | ||
]); | ||
|
||
const callback = jest.fn(); | ||
await getUserPostRanksAndTopRankedWhys.call(synuser, 'discussion1', 1, ids, callback); | ||
|
||
expect(callback).toHaveBeenCalledWith({ | ||
ranks: [], | ||
whys: expect.any(Array), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of .any use But this will only work if the ids are the same every time. |
||
}); | ||
}); | ||
|
||
test('Above scenario with 5 ranked, nothing for other 5', async () => { | ||
const ids = Array.from({ length: 10 }, () => new ObjectId().toString()); | ||
|
||
const rankings = ids.slice(0, 5).map(id => ({ | ||
_id: new ObjectId(), | ||
parentId: id, | ||
category: 'most', | ||
stage: 'post', | ||
discussionId: 'discussion1', | ||
round: 1, | ||
userId: '123456', | ||
})); | ||
|
||
if (rankings.length > 0) { | ||
await db.collection('rankings').insertMany(rankings); | ||
} | ||
|
||
const callback = jest.fn(); | ||
await getUserPostRanksAndTopRankedWhys.call(synuser, 'discussion1', 1, ids, callback); | ||
|
||
expect(callback).toHaveBeenCalledWith({ | ||
ranks: expect.any(Array), | ||
whys: [], | ||
}); | ||
}); | ||
|
||
test('Above scenario with all ranked', async () => { | ||
const ids = Array.from({ length: 10 }, () => new ObjectId().toString()); | ||
|
||
const rankings = ids.map(id => ({ | ||
_id: new ObjectId(), | ||
parentId: id, | ||
category: 'most', | ||
stage: 'post', | ||
discussionId: 'discussion1', | ||
round: 1, | ||
userId: '123456', | ||
})); | ||
|
||
if (rankings.length > 0) { | ||
await db.collection('rankings').insertMany(rankings); | ||
} | ||
|
||
const callback = jest.fn(); | ||
await getUserPostRanksAndTopRankedWhys.call(synuser, 'discussion1', 1, ids, callback); | ||
|
||
expect(callback).toHaveBeenCalledWith({ | ||
ranks: expect.any(Array), | ||
whys: expect.any(Array), | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// https://github.com/EnCiv/civil-pursuit/issues/208 | ||
const Rankings = require('../models/rankings'); | ||
const getTopRankedWhysForPoint = require('./get-top-ranked-whys-for-point'); | ||
const { ObjectId } = require('mongodb'); | ||
|
||
async function getUserPostRanksAndTopRankedWhys(discussionId, round, ids, cb) { | ||
if (!this.synuser || !this.synuser.id) { | ||
console.error('getUserPostRanksAndTopRankedWhys called but no user logged in'); | ||
return cb && cb(undefined); | ||
} | ||
|
||
if (!discussionId || typeof round !== 'number' || !Array.isArray(ids) || ids.length === 0) { | ||
console.error('getUserPostRanksAndTopRankedWhys called with invalid parameters'); | ||
return cb && cb(undefined); | ||
} | ||
|
||
try { | ||
// Fetch rankings for discussionId, round, and stage 'post' | ||
const ranks = await Rankings.aggregate([ | ||
{ | ||
$match: { | ||
discussionId: discussionId.toString(), | ||
round, | ||
stage: 'post', | ||
parentId: { $in: ids.map(id => id.toString()) }, | ||
}, | ||
}, | ||
]).toArray(); | ||
|
||
// Remove userId for ranks not created by the current user | ||
const filteredRanks = ranks.map(({ userId, ...rest }) => | ||
userId === this.synuser.id ? { userId, ...rest } : rest | ||
); | ||
|
||
// Fetch top-ranked whys for each point in ids | ||
const topWhys = await Promise.all( | ||
ids.map(async id => { | ||
return new Promise(resolve => | ||
getTopRankedWhysForPoint.call( | ||
this, | ||
id.toString(), | ||
'most', | ||
0, | ||
1, | ||
whys => resolve(whys[0] || null) // Get the top-ranked why point | ||
) | ||
); | ||
}) | ||
); | ||
|
||
// Filter out nulls from topWhys | ||
const filteredWhys = topWhys.filter(Boolean); | ||
|
||
cb({ ranks: filteredRanks, whys: filteredWhys }); | ||
} catch (error) { | ||
console.error('Error in getUserPostRanksAndTopRankedWhys:', error); | ||
cb(undefined); | ||
} | ||
} | ||
|
||
module.exports = getUserPostRanksAndTopRankedWhys; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling .setCollectionProps is not needed for these models. It's done when the model is loaded.