@prosopo/procaptcha-wrapper 2.6.103 → 2.6.104

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 (46) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +11 -9
  2. package/.turbo/turbo-build$colon$tsc.log +9 -9
  3. package/.turbo/turbo-build.log +13 -10
  4. package/CHANGELOG.md +42 -0
  5. package/dist/_virtual/_rolldown/runtime.js +3 -0
  6. package/dist/cjs/index.cjs +5 -7
  7. package/dist/cjs/render/renderFunction.cjs +34 -31
  8. package/dist/cjs/render/renderer.cjs +16 -19
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +7 -8
  12. package/dist/render/renderFunction.d.ts +1 -0
  13. package/dist/render/renderFunction.d.ts.map +1 -1
  14. package/dist/render/renderFunction.js +34 -32
  15. package/dist/render/renderFunction.js.map +1 -1
  16. package/dist/render/renderer.d.ts +3 -3
  17. package/dist/render/renderer.d.ts.map +1 -1
  18. package/dist/render/renderer.js +16 -19
  19. package/dist/render/renderer.js.map +1 -1
  20. package/dist/tests/index.unit.test.d.ts +2 -0
  21. package/dist/tests/index.unit.test.d.ts.map +1 -0
  22. package/dist/tests/index.unit.test.js +26 -0
  23. package/dist/tests/index.unit.test.js.map +1 -0
  24. package/dist/tests/renderFunction.unit.test.d.ts +2 -0
  25. package/dist/tests/renderFunction.unit.test.d.ts.map +1 -0
  26. package/dist/tests/renderFunction.unit.test.js +186 -0
  27. package/dist/tests/renderFunction.unit.test.js.map +1 -0
  28. package/dist/tests/renderer.test-d.d.ts +2 -0
  29. package/dist/tests/renderer.test-d.d.ts.map +1 -0
  30. package/dist/tests/renderer.test-d.js +92 -0
  31. package/dist/tests/renderer.test-d.js.map +1 -0
  32. package/dist/tests/renderer.unit.test.d.ts +2 -0
  33. package/dist/tests/renderer.unit.test.d.ts.map +1 -0
  34. package/dist/tests/renderer.unit.test.js +207 -0
  35. package/dist/tests/renderer.unit.test.js.map +1 -0
  36. package/package.json +15 -6
  37. package/src/index.ts +7 -1
  38. package/src/render/renderFunction.ts +13 -3
  39. package/src/render/renderer.ts +21 -7
  40. package/src/tests/index.unit.test.ts +47 -0
  41. package/src/tests/renderFunction.unit.test.ts +275 -0
  42. package/src/tests/renderer.test-d.ts +175 -0
  43. package/src/tests/renderer.unit.test.ts +331 -0
  44. package/tsconfig.tsbuildinfo +1 -1
  45. package/vite.test.config.ts +39 -0
  46. package/.turbo/turbo-typecheck.log +0 -4
