@hubspot/ui-extensions-dev-server 1.0.2 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -253,4 +253,93 @@ describe('devBuildPlugin', () => {
253
253
  }).not.toThrow();
254
254
  });
255
255
  });
256
+ describe('handleBuildError', () => {
257
+ it('should not crash if websocket is not initialized during configureServer', async () => {
258
+ // Remove the websocket to simulate it not being initialized yet
259
+ // @ts-expect-error Setting private property for testing
260
+ options.devServerState._mutableState.extensionsWebSocket = null;
261
+ const error = {
262
+ plugin: 'vite:esbuild',
263
+ errors: ['build error'],
264
+ frame: 'Error on this line',
265
+ loc: { column: 1, line: 5 },
266
+ id: 'src/file.ts',
267
+ };
268
+ vi.mocked(build).mockImplementationOnce(() => {
269
+ throw error;
270
+ });
271
+ // Should not throw even though websocket doesn't exist
272
+ await expect(
273
+ // @ts-expect-error TS thinks this isn't a function
274
+ plugin.configureServer(server)).resolves.not.toThrow();
275
+ // Verify broadcast was NOT called (since websocket doesn't exist)
276
+ expect(mockWebSocket.broadcast).not.toHaveBeenCalled();
277
+ });
278
+ it('should broadcast error when websocket exists and browser connects', async () => {
279
+ // Websocket is already set up in beforeEach
280
+ const error = {
281
+ plugin: 'vite:esbuild',
282
+ errors: ['build error'],
283
+ frame: 'Error on this line',
284
+ loc: { column: 1, line: 5 },
285
+ id: 'src/file.ts',
286
+ };
287
+ vi.mocked(build).mockImplementationOnce(() => {
288
+ throw error;
289
+ });
290
+ // @ts-expect-error TS thinks this isn't a function
291
+ await plugin.configureServer(server);
292
+ options.devServerState.triggerWebSocketSetup();
293
+ // Get the connection handler
294
+ const connectionHandler = mockWebSocket.onConnection.mock.calls[0][0];
295
+ // Simulate browser connection - should broadcast the stored error
296
+ connectionHandler();
297
+ expect(mockWebSocket.broadcast).toHaveBeenCalledWith(expect.objectContaining({
298
+ event: 'error',
299
+ error: expect.objectContaining({
300
+ details: expect.objectContaining({
301
+ file: error.id,
302
+ }),
303
+ }),
304
+ }));
305
+ });
306
+ it('should broadcast error after websocket is initialized and browser connects', async () => {
307
+ // Remove the websocket to simulate it not being initialized yet
308
+ // @ts-expect-error Setting private property for testing
309
+ options.devServerState._mutableState.extensionsWebSocket = null;
310
+ const error = {
311
+ plugin: 'vite:esbuild',
312
+ errors: ['build error'],
313
+ frame: 'Error on this line',
314
+ loc: { column: 1, line: 5 },
315
+ id: 'src/file.ts',
316
+ };
317
+ vi.mocked(build).mockImplementationOnce(() => {
318
+ throw error;
319
+ });
320
+ // configureServer runs with error, but websocket doesn't exist yet
321
+ // @ts-expect-error TS thinks this isn't a function
322
+ await plugin.configureServer(server);
323
+ // At this point, broadcast should not have been called
324
+ expect(mockWebSocket.broadcast).not.toHaveBeenCalled();
325
+ // Now initialize the websocket (simulating what happens in server.ts)
326
+ // @ts-expect-error Setting private property for testing
327
+ options.devServerState._mutableState.extensionsWebSocket =
328
+ mockWebSocket;
329
+ // Trigger the websocket setup callback
330
+ options.devServerState.triggerWebSocketSetup();
331
+ // Get the connection handler
332
+ const connectionHandler = mockWebSocket.onConnection.mock.calls[0][0];
333
+ // Simulate browser connection - should NOW broadcast the stored error
334
+ connectionHandler();
335
+ expect(mockWebSocket.broadcast).toHaveBeenCalledWith(expect.objectContaining({
336
+ event: 'error',
337
+ error: expect.objectContaining({
338
+ details: expect.objectContaining({
339
+ file: error.id,
340
+ }),
341
+ }),
342
+ }));
343
+ });
344
+ });
256
345
  });
@@ -59,7 +59,7 @@ describe('friendlyLoggingPlugin', () => {
59
59
  });
60
60
  expect(result).toBe(false);
61
61
  expect(logger.error).toHaveBeenCalledTimes(1);
62
- expect(logger.error).toHaveBeenCalledWith('@hubspot/extensions is imported by import.jsx, but @hubspot/extensions cannot be resolved. Make sure @hubspot/extensions is installed.');
62
+ expect(logger.error).toHaveBeenCalledWith('@hubspot/extensions is imported by import.jsx, but @hubspot/extensions cannot be resolved. Make sure @hubspot/extensions is installed by running `hs project install-deps`.');
63
63
  });
64
64
  });
65
65
  });
@@ -4,7 +4,7 @@ const unfriendlyCodeMapper = Object.freeze({
4
4
  const { exporter, id } = loggable;
5
5
  const { base: extension } = path.parse(id);
6
6
  return {
7
- message: `${exporter} is imported by ${extension}, but ${exporter} cannot be resolved. Make sure ${exporter} is installed.`,
7
+ message: `${exporter} is imported by ${extension}, but ${exporter} cannot be resolved. Make sure ${exporter} is installed by running \`hs project install-deps\`.`,
8
8
  level: 'error',
9
9
  };
10
10
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/ui-extensions-dev-server",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "bin": {