const expect = require("chai").expect
|
|
const db = require("../lib/db")
|
const testData = require("./data")
|
const dayjs = require("dayjs");
|
const {alleAuswerten, auswerten, partitionDates} = require("../lib/libLp");
|
|
/////////////////////////////////////////////////////////////////////////
|
|
describe("regarding the Kurs LP", function () {
|
|
const kurs = testData.kurs // TODO real test
|
let kursId = 32212
|
|
beforeEach(async function () {
|
})
|
|
afterEach(async function () {
|
})
|
|
describe("the function getKursUnterobjektLp", function () {
|
it("should deliver the LP for the Kurs Unterobjekte", async function () {
|
const res = await db.getKursUnterobjektLp(kursId)
|
// console.table(res)
|
expect(res).to.be.a("array")
|
for (const item of res) {
|
expect(item).to.have.property("obj_id").and.to.be.a("number")
|
expect(item).to.have.property("item_id").and.to.be.a("number")
|
expect(item).to.have.property("lpmode").and.to.be.a("number")
|
expect(item).to.have.property("item_obj_id").and.to.be.a("number")
|
expect(item).to.have.property("usr_id").and.to.be.a("number")
|
expect(item).to.have.property("status").and.to.be.a("number")
|
expect(item).to.have.property("status_changed").and.to.be.a("date")
|
}
|
})
|
})
|
|
describe("the function getKursLp", function () {
|
it("should return the unified LP of a Kurs", async function () {
|
const res = await db.getKursLp(kursId)
|
console.table(res)
|
})
|
})
|
|
describe('the function partitionDates()', function () {
|
|
const maxDate = dayjs("2025-06-15T12:00:00")
|
const item = (status, date) => ({status, status_changed: date})
|
|
it("should return an object with inside and outside arrays", function () {
|
const res = partitionDates(maxDate, [])
|
expect(res).to.be.an("object")
|
expect(res.inside).to.be.an("array")
|
expect(res.outside).to.be.an("array")
|
})
|
|
it("should put an empty item list into empty arrays", function () {
|
const {inside, outside} = partitionDates(maxDate, [])
|
expect(inside).to.have.lengthOf(0)
|
expect(outside).to.have.lengthOf(0)
|
})
|
|
it("should put all items inside when all are within the last month", function () {
|
const items = [
|
item(0, dayjs(maxDate).subtract(1, "day").toDate()),
|
item(1, dayjs(maxDate).subtract(2, "week").toDate()),
|
item(2, dayjs(maxDate).subtract(3, "week").toDate()),
|
]
|
const {inside, outside} = partitionDates(maxDate, items)
|
expect(inside).to.have.lengthOf(3)
|
expect(outside).to.have.lengthOf(0)
|
})
|
|
it("should put all items outside when all are older than a month", function () {
|
const items = [
|
item(0, dayjs(maxDate).subtract(2, "month").toDate()),
|
item(1, dayjs(maxDate).subtract(1, "year").toDate()),
|
]
|
const {inside, outside} = partitionDates(maxDate, items)
|
expect(inside).to.have.lengthOf(0)
|
expect(outside).to.have.lengthOf(2)
|
})
|
|
it("should treat an item exactly one month before maxDate as inside", function () {
|
const it0 = item(0, dayjs(maxDate).subtract(1, "month").toDate())
|
const {inside, outside} = partitionDates(maxDate, [it0])
|
expect(inside).to.deep.equal([it0])
|
expect(outside).to.have.lengthOf(0)
|
})
|
|
it("should treat an item slightly more than one month before maxDate as outside", function () {
|
const it0 = item(0, dayjs(maxDate).subtract(1, "month").subtract(1, "second").toDate())
|
const {inside, outside} = partitionDates(maxDate, [it0])
|
expect(inside).to.have.lengthOf(0)
|
expect(outside).to.deep.equal([it0])
|
})
|
|
it("should treat an item at the same instant as maxDate as inside", function () {
|
const it0 = item(2, maxDate.toDate())
|
const {inside, outside} = partitionDates(maxDate, [it0])
|
expect(inside).to.deep.equal([it0])
|
expect(outside).to.have.lengthOf(0)
|
})
|
|
it("should treat an item after maxDate as inside", function () {
|
const it0 = item(1, dayjs(maxDate).add(1, "day").toDate())
|
const {inside, outside} = partitionDates(maxDate, [it0])
|
expect(inside).to.deep.equal([it0])
|
expect(outside).to.have.lengthOf(0)
|
})
|
|
it("should split a mixed list correctly", function () {
|
const recent = item(2, dayjs(maxDate).subtract(10, "day").toDate())
|
const old = item(3, dayjs(maxDate).subtract(6, "month").toDate())
|
const veryOld = item(1, dayjs(maxDate).subtract(1, "year").toDate())
|
const {inside, outside} = partitionDates(maxDate, [recent, old, veryOld])
|
expect(inside).to.deep.equal([recent])
|
expect(outside).to.deep.equal([old, veryOld])
|
})
|
|
it("should preserve the original item objects", function () {
|
const recent = item(2, dayjs(maxDate).subtract(1, "day").toDate())
|
const old = item(3, dayjs(maxDate).subtract(1, "year").toDate())
|
const {inside, outside} = partitionDates(maxDate, [recent, old])
|
expect(inside[0]).to.equal(recent)
|
expect(outside[0]).to.equal(old)
|
})
|
|
it("should not mutate the input array", function () {
|
const items = [
|
item(0, dayjs(maxDate).subtract(1, "day").toDate()),
|
item(2, dayjs(maxDate).subtract(2, "year").toDate()),
|
]
|
const copy = items.slice()
|
partitionDates(maxDate, items)
|
expect(items).to.deep.equal(copy)
|
})
|
|
})
|
|
describe('the function auswerten()', function () {
|
|
const recent = () => dayjs().subtract(1, "day").toDate()
|
const stale = () => dayjs().subtract(2, "month").toDate()
|
const item = (status, date) => ({status, status_changed: date})
|
// an "outside" element used to trigger the outside-handling branches
|
const outsideItem = () => item(0, stale())
|
|
/////// Fall 1: no sub statuses
|
|
it("Fall 1: should return 0 for an empty list", function () {
|
expect(auswerten([])).to.equal(0)
|
})
|
|
/////// Fall 2: any 'not passed' (3) -> 3
|
|
it("Fall 2: should return 3 when a 3 is present", function () {
|
expect(auswerten([item(3, recent()), item(2, recent())])).to.equal(3)
|
})
|
|
it("Fall 2: should return 3 when all statuses are 3", function () {
|
expect(auswerten([item(3, recent()), item(3, recent())])).to.equal(3)
|
})
|
|
it("Fall 2: should return 3 for mixed 0,1,2,3", function () {
|
expect(auswerten([item(0, recent()), item(1, recent()), item(2, recent()), item(3, recent())])).to.equal(3)
|
})
|
|
/////// Fall 3: all statuses equal
|
|
it("Fall 3: should return 0 when all are 0 (no outside)", function () {
|
expect(auswerten([item(0, recent()), item(0, recent())])).to.equal(0)
|
})
|
|
it("Fall 3: should return 1 when all are 1 (no outside)", function () {
|
expect(auswerten([item(1, recent()), item(1, recent())])).to.equal(1)
|
})
|
|
it("Fall 3: should return 2 when all are 2 (no outside)", function () {
|
expect(auswerten([item(2, recent()), item(2, recent())])).to.equal(2)
|
})
|
|
it("Fall 3: should return 3 when all are 3 (no outside)", function () {
|
expect(auswerten([item(3, recent()), item(3, recent())])).to.equal(3)
|
})
|
|
it("Fall 3: should return the status of a single status (no outside)", function () {
|
expect(auswerten([item(0, recent())])).to.equal(0)
|
expect(auswerten([item(1, recent())])).to.equal(1)
|
expect(auswerten([item(2, recent())])).to.equal(2)
|
expect(auswerten([item(3, recent())])).to.equal(3)
|
})
|
|
it("Fall 3: should return 1 when all are equal but an outside element exists", function () {
|
expect(auswerten([item(2, recent()), item(2, recent()), outsideItem()])).to.equal(1)
|
})
|
|
/////// Fall 4: something is in progress (1 or 2)
|
|
it("Fall 4: should return 1 for 0,1,0", function () {
|
expect(auswerten([item(0, recent()), item(1, recent()), item(0, recent())])).to.equal(1)
|
})
|
|
it("Fall 4: should return 1 for 2,1,2", function () {
|
expect(auswerten([item(2, recent()), item(1, recent()), item(2, recent())])).to.equal(1)
|
})
|
|
it("Fall 4: should return 1 for 0,2", function () {
|
expect(auswerten([item(0, recent()), item(2, recent())])).to.equal(1)
|
})
|
|
it("Fall 4: should return 1 for 0,1,2", function () {
|
expect(auswerten([item(0, recent()), item(1, recent()), item(2, recent())])).to.equal(1)
|
})
|
|
/////// Fall 5: everything else
|
|
it("Fall 5: should return 0 when only 0 and no 3/1/2 mixed in", function () {
|
expect(auswerten([item(0, recent()), item(0, recent()), item(0, recent())])).to.equal(0)
|
})
|
|
/////// stale dates (outside the one-month ballpark)
|
|
it("stale: should return the status when all items are stale and equal", function () {
|
expect(auswerten([item(2, stale()), item(2, stale())])).to.equal(2)
|
})
|
|
it("stale: should return 1 when all stale items are mixed (0,2)", function () {
|
expect(auswerten([item(0, stale()), item(2, stale())])).to.equal(1)
|
})
|
|
it("stale: should return 3 when all stale items are 3", function () {
|
expect(auswerten([item(3, stale()), item(3, stale())])).to.equal(3)
|
})
|
|
it("stale: should return the status for a single stale item", function () {
|
expect(auswerten([item(2, stale())])).to.equal(2)
|
expect(auswerten([item(3, stale())])).to.equal(3)
|
})
|
|
it("stale: a stale 3 should not force 3 when a recent item exists", function () {
|
expect(auswerten([item(3, stale()), item(2, recent())])).to.equal(1)
|
})
|
|
it("stale: a stale 3 should still force 3 when a recent 3 exists", function () {
|
expect(auswerten([item(3, stale()), item(3, recent())])).to.equal(3)
|
})
|
|
it("stale: should return 1 when all recent statuses are equal but a stale item exists", function () {
|
expect(auswerten([item(0, recent()), item(0, recent()), item(0, stale())])).to.equal(1)
|
})
|
|
it("stale: should return 1 for a recent 2 plus a stale 2", function () {
|
expect(auswerten([item(2, recent()), item(2, stale())])).to.equal(1)
|
})
|
|
it("stale: should ignore a stale item when recent statuses are already mixed", function () {
|
expect(auswerten([item(0, recent()), item(2, recent()), item(0, stale())])).to.equal(1)
|
})
|
|
it("stale: boundary - item just inside the month counts as recent", function () {
|
const now = dayjs()
|
const inside = now.subtract(1, "month").add(1, "day").toDate()
|
expect(auswerten([item(0, now.toDate()), item(0, inside)])).to.equal(0)
|
})
|
|
it("stale: boundary - item just outside the month counts as stale", function () {
|
const now = dayjs()
|
const outside = now.subtract(1, "month").subtract(1, "day").toDate()
|
expect(auswerten([item(0, now.toDate()), item(0, outside)])).to.equal(1)
|
})
|
|
})
|
|
describe('the function alleAuswerten()', function () {
|
|
const recent = () => dayjs().subtract(1, "day").toDate()
|
const stale = () => dayjs().subtract(2, "month").toDate()
|
// build a raw row like the ones coming from getKursUnterobjektLp()
|
const row = (usr_id, status, date, extra = {}) => Object.assign({
|
usr_id,
|
login: `login${usr_id}`,
|
firstname: `First${usr_id}`,
|
lastname: `Last${usr_id}`,
|
obj_id: 32212,
|
item_id: 1,
|
item_obj_id: 100,
|
status,
|
status_changed: date,
|
}, extra)
|
|
it("should return an empty array for empty input", function () {
|
expect(alleAuswerten([])).to.be.an("array").and.to.have.lengthOf(0)
|
})
|
|
it("should return one row per user", function () {
|
const res = alleAuswerten([
|
row(1, 0, recent()), row(1, 2, recent()), row(1, 1, recent()),
|
row(2, 2, recent()),
|
])
|
expect(res).to.be.an("array").and.to.have.lengthOf(2)
|
expect(res.map(r => r.usr_id).sort()).to.deep.equal([1, 2])
|
})
|
|
it("should group all items of a user into a single result row", function () {
|
const res = alleAuswerten([
|
row(1, 0, recent()), row(1, 0, recent()), row(1, 0, recent()),
|
])
|
expect(res).to.have.lengthOf(1)
|
expect(res[0].usr_id).to.equal(1)
|
})
|
|
it("should keep users separated", function () {
|
const res = alleAuswerten([
|
row(1, 0, recent()), row(1, 2, recent()), // user 1 -> mixed -> 1
|
row(2, 2, recent()), row(2, 2, recent()), // user 2 -> all 2 -> 2
|
])
|
const byId = Object.fromEntries(res.map(r => [r.usr_id, r.status]))
|
expect(byId[1]).to.equal(1)
|
expect(byId[2]).to.equal(2)
|
})
|
|
it("should order the result by usr_id ascending", function () {
|
const res = alleAuswerten([
|
row(7, 0, recent()), row(3, 0, recent()), row(7, 1, recent()),
|
])
|
expect(res.map(r => r.usr_id)).to.deep.equal([3, 7])
|
})
|
|
/////// stale dates (outside the one-month ballpark)
|
|
it("stale: should return the status when all of a user's items are stale and equal", function () {
|
const res = alleAuswerten([row(1, 2, stale()), row(1, 2, stale())])
|
expect(res[0].status).to.equal(2)
|
})
|
|
it("stale: should return 1 when a user's stale items are mixed", function () {
|
const res = alleAuswerten([row(1, 0, stale()), row(1, 2, stale())])
|
expect(res[0].status).to.equal(1)
|
})
|
|
it("stale: a stale item should turn equal recent statuses into 1", function () {
|
const res = alleAuswerten([row(1, 0, recent()), row(1, 0, stale())])
|
expect(res[0].status).to.equal(1)
|
})
|
|
it("stale: should still return 3 when a recent item of the user is 3", function () {
|
const res = alleAuswerten([row(1, 3, recent()), row(1, 3, stale())])
|
expect(res[0].status).to.equal(3)
|
})
|
|
})
|
|
})
|
|
/////////////////////////////////////////////////////////////////////////
|