@@ -0,0 +1,186 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { loadRenderFunction, loadScript, } from "../render/renderFunction.js";
3
+ const SCRIPT_URL = "https://example.test/procaptcha.bundle.js";
4
+ const SCRIPT_ID = "procaptcha-script";
5
+ const noopRender = async () => { };
6
+ const lastScript = () => {
7
+ const scripts = document.head.querySelectorAll("script");
8
+ const script = scripts[scripts.length - 1];
9
+ if (undefined === script) {
10
+ throw new Error("no script tag was appended");
11
+ }
12
+ return script;
13
+ };
14
+ const settleScript = async (outcome) => {
15
+ await Promise.resolve();
16
+ lastScript().dispatchEvent(new Event(outcome));
17
+ };
18
+ afterEach(() => {
19
+ document.head.innerHTML = "";
20
+ document.body.innerHTML = "";
21
+ window.procaptcha = undefined;
22
+ vi.restoreAllMocks();
23
+ });
24
+ describe("loadScript", () => {
25
+ it("appends a script tag carrying the requested src", async () => {
26
+ const loading = loadScript(SCRIPT_URL);
27
+ await settleScript("load");
28
+ await loading;
29
+ expect(lastScript().src).toBe(SCRIPT_URL);
30
+ });
31
+ it("applies the supplied attributes to the tag", async () => {
32
+ const loading = loadScript(SCRIPT_URL, {
33
+ id: SCRIPT_ID,
34
+ type: "module",
35
+ async: true,
36
+ defer: true,
37
+ });
38
+ await settleScript("load");
39
+ await loading;
40
+ const script = lastScript();
41
+ expect(script.id).toBe(SCRIPT_ID);
42
+ expect(script.type).toBe("module");
43
+ expect(script.async).toBe(true);
44
+ expect(script.defer).toBe(true);
45
+ });
46
+ it("works with no attributes at all", async () => {
47
+ const loading = loadScript(SCRIPT_URL);
48
+ await settleScript("load");
49
+ await expect(loading).resolves.toBeUndefined();
50
+ });
51
+ it("lets an attribute override the src", async () => {
52
+ const loading = loadScript(SCRIPT_URL, {
53
+ src: "https://example.test/other.js",
54
+ });
55
+ await settleScript("load");
56
+ await loading;
57
+ expect(lastScript().src).toBe("https://example.test/other.js");
58
+ });
59
+ it("appends the tag to document.head, not the body", async () => {
60
+ const loading = loadScript(SCRIPT_URL);
61
+ await settleScript("load");
62
+ await loading;
63
+ expect(document.head.querySelectorAll("script")).toHaveLength(1);
64
+ expect(document.body.querySelectorAll("script")).toHaveLength(0);
65
+ });
66
+ it("rejects with an Error, not the raw DOM Event", async () => {
67
+ const loading = loadScript(SCRIPT_URL);
68
+ await settleScript("error");
69
+ await expect(loading).rejects.toBeInstanceOf(Error);
70
+ });
71
+ it("names the failing url in the rejection message", async () => {
72
+ const loading = loadScript(SCRIPT_URL);
73
+ await settleScript("error");
74
+ await expect(loading).rejects.toThrow(`Failed to load script: ${SCRIPT_URL}`);
75
+ });
76
+ it("removes the failed tag so a retry leaves no duplicate id behind", async () => {
77
+ const first = loadScript(SCRIPT_URL, { id: SCRIPT_ID });
78
+ await settleScript("error");
79
+ await expect(first).rejects.toThrow();
80
+ expect(document.head.querySelectorAll("script")).toHaveLength(0);
81
+ const second = loadScript(SCRIPT_URL, { id: SCRIPT_ID });
82
+ await settleScript("load");
83
+ await second;
84
+ expect(document.querySelectorAll(`#${SCRIPT_ID}`)).toHaveLength(1);
85
+ });
86
+ it("stays pending until the script settles", async () => {
87
+ let settled = false;
88
+ const loading = loadScript(SCRIPT_URL).then(() => {
89
+ settled = true;
90
+ });
91
+ await Promise.resolve();
92
+ expect(settled).toBe(false);
93
+ await settleScript("load");
94
+ await loading;
95
+ expect(settled).toBe(true);
96
+ });
97
+ it("accepts an empty url without throwing synchronously", async () => {
98
+ const loading = loadScript("");
99
+ await settleScript("load");
100
+ await expect(loading).resolves.toBeUndefined();
101
+ });
102
+ });
103
+ describe("loadRenderFunction", () => {
104
+ it("returns the render function the script installed on window", async () => {
105
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
106
+ await Promise.resolve();
107
+ window.procaptcha = { render: noopRender };
108
+ lastScript().dispatchEvent(new Event("load"));
109
+ await expect(loading).resolves.toBe(noopRender);
110
+ });
111
+ it("requests the script as a deferred async module with the given id", async () => {
112
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
113
+ await Promise.resolve();
114
+ const script = lastScript();
115
+ expect(script.src).toBe(SCRIPT_URL);
116
+ expect(script.id).toBe(SCRIPT_ID);
117
+ expect(script.type).toBe("module");
118
+ expect(script.async).toBe(true);
119
+ expect(script.defer).toBe(true);
120
+ window.procaptcha = { render: noopRender };
121
+ script.dispatchEvent(new Event("load"));
122
+ await loading;
123
+ });
124
+ it("removes the tag when the script loads but is the wrong script", async () => {
125
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
126
+ await settleScript("load");
127
+ await expect(loading).rejects.toThrow();
128
+ expect(document.getElementById(SCRIPT_ID)).toBeNull();
129
+ });
130
+ it("leaves a retry with exactly one tag after a wrong-script load", async () => {
131
+ const first = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
132
+ await settleScript("load");
133
+ await expect(first).rejects.toThrow();
134
+ const second = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
135
+ await Promise.resolve();
136
+ window.procaptcha = { render: noopRender };
137
+ lastScript().dispatchEvent(new Event("load"));
138
+ await expect(second).resolves.toBe(noopRender);
139
+ expect(document.querySelectorAll(`#${SCRIPT_ID}`)).toHaveLength(1);
140
+ });
141
+ it("keeps the tag when the script loads successfully", async () => {
142
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
143
+ await Promise.resolve();
144
+ window.procaptcha = { render: noopRender };
145
+ lastScript().dispatchEvent(new Event("load"));
146
+ await loading;
147
+ expect(document.getElementById(SCRIPT_ID)).not.toBeNull();
148
+ });
149
+ it("throws when the script loads but installs no procaptcha global", async () => {
150
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
151
+ await settleScript("load");
152
+ await expect(loading).rejects.toThrow("Render script does not contain the render function");
153
+ });
154
+ it("throws when the global exists but carries no render function", async () => {
155
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
156
+ await Promise.resolve();
157
+ window.procaptcha = { render: undefined };
158
+ lastScript().dispatchEvent(new Event("load"));
159
+ await expect(loading).rejects.toThrow("Render script does not contain the render function");
160
+ });
161
+ it("propagates the load failure rather than reporting a missing function", async () => {
162
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
163
+ await settleScript("error");
164
+ await expect(loading).rejects.toThrow(`Failed to load script: ${SCRIPT_URL}`);
165
+ });
166
+ it("does not check the global until the script has loaded", async () => {
167
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
168
+ await Promise.resolve();
169
+ window.procaptcha = { render: noopRender };
170
+ lastScript().dispatchEvent(new Event("load"));
171
+ await expect(loading).resolves.toBe(noopRender);
172
+ });
173
+ it("returns a function that forwards its arguments to the loaded render", async () => {
174
+ const render = vi.fn(async () => { });
175
+ const loading = loadRenderFunction(SCRIPT_URL, SCRIPT_ID);
176
+ await Promise.resolve();
177
+ window.procaptcha = { render };
178
+ lastScript().dispatchEvent(new Event("load"));
179
+ const loaded = await loading;
180
+ const element = document.createElement("div");
181
+ const options = { siteKey: "site-key" };
182
+ await loaded(element, options);
183
+ expect(render).toHaveBeenCalledWith(element, options);
184
+ });
185
+ });
186
+ //# sourceMappingURL=renderFunction.unit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderFunction.unit.test.js","sourceRoot":"","sources":["../../src/tests/renderFunction.unit.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=renderer.test-d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.test-d.d.ts","sourceRoot":"","sources":["../../src/tests/renderer.test-d.ts"],"names":[],"mappings":""}
@@ -0,0 +1,92 @@
1
+ import { assertType, describe, expectTypeOf, it } from "vitest";
2
+ import { renderProcaptcha } from "../index.js";
3
+ import { loadRenderFunction, loadScript, } from "../render/renderFunction.js";
4
+ import { createRenderer, } from "../render/renderer.js";
5
+ describe("RendererFunction", () => {
6
+ it("takes an element and options, and resolves to void", () => {
7
+ expectTypeOf().parameters.toEqualTypeOf();
8
+ expectTypeOf().returns.toEqualTypeOf();
9
+ });
10
+ it("does not accept a bare Element for the mount point", () => {
11
+ expectTypeOf().not.toMatchTypeOf();
12
+ });
13
+ it("requires a siteKey in the options", () => {
14
+ assertType({ siteKey: "site-key" });
15
+ assertType({});
16
+ });
17
+ it("rejects an unknown option key", () => {
18
+ assertType({
19
+ siteKey: "site-key",
20
+ notAnOption: true,
21
+ });
22
+ });
23
+ });
24
+ describe("renderProcaptcha", () => {
25
+ it("is exposed as a RendererFunction", () => {
26
+ expectTypeOf(renderProcaptcha).toEqualTypeOf();
27
+ });
28
+ });
29
+ describe("re-exported types", () => {
30
+ it("aliases the shared types rather than redeclaring them", () => {
31
+ expectTypeOf().toEqualTypeOf();
32
+ expectTypeOf().toEqualTypeOf();
33
+ });
34
+ it("exports the language union as a usable type", () => {
35
+ expectTypeOf().toEqualTypeOf();
36
+ assertType("en");
37
+ });
38
+ it("keeps the language union aligned with the render options", () => {
39
+ expectTypeOf().toEqualTypeOf();
40
+ });
41
+ it("rejects a language outside the union", () => {
42
+ assertType("not-a-language");
43
+ });
44
+ });
45
+ describe("createRenderer", () => {
46
+ it("returns a RendererFunction", () => {
47
+ expectTypeOf(createRenderer).returns.toEqualTypeOf();
48
+ });
49
+ it("takes settings and an optional loader override", () => {
50
+ expectTypeOf(createRenderer).parameters.toEqualTypeOf();
51
+ });
52
+ it("accepts a call with settings alone", () => {
53
+ expectTypeOf(createRenderer).toBeCallableWith({
54
+ scriptUrl: "url",
55
+ scriptId: "id",
56
+ });
57
+ });
58
+ it("requires both settings fields", () => {
59
+ assertType({ scriptUrl: "url" });
60
+ assertType({ scriptId: "id" });
61
+ });
62
+ it("rejects a loader that resolves to the wrong shape", () => {
63
+ createRenderer({ scriptUrl: "url", scriptId: "id" }, async () => "nope");
64
+ });
65
+ });
66
+ describe("LoadRenderFunction", () => {
67
+ it("takes two strings and resolves to a RendererFunction", () => {
68
+ expectTypeOf().parameters.toEqualTypeOf();
69
+ expectTypeOf().returns.toEqualTypeOf();
70
+ });
71
+ it("is satisfied by the real loader", () => {
72
+ expectTypeOf(loadRenderFunction).toMatchTypeOf();
73
+ });
74
+ });
75
+ describe("loadScript", () => {
76
+ it("resolves to void rather than the tag it created", () => {
77
+ expectTypeOf(loadScript).returns.toEqualTypeOf();
78
+ });
79
+ it("takes an optional partial set of script attributes", () => {
80
+ expectTypeOf(loadScript).toBeCallableWith("url");
81
+ expectTypeOf(loadScript).toBeCallableWith("url", { id: "id" });
82
+ });
83
+ it("rejects an attribute that is not on a script element", () => {
84
+ loadScript("url", { href: "url" });
85
+ });
86
+ });
87
+ describe("window.procaptcha", () => {
88
+ it("is declared as possibly absent", () => {
89
+ expectTypeOf().toEqualTypeOf();
90
+ });
91
+ });
92
+ //# sourceMappingURL=renderer.test-d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.test-d.js","sourceRoot":"","sources":["../../src/tests/renderer.test-d.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=renderer.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.unit.test.d.ts","sourceRoot":"","sources":["../../src/tests/renderer.unit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,207 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { createRenderer, } from "../render/renderer.js";
3
+ const SETTINGS = {
4
+ scriptUrl: "https://example.test/procaptcha.bundle.js",
5
+ scriptId: "procaptcha-script",
6
+ };
7
+ const options = (siteKey = "site-key") => ({
8
+ siteKey,
9
+ });
10
+ const stubLoad = (render) => {
11
+ let calls = 0;
12
+ const load = async () => {
13
+ calls += 1;
14
+ return render;
15
+ };
16
+ return { load, calls: () => calls };
17
+ };
18
+ const deferredLoad = () => {
19
+ let calls = 0;
20
+ let resolveFn = () => { };
21
+ let rejectFn = () => { };
22
+ const load = () => {
23
+ calls += 1;
24
+ return new Promise((resolve, reject) => {
25
+ resolveFn = resolve;
26
+ rejectFn = reject;
27
+ });
28
+ };
29
+ return {
30
+ load,
31
+ resolve: (render) => {
32
+ resolveFn(render);
33
+ },
34
+ reject: (error) => {
35
+ rejectFn(error);
36
+ },
37
+ calls: () => calls,
38
+ };
39
+ };
40
+ afterEach(() => {
41
+ document.head.innerHTML = "";
42
+ document.body.innerHTML = "";
43
+ window.procaptcha = undefined;
44
+ vi.restoreAllMocks();
45
+ });
46
+ describe("createRenderer", () => {
47
+ it("renders into the given element with the given options", async () => {
48
+ const render = vi.fn(async () => { });
49
+ const { load } = stubLoad(render);
50
+ const element = document.createElement("div");
51
+ await createRenderer(SETTINGS, load)(element, options());
52
+ expect(render).toHaveBeenCalledTimes(1);
53
+ expect(render.mock.calls[0]?.[0]).toBe(element);
54
+ });
55
+ it("passes the configured script url and id to the loader", async () => {
56
+ const load = vi.fn(async () => async () => { });
57
+ await createRenderer(SETTINGS, load)(document.createElement("div"), options());
58
+ expect(load).toHaveBeenCalledWith(SETTINGS.scriptUrl, SETTINGS.scriptId);
59
+ });
60
+ it("loads the script only once across repeated renders", async () => {
61
+ const { load, calls } = stubLoad(async () => { });
62
+ const renderer = createRenderer(SETTINGS, load);
63
+ await renderer(document.createElement("div"), options());
64
+ await renderer(document.createElement("div"), options());
65
+ await renderer(document.createElement("div"), options());
66
+ expect(calls()).toBe(1);
67
+ });
68
+ it("loads only once when renders overlap", async () => {
69
+ const deferred = deferredLoad();
70
+ const renderer = createRenderer(SETTINGS, deferred.load);
71
+ const first = renderer(document.createElement("div"), options());
72
+ const second = renderer(document.createElement("div"), options());
73
+ await Promise.resolve();
74
+ expect(deferred.calls()).toBe(1);
75
+ deferred.resolve(async () => { });
76
+ await Promise.all([first, second]);
77
+ expect(deferred.calls()).toBe(1);
78
+ });
79
+ it("renders every overlapping call once the script arrives", async () => {
80
+ const render = vi.fn(async () => { });
81
+ const deferred = deferredLoad();
82
+ const renderer = createRenderer(SETTINGS, deferred.load);
83
+ const pending = [
84
+ renderer(document.createElement("div"), options()),
85
+ renderer(document.createElement("div"), options()),
86
+ ];
87
+ deferred.resolve(render);
88
+ await Promise.all(pending);
89
+ expect(render).toHaveBeenCalledTimes(2);
90
+ });
91
+ it("clones the options so the render function cannot mutate the caller's object", async () => {
92
+ const supplied = options();
93
+ const render = async (_element, received) => {
94
+ Object.assign(received, { siteKey: "mutated" });
95
+ };
96
+ const { load } = stubLoad(render);
97
+ await createRenderer(SETTINGS, load)(document.createElement("div"), supplied);
98
+ expect(supplied.siteKey).toBe("site-key");
99
+ });
100
+ it("passes an extensible copy even when the caller's options are frozen", async () => {
101
+ const supplied = Object.freeze(options());
102
+ const render = async (_element, received) => {
103
+ Object.assign(received, { siteKey: "mutated" });
104
+ };
105
+ const { load } = stubLoad(render);
106
+ await expect(createRenderer(SETTINGS, load)(document.createElement("div"), supplied)).resolves.toBeUndefined();
107
+ });
108
+ it("forwards the option values on the copy it makes", async () => {
109
+ const render = vi.fn(async () => { });
110
+ const { load } = stubLoad(render);
111
+ await createRenderer(SETTINGS, load)(document.createElement("div"), options("abc"));
112
+ expect(render.mock.calls[0]?.[1]).toEqual({ siteKey: "abc" });
113
+ });
114
+ it("gives each render its own copy of the options", async () => {
115
+ const seen = [];
116
+ const render = async (_element, received) => {
117
+ seen.push(received);
118
+ };
119
+ const { load } = stubLoad(render);
120
+ const renderer = createRenderer(SETTINGS, load);
121
+ const supplied = options();
122
+ await renderer(document.createElement("div"), supplied);
123
+ await renderer(document.createElement("div"), supplied);
124
+ expect(seen[0]).not.toBe(seen[1]);
125
+ });
126
+ it("propagates a load failure to the caller", async () => {
127
+ const load = async () => {
128
+ throw new Error("network down");
129
+ };
130
+ await expect(createRenderer(SETTINGS, load)(document.createElement("div"), options())).rejects.toThrow("network down");
131
+ });
132
+ it("retries the load after a failure rather than caching the rejection", async () => {
133
+ let calls = 0;
134
+ const render = vi.fn(async () => { });
135
+ const load = async () => {
136
+ calls += 1;
137
+ if (1 === calls) {
138
+ throw new Error("network down");
139
+ }
140
+ return render;
141
+ };
142
+ const renderer = createRenderer(SETTINGS, load);
143
+ await expect(renderer(document.createElement("div"), options())).rejects.toThrow("network down");
144
+ await renderer(document.createElement("div"), options());
145
+ expect(calls).toBe(2);
146
+ expect(render).toHaveBeenCalledTimes(1);
147
+ });
148
+ it("fails every overlapping render when the shared load fails", async () => {
149
+ const deferred = deferredLoad();
150
+ const renderer = createRenderer(SETTINGS, deferred.load);
151
+ const first = renderer(document.createElement("div"), options());
152
+ const second = renderer(document.createElement("div"), options());
153
+ deferred.reject(new Error("network down"));
154
+ await expect(first).rejects.toThrow("network down");
155
+ await expect(second).rejects.toThrow("network down");
156
+ expect(deferred.calls()).toBe(1);
157
+ });
158
+ it("propagates an error thrown by the render function itself", async () => {
159
+ const { load } = stubLoad(async () => {
160
+ throw new Error("render blew up");
161
+ });
162
+ await expect(createRenderer(SETTINGS, load)(document.createElement("div"), options())).rejects.toThrow("render blew up");
163
+ });
164
+ it("keeps the loaded script cached after a render failure", async () => {
165
+ let calls = 0;
166
+ let shouldThrow = true;
167
+ const load = async () => {
168
+ calls += 1;
169
+ return async () => {
170
+ if (shouldThrow) {
171
+ throw new Error("render blew up");
172
+ }
173
+ };
174
+ };
175
+ const renderer = createRenderer(SETTINGS, load);
176
+ await expect(renderer(document.createElement("div"), options())).rejects.toThrow("render blew up");
177
+ shouldThrow = false;
178
+ await renderer(document.createElement("div"), options());
179
+ expect(calls).toBe(1);
180
+ });
181
+ it("keeps separate renderers independent", async () => {
182
+ const a = stubLoad(async () => { });
183
+ const b = stubLoad(async () => { });
184
+ await createRenderer(SETTINGS, a.load)(document.createElement("div"), options());
185
+ await createRenderer(SETTINGS, b.load)(document.createElement("div"), options());
186
+ expect(a.calls()).toBe(1);
187
+ expect(b.calls()).toBe(1);
188
+ });
189
+ it("renders into a detached element without touching the document", async () => {
190
+ const render = vi.fn(async () => { });
191
+ const { load } = stubLoad(render);
192
+ const detached = document.createElement("div");
193
+ await createRenderer(SETTINGS, load)(detached, options());
194
+ expect(render).toHaveBeenCalledTimes(1);
195
+ expect(document.body.contains(detached)).toBe(false);
196
+ });
197
+ it("defaults to the real loader when none is injected", async () => {
198
+ const renderer = createRenderer(SETTINGS);
199
+ const rendering = renderer(document.createElement("div"), options());
200
+ await Promise.resolve();
201
+ const script = document.head.querySelector("script");
202
+ expect(script?.src).toBe(SETTINGS.scriptUrl);
203
+ script?.dispatchEvent(new Event("error"));
204
+ await expect(rendering).rejects.toThrow("Failed to load script");
205
+ });
206
+ });
207
+ //# sourceMappingURL=renderer.unit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.unit.test.js","sourceRoot":"","sources":["../../src/tests/renderer.unit.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/procaptcha-wrapper",
3
- "version": "2.6.103",
3
+ "version": "2.6.104",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": "^24",
@@ -21,16 +21,25 @@
21
21
  "build:cross-env": "vite build --config vite.esm.config.ts",
