-
Notifications
You must be signed in to change notification settings - Fork 481
Expand file tree
/
Copy pathTrackPower.test.tsx
More file actions
254 lines (232 loc) · 8.32 KB
/
Copy pathTrackPower.test.tsx
File metadata and controls
254 lines (232 loc) · 8.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import type { IndexIntoSamplesTable, CssPixels } from 'firefox-profiler/types';
import { Provider } from 'react-redux';
import { fireEvent } from '@testing-library/react';
import { render, screen } from 'firefox-profiler/test/fixtures/testing-library';
import { updatePreviewSelection } from 'firefox-profiler/actions/profile-view';
import { TrackCounter } from '../../components/timeline/TrackCounter';
import { ensureExists } from '../../utils/types';
import {
autoMockCanvasContext,
flushDrawLog,
} from '../fixtures/mocks/canvas-context';
import { mockRaf } from '../fixtures/mocks/request-animation-frame';
import { storeWithProfile } from '../fixtures/stores';
import {
addRootOverlayElement,
removeRootOverlayElement,
getMouseEvent,
} from '../fixtures/utils';
import {
getProfileFromTextSamples,
getCounterForThreadWithSamples,
} from '../fixtures/profiles/processed-profile';
import { autoMockElementSize } from '../fixtures/mocks/element-size';
import { autoMockIntersectionObserver } from '../fixtures/mocks/intersection-observer';
// The following constants determine the size of the drawn graph.
const SAMPLE_COUNT = 12;
const PIXELS_PER_SAMPLE = 10;
const GRAPH_WIDTH = PIXELS_PER_SAMPLE * SAMPLE_COUNT;
const GRAPH_HEIGHT = 10;
function getSamplesPixelPosition(
sampleIndex: IndexIntoSamplesTable,
samplePosition: number
): CssPixels {
// Compute the pixel position of the center of a given sample.
return sampleIndex * PIXELS_PER_SAMPLE + PIXELS_PER_SAMPLE * samplePosition;
}
/**
* This test verifies that the power track can draw a graph.
*/
describe('TrackPower', function () {
function setup() {
const { profile } = getProfileFromTextSamples(
Array(SAMPLE_COUNT).fill('A').join(' ')
);
const threadIndex = 0;
const thread = profile.threads[threadIndex];
const sampleTimes = ensureExists(thread.samples.time);
// Changing one of the sample times, so we can test different intervals.
sampleTimes[1] = 1.5; // It was 1 before.
// Ensure some samples are very close to each other, to exercise
// the max min decimation algorithm.
for (let i = 7; i < sampleTimes.length - 1; ++i) {
sampleTimes[i] = 7 + i / 100;
}
const counter = getCounterForThreadWithSamples(
thread,
threadIndex,
{
time: sampleTimes.slice(),
// Power usage numbers. They are pWh so they are pretty big.
count: [
10000, 40000, 50000, 100000, 2000000, 5000000, 30000, 1000000, 20000,
1, 12000, 100000,
],
length: SAMPLE_COUNT,
},
'SystemPower',
'power'
);
counter.display = {
...counter.display,
graphType: 'line-rate',
unit: 'pWh',
sortWeight: 30,
label: 'SystemPower',
};
profile.counters = [counter];
const store = storeWithProfile(profile);
const { getState, dispatch } = store;
const flushRafCalls = mockRaf();
const renderResult = render(
<Provider store={store}>
<TrackCounter counterIndex={0} />
</Provider>
);
const { container } = renderResult;
// WithSize uses requestAnimationFrame
flushRafCalls();
const canvas = ensureExists(
container.querySelector('.timelineTrackCounterCanvas'),
`Couldn't find the power canvas, with selector .timelineTrackCounterCanvas`
);
const getTooltipContents = () =>
document.querySelector('.timelineTrackCounterTooltip');
const getPowerDot = () =>
container.querySelector('.timelineTrackCounterGraphDot');
const moveMouseAtCounter = (index: number, pos: number) =>
fireEvent(
canvas,
getMouseEvent('mousemove', {
pageX: getSamplesPixelPosition(index, pos),
})
);
return {
...renderResult,
dispatch,
getState,
profile,
thread,
store,
threadIndex,
canvas,
getTooltipContents,
moveMouseAtCounter,
flushRafCalls,
getPowerDot,
};
}
autoMockCanvasContext();
autoMockElementSize({ width: GRAPH_WIDTH, height: GRAPH_HEIGHT });
autoMockIntersectionObserver();
beforeEach(addRootOverlayElement);
afterEach(removeRootOverlayElement);
it('matches the component snapshot', () => {
const { container } = setup();
expect(container.firstChild).toMatchSnapshot();
});
it('matches the 2d canvas draw snapshot', () => {
const { flushRafCalls } = setup();
flushRafCalls();
expect(flushDrawLog()).toMatchSnapshot();
});
it('can create a tooltip', function () {
const { moveMouseAtCounter, getTooltipContents, canvas } = setup();
expect(getTooltipContents()).toBeFalsy();
moveMouseAtCounter(1, 0.5);
expect(getTooltipContents()).toBeTruthy();
fireEvent.mouseLeave(canvas);
expect(getTooltipContents()).toBeFalsy();
});
it('has a tooltip that matches the snapshot', function () {
const { moveMouseAtCounter, getTooltipContents } = setup();
// We are hovering exactly between 4th and 5th counter. That's why it should
// show the 5th counter.
// Here are the values we'll get in the tooltip:
// 5th counter value is 5000000 pWh, that is 5 µWh. Over 1ms, this means
// 18W (5 * 1000 * 3600 / 1000^2).
// Over the full range, we get 7.240 µWh, therefore we'll see in the tooltip
// 0.007 mWh.
moveMouseAtCounter(4, 0.5);
expect(getTooltipContents()).toMatchSnapshot();
});
it('draws a dot on the graph', function () {
const { moveMouseAtCounter, getPowerDot } = setup();
expect(getPowerDot()).toBeFalsy();
moveMouseAtCounter(1, 0.5);
expect(getPowerDot()).toBeTruthy();
});
it('can draw a dot on both extremes of the graph', function () {
const { moveMouseAtCounter, getPowerDot } = setup();
expect(getPowerDot()).toBeFalsy();
moveMouseAtCounter(0, 0.25);
expect(getPowerDot()).toBeTruthy();
moveMouseAtCounter(7, 0);
expect(getPowerDot()).toBeTruthy();
});
it('draws a dot that matches the snapshot', function () {
const { moveMouseAtCounter, getPowerDot } = setup();
moveMouseAtCounter(1, 0.5);
expect(getPowerDot()).toMatchSnapshot();
});
it('shows a tooltip with a Power: line and a power unit', function () {
const { dispatch, moveMouseAtCounter } = setup();
dispatch(
updatePreviewSelection({
isModifying: false,
selectionStart: 5,
selectionEnd: 6,
})
);
moveMouseAtCounter(3, 0);
// 100000pWh spent over 1ms is 360mW
// Note: Fluent adds isolation characters \u2068 and \u2069 around variables.
expect(screen.getByText(/Power:/).nextSibling).toHaveTextContent(
'360\u2069 mW'
);
// Over the full range, we get 8.352 µWh, therefore we'll see in the tooltip
// 8.4 µWh.
expect(screen.getByText(/visible range:/).nextSibling).toHaveTextContent(
'8.4\u2069 µWh'
);
// Over the preview selection, we get 5 µWh which shows up as 5.0 µWh.
expect(
screen.getByText(/Energy used in the current selection:/).nextSibling
).toHaveTextContent('5.0\u2069 µWh');
expect(
screen.getByText(/Average power in the current selection/).nextSibling
).toHaveTextContent('18.0\u2069 W');
});
it('does not break when the selection is empty', function () {
const { dispatch, moveMouseAtCounter } = setup();
dispatch(
updatePreviewSelection({
isModifying: false,
selectionStart: 6,
selectionEnd: 6,
})
);
moveMouseAtCounter(3, 0);
// 100000pWh spent over 1ms is 360mW
// Note: Fluent adds isolation characters \u2068 and \u2069 around variables.
expect(screen.getByText(/Power:/).nextSibling).toHaveTextContent(
'360\u2069 mW'
);
// Over the full range, we get 8.352 µWh, therefore we'll see in the tooltip
// 8.4 µWh.
expect(screen.getByText(/visible range:/).nextSibling).toHaveTextContent(
'8.4\u2069 µWh'
);
// The preview selection being empty, these 2 lines are not useful and
// therefore not rendered.
expect(
screen.queryByText(/Energy used in the current selection:/)
).not.toBeInTheDocument();
expect(
screen.queryByText(/Average power in the current selection/)
).not.toBeInTheDocument();
});
});