Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/frontend/app/dayjs-antd-plugins.test.ts
16567 views
1
/*
2
* This file is part of CoCalc: Copyright © 2026 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Regression test for the antd DatePicker "weekday is not a function" crash.
8
9
antd's pickers (via rc-picker) call dayjs plugin methods such as
10
`.weekday()` and `.localeData()` on the dayjs objects we hand them. Those
11
methods only exist if the corresponding plugins were registered via
12
`dayjs.extend(...)` on *our* dayjs instance. When they aren't, the store's
13
license start/end date picker throws:
14
15
TypeError: t.weekday is not a function
16
at Object.getWeekDay ...
17
18
See ./dayjs-antd-plugins.ts for the full explanation.
19
*/
20
21
import { readFileSync } from "fs";
22
import { join } from "path";
23
24
import dayjs from "dayjs";
25
26
// Importing the setup module for its side effects is exactly what the app
27
// entry points do. After this, our dayjs instance must have all the plugins.
28
import "./dayjs-antd-plugins";
29
30
describe("antd dayjs plugin registration", () => {
31
it("exposes the plugin methods rc-picker needs on a dayjs object", () => {
32
const d = dayjs();
33
expect(typeof d.weekday).toBe("function");
34
expect(typeof d.localeData).toBe("function");
35
expect(typeof d.week).toBe("function"); // weekOfYear
36
expect(typeof d.weekYear).toBe("function");
37
});
38
39
it("reproduces rc-picker's getWeekDay() without throwing", () => {
40
// This mirrors rc-picker/es/generate/dayjs.js getWeekDay(), the exact
41
// call site that threw "t.weekday is not a function" in production.
42
const getWeekDay = (date: dayjs.Dayjs): number => {
43
const clone = date.locale("en");
44
return clone.weekday() + clone.localeData().firstDayOfWeek();
45
};
46
expect(() => getWeekDay(dayjs("2026-06-08"))).not.toThrow();
47
expect(typeof getWeekDay(dayjs("2026-06-08"))).toBe("number");
48
});
49
50
it("supports advancedFormat tokens (Q, Do, k, ...)", () => {
51
// advancedFormat adds tokens like Q (quarter) and Do (ordinal day).
52
expect(dayjs("2026-06-08").format("Q")).toBe("2");
53
expect(dayjs("2026-06-08").format("Do")).toBe("8th");
54
});
55
56
it("supports customParseFormat parsing", () => {
57
const d = dayjs("08-06-2026", "DD-MM-YYYY");
58
expect(d.isValid()).toBe(true);
59
expect(d.year()).toBe(2026);
60
expect(d.month()).toBe(5); // June (0-indexed)
61
expect(d.date()).toBe(8);
62
});
63
});
64
65
describe("antd dayjs plugins are wired into the app entry points", () => {
66
// Guard against silently dropping the side-effect import that activates the
67
// fix. If these break, the production picker crash will come back.
68
const setupImport = "app/dayjs-antd-plugins";
69
70
it("frontend entry-point.ts imports the dayjs plugin setup", () => {
71
const src = readFileSync(join(__dirname, "..", "entry-point.ts"), "utf8");
72
expect(src).toContain(setupImport);
73
});
74
75
it("next _app.tsx imports the dayjs plugin setup", () => {
76
const appPath = join(
77
__dirname,
78
"..",
79
"..",
80
"next",
81
"pages",
82
"_app.tsx",
83
);
84
const src = readFileSync(appPath, "utf8");
85
expect(src).toContain(setupImport);
86
});
87
});
88
89