22
22
  "build:tsc": "tsc --build --verbose",
23
23
  "build:cjs": "NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV",
24
- "typecheck": "tsc --project tsconfig.types.json"
24
+ "typecheck": "tsc --project tsconfig.types.json",
25
+ "test": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --config ./vite.test.config.ts",
26
+ "test:watch": "NODE_ENV=${NODE_ENV:-test}; npx vitest --config ./vite.test.config.ts",
27
+ "test:coverage": "NODE_ENV=${NODE_ENV:-test}; npx vitest run --coverage --config ./vite.test.config.ts"
25
28
  },
26
29
  "dependencies": {
27
- "@prosopo/types": "4.9.12",
28
- "@prosopo/locale": "3.2.7"
30
+ "@prosopo/types": "4.10.0",
31
+ "@prosopo/locale": "3.2.8"
29
32
  },
30
33
  "devDependencies": {
31
- "@prosopo/config": "3.3.4",
34
+ "@prosopo/config": "3.3.5",
35
+ "@types/jsdom": "21.1.7",
32
36
  "@types/node": "22.10.2",
33
- "del-cli": "6.0.0"
37
+ "@vitest/coverage-v8": "4.1.10",
38
+ "del-cli": "6.0.0",
39
+ "dotenv": "17.3.1",
40
+ "jsdom": "25.0.0",
41
+ "vite": "8.1.5",
42
+ "vitest": "4.1.10"
34
43
  },
