jsgantt-improved 2.8.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.mocharc.cjs +5 -0
  2. package/.travis.yml +0 -2
  3. package/Documentation.md +1 -1
  4. package/dist/draw_columns.js +171 -0
  5. package/dist/draw_dependencies.js +97 -0
  6. package/dist/e2e/app.e2e-spec.js +3 -3
  7. package/dist/e2e/app.e2e-spec.js.map +1 -1
  8. package/dist/e2e/app.po.js +5 -5
  9. package/dist/e2e/app.po.js.map +1 -1
  10. package/dist/jsgantt.js +580 -473
  11. package/dist/json.js +200 -0
  12. package/dist/lang.js +1635 -0
  13. package/dist/options.js +219 -0
  14. package/dist/playwright.config.js +33 -0
  15. package/dist/playwright.config.js.map +1 -0
  16. package/dist/src/draw.js +149 -148
  17. package/dist/src/draw.js.map +1 -1
  18. package/dist/src/draw_columns.js +66 -63
  19. package/dist/src/draw_columns.js.map +1 -1
  20. package/dist/src/draw_dependencies.js +4 -2
  21. package/dist/src/draw_dependencies.js.map +1 -1
  22. package/dist/src/events.js +72 -54
  23. package/dist/src/events.js.map +1 -1
  24. package/dist/src/json.js +10 -7
  25. package/dist/src/json.js.map +1 -1
  26. package/dist/src/lang.js +1 -1
  27. package/dist/src/lang.js.map +1 -1
  28. package/dist/src/options.js +14 -13
  29. package/dist/src/options.js.map +1 -1
  30. package/dist/src/task.js +61 -49
  31. package/dist/src/task.js.map +1 -1
  32. package/dist/src/utils/date_utils.js +46 -15
  33. package/dist/src/utils/date_utils.js.map +1 -1
  34. package/dist/src/utils/draw_utils.js +24 -18
  35. package/dist/src/utils/draw_utils.js.map +1 -1
  36. package/dist/src/utils/general_utils.js +59 -36
  37. package/dist/src/utils/general_utils.js.map +1 -1
  38. package/dist/src/utils.js +498 -0
  39. package/dist/src/utils.js.map +1 -0
  40. package/dist/src/xml.js +74 -67
  41. package/dist/src/xml.js.map +1 -1
  42. package/dist/test/e2e/gantt.page.js +150 -0
  43. package/dist/test/e2e/gantt.page.js.map +1 -0
  44. package/dist/test/e2e/issue172-row-alignment.spec.js +198 -0
  45. package/dist/test/e2e/issue172-row-alignment.spec.js.map +1 -0
  46. package/dist/test/e2e/issue207-bar-axis-alignment.spec.js +329 -0
  47. package/dist/test/e2e/issue207-bar-axis-alignment.spec.js.map +1 -0
  48. package/dist/test/e2e/issue255-show-weekends.spec.js +102 -0
  49. package/dist/test/e2e/issue255-show-weekends.spec.js.map +1 -0
  50. package/dist/test/e2e/issue349-taskname-click-event.spec.js +270 -0
  51. package/dist/test/e2e/issue349-taskname-click-event.spec.js.map +1 -0
  52. package/dist/test/e2e/issue48-dependency-lines.spec.js +204 -0
  53. package/dist/test/e2e/issue48-dependency-lines.spec.js.map +1 -0
  54. package/dist/test/e2e/issue54-month-today.spec.js +181 -0
  55. package/dist/test/e2e/issue54-month-today.spec.js.map +1 -0
  56. package/dist/test/e2e/issue68-working-days.spec.js +243 -0
  57. package/dist/test/e2e/issue68-working-days.spec.js.map +1 -0
  58. package/dist/test/e2e/zoom-alignment.spec.js +133 -0
  59. package/dist/test/e2e/zoom-alignment.spec.js.map +1 -0
  60. package/dist/test/index.js +3 -8
  61. package/dist/test/index.js.map +1 -1
  62. package/dist/test/unit/date-utils.spec.js +180 -0
  63. package/dist/test/unit/date-utils.spec.js.map +1 -0
  64. package/dist/test/unit/draw-cols-chart.spec.js +105 -0
  65. package/dist/test/unit/draw-cols-chart.spec.js.map +1 -0
  66. package/dist/test/unit/gantt-chart-constructor.spec.js +85 -0
  67. package/dist/test/unit/gantt-chart-constructor.spec.js.map +1 -0
  68. package/dist/test/unit/helpers.js +67 -0
  69. package/dist/test/unit/helpers.js.map +1 -0
  70. package/dist/test/unit/task-item.spec.js +46 -0
  71. package/dist/test/unit/task-item.spec.js.map +1 -0
  72. package/dist/test/unit/task-management.spec.js +141 -0
  73. package/dist/test/unit/task-management.spec.js.map +1 -0
  74. package/dist/test/unit/working-days.spec.js +109 -0
  75. package/dist/test/unit/working-days.spec.js.map +1 -0
  76. package/dist/utils/draw_utils.js +169 -0
  77. package/dist/utils/general_utils.js +498 -0
  78. package/dist/xml.js +345 -0
  79. package/dist-e2e/gantt.page.js +79 -0
  80. package/dist-e2e/gantt.page.js.map +1 -0
  81. package/dist-e2e/issue-setMinDate-setMaxDate.spec.js +96 -0
  82. package/dist-e2e/issue172-row-alignment.spec.js +90 -0
  83. package/dist-e2e/issue172-row-alignment.spec.js.map +1 -0
  84. package/dist-e2e/issue207-bar-axis-alignment.spec.js +161 -0
  85. package/dist-e2e/issue207-bar-axis-alignment.spec.js.map +1 -0
  86. package/dist-e2e/issue349-taskname-click-event.spec.js +170 -0
  87. package/dist-e2e/issue349-taskname-click-event.spec.js.map +1 -0
  88. package/dist-e2e/issue375-column-visibility.spec.js +129 -0
  89. package/dist-e2e/issue375-column-visibility.spec.js.map +1 -0
  90. package/dist-e2e/issue54-month-today.spec.js +84 -0
  91. package/dist-e2e/issue54-month-today.spec.js.map +1 -0
  92. package/dist-e2e/issue68-working-days.spec.js +105 -0
  93. package/dist-e2e/issue68-working-days.spec.js.map +1 -0
  94. package/docs/index.js +5 -2
  95. package/docs/jsgantt.js +5749 -0
  96. package/jsgantt.js +5749 -0
  97. package/package.json +10 -18
  98. package/pw-e2e.config.js +13 -0
  99. package/test-results/.last-run.json +4 -0
  100. package/protractor.conf.js +0 -29
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ /**
3
+ * E2E tests for issue #54: Month view — today line hidden and month header
4
+ * missing when the max date falls on the 1st of a month.
5
+ *
6
+ * Root cause (suspected): getMaxDate() in month format uses:
7
+ * while (vDate.getDate() > 1) vDate.setDate(vDate.getDate() + 1);
8
+ * vDate.setDate(vDate.getDate() - 1);
9
+ * When vDate is already the 1st of a month the while never runs, then
10
+ * setDate(0) rolls back to the last day of the *previous* month — so
11
+ * a task ending August 1 causes vMaxDate = July 31, hiding August.
12
+ *
13
+ * Test cases (no Date mocking needed):
14
+ *
15
+ * 1. "August header" — tasks span Jan–Aug 1 2025.
16
+ * Bug: vMaxDate = July 31 → August column missing.
17
+ * Fix: vMaxDate = August 31 → August column present.
18
+ *
19
+ * 2. "today line" — tasks span Jan 2026 → April 1 2026 (today = April 13 2026).
20
+ * Bug: vMaxDate = March 31 < today (Apr 13) → today line hidden.
21
+ * Fix: vMaxDate = April 30 ≥ today → today line visible.
22
+ */
23
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
24
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
25
+ return new (P || (P = Promise))(function (resolve, reject) {
26
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
27
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
28
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
29
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
30
+ });
31
+ };
32
+ var __generator = (this && this.__generator) || function (thisArg, body) {
33
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
34
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
35
+ function verb(n) { return function (v) { return step([n, v]); }; }
36
+ function step(op) {
37
+ if (f) throw new TypeError("Generator is already executing.");
38
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
39
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
40
+ if (y = 0, t) op = [op[0] & 2, t.value];
41
+ switch (op[0]) {
42
+ case 0: case 1: t = op; break;
43
+ case 4: _.label++; return { value: op[1], done: false };
44
+ case 5: _.label++; y = op[1]; op = [0]; continue;
45
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
46
+ default:
47
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
48
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
49
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
50
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
51
+ if (t[2]) _.ops.pop();
52
+ _.trys.pop(); continue;
53
+ }
54
+ op = body.call(thisArg, _);
55
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
56
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
57
+ }
58
+ };
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ var test_1 = require("@playwright/test");
61
+ // Use the base URL from the environment (or default) and append demo.html.
62
+ // We build the full URL here because DEMO_URL ('demo.html') is a relative path
63
+ // and Playwright resolves it relative to the base URL *without* a trailing
64
+ // slash, which can produce a 404 (e.g. https://host/project → https://host/demo.html).
65
+ function demoUrl() {
66
+ var _a;
67
+ var base = ((_a = process.env.JSGANTT_E2E_BASE_URL) !== null && _a !== void 0 ? _a : 'http://localhost:8080').replace(/\/$/, '');
68
+ return "".concat(base, "/demo.html");
69
+ }
70
+ /** Build a gantt in month format by injecting into the live demo page. */
71
+ function mountMonthGantt(page, startMM, startDD, startYYYY, endMM, endDD, endYYYY) {
72
+ return __awaiter(this, void 0, void 0, function () {
73
+ return __generator(this, function (_a) {
74
+ switch (_a.label) {
75
+ case 0:
76
+ // Ensure the demo page has rendered at least once before we overwrite it
77
+ return [4 /*yield*/, page.waitForSelector('#embedded-Gantt', { timeout: 15000 })];
78
+ case 1:
79
+ // Ensure the demo page has rendered at least once before we overwrite it
80
+ _a.sent();
81
+ return [4 /*yield*/, page.evaluate(function (_a) {
82
+ var startMM = _a.startMM, startDD = _a.startDD, startYYYY = _a.startYYYY, endMM = _a.endMM, endDD = _a.endDD, endYYYY = _a.endYYYY;
83
+ var container = document.getElementById('embedded-Gantt');
84
+ if (!container)
85
+ throw new Error('#embedded-Gantt not found');
86
+ container.innerHTML = '';
87
+ var g = new window['JSGantt'].GanttChart(container, 'month');
88
+ g.setOptions({ vFormat: 'month', vFormatArr: ['Month'] });
89
+ // Default date input format is yyyy-mm-dd
90
+ var pad = function (n) { return String(n).padStart(2, '0'); };
91
+ var fmt = function (y, m, d) { return "".concat(y, "-").concat(pad(m), "-").concat(pad(d)); };
92
+ g.AddTaskItem(new window['JSGantt'].TaskItem(1, 'Task A', fmt(startYYYY, startMM, startDD), fmt(endYYYY, endMM, endDD), '', '', 0, 'Me', 0, 1, 0, 1, '', '', '', g));
93
+ g.Draw();
94
+ }, { startMM: startMM, startDD: startDD, startYYYY: startYYYY, endMM: endMM, endDD: endDD, endYYYY: endYYYY })];
95
+ case 2:
96
+ _a.sent();
97
+ return [4 /*yield*/, page.waitForSelector('#embedded-Gantt .gcharttable', { timeout: 10000 })];
98
+ case 3:
99
+ _a.sent();
100
+ return [4 /*yield*/, page.waitForTimeout(300)];
101
+ case 4:
102
+ _a.sent();
103
+ return [2 /*return*/];
104
+ }
105
+ });
106
+ });
107
+ }
108
+ test_1.test.describe('Issue #54 — Month view: today line and month header', function () {
109
+ test_1.test.beforeEach(function (_a) {
110
+ var page = _a.page;
111
+ return __awaiter(void 0, void 0, void 0, function () {
112
+ return __generator(this, function (_b) {
113
+ switch (_b.label) {
114
+ case 0: return [4 /*yield*/, page.goto(demoUrl(), { waitUntil: 'networkidle', timeout: 25000 })];
115
+ case 1:
116
+ _b.sent();
117
+ return [2 /*return*/];
118
+ }
119
+ });
120
+ });
121
+ });
122
+ (0, test_1.test)('August column header is visible when task ends on Aug 1', function (_a) {
123
+ var page = _a.page;
124
+ return __awaiter(void 0, void 0, void 0, function () {
125
+ var headerTexts;
126
+ return __generator(this, function (_b) {
127
+ switch (_b.label) {
128
+ case 0:
129
+ // Task Jan 1 2025 → Aug 1 2025
130
+ // Bug: vMaxDate rolls back to July 31 → August header missing
131
+ return [4 /*yield*/, mountMonthGantt(page, 1, 1, 2025, 8, 1, 2025)];
132
+ case 1:
133
+ // Task Jan 1 2025 → Aug 1 2025
134
+ // Bug: vMaxDate rolls back to July 31 → August header missing
135
+ _b.sent();
136
+ return [4 /*yield*/, page.evaluate(function () {
137
+ var _a;
138
+ var headerTable = document.querySelector('#embedded-Gantt .gcharttableh');
139
+ if (!headerTable)
140
+ return [];
141
+ var rows = headerTable.querySelectorAll('tr');
142
+ var lastRow = rows[rows.length - 1];
143
+ return Array.from((_a = lastRow === null || lastRow === void 0 ? void 0 : lastRow.querySelectorAll('td')) !== null && _a !== void 0 ? _a : []).map(function (td) { return td.innerText.trim(); });
144
+ })];
145
+ case 2:
146
+ headerTexts = _b.sent();
147
+ (0, test_1.expect)(headerTexts.some(function (t) { return /aug/i.test(t); }), "Expected August in month header, got: ".concat(JSON.stringify(headerTexts))).toBe(true);
148
+ return [2 /*return*/];
149
+ }
150
+ });
151
+ });
152
+ });
153
+ (0, test_1.test)('today line is rendered when task ends on the 1st and today is within that month', function (_a) {
154
+ var page = _a.page;
155
+ return __awaiter(void 0, void 0, void 0, function () {
156
+ var todayLineExists;
157
+ return __generator(this, function (_b) {
158
+ switch (_b.label) {
159
+ case 0:
160
+ // Today = 2026-04-13. Task ends April 1 2026.
161
+ // Bug: vMaxDate = March 31, 2026 < today (Apr 13) → today line hidden
162
+ // Fix: vMaxDate = April 30, 2026 ≥ today → today line visible
163
+ return [4 /*yield*/, mountMonthGantt(page, 1, 1, 2026, 4, 1, 2026)];
164
+ case 1:
165
+ // Today = 2026-04-13. Task ends April 1 2026.
166
+ // Bug: vMaxDate = March 31, 2026 < today (Apr 13) → today line hidden
167
+ // Fix: vMaxDate = April 30, 2026 ≥ today → today line visible
168
+ _b.sent();
169
+ return [4 /*yield*/, page.evaluate(function () {
170
+ return document.querySelector('#embedded-Gantt .gCurDate') !== null;
171
+ })];
172
+ case 2:
173
+ todayLineExists = _b.sent();
174
+ (0, test_1.expect)(todayLineExists, 'Today line (.gCurDate) should be rendered').toBe(true);
175
+ return [2 /*return*/];
176
+ }
177
+ });
178
+ });
179
+ });
180
+ });
181
+ //# sourceMappingURL=issue54-month-today.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue54-month-today.spec.js","sourceRoot":"","sources":["../../../test/e2e/issue54-month-today.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ "use strict";
2
+ /**
3
+ * E2E tests for issue #68: configurable working days.
4
+ *
5
+ * Verifies that setWorkingDays() causes getDuration() to count only
6
+ * working days, and that the default (all days working) is unchanged.
7
+ *
8
+ * Test chart: day format, one task Mon 2025-01-06 → Mon 2025-01-13.
9
+ *
10
+ * Date arithmetic note: '2025-01-13' parses to local midnight, which always
11
+ * satisfies the getDuration midnight-check, so vTaskEnd is shifted +1 day to
12
+ * Jan 14. The effective span is therefore Jan 6 → Jan 14 (8 calendar days).
13
+ * Calendar span (Jan 6–13): 8 days
14
+ * Working days Mon–Fri (Jan 6–13): Mon 6,Tue 7,Wed 8,Thu 9,Fri 10,Mon 13 = 6 days
15
+ * Working days Mon–Sat: add Sat 11 = 7 days
16
+ */
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ var __generator = (this && this.__generator) || function (thisArg, body) {
27
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
+ function verb(n) { return function (v) { return step([n, v]); }; }
30
+ function step(op) {
31
+ if (f) throw new TypeError("Generator is already executing.");
32
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
+ if (y = 0, t) op = [op[0] & 2, t.value];
35
+ switch (op[0]) {
36
+ case 0: case 1: t = op; break;
37
+ case 4: _.label++; return { value: op[1], done: false };
38
+ case 5: _.label++; y = op[1]; op = [0]; continue;
39
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
+ default:
41
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
+ if (t[2]) _.ops.pop();
46
+ _.trys.pop(); continue;
47
+ }
48
+ op = body.call(thisArg, _);
49
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
+ }
52
+ };
53
+ var _a;
54
+ Object.defineProperty(exports, "__esModule", { value: true });
55
+ var test_1 = require("@playwright/test");
56
+ var BASE = ((_a = process.env.JSGANTT_E2E_BASE_URL) !== null && _a !== void 0 ? _a : 'http://localhost:8080').replace(/\/$/, '');
57
+ var DEMO_URL = "".concat(BASE, "/demo.html");
58
+ /** Wait for JSGantt global and navigate to demo page. */
59
+ function gotoDemo(page) {
60
+ return __awaiter(this, void 0, void 0, function () {
61
+ return __generator(this, function (_a) {
62
+ switch (_a.label) {
63
+ case 0: return [4 /*yield*/, page.goto(DEMO_URL, { waitUntil: 'load', timeout: 25000 })];
64
+ case 1:
65
+ _a.sent();
66
+ return [4 /*yield*/, page.waitForFunction(function () { return typeof window.JSGantt !== 'undefined'; }, { timeout: 15000 })];
67
+ case 2:
68
+ _a.sent();
69
+ return [2 /*return*/];
70
+ }
71
+ });
72
+ });
73
+ }
74
+ /**
75
+ * Inject a day-format Gantt with one task (Mon Jan 6 → Mon Jan 13 2025) into
76
+ * #embedded-Gantt with optional working-days configuration.
77
+ *
78
+ * @param workingDays If supplied, passed to g.setWorkingDays(). Null = default (all days).
79
+ */
80
+ function mountDayGantt(page, workingDays) {
81
+ if (workingDays === void 0) { workingDays = null; }
82
+ return __awaiter(this, void 0, void 0, function () {
83
+ return __generator(this, function (_a) {
84
+ switch (_a.label) {
85
+ case 0: return [4 /*yield*/, page.evaluate(function (wd) {
86
+ var container = document.getElementById('embedded-Gantt');
87
+ if (!container)
88
+ throw new Error('#embedded-Gantt not found');
89
+ container.innerHTML = '';
90
+ var g = new window.JSGantt.GanttChart(container, 'day');
91
+ g.setOptions({ vFormat: 'day', vFormatArr: ['Day'], vShowDur: 1 });
92
+ if (wd)
93
+ g.setWorkingDays(wd);
94
+ g.AddTaskItem(new window.JSGantt.TaskItem(1, 'Task A', '2025-01-06', // Monday
95
+ '2025-01-13', // Monday (midnight → effective end = Tue Jan 14 for duration calc)
96
+ 'gtaskblue', '', 0, 'Me', 0, 0, 0, 1, '', '', '', g));
97
+ g.Draw();
98
+ }, workingDays)];
99
+ case 1:
100
+ _a.sent();
101
+ return [4 /*yield*/, page.waitForSelector('#embedded-Gantt .gcharttable', { timeout: 10000 })];
102
+ case 2:
103
+ _a.sent();
104
+ return [4 /*yield*/, page.waitForTimeout(300)];
105
+ case 3:
106
+ _a.sent();
107
+ return [2 /*return*/];
108
+ }
109
+ });
110
+ });
111
+ }
112
+ /** Read the text of the first .gduration cell. */
113
+ function getDurationText(page) {
114
+ return __awaiter(this, void 0, void 0, function () {
115
+ return __generator(this, function (_a) {
116
+ return [2 /*return*/, page.evaluate(function () {
117
+ var cell = document.querySelector('#embedded-Gantt .gduration div');
118
+ return cell ? cell.innerText.trim() : '';
119
+ })];
120
+ });
121
+ });
122
+ }
123
+ /** Read the pixel width of the first task bar. */
124
+ function getBarWidth(page) {
125
+ return __awaiter(this, void 0, void 0, function () {
126
+ return __generator(this, function (_a) {
127
+ return [2 /*return*/, page.evaluate(function () {
128
+ var bar = document.querySelector('[id*="bardiv_"]');
129
+ return bar ? parseInt(bar.style.width || '0', 10) : 0;
130
+ })];
131
+ });
132
+ });
133
+ }
134
+ test_1.test.describe('Issue #68 — working days duration', function () {
135
+ test_1.test.beforeEach(function (_a) {
136
+ var page = _a.page;
137
+ return __awaiter(void 0, void 0, void 0, function () {
138
+ return __generator(this, function (_b) {
139
+ switch (_b.label) {
140
+ case 0: return [4 /*yield*/, gotoDemo(page)];
141
+ case 1:
142
+ _b.sent();
143
+ return [2 /*return*/];
144
+ }
145
+ });
146
+ });
147
+ });
148
+ (0, test_1.test)('default: all-days chart shows 8 calendar days', function (_a) {
149
+ var page = _a.page;
150
+ return __awaiter(void 0, void 0, void 0, function () {
151
+ var dur;
152
+ return __generator(this, function (_b) {
153
+ switch (_b.label) {
154
+ case 0: return [4 /*yield*/, mountDayGantt(page, null)];
155
+ case 1:
156
+ _b.sent();
157
+ return [4 /*yield*/, getDurationText(page)];
158
+ case 2:
159
+ dur = _b.sent();
160
+ // Effective span Jan 6 → Jan 14 = 8 calendar days (midnight +1 day adjustment)
161
+ (0, test_1.expect)(parseInt(dur), "Expected 8 days, got \"".concat(dur, "\"")).toBe(8);
162
+ return [2 /*return*/];
163
+ }
164
+ });
165
+ });
166
+ });
167
+ (0, test_1.test)('setWorkingDays Mon–Fri: duration shows 6 working days', function (_a) {
168
+ var page = _a.page;
169
+ return __awaiter(void 0, void 0, void 0, function () {
170
+ var dur;
171
+ return __generator(this, function (_b) {
172
+ switch (_b.label) {
173
+ case 0: return [4 /*yield*/, mountDayGantt(page, { 0: false, 1: true, 2: true, 3: true, 4: true, 5: true, 6: false })];
174
+ case 1:
175
+ _b.sent();
176
+ return [4 /*yield*/, getDurationText(page)];
177
+ case 2:
178
+ dur = _b.sent();
179
+ // Mon 6, Tue 7, Wed 8, Thu 9, Fri 10, Mon 13 = 6 working days
180
+ (0, test_1.expect)(parseInt(dur), "Expected 6 working days, got \"".concat(dur, "\"")).toBe(6);
181
+ return [2 /*return*/];
182
+ }
183
+ });
184
+ });
185
+ });
186
+ (0, test_1.test)('setWorkingDays Mon–Sat: duration shows 7 working days', function (_a) {
187
+ var page = _a.page;
188
+ return __awaiter(void 0, void 0, void 0, function () {
189
+ var dur;
190
+ return __generator(this, function (_b) {
191
+ switch (_b.label) {
192
+ case 0: return [4 /*yield*/, mountDayGantt(page, { 0: false, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true })];
193
+ case 1:
194
+ _b.sent();
195
+ return [4 /*yield*/, getDurationText(page)];
196
+ case 2:
197
+ dur = _b.sent();
198
+ // Mon 6, Tue 7, Wed 8, Thu 9, Fri 10, Sat 11, Mon 13 = 7 working days
199
+ (0, test_1.expect)(parseInt(dur), "Expected 7 working days, got \"".concat(dur, "\"")).toBe(7);
200
+ return [2 /*return*/];
201
+ }
202
+ });
203
+ });
204
+ });
205
+ (0, test_1.test)('all-true vWorkingDays gives same duration as default', function (_a) {
206
+ var page = _a.page;
207
+ return __awaiter(void 0, void 0, void 0, function () {
208
+ var defaultDur, allTrueDur;
209
+ return __generator(this, function (_b) {
210
+ switch (_b.label) {
211
+ case 0: return [4 /*yield*/, mountDayGantt(page, null)];
212
+ case 1:
213
+ _b.sent();
214
+ return [4 /*yield*/, getDurationText(page)];
215
+ case 2:
216
+ defaultDur = _b.sent();
217
+ // Re-mount with explicit all-true working days
218
+ return [4 /*yield*/, page.evaluate(function () {
219
+ var container = document.getElementById('embedded-Gantt');
220
+ container.innerHTML = '';
221
+ var g = new window.JSGantt.GanttChart(container, 'day');
222
+ g.setOptions({ vFormat: 'day', vFormatArr: ['Day'], vShowDur: 1 });
223
+ g.setWorkingDays({ 0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true });
224
+ g.AddTaskItem(new window.JSGantt.TaskItem(1, 'Task A', '2025-01-06', '2025-01-13', 'gtaskblue', '', 0, 'Me', 0, 0, 0, 1, '', '', '', g));
225
+ g.Draw();
226
+ })];
227
+ case 3:
228
+ // Re-mount with explicit all-true working days
229
+ _b.sent();
230
+ return [4 /*yield*/, page.waitForTimeout(300)];
231
+ case 4:
232
+ _b.sent();
233
+ return [4 /*yield*/, getDurationText(page)];
234
+ case 5:
235
+ allTrueDur = _b.sent();
236
+ (0, test_1.expect)(parseInt(allTrueDur), "all-true working days (".concat(allTrueDur, ") should equal default (").concat(defaultDur, ")")).toBe(parseInt(defaultDur));
237
+ return [2 /*return*/];
238
+ }
239
+ });
240
+ });
241
+ });
242
+ });
243
+ //# sourceMappingURL=issue68-working-days.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue68-working-days.spec.js","sourceRoot":"","sources":["../../../test/e2e/issue68-working-days.spec.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,yCAAgD;AAEhD,IAAM,IAAI,GAAG,CAAC,MAAA,OAAO,CAAC,GAAG,CAAC,oBAAoB,mCAAI,uBAAuB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC9F,IAAM,QAAQ,GAAG,UAAG,IAAI,eAAY,CAAC;AAErC,yDAAyD;AACzD,SAAe,QAAQ,CAAC,IAAI;;;;wBAC1B,qBAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,KAAM,EAAE,CAAC,EAAA;;oBAAjE,SAAiE,CAAC;oBAClE,qBAAM,IAAI,CAAC,eAAe,CAAC,cAAM,OAAA,OAAQ,MAAc,CAAC,OAAO,KAAK,WAAW,EAA9C,CAA8C,EAAE,EAAE,OAAO,EAAE,KAAM,EAAE,CAAC,EAAA;;oBAArG,SAAqG,CAAC;;;;;CACvG;AAED;;;;;GAKG;AACH,SAAe,aAAa,CAAC,IAAI,EAAE,WAAkD;IAAlD,4BAAA,EAAA,kBAAkD;;;;wBACnF,qBAAM,IAAI,CAAC,QAAQ,CAAC,UAAC,EAAE;wBACrB,IAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;wBAC5D,IAAI,CAAC,SAAS;4BAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;wBAC7D,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;wBAEzB,IAAM,CAAC,GAAG,IAAK,MAAc,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;wBACnE,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;wBAEnE,IAAI,EAAE;4BAAE,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;wBAE7B,CAAC,CAAC,WAAW,CAAC,IAAK,MAAc,CAAC,OAAO,CAAC,QAAQ,CAChD,CAAC,EAAE,QAAQ,EACX,YAAY,EAAG,SAAS;wBACxB,YAAY,EAAG,mEAAmE;wBAClF,WAAW,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CACpD,CAAC,CAAC;wBAEH,CAAC,CAAC,IAAI,EAAE,CAAC;oBACX,CAAC,EAAE,WAAW,CAAC,EAAA;;oBAlBf,SAkBe,CAAC;oBAEhB,qBAAM,IAAI,CAAC,eAAe,CAAC,8BAA8B,EAAE,EAAE,OAAO,EAAE,KAAM,EAAE,CAAC,EAAA;;oBAA/E,SAA+E,CAAC;oBAChF,qBAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAA;;oBAA9B,SAA8B,CAAC;;;;;CAChC;AAED,kDAAkD;AAClD,SAAe,eAAe,CAAC,IAAI;;;YACjC,sBAAO,IAAI,CAAC,QAAQ,CAAC;oBACnB,IAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,gCAAgC,CAAuB,CAAC;oBAC5F,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3C,CAAC,CAAC,EAAC;;;CACJ;AAED,kDAAkD;AAClD,SAAe,WAAW,CAAC,IAAI;;;YAC7B,sBAAO,IAAI,CAAC,QAAQ,CAAC;oBACnB,IAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,iBAAiB,CAAuB,CAAC;oBAC5E,OAAO,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxD,CAAC,CAAC,EAAC;;;CACJ;AAED,WAAI,CAAC,QAAQ,CAAC,mCAAmC,EAAE;IAEjD,WAAI,CAAC,UAAU,CAAC,UAAO,EAAQ;YAAN,IAAI,UAAA;;;;4BAC3B,qBAAM,QAAQ,CAAC,IAAI,CAAC,EAAA;;wBAApB,SAAoB,CAAC;;;;;KACtB,CAAC,CAAC;IAEH,IAAA,WAAI,EAAC,+CAA+C,EAAE,UAAO,EAAQ;YAAN,IAAI,UAAA;;;;;4BACjE,qBAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,EAAA;;wBAA/B,SAA+B,CAAC;wBAEpB,qBAAM,eAAe,CAAC,IAAI,CAAC,EAAA;;wBAAjC,GAAG,GAAG,SAA2B;wBACvC,+EAA+E;wBAC/E,IAAA,aAAM,EAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,iCAAyB,GAAG,OAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;;;;KAChE,CAAC,CAAC;IAEH,IAAA,WAAI,EAAC,uDAAuD,EAAE,UAAO,EAAQ;YAAN,IAAI,UAAA;;;;;4BACzE,qBAAM,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAA;;wBAA9F,SAA8F,CAAC;wBAEnF,qBAAM,eAAe,CAAC,IAAI,CAAC,EAAA;;wBAAjC,GAAG,GAAG,SAA2B;wBACvC,8DAA8D;wBAC9D,IAAA,aAAM,EAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,yCAAiC,GAAG,OAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;;;;KACxE,CAAC,CAAC;IAEH,IAAA,WAAI,EAAC,uDAAuD,EAAE,UAAO,EAAQ;YAAN,IAAI,UAAA;;;;;4BACzE,qBAAM,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAA;;wBAA7F,SAA6F,CAAC;wBAElF,qBAAM,eAAe,CAAC,IAAI,CAAC,EAAA;;wBAAjC,GAAG,GAAG,SAA2B;wBACvC,sEAAsE;wBACtE,IAAA,aAAM,EAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,yCAAiC,GAAG,OAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;;;;KACxE,CAAC,CAAC;IAEH,IAAA,WAAI,EAAC,sDAAsD,EAAE,UAAO,EAAQ;YAAN,IAAI,UAAA;;;;;4BACxE,qBAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,EAAA;;wBAA/B,SAA+B,CAAC;wBACb,qBAAM,eAAe,CAAC,IAAI,CAAC,EAAA;;wBAAxC,UAAU,GAAG,SAA2B;wBAE9C,+CAA+C;wBAC/C,qBAAM,IAAI,CAAC,QAAQ,CAAC;gCAClB,IAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,gBAAgB,CAAE,CAAC;gCAC7D,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;gCACzB,IAAM,CAAC,GAAG,IAAK,MAAc,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;gCACnE,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;gCACnE,CAAC,CAAC,cAAc,CAAC,EAAE,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,IAAI,EAAE,CAAC,CAAC;gCACvE,CAAC,CAAC,WAAW,CAAC,IAAK,MAAc,CAAC,OAAO,CAAC,QAAQ,CAChD,CAAC,EAAC,QAAQ,EAAC,YAAY,EAAC,YAAY,EAAC,WAAW,EAAC,EAAE,EAAC,CAAC,EAAC,IAAI,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,EAAE,EAAC,EAAE,EAAC,EAAE,EAAC,CAAC,CAC9E,CAAC,CAAC;gCACH,CAAC,CAAC,IAAI,EAAE,CAAC;4BACX,CAAC,CAAC,EAAA;;wBAXF,+CAA+C;wBAC/C,SAUE,CAAC;wBACH,qBAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAA;;wBAA9B,SAA8B,CAAC;wBAEZ,qBAAM,eAAe,CAAC,IAAI,CAAC,EAAA;;wBAAxC,UAAU,GAAG,SAA2B;wBAC9C,IAAA,aAAM,EAAC,QAAQ,CAAC,UAAU,CAAC,EACzB,iCAA0B,UAAU,qCAA2B,UAAU,MAAG,CAC7E,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;;;;;KAC9B,CAAC,CAAC;AAEL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /**
3
+ * E2E tests for issue #23: bar misalignment at non-100% browser zoom.
4
+ *
5
+ * Root cause: table-layout:auto gives columns fractional pixel widths at
6
+ * non-100% zoom. As columns accumulate, bars drift away from their date.
7
+ *
8
+ * Fix: table-layout:fixed + explicit JS cell widths (already applied).
9
+ *
10
+ * Test strategy:
11
+ * - Apply CSS zoom to #embedded-Gantt (equivalent to browser-level zoom)
12
+ * - At each zoom level, assert bars scale proportionally with zoom
13
+ * (viewportLeft ≈ styleLeft × zoom ± tolerance)
14
+ * - Assert column widths are uniform within each zoom level
15
+ * (no fractional-px spread from table-layout:auto)
16
+ */
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ var __generator = (this && this.__generator) || function (thisArg, body) {
27
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
28
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
29
+ function verb(n) { return function (v) { return step([n, v]); }; }
30
+ function step(op) {
31
+ if (f) throw new TypeError("Generator is already executing.");
32
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
33
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
34
+ if (y = 0, t) op = [op[0] & 2, t.value];
35
+ switch (op[0]) {
36
+ case 0: case 1: t = op; break;
37
+ case 4: _.label++; return { value: op[1], done: false };
38
+ case 5: _.label++; y = op[1]; op = [0]; continue;
39
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
40
+ default:
41
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
42
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
43
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
44
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
45
+ if (t[2]) _.ops.pop();
46
+ _.trys.pop(); continue;
47
+ }
48
+ op = body.call(thisArg, _);
49
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
50
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
51
+ }
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ var test_1 = require("@playwright/test");
55
+ var gantt_page_1 = require("./gantt.page");
56
+ var ZOOM_LEVELS = [0.75, 0.8, 1.0, 1.25, 1.5];
57
+ /** Maximum allowed drift between expected and actual bar position (px). */
58
+ var DRIFT_TOLERANCE_PX = 3;
59
+ /** Maximum allowed spread between widest and narrowest column at the same zoom (px). */
60
+ var COL_SPREAD_TOLERANCE_PX = 1;
61
+ test_1.test.describe('Issue #23 — bar alignment at non-100% zoom', function () {
62
+ var _loop_1 = function (zoom) {
63
+ var label = "".concat(Math.round(zoom * 100), "%");
64
+ (0, test_1.test)("bars are correctly aligned at ".concat(label, " zoom"), function (_a) {
65
+ var page = _a.page;
66
+ return __awaiter(void 0, void 0, void 0, function () {
67
+ var gantt, bars, _i, bars_1, bar, expectedLeft, drift;
68
+ return __generator(this, function (_b) {
69
+ switch (_b.label) {
70
+ case 0:
71
+ gantt = new gantt_page_1.GanttPage(page);
72
+ return [4 /*yield*/, gantt.goto(gantt_page_1.DEMO_URL)];
73
+ case 1:
74
+ _b.sent();
75
+ return [4 /*yield*/, gantt.applyZoom(zoom)];
76
+ case 2:
77
+ _b.sent();
78
+ return [4 /*yield*/, gantt.getBarMetrics(8)];
79
+ case 3:
80
+ bars = _b.sent();
81
+ (0, test_1.expect)(bars.length, 'should find rendered task bars').toBeGreaterThan(0);
82
+ for (_i = 0, bars_1 = bars; _i < bars_1.length; _i++) {
83
+ bar = bars_1[_i];
84
+ expectedLeft = bar.styleLeft * zoom;
85
+ drift = Math.abs(bar.viewportLeft - expectedLeft);
86
+ (0, test_1.expect)(drift, "".concat(bar.id, " at zoom ").concat(label, ": viewportLeft=").concat(bar.viewportLeft, " expected\u2248").concat(expectedLeft.toFixed(1))).toBeLessThanOrEqual(DRIFT_TOLERANCE_PX);
87
+ }
88
+ return [2 /*return*/];
89
+ }
90
+ });
91
+ });
92
+ });
93
+ (0, test_1.test)("column widths are uniform at ".concat(label, " zoom"), function (_a) {
94
+ var page = _a.page;
95
+ return __awaiter(void 0, void 0, void 0, function () {
96
+ var gantt, baseCols, baseColWidth, cols, widths, spread, expectedWidth, avgWidth;
97
+ var _b, _c;
98
+ return __generator(this, function (_d) {
99
+ switch (_d.label) {
100
+ case 0:
101
+ gantt = new gantt_page_1.GanttPage(page);
102
+ return [4 /*yield*/, gantt.goto(gantt_page_1.DEMO_URL)];
103
+ case 1:
104
+ _d.sent();
105
+ return [4 /*yield*/, gantt.getColumnMetrics(5)];
106
+ case 2:
107
+ baseCols = _d.sent();
108
+ baseColWidth = (_c = (_b = baseCols[0]) === null || _b === void 0 ? void 0 : _b.viewportWidth) !== null && _c !== void 0 ? _c : 39;
109
+ return [4 /*yield*/, gantt.applyZoom(zoom)];
110
+ case 3:
111
+ _d.sent();
112
+ return [4 /*yield*/, gantt.getColumnMetrics(20)];
113
+ case 4:
114
+ cols = _d.sent();
115
+ (0, test_1.expect)(cols.length, 'should find header columns').toBeGreaterThan(0);
116
+ widths = cols.map(function (c) { return c.viewportWidth; });
117
+ spread = Math.max.apply(Math, widths) - Math.min.apply(Math, widths);
118
+ (0, test_1.expect)(spread, "column width spread at ".concat(label, " zoom (min=").concat(Math.min.apply(Math, widths).toFixed(2), " max=").concat(Math.max.apply(Math, widths).toFixed(2), ")")).toBeLessThanOrEqual(COL_SPREAD_TOLERANCE_PX);
119
+ expectedWidth = baseColWidth * zoom;
120
+ avgWidth = widths.reduce(function (a, b) { return a + b; }, 0) / widths.length;
121
+ (0, test_1.expect)(Math.abs(avgWidth - expectedWidth), "avg col width ".concat(avgWidth.toFixed(2), " should be \u2248 baseCol(").concat(baseColWidth, ") \u00D7 zoom(").concat(zoom, ") = ").concat(expectedWidth.toFixed(2))).toBeLessThanOrEqual(1);
122
+ return [2 /*return*/];
123
+ }
124
+ });
125
+ });
126
+ });
127
+ };
128
+ for (var _i = 0, ZOOM_LEVELS_1 = ZOOM_LEVELS; _i < ZOOM_LEVELS_1.length; _i++) {
129
+ var zoom = ZOOM_LEVELS_1[_i];
130
+ _loop_1(zoom);
131
+ }
132
+ });
133
+ //# sourceMappingURL=zoom-alignment.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoom-alignment.spec.js","sourceRoot":"","sources":["../../../test/e2e/zoom-alignment.spec.ts"],"names":[],"mappings":"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"}
@@ -2,14 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  var JSGantt = require("../index");
4
4
  var chai_1 = require("chai");
5
- var protractor_1 = require("protractor");
6
- var dv = protractor_1.browser.driver;
7
- describe('Browser test', function () {
8
- it('JSGantt exists', function () {
9
- chai_1.expect(JSGantt).to.exist;
10
- });
11
- it('Driver exists', function () {
12
- chai_1.expect(dv).to.exist;
5
+ describe('Initial test', function () {
6
+ it('Import', function () {
7
+ (0, chai_1.expect)(JSGantt).to.exist;
13
8
  });
14
9
  });
15
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../test/index.ts"],"names":[],"mappings":";;AACA,kCAAoC;AACpC,6BAA8B;AAC9B,yCAAkD;AAElD,IAAM,EAAE,GAAG,oBAAO,CAAC,MAAM,CAAC;AAE1B,QAAQ,CAAC,cAAc,EAAE;IACvB,EAAE,CAAC,gBAAgB,EAAE;QACnB,aAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,eAAe,EAAE;QAClB,aAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../test/index.ts"],"names":[],"mappings":";;AACA,kCAAoC;AACpC,6BAA8B;AAE9B,QAAQ,CAAC,cAAc,EAAE;IACvB,EAAE,CAAC,QAAQ,EAAE;QACX,IAAA,aAAM,EAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}