135 lines
8.1 KiB
JavaScript
135 lines
8.1 KiB
JavaScript
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 expected = [
|
|
['/contact', 'en', 'contact'], ['/es/contact', 'es', 'contact'],
|
|
...['aba-therapy','aba-insurance','aba-ahcccs','aba-private-pay','early-intervention'].map(s => ['/lp/' + s, 'en', 'landing']),
|
|
['/client-consultation', 'en', 'consultation'], ['/es/client-consultation', 'es', 'consultation'], ['/schedule-consultation', 'en', 'consultation'],
|
|
...['en','es'].flatMap(lang => ['aba-therapy','autism-evaluations','learner-social-club'].map(s => [(lang === 'es' ? '/es/' : '/') + s, lang, 'consultation'])),
|
|
];
|
|
|
|
test('default and explicit live enable exactly sixteen fixed route/locale/context placements', () => {
|
|
assert.equal(formAIframeOrigin, 'https://form.jotform.com');
|
|
assert.equal(formAIframeId, '262946078314059');
|
|
assert.deepEqual(formAIframePlacements.map(p => [p.route,p.locale,p.context]), expected);
|
|
assert.equal(new Set(formAIframePlacements.map(p => p.route)).size, 16);
|
|
for (const rawMode of [undefined, '', ' ', 'live', 'LIVE']) for (const [route, locale, context] of expected) {
|
|
const config = resolveFormAIframe({ rawMode, route, locale });
|
|
assert.equal(config.enabled, true, route);
|
|
assert.equal(config.context, context);
|
|
assert.equal(config.mode, 'live');
|
|
assert.equal(config.url, `https://form.jotform.com/262946078314059?formContext=${context}&language=${locale}`);
|
|
assert.equal(formModeForRuntime(resolveFormMode(rawMode)), 'off', 'native surfaces remain inactive');
|
|
}
|
|
});
|
|
|
|
test('invalid and obsolete mode values fail clearly instead of silently disabling forms', () => {
|
|
for (const rawMode of ['isolated-test', 'production', 'invalid', 'false']) {
|
|
assert.throws(() => resolveFormMode(rawMode), /PUBLIC_AIA_FORMS_MODE.*Remove.*live, off, or mock/);
|
|
assert.throws(() => resolveFormAIframe({ rawMode, route: '/contact', locale: 'en' }), /PUBLIC_AIA_FORMS_MODE/);
|
|
}
|
|
});
|
|
|
|
test('off and mock reject real frames on every approved placement', () => {
|
|
for (const rawMode of ['off', 'mock']) for (const [route, locale] of expected) {
|
|
const config = resolveFormAIframe({ rawMode, route, locale });
|
|
assert.equal(config.enabled, false);
|
|
assert.equal(config.url, undefined);
|
|
}
|
|
});
|
|
|
|
test('registry rejects unknown routes, mismatched locales and arbitrary URL parameters', () => {
|
|
for (const route of ['/referrals', '/tour', '/ar/contact', '/contact/', '/contact?formContext=landing', 'https://evil.invalid']) {
|
|
assert.equal(resolveFormAIframe({ rawMode: undefined, route, locale: 'en' }).reason, 'route-not-authorized');
|
|
}
|
|
for (const [route, locale] of expected) {
|
|
assert.equal(resolveFormAIframe({ rawMode: undefined, route, locale: locale === 'en' ? 'es' : 'en' }).reason, 'locale-not-authorized');
|
|
}
|
|
assert.throws(() => buildFormAIframeUrl('ar', 'contact'), /Unsupported/);
|
|
assert.throws(() => buildFormAIframeUrl('en', 'untrusted'), /Unsupported/);
|
|
});
|
|
|
|
test('EN/ES consultation and contact titles/fallbacks remain localized', () => {
|
|
const en = resolveFormAIframe({ rawMode: undefined, route: '/client-consultation', locale: 'en' });
|
|
const es = resolveFormAIframe({ rawMode: undefined, route: '/es/client-consultation', locale: 'es' });
|
|
assert.equal(en.title, 'AIA consultation form');
|
|
assert.equal(es.title, 'Formulario de consulta de AIA');
|
|
assert.equal(es.fallbackLinkText, 'abra el formulario de consulta en una pestaña nueva.');
|
|
assert.equal(resolveFormAIframe({rawMode: undefined,route:'/es/contact',locale:'es'}).fallbackText,'Si el formulario integrado no se carga,');
|
|
});
|
|
|
|
test('the shared adapter preserves layout, bilingual drawers, sandbox, fallback and dimensions', () => {
|
|
const contact = fs.readFileSync('src/components/pages/ContactPage.astro', 'utf8');
|
|
const adapter = fs.readFileSync('src/components/JotformIframe.astro', 'utf8');
|
|
const shell = fs.readFileSync('src/components/FormShell.astro', 'utf8');
|
|
const drawer = fs.readFileSync('src/components/ServiceInquiryDrawer.astro', 'utf8');
|
|
const layout = fs.readFileSync('src/layouts/PageLayout.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(shell, /resolveFormAIframe/);
|
|
assert.match(shell, /JotformIframe/);
|
|
assert.match(drawer, /lang: SupportedLocale/);
|
|
assert.match(drawer, /data-consultation-enabled/);
|
|
assert.match(drawer, /serviceCopy.heading/);
|
|
assert.match(drawer, /deferUntilActivated/);
|
|
assert.match(fs.readFileSync('src/scripts/service-inquiry.ts', 'utf8'), /aia:jotform-activate/);
|
|
assert.match(drawer, /Cerrar el formulario de consulta/);
|
|
assert.doesNotMatch(drawer, /No WAITLIST!|guarantee your child|now open for enrollment/i);
|
|
assert.match(layout, /entry\.data\.lang === 'en' \|\| entry\.data\.lang === 'es'/);
|
|
assert.match(adapter, /referrerpolicy="no-referrer"/);
|
|
assert.match(adapter, /sandbox="allow-forms allow-scripts allow-same-origin"/);
|
|
assert.match(adapter, /data-form-mode=\{config\.mode\}/);
|
|
assert.match(adapter, /data-jotform-iframe-frame/);
|
|
assert.match(adapter, /data-jotform-iframe-url/);
|
|
assert.match(adapter, /data-jotform-deferred/);
|
|
assert.match(adapter, /data-jotform-iframe-fallback hidden aria-live="polite" role="status"/);
|
|
assert.match(adapter, /<noscript>/);
|
|
assert.match(adapter, /fallbackTimeoutMs = 15_000/);
|
|
assert.match(adapter, /frame\.addEventListener\('load', onLoad, \{ once: true \}\)/);
|
|
assert.match(adapter, /document\.addEventListener\('astro:before-swap', dispose, \{ once: true \}\)/);
|
|
assert.match(adapter, /container\.addEventListener\('aia:jotform-activate'/);
|
|
assert.doesNotMatch(adapter, /set:html=|fallbackMarkup|escapeHtml\(/);
|
|
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.match(adapter, /\.jotform-iframe--drawer \{\s*--jotform-frame-height: 72rem/);
|
|
assert.match(adapter, /\.jotform-iframe--drawer \.jotform-iframe__frame \{\s*height: 82rem/);
|
|
assert.doesNotMatch(adapter, /for-form-embed-handler|jotformEmbedHandler|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);
|
|
});
|