35
44
  "author": "PROSOPO LIMITED <info@prosopo.io>",
36
45
  "license": "Apache-2.0",
package/src/index.ts CHANGED
@@ -24,8 +24,14 @@ export const renderProcaptcha: RendererFunction = createRenderer({
24
24
  scriptId: import.meta.env.VITE_RENDER_SCRIPT_ID,
25
25
  });
26
26
 
27
+ // `Languages` is a const object, so it carries no type meaning of its own:
28
+ // re-exporting the name as a type gave consumers a binding they could not
29
+ // actually use in a type position. Export the union of its values instead,
30
+ // which is what ProcaptchaRenderOptions["language"] already accepts.
31
+ type ProcaptchaLanguages = (typeof Languages)[keyof typeof Languages];
32
+
27
33
  export type {
28
34
  ProcaptchaRenderOptions,
29
35
  CaptchaType as ProcaptchaType,
30
- Languages as ProcaptchaLanguages,
36
+ ProcaptchaLanguages,
31
37
  };
@@ -31,13 +31,17 @@ export const loadRenderFunction = async (
31
31
  });
32
32
 
33
33
  if (undefined === window.procaptcha?.render) {
34
+ // The script loaded but is not the one we wanted. Leaving the tag behind
35
+ // would let a retry append a second tag carrying the same id, just as a
36
+ // failed load would.
37
+ document.getElementById(scriptId)?.remove();
34
38
  throw new Error("Render script does not contain the render function");
35
39
  }
36
40
 
37
41
  return window.procaptcha.render;
38
42
  };
39
43
 
40
- const loadScript = async (
44
+ export const loadScript = async (
41
45
  url: string,
42
46
  attributes?: Partial<HTMLScriptElement>,
43
47
  ): Promise<void> => {
@@ -62,8 +66,14 @@ const insertScriptTag = async (
62
66
  resolve();
63
67
  };
64
68
 
65
- scriptTag.onerror = (event: Event | string) => {
66
- reject(event);
69
+ scriptTag.onerror = () => {
70
+ // Remove the tag that failed: leaving it behind means a retry would
71
+ // append a second tag carrying the same id, and any `getElementById`
72
+ // lookup would keep resolving to the dead one.
73
+ scriptTag.remove();
74
+ // The DOM hands us an Event, which carries no message and breaks any
75
+ // caller reading `error.message`. Report the failure as an Error.
76
+ reject(new Error(`Failed to load script: ${scriptTag.src}`));
67
77
  };
68
78
 
69
79
  target.appendChild(scriptTag);