@@ -2,20 +2,24 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
22import { fakeAsync , flush } from '@angular/core/testing' ;
33import { IconLibraryTestingModule } from '@hypertrace/assets-library' ;
44import { NavigationService } from '@hypertrace/common' ;
5- import { SelectComponent , SelectModule } from '@hypertrace/components' ;
5+ import { InputModule , LetAsyncModule , SelectComponent , SelectModule } from '@hypertrace/components' ;
66import { byText , createHostFactory , mockProvider } from '@ngneat/spectator/jest' ;
77import { EMPTY , of } from 'rxjs' ;
8- import { AttributeMetadata } from '../../../graphql/model/metadata/attribute-metadata' ;
8+ import { AttributeMetadata , AttributeMetadataType } from '../../../graphql/model/metadata/attribute-metadata' ;
99import { ObservabilityTraceType } from '../../../graphql/model/schema/observability-traces' ;
1010import { MetadataService } from '../../../services/metadata/metadata.service' ;
1111import { ExploreQueryGroupByEditorComponent } from './explore-query-group-by-editor.component' ;
1212
1313describe ( 'Explore Query Group by Editor component' , ( ) => {
1414 // Define metadata at top level so equality checks always get same values
15- const attributeMetadata = [ { name : 'test value' } , { name : 'foo bar' } ] ;
15+ const attributeMetadata = [
16+ { name : 'test value' , type : AttributeMetadataType . String } ,
17+ { name : 'foo bar' , type : AttributeMetadataType . String } ,
18+ { name : 'test map' , type : AttributeMetadataType . StringMap }
19+ ] ;
1620 const hostBuilder = createHostFactory ( {
1721 component : ExploreQueryGroupByEditorComponent ,
18- imports : [ SelectModule , HttpClientTestingModule , IconLibraryTestingModule ] ,
22+ imports : [ SelectModule , HttpClientTestingModule , IconLibraryTestingModule , LetAsyncModule , InputModule ] ,
1923 providers : [
2024 mockProvider ( MetadataService , {
2125 getAttributeDisplayName : ( attribute : AttributeMetadata ) => attribute . name ,
@@ -29,13 +33,11 @@ describe('Explore Query Group by Editor component', () => {
2933 } ) ;
3034
3135 test ( 'sets group by to none if undefined provided' , fakeAsync ( ( ) => {
32- const spectator = hostBuilder (
33- `
36+ const spectator = hostBuilder ( `
3437 <ht-explore-query-group-by-editor
35- context="${ ObservabilityTraceType . Api } " [groupByKey ]="groupBy "
38+ context="${ ObservabilityTraceType . Api } " [groupByExpression ]="groupByExpression "
3639 ></ht-explore-query-group-by-editor>
37- `
38- ) ;
40+ ` ) ;
3941 spectator . tick ( ) ;
4042
4143 expect ( spectator . query ( SelectComponent ) ! . selected ) . toBeUndefined ( ) ;
@@ -46,38 +48,38 @@ describe('Explore Query Group by Editor component', () => {
4648 const spectator = hostBuilder (
4749 `
4850 <ht-explore-query-group-by-editor
49- context="${ ObservabilityTraceType . Api } " [groupByKey ]="groupByKey "
51+ context="${ ObservabilityTraceType . Api } " [groupByExpression ]="groupByExpression "
5052 ></ht-explore-query-group-by-editor>
5153 ` ,
5254 {
5355 hostProps : {
54- groupByKey : 'test value'
56+ groupByExpression : { key : 'test value' }
5557 }
5658 }
5759 ) ;
5860
59- expect ( spectator . query ( SelectComponent ) ! . selected ) . toBe ( 'test value' ) ;
61+ expect ( spectator . query ( SelectComponent ) ! . selected ) . toEqual ( attributeMetadata [ 0 ] ) ;
6062 } ) ;
6163
6264 test ( 'updates if new group by is provided' , ( ) => {
6365 const spectator = hostBuilder (
6466 `
6567 <ht-explore-query-group-by-editor
66- context="${ ObservabilityTraceType . Api } " [groupByKey ]="groupByKey "
68+ context="${ ObservabilityTraceType . Api } " [groupByExpression ]="groupByExpression "
6769 ></ht-explore-query-group-by-editor>
6870 ` ,
6971 {
7072 hostProps : {
71- groupByKey : 'test value'
73+ groupByExpression : { key : 'test value' }
7274 }
7375 }
7476 ) ;
7577
76- spectator . setHostInput ( { groupByKey : 'foo bar' } ) ;
78+ spectator . setHostInput ( { groupByExpression : { key : 'foo bar' } } ) ;
7779
78- expect ( spectator . query ( SelectComponent ) ! . selected ) . toBe ( 'foo bar' ) ;
80+ expect ( spectator . query ( SelectComponent ) ! . selected ) . toEqual ( attributeMetadata [ 1 ] ) ;
7981
80- spectator . setHostInput ( { groupByKey : undefined } ) ;
82+ spectator . setHostInput ( { groupByExpression : undefined } ) ;
8183
8284 expect ( spectator . query ( SelectComponent ) ! . selected ) . toBeUndefined ( ) ;
8385 } ) ;
@@ -87,12 +89,42 @@ describe('Explore Query Group by Editor component', () => {
8789 const spectator = hostBuilder (
8890 `
8991 <ht-explore-query-group-by-editor
90- context="${ ObservabilityTraceType . Api } " [groupByKey]="groupByKey" (groupByKeyChange)="onChange($event)"
92+ context="${ ObservabilityTraceType . Api } " [groupByExpression]="groupByExpression" (groupByExpressionChange)="onChange($event)"
93+ ></ht-explore-query-group-by-editor>
94+ ` ,
95+ {
96+ hostProps : {
97+ groupByExpression : { key : 'test value' } ,
98+ onChange : onChange
99+ }
100+ }
101+ ) ;
102+ spectator . tick ( ) ; // Needs to tick to interact with select which is async
103+
104+ spectator . click ( spectator . query ( byText ( 'test value' ) ) ! ) ;
105+
106+ const options = spectator . queryAll ( '.select-option' , { root : true } ) ;
107+ expect ( options . length ) . toBe ( 4 ) ;
108+ spectator . click ( options [ 2 ] ) ;
109+
110+ spectator . tick ( 500 ) ; // 500ms debounce after group by change
111+ expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
112+ expect ( onChange ) . toHaveBeenCalledWith ( { key : 'foo bar' } ) ;
113+
114+ flush ( ) ; // Overlay removes async
115+ } ) ) ;
116+
117+ test ( 'emits when group by key is changed' , fakeAsync ( ( ) => {
118+ const onChange = jest . fn ( ) ;
119+ const spectator = hostBuilder (
120+ `
121+ <ht-explore-query-group-by-editor
122+ context="${ ObservabilityTraceType . Api } " [groupByExpression]="groupByExpression" (groupByExpressionChange)="onChange($event)"
91123 ></ht-explore-query-group-by-editor>
92124 ` ,
93125 {
94126 hostProps : {
95- groupByKey : 'test value' ,
127+ groupByExpression : { key : 'test value' } ,
96128 onChange : onChange
97129 }
98130 }
@@ -102,12 +134,70 @@ describe('Explore Query Group by Editor component', () => {
102134 spectator . click ( spectator . query ( byText ( 'test value' ) ) ! ) ;
103135
104136 const options = spectator . queryAll ( '.select-option' , { root : true } ) ;
105- expect ( options . length ) . toBe ( 3 ) ;
137+ expect ( options . length ) . toBe ( 4 ) ;
106138 spectator . click ( options [ 2 ] ) ;
107139
140+ spectator . tick ( 500 ) ; // 500ms debounce after group by change
108141 expect ( onChange ) . toHaveBeenCalledTimes ( 1 ) ;
109- expect ( onChange ) . toHaveBeenCalledWith ( 'foo bar' ) ;
142+ expect ( onChange ) . toHaveBeenCalledWith ( { key : 'foo bar' } ) ;
143+
144+ flush ( ) ; // Overlay removes async
145+ } ) ) ;
146+
147+ test ( 'shows subpath for map attributes only' , fakeAsync ( ( ) => {
148+ const spectator = hostBuilder (
149+ `
150+ <ht-explore-query-group-by-editor
151+ context="${ ObservabilityTraceType . Api } " [groupByExpression]="groupByExpression"
152+ ></ht-explore-query-group-by-editor>
153+ ` ,
154+ {
155+ hostProps : {
156+ groupByExpression : { key : 'test value' }
157+ }
158+ }
159+ ) ;
160+ spectator . tick ( ) ; // Needs to tick to interact with select which is async
161+
162+ expect ( spectator . query ( '.select' ) ) . toHaveText ( 'test value' ) ;
163+ expect ( spectator . query ( '.group-by-path-input' ) ) . not . toExist ( ) ;
164+ spectator . click ( spectator . query ( byText ( 'test value' ) ) ! ) ;
165+ const options = spectator . queryAll ( '.select-option' , { root : true } ) ;
166+ spectator . click ( options [ 3 ] ) ;
167+
168+ expect ( spectator . query ( '.group-by-path-input' ) ) . toExist ( ) ;
169+
170+ flush ( ) ; // Overlay removes async
171+ } ) ) ;
110172
173+ test ( 'outputs map expressions correctly' , fakeAsync ( ( ) => {
174+ const onChange = jest . fn ( ) ;
175+ const spectator = hostBuilder (
176+ `
177+ <ht-explore-query-group-by-editor
178+ context="${ ObservabilityTraceType . Api } " (groupByExpressionChange)="onChange($event)"
179+ ></ht-explore-query-group-by-editor>
180+ ` ,
181+ {
182+ hostProps : {
183+ onChange : onChange
184+ }
185+ }
186+ ) ;
187+ spectator . tick ( ) ; // Needs to tick to interact with select which is async
188+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
189+ spectator . click ( spectator . query ( byText ( 'None' ) ) ! ) ;
190+ const options = spectator . queryAll ( '.select-option' , { root : true } ) ;
191+ spectator . click ( options [ 3 ] ) ;
192+ // Wait for debounce
193+ spectator . tick ( 500 ) ;
194+ // Should not emit on switching to map group by, not eligible without a subpath
195+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
196+ spectator . typeInElement ( 'test.subpath' , '.group-by-path-input input' ) ;
197+ expect ( onChange ) . not . toHaveBeenCalled ( ) ;
198+ // Wait for debounce
199+ spectator . tick ( 500 ) ;
200+ expect ( onChange ) . toHaveBeenCalledWith ( { key : 'test map' , subpath : 'test.subpath' } ) ;
111201 flush ( ) ; // Overlay removes async
112202 } ) ) ;
113203} ) ;
0 commit comments