11// @vitest -environment jsdom
22import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
3- import { loadModelContextPolyfill , resetModelContextPolyfillForTest } from "./polyfill" ;
43import type { ModelContext } from "./types" ;
54
65// The real package defines `document.modelContext` as an import side effect.
76// A mock cannot do that, so tests stand the object up themselves to represent
87// the import having happened.
8+ const trackEvent = vi . hoisted ( ( ) => vi . fn ( ) ) ;
99vi . mock ( "@mcp-b/global" , ( ) => ( { } ) ) ;
10+ vi . mock ( "../telemetry/client" , ( ) => ( { trackEvent } ) ) ;
11+
12+ let loadModelContextPolyfill : typeof import ( "./polyfill" ) . loadModelContextPolyfill ;
1013
1114function installModelContext ( ) : ModelContext {
1215 const modelContext : ModelContext = { registerTool : vi . fn ( ) . mockResolvedValue ( undefined ) } ;
@@ -18,8 +21,10 @@ function installModelContext(): ModelContext {
1821 return modelContext ;
1922}
2023
21- beforeEach ( ( ) => {
22- resetModelContextPolyfillForTest ( ) ;
24+ beforeEach ( async ( ) => {
25+ vi . resetModules ( ) ;
26+ ( { loadModelContextPolyfill } = await import ( "./polyfill" ) ) ;
27+ trackEvent . mockReset ( ) ;
2328} ) ;
2429
2530afterEach ( ( ) => {
@@ -32,6 +37,7 @@ describe("loadModelContextPolyfill", () => {
3237 const modelContext = installModelContext ( ) ;
3338
3439 await expect ( loadModelContextPolyfill ( ) ) . resolves . toBe ( modelContext ) ;
40+ expect ( trackEvent ) . toHaveBeenCalledWith ( "webmcp.polyfill_loaded" ) ;
3541 } ) ;
3642
3743 it ( "shares one load between callers that race" , async ( ) => {
@@ -57,16 +63,36 @@ describe("loadModelContextPolyfill", () => {
5763
5864 it ( "returns null when the package loads but defines nothing" , async ( ) => {
5965 // Studio must still boot. A missing agent surface is not a broken editor.
60- await expect ( loadModelContextPolyfill ( ) ) . resolves . toBeNull ( ) ;
66+ const first = loadModelContextPolyfill ( ) ;
67+ await expect ( first ) . resolves . toBeNull ( ) ;
68+
69+ expect ( trackEvent ) . toHaveBeenCalledWith ( "webmcp.polyfill_failed" , {
70+ error_name : "ModelContextMissingError" ,
71+ } ) ;
72+ const retry = loadModelContextPolyfill ( ) ;
73+ expect ( retry ) . not . toBe ( first ) ;
74+ await expect ( retry ) . resolves . toBeNull ( ) ;
6175 } ) ;
6276
63- it ( "starts a fresh load after the test seam resets it" , async ( ) => {
64- installModelContext ( ) ;
65- const first = loadModelContextPolyfill ( ) ;
66- await first ;
77+ it ( "reports a polyfill failure and lets a later mount retry" , async ( ) => {
78+ const failure = new TypeError ( "blocked by policy" ) ;
79+ Object . defineProperty ( document , "modelContext" , {
80+ configurable : true ,
81+ get : ( ) => {
82+ throw failure ;
83+ } ,
84+ } ) ;
6785
68- resetModelContextPolyfillForTest ( ) ;
86+ const first = loadModelContextPolyfill ( ) ;
87+ await expect ( first ) . resolves . toBeNull ( ) ;
88+ expect ( trackEvent ) . toHaveBeenCalledWith ( "webmcp.polyfill_failed" , {
89+ error_name : "TypeError" ,
90+ } ) ;
6991
70- expect ( loadModelContextPolyfill ( ) ) . not . toBe ( first ) ;
92+ Reflect . deleteProperty ( document , "modelContext" ) ;
93+ const modelContext = installModelContext ( ) ;
94+ const retry = loadModelContextPolyfill ( ) ;
95+ expect ( retry ) . not . toBe ( first ) ;
96+ await expect ( retry ) . resolves . toBe ( modelContext ) ;
7197 } ) ;
7298} ) ;
0 commit comments