diff --git a/craft/src/components/forms/ContactForm.toHtml.test.ts b/craft/src/components/forms/ContactForm.toHtml.test.ts
index 8f0f7be..4f50fec 100644
--- a/craft/src/components/forms/ContactForm.toHtml.test.ts
+++ b/craft/src/components/forms/ContactForm.toHtml.test.ts
@@ -6,12 +6,12 @@ const toHtml = (ContactForm as any).toHtml;
describe('ContactForm.toHtml relay wiring', () => {
test('with recipientEmail: emits marker, placeholder action, honeypot', () => {
const { html } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx', fields: [] }, '');
- expect(html).toMatch(//);
- expect(html).toMatch(/action="__WHP_FORM_ACTION__F[0-9a-z]+__"/);
+ expect(html).toMatch(//);
+ expect(html).toMatch(/action="__WHP_FORM_ACTION__F_[0-9a-z]+__"/);
expect(html).toContain('method="POST"');
expect(html).toContain('name="_gotcha"');
// marker id and action id match
- const mid = html.match(/id="(F[0-9a-z]+)"/)![1];
+ const mid = html.match(/id="(F_[0-9a-z]+)"/)![1];
expect(html).toContain(`__WHP_FORM_ACTION__${mid}__`);
});
@@ -64,6 +64,28 @@ describe('ContactForm.toHtml successMessage', () => {
});
});
+describe('ContactForm.toHtml relay marker deterministic + unique via node id (no Math.random)', () => {
+ test('same node id -> identical marker+placeholder ids across two calls', () => {
+ const { html: html1 } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx', fields: [] }, '', 'node-cf1');
+ const { html: html2 } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx', fields: [] }, '', 'node-cf1');
+ expect(html1).toBe(html2);
+ });
+
+ test('marker id always equals the placeholder id it pairs with', () => {
+ const { html } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx', fields: [] }, '', 'node-cf1');
+ const mid = html.match(//);
- expect(html).toMatch(/action="__WHP_FORM_ACTION__F[0-9a-z]+__"/);
+ expect(html).toMatch(//);
+ expect(html).toMatch(/action="__WHP_FORM_ACTION__F_[0-9a-z]+__"/);
expect(html).toContain('method="POST"'); // relay forces POST even though method=GET
expect(html).toContain('name="_gotcha"');
// honeypot precedes the form's children
expect(html.indexOf('_gotcha')).toBeLessThan(html.indexOf('name="email"'));
// marker id === action id
- const mid = html.match(/id="(F[0-9a-z]+)"/)![1];
+ const mid = html.match(/id="(F_[0-9a-z]+)"/)![1];
expect(html).toContain(`__WHP_FORM_ACTION__${mid}__`);
});
@@ -24,4 +24,18 @@ describe('FormContainer.toHtml relay wiring', () => {
expect(html).toContain('action="/legacy"');
expect(html).toContain('');
});
+
+ test('same node id -> identical marker+placeholder ids across two calls', () => {
+ const { html: html1 } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx' }, '', 'node-fc1');
+ const { html: html2 } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx' }, '', 'node-fc1');
+ expect(html1).toBe(html2);
+ });
+
+ test('two different node ids -> different fids', () => {
+ const { html: html1 } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx' }, '', 'node-fc1');
+ const { html: html2 } = toHtml({ recipientEmail: 'a@b.com', thankYouUrl: '/thx' }, '', 'node-fc2');
+ const mid1 = html1.match(/`,