@fireproof/core 0.20.0-dev-preview-51 → 0.20.0-dev-preview-53
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/README.md +147 -59
- package/deno.json +2 -2
- package/index.cjs +2 -1
- package/index.cjs.map +1 -1
- package/index.d.cts +1 -1
- package/index.d.ts +1 -1
- package/index.js +2 -1
- package/index.js.map +1 -1
- package/metafile-cjs.json +1 -1
- package/metafile-esm.json +1 -1
- package/package.json +4 -4
- package/react/index.cjs +64 -0
- package/react/index.cjs.map +1 -1
- package/react/index.d.cts +290 -2
- package/react/index.d.ts +290 -2
- package/react/index.js +54 -0
- package/react/index.js.map +1 -1
- package/react/metafile-cjs.json +1 -1
- package/react/metafile-esm.json +1 -1
- package/tests/react/img-file.test.tsx +199 -0
- package/tests/react/useFireproof.test.tsx +418 -334
@@ -0,0 +1,199 @@
|
|
1
|
+
import { render, waitFor } from "@testing-library/react";
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
3
|
+
import { ImgFile, bs } from "use-fireproof";
|
4
|
+
import { createElement } from "react";
|
5
|
+
import type { DocFileMeta } from "use-fireproof";
|
6
|
+
|
7
|
+
// Extend HTMLElement to include querySelector for TypeScript
|
8
|
+
declare global {
|
9
|
+
interface HTMLElement {
|
10
|
+
querySelector(selectors: string): HTMLElement | null;
|
11
|
+
getAttribute(name: string): string | null;
|
12
|
+
classList: {
|
13
|
+
contains(token: string): boolean;
|
14
|
+
};
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
// Simple SVG content for testing
|
19
|
+
const SVG_CONTENT = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
20
|
+
<circle cx="12" cy="12" r="10" fill="blue" />
|
21
|
+
</svg>`;
|
22
|
+
|
23
|
+
describe("COMPONENT: ImgFile", () => {
|
24
|
+
// Mock URL methods
|
25
|
+
const mockObjectURL = "mock-object-url";
|
26
|
+
const originalCreateObjectURL = window.URL.createObjectURL;
|
27
|
+
const originalRevokeObjectURL = window.URL.revokeObjectURL;
|
28
|
+
|
29
|
+
beforeEach(() => {
|
30
|
+
window.URL.createObjectURL = vi.fn(() => mockObjectURL);
|
31
|
+
window.URL.revokeObjectURL = vi.fn();
|
32
|
+
});
|
33
|
+
|
34
|
+
afterEach(() => {
|
35
|
+
window.URL.createObjectURL = originalCreateObjectURL;
|
36
|
+
window.URL.revokeObjectURL = originalRevokeObjectURL;
|
37
|
+
});
|
38
|
+
|
39
|
+
// Test timeout value for CI
|
40
|
+
const TEST_TIMEOUT = 60000; // 1 minute per test
|
41
|
+
|
42
|
+
it(
|
43
|
+
"renders the image from a File object",
|
44
|
+
async () => {
|
45
|
+
const file = new File([new Blob([SVG_CONTENT], { type: "image/svg+xml" })], "test.svg", { type: "image/svg+xml" });
|
46
|
+
|
47
|
+
const { container } = render(
|
48
|
+
createElement(ImgFile, {
|
49
|
+
file: file,
|
50
|
+
alt: "Test SVG",
|
51
|
+
className: "test-class",
|
52
|
+
}),
|
53
|
+
);
|
54
|
+
|
55
|
+
await waitFor(() => {
|
56
|
+
const img = container.querySelector("img");
|
57
|
+
expect(img).not.toBeNull();
|
58
|
+
});
|
59
|
+
|
60
|
+
const img = container.querySelector("img");
|
61
|
+
expect(img?.getAttribute("src")).toBe(mockObjectURL);
|
62
|
+
expect(img?.getAttribute("alt")).toBe("Test SVG");
|
63
|
+
expect(img?.classList.contains("test-class")).toBe(true);
|
64
|
+
expect(window.URL.createObjectURL).toHaveBeenCalledWith(file);
|
65
|
+
},
|
66
|
+
TEST_TIMEOUT,
|
67
|
+
);
|
68
|
+
|
69
|
+
it(
|
70
|
+
"does not render when file is not present",
|
71
|
+
() => {
|
72
|
+
const { container } = render(
|
73
|
+
createElement(ImgFile, {
|
74
|
+
file: undefined,
|
75
|
+
alt: "No File",
|
76
|
+
}),
|
77
|
+
);
|
78
|
+
|
79
|
+
const img = container.querySelector("img");
|
80
|
+
expect(img).toBeNull();
|
81
|
+
expect(window.URL.createObjectURL).not.toHaveBeenCalled();
|
82
|
+
},
|
83
|
+
TEST_TIMEOUT,
|
84
|
+
);
|
85
|
+
|
86
|
+
it(
|
87
|
+
"supports legacy 'meta' parameter",
|
88
|
+
async () => {
|
89
|
+
const file = new File([new Blob([SVG_CONTENT], { type: "image/svg+xml" })], "legacy.svg", { type: "image/svg+xml" });
|
90
|
+
|
91
|
+
const { container } = render(
|
92
|
+
createElement(ImgFile, {
|
93
|
+
meta: file,
|
94
|
+
alt: "Legacy File",
|
95
|
+
}),
|
96
|
+
);
|
97
|
+
|
98
|
+
await waitFor(() => {
|
99
|
+
const img = container.querySelector("img");
|
100
|
+
expect(img).not.toBeNull();
|
101
|
+
});
|
102
|
+
|
103
|
+
const img = container.querySelector("img");
|
104
|
+
expect(img?.getAttribute("src")).toBe(mockObjectURL);
|
105
|
+
expect(img?.getAttribute("alt")).toBe("Legacy File");
|
106
|
+
expect(window.URL.createObjectURL).toHaveBeenCalledWith(file);
|
107
|
+
},
|
108
|
+
TEST_TIMEOUT,
|
109
|
+
);
|
110
|
+
|
111
|
+
it(
|
112
|
+
"renders from DocFileMeta object",
|
113
|
+
async () => {
|
114
|
+
const file = new File([new Blob([SVG_CONTENT], { type: "image/svg+xml" })], "meta.svg", { type: "image/svg+xml" });
|
115
|
+
|
116
|
+
// Create a mock DocFileMeta with required cid property
|
117
|
+
const mockCid = { toString: () => "test-cid" } as bs.AnyLink;
|
118
|
+
const docFileMeta: DocFileMeta = {
|
119
|
+
type: "image/svg+xml",
|
120
|
+
size: file.size,
|
121
|
+
cid: mockCid,
|
122
|
+
file: async () => file,
|
123
|
+
};
|
124
|
+
|
125
|
+
const { container } = render(
|
126
|
+
createElement(ImgFile, {
|
127
|
+
file: docFileMeta,
|
128
|
+
alt: "DocFileMeta Image",
|
129
|
+
}),
|
130
|
+
);
|
131
|
+
|
132
|
+
await waitFor(() => {
|
133
|
+
const img = container.querySelector("img");
|
134
|
+
expect(img).not.toBeNull();
|
135
|
+
});
|
136
|
+
|
137
|
+
const img = container.querySelector("img");
|
138
|
+
expect(img?.getAttribute("src")).toBe(mockObjectURL);
|
139
|
+
expect(img?.getAttribute("alt")).toBe("DocFileMeta Image");
|
140
|
+
expect(window.URL.createObjectURL).toHaveBeenCalledWith(file);
|
141
|
+
},
|
142
|
+
TEST_TIMEOUT,
|
143
|
+
);
|
144
|
+
|
145
|
+
it(
|
146
|
+
"does not render for non-image file types",
|
147
|
+
async () => {
|
148
|
+
const textFile = new File(["test content"], "test.txt", { type: "text/plain" });
|
149
|
+
|
150
|
+
const { container } = render(
|
151
|
+
createElement(ImgFile, {
|
152
|
+
file: textFile,
|
153
|
+
alt: "Text File",
|
154
|
+
}),
|
155
|
+
);
|
156
|
+
|
157
|
+
// Wait a bit to ensure any async operations complete
|
158
|
+
await waitFor(
|
159
|
+
() => {
|
160
|
+
// Verify that createObjectURL was called (or not called)
|
161
|
+
expect(window.URL.createObjectURL).toHaveBeenCalledTimes(0);
|
162
|
+
},
|
163
|
+
{ timeout: 1000 },
|
164
|
+
);
|
165
|
+
|
166
|
+
const img = container.querySelector("img");
|
167
|
+
expect(img).toBeNull();
|
168
|
+
},
|
169
|
+
TEST_TIMEOUT,
|
170
|
+
);
|
171
|
+
|
172
|
+
it(
|
173
|
+
"cleans up object URLs when unmounted",
|
174
|
+
async () => {
|
175
|
+
const file = new File([new Blob([SVG_CONTENT], { type: "image/svg+xml" })], "cleanup.svg", { type: "image/svg+xml" });
|
176
|
+
|
177
|
+
const { container, unmount } = render(
|
178
|
+
createElement(ImgFile, {
|
179
|
+
file: file,
|
180
|
+
alt: "Cleanup Test",
|
181
|
+
}),
|
182
|
+
);
|
183
|
+
|
184
|
+
await waitFor(() => {
|
185
|
+
const img = container.querySelector("img");
|
186
|
+
expect(img).not.toBeNull();
|
187
|
+
});
|
188
|
+
|
189
|
+
expect(window.URL.createObjectURL).toHaveBeenCalledWith(file);
|
190
|
+
expect(window.URL.revokeObjectURL).not.toHaveBeenCalled();
|
191
|
+
|
192
|
+
// Unmount to trigger cleanup
|
193
|
+
unmount();
|
194
|
+
|
195
|
+
expect(window.URL.revokeObjectURL).toHaveBeenCalledWith(mockObjectURL);
|
196
|
+
},
|
197
|
+
TEST_TIMEOUT,
|
198
|
+
);
|
199
|
+
});
|