feat(forms): add isolated Form A iframe adapter

This commit is contained in:
DeCentN2Madness committed 2026-10-28 17:19:56 -07:00
1 parent a635a5f55c
commit 61b2bd0f1e
18 files changed
+1345 -170

No files matched your search

+3
View File
@@ -150,8 +150,11 @@ test('early-intervention preserves its own publication identity and source secti
assert.equal($('.qr-benefit-card').length, 3);
assert.equal($('.qr-process-step').length, 3);
assert.equal($('form, input[type="hidden"], script[src]').length, 0);
assert.equal($('#consultation-heading').text(), 'Contact AIA about early intervention');
assert.equal($('#consultation input').length, 3);
assert.equal($('#consultation input:disabled').length, 3);
assert.equal($('#consultation').attr('data-forms-mode'), 'off');
assert.equal($('#consultation [data-jotform-form-a]').length, 0);
assert.equal($('#consultation button').attr('type'), 'button');
assert.ok($('.qr-call-card a[href="tel:+14806877099"]').length);
assert.equal($('#consultation-unavailable, [data-form-status-notice]').length, 0);
+193
View File
@@ -0,0 +1,193 @@
/**
* Deterministic Form A adapter check. Build the requested mode first, then
* run this against a loopback-only Astro preview. Every external request is
* intercepted and aborted before it can leave the browser.
*
* FORM_A_IFRAME_BROWSER_MODE=isolated-test \
* PLAYWRIGHT_MODULE=/path/to/playwright/index.mjs \
* CHROMIUM_EXECUTABLE=/path/to/chromium node tools/jotform-form-a-browser.mjs
*/
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import http from 'node:http';
import net from 'node:net';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { setTimeout as delay } from 'node:timers/promises';
const root = fileURLToPath(new URL('../', import.meta.url));
const moduleName = process.env.PLAYWRIGHT_MODULE ? pathToFileURL(path.resolve(process.env.PLAYWRIGHT_MODULE)).href : 'playwright';
const mode = process.env.FORM_A_IFRAME_BROWSER_MODE ?? 'off';
if (!['off', 'mock', 'isolated-test'].includes(mode)) throw new Error(`Unsupported Form A browser mode: ${mode}`);
const expectedIframe = mode === 'isolated-test';
const routes = [
{ route: '/contact', locale: 'en', context: 'contact', screenshot: 'contact' },
{ route: '/es/contact', locale: 'es', context: 'contact', screenshot: 'es-contact' },
{ route: '/lp/aba-therapy', locale: 'en', context: 'landing', screenshot: 'aba-therapy' },
{ route: '/lp/aba-insurance', locale: 'en', context: 'landing', screenshot: 'aba-insurance' },
{ route: '/lp/aba-ahcccs', locale: 'en', context: 'landing', screenshot: 'aba-ahcccs' },
{ route: '/lp/aba-private-pay', locale: 'en', context: 'landing', screenshot: 'aba-private-pay' },
{ route: '/lp/early-intervention', locale: 'en', context: 'landing', screenshot: 'early-intervention' },
];
const widths = [320, 390, 768, 1440];
const output = await fs.mkdtemp('/tmp/aia-form-a-iframe-');
const evidence = { mode, routes, widths, checks: 0, blocked: [], jotformAttempts: [], screenshots: [], status: 'failed' };
const reserve = net.createServer();
await new Promise((resolve, reject) => { reserve.once('error', reject); reserve.listen(0, '127.0.0.1', resolve); });
const port = reserve.address().port;
await new Promise((resolve) => reserve.close(resolve));
const origin = `http://127.0.0.1:${port}`;
let browser;
let preview;
try {
const { chromium } = await import(moduleName);
browser = await chromium.launch(process.env.CHROMIUM_EXECUTABLE ? { headless: true, executablePath: process.env.CHROMIUM_EXECUTABLE } : { headless: true });
preview = spawn(process.execPath, ['node_modules/astro/bin/astro.mjs', 'preview', '--host', '127.0.0.1', '--port', String(port)], {
cwd: root,
env: { ...process.env, ASTRO_TELEMETRY_DISABLED: '1' },
stdio: 'ignore',
});
const reachable = () => new Promise((resolve) => {
const request = http.get(origin + '/', (response) => { response.resume(); resolve(response.statusCode === 200); });
request.setTimeout(500, () => request.destroy());
request.on('error', () => resolve(false));
});
for (let i = 0; i < 60 && !(await reachable()); i++) await delay(250);
assert.equal(await reachable(), true, 'Loopback preview did not become reachable');
for (const width of widths) {
const context = await browser.newContext({ viewport: { width, height: width < 500 ? 844 : 960 }, serviceWorkers: 'block' });
await context.routeWebSocket('**/*', (socket) => socket.close());
await context.route('**/*', async (route) => {
const request = route.request();
const url = new URL(request.url());
if (url.origin === origin && ['GET', 'HEAD'].includes(request.method())) return route.continue();
const item = { origin: url.origin, path: url.pathname, search: url.search, method: request.method() };
evidence.blocked.push(item);
if (url.origin === 'https://form.jotform.com') evidence.jotformAttempts.push(item);
return route.abort();
});
const page = await context.newPage();
for (const expected of routes) {
const { route, locale, context: formContext, screenshot: screenshotName } = expected;
evidence.checks++;
const response = await page.goto(origin + route, { waitUntil: 'domcontentloaded', timeout: 15000 });
assert.equal(response?.status(), 200, route);
assert.equal(await page.locator('main h1').count(), 1, route);
assert.equal(await page.locator('main form').count(), 0, route);
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), `${route} at ${width}px has horizontal overflow`);
const iframe = page.locator('[data-jotform-form-a] iframe');
if (!expectedIframe) {
assert.equal(await iframe.count(), 0, `${route} should not emit an iframe in ${mode}`);
assert.equal(await page.locator('[data-jotform-form-a]').count(), 0, `${route} should not emit an adapter in ${mode}`);
continue;
}
const expectedUrl = `https://form.jotform.com/262946078314059?formContext=${formContext}&language=${locale}`;
assert.equal(await iframe.count(), 1, route);
assert.equal(await iframe.getAttribute('src'), expectedUrl, route);
assert.equal(await iframe.getAttribute('title'), locale === 'es' ? 'Formulario de consultas generales de AIA' : 'AIA general enquiries form', route);
assert.equal(await iframe.getAttribute('referrerpolicy'), 'no-referrer', route);
assert.equal(await iframe.getAttribute('sandbox'), 'allow-forms allow-scripts allow-same-origin', route);
assert.equal(await page.locator('[data-jotform-form-a][data-form-mode="isolated-test"]').count(), 1, route);
assert.equal(await page.locator(`[data-jotform-form-a][data-form-context="${formContext}"]`).count(), 1, route);
const frameBox = await iframe.boundingBox();
const expectedFrameHeight = formContext === 'contact'
? width < 500 ? 1088 : 960
: width < 500 ? 800 : 672;
assert.ok(frameBox && frameBox.width > 0 && frameBox.height >= expectedFrameHeight, `${route} iframe has an insufficient context-specific responsive frame`);
if ((route === '/contact' || route === '/es/contact') && width >= 768) {
const copyBox = await page.locator('.contact-page__copy').boundingBox();
const adapterBox = await page.locator('[data-jotform-form-a]').boundingBox();
assert.ok(copyBox && adapterBox && Math.abs(copyBox.width - adapterBox.width) <= 1, `${route} should use the full desktop grid column`);
}
const fallbackMarkup = await iframe.evaluate((element) => element.innerHTML);
assert.match(fallbackMarkup, /class="jotform-iframe__fallback"/, route);
const encodedFallbackUrl = expectedUrl.replace(/&/g, '&amp;');
assert.match(fallbackMarkup, new RegExp(`href="${encodedFallbackUrl.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}"`), route);
assert.match(fallbackMarkup, /target="_blank" rel="noopener noreferrer"/, route);
assert.equal(await page.locator('[data-jotform-form-a] > .jotform-iframe__fallback').count(), 0, `${route} should not show a duplicate parent fallback`);
if (route.startsWith('/lp/')) {
const expectedSurface = route === '/lp/early-intervention'
? '#consultation.lead-form > [data-jotform-form-a].jotform-iframe--embedded'
: '.form-wrap > [data-jotform-form-a].jotform-iframe--embedded';
assert.equal(await page.locator(expectedSurface).count(), 1, route);
assert.equal(await page.locator('#lead-form, [data-form-a-preview], #consultation input:enabled').count(), 0, route);
if (route !== '/lp/early-intervention') {
assert.equal(
await page.locator('[data-jotform-form-a] .jotform-iframe__description').innerText(),
'Use this form to request a conversation. An AIA team member can explain the next steps for your family.',
`${route} should use the shared iframe description instead of repeating companion copy`,
);
}
}
await iframe.focus();
assert.equal(await page.evaluate(() => document.activeElement?.tagName), 'IFRAME', route);
const screenshot = path.join(output, `${screenshotName}-${width}.png`);
await page.screenshot({ path: screenshot, fullPage: true });
evidence.screenshots.push(screenshot);
}
await context.close();
}
if (expectedIframe) {
const context = await browser.newContext({ viewport: { width: 390, height: 844 }, javaScriptEnabled: false, serviceWorkers: 'block' });
await context.route('**/*', async (route) => {
const request = route.request();
const url = new URL(request.url());
if (url.origin === origin && ['GET', 'HEAD'].includes(request.method())) return route.continue();
const item = { origin: url.origin, path: url.pathname, search: url.search, method: request.method(), noJavaScript: true };
evidence.blocked.push(item);
if (url.origin === 'https://form.jotform.com') evidence.jotformAttempts.push(item);
return route.abort();
});
for (const { route } of routes) {
evidence.checks++;
const page = await context.newPage();
const response = await page.goto(origin + route, { waitUntil: 'domcontentloaded', timeout: 15000 });
assert.equal(response?.status(), 200, `${route} without JavaScript`);
assert.equal(await page.locator('[data-jotform-form-a] iframe').count(), 1, `${route} without JavaScript`);
const iframe = page.locator('[data-jotform-form-a] iframe');
const fallbackMarkup = await iframe.evaluate((element) => element.innerHTML);
assert.match(fallbackMarkup, /class="jotform-iframe__fallback"/, `${route} without JavaScript`);
assert.match(fallbackMarkup, /target="_blank" rel="noopener noreferrer"/, `${route} without JavaScript`);
assert.equal(await page.locator('[data-jotform-form-a] > .jotform-iframe__fallback').count(), 0, `${route} without JavaScript should not show a duplicate parent fallback`);
if (route.startsWith('/lp/')) {
const expectedSurface = route === '/lp/early-intervention'
? '#consultation.lead-form > [data-jotform-form-a].jotform-iframe--embedded'
: '.form-wrap > [data-jotform-form-a].jotform-iframe--embedded';
assert.equal(await page.locator(expectedSurface).count(), 1, `${route} without JavaScript`);
}
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), `${route} without JavaScript has horizontal overflow`);
}
await context.close();
}
const formAttempts = evidence.jotformAttempts;
if (expectedIframe) {
assert.ok(formAttempts.length >= routes.length, 'Expected intercepted Jotform iframe GET attempts');
for (const attempt of formAttempts) {
assert.equal(attempt.method, 'GET');
assert.equal(attempt.path, '/262946078314059');
assert.match(attempt.search, /^\?formContext=(?:contact|landing)&language=(?:en|es)$/);
}
} else {
assert.equal(formAttempts.length, 0, `${mode} attempted Jotform traffic`);
}
assert.equal(evidence.blocked.filter((item) => !['GET', 'HEAD'].includes(item.method)).length, 0, 'A blocked non-read request was attempted');
evidence.status = 'passed';
} catch (error) {
evidence.error = error instanceof Error ? error.message : String(error);
throw error;
} finally {
await fs.writeFile(path.join(output, 'evidence.json'), JSON.stringify(evidence, null, 2));
if (preview && preview.exitCode === null) {
preview.kill('SIGTERM');
await Promise.race([new Promise((resolve) => preview.once('exit', resolve)), delay(3000)]);
if (preview.exitCode === null) preview.kill('SIGKILL');
}
await browser?.close();
console.log(JSON.stringify({ ...evidence, screenshots: evidence.screenshots.map((file) => path.basename(file)), artifactDirectory: output }, null, 2));
}
@@ -0,0 +1,147 @@
/**
* Read-only Form A iframe sizing acceptance probe.
*
* This intentionally requires a separate affirmative environment value
* because it permits GET/HEAD requests to form.jotform.com. It never fills,
* focuses, clicks, or submits an iframe control. All other external origins,
* non-read methods, downloads, and WebSockets are blocked and recorded.
*
* Build the isolated-test artifact first, then run:
* FORM_A_IFRAME_REAL_LOAD_APPROVED=true \
* FORM_A_IFRAME_JOTFORM_ASSETS_APPROVED=true \
* PLAYWRIGHT_MODULE=/path/to/playwright/index.mjs \
* CHROMIUM_EXECUTABLE=/path/to/chromium \
* node tools/jotform-form-a-real-iframe-sizing.mjs
*/
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import http from 'node:http';
import net from 'node:net';
import path from 'node:path';
import { spawn } from 'node:child_process';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { setTimeout as delay } from 'node:timers/promises';
if (process.env.FORM_A_IFRAME_REAL_LOAD_APPROVED !== 'true') {
throw new Error('Set FORM_A_IFRAME_REAL_LOAD_APPROVED=true to permit read-only requests to form.jotform.com.');
}
const root = fileURLToPath(new URL('../', import.meta.url));
const playwrightModule = process.env.PLAYWRIGHT_MODULE
? pathToFileURL(path.resolve(process.env.PLAYWRIGHT_MODULE)).href
: 'playwright';
const jotformOrigin = 'https://form.jotform.com';
const jotformAssetOrigin = 'https://cdn.jotfor.ms';
const allowJotformAssets = process.env.FORM_A_IFRAME_JOTFORM_ASSETS_APPROVED === 'true';
const allowedOrigins = new Set([jotformOrigin, ...(allowJotformAssets ? [jotformAssetOrigin] : [])]);
const routes = [
{ route: '/contact', context: 'contact', locale: 'en', file: 'contact' },
{ route: '/es/contact', context: 'contact', locale: 'es', file: 'es-contact' },
{ route: '/lp/aba-therapy', context: 'landing', locale: 'en', file: 'aba-therapy' },
{ route: '/lp/aba-insurance', context: 'landing', locale: 'en', file: 'aba-insurance' },
{ route: '/lp/aba-ahcccs', context: 'landing', locale: 'en', file: 'aba-ahcccs' },
{ route: '/lp/aba-private-pay', context: 'landing', locale: 'en', file: 'aba-private-pay' },
{ route: '/lp/early-intervention', context: 'landing', locale: 'en', file: 'early-intervention' },
];
const widths = [320, 390, 768, 1440];
const output = await fs.mkdtemp('/tmp/aia-form-a-real-iframe-sizing-');
const evidence = {
routes: routes.map(({ route, context, locale }) => ({ route, context, locale })),
widths,
allowedOrigins: [...allowedOrigins],
allowedJotformRequests: [],
blockedExternalRequests: [],
forbiddenAttempts: [],
screenshots: [],
status: 'failed',
};
const forbiddenHost = /(?:api\.azinstitute4autism\.com|google-analytics|googletagmanager|googleadservices|doubleclick)/i;
const reserve = net.createServer();
await new Promise((resolve, reject) => { reserve.once('error', reject); reserve.listen(0, '127.0.0.1', resolve); });
const port = reserve.address().port;
await new Promise((resolve) => reserve.close(resolve));
const origin = `http://127.0.0.1:${port}`;
let browser;
let preview;
try {
const { chromium } = await import(playwrightModule);
browser = await chromium.launch(process.env.CHROMIUM_EXECUTABLE
? { headless: true, executablePath: process.env.CHROMIUM_EXECUTABLE }
: { headless: true });
preview = spawn(process.execPath, ['node_modules/astro/bin/astro.mjs', 'preview', '--host', '127.0.0.1', '--port', String(port)], {
cwd: root,
env: { ...process.env, ASTRO_TELEMETRY_DISABLED: '1' },
stdio: 'ignore',
});
const reachable = () => new Promise((resolve) => {
const request = http.get(origin + '/', (response) => { response.resume(); resolve(response.statusCode === 200); });
request.setTimeout(500, () => request.destroy());
request.on('error', () => resolve(false));
});
for (let attempts = 0; attempts < 60 && !(await reachable()); attempts++) await delay(250);
assert.equal(await reachable(), true, 'Loopback preview did not become reachable');
for (const width of widths) {
const context = await browser.newContext({
viewport: { width, height: width < 641 ? 844 : 960 },
serviceWorkers: 'block',
acceptDownloads: false,
});
await context.routeWebSocket('**/*', (socket) => socket.close());
await context.route('**/*', async (route) => {
const request = route.request();
const url = new URL(request.url());
const item = { origin: url.origin, path: url.pathname, method: request.method() };
if (url.origin === origin && ['GET', 'HEAD'].includes(request.method())) return route.continue();
if (allowedOrigins.has(url.origin) && ['GET', 'HEAD'].includes(request.method())) {
evidence.allowedJotformRequests.push(item);
return route.continue();
}
evidence.blockedExternalRequests.push(item);
if (forbiddenHost.test(url.hostname)) evidence.forbiddenAttempts.push(item);
return route.abort();
});
const page = await context.newPage();
for (const expected of routes) {
const response = await page.goto(origin + expected.route, { waitUntil: 'domcontentloaded', timeout: 15000 });
assert.equal(response?.status(), 200, expected.route);
const iframe = page.locator('[data-jotform-form-a] iframe');
const expectedUrl = `${jotformOrigin}/262946078314059?formContext=${expected.context}&language=${expected.locale}`;
assert.equal(await iframe.count(), 1, expected.route);
assert.equal(await iframe.getAttribute('src'), expectedUrl, expected.route);
assert.equal(await iframe.getAttribute('sandbox'), 'allow-forms allow-scripts allow-same-origin', expected.route);
assert.equal(await iframe.getAttribute('referrerpolicy'), 'no-referrer', expected.route);
const box = await iframe.boundingBox();
const expectedHeight = expected.context === 'contact'
? width < 641 ? 1088 : 960
: width < 641 ? 800 : 672;
assert.ok(box && box.width > 0 && box.height >= expectedHeight, `${expected.route}: context-specific frame height is insufficient`);
await page.waitForTimeout(1200);
const screenshot = path.join(output, `${expected.file}-${width}.png`);
await page.screenshot({ path: screenshot, fullPage: true });
evidence.screenshots.push(screenshot);
}
await context.close();
}
assert.ok(evidence.allowedJotformRequests.length >= routes.length, 'Expected read-only Jotform iframe requests.');
assert.equal(evidence.forbiddenAttempts.length, 0, `Forbidden external requests: ${JSON.stringify(evidence.forbiddenAttempts)}`);
assert.equal(evidence.blockedExternalRequests.filter((item) => !['GET', 'HEAD'].includes(item.method)).length, 0, 'A non-read external request was attempted.');
evidence.status = 'passed';
} catch (error) {
evidence.error = error instanceof Error ? error.message : String(error);
throw error;
} finally {
await fs.writeFile(path.join(output, 'evidence.json'), JSON.stringify(evidence, null, 2));
if (preview?.exitCode === null) {
preview.kill('SIGTERM');
await Promise.race([new Promise((resolve) => preview.once('exit', resolve)), delay(3000)]);
if (preview.exitCode === null) preview.kill('SIGKILL');
}
await browser?.close();
console.log(JSON.stringify({
...evidence,
screenshots: evidence.screenshots.map((file) => path.basename(file)),
artifactDirectory: output,
}, null, 2));
}
+120
View File
@@ -0,0 +1,120 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import test from 'node:test';
import {
buildFormAIframeUrl,
formAIframeId,
formAIframeOrigin,
formAIframePlacements,
formModeForRuntime,
resolveFormAIframe,
resolveFormMode,
} from '../src/utils/form-integration.ts';
const isolated = (overrides = {}) => ({
rawMode: 'isolated-test',
liveApproved: 'false',
isolatedTestApproved: 'true',
environmentRole: 'isolated-test',
allowIndexing: 'false',
route: '/contact',
locale: 'en',
...overrides,
});
test('Form A iframe uses only fixed, approved route parameters', () => {
assert.equal(formAIframeOrigin, 'https://form.jotform.com');
assert.equal(formAIframeId, '262946078314059');
assert.equal(
buildFormAIframeUrl('en', 'contact'),
'https://form.jotform.com/262946078314059?formContext=contact&language=en',
);
assert.equal(
buildFormAIframeUrl('es', 'contact'),
'https://form.jotform.com/262946078314059?formContext=contact&language=es',
);
assert.equal(
buildFormAIframeUrl('en', 'landing'),
'https://form.jotform.com/262946078314059?formContext=landing&language=en',
);
assert.deepEqual(formAIframePlacements.map((placement) => placement.route), [
'/contact',
'/es/contact',
'/lp/aba-therapy',
'/lp/aba-insurance',
'/lp/aba-ahcccs',
'/lp/aba-private-pay',
'/lp/early-intervention',
]);
});
test('Form A iframe requires every isolated-test gate and refuses live mode', () => {
const enabled = resolveFormAIframe(isolated());
assert.equal(enabled.enabled, true);
assert.equal(enabled.reason, 'enabled');
assert.equal(enabled.title, 'AIA general enquiries form');
assert.equal(resolveFormAIframe(isolated({ rawMode: undefined })).reason, 'mode-not-isolated-test');
assert.equal(resolveFormAIframe(isolated({ rawMode: 'mock' })).reason, 'mode-not-isolated-test');
assert.equal(resolveFormAIframe(isolated({ rawMode: 'live', liveApproved: 'true' })).reason, 'mode-not-isolated-test');
assert.equal(resolveFormAIframe(isolated({ isolatedTestApproved: 'false' })).reason, 'isolated-test-not-approved');
assert.equal(resolveFormAIframe(isolated({ environmentRole: 'staging' })).reason, 'invalid-environment-role');
assert.equal(resolveFormAIframe(isolated({ allowIndexing: 'true' })).reason, 'indexing-enabled');
assert.equal(resolveFormAIframe(isolated({ route: '/lp/early-intervention' })).url, 'https://form.jotform.com/262946078314059?formContext=landing&language=en');
assert.equal(resolveFormAIframe(isolated({ route: '/es/contact', locale: 'en' })).reason, 'locale-not-authorized');
assert.equal(resolveFormAIframe(isolated({ route: '/es/contact', locale: 'es' })).url, 'https://form.jotform.com/262946078314059?formContext=contact&language=es');
const campaign = resolveFormAIframe(isolated({ route: '/lp/aba-therapy' }));
assert.equal(campaign.url, 'https://form.jotform.com/262946078314059?formContext=landing&language=en');
assert.equal(campaign.context, 'landing');
assert.equal(formModeForRuntime(resolveFormMode('isolated-test', undefined)), 'off');
assert.equal(formModeForRuntime(resolveFormMode('live', 'true')), 'off');
});
test('Only the seven allowlisted placements can render the adapter, with no helper, tracking, or parent submission code', () => {
const contact = fs.readFileSync('src/components/pages/ContactPage.astro', 'utf8');
const adapter = fs.readFileSync('src/components/JotformIframe.astro', 'utf8');
const campaign = fs.readFileSync('src/components/campaign/ConsultationForm.astro', 'utf8');
const earlyIntervention = fs.readFileSync('src/components/campaign/EarlyInterventionPage.astro', 'utf8');
assert.match(contact, /resolveFormAIframe/);
assert.match(contact, /route = lang === 'es' \? '\/es\/contact' : '\/contact'/);
assert.match(contact, /JotformIframe/);
assert.match(campaign, /resolveFormAIframe/);
assert.match(campaign, /JotformIframe/);
assert.match(campaign, /variant="embedded"/);
assert.match(campaign, /\/lp\/aba-therapy/);
assert.match(campaign, /const iframeDescription = 'Use this form to request a conversation\. An AIA team member can explain the next steps for your family\.'/);
assert.match(campaign, /description=\{iframeDescription\}/);
assert.doesNotMatch(campaign, /description=\{intro\}/);
assert.match(earlyIntervention, /resolveFormAIframe/);
assert.match(earlyIntervention, /route: '\/lp\/early-intervention'/);
assert.match(earlyIntervention, /JotformIframe/);
assert.match(adapter, /referrerpolicy="no-referrer"/);
assert.match(adapter, /sandbox="allow-forms allow-scripts allow-same-origin"/);
assert.match(adapter, /const fallbackMarkup = `<p class="jotform-iframe__fallback">/);
assert.match(adapter, /set:html=\{fallbackMarkup\}/);
assert.match(adapter, /escapeHtml\(config\.url\)/);
assert.doesNotMatch(adapter, /<\/h3>\s*(?:\{description[^\n]*\}\s*)?<p class="jotform-iframe__fallback">/);
assert.match(adapter, /target="_blank" rel="noopener noreferrer"/);
assert.match(adapter, /--jotform-frame-height: 60rem/);
assert.match(adapter, /max-width: none;/);
assert.match(adapter, /width: 100%;/);
assert.match(adapter, /\.jotform-iframe--embedded \{\s*--jotform-frame-height: 42rem/);
assert.match(adapter, /\.jotform-iframe__frame \{\s*height: 68rem/);
assert.match(adapter, /\.jotform-iframe--embedded \.jotform-iframe__frame \{\s*height: 50rem/);
assert.doesNotMatch(adapter, /<script|onload=|postMessage|fetch\(|form\.submit|analytics|googletag/i);
assert.doesNotMatch(campaign, /262946078314059/);
});
test('Jotform Builder CSS retains the owner-reconciled theme overrides without external assets', () => {
const css = fs.readFileSync('integrations/jotform/aia-form-a.css', 'utf8');
for (const declaration of [
'background: #fcf9f5 !important',
'border: 1px solid #edeef3 !important',
'background: #ffbd59 !important',
'border: 2px solid #ffbd59 !important',
'border-color: #ff914d !important',
'color: #254080 !important',
]) assert.match(css, new RegExp(declaration.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
assert.match(css, /:focus-visible/);
assert.doesNotMatch(css, /https?:\/\/|@import|url\(/i);
});
+7
View File
@@ -39,6 +39,7 @@ function hasTerminalSlash(url) {
function unsafeSignals(html) {
const signals = [];
if (/<iframe\b[^>]*\bsrc=["'][^"']*jotform/i.test(html)) signals.push('active Jotform iframe');
if (/262946078314059/i.test(html)) signals.push('isolated-test Form A identifier');
if (/<script\b[^>]*\bsrc=["'][^"']*(?:jotform|googletagmanager|google-analytics|doubleclick)/i.test(html)) signals.push('active vendor tracking/form script');
if (/data-(?:form|forms)-mode=["']live["']/i.test(html)) signals.push('live form mode');
if (/api\.azinstitute4autism\.com/i.test(html)) signals.push('production API origin');
@@ -98,14 +99,20 @@ export async function verifyArtifact(root, mode = 'staging') {
if (secretSignals.length) errors.push(`unsafe artifact signals: ${JSON.stringify(secretSignals)}`);
const files = (await fg('**/*', { cwd: root, absolute: true, onlyFiles: true })).sort();
const formAResourceFiles = [];
const digest = createHash('sha256');
for (const file of files) {
const relative = path.relative(root, file).replaceAll(path.sep, '/');
if (/\.(?:html?|js|mjs|css|json|xml|txt)$/i.test(relative)) {
const contents = await fs.readFile(file, 'utf8');
if (/262946078314059/i.test(contents)) formAResourceFiles.push(relative);
}
digest.update(relative);
digest.update('\0');
digest.update(createHash('sha256').update(await fs.readFile(file)).digest('hex'));
digest.update('\n');
}
if (formAResourceFiles.length) errors.push(`isolated-test Form A identifier appears in artifact: ${formAResourceFiles.join(', ')}`);
return {
mode,
htmlRoutes: htmlFiles.length,
+8
View File
@@ -49,6 +49,14 @@ test('artifact rejects live form mode and production API origin', async () => {
assert.ok(result.errors.some((error) => error.includes('unsafe artifact signals')));
});
test('artifact rejects the isolated-test Form A identifier in any shipped text asset', async () => {
const root = await fixture('staging');
await fs.writeFile(path.join(root, 'assets.js'), 'https://form.jotform.com/262946078314059?formContext=contact');
const result = await verifyArtifact(root, 'staging');
assert.equal(result.passed, false);
assert.ok(result.errors.some((error) => error.includes('isolated-test Form A identifier')));
});
test('artifact rejects root-relative URLs with terminal slashes', async () => {
const root = await fixture('staging');
await fs.appendFile(path.join(root, 'index.html'), '<a href="/lp/aba-therapy/">Campaign</a>');
+4 -1
View File
@@ -51,7 +51,10 @@ test('form mapping covers nine native instances and five landing journeys', () =
assert.equal(logicalFormForRoute('/contact'), 'general');
assert.equal(logicalFormForRoute('/es/client-consultation'), 'service');
assert.equal(logicalFormForRoute('/referrals'), 'referral');
assert.equal(logicalFormForRoute('/lp/early-intervention'), 'service');
for (const route of ['/lp/aba-therapy', '/lp/aba-insurance', '/lp/aba-ahcccs', '/lp/aba-private-pay']) {
assert.equal(logicalFormForRoute(route), 'general');
}
assert.equal(logicalFormForRoute('/lp/early-intervention'), 'general');
assert.equal(logicalFormForRoute('/ar/contact'), undefined);
});