diff --git a/cmd/internal-tools/bundle-check/main_test.go b/cmd/internal-tools/bundle-check/main_test.go index b963556..a69cceb 100644 --- a/cmd/internal-tools/bundle-check/main_test.go +++ b/cmd/internal-tools/bundle-check/main_test.go @@ -1,8 +1,10 @@ package main import ( + "bytes" "os" "path/filepath" + "strings" "testing" ) @@ -55,3 +57,55 @@ func TestBundleSpec_ResolvesSpecAliases(t *testing.T) { t.Errorf("unstable bundle hash: %s vs %s", result.SHA256, second.SHA256) } } + +func testdataSpec(t *testing.T, name string) string { + t.Helper() + path, err := filepath.Abs(filepath.Join("testdata", name)) + if err != nil { + t.Fatal(err) + } + return path +} + +func TestCheck_RejectsSpecThatRegistersNoProperties(t *testing.T) { + var stdout bytes.Buffer + err := check(repoSpecSrc(t), testdataSpec(t, "no-properties.ts"), &stdout) + if err == nil { + t.Fatal("a spec registering zero properties passed the gate: a run against it reports no violations while checking nothing") + } + if !strings.Contains(err.Error(), "registers no properties") { + t.Errorf("failure must name the missing registration, got: %v", err) + } + if !strings.Contains(stdout.String(), "bundled: ") { + t.Errorf("bundle size and hash must still be reported for a spec awaiting its properties, got: %q", stdout.String()) + } +} + +func TestCheck_ReportsRegisteredPropertyCountAndNames(t *testing.T) { + var stdout bytes.Buffer + if err := check(repoSpecSrc(t), testdataSpec(t, "spec.ts"), &stdout); err != nil { + t.Fatalf("check: %v", err) + } + if !strings.Contains(stdout.String(), "properties registered: 1 (noUncaughtExceptions)") { + t.Errorf("expected the registered count and name, got: %q", stdout.String()) + } +} + +// TestCheck_ReportsUnchangedBundleHash pins the reported bundle of a fixture +// that imports nothing, so the hash moves only when the bundler itself does. +// Frozen pre-registrations record these hashes, so bundle-check reporting a +// different bundle (the runtime-entry one, say) silently invalidates them. +func TestCheck_ReportsUnchangedBundleHash(t *testing.T) { + const ( + plainBytes = 57 + plainSHA256 = "bd757084b3f29c04c68ba2aa4c7b93e63b6dc6dd08ea3f726e0d1878be845888" + ) + result, err := bundleSpec(repoSpecSrc(t), testdataSpec(t, "plain.ts")) + if err != nil { + t.Fatal(err) + } + if len(result.JavaScript) != plainBytes || result.SHA256 != plainSHA256 { + t.Errorf("reported bundle changed: %d bytes sha256=%s, want %d bytes sha256=%s", + len(result.JavaScript), result.SHA256, plainBytes, plainSHA256) + } +} diff --git a/cmd/internal-tools/bundle-check/testdata/no-properties.ts b/cmd/internal-tools/bundle-check/testdata/no-properties.ts new file mode 100644 index 0000000..f9ce909 --- /dev/null +++ b/cmd/internal-tools/bundle-check/testdata/no-properties.ts @@ -0,0 +1,7 @@ +import { Tap, actions } from "@sanderling/spec"; + +export const properties = {}; +export const actionsRoot = actions((state) => { + const button = state.ax.find("desc:primary"); + return button ? [Tap({ on: button })] : []; +}); diff --git a/cmd/internal-tools/bundle-check/testdata/plain.ts b/cmd/internal-tools/bundle-check/testdata/plain.ts new file mode 100644 index 0000000..64a32fd --- /dev/null +++ b/cmd/internal-tools/bundle-check/testdata/plain.ts @@ -0,0 +1 @@ +export const answer = 42;