1- // Mock global location before importing domo
2- ( global as any ) . location = { search : '' } ;
3-
41import Domo , { __mutationObserverCallback } from './domo' ;
52import { RequestMethods } from './models/enums/request-methods' ;
63
@@ -10,76 +7,20 @@ const originalPost = Domo.post;
107const originalPut = Domo . put ;
118const originalDelete = Domo . delete ;
129
13- declare global {
14- // eslint-disable-next-line no-var
15- var _originalXMLHttpRequest : any ;
16- // eslint-disable-next-line no-var
17- var _openSpy : jest . Mock ;
18- // eslint-disable-next-line no-var
19- var _xhrInstance : any ;
20- }
21-
22- // Mock MessagePort and MessageChannel globally for Jest
2310class MockMessagePort {
2411 onmessage : ( ( event : any ) => void ) | null = null ;
2512 postMessage = jest . fn ( ) ;
2613 close = jest . fn ( ) ;
2714}
28- ( global as any ) . MessagePort = MockMessagePort ;
2915( global as any ) . MessageChannel = class {
3016 port1 = new MockMessagePort ( ) ;
3117 port2 = new MockMessagePort ( ) ;
3218} ;
3319
34- // Patch window.addEventListener and removeEventListener to track message listeners for test cleanup
35- const realAddEventListener = window . addEventListener ;
36- const realRemoveEventListener = window . removeEventListener ;
37- ( window as any ) . eventListeners = { message : [ ] } ;
38- window . addEventListener = function ( type : string , listener : EventListenerOrEventListenerObject , options ?: boolean | AddEventListenerOptions ) {
39- if ( type === 'message' ) {
40- ( window as any ) . eventListeners . message . push ( listener ) ;
41- }
42- return realAddEventListener . call ( this , type , listener , options ) ;
43- } ;
44- window . removeEventListener = function ( type : string , listener : EventListenerOrEventListenerObject , options ?: boolean | EventListenerOptions ) {
45- if ( type === 'message' ) {
46- const arr = ( window as any ) . eventListeners . message ;
47- const idx = arr . indexOf ( listener ) ;
48- if ( idx !== - 1 ) arr . splice ( idx , 1 ) ;
49- }
50- return realRemoveEventListener . call ( this , type , listener , options ) ;
51- } ;
52-
5320// Mock browser APIs and global objects as needed
5421beforeEach ( ( ) => {
5522 jest . resetAllMocks ( ) ;
5623 ( window as any ) [ '__RYUU_SID__' ] = 'test-token' ;
57- window . parent . postMessage = jest . fn ( ) ;
58- Object . defineProperty ( window . navigator , 'userAgent' , {
59- value : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)' ,
60- configurable : true
61- } ) ;
62- ( window as any ) [ 'webkit' ] = { messageHandlers : { domofilter : { postMessage : jest . fn ( ) } , domovariable : { postMessage : jest . fn ( ) } } } ;
63- // Only redefine MessageChannel if needed for test isolation
64- ( global as any ) . MessageChannel = ( global as any ) . MessageChannel ;
65-
66- // XMLHttpRequest mock for all HTTP verb tests
67- globalThis . _originalXMLHttpRequest = ( global as any ) . XMLHttpRequest ;
68- globalThis . _openSpy = jest . fn ( ) ;
69- globalThis . _xhrInstance = {
70- open : globalThis . _openSpy ,
71- setRequestHeader : jest . fn ( ) ,
72- send : jest . fn ( ) ,
73- addEventListener : jest . fn ( ) ,
74- removeEventListener : jest . fn ( ) ,
75- onload : null ,
76- onerror : null ,
77- readyState : 4 ,
78- status : 200 ,
79- response : '{}' ,
80- getResponseHeader : jest . fn ( )
81- } ;
82- ( global as any ) . XMLHttpRequest = jest . fn ( ( ) => globalThis . _xhrInstance ) ;
8324
8425 Domo . domoHttp = originalDomoHttp ;
8526 Domo . get = originalGet ;
@@ -88,90 +29,61 @@ beforeEach(() => {
8829 Domo . delete = originalDelete ;
8930} ) ;
9031
91- afterEach ( ( ) => {
92- ( global as any ) . XMLHttpRequest = globalThis . _originalXMLHttpRequest ;
93- // Remove all message event listeners to prevent test pollution
94- const listeners : EventListenerOrEventListenerObject [ ] = ( window as any ) . eventListeners ?. message ?? [ ] ;
95- listeners . forEach ( ( listener : EventListenerOrEventListenerObject ) => {
96- realRemoveEventListener . call ( window , 'message' , listener ) ;
97- } ) ;
98- ( window as any ) . eventListeners . message = [ ] ;
99- } ) ;
32+ describe ( 'Domo Connect & MessageChannel' , ( ) => {
33+ let appDataSpy : jest . Mock ,
34+ filtersSpy : jest . Mock ,
35+ variablesSpy : jest . Mock ;
10036
37+ beforeEach ( ( ) => {
38+ Domo . listeners . onAppDataUpdated = [ ] ;
39+ Domo . listeners . onFiltersUpdated = [ ] ;
40+ Domo . listeners . onVariablesUpdated = [ ] ;
10141
102- describe ( 'domo event/callback APIs' , ( ) => {
103- describe ( 'connect/MessageChannel' , ( ) => {
104- function makeMessageEvent ( data : any , ports : any [ ] = [ ] ) {
105- return { data, ports } as any ;
106- }
42+ appDataSpy = jest . fn ( ) ;
43+ filtersSpy = jest . fn ( ) ;
44+ variablesSpy = jest . fn ( ) ;
45+
46+ Domo . listeners . onAppDataUpdated . push ( appDataSpy ) ;
47+ Domo . listeners . onFiltersUpdated . push ( filtersSpy ) ;
48+ Domo . listeners . onVariablesUpdated . push ( variablesSpy ) ;
49+ } ) ;
50+
51+ function makeMessageEvent ( data : any , ports : any [ ] = [ ] ) {
52+ return { data, ports } as any ;
53+ }
10754
108- it ( 'should early return if responsePort is undefined' , ( ) => {
109- Domo . connect ( ) ;
110- expect ( ( ) => Domo . channel . port1 . onmessage ( makeMessageEvent ( { event : 'filtersUpdated' , filters : [ ] } , [ ] ) ) ) . not . toThrow ( ) ;
111- } ) ;
55+ it ( 'should early return if responsePort is undefined' , ( ) => {
56+ const data = { event : 'filtersUpdated' , filters : [ ] } as any ;
57+ Domo . connect ( ) ;
58+ expect ( ( ) => Domo . channel ?. port1 ?. onmessage ?.( makeMessageEvent ( data , [ ] ) ) ) . not . toThrow ( ) ;
59+ } ) ;
60+
61+ it ( 'should handle multiple messages correctly' , ( ) => {
62+ const channel = new MessageChannel ( ) ;
63+ const data1 = { event : 'filtersUpdated' , filters : [ ] } as any ;
64+ const data2 = { event : 'appData' , data : { } } as any ;
65+ const data3 = { event : 'variablesUpdated' , variables : { } } as any ;
66+
67+ expect ( ( ) => Domo . channel ?. port1 ?. onmessage ?.( makeMessageEvent ( data1 , [ channel . port2 ] ) ) ) . not . toThrow ( ) ;
68+ expect ( ( ) => Domo . channel ?. port1 ?. onmessage ?.( makeMessageEvent ( data2 , [ channel . port2 ] ) ) ) . not . toThrow ( ) ;
69+ expect ( ( ) => Domo . channel ?. port1 ?. onmessage ?.( makeMessageEvent ( data3 , [ channel . port2 ] ) ) ) . not . toThrow ( ) ;
70+ expect ( variablesSpy ) . toHaveBeenCalled ( ) ;
71+ expect ( filtersSpy ) . toHaveBeenCalled ( ) ;
72+ expect ( appDataSpy ) . toHaveBeenCalled ( ) ;
73+ expect ( channel . port2 . postMessage ) . toHaveBeenCalledTimes ( 3 ) ;
11274 } ) ;
11375} ) ;
11476
77+
11578describe ( 'domo.__util (internal utilities)' , ( ) => {
11679 it ( 'should expose the expected private functions' , ( ) => {
11780 expect ( typeof Domo . __util . isVerifiedOrigin ) . toBe ( 'function' ) ;
11881 expect ( typeof Domo . __util . isSuccess ) . toBe ( 'function' ) ;
11982 expect ( typeof Domo . __util . getQueryParams ) . toBe ( 'function' ) ;
12083 expect ( typeof Domo . __util . setFormatHeaders ) . toBe ( 'function' ) ;
12184 } ) ;
122-
123- it ( 'isSuccess returns true for 2xx, false otherwise' , ( ) => {
124- expect ( Domo . __util . isSuccess ( 200 ) ) . toBe ( true ) ;
125- expect ( Domo . __util . isSuccess ( 299 ) ) . toBe ( true ) ;
126- expect ( Domo . __util . isSuccess ( 199 ) ) . toBe ( false ) ;
127- expect ( Domo . __util . isSuccess ( 300 ) ) . toBe ( false ) ;
128- expect ( Domo . __util . isSuccess ( null ) ) . toBe ( false ) ;
129- expect ( Domo . __util . isSuccess ( undefined ) ) . toBe ( false ) ;
130- } ) ;
131-
132- it ( 'isVerifiedOrigin honors whitelisting and blacklisting' , ( ) => {
133- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.domo.com' ) ) ) . toBe ( true ) ;
134- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.domotech.io' ) ) ) . toBe ( true ) ;
135- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.domorig.io' ) ) ) . toBe ( true ) ;
136- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://domo.demo.domo.com' ) ) ) . toBe ( true ) ;
137- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://qa2staging.fastage1.domotech.io/auth/index' ) ) ) . toBe ( true ) ;
138- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.domoapps-test.domo.com' ) ) ) . toBe ( false ) ;
139- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.test-domoapps.domo.com' ) ) ) . toBe ( false ) ;
140- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.somethingk.com' ) ) ) . toBe ( false ) ;
141- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'https://www.domo.com.bad.io' ) ) ) . toBe ( false ) ;
142- expect ( Boolean ( Domo . __util . isVerifiedOrigin ( 'http://www.domo.com' ) ) ) . toBe ( false ) ;
143- } ) ;
144-
145- it ( 'getQueryParams parses query string' , ( ) => {
146- Object . defineProperty ( global , 'location' , {
147- value : { search : '?foo=bar&baz=qux' } ,
148- configurable : true
149- } ) ;
150- const params = Domo . __util . getQueryParams ( ) ;
151- expect ( 'foo' in params ) . toBe ( true ) ;
152- expect ( 'baz' in params ) . toBe ( true ) ;
153- expect ( ( params as any ) [ 'foo' ] ) . toBe ( 'bar' ) ;
154- expect ( ( params as any ) [ 'baz' ] ) . toBe ( 'qux' ) ;
155- } ) ;
156-
157- it ( 'setFormatHeaders sets Accept header for data/v URLs' , ( ) => {
158- const req = { setRequestHeader : jest . fn ( ) } ;
159- Domo . __util . setFormatHeaders ( req as any , 'https://domo.com/data/v1' , { format : 'array-of-objects' } ) ;
160- expect ( req . setRequestHeader ) . toHaveBeenCalledWith ( 'Accept' , expect . any ( String ) ) ;
161- } ) ;
16285} ) ;
16386
164- describe ( 'domo.env and global exposure' , ( ) => {
165- it ( 'should have env properties with expected types' , ( ) => {
166- expect ( typeof Domo . env ) . toBe ( 'object' ) ;
167- expect ( typeof Domo . env . userId ) . toBeDefined ( ) ;
168- } ) ;
169-
170- it ( 'should expose env and __util' , ( ) => {
171- expect ( Domo . env ) . toBeDefined ( ) ;
172- expect ( Domo . __util ) . toBeDefined ( ) ;
173- } ) ;
174- } ) ;
17587
17688describe ( 'MutationObserver integration' , ( ) => {
17789 it ( 'should call handleNode when a new element is added to the DOM' , ( ) => {
@@ -186,23 +98,20 @@ describe('MutationObserver integration', () => {
18698 } ) ;
18799} ) ;
188100
189- describe ( 'domo uncovered/miscellaneous branches' , ( ) => {
190- it ( 'should handle catch branch in isVerifiedOrigin' , ( ) => {
191- expect ( Domo . __util . isVerifiedOrigin ( 'not a url' ) ) . toBe ( false ) ;
192- } ) ;
193101
194- it ( 'should use DataFormats.DEFAULT in setFormatHeaders ', ( ) => {
195- const req = { setRequestHeader : jest . fn ( ) } ;
196- Domo . __util . setFormatHeaders ( req as any , 'https://domo.com/data/v1' , { } ) ;
197- expect ( req . setRequestHeader ) . toHaveBeenCalledWith ( 'Accept' , expect . anything ( ) ) ;
102+ describe ( 'domo.env and global exposure ', ( ) => {
103+ it ( 'should have env properties with expected types' , ( ) => {
104+ expect ( typeof Domo . env ) . toBe ( 'object' ) ;
105+ expect ( typeof Domo . env . userId ) . toBeDefined ( ) ;
198106 } ) ;
199107
200- it ( 'should import FilterDataTypes from models/index ' , ( ) => {
201- const { FilterDataTypes } = require ( '../src/models/interfaces/filter-data-types' ) ;
202- expect ( FilterDataTypes ) . toBeDefined ( ) ;
108+ it ( 'should expose env and __util ' , ( ) => {
109+ expect ( Domo . env ) . toBeDefined ( ) ;
110+ expect ( Domo . __util ) . toBeDefined ( ) ;
203111 } ) ;
204112} ) ;
205113
114+
206115describe ( 'Domo.extend' , ( ) => {
207116 beforeEach ( ( ) => {
208117 jest . resetModules ( ) ;
@@ -258,5 +167,4 @@ describe('Domo.extend', () => {
258167 expect ( mockHttp ) . toHaveBeenCalledWith ( 'DELETE' , '/grault' , undefined ) ;
259168 expect ( deleteResult ) . toBe ( 'mocked-http' ) ;
260169 } ) ;
261-
262170} ) ;
0 commit comments