44 * https://opensource.org/licenses/MIT.
55 */
66
7- import { describe , it , expect } from "vitest" ;
7+ import { describe , it , expect , vi } from "vitest" ;
88import { renderHook , act } from "@testing-library/react" ;
99import type { TopLevelSpec } from "vega-lite" ;
1010import { useSignalListeners } from "./useSignalListeners" ;
1111import { createChangeHandler } from "@/plugins/mui/common.test" ;
12+ import type { Result as VegaEmbedResult } from "vega-embed" ;
1213
1314const chart : TopLevelSpec = {
1415 $schema : "https://vega.github.io/schema/vega-lite/v6.json" ,
@@ -72,7 +73,7 @@ describe("useSignalListeners", () => {
7273 expect ( signalHandlers [ "sel_interval" ] ) . toBeTypeOf ( "function" ) ;
7374 expect ( signalHandlers [ "sel_point_a" ] ) . toBeTypeOf ( "function" ) ;
7475 // "wheel" not supported
75- expect ( signalHandlers [ "sel_point_b " ] ) . toBeUndefined ( ) ;
76+ expect ( signalHandlers [ "sel_interval_b " ] ) . toBeUndefined ( ) ;
7677 } ) ;
7778
7879 it ( "should call onChange" , ( ) => {
@@ -95,4 +96,99 @@ describe("useSignalListeners", () => {
9596 value : [ 1 , 2 , 3 ] ,
9697 } ) ;
9798 } ) ;
99+
100+ it ( "should register signal listeners on embed" , ( ) => {
101+ const { result } = renderHook ( ( ) =>
102+ useSignalListeners ( chartWithSelect , "VegaChart" , "my_chart" , ( ) => { } ) ,
103+ ) ;
104+
105+ const view = createMockView ( ) ;
106+
107+ act ( ( ) => {
108+ result . current . onEmbed ( { view } as unknown as VegaEmbedResult ) ;
109+ } ) ;
110+
111+ // Supported signals: sel_point, sel_interval, sel_point_a
112+ expect ( view . addSignalListener ) . toHaveBeenCalledTimes ( 3 ) ;
113+
114+ const names = view . addSignalListener . mock . calls . map ( ( [ name ] ) => name ) ;
115+ expect ( names ) . toEqual (
116+ expect . arrayContaining ( [ "sel_point" , "sel_interval" , "sel_point_a" ] ) ,
117+ ) ;
118+
119+ // Unsupported "wheel" should not be registered
120+ expect ( names ) . not . toContain ( "sel_interval_b" ) ;
121+ } ) ;
122+
123+ it ( "should remove old listeners when embedding again" , ( ) => {
124+ const { result } = renderHook ( ( ) =>
125+ useSignalListeners ( chartWithSelect , "VegaChart" , "my_chart" , ( ) => { } ) ,
126+ ) ;
127+
128+ const view1 = createMockView ( ) ;
129+ const view2 = createMockView ( ) ;
130+
131+ act ( ( ) => {
132+ result . current . onEmbed ( { view : view1 } as unknown as VegaEmbedResult ) ;
133+ } ) ;
134+
135+ const attachedToView1 = view1 . addSignalListener . mock . calls . map (
136+ ( [ name , fn ] ) => ( { name, fn } ) ,
137+ ) ;
138+
139+ act ( ( ) => {
140+ result . current . onEmbed ( { view : view2 } as unknown as VegaEmbedResult ) ;
141+ } ) ;
142+
143+ expect ( view1 . removeSignalListener ) . toHaveBeenCalledTimes (
144+ attachedToView1 . length ,
145+ ) ;
146+
147+ for ( const { name, fn } of attachedToView1 ) {
148+ expect ( view1 . removeSignalListener ) . toHaveBeenCalledWith ( name , fn ) ;
149+ }
150+
151+ expect ( view2 . addSignalListener ) . toHaveBeenCalledTimes ( 3 ) ;
152+ } ) ;
153+
154+ it ( "should cleanup listeners on unmount" , ( ) => {
155+ const { result, unmount } = renderHook ( ( ) =>
156+ useSignalListeners ( chartWithSelect , "VegaChart" , "my_chart" , ( ) => { } ) ,
157+ ) ;
158+
159+ const view = createMockView ( ) ;
160+
161+ act ( ( ) => {
162+ result . current . onEmbed ( { view } as unknown as VegaEmbedResult ) ;
163+ } ) ;
164+
165+ const attached = view . addSignalListener . mock . calls . map ( ( [ name , fn ] ) => ( {
166+ name,
167+ fn,
168+ } ) ) ;
169+
170+ unmount ( ) ;
171+
172+ expect ( view . removeSignalListener ) . toHaveBeenCalledTimes ( attached . length ) ;
173+ for ( const { name, fn } of attached ) {
174+ expect ( view . removeSignalListener ) . toHaveBeenCalledWith ( name , fn ) ;
175+ }
176+ } ) ;
177+
178+ it ( "should do nothing if embed result has no view" , ( ) => {
179+ const { result } = renderHook ( ( ) =>
180+ useSignalListeners ( chartWithSelect , "VegaChart" , "my_chart" , ( ) => { } ) ,
181+ ) ;
182+
183+ act ( ( ) => {
184+ result . current . onEmbed ( { } as unknown as VegaEmbedResult ) ;
185+ } ) ;
186+ } ) ;
98187} ) ;
188+
189+ function createMockView ( ) {
190+ return {
191+ addSignalListener : vi . fn ( ) ,
192+ removeSignalListener : vi . fn ( ) ,
193+ } ;
194+ }
0 commit comments