209 lines
6.0 KiB
JavaScript
209 lines
6.0 KiB
JavaScript
const fs = require("fs");
|
|
const path = require("path");
|
|
const vm = require("vm");
|
|
|
|
const scriptPath = path.join(__dirname, "script.js");
|
|
const scriptSource = fs.readFileSync(scriptPath, "utf8");
|
|
|
|
function createClassList() {
|
|
const values = new Set();
|
|
return {
|
|
toggle(name, enabled) {
|
|
if (enabled) values.add(name);
|
|
else values.delete(name);
|
|
},
|
|
has(name) {
|
|
return values.has(name);
|
|
},
|
|
};
|
|
}
|
|
|
|
function createForm(valid, entries) {
|
|
const listeners = {};
|
|
let resetCount = 0;
|
|
return {
|
|
__entries: entries,
|
|
reportValidity() {
|
|
return valid;
|
|
},
|
|
reset() {
|
|
resetCount += 1;
|
|
},
|
|
get resetCount() {
|
|
return resetCount;
|
|
},
|
|
addEventListener(type, handler) {
|
|
listeners[type] = handler;
|
|
},
|
|
dispatch(type, event) {
|
|
if (!listeners[type]) throw new Error(`missing listener: ${type}`);
|
|
return listeners[type](event);
|
|
},
|
|
};
|
|
}
|
|
|
|
function createButton() {
|
|
const listeners = {};
|
|
return {
|
|
addEventListener(type, handler) {
|
|
listeners[type] = handler;
|
|
},
|
|
dispatch(type, event) {
|
|
if (!listeners[type]) throw new Error(`missing listener: ${type}`);
|
|
return listeners[type](event);
|
|
},
|
|
};
|
|
}
|
|
|
|
function createEnv({ valid = true, fetchOk = true, clipboardFails = false } = {}) {
|
|
const timers = [];
|
|
const output = { textContent: "", classList: createClassList() };
|
|
const heroAnimation = {
|
|
src: "./squaremcp_launch.gif",
|
|
dataset: {
|
|
posterSrc: "./squaremcp_launch_poster.png",
|
|
playMs: "9600",
|
|
},
|
|
};
|
|
const entries = [
|
|
["name", "Casey"],
|
|
["email", "casey@example.com"],
|
|
["company", "SquareMCP Labs"],
|
|
["role", "Founder"],
|
|
["use_case", "Internal support copilot"],
|
|
["timeline", "Within 2 weeks"],
|
|
["systems", "Postgres, internal REST APIs"],
|
|
["requirements", "Audit logs and SSO"],
|
|
];
|
|
const form = createForm(valid, entries);
|
|
const button = createButton();
|
|
const fetchCalls = [];
|
|
let clipboardText = null;
|
|
|
|
const context = {
|
|
console,
|
|
window: {
|
|
setTimeout(fn, ms) {
|
|
timers.push({ fn, ms });
|
|
return timers.length;
|
|
},
|
|
},
|
|
document: {
|
|
getElementById(id) {
|
|
if (id === "pilotIntakeForm") return form;
|
|
if (id === "pilotOutput") return output;
|
|
if (id === "copyRequestButton") return button;
|
|
if (id === "heroAnimation") return heroAnimation;
|
|
return null;
|
|
},
|
|
},
|
|
navigator: {
|
|
clipboard: {
|
|
async writeText(value) {
|
|
if (clipboardFails) throw new Error("clipboard denied");
|
|
clipboardText = value;
|
|
},
|
|
},
|
|
},
|
|
fetch: async (url, options) => {
|
|
fetchCalls.push({ url, options });
|
|
if (!fetchOk) {
|
|
return {
|
|
ok: false,
|
|
status: 500,
|
|
async json() {
|
|
return { error: "submit failed" };
|
|
},
|
|
};
|
|
}
|
|
return {
|
|
ok: true,
|
|
status: 201,
|
|
async json() {
|
|
return { ok: true, request_id: "req-123" };
|
|
},
|
|
};
|
|
},
|
|
FormData: class MockFormData {
|
|
constructor(target) {
|
|
this.target = target;
|
|
}
|
|
entries() {
|
|
return this.target.__entries[Symbol.iterator]();
|
|
}
|
|
[Symbol.iterator]() {
|
|
return this.entries();
|
|
}
|
|
},
|
|
};
|
|
|
|
vm.createContext(context);
|
|
vm.runInContext(scriptSource, context, { filename: "script.js" });
|
|
|
|
return {
|
|
form,
|
|
button,
|
|
output,
|
|
heroAnimation,
|
|
timers,
|
|
fetchCalls,
|
|
getClipboardText: () => clipboardText,
|
|
};
|
|
}
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
async function run() {
|
|
const validEnv = createEnv();
|
|
assert(validEnv.timers.length === 1, "hero animation timer missing");
|
|
assert(validEnv.timers[0].ms === 9600, "hero animation timer mismatch");
|
|
validEnv.timers[0].fn();
|
|
assert(validEnv.heroAnimation.src === "./squaremcp_launch_poster.png", "hero poster swap failed");
|
|
|
|
let prevented = false;
|
|
await validEnv.form.dispatch("submit", {
|
|
preventDefault() {
|
|
prevented = true;
|
|
},
|
|
});
|
|
assert(prevented, "submit did not prevent default");
|
|
assert(validEnv.fetchCalls.length === 1, "submit did not call fetch");
|
|
assert(validEnv.fetchCalls[0].url === "/api/pilot-request", "submit endpoint mismatch");
|
|
assert(validEnv.fetchCalls[0].options.method === "POST", "submit method mismatch");
|
|
const payload = JSON.parse(validEnv.fetchCalls[0].options.body);
|
|
assert(payload.company === "SquareMCP Labs", "submit payload mismatch");
|
|
assert(validEnv.form.resetCount === 1, "form did not reset after success");
|
|
assert(validEnv.output.textContent.includes("Saved to SquareMCP intake successfully."), "submit success message missing");
|
|
assert(validEnv.output.classList.has("ready"), "submit did not set ready class");
|
|
|
|
await validEnv.button.dispatch("click", {});
|
|
assert(validEnv.getClipboardText().includes("SquareMCP Labs"), "copy handler did not write clipboard");
|
|
assert(validEnv.output.textContent.includes("Copied to clipboard."), "copy success message missing");
|
|
|
|
const invalidEnv = createEnv({ valid: false });
|
|
await invalidEnv.form.dispatch("submit", { preventDefault() {} });
|
|
assert(invalidEnv.fetchCalls.length === 0, "invalid submit should not call fetch");
|
|
assert(invalidEnv.output.textContent === "", "invalid submit should not update output");
|
|
|
|
const failureEnv = createEnv({ fetchOk: false });
|
|
await failureEnv.form.dispatch("submit", { preventDefault() {} });
|
|
assert(failureEnv.output.textContent.includes("Submission failed."), "submit failure message missing");
|
|
assert(failureEnv.form.resetCount === 0, "failed submit should not reset form");
|
|
|
|
const clipboardFailureEnv = createEnv({ clipboardFails: true });
|
|
await clipboardFailureEnv.button.dispatch("click", {});
|
|
assert(
|
|
clipboardFailureEnv.output.textContent.includes("Clipboard access failed."),
|
|
"clipboard failure message missing"
|
|
);
|
|
|
|
console.log("squaremcp product site smoke test: PASS");
|
|
}
|
|
|
|
run().catch((error) => {
|
|
console.error(`squaremcp product site smoke test: FAIL: ${error.message}`);
|
|
process.exit(1);
|
|
});
|