@livetemplate/client 0.4.0 → 0.4.1
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.
- package/dist/tests/directives.test.d.ts +2 -0
- package/dist/tests/directives.test.d.ts.map +1 -0
- package/dist/tests/directives.test.js +208 -0
- package/dist/tests/directives.test.js.map +1 -0
- package/dist/tests/loading-indicator.test.d.ts +2 -0
- package/dist/tests/loading-indicator.test.d.ts.map +1 -0
- package/dist/tests/loading-indicator.test.js +60 -0
- package/dist/tests/loading-indicator.test.js.map +1 -0
- package/dist/tests/logger.test.d.ts +2 -0
- package/dist/tests/logger.test.d.ts.map +1 -0
- package/dist/tests/logger.test.js +201 -0
- package/dist/tests/logger.test.js.map +1 -0
- package/dist/tests/observer-manager.test.d.ts +2 -0
- package/dist/tests/observer-manager.test.d.ts.map +1 -0
- package/dist/tests/observer-manager.test.js +192 -0
- package/dist/tests/observer-manager.test.js.map +1 -0
- package/dist/tests/s3-uploader.test.d.ts +2 -0
- package/dist/tests/s3-uploader.test.d.ts.map +1 -0
- package/dist/tests/s3-uploader.test.js +141 -0
- package/dist/tests/s3-uploader.test.js.map +1 -0
- package/dist/tests/upload-handler.test.d.ts +2 -0
- package/dist/tests/upload-handler.test.d.ts.map +1 -0
- package/dist/tests/upload-handler.test.js +365 -0
- package/dist/tests/upload-handler.test.js.map +1 -0
- package/dist/tests/websocket.test.d.ts +2 -0
- package/dist/tests/websocket.test.d.ts.map +1 -0
- package/dist/tests/websocket.test.js +379 -0
- package/dist/tests/websocket.test.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const observer_manager_1 = require("../dom/observer-manager");
|
|
4
|
+
const logger_1 = require("../utils/logger");
|
|
5
|
+
// Mock IntersectionObserver
|
|
6
|
+
class MockIntersectionObserver {
|
|
7
|
+
constructor(callback, options) {
|
|
8
|
+
this.elements = [];
|
|
9
|
+
this.callback = callback;
|
|
10
|
+
this.options = options;
|
|
11
|
+
}
|
|
12
|
+
observe(element) {
|
|
13
|
+
this.elements.push(element);
|
|
14
|
+
}
|
|
15
|
+
unobserve(element) {
|
|
16
|
+
this.elements = this.elements.filter((e) => e !== element);
|
|
17
|
+
}
|
|
18
|
+
disconnect() {
|
|
19
|
+
this.elements = [];
|
|
20
|
+
}
|
|
21
|
+
// Helper to trigger intersection
|
|
22
|
+
triggerIntersection(isIntersecting) {
|
|
23
|
+
const entries = this.elements.map((target) => ({
|
|
24
|
+
target,
|
|
25
|
+
isIntersecting,
|
|
26
|
+
boundingClientRect: {},
|
|
27
|
+
intersectionRatio: isIntersecting ? 1 : 0,
|
|
28
|
+
intersectionRect: {},
|
|
29
|
+
rootBounds: null,
|
|
30
|
+
time: Date.now(),
|
|
31
|
+
}));
|
|
32
|
+
this.callback(entries, this);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
global.IntersectionObserver = MockIntersectionObserver;
|
|
36
|
+
describe("ObserverManager", () => {
|
|
37
|
+
let mockContext;
|
|
38
|
+
let mockSend;
|
|
39
|
+
let manager;
|
|
40
|
+
let mockLogger;
|
|
41
|
+
let mockConsole;
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
document.body.innerHTML = "";
|
|
44
|
+
mockSend = jest.fn();
|
|
45
|
+
mockConsole = {
|
|
46
|
+
debug: jest.fn(),
|
|
47
|
+
info: jest.fn(),
|
|
48
|
+
warn: jest.fn(),
|
|
49
|
+
error: jest.fn(),
|
|
50
|
+
};
|
|
51
|
+
mockLogger = (0, logger_1.createLogger)({
|
|
52
|
+
level: "debug",
|
|
53
|
+
sink: mockConsole,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
if (manager) {
|
|
58
|
+
manager.teardown();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
describe("setupInfiniteScrollObserver", () => {
|
|
62
|
+
it("does nothing if wrapper element is null", () => {
|
|
63
|
+
mockContext = {
|
|
64
|
+
getWrapperElement: () => null,
|
|
65
|
+
send: mockSend,
|
|
66
|
+
};
|
|
67
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
68
|
+
manager.setupInfiniteScrollObserver();
|
|
69
|
+
// Should not throw and should not call send
|
|
70
|
+
expect(mockSend).not.toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
it("does nothing if scroll-sentinel element is not found", () => {
|
|
73
|
+
document.body.innerHTML = "<div id='wrapper'></div>";
|
|
74
|
+
mockContext = {
|
|
75
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
76
|
+
send: mockSend,
|
|
77
|
+
};
|
|
78
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
79
|
+
manager.setupInfiniteScrollObserver();
|
|
80
|
+
expect(mockSend).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
it("sets up IntersectionObserver when sentinel exists", () => {
|
|
83
|
+
document.body.innerHTML = `
|
|
84
|
+
<div id="wrapper">
|
|
85
|
+
<div id="scroll-sentinel"></div>
|
|
86
|
+
</div>
|
|
87
|
+
`;
|
|
88
|
+
mockContext = {
|
|
89
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
90
|
+
send: mockSend,
|
|
91
|
+
};
|
|
92
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
93
|
+
manager.setupInfiniteScrollObserver();
|
|
94
|
+
expect(mockConsole.debug).toHaveBeenCalledWith(expect.any(String), "Observer set up successfully");
|
|
95
|
+
});
|
|
96
|
+
it("disconnects previous observer before setting up new one", () => {
|
|
97
|
+
document.body.innerHTML = `
|
|
98
|
+
<div id="wrapper">
|
|
99
|
+
<div id="scroll-sentinel"></div>
|
|
100
|
+
</div>
|
|
101
|
+
`;
|
|
102
|
+
mockContext = {
|
|
103
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
104
|
+
send: mockSend,
|
|
105
|
+
};
|
|
106
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
107
|
+
manager.setupInfiniteScrollObserver();
|
|
108
|
+
manager.setupInfiniteScrollObserver();
|
|
109
|
+
// Should have logged setup twice (once per call)
|
|
110
|
+
const setupCalls = mockConsole.debug.mock.calls.filter((call) => call[1] === "Observer set up successfully");
|
|
111
|
+
expect(setupCalls.length).toBe(2);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe("setupInfiniteScrollMutationObserver", () => {
|
|
115
|
+
it("does nothing if wrapper element is null", () => {
|
|
116
|
+
mockContext = {
|
|
117
|
+
getWrapperElement: () => null,
|
|
118
|
+
send: mockSend,
|
|
119
|
+
};
|
|
120
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
121
|
+
manager.setupInfiniteScrollMutationObserver();
|
|
122
|
+
// Should not log setup message since wrapper is null
|
|
123
|
+
const mutationSetupCalls = mockConsole.debug.mock.calls.filter((call) => call[1] === "MutationObserver set up successfully");
|
|
124
|
+
expect(mutationSetupCalls.length).toBe(0);
|
|
125
|
+
});
|
|
126
|
+
it("sets up MutationObserver when wrapper exists", () => {
|
|
127
|
+
document.body.innerHTML = "<div id='wrapper'></div>";
|
|
128
|
+
mockContext = {
|
|
129
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
130
|
+
send: mockSend,
|
|
131
|
+
};
|
|
132
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
133
|
+
manager.setupInfiniteScrollMutationObserver();
|
|
134
|
+
expect(mockConsole.debug).toHaveBeenCalledWith(expect.any(String), "MutationObserver set up successfully");
|
|
135
|
+
});
|
|
136
|
+
it("disconnects previous mutation observer before setting up new one", () => {
|
|
137
|
+
document.body.innerHTML = "<div id='wrapper'></div>";
|
|
138
|
+
mockContext = {
|
|
139
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
140
|
+
send: mockSend,
|
|
141
|
+
};
|
|
142
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
143
|
+
manager.setupInfiniteScrollMutationObserver();
|
|
144
|
+
manager.setupInfiniteScrollMutationObserver();
|
|
145
|
+
const mutationSetupCalls = mockConsole.debug.mock.calls.filter((call) => call[1] === "MutationObserver set up successfully");
|
|
146
|
+
expect(mutationSetupCalls.length).toBe(2);
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
describe("teardown", () => {
|
|
150
|
+
it("disconnects all observers", () => {
|
|
151
|
+
document.body.innerHTML = `
|
|
152
|
+
<div id="wrapper">
|
|
153
|
+
<div id="scroll-sentinel"></div>
|
|
154
|
+
</div>
|
|
155
|
+
`;
|
|
156
|
+
mockContext = {
|
|
157
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
158
|
+
send: mockSend,
|
|
159
|
+
};
|
|
160
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
161
|
+
manager.setupInfiniteScrollObserver();
|
|
162
|
+
manager.setupInfiniteScrollMutationObserver();
|
|
163
|
+
// Should not throw
|
|
164
|
+
expect(() => manager.teardown()).not.toThrow();
|
|
165
|
+
});
|
|
166
|
+
it("is safe to call when no observers are set up", () => {
|
|
167
|
+
mockContext = {
|
|
168
|
+
getWrapperElement: () => null,
|
|
169
|
+
send: mockSend,
|
|
170
|
+
};
|
|
171
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
172
|
+
expect(() => manager.teardown()).not.toThrow();
|
|
173
|
+
});
|
|
174
|
+
it("is safe to call multiple times", () => {
|
|
175
|
+
document.body.innerHTML = `
|
|
176
|
+
<div id="wrapper">
|
|
177
|
+
<div id="scroll-sentinel"></div>
|
|
178
|
+
</div>
|
|
179
|
+
`;
|
|
180
|
+
mockContext = {
|
|
181
|
+
getWrapperElement: () => document.getElementById("wrapper"),
|
|
182
|
+
send: mockSend,
|
|
183
|
+
};
|
|
184
|
+
manager = new observer_manager_1.ObserverManager(mockContext, mockLogger);
|
|
185
|
+
manager.setupInfiniteScrollObserver();
|
|
186
|
+
manager.teardown();
|
|
187
|
+
manager.teardown();
|
|
188
|
+
expect(() => manager.teardown()).not.toThrow();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
//# sourceMappingURL=observer-manager.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observer-manager.test.js","sourceRoot":"","sources":["../../tests/observer-manager.test.ts"],"names":[],"mappings":";;AAAA,8DAA2E;AAC3E,4CAA+C;AAE/C,4BAA4B;AAC5B,MAAM,wBAAwB;IAK5B,YAAY,QAAsC,EAAE,OAAkC;QAFtF,aAAQ,GAAc,EAAE,CAAC;QAGvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,OAAgB;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,SAAS,CAAC,OAAgB;QACxB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;IAC7D,CAAC;IAED,UAAU;QACR,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;IAED,iCAAiC;IACjC,mBAAmB,CAAC,cAAuB;QACzC,MAAM,OAAO,GAAgC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC1E,MAAM;YACN,cAAc;YACd,kBAAkB,EAAE,EAAqB;YACzC,iBAAiB,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,gBAAgB,EAAE,EAAqB;YACvC,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;SACjB,CAAC,CAAC,CAAC;QACJ,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAuC,CAAC,CAAC;IAClE,CAAC;CACF;AAEA,MAAc,CAAC,oBAAoB,GAAG,wBAAwB,CAAC;AAEhE,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,WAA4B,CAAC;IACjC,IAAI,QAAmB,CAAC;IACxB,IAAI,OAAwB,CAAC;IAC7B,IAAI,UAA2C,CAAC;IAChD,IAAI,WAAqF,CAAC;IAE1F,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QAC7B,QAAQ,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QACrB,WAAW,GAAG;YACZ,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;YAChB,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;YACf,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE;YACf,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE;SACjB,CAAC;QACF,UAAU,GAAG,IAAA,qBAAY,EAAC;YACxB,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,WAAiC;SACxC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;QAC3C,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;gBAC7B,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAEtC,4CAA4C;YAC5C,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,0BAA0B,CAAC;YACrD,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAEtC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG;;;;OAIzB,CAAC;YACF,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAEtC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAC5C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAClB,8BAA8B,CAC/B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG;;;;OAIzB,CAAC;YACF,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,2BAA2B,EAAE,CAAC;YACtC,OAAO,CAAC,2BAA2B,EAAE,CAAC;YAEtC,iDAAiD;YACjD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CACpD,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,8BAA8B,CACrD,CAAC;YACF,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qCAAqC,EAAE,GAAG,EAAE;QACnD,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;gBAC7B,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,mCAAmC,EAAE,CAAC;YAE9C,qDAAqD;YACrD,MAAM,kBAAkB,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAC5D,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,sCAAsC,CAC7D,CAAC;YACF,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,0BAA0B,CAAC;YACrD,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,mCAAmC,EAAE,CAAC;YAE9C,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAC5C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAClB,sCAAsC,CACvC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;YAC1E,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG,0BAA0B,CAAC;YACrD,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,mCAAmC,EAAE,CAAC;YAC9C,OAAO,CAAC,mCAAmC,EAAE,CAAC;YAE9C,MAAM,kBAAkB,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAC5D,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,sCAAsC,CAC7D,CAAC;YACF,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG;;;;OAIzB,CAAC;YACF,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,2BAA2B,EAAE,CAAC;YACtC,OAAO,CAAC,mCAAmC,EAAE,CAAC;YAE9C,mBAAmB;YACnB,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;gBAC7B,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,QAAQ,CAAC,IAAI,CAAC,SAAS,GAAG;;;;OAIzB,CAAC;YACF,WAAW,GAAG;gBACZ,iBAAiB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC;gBAC3D,IAAI,EAAE,QAAQ;aACf,CAAC;YACF,OAAO,GAAG,IAAI,kCAAe,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YAEvD,OAAO,CAAC,2BAA2B,EAAE,CAAC;YACtC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO,CAAC,QAAQ,EAAE,CAAC;YAEnB,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-uploader.test.d.ts","sourceRoot":"","sources":["../../tests/s3-uploader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const s3_uploader_1 = require("../upload/s3-uploader");
|
|
4
|
+
describe("S3Uploader", () => {
|
|
5
|
+
let uploader;
|
|
6
|
+
let mockXHR;
|
|
7
|
+
let xhrEventHandlers;
|
|
8
|
+
let uploadEventHandlers;
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
xhrEventHandlers = new Map();
|
|
11
|
+
uploadEventHandlers = new Map();
|
|
12
|
+
mockXHR = {
|
|
13
|
+
open: jest.fn(),
|
|
14
|
+
send: jest.fn(),
|
|
15
|
+
setRequestHeader: jest.fn(),
|
|
16
|
+
abort: jest.fn(),
|
|
17
|
+
upload: {
|
|
18
|
+
addEventListener: jest.fn((event, handler) => {
|
|
19
|
+
uploadEventHandlers.set(event, handler);
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
addEventListener: jest.fn((event, handler) => {
|
|
23
|
+
xhrEventHandlers.set(event, handler);
|
|
24
|
+
}),
|
|
25
|
+
status: 200,
|
|
26
|
+
statusText: "OK",
|
|
27
|
+
};
|
|
28
|
+
global.XMLHttpRequest = jest.fn(() => mockXHR);
|
|
29
|
+
uploader = new s3_uploader_1.S3Uploader();
|
|
30
|
+
});
|
|
31
|
+
const createMockEntry = (overrides = {}) => ({
|
|
32
|
+
id: "test-entry-1",
|
|
33
|
+
file: new File(["test content"], "test.txt", { type: "text/plain" }),
|
|
34
|
+
uploadName: "test-upload",
|
|
35
|
+
progress: 0,
|
|
36
|
+
bytesUploaded: 0,
|
|
37
|
+
valid: true,
|
|
38
|
+
done: false,
|
|
39
|
+
...overrides,
|
|
40
|
+
});
|
|
41
|
+
const createMockMeta = (overrides = {}) => ({
|
|
42
|
+
uploader: "s3",
|
|
43
|
+
url: "https://s3.example.com/bucket/key?presigned=signature",
|
|
44
|
+
...overrides,
|
|
45
|
+
});
|
|
46
|
+
describe("upload", () => {
|
|
47
|
+
it("uploads file to presigned URL", async () => {
|
|
48
|
+
const entry = createMockEntry();
|
|
49
|
+
const meta = createMockMeta();
|
|
50
|
+
const uploadPromise = uploader.upload(entry, meta);
|
|
51
|
+
expect(mockXHR.open).toHaveBeenCalledWith("PUT", meta.url);
|
|
52
|
+
expect(mockXHR.send).toHaveBeenCalledWith(entry.file);
|
|
53
|
+
// Simulate successful upload
|
|
54
|
+
mockXHR.status = 200;
|
|
55
|
+
xhrEventHandlers.get("load")();
|
|
56
|
+
await uploadPromise;
|
|
57
|
+
expect(entry.done).toBe(true);
|
|
58
|
+
expect(entry.progress).toBe(100);
|
|
59
|
+
});
|
|
60
|
+
it("sets custom headers", async () => {
|
|
61
|
+
const entry = createMockEntry();
|
|
62
|
+
const meta = createMockMeta({
|
|
63
|
+
headers: {
|
|
64
|
+
"Content-Type": "text/plain",
|
|
65
|
+
"x-amz-acl": "public-read",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
const uploadPromise = uploader.upload(entry, meta);
|
|
69
|
+
expect(mockXHR.setRequestHeader).toHaveBeenCalledWith("Content-Type", "text/plain");
|
|
70
|
+
expect(mockXHR.setRequestHeader).toHaveBeenCalledWith("x-amz-acl", "public-read");
|
|
71
|
+
mockXHR.status = 200;
|
|
72
|
+
xhrEventHandlers.get("load")();
|
|
73
|
+
await uploadPromise;
|
|
74
|
+
});
|
|
75
|
+
it("tracks upload progress", async () => {
|
|
76
|
+
const entry = createMockEntry();
|
|
77
|
+
const meta = createMockMeta();
|
|
78
|
+
const onProgress = jest.fn();
|
|
79
|
+
const uploadPromise = uploader.upload(entry, meta, onProgress);
|
|
80
|
+
// Simulate progress event
|
|
81
|
+
uploadEventHandlers.get("progress")({
|
|
82
|
+
lengthComputable: true,
|
|
83
|
+
loaded: 50,
|
|
84
|
+
total: 100,
|
|
85
|
+
});
|
|
86
|
+
expect(entry.bytesUploaded).toBe(50);
|
|
87
|
+
expect(entry.progress).toBe(50);
|
|
88
|
+
expect(onProgress).toHaveBeenCalledWith(entry);
|
|
89
|
+
// Complete upload
|
|
90
|
+
mockXHR.status = 200;
|
|
91
|
+
xhrEventHandlers.get("load")();
|
|
92
|
+
await uploadPromise;
|
|
93
|
+
});
|
|
94
|
+
it("handles upload failure with status code", async () => {
|
|
95
|
+
const entry = createMockEntry();
|
|
96
|
+
const meta = createMockMeta();
|
|
97
|
+
const uploadPromise = uploader.upload(entry, meta);
|
|
98
|
+
mockXHR.status = 403;
|
|
99
|
+
mockXHR.statusText = "Forbidden";
|
|
100
|
+
xhrEventHandlers.get("load")();
|
|
101
|
+
await expect(uploadPromise).rejects.toThrow("S3 upload failed with status 403: Forbidden");
|
|
102
|
+
expect(entry.error).toBe("S3 upload failed with status 403: Forbidden");
|
|
103
|
+
});
|
|
104
|
+
it("handles network error", async () => {
|
|
105
|
+
const entry = createMockEntry();
|
|
106
|
+
const meta = createMockMeta();
|
|
107
|
+
const uploadPromise = uploader.upload(entry, meta);
|
|
108
|
+
xhrEventHandlers.get("error")();
|
|
109
|
+
await expect(uploadPromise).rejects.toThrow("S3 upload failed: Network error");
|
|
110
|
+
expect(entry.error).toBe("S3 upload failed: Network error");
|
|
111
|
+
});
|
|
112
|
+
it("supports abort/cancellation", async () => {
|
|
113
|
+
const entry = createMockEntry();
|
|
114
|
+
const meta = createMockMeta();
|
|
115
|
+
const uploadPromise = uploader.upload(entry, meta);
|
|
116
|
+
// Abort the upload
|
|
117
|
+
entry.abortController.abort();
|
|
118
|
+
// The abort event should be triggered
|
|
119
|
+
xhrEventHandlers.get("abort")();
|
|
120
|
+
await expect(uploadPromise).rejects.toThrow("S3 upload cancelled");
|
|
121
|
+
expect(mockXHR.abort).toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
it("does not call progress callback for non-computable progress", async () => {
|
|
124
|
+
const entry = createMockEntry();
|
|
125
|
+
const meta = createMockMeta();
|
|
126
|
+
const onProgress = jest.fn();
|
|
127
|
+
const uploadPromise = uploader.upload(entry, meta, onProgress);
|
|
128
|
+
// Simulate progress event without length
|
|
129
|
+
uploadEventHandlers.get("progress")({
|
|
130
|
+
lengthComputable: false,
|
|
131
|
+
loaded: 50,
|
|
132
|
+
total: 0,
|
|
133
|
+
});
|
|
134
|
+
expect(onProgress).not.toHaveBeenCalled();
|
|
135
|
+
mockXHR.status = 200;
|
|
136
|
+
xhrEventHandlers.get("load")();
|
|
137
|
+
await uploadPromise;
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=s3-uploader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3-uploader.test.js","sourceRoot":"","sources":["../../tests/s3-uploader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-handler.test.d.ts","sourceRoot":"","sources":["../../tests/upload-handler.test.ts"],"names":[],"mappings":""}
|