mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-25 04:37:13 -05:00
244 lines
6.7 KiB
TypeScript
244 lines
6.7 KiB
TypeScript
import { beforeEach, describe, expect, test } from "vitest";
|
|
import * as AvailabilityWeekFactory from "~/db/seed/factories/AvailabilityWeekFactory";
|
|
import * as TeamEventFactory from "~/db/seed/factories/TeamEventFactory";
|
|
import * as TeamFactory from "~/db/seed/factories/TeamFactory";
|
|
import * as UserFactory from "~/db/seed/factories/UserFactory";
|
|
import { AVAILABILITY } from "../availability-constants";
|
|
import * as Availability from "./Availability";
|
|
import * as RosterSchedule from "./RosterSchedule.server";
|
|
|
|
const users = UserFactory.pool();
|
|
const memberId = () => users.id(1);
|
|
const teammateId = () => users.id(2);
|
|
const viewerId = () => users.id(3);
|
|
|
|
const TIMEZONE = "Europe/Helsinki";
|
|
const HOUR = 60 * 60;
|
|
|
|
const currentWeekStartsAt = () =>
|
|
Availability.weekStartsAt(new Date(), TIMEZONE);
|
|
|
|
const dataOf = (userIds: Array<number>) =>
|
|
RosterSchedule.rosterScheduleData({
|
|
userIds,
|
|
timezone: TIMEZONE,
|
|
viewerId: viewerId(),
|
|
});
|
|
|
|
const memberOf = async (userId: number) =>
|
|
(await dataOf([userId])).members.find((member) => member.userId === userId);
|
|
|
|
describe("RosterSchedule.rosterScheduleData", () => {
|
|
beforeEach(async () => {
|
|
await users.create(3);
|
|
});
|
|
|
|
test("lays out the current and the next week as seven days each", async () => {
|
|
const { weeks } = await dataOf([memberId()]);
|
|
|
|
expect(weeks).toHaveLength(2);
|
|
expect(weeks[0].startsAt).toBe(currentWeekStartsAt());
|
|
expect(weeks[1].startsAt).toBe(weeks[0].endsAt);
|
|
|
|
for (const week of weeks) {
|
|
expect(week.days).toHaveLength(7);
|
|
expect(week.days[0].startsAt).toBe(week.startsAt);
|
|
expect(week.days[6].endsAt).toBe(week.endsAt);
|
|
}
|
|
});
|
|
|
|
test("keeps an entry for a member not sharing their schedule, with nothing in it", async () => {
|
|
await AvailabilityWeekFactory.create({
|
|
userId: memberId(),
|
|
weekStartsAt: currentWeekStartsAt(),
|
|
timezone: TIMEZONE,
|
|
slots: [
|
|
{
|
|
startsAt: currentWeekStartsAt() + 18 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
},
|
|
],
|
|
});
|
|
await UserFactory.grant(memberId(), {
|
|
preferences: { scheduleVisibility: { friends: false, teamIds: [] } },
|
|
});
|
|
|
|
expect(await memberOf(memberId())).toEqual({
|
|
userId: memberId(),
|
|
reportedWeekStarts: [],
|
|
ranges: [],
|
|
});
|
|
});
|
|
|
|
test("reports which of the weeks the member has filled in", async () => {
|
|
await AvailabilityWeekFactory.create({
|
|
userId: memberId(),
|
|
weekStartsAt: currentWeekStartsAt(),
|
|
timezone: TIMEZONE,
|
|
});
|
|
|
|
expect((await memberOf(memberId()))?.reportedWeekStarts).toEqual([
|
|
currentWeekStartsAt(),
|
|
]);
|
|
});
|
|
|
|
test("cuts a commitment out of the reported availability", async () => {
|
|
const slot = {
|
|
startsAt: currentWeekStartsAt() + 18 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
};
|
|
await AvailabilityWeekFactory.create({
|
|
userId: memberId(),
|
|
weekStartsAt: currentWeekStartsAt(),
|
|
timezone: TIMEZONE,
|
|
slots: [slot],
|
|
});
|
|
const team = await TeamFactory.create({
|
|
memberUserIds: [memberId(), teammateId()],
|
|
});
|
|
await TeamEventFactory.create({
|
|
teamId: team.id,
|
|
authorId: memberId(),
|
|
name: "VoD review",
|
|
startsAt: slot.startsAt + HOUR,
|
|
endsAt: slot.startsAt + 2 * HOUR,
|
|
});
|
|
|
|
const member = await memberOf(memberId());
|
|
|
|
expect(member?.ranges).toEqual([
|
|
{ startsAt: slot.startsAt, endsAt: slot.startsAt + HOUR },
|
|
{ startsAt: slot.startsAt + 2 * HOUR, endsAt: slot.endsAt },
|
|
]);
|
|
});
|
|
|
|
test("returns a member with nothing reported as an empty week", async () => {
|
|
expect(await memberOf(memberId())).toEqual({
|
|
userId: memberId(),
|
|
reportedWeekStarts: [],
|
|
ranges: [],
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("RosterSchedule.windowSchedules", () => {
|
|
const window = (id: number, from: number, to: number) => ({
|
|
id,
|
|
startsAt: currentWeekStartsAt() + from * HOUR,
|
|
endsAt: currentWeekStartsAt() + to * HOUR,
|
|
});
|
|
|
|
const schedulesOf = async (
|
|
windows: Array<ReturnType<typeof window>>,
|
|
userIds: Array<number> = [memberId()],
|
|
) =>
|
|
RosterSchedule.windowSchedules({ windows, userIds, viewerId: viewerId() });
|
|
|
|
beforeEach(async () => {
|
|
await users.create(3);
|
|
});
|
|
|
|
test("reports what the member has free inside the window", async () => {
|
|
await AvailabilityWeekFactory.create({
|
|
userId: memberId(),
|
|
weekStartsAt: currentWeekStartsAt(),
|
|
timezone: TIMEZONE,
|
|
slots: [
|
|
{
|
|
startsAt: currentWeekStartsAt() + 18 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
},
|
|
],
|
|
});
|
|
|
|
const [schedules] = await schedulesOf([window(1, 20, 23)]);
|
|
|
|
expect(schedules.members).toEqual([
|
|
{
|
|
userId: memberId(),
|
|
reported: true,
|
|
ranges: [
|
|
{
|
|
startsAt: currentWeekStartsAt() + 20 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
},
|
|
],
|
|
busy: [],
|
|
},
|
|
]);
|
|
});
|
|
|
|
test("keeps an entry for a member not sharing their schedule, with nothing in it", async () => {
|
|
await AvailabilityWeekFactory.create({
|
|
userId: memberId(),
|
|
weekStartsAt: currentWeekStartsAt(),
|
|
timezone: TIMEZONE,
|
|
slots: [
|
|
{
|
|
startsAt: currentWeekStartsAt() + 18 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
},
|
|
],
|
|
});
|
|
await UserFactory.grant(memberId(), {
|
|
preferences: { scheduleVisibility: { friends: false, teamIds: [] } },
|
|
});
|
|
|
|
const [schedules] = await schedulesOf([window(1, 20, 23)]);
|
|
|
|
expect(schedules.members).toEqual([
|
|
{ userId: memberId(), reported: false, ranges: [], busy: [] },
|
|
]);
|
|
});
|
|
|
|
test("cuts a commitment out of the availability and reports it", async () => {
|
|
await AvailabilityWeekFactory.create({
|
|
userId: memberId(),
|
|
weekStartsAt: currentWeekStartsAt(),
|
|
timezone: TIMEZONE,
|
|
slots: [
|
|
{
|
|
startsAt: currentWeekStartsAt() + 18 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
},
|
|
],
|
|
});
|
|
const team = await TeamFactory.create({
|
|
memberUserIds: [memberId(), teammateId()],
|
|
});
|
|
await TeamEventFactory.create({
|
|
teamId: team.id,
|
|
authorId: memberId(),
|
|
name: "VoD review",
|
|
startsAt: currentWeekStartsAt() + 19 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 20 * HOUR,
|
|
});
|
|
|
|
const [schedules] = await schedulesOf([window(1, 18, 22)]);
|
|
|
|
expect(schedules.members[0].ranges).toEqual([
|
|
{
|
|
startsAt: currentWeekStartsAt() + 18 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 19 * HOUR,
|
|
},
|
|
{
|
|
startsAt: currentWeekStartsAt() + 20 * HOUR,
|
|
endsAt: currentWeekStartsAt() + 22 * HOUR,
|
|
},
|
|
]);
|
|
expect(schedules.members[0].busy).toHaveLength(1);
|
|
});
|
|
|
|
test("marks a week the member never filled in as not reported", async () => {
|
|
const [schedules] = await schedulesOf([window(1, 18, 20)]);
|
|
|
|
expect(schedules.members[0].reported).toBe(false);
|
|
});
|
|
|
|
test("leaves out a window past the reportable horizon", async () => {
|
|
const beyond = 24 * 7 * (AVAILABILITY.WEEK_HORIZON + 1);
|
|
|
|
expect(await schedulesOf([window(1, beyond, beyond + 2)])).toEqual([]);
|
|
});
|
|
});
|