1
1
import { EventFixture } from 'sentry-fixture/event' ;
2
2
import { GroupFixture } from 'sentry-fixture/group' ;
3
+ import { LogFixture } from 'sentry-fixture/log' ;
3
4
import { OrganizationFixture } from 'sentry-fixture/organization' ;
4
5
import { ProjectFixture } from 'sentry-fixture/project' ;
5
6
6
- import { render , screen , userEvent , within } from 'sentry-test/reactTestingLibrary' ;
7
+ import {
8
+ render ,
9
+ screen ,
10
+ userEvent ,
11
+ waitFor ,
12
+ within ,
13
+ } from 'sentry-test/reactTestingLibrary' ;
7
14
8
15
import { OurlogsSection } from 'sentry/components/events/ourlogs/ourlogsSection' ;
16
+ import PageFiltersStore from 'sentry/stores/pageFiltersStore' ;
17
+ import ProjectsStore from 'sentry/stores/projectsStore' ;
9
18
import { OurLogKnownFieldKey } from 'sentry/views/explore/logs/types' ;
10
19
11
20
const TRACE_ID = '00000000000000000000000000000000' ;
12
21
13
- const organization = OrganizationFixture ( { features : [ 'ourlogs-enabled' ] } ) ;
22
+ jest . mock ( '@tanstack/react-virtual' , ( ) => {
23
+ return {
24
+ useWindowVirtualizer : jest . fn ( ) . mockReturnValue ( {
25
+ getVirtualItems : jest . fn ( ) . mockReturnValue ( [
26
+ { key : '1' , index : 0 , start : 0 , end : 50 , lane : 0 } ,
27
+ { key : '2' , index : 1 , start : 50 , end : 100 , lane : 0 } ,
28
+ { key : '3' , index : 2 , start : 100 , end : 150 , lane : 0 } ,
29
+ ] ) ,
30
+ getTotalSize : jest . fn ( ) . mockReturnValue ( 150 ) ,
31
+ options : {
32
+ scrollMargin : 0 ,
33
+ } ,
34
+ scrollDirection : 'forward' ,
35
+ scrollOffset : 0 ,
36
+ isScrolling : false ,
37
+ } ) ,
38
+ useVirtualizer : jest . fn ( ) . mockReturnValue ( {
39
+ getVirtualItems : jest . fn ( ) . mockReturnValue ( [
40
+ { key : '1' , index : 0 , start : 0 , end : 50 , lane : 0 } ,
41
+ { key : '2' , index : 1 , start : 50 , end : 100 , lane : 0 } ,
42
+ { key : '3' , index : 2 , start : 100 , end : 150 , lane : 0 } ,
43
+ ] ) ,
44
+ getTotalSize : jest . fn ( ) . mockReturnValue ( 150 ) ,
45
+ options : {
46
+ scrollMargin : 0 ,
47
+ } ,
48
+ scrollDirection : 'forward' ,
49
+ scrollOffset : 0 ,
50
+ isScrolling : false ,
51
+ } ) ,
52
+ } ;
53
+ } ) ;
54
+
55
+ const organization = OrganizationFixture ( {
56
+ features : [ 'ourlogs-enabled' , 'ourlogs-infinite-scroll' ] ,
57
+ } ) ;
14
58
const project = ProjectFixture ( ) ;
15
59
const group = GroupFixture ( ) ;
16
60
const event = EventFixture ( {
@@ -65,13 +109,69 @@ const event = EventFixture({
65
109
} ) ;
66
110
67
111
describe ( 'OurlogsSection' , ( ) => {
112
+ let logId : string ;
113
+ let mockRequest : jest . Mock ;
68
114
beforeEach ( ( ) => {
69
- // the search query combobox is firing updates and causing console.errors
70
- jest . spyOn ( console , 'error' ) . mockImplementation ( ( ) => { } ) ;
115
+ logId = '11111111111111111111111111111111' ;
116
+
117
+ ProjectsStore . loadInitialData ( [ project ] ) ;
118
+
119
+ PageFiltersStore . init ( ) ;
120
+ PageFiltersStore . onInitializeUrlState (
121
+ {
122
+ projects : [ parseInt ( project . id , 10 ) ] ,
123
+ environments : [ ] ,
124
+ datetime : {
125
+ period : '14d' ,
126
+ start : null ,
127
+ end : null ,
128
+ utc : null ,
129
+ } ,
130
+ } ,
131
+ new Set ( )
132
+ ) ;
133
+
134
+ MockApiClient . addMockResponse ( {
135
+ url : `/projects/` ,
136
+ body : [ project ] ,
137
+ } ) ;
138
+
139
+ MockApiClient . addMockResponse ( {
140
+ url : `/projects/${ organization . slug } /${ project . slug } /` ,
141
+ body : project ,
142
+ } ) ;
143
+
144
+ mockRequest = MockApiClient . addMockResponse ( {
145
+ url : `/organizations/${ organization . slug } /trace-logs/` ,
146
+ body : {
147
+ data : [
148
+ LogFixture ( {
149
+ [ OurLogKnownFieldKey . ID ] : logId ,
150
+ [ OurLogKnownFieldKey . PROJECT_ID ] : project . id ,
151
+ [ OurLogKnownFieldKey . ORGANIZATION_ID ] : Number ( organization . id ) ,
152
+ [ OurLogKnownFieldKey . TRACE_ID ] : TRACE_ID ,
153
+ [ OurLogKnownFieldKey . SEVERITY_NUMBER ] : 0 ,
154
+ [ OurLogKnownFieldKey . MESSAGE ] : 'i am a log' ,
155
+ } ) ,
156
+ ] ,
157
+ meta : { } ,
158
+ } ,
159
+ } ) ;
160
+
161
+ MockApiClient . addMockResponse ( {
162
+ url : `/organizations/${ organization . slug } /trace-items/attributes/` ,
163
+ method : 'GET' ,
164
+ body : { } ,
165
+ } ) ;
166
+
167
+ MockApiClient . addMockResponse ( {
168
+ url : '/organizations/org-slug/recent-searches/' ,
169
+ body : [ ] ,
170
+ } ) ;
71
171
} ) ;
72
172
73
173
it ( 'renders empty' , ( ) => {
74
- const mockRequest = MockApiClient . addMockResponse ( {
174
+ const mockRequestEmpty = MockApiClient . addMockResponse ( {
75
175
url : `/organizations/${ organization . slug } /trace-logs/` ,
76
176
body : {
77
177
data : [ ] ,
@@ -81,44 +181,40 @@ describe('OurlogsSection', () => {
81
181
render ( < OurlogsSection event = { event } project = { project } group = { group } /> , {
82
182
organization,
83
183
} ) ;
84
- expect ( mockRequest ) . toHaveBeenCalledTimes ( 1 ) ;
184
+ expect ( mockRequestEmpty ) . toHaveBeenCalledTimes ( 1 ) ;
85
185
expect ( screen . queryByText ( / L o g s / ) ) . not . toBeInTheDocument ( ) ;
86
186
} ) ;
87
187
88
188
it ( 'renders logs' , async ( ) => {
89
- const now = new Date ( ) ;
90
- const mockRequest = MockApiClient . addMockResponse ( {
91
- url : `/organizations/ ${ organization . slug } /trace-logs/` ,
189
+ const mockRowDetailsRequest = MockApiClient . addMockResponse ( {
190
+ url : `/projects/ ${ organization . slug } / ${ project . slug } /trace-items/ ${ logId } /` ,
191
+ method : 'GET' ,
92
192
body : {
93
- data : [
94
- {
95
- 'sentry.item_id' : '11111111111111111111111111111111' ,
96
- 'project.id' : 1 ,
97
- trace : TRACE_ID ,
98
- severity_number : 0 ,
99
- severity : 'info' ,
100
- timestamp : now . toISOString ( ) ,
101
- [ OurLogKnownFieldKey . TIMESTAMP_PRECISE ] : now . getTime ( ) * 1e6 ,
102
- message : 'i am a log' ,
103
- } ,
193
+ itemId : logId ,
194
+ timestamp : '2025-04-03T15:50:10+00:00' ,
195
+ attributes : [
196
+ { name : 'severity' , type : 'str' , value : 'error' } ,
197
+ { name : 'special_field' , type : 'str' , value : 'special value' } ,
104
198
] ,
105
- meta : { } ,
106
199
} ,
107
200
} ) ;
201
+
108
202
render ( < OurlogsSection event = { event } project = { project } group = { group } /> , {
109
203
organization,
204
+ initialRouterConfig : {
205
+ location : {
206
+ pathname : `/organizations/${ organization . slug } /issues/${ group . id } /` ,
207
+ query : {
208
+ project : project . id ,
209
+ } ,
210
+ } ,
211
+ } ,
110
212
} ) ;
111
213
expect ( mockRequest ) . toHaveBeenCalledTimes ( 1 ) ;
112
214
113
- // without waiting a few ticks, the test fails just before the
114
- // promise corresponding to the request resolves
115
- // by adding some ticks, it forces the test to wait a little longer
116
- // until the promise is resolved
117
- for ( let i = 0 ; i < 10 ; i ++ ) {
118
- await tick ( ) ;
119
- }
120
-
121
- expect ( screen . getByText ( / i a m a l o g / ) ) . toBeInTheDocument ( ) ;
215
+ await waitFor ( ( ) => {
216
+ expect ( screen . getByText ( / i a m a l o g / ) ) . toBeInTheDocument ( ) ;
217
+ } ) ;
122
218
123
219
expect (
124
220
screen . queryByRole ( 'complementary' , { name : 'logs drawer' } )
@@ -129,6 +225,15 @@ describe('OurlogsSection', () => {
129
225
const aside = screen . getByRole ( 'complementary' , { name : 'logs drawer' } ) ;
130
226
expect ( aside ) . toBeInTheDocument ( ) ;
131
227
132
- expect ( within ( aside ) . getByText ( / i a m a l o g / ) ) . toBeInTheDocument ( ) ;
228
+ await waitFor ( ( ) => {
229
+ expect ( mockRowDetailsRequest ) . toHaveBeenCalledTimes ( 1 ) ;
230
+ } ) ;
231
+
232
+ await waitFor ( ( ) => {
233
+ expect ( within ( aside ) . getByText ( / s p e c i a l v a l u e / ) ) . toBeInTheDocument ( ) ;
234
+ } ) ;
235
+
236
+ expect ( within ( aside ) . getByTestId ( 'tree-key-severity' ) ) . toBeInTheDocument ( ) ;
237
+ expect ( within ( aside ) . getByTestId ( 'tree-key-severity' ) ) . toHaveTextContent ( 'severity' ) ;
133
238
} ) ;
134
239
} ) ;
0 commit comments