import {mountWithTheme} from 'sentry-test/enzyme';
import {doEventsRequest} from 'sentry/actionCreators/events';
import EventsRequest from 'sentry/components/charts/eventsRequest';
const COUNT_OBJ = {
count: 123,
};
jest.mock('sentry/actionCreators/events', () => ({
doEventsRequest: jest.fn(),
}));
describe('EventsRequest', function () {
const project = TestStubs.Project();
const organization = TestStubs.Organization();
const mock = jest.fn(() => null);
const DEFAULTS = {
api: new MockApiClient(),
projects: [parseInt(project.id, 10)],
environments: [],
period: '24h',
organization,
tag: 'release',
includePrevious: false,
includeTimeseries: true,
};
let wrapper;
describe('with props changes', function () {
beforeAll(function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
data: [[new Date(), [COUNT_OBJ]]],
})
);
wrapper = mountWithTheme({mock});
});
it('makes requests', function () {
expect(mock).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
loading: true,
})
);
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
loading: false,
timeseriesData: [
{
seriesName: expect.anything(),
data: [
expect.objectContaining({
name: expect.any(Number),
value: 123,
}),
],
},
],
originalTimeseriesData: [[expect.anything(), expect.anything()]],
})
);
expect(doEventsRequest).toHaveBeenCalled();
});
it('makes a new request if projects prop changes', async function () {
doEventsRequest.mockClear();
wrapper.setProps({projects: [123]});
await tick();
wrapper.update();
expect(doEventsRequest).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
projects: [123],
})
);
});
it('makes a new request if environments prop changes', async function () {
doEventsRequest.mockClear();
wrapper.setProps({environments: ['dev']});
await tick();
wrapper.update();
expect(doEventsRequest).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
environments: ['dev'],
})
);
});
it('makes a new request if period prop changes', async function () {
doEventsRequest.mockClear();
wrapper.setProps({period: '7d'});
await tick();
wrapper.update();
expect(doEventsRequest).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
period: '7d',
})
);
});
});
describe('transforms', function () {
beforeEach(function () {
doEventsRequest.mockClear();
});
it('expands period in query if `includePrevious`', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
})
);
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
// actionCreator handles expanding the period when calling the API
expect(doEventsRequest).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
period: '24h',
})
);
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
loading: false,
allTimeseriesData: [
[
expect.anything(),
[
expect.objectContaining({count: 321}),
expect.objectContaining({count: 79}),
],
],
[expect.anything(), [expect.objectContaining({count: 123})]],
],
timeseriesData: [
{
seriesName: expect.anything(),
data: [
expect.objectContaining({
name: expect.anything(),
value: 123,
}),
],
},
],
previousTimeseriesData: [
expect.objectContaining({
seriesName: 'Previous',
data: [
expect.objectContaining({
name: expect.anything(),
value: 400,
}),
],
}),
],
originalTimeseriesData: [
[expect.anything(), [expect.objectContaining({count: 123})]],
],
originalPreviousTimeseriesData: [
[
expect.anything(),
[
expect.objectContaining({count: 321}),
expect.objectContaining({count: 79}),
],
],
],
})
);
});
it('expands multiple periods in query if `includePrevious`', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
'count()': {
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
},
'failure_count()': {
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 421},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
},
})
);
const multiYOptions = {
yAxis: ['count()', 'failure_count()'],
previousSeriesNames: ['previous count()', 'previous failure_count()'],
};
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
// actionCreator handles expanding the period when calling the API
expect(doEventsRequest).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
period: '24h',
})
);
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
loading: false,
yAxis: ['count()', 'failure_count()'],
previousSeriesNames: ['previous count()', 'previous failure_count()'],
results: [
expect.objectContaining({
data: [expect.objectContaining({name: expect.anything(), value: 123})],
seriesName: 'count()',
}),
expect.objectContaining({
data: [expect.objectContaining({name: expect.anything(), value: 123})],
seriesName: 'failure_count()',
}),
],
previousTimeseriesData: [
expect.objectContaining({
data: [expect.objectContaining({name: expect.anything(), value: 400})],
seriesName: 'previous count()',
stack: 'previous',
}),
expect.objectContaining({
data: [expect.objectContaining({name: expect.anything(), value: 500})],
seriesName: 'previous failure_count()',
stack: 'previous',
}),
],
})
);
});
it('aggregates counts per timestamp only when `includeTimeAggregation` prop is true', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
data: [[new Date(), [COUNT_OBJ, {...COUNT_OBJ, count: 100}]]],
})
);
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
timeAggregatedData: {},
})
);
wrapper.setProps({
includeTimeAggregation: true,
timeAggregationSeriesName: 'aggregated series',
});
await tick();
wrapper.update();
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
timeAggregatedData: {
seriesName: 'aggregated series',
data: [{name: expect.anything(), value: 223}],
},
})
);
});
it('aggregates all counts per timestamp when category name identical', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
data: [[new Date(), [COUNT_OBJ, {...COUNT_OBJ, count: 100}]]],
})
);
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
timeAggregatedData: {},
})
);
wrapper.setProps({
includeTimeAggregation: true,
timeAggregationSeriesName: 'aggregated series',
});
await tick();
wrapper.update();
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
timeAggregatedData: {
seriesName: 'aggregated series',
data: [{name: expect.anything(), value: 223}],
},
})
);
});
});
describe('yAxis', function () {
beforeEach(function () {
doEventsRequest.mockClear();
});
it('supports yAxis', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
})
);
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
loading: false,
allTimeseriesData: [
[
expect.anything(),
[
expect.objectContaining({count: 321}),
expect.objectContaining({count: 79}),
],
],
[expect.anything(), [expect.objectContaining({count: 123})]],
],
timeseriesData: [
{
seriesName: expect.anything(),
data: [
expect.objectContaining({
name: expect.anything(),
value: 123,
}),
],
},
],
previousTimeseriesData: [
expect.objectContaining({
seriesName: 'Previous',
data: [
expect.objectContaining({
name: expect.anything(),
value: 400,
}),
],
}),
],
originalTimeseriesData: [
[expect.anything(), [expect.objectContaining({count: 123})]],
],
originalPreviousTimeseriesData: [
[
expect.anything(),
[
expect.objectContaining({count: 321}),
expect.objectContaining({count: 79}),
],
],
],
})
);
});
it('supports multiple yAxis', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
'epm()': {
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
},
'apdex()': {
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
},
})
);
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
const generateExpected = name => {
return {
seriesName: name,
data: [
{name: expect.anything(), value: 400},
{name: expect.anything(), value: 123},
],
};
};
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
loading: false,
results: [generateExpected('epm()'), generateExpected('apdex()')],
})
);
});
});
describe('topEvents', function () {
beforeEach(function () {
doEventsRequest.mockClear();
});
it('supports topEvents parameter', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
'project1,error': {
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
},
'project1,warning': {
data: [
[
new Date(),
[
{...COUNT_OBJ, count: 321},
{...COUNT_OBJ, count: 79},
],
],
[new Date(), [COUNT_OBJ]],
],
},
})
);
wrapper = mountWithTheme(
{mock}
);
await tick();
wrapper.update();
const generateExpected = name => {
return {
seriesName: name,
data: [
{name: expect.anything(), value: 400},
{name: expect.anything(), value: 123},
],
};
};
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
loading: false,
results: [
generateExpected('project1,error'),
generateExpected('project1,warning'),
],
})
);
});
});
describe('out of retention', function () {
beforeEach(function () {
doEventsRequest.mockClear();
});
it('does not make request', function () {
wrapper = mountWithTheme(
{mock}
);
expect(doEventsRequest).not.toHaveBeenCalled();
});
it('errors', function () {
wrapper = mountWithTheme(
{mock}
);
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
expired: true,
errored: true,
})
);
});
});
describe('timeframe', function () {
beforeEach(function () {
doEventsRequest.mockClear();
});
it('passes query timeframe start and end to the child if supplied by timeseriesData', async function () {
doEventsRequest.mockImplementation(() =>
Promise.resolve({
p95: {
data: [[new Date(), [COUNT_OBJ]]],
start: 1627402280,
end: 1627402398,
},
})
);
wrapper = mountWithTheme({mock});
await tick();
wrapper.update();
expect(mock).toHaveBeenLastCalledWith(
expect.objectContaining({
timeframe: {
start: 1627402280000,
end: 1627402398000,
},
})
);
});
});
});