mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
test: real-Chrome and CI smoke pages inline GSAP so they wait on no CDN (#6406)
* test(studio): real-Chrome tests inline GSAP so their page waits on no request * test(ci): smoke projects inline GSAP so required checks wait on no CDN
This commit is contained in:
@@ -1467,6 +1467,9 @@ jobs:
|
||||
--non-interactive \
|
||||
--skip-skills
|
||||
|
||||
# No smoke page waits on a CDN for GSAP.
|
||||
node scripts/ci/inline-gsap.mjs /tmp/hf-cli-inside
|
||||
|
||||
bun run --filter @hyperframes/cli dev -- lint /tmp/hf-cli-inside
|
||||
bun run --filter @hyperframes/cli dev -- validate /tmp/hf-cli-inside --timeout 3000
|
||||
bun run --filter @hyperframes/cli dev -- render /tmp/hf-cli-inside \
|
||||
@@ -1532,6 +1535,9 @@ jobs:
|
||||
--non-interactive \
|
||||
--skip-skills
|
||||
|
||||
# No smoke page waits on a CDN for GSAP.
|
||||
node scripts/ci/inline-gsap.mjs /tmp/hf-cli-outside
|
||||
|
||||
hyperframes lint /tmp/hf-cli-outside
|
||||
hyperframes validate /tmp/hf-cli-outside --timeout 3000
|
||||
hyperframes render /tmp/hf-cli-outside \
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@
|
||||
"player:perf": "bun run --filter @hyperframes/player perf",
|
||||
"format:check": "oxfmt --check .",
|
||||
"knip": "knip",
|
||||
"test:scripts": "node --import tsx --test scripts/animejs-v4-guidance.test.mjs scripts/check-tracked-artifacts.test.mjs scripts/check-registry-set-delta.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-pr-captures.test.mjs scripts/check-comment-citations.test.mjs scripts/comments-workflow.test.mjs scripts/comment-ratchet.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-media-use-copy-parity.test.mjs scripts/check-svg-sanitize-parity.test.mjs scripts/check-media-use-svg-sanitize-generated.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/check-cli-lazy-deps.test.mjs scripts/file-url-paths.test.mjs scripts/check-studio-copy-dashes.test.mjs scripts/check-large-files.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/clawhub-sync.test.mjs scripts/clawhub-unlist-retired.test.mjs scripts/publish-workflow.test.mjs scripts/pr-edit-concurrency.test.mjs scripts/merge-queue-workflows.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/check-edit-accuracy-filter.test.mjs scripts/edit-accuracy-retry.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/catalog-payload-assets.test.ts scripts/host-registry-assets.test.ts scripts/catalog-preview-temp.test.ts scripts/backfill-block-previews.test.ts scripts/catalog-hosted-files.test.ts scripts/player-cdn-pin.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/rewrite-relative-import-extensions.test.mjs scripts/lint-skills.test.mjs scripts/check-core-skills.test.mjs scripts/creator-editing-recipes.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs packages/core/scripts/writeGeneratedFile.test.ts scripts/catalog-publication.test.mjs scripts/ci/resolve-workflow-pr.test.mjs scripts/lefthook-order.test.mjs scripts/ci/flake-gate.test.mjs scripts/ci/base-file.test.mjs scripts/check-catalog-source-pr.test.mjs scripts/generate-registry-items.test.ts scripts/catalog-drift.test.ts scripts/catalog-fetch-mirror.test.ts scripts/catalog-script-inlining.test.ts scripts/catalog-detail.test.ts scripts/generate-catalog-pages.test.ts scripts/verify-catalog-payloads.test.ts scripts/registry-theme-fallbacks.test.ts scripts/registry-skill-files.test.ts scripts/creator-editing-capabilities.test.mjs scripts/generate-catalog-previews.test.ts scripts/registry-primitive-payloads.test.ts registry/components/pan-stations/pan-stations.test.mjs registry/components/filmed-screen/filmed-screen.test.mjs registry/components/echo-smear/echo-smear.test.mjs && vitest run scripts/catalog/ scripts/contrastRatchet.test.ts scripts/generate-catalog-payloads.test.ts",
|
||||
"test:scripts": "node --import tsx --test scripts/animejs-v4-guidance.test.mjs scripts/check-tracked-artifacts.test.mjs scripts/check-registry-set-delta.test.mjs scripts/check-no-main-deletions.test.mjs scripts/check-pr-captures.test.mjs scripts/check-comment-citations.test.mjs scripts/comments-workflow.test.mjs scripts/comment-ratchet.test.mjs scripts/check-docs-snippet-motion.test.mjs scripts/registry-target-paths.test.mjs scripts/check-workspace-contracts.test.mjs scripts/check-media-use-copy-parity.test.mjs scripts/check-svg-sanitize-parity.test.mjs scripts/check-media-use-svg-sanitize-generated.test.mjs scripts/check-package-cycles.test.mjs scripts/check-cli-process-ownership.test.mjs scripts/check-cli-lazy-deps.test.mjs scripts/file-url-paths.test.mjs scripts/check-studio-copy-dashes.test.mjs scripts/check-large-files.test.mjs scripts/package-subpaths.test.mjs scripts/validate-release-channel.test.mjs scripts/clawhub-sync.test.mjs scripts/clawhub-unlist-retired.test.mjs scripts/publish-workflow.test.mjs scripts/pr-edit-concurrency.test.mjs scripts/merge-queue-workflows.test.mjs scripts/install-workspace-dependencies.test.mjs scripts/check-edit-accuracy-filter.test.mjs scripts/edit-accuracy-retry.test.mjs scripts/draft-changelog.test.ts scripts/set-version.test.ts scripts/release-prepare.test.ts scripts/cli-options.test.ts scripts/changelog-weekly.test.ts scripts/claude-plugin-compression.test.ts scripts/catalog-payload-assets.test.ts scripts/host-registry-assets.test.ts scripts/catalog-preview-temp.test.ts scripts/backfill-block-previews.test.ts scripts/catalog-hosted-files.test.ts scripts/player-cdn-pin.test.ts scripts/studio-runtime-smoke.test.mjs scripts/verify-packed-manifests.test.mjs scripts/rewrite-relative-import-extensions.test.mjs scripts/lint-skills.test.mjs scripts/check-core-skills.test.mjs scripts/creator-editing-recipes.test.mjs packages/gcp-cloud-run/check-dockerfile-workspaces.test.mjs packages/core/scripts/writeGeneratedFile.test.ts scripts/catalog-publication.test.mjs scripts/ci/resolve-workflow-pr.test.mjs scripts/lefthook-order.test.mjs scripts/inline-gsap.test.mjs scripts/ci/flake-gate.test.mjs scripts/ci/base-file.test.mjs scripts/check-catalog-source-pr.test.mjs scripts/generate-registry-items.test.ts scripts/catalog-drift.test.ts scripts/catalog-fetch-mirror.test.ts scripts/catalog-script-inlining.test.ts scripts/catalog-detail.test.ts scripts/generate-catalog-pages.test.ts scripts/verify-catalog-payloads.test.ts scripts/registry-theme-fallbacks.test.ts scripts/registry-skill-files.test.ts scripts/creator-editing-capabilities.test.mjs scripts/generate-catalog-previews.test.ts scripts/registry-primitive-payloads.test.ts registry/components/pan-stations/pan-stations.test.mjs registry/components/filmed-screen/filmed-screen.test.mjs registry/components/echo-smear/echo-smear.test.mjs && vitest run scripts/catalog/ scripts/contrastRatchet.test.ts scripts/generate-catalog-payloads.test.ts",
|
||||
"typecheck:scripts": "tsc --noEmit -p scripts/tsconfig.json",
|
||||
"test:skills": "HYPERFRAMES_MEDIA_HOME_REQUIRED=1 node --import ./packages/cli/scripts/test-home.mjs --test 'skills/**/*.test.mjs' 'packages/cli/src/media-use/**/*.test.mjs'",
|
||||
"generate:previews": "tsx scripts/generate-template-previews.ts",
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { expect, it, vi } from "vitest";
|
||||
import { closeTestChrome, launchTestChrome, showWithRuntime } from "./chromeTestUtils";
|
||||
|
||||
vi.setConfig({ testTimeout: 60_000 });
|
||||
|
||||
it("shows a page that names the GSAP CDN script without the page making a request", async () => {
|
||||
const browser = await launchTestChrome();
|
||||
try {
|
||||
const tab = await browser.newPage();
|
||||
const requests: string[] = [];
|
||||
tab.on("request", (request) => requests.push(request.url()));
|
||||
await showWithRuntime(
|
||||
tab,
|
||||
`<!doctype html><html><body>
|
||||
<div id="root" data-composition-id="main" data-start="0" data-duration="1" data-width="640" data-height="360"></div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<script>window.__timelines = window.__timelines || {}; window.__timelines["main"] = gsap.timeline({ paused: true });</script>
|
||||
</body></html>`,
|
||||
);
|
||||
expect(await tab.evaluate(() => typeof (window as unknown as { gsap?: object }).gsap)).toBe(
|
||||
"object",
|
||||
);
|
||||
expect(requests).toEqual([]);
|
||||
} finally {
|
||||
await closeTestChrome(browser);
|
||||
}
|
||||
});
|
||||
@@ -67,15 +67,16 @@ export async function closeTestChrome(
|
||||
await browser.disconnect().catch(() => undefined);
|
||||
}
|
||||
|
||||
/** Shows `html` with the HyperFrames runtime; only its GSAP CDN script is served, nothing is fetched. */
|
||||
const GSAP_CDN_TAG = /<script src="[^"]*\/gsap\.min\.js"><\/script>/;
|
||||
|
||||
/** Shows `html` with the HyperFrames runtime. Its GSAP CDN script tag is replaced by the script itself, so the
|
||||
* page makes no request at all and `load` waits on nothing outside the page. */
|
||||
export async function showWithRuntime(page: Page, html: string): Promise<void> {
|
||||
await page.setRequestInterception(true);
|
||||
page.on("request", (request) =>
|
||||
request.url().endsWith("/gsap.min.js")
|
||||
? request.respond({ body: readFileSync(require.resolve("gsap/dist/gsap.min.js"), "utf8") })
|
||||
: request.abort("blockedbyclient"),
|
||||
const gsap = readFileSync(require.resolve("gsap/dist/gsap.min.js"), "utf8");
|
||||
await page.setContent(
|
||||
html.replace(GSAP_CDN_TAG, () => `<script>${gsap}</script>`),
|
||||
{ waitUntil: "load" },
|
||||
);
|
||||
await page.setContent(html, { waitUntil: "load" });
|
||||
await page.evaluate(readFileSync(require.resolve("@hyperframes/core/runtime"), "utf8"));
|
||||
await page.waitForFunction(() => "__player" in window);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env node
|
||||
// inline-gsap.mjs <project dir>: puts GSAP into the project's html in place of its CDN script tags,
|
||||
// so a smoke test's page never waits on the network. Fails when no tag is found, so a template change is noticed.
|
||||
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const GSAP_TAG = /<script src="[^"]*\/gsap\.min\.js"><\/script>/g;
|
||||
|
||||
export const inlineGsap = (html, gsap) => html.replace(GSAP_TAG, () => `<script>${gsap}</script>`);
|
||||
|
||||
function htmlFiles(dir) {
|
||||
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
||||
const path = join(dir, entry.name);
|
||||
if (entry.isDirectory()) return entry.name === "node_modules" ? [] : htmlFiles(path);
|
||||
return entry.name.endsWith(".html") ? [path] : [];
|
||||
});
|
||||
}
|
||||
|
||||
export function inlineGsapInProject(dir, gsap) {
|
||||
let tags = 0;
|
||||
for (const file of htmlFiles(dir)) {
|
||||
const html = readFileSync(file, "utf8");
|
||||
const next = inlineGsap(html, gsap);
|
||||
if (next === html) continue;
|
||||
tags += html.match(GSAP_TAG).length;
|
||||
writeFileSync(file, next);
|
||||
}
|
||||
if (tags === 0) throw new Error(`no GSAP CDN script tag found under ${dir}`);
|
||||
return tags;
|
||||
}
|
||||
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
||||
const gsapPath = createRequire(join(root, "packages", "core", "package.json")).resolve(
|
||||
"gsap/dist/gsap.min.js",
|
||||
);
|
||||
const tags = inlineGsapInProject(resolve(process.argv[2]), readFileSync(gsapPath, "utf8"));
|
||||
console.log(`inlined GSAP into ${tags} script tag(s)`);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { test } from "node:test";
|
||||
import { inlineGsap, inlineGsapInProject } from "./ci/inline-gsap.mjs";
|
||||
|
||||
const TAG = '<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>';
|
||||
|
||||
test("a GSAP CDN tag becomes the script itself and other tags stay", () => {
|
||||
const html = `<head>${TAG}<script src="https://example.com/other.js"></script></head>`;
|
||||
const out = inlineGsap(html, "var gsap=1;");
|
||||
assert.equal(
|
||||
out,
|
||||
'<head><script>var gsap=1;</script><script src="https://example.com/other.js"></script></head>',
|
||||
);
|
||||
});
|
||||
|
||||
test("every html file of a project is rewritten, and a project with no tag fails", () => {
|
||||
const dir = mkdtempSync(join(tmpdir(), "inline-gsap-"));
|
||||
try {
|
||||
mkdirSync(join(dir, "compositions"));
|
||||
writeFileSync(join(dir, "index.html"), `<body>${TAG}</body>`);
|
||||
writeFileSync(join(dir, "compositions", "a.html"), `<template>${TAG}</template>`);
|
||||
assert.equal(inlineGsapInProject(dir, "G;"), 2);
|
||||
assert.equal(readFileSync(join(dir, "index.html"), "utf8"), "<body><script>G;</script></body>");
|
||||
assert.throws(() => inlineGsapInProject(dir, "G;"), /no GSAP CDN script tag/);
|
||||
} finally {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user