1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886 |
- import shuffle from 'lodash/shuffle';
- import {Organization} from 'sentry-fixture/organization';
- import {PageFilters} from 'sentry-fixture/pageFilters';
- import {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable';
- import {NewQuery, SavedQuery} from 'sentry/types';
- import EventView, {
- isAPIPayloadSimilar,
- MetaType,
- pickRelevantLocationQueryStrings,
- } from 'sentry/utils/discover/eventView';
- import {Column} from 'sentry/utils/discover/fields';
- import {
- CHART_AXIS_OPTIONS,
- DiscoverDatasets,
- DISPLAY_MODE_OPTIONS,
- DisplayModes,
- } from 'sentry/utils/discover/types';
- import {AggregationKey, WebVital} from 'sentry/utils/fields';
- import {SpanOperationBreakdownFilter} from 'sentry/views/performance/transactionSummary/filter';
- import {EventsDisplayFilterName} from 'sentry/views/performance/transactionSummary/transactionEvents/utils';
- const generateFields = fields =>
- fields.map(field => ({
- field,
- }));
- const generateSorts = sorts =>
- sorts.map(sortName => ({
- field: sortName,
- kind: 'desc',
- }));
- const REQUIRED_CONSTRUCTOR_PROPS = {
- createdBy: undefined,
- end: undefined,
- environment: [],
- fields: [],
- name: undefined,
- project: [],
- query: '',
- start: undefined,
- team: [],
- sorts: [],
- statsPeriod: undefined,
- topEvents: undefined,
- id: undefined,
- display: undefined,
- };
- describe('EventView constructor', function () {
- it('instantiates default values', function () {
- const eventView = new EventView(REQUIRED_CONSTRUCTOR_PROPS);
- expect(eventView).toMatchObject({
- id: undefined,
- name: undefined,
- fields: [],
- sorts: [],
- query: '',
- project: [],
- start: undefined,
- end: undefined,
- statsPeriod: undefined,
- environment: [],
- yAxis: undefined,
- display: undefined,
- });
- });
- });
- describe('EventView.fromLocation()', function () {
- it('maps query strings', function () {
- const location = TestStubs.location({
- query: {
- id: '42',
- name: 'best query',
- field: ['count()', 'id'],
- widths: ['123', '456'],
- sort: ['title', '-count'],
- query: 'event.type:transaction',
- project: ['123'],
- team: ['myteams', '1', '2'],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'p95',
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- },
- });
- const eventView = EventView.fromLocation(location);
- expect(eventView).toMatchObject({
- id: '42',
- name: 'best query',
- fields: [
- {field: 'count()', width: 123},
- {field: 'id', width: 456},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:transaction',
- project: [123],
- team: ['myteams', 1, 2],
- start: undefined,
- end: undefined,
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'p95',
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- });
- });
- it('includes first valid statsPeriod', function () {
- const location = TestStubs.location({
- query: {
- id: '42',
- name: 'best query',
- field: ['count()', 'id'],
- widths: ['123', '456'],
- sort: ['title', '-count'],
- query: 'event.type:transaction',
- project: ['123'],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: ['invalid', '28d'],
- environment: ['staging'],
- },
- });
- const eventView = EventView.fromLocation(location);
- expect(eventView).toMatchObject({
- id: '42',
- name: 'best query',
- fields: [
- {field: 'count()', width: 123},
- {field: 'id', width: 456},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:transaction',
- project: [123],
- start: undefined,
- end: undefined,
- statsPeriod: '28d',
- environment: ['staging'],
- });
- });
- it('includes start and end', function () {
- const location = TestStubs.location({
- query: {
- id: '42',
- name: 'best query',
- field: ['count()', 'id'],
- widths: ['123', '456'],
- sort: ['title', '-count'],
- query: 'event.type:transaction',
- project: ['123'],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- environment: ['staging'],
- },
- });
- const eventView = EventView.fromLocation(location);
- expect(eventView).toMatchObject({
- id: '42',
- name: 'best query',
- fields: [
- {field: 'count()', width: 123},
- {field: 'id', width: 456},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:transaction',
- project: [123],
- start: '2019-10-01T00:00:00.000',
- end: '2019-10-02T00:00:00.000',
- environment: ['staging'],
- });
- });
- it('generates event view when there are no query strings', function () {
- const location = TestStubs.location({
- query: {},
- });
- const eventView = EventView.fromLocation(location);
- expect(eventView).toMatchObject({
- id: void 0,
- name: void 0,
- fields: [],
- sorts: [],
- query: '',
- project: [],
- start: void 0,
- end: void 0,
- statsPeriod: '14d',
- environment: [],
- yAxis: void 0,
- });
- });
- });
- describe('EventView.fromSavedQuery()', function () {
- it('maps basic properties of saved query', function () {
- const saved: SavedQuery = {
- id: '42',
- name: 'best query',
- fields: ['count()', 'id'],
- query: 'event.type:transaction',
- projects: [123],
- teams: ['myteams', 1],
- range: '14d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- orderby: '-id',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- dateCreated: '2019-10-30T06:13:17.632078Z',
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- version: 2,
- };
- const eventView = EventView.fromSavedQuery(saved);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [123],
- team: ['myteams', 1],
- start: undefined,
- end: undefined,
- // statsPeriod has precedence
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: undefined,
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- });
- const eventView2 = EventView.fromSavedQuery({
- ...saved,
- range: undefined,
- });
- expect(eventView2).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [123],
- team: ['myteams', 1],
- start: '2019-10-01T00:00:00.000',
- end: '2019-10-02T00:00:00.000',
- statsPeriod: undefined,
- environment: ['staging'],
- });
- });
- it('maps saved query with no conditions', function () {
- const saved: SavedQuery = {
- orderby: '-count',
- name: 'foo bar',
- fields: ['release', 'count()'],
- widths: ['111', '222'],
- dateCreated: '2019-10-30T06:13:17.632078Z',
- environment: ['dev', 'production'],
- version: 2,
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- id: '5',
- projects: [1],
- yAxis: ['count()'],
- };
- const eventView = EventView.fromSavedQuery(saved);
- const expected = {
- id: '5',
- name: 'foo bar',
- fields: [
- {field: 'release', width: 111},
- {field: 'count()', width: 222},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: '',
- project: [1],
- environment: ['dev', 'production'],
- yAxis: 'count()',
- };
- expect(eventView).toMatchObject(expected);
- });
- it('maps properties from v2 saved query', function () {
- const saved: SavedQuery = {
- id: '42',
- projects: [123],
- name: 'best query',
- fields: ['count()', 'title'],
- range: '14d',
- start: '',
- end: '',
- dateCreated: '2019-10-30T06:13:17.632078Z',
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- version: 2,
- };
- const eventView = EventView.fromSavedQuery(saved);
- expect(eventView.fields).toEqual([
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'title', width: COL_WIDTH_UNDEFINED},
- ]);
- expect(eventView.name).toEqual(saved.name);
- expect(eventView.statsPeriod).toEqual('14d');
- expect(eventView.start).toEqual(undefined);
- expect(eventView.end).toEqual(undefined);
- });
- it('saved queries are equal when start and end datetime differ in format', function () {
- const saved: SavedQuery = {
- orderby: '-count_timestamp',
- end: '2019-10-23T19:27:04+0000',
- name: 'release query',
- fields: ['release', 'count(timestamp)'],
- dateCreated: '2019-10-30T05:10:23.718937Z',
- environment: ['dev', 'production'],
- start: '2019-10-20T21:02:51+0000',
- version: 2,
- dateUpdated: '2019-10-30T07:25:58.291917Z',
- id: '3',
- projects: [1],
- };
- const eventView = EventView.fromSavedQuery(saved);
- const eventView2 = EventView.fromSavedQuery({
- ...saved,
- start: '2019-10-20T21:02:51Z',
- end: '2019-10-23T19:27:04Z',
- });
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- const eventView3 = EventView.fromSavedQuery({
- ...saved,
- start: '2019-10-20T21:02:51Z',
- });
- expect(eventView.isEqualTo(eventView3)).toBe(true);
- const eventView4 = EventView.fromSavedQuery({
- ...saved,
- end: '2019-10-23T19:27:04Z',
- });
- expect(eventView.isEqualTo(eventView4)).toBe(true);
- });
- it('saved queries are not equal when datetime selection are invalid', function () {
- const saved: SavedQuery = {
- orderby: '-count_timestamp',
- end: '2019-10-23T19:27:04+0000',
- name: 'release query',
- fields: ['release', 'count(timestamp)'],
- dateCreated: '2019-10-30T05:10:23.718937Z',
- environment: ['dev', 'production'],
- start: '2019-10-20T21:02:51+0000',
- version: 2,
- dateUpdated: '2019-10-30T07:25:58.291917Z',
- id: '3',
- projects: [1],
- };
- const eventView = EventView.fromSavedQuery(saved);
- const eventView2 = EventView.fromSavedQuery({
- ...saved,
- start: '',
- });
- expect(eventView.isEqualTo(eventView2)).toBe(false);
- const eventView3 = EventView.fromSavedQuery({
- ...saved,
- end: '',
- });
- expect(eventView.isEqualTo(eventView3)).toBe(false);
- // this is expected since datetime (start and end) are normalized
- expect(eventView2.isEqualTo(eventView3)).toBe(true);
- });
- it('saved queries with undefined yAxis are defaulted to count() when comparing with isEqualTo', function () {
- const saved: SavedQuery = {
- orderby: '-count_timestamp',
- end: '2019-10-23T19:27:04+0000',
- name: 'release query',
- fields: ['release', 'count(timestamp)'],
- dateCreated: '2019-10-30T05:10:23.718937Z',
- environment: ['dev', 'production'],
- start: '2019-10-20T21:02:51+0000',
- version: 2,
- dateUpdated: '2019-10-30T07:25:58.291917Z',
- id: '3',
- projects: [1],
- };
- const eventView = EventView.fromSavedQuery(saved);
- const eventView2 = EventView.fromSavedQuery({
- ...saved,
- yAxis: ['count()'],
- });
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- });
- it('uses the first yAxis from the SavedQuery', function () {
- const saved: SavedQuery = {
- id: '42',
- name: 'best query',
- fields: ['count()', 'id'],
- query: 'event.type:transaction',
- projects: [123],
- teams: ['myteams', 1],
- range: '14d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- orderby: '-id',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- yAxis: ['count()'],
- dateCreated: '2019-10-30T06:13:17.632078Z',
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- version: 2,
- };
- const eventView = EventView.fromSavedQuery(saved);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [123],
- team: ['myteams', 1],
- start: undefined,
- end: undefined,
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'count()',
- dataset: DiscoverDatasets.DISCOVER,
- display: 'previous',
- });
- });
- it('preserves utc with start/end', function () {
- const saved: SavedQuery = {
- id: '42',
- version: 2,
- projects: [123],
- name: 'best query',
- query: 'event.type:transaction',
- fields: ['count()', 'title'],
- start: '2019-10-20T21:02:51+0000',
- end: '2019-10-23T19:27:04+0000',
- utc: 'true',
- dateCreated: '2019-10-30T06:13:17.632078Z',
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- };
- const eventView = EventView.fromSavedQuery(saved);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'title', width: COL_WIDTH_UNDEFINED},
- ],
- query: 'event.type:transaction',
- start: '2019-10-20T21:02:51.000',
- end: '2019-10-23T19:27:04.000',
- utc: 'true',
- });
- });
- });
- describe('EventView.fromNewQueryWithPageFilters()', function () {
- const prebuiltQuery: NewQuery = {
- id: undefined,
- name: 'Page Filter Events',
- query: '',
- projects: undefined,
- fields: ['title', 'project', 'timestamp'],
- orderby: '-timestamp',
- version: 2,
- };
- it('maps basic properties of a prebuilt query', function () {
- const pageFilters = PageFilters();
- const eventView = EventView.fromNewQueryWithPageFilters(prebuiltQuery, pageFilters);
- expect(eventView).toMatchObject({
- id: undefined,
- name: 'Page Filter Events',
- fields: [{field: 'title'}, {field: 'project'}, {field: 'timestamp'}],
- sorts: [{field: 'timestamp', kind: 'desc'}],
- query: '',
- project: [],
- start: undefined,
- end: undefined,
- statsPeriod: '14d',
- environment: [],
- yAxis: undefined,
- });
- });
- it('merges page filter values', function () {
- const pageFilters = TestStubs.PageFilters({
- datetime: {
- period: '3d',
- },
- projects: [42],
- environments: ['prod'],
- });
- const eventView = EventView.fromNewQueryWithPageFilters(prebuiltQuery, pageFilters);
- expect(eventView).toMatchObject({
- id: undefined,
- name: 'Page Filter Events',
- fields: [{field: 'title'}, {field: 'project'}, {field: 'timestamp'}],
- sorts: [{field: 'timestamp', kind: 'desc'}],
- query: '',
- project: [42],
- start: undefined,
- end: undefined,
- statsPeriod: '3d',
- environment: ['prod'],
- yAxis: undefined,
- });
- });
- });
- describe('EventView.fromNewQueryWithLocation()', function () {
- const prebuiltQuery: NewQuery = {
- id: undefined,
- name: 'Sampled Events',
- query: '',
- projects: [],
- fields: ['title', 'event.type', 'project', 'user', 'timestamp'],
- orderby: '-timestamp',
- version: 2,
- };
- it('maps basic properties of a prebuilt query', function () {
- const location = TestStubs.location({
- query: {
- statsPeriod: '99d',
- },
- });
- const eventView = EventView.fromNewQueryWithLocation(prebuiltQuery, location);
- expect(eventView).toMatchObject({
- id: undefined,
- name: 'Sampled Events',
- fields: [
- {field: 'title'},
- {field: 'event.type'},
- {field: 'project'},
- {field: 'user'},
- {field: 'timestamp'},
- ],
- sorts: [{field: 'timestamp', kind: 'desc'}],
- query: '',
- project: [],
- start: undefined,
- end: undefined,
- // statsPeriod has precedence
- statsPeriod: '99d',
- environment: [],
- yAxis: undefined,
- });
- });
- it('merges global selection values', function () {
- const location = TestStubs.location({
- query: {
- statsPeriod: '99d',
- project: ['456'],
- environment: ['prod'],
- },
- });
- const eventView = EventView.fromNewQueryWithLocation(prebuiltQuery, location);
- expect(eventView).toMatchObject({
- id: undefined,
- name: 'Sampled Events',
- fields: [
- {field: 'title'},
- {field: 'event.type'},
- {field: 'project'},
- {field: 'user'},
- {field: 'timestamp'},
- ],
- sorts: [{field: 'timestamp', kind: 'desc'}],
- query: '',
- project: [456],
- start: undefined,
- end: undefined,
- statsPeriod: '99d',
- environment: ['prod'],
- yAxis: undefined,
- });
- });
- it('new query takes precedence over global selection values', function () {
- const location = TestStubs.location({
- query: {
- statsPeriod: '99d',
- project: ['456'],
- environment: ['prod'],
- },
- });
- const prebuiltQuery2: NewQuery = {
- ...prebuiltQuery,
- range: '42d',
- projects: [987],
- environment: ['staging'],
- };
- const eventView = EventView.fromNewQueryWithLocation(prebuiltQuery2, location);
- expect(eventView).toMatchObject({
- id: undefined,
- name: 'Sampled Events',
- fields: [
- {field: 'title'},
- {field: 'event.type'},
- {field: 'project'},
- {field: 'user'},
- {field: 'timestamp'},
- ],
- sorts: [{field: 'timestamp', kind: 'desc'}],
- query: '',
- project: [987],
- start: undefined,
- end: undefined,
- statsPeriod: '42d',
- environment: ['staging'],
- yAxis: undefined,
- });
- // also test start and end
- const location2 = TestStubs.location({
- query: {
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- project: ['456'],
- environment: ['prod'],
- },
- });
- const prebuiltQuery3: NewQuery = {
- ...prebuiltQuery,
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- projects: [987],
- environment: ['staging'],
- };
- const eventView2 = EventView.fromNewQueryWithLocation(prebuiltQuery3, location2);
- expect(eventView2).toMatchObject({
- id: undefined,
- name: 'Sampled Events',
- fields: [
- {field: 'title'},
- {field: 'event.type'},
- {field: 'project'},
- {field: 'user'},
- {field: 'timestamp'},
- ],
- sorts: [{field: 'timestamp', kind: 'desc'}],
- query: '',
- project: [987],
- start: '2019-10-01T00:00:00.000',
- end: '2019-10-02T00:00:00.000',
- statsPeriod: undefined,
- environment: ['staging'],
- yAxis: undefined,
- });
- });
- });
- describe('EventView.fromSavedQueryOrLocation()', function () {
- it('maps basic properties of saved query', function () {
- const saved: SavedQuery = {
- id: '42',
- name: 'best query',
- fields: ['count()', 'id'],
- query: 'event.type:transaction',
- projects: [123],
- range: '14d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- orderby: '-id',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- dateCreated: '2019-10-30T06:13:17.632078Z',
- version: 2,
- };
- const location = TestStubs.location({
- query: {
- statsPeriod: '14d',
- project: ['123'],
- team: ['myteams', '1', '2'],
- environment: ['staging'],
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [123],
- team: ['myteams', 1, 2],
- start: undefined,
- end: undefined,
- // statsPeriod has precedence
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: undefined,
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- });
- const savedQuery2: SavedQuery = {...saved, range: undefined};
- const location2 = TestStubs.location({
- query: {
- project: ['123'],
- environment: ['staging'],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- },
- });
- const eventView2 = EventView.fromSavedQueryOrLocation(savedQuery2, location2);
- expect(eventView2).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [123],
- start: '2019-10-01T00:00:00.000',
- end: '2019-10-02T00:00:00.000',
- statsPeriod: undefined,
- environment: ['staging'],
- });
- });
- it('overrides saved query params with location params', function () {
- const saved: SavedQuery = {
- id: '42',
- name: 'best query',
- fields: ['count()', 'id'],
- query: 'event.type:transaction',
- projects: [123],
- range: '14d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- orderby: '-id',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- dateCreated: '2019-10-30T06:13:17.632078Z',
- version: 2,
- };
- const location = TestStubs.location({
- query: {
- id: '42',
- statsPeriod: '7d',
- project: ['3'],
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [3],
- start: undefined,
- end: undefined,
- // statsPeriod has precedence
- statsPeriod: '7d',
- environment: [],
- yAxis: undefined,
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- });
- });
- it('maps saved query with no conditions', function () {
- const saved: SavedQuery = {
- orderby: '-count',
- name: 'foo bar',
- fields: ['release', 'count()'],
- widths: ['111', '222'],
- dateCreated: '2019-10-30T06:13:17.632078Z',
- query: '',
- environment: [],
- version: 2,
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- projects: [123],
- id: '5',
- yAxis: ['count()'],
- };
- const location = TestStubs.location({
- query: {
- id: '5',
- project: ['1'],
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- const expected = {
- id: '5',
- name: 'foo bar',
- fields: [
- {field: 'release', width: 111},
- {field: 'count()', width: 222},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: '',
- project: [1],
- yAxis: 'count()',
- };
- expect(eventView).toMatchObject(expected);
- });
- it('maps query with cleared conditions', function () {
- const saved: SavedQuery = {
- id: '42',
- name: 'best query',
- fields: ['count()', 'id'],
- query: 'event.type:transaction',
- projects: [123],
- range: '14d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- orderby: '-id',
- environment: ['staging'],
- display: 'previous',
- dateUpdated: '2019-10-30T06:13:17.632096Z',
- dateCreated: '2019-10-30T06:13:17.632078Z',
- version: 2,
- };
- const location = TestStubs.location({
- query: {
- id: '42',
- statsPeriod: '7d',
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- start: undefined,
- end: undefined,
- // statsPeriod has precedence
- statsPeriod: '7d',
- environment: [],
- yAxis: undefined,
- display: 'previous',
- });
- const location2 = TestStubs.location({
- query: {
- id: '42',
- statsPeriod: '7d',
- query: '',
- },
- });
- const eventView2 = EventView.fromSavedQueryOrLocation(saved, location2);
- expect(eventView2).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: '',
- start: undefined,
- end: undefined,
- // statsPeriod has precedence
- statsPeriod: '7d',
- environment: [],
- yAxis: undefined,
- display: 'previous',
- });
- });
- it('event views are equal when start and end datetime differ in format', function () {
- const saved: SavedQuery = {
- orderby: '-count_timestamp',
- end: '2019-10-23T19:27:04+0000',
- name: 'release query',
- fields: ['release', 'count(timestamp)'],
- dateCreated: '2019-10-30T05:10:23.718937Z',
- environment: ['dev', 'production'],
- start: '2019-10-20T21:02:51+0000',
- projects: [123],
- version: 2,
- dateUpdated: '2019-10-30T07:25:58.291917Z',
- id: '3',
- };
- const location = TestStubs.location({
- query: {
- id: '3',
- start: '2019-10-20T21:02:51+0000',
- end: '2019-10-23T19:27:04+0000',
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- const location2 = TestStubs.location({
- query: {
- id: '3',
- start: '2019-10-20T21:02:51Z',
- end: '2019-10-23T19:27:04Z',
- },
- });
- const eventView2 = EventView.fromSavedQueryOrLocation(saved, location2);
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- const location3 = TestStubs.location({
- query: {
- id: '3',
- start: '2019-10-20T21:02:51Z',
- end: '2019-10-23T19:27:04+0000',
- },
- });
- const eventView3 = EventView.fromSavedQueryOrLocation(saved, location3);
- expect(eventView.isEqualTo(eventView3)).toBe(true);
- const location4 = TestStubs.location({
- query: {
- id: '3',
- start: '2019-10-20T21:02:51+0000',
- end: '2019-10-23T19:27:04Z',
- },
- });
- const eventView4 = EventView.fromSavedQueryOrLocation(saved, location4);
- expect(eventView.isEqualTo(eventView4)).toBe(true);
- });
- it('event views are not equal when datetime selection are invalid', function () {
- const saved: SavedQuery = {
- orderby: '-count_timestamp',
- end: '2019-10-23T19:27:04+0000',
- name: 'release query',
- fields: ['release', 'count(timestamp)'],
- dateCreated: '2019-10-30T05:10:23.718937Z',
- environment: ['dev', 'production'],
- start: '2019-10-20T21:02:51+0000',
- version: 2,
- dateUpdated: '2019-10-30T07:25:58.291917Z',
- id: '3',
- projects: [1],
- };
- const location = TestStubs.location({
- query: {
- id: '3',
- end: '2019-10-23T19:27:04+0000',
- start: '2019-10-20T21:02:51+0000',
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- const location2 = TestStubs.location({
- query: {
- id: '3',
- end: '2019-10-23T19:27:04+0000',
- start: '',
- },
- });
- const eventView2 = EventView.fromSavedQueryOrLocation(saved, location2);
- expect(eventView.isEqualTo(eventView2)).toBe(false);
- const location3 = TestStubs.location({
- query: {
- id: '3',
- end: '',
- start: '2019-10-20T21:02:51+0000',
- },
- });
- const eventView3 = EventView.fromSavedQueryOrLocation(saved, location3);
- expect(eventView.isEqualTo(eventView3)).toBe(false);
- // this is expected since datetime (start and end) are normalized
- expect(eventView2.isEqualTo(eventView3)).toBe(true);
- });
- it('uses the first yAxis from the SavedQuery', function () {
- const saved: SavedQuery = {
- id: '42',
- name: 'best query',
- fields: ['count()', 'id'],
- query: 'event.type:transaction',
- projects: [123],
- range: '14d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- orderby: '-id',
- environment: ['staging'],
- display: 'previous',
- yAxis: ['count()', 'failure_count()'],
- dateCreated: '2019-10-30T05:10:23.718937Z',
- dateUpdated: '2019-10-30T07:25:58.291917Z',
- version: 2,
- };
- const location = TestStubs.location({
- query: {
- statsPeriod: '14d',
- project: ['123'],
- team: ['myteams', '1', '2'],
- environment: ['staging'],
- },
- });
- const eventView = EventView.fromSavedQueryOrLocation(saved, location);
- expect(eventView).toMatchObject({
- id: saved.id,
- name: saved.name,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'id', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [{field: 'id', kind: 'desc'}],
- query: 'event.type:transaction',
- project: [123],
- team: ['myteams', 1, 2],
- start: undefined,
- end: undefined,
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'count()',
- display: 'previous',
- });
- });
- it('filters out invalid teams', function () {
- const eventView = EventView.fromSavedQueryOrLocation(
- undefined,
- TestStubs.location({
- query: {
- statsPeriod: '14d',
- project: ['123'],
- team: ['myteams', '1', 'unassigned'],
- environment: ['staging'],
- },
- })
- );
- expect(eventView.team).toEqual(['myteams', 1]);
- });
- });
- describe('EventView.generateQueryStringObject()', function () {
- it('skips empty values', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['id', 'title']),
- sorts: [],
- project: [],
- environment: [],
- statsPeriod: '',
- start: undefined,
- end: undefined,
- yAxis: undefined,
- display: 'previous',
- });
- const expected = {
- id: undefined,
- name: undefined,
- field: ['id', 'title'],
- widths: [],
- sort: [],
- query: '',
- project: [],
- environment: [],
- display: 'previous',
- yAxis: 'count()',
- };
- expect(eventView.generateQueryStringObject()).toEqual(expected);
- });
- it('generates query string object', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [
- {field: 'count()', width: 123},
- {field: 'project.id', width: 456},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'count()',
- display: 'releases',
- interval: '1m',
- };
- const eventView = new EventView(state);
- const expected = {
- id: '1234',
- name: 'best query',
- field: ['count()', 'project.id'],
- widths: [123, 456],
- sort: ['-count'],
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'count()',
- display: 'releases',
- interval: '1m',
- };
- expect(eventView.generateQueryStringObject()).toEqual(expected);
- });
- it('encodes fields', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'id'}, {field: 'title'}],
- sorts: [],
- });
- const query = eventView.generateQueryStringObject();
- expect(query.field).toEqual(['id', 'title']);
- });
- it('returns a copy of data preventing mutation', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'id'}, {field: 'title'}],
- sorts: [],
- });
- const query = eventView.generateQueryStringObject();
- if (Array.isArray(query.field)) {
- query.field.push('newthing');
- }
- // Getting the query again should return the original values.
- const secondQuery = eventView.generateQueryStringObject();
- expect(secondQuery.field).toEqual(['id', 'title']);
- expect(query).not.toEqual(secondQuery);
- });
- });
- describe('EventView.getEventsAPIPayload()', function () {
- it('generates the API payload', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '34',
- name: 'amazing query',
- fields: generateFields(['id']),
- sorts: generateSorts(['id']),
- query: 'event.type:csp',
- project: [567],
- environment: ['prod'],
- yAxis: 'users',
- display: 'releases',
- });
- expect(eventView.getEventsAPIPayload(TestStubs.location())).toEqual({
- field: ['id'],
- per_page: 50,
- sort: '-id',
- query: 'event.type:csp',
- project: ['567'],
- environment: ['prod'],
- statsPeriod: '14d',
- });
- });
- it('does not append query conditions in location', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['id']),
- sorts: [],
- query: 'event.type:csp',
- });
- const location = TestStubs.location({
- query: {
- query: 'TypeError',
- },
- });
- expect(eventView.getEventsAPIPayload(location).query).toEqual('event.type:csp');
- });
- it('only includes at most one sort key', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['count()', 'title']),
- sorts: generateSorts(['title', AggregationKey.COUNT]),
- query: 'event.type:csp',
- });
- const location = TestStubs.location({
- query: {},
- });
- expect(eventView.getEventsAPIPayload(location).sort).toEqual('-title');
- });
- it('only includes sort keys that are defined in fields', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts(['project', AggregationKey.COUNT]),
- query: 'event.type:csp',
- });
- const location = TestStubs.location({
- query: {},
- });
- expect(eventView.getEventsAPIPayload(location).sort).toEqual('-count');
- });
- it('only includes relevant query strings', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts(['project', AggregationKey.COUNT]),
- query: 'event.type:csp',
- });
- const location = TestStubs.location({
- query: {
- start: '2020-08-12 12:13:14',
- end: '2020-08-26 12:13:14',
- utc: 'true',
- statsPeriod: '14d',
- cursor: 'some cursor',
- yAxis: 'count()',
- // irrelevant query strings
- bestCountry: 'canada',
- project: '1234',
- environment: ['staging'],
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- project: [],
- environment: [],
- utc: 'true',
- statsPeriod: '14d',
- field: ['title', 'count()'],
- per_page: 50,
- query: 'event.type:csp',
- sort: '-count',
- cursor: 'some cursor',
- });
- });
- it('includes default coerced statsPeriod when omitted or is invalid', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts(['project', AggregationKey.COUNT]),
- query: 'event.type:csp',
- project: [1234],
- environment: ['staging'],
- });
- const location = TestStubs.location({
- query: {
- start: '',
- end: '',
- utc: 'true',
- // invalid statsPeriod string
- statsPeriod: 'invalid',
- cursor: 'some cursor',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- project: ['1234'],
- environment: ['staging'],
- utc: 'true',
- statsPeriod: '14d',
- field: ['title', 'count()'],
- per_page: 50,
- query: 'event.type:csp',
- sort: '-count',
- cursor: 'some cursor',
- });
- const location2 = TestStubs.location({
- query: {
- start: '',
- end: '',
- utc: 'true',
- // statsPeriod is omitted here
- cursor: 'some cursor',
- },
- });
- expect(eventView.getEventsAPIPayload(location2)).toEqual({
- project: ['1234'],
- environment: ['staging'],
- utc: 'true',
- statsPeriod: '14d',
- field: ['title', 'count()'],
- per_page: 50,
- query: 'event.type:csp',
- sort: '-count',
- cursor: 'some cursor',
- });
- });
- it('includes default coerced statsPeriod when either start or end is only provided', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts(['project', AggregationKey.COUNT]),
- query: 'event.type:csp',
- project: [1234],
- environment: ['staging'],
- });
- const location = TestStubs.location({
- query: {
- start: '',
- utc: 'true',
- statsPeriod: 'invalid',
- cursor: 'some cursor',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- project: ['1234'],
- environment: ['staging'],
- utc: 'true',
- statsPeriod: '14d',
- field: ['title', 'count()'],
- per_page: 50,
- query: 'event.type:csp',
- sort: '-count',
- cursor: 'some cursor',
- });
- const location2 = TestStubs.location({
- query: {
- end: '',
- utc: 'true',
- statsPeriod: 'invalid',
- cursor: 'some cursor',
- },
- });
- expect(eventView.getEventsAPIPayload(location2)).toEqual({
- project: ['1234'],
- environment: ['staging'],
- utc: 'true',
- statsPeriod: '14d',
- field: ['title', 'count()'],
- per_page: 50,
- query: 'event.type:csp',
- sort: '-count',
- cursor: 'some cursor',
- });
- });
- it('includes start and end', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:csp',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- environment: [],
- project: [],
- });
- const location = TestStubs.location({
- query: {
- // these should not be part of the API payload
- statsPeriod: '55d',
- period: '55d',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- field: ['title', 'count()'],
- sort: '-count',
- query: 'event.type:csp',
- start: '2019-10-01T00:00:00.000',
- end: '2019-10-02T00:00:00.000',
- per_page: 50,
- project: [],
- environment: [],
- });
- });
- it("an eventview's date selection has higher precedence than the date selection in the query string", function () {
- const initialState = {
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:csp',
- environment: [],
- project: [],
- };
- const output = {
- field: ['title', 'count()'],
- sort: '-count',
- query: 'event.type:csp',
- per_page: 50,
- project: [],
- environment: [],
- };
- // eventview's statsPeriod has highest precedence
- let eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- ...initialState,
- statsPeriod: '90d',
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- });
- let location = TestStubs.location({
- query: {
- // these should not be part of the API payload
- statsPeriod: '55d',
- period: '30d',
- start: '2020-10-01T00:00:00',
- end: '2020-10-02T00:00:00',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- ...output,
- statsPeriod: '90d',
- });
- // eventview's start/end has higher precedence than the date selection in the query string
- eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- ...initialState,
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- });
- location = TestStubs.location({
- query: {
- // these should not be part of the API payload
- statsPeriod: '55d',
- period: '30d',
- start: '2020-10-01T00:00:00',
- end: '2020-10-02T00:00:00',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- ...output,
- start: '2019-10-01T00:00:00.000',
- end: '2019-10-02T00:00:00.000',
- });
- // the date selection in the query string should be applied as expected
- eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- ...initialState,
- });
- location = TestStubs.location({
- query: {
- statsPeriod: '55d',
- period: '30d',
- start: '2020-10-01T00:00:00',
- end: '2020-10-02T00:00:00',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- ...output,
- statsPeriod: '55d',
- });
- location = TestStubs.location({
- query: {
- period: '30d',
- start: '2020-10-01T00:00:00',
- end: '2020-10-02T00:00:00',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- ...output,
- statsPeriod: '30d',
- });
- location = TestStubs.location({
- query: {
- start: '2020-10-01T00:00:00',
- end: '2020-10-02T00:00:00',
- },
- });
- expect(eventView.getEventsAPIPayload(location)).toEqual({
- ...output,
- start: '2020-10-01T00:00:00.000',
- end: '2020-10-02T00:00:00.000',
- });
- });
- });
- describe('EventView.getFacetsAPIPayload()', function () {
- it('only includes relevant query strings', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: generateFields(['title', 'count()']),
- sorts: generateSorts(['project', AggregationKey.COUNT]),
- query: 'event.type:csp',
- });
- const location = TestStubs.location({
- query: {
- start: '',
- end: '',
- utc: 'true',
- statsPeriod: '14d',
- // irrelevant query strings
- bestCountry: 'canada',
- cursor: 'some cursor',
- sort: 'the world',
- project: '1234',
- environment: ['staging'],
- display: 'releases',
- },
- });
- expect(eventView.getFacetsAPIPayload(location)).toEqual({
- project: [],
- environment: [],
- utc: 'true',
- statsPeriod: '14d',
- query: 'event.type:csp',
- });
- });
- });
- describe('EventView.toNewQuery()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [
- {field: 'count()', width: 123},
- {field: 'project.id', width: 456},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- it('outputs the right fields', function () {
- const eventView = new EventView(state);
- const output = eventView.toNewQuery();
- const expected = {
- version: 2,
- id: '1234',
- name: 'best query',
- fields: ['count()', 'project.id'],
- widths: ['123', '456'],
- orderby: '-count',
- query: 'event.type:error',
- projects: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- range: '14d',
- environment: ['staging'],
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- expect(output).toEqual(expected);
- });
- it('omits query when query is an empty string', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- };
- modifiedState.query = '';
- const eventView = new EventView(modifiedState);
- const output = eventView.toNewQuery();
- const expected = {
- version: 2,
- id: '1234',
- name: 'best query',
- fields: ['count()', 'project.id'],
- widths: ['123', '456'],
- orderby: '-count',
- projects: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- range: '14d',
- environment: ['staging'],
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- expect(output).toEqual(expected);
- });
- it('omits query when query is not defined', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- };
- modifiedState.query = '';
- const eventView = new EventView(modifiedState);
- const output = eventView.toNewQuery();
- const expected = {
- version: 2,
- id: '1234',
- name: 'best query',
- fields: ['count()', 'project.id'],
- widths: ['123', '456'],
- orderby: '-count',
- projects: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- range: '14d',
- environment: ['staging'],
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- expect(output).toEqual(expected);
- });
- });
- describe('EventView.isValid()', function () {
- it('event view is valid when there is at least one field', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: [],
- project: [],
- });
- expect(eventView.isValid()).toBe(true);
- });
- it('event view is not valid when there are no fields', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- project: [],
- });
- expect(eventView.isValid()).toBe(false);
- });
- });
- describe('EventView.getWidths()', function () {
- it('returns widths', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'project.id', width: 2020},
- {field: 'title', width: COL_WIDTH_UNDEFINED},
- {field: 'time', width: 420},
- {field: 'lcp', width: 69},
- {field: 'lcp', width: COL_WIDTH_UNDEFINED},
- {field: 'fcp', width: COL_WIDTH_UNDEFINED},
- {field: 'cls', width: COL_WIDTH_UNDEFINED},
- ],
- sorts: [],
- project: [],
- });
- expect(eventView.getWidths()).toEqual([
- COL_WIDTH_UNDEFINED,
- 2020,
- COL_WIDTH_UNDEFINED,
- 420,
- 69,
- ]);
- });
- });
- describe('EventView.getFields()', function () {
- it('returns fields', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: [],
- project: [],
- });
- expect(eventView.getFields()).toEqual(['count()', 'project.id']);
- });
- });
- describe('EventView.numOfColumns()', function () {
- it('returns correct number of columns', function () {
- // has columns
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: [],
- project: [],
- });
- expect(eventView.numOfColumns()).toBe(2);
- // has no columns
- const eventView2 = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- project: [],
- });
- expect(eventView2.numOfColumns()).toBe(0);
- });
- });
- describe('EventView.getDays()', function () {
- it('returns the right number of days for statsPeriod', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- statsPeriod: '14d',
- });
- expect(eventView.getDays()).toBe(14);
- const eventView2 = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- statsPeriod: '12h',
- });
- expect(eventView2.getDays()).toBe(0.5);
- });
- it('returns the right number of days for start/end', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- });
- expect(eventView.getDays()).toBe(1);
- const eventView2 = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- start: '2019-10-01T00:00:00',
- end: '2019-10-15T00:00:00',
- });
- expect(eventView2.getDays()).toBe(14);
- });
- });
- describe('EventView.clone()', function () {
- it('returns a unique instance', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- interval: '5m',
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- const eventView = new EventView(state);
- const eventView2 = eventView.clone();
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- expect(eventView2).toMatchObject(state);
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- expect(
- eventView.additionalConditions === eventView2.additionalConditions
- ).toBeFalsy();
- });
- });
- describe('EventView.withColumns()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [
- {field: 'count()', width: 30},
- {field: 'project.id', width: 99},
- {field: 'failure_count()', width: 30},
- ],
- yAxis: 'failure_count()',
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const eventView = new EventView(state);
- it('adds new columns, and replaces existing ones', function () {
- const newView = eventView.withColumns([
- {kind: 'field', field: 'title'},
- {kind: 'function', function: [AggregationKey.COUNT, '', undefined, undefined]},
- {kind: 'field', field: 'project.id'},
- {kind: 'field', field: 'culprit'},
- ]);
- // Views should be different.
- expect(newView.isEqualTo(eventView)).toBe(false);
- expect(newView.fields).toEqual([
- {field: 'title', width: COL_WIDTH_UNDEFINED},
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- {field: 'project.id', width: COL_WIDTH_UNDEFINED},
- {field: 'culprit', width: COL_WIDTH_UNDEFINED},
- ]);
- });
- it('drops empty columns', function () {
- const newView = eventView.withColumns([
- {kind: 'field', field: 'issue'},
- {kind: 'function', function: [AggregationKey.COUNT, '', undefined, undefined]},
- {kind: 'field', field: ''},
- {kind: 'function', function: ['', '', undefined, undefined]},
- {kind: 'function', function: ['', '', undefined, undefined]},
- ]);
- expect(newView.fields).toEqual([
- {field: 'issue', width: COL_WIDTH_UNDEFINED},
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- ]);
- });
- it('inherits widths from existing columns when names match', function () {
- const newView = eventView.withColumns([
- {kind: 'function', function: [AggregationKey.COUNT, '', undefined, undefined]},
- {kind: 'field', field: 'project.id'},
- {kind: 'field', field: 'title'},
- {kind: 'field', field: 'time'},
- ]);
- expect(newView.fields).toEqual([
- {field: 'count()', width: 30},
- {field: 'project.id', width: 99},
- {field: 'title', width: COL_WIDTH_UNDEFINED},
- {field: 'time', width: COL_WIDTH_UNDEFINED},
- ]);
- });
- it('retains sorts when sorted field is included', function () {
- const newView = eventView.withColumns([
- {kind: 'field', field: 'title'},
- {kind: 'function', function: [AggregationKey.COUNT, '', undefined, undefined]},
- ]);
- expect(newView.fields).toEqual([
- {field: 'title', width: COL_WIDTH_UNDEFINED},
- {field: 'count()', width: COL_WIDTH_UNDEFINED},
- ]);
- expect(newView.sorts).toEqual([{field: AggregationKey.COUNT, kind: 'desc'}]);
- });
- it('updates sorts when sorted field is removed', function () {
- const newView = eventView.withColumns([{kind: 'field', field: 'title'}]);
- expect(newView.fields).toEqual([{field: 'title', width: COL_WIDTH_UNDEFINED}]);
- // Should pick a sortable field.
- expect(newView.sorts).toEqual([{field: 'title', kind: 'desc'}]);
- });
- it('has no sort if no sortable fields remain', function () {
- const newView = eventView.withColumns([{kind: 'field', field: 'issue'}]);
- expect(newView.fields).toEqual([{field: 'issue', width: COL_WIDTH_UNDEFINED}]);
- expect(newView.sorts).toEqual([]);
- });
- it('updates yAxis if column is dropped', function () {
- const newView = eventView.withColumns([
- {kind: 'field', field: 'count()'},
- {kind: 'field', field: 'project.id'},
- ]);
- expect(newView.fields).toEqual([
- {field: 'count()', width: 30},
- {field: 'project.id', width: 99},
- ]);
- expect(eventView.yAxis).toEqual('failure_count()');
- expect(newView.yAxis).toEqual('count()');
- });
- });
- describe('EventView.withNewColumn()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [
- {field: 'count()', width: 30},
- {field: 'project.id', width: 99},
- ],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- it('adds a field', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'field',
- field: 'title',
- };
- const eventView2 = eventView.withNewColumn(newColumn);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- fields: [...state.fields, {field: 'title'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('adds an aggregate function with no arguments', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.COUNT, '', undefined, undefined],
- };
- const eventView2 = eventView.withNewColumn(newColumn);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- fields: [...state.fields, {field: 'count()'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('add an aggregate function with field', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.AVG, 'transaction.duration', undefined, undefined],
- };
- const eventView2 = eventView.withNewColumn(newColumn);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- fields: [...state.fields, {field: 'avg(transaction.duration)'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('add an aggregate function with field & refinement', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.PERCENTILE, 'transaction.duration', '0.5', undefined],
- };
- const updated = eventView.withNewColumn(newColumn);
- expect(updated.fields).toEqual([
- ...state.fields,
- {field: 'percentile(transaction.duration,0.5)', width: COL_WIDTH_UNDEFINED},
- ]);
- });
- });
- describe('EventView.withResizedColumn()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const view = new EventView(state);
- it('updates a column that exists', function () {
- const newView = view.withResizedColumn(0, 99);
- expect(view.fields[0].width).toBeUndefined();
- expect(newView.fields[0].width).toEqual(99);
- });
- it('ignores columns that do not exist', function () {
- const newView = view.withResizedColumn(100, 99);
- expect(view.fields).toEqual(newView.fields);
- });
- });
- describe('EventView.withUpdatedColumn()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const meta: MetaType = {
- count: 'integer',
- title: 'string',
- };
- it('update a column with no changes', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.COUNT, '', undefined, undefined],
- };
- const eventView2 = eventView.withUpdatedColumn(0, newColumn, meta);
- expect(eventView2 === eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- });
- it('update a column to a field', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'field',
- field: 'title',
- };
- const eventView2 = eventView.withUpdatedColumn(1, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- fields: [state.fields[0], {field: 'title'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('update a column to an aggregate function with no arguments', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.COUNT, '', undefined, undefined],
- };
- const eventView2 = eventView.withUpdatedColumn(1, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- fields: [state.fields[0], {field: 'count()'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('update a column to an aggregate function with field', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.AVG, 'transaction.duration', undefined, undefined],
- };
- const eventView2 = eventView.withUpdatedColumn(1, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- fields: [state.fields[0], {field: 'avg(transaction.duration)'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('update a column to an aggregate function with field & refinement', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.PERCENTILE, 'transaction.duration', '0.5', undefined],
- };
- const newView = eventView.withUpdatedColumn(1, newColumn, meta);
- expect(newView.fields).toEqual([
- state.fields[0],
- {field: 'percentile(transaction.duration,0.5)', width: COL_WIDTH_UNDEFINED},
- ]);
- });
- describe('update a column that is sorted', function () {
- it('the sorted column is the only sorted column', function () {
- const eventView = new EventView(state);
- const newColumn: Column = {
- kind: 'field',
- field: 'title',
- };
- const eventView2 = eventView.withUpdatedColumn(0, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- sorts: [{field: 'title', kind: 'desc'}],
- fields: [{field: 'title'}, state.fields[1]],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('the sorted column occurs at least twice', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [...state.fields, {field: 'count()'}],
- };
- const eventView = new EventView(modifiedState);
- const newColumn: Column = {
- kind: 'field',
- field: 'title',
- };
- const eventView2 = eventView.withUpdatedColumn(0, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(modifiedState);
- const nextState = {
- ...state,
- fields: [{field: 'title'}, state.fields[1], {field: 'count()'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('using no provided table meta', function () {
- // table meta may not be provided in the invalid query state;
- // we will still want to be able to update columns
- const eventView = new EventView(state);
- const expected = {
- ...state,
- sorts: [{field: 'title', kind: 'desc'}],
- fields: [{field: 'title'}, state.fields[1]],
- };
- const newColumn: Column = {
- kind: 'field',
- field: 'title',
- };
- const eventView2 = eventView.withUpdatedColumn(0, newColumn, {});
- expect(eventView2).toMatchObject(expected);
- const eventView3 = eventView.withUpdatedColumn(0, newColumn, undefined);
- expect(eventView3).toMatchObject(expected);
- });
- });
- describe('update a column to a non-sortable column', function () {
- it('default to a sortable column', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [{field: 'count()'}, {field: 'title'}],
- };
- const eventView = new EventView(modifiedState);
- // this column is expected to be non-sortable
- const newColumn: Column = {
- kind: 'field',
- field: 'project.id',
- };
- const eventView2 = eventView.withUpdatedColumn(0, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(modifiedState);
- const nextState = {
- ...state,
- sorts: [{field: 'title', kind: 'desc'}],
- fields: [{field: 'project.id'}, {field: 'title'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('has no sort if there are no sortable columns', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [{field: 'count()'}],
- };
- const eventView = new EventView(modifiedState);
- // this column is expected to be non-sortable
- const newColumn: Column = {
- kind: 'field',
- field: 'project.id',
- };
- const eventView2 = eventView.withUpdatedColumn(0, newColumn, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(modifiedState);
- const nextState = {
- ...state,
- sorts: [],
- fields: [{field: 'project.id'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- });
- });
- describe('EventView.withDeletedColumn()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const meta: MetaType = {
- count: 'integer',
- title: 'string',
- };
- it('returns itself when attempting to delete the last remaining column', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [{field: 'count()'}],
- };
- const eventView = new EventView(modifiedState);
- const eventView2 = eventView.withDeletedColumn(0, meta);
- expect(eventView2 === eventView).toBeTruthy();
- expect(eventView).toMatchObject(modifiedState);
- });
- describe('deletes column, and use any remaining sortable column', function () {
- it('using no provided table meta', function () {
- // table meta may not be provided in the invalid query state;
- // we will still want to be able to delete columns
- const state2 = {
- ...state,
- fields: [{field: 'title'}, {field: 'timestamp'}, {field: 'count()'}],
- sorts: generateSorts(['timestamp']),
- };
- const eventView = new EventView(state2);
- const expected = {
- ...state,
- sorts: generateSorts(['title']),
- fields: [{field: 'title'}, {field: 'count()'}],
- };
- const eventView2 = eventView.withDeletedColumn(1, {});
- expect(eventView2).toMatchObject(expected);
- const eventView3 = eventView.withDeletedColumn(1, undefined);
- expect(eventView3).toMatchObject(expected);
- });
- it('has no remaining sortable column', function () {
- const eventView = new EventView(state);
- const eventView2 = eventView.withDeletedColumn(0, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- const nextState = {
- ...state,
- // we expect sorts to be empty since project.id is non-sortable
- sorts: [],
- fields: [state.fields[1]],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('has a remaining sortable column', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [{field: 'count()'}, {field: 'project.id'}, {field: 'title'}],
- };
- const eventView = new EventView(modifiedState);
- const eventView2 = eventView.withDeletedColumn(0, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(modifiedState);
- const nextState = {
- ...state,
- sorts: [{field: 'title', kind: 'desc'}],
- fields: [{field: 'project.id'}, {field: 'title'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('sorted column occurs at least twice', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [...state.fields, state.fields[0]],
- };
- const eventView = new EventView(modifiedState);
- const eventView2 = eventView.withDeletedColumn(0, meta);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(modifiedState);
- const nextState = {
- ...state,
- fields: [state.fields[1], state.fields[0]],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('ensures there is at one auto-width column on deletion', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [
- {field: 'id', width: 75},
- {field: 'title', width: 100},
- {field: 'project', width: 80},
- {field: 'environment', width: 99},
- ],
- };
- const eventView = new EventView(modifiedState);
- let updated = eventView.withDeletedColumn(0, meta);
- let updatedFields = [
- {field: 'title', width: -1},
- {field: 'project', width: 80},
- {field: 'environment', width: 99},
- ];
- expect(updated.fields).toEqual(updatedFields);
- updated = updated.withDeletedColumn(0, meta);
- updatedFields = [
- {field: 'project', width: -1},
- {field: 'environment', width: 99},
- ];
- expect(updated.fields).toEqual(updatedFields);
- });
- });
- });
- describe('EventView.getSorts()', function () {
- it('returns fields', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- project: [],
- });
- expect(eventView.getSorts()).toEqual([
- {
- key: AggregationKey.COUNT,
- order: 'desc',
- },
- ]);
- });
- });
- describe('EventView.getQuery()', function () {
- it('with query', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- project: [],
- query: 'event.type:error',
- });
- expect(eventView.getQuery()).toEqual('event.type:error');
- expect(eventView.getQuery(null)).toEqual('event.type:error');
- expect(eventView.getQuery('hello')).toEqual('event.type:error hello');
- expect(eventView.getQuery(['event.type:error', 'hello'])).toEqual(
- 'event.type:error hello'
- );
- });
- it('without query', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- project: [],
- });
- expect(eventView.getQuery()).toEqual('');
- expect(eventView.getQuery(null)).toEqual('');
- expect(eventView.getQuery('hello')).toEqual('hello');
- expect(eventView.getQuery(['event.type:error', 'hello'])).toEqual(
- 'event.type:error hello'
- );
- });
- });
- describe('EventView.getQueryWithAdditionalConditions', function () {
- it('with overlapping conditions', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- project: [],
- query: 'event.type:transaction foo:bar',
- });
- eventView.additionalConditions.setFilterValues('event.type', ['transaction']);
- expect(eventView.getQueryWithAdditionalConditions()).toEqual(
- 'event.type:transaction foo:bar'
- );
- });
- });
- describe('EventView.sortForField()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const eventView = new EventView(state);
- const meta: MetaType = {count: 'integer'};
- it('returns the sort when selected field is sorted', function () {
- const field = {
- field: 'count()',
- };
- const actual = eventView.sortForField(field, meta);
- expect(actual).toEqual({
- field: AggregationKey.COUNT,
- kind: 'desc',
- });
- });
- it('returns undefined when selected field is not sorted', function () {
- const field = {
- field: 'project.id',
- };
- expect(eventView.sortForField(field, meta)).toBeUndefined();
- });
- it('returns undefined when no meta is provided', function () {
- const field = {
- field: 'project.id',
- };
- expect(eventView.sortForField(field, undefined)).toBeUndefined();
- });
- });
- describe('EventView.sortOnField()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const meta: MetaType = {count: 'integer', title: 'string'};
- it('returns itself when attempting to sort on un-sortable field', function () {
- const eventView = new EventView(state);
- expect(eventView).toMatchObject(state);
- const field = state.fields[1];
- const eventView2 = eventView.sortOnField(field, meta);
- expect(eventView2 === eventView).toBe(true);
- });
- it('reverses the sorted field', function () {
- const eventView = new EventView(state);
- expect(eventView).toMatchObject(state);
- const field = state.fields[0];
- const eventView2 = eventView.sortOnField(field, meta);
- expect(eventView2 !== eventView).toBe(true);
- const nextState = {
- ...state,
- sorts: [{field: AggregationKey.COUNT, kind: 'asc'}],
- };
- expect(eventView2).toMatchObject(nextState);
- });
- it('enforce sort order on sorted field', function () {
- const eventView = new EventView(state);
- expect(eventView).toMatchObject(state);
- const field = state.fields[0];
- const eventView2 = eventView.sortOnField(field, meta, 'asc');
- expect(eventView2).toMatchObject({
- ...state,
- sorts: [{field: AggregationKey.COUNT, kind: 'asc'}],
- });
- const eventView3 = eventView.sortOnField(field, meta, 'desc');
- expect(eventView3).toMatchObject({
- ...state,
- sorts: [{field: AggregationKey.COUNT, kind: 'desc'}],
- });
- });
- it('supports function format on equation sorts', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [{field: 'count()'}, {field: 'equation|count() + 100'}],
- sorts: [{field: 'equation|count() + 100', kind: 'desc'}],
- };
- const eventView = new EventView(modifiedState);
- expect(eventView).toMatchObject(modifiedState);
- });
- it('supports index format on equation sorts', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [{field: 'count()'}, {field: 'equation|count() + 100'}],
- sorts: [{field: 'equation[0]', kind: 'desc'}],
- };
- const eventView = new EventView(modifiedState);
- expect(eventView).toMatchObject(modifiedState);
- });
- it('sort on new field', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [...state.fields, {field: 'title'}],
- };
- const eventView = new EventView(modifiedState);
- expect(eventView).toMatchObject(modifiedState);
- const field = modifiedState.fields[2];
- const eventView2 = eventView.sortOnField(field, meta);
- expect(eventView2 !== eventView).toBe(true);
- const nextState = {
- ...modifiedState,
- sorts: [{field: 'title', kind: 'desc'}],
- };
- expect(eventView2).toMatchObject(nextState);
- // enforce asc sort order
- const eventView3 = eventView.sortOnField(field, meta, 'asc');
- expect(eventView3).toMatchObject({
- ...modifiedState,
- sorts: [{field: 'title', kind: 'asc'}],
- });
- // enforce desc sort order
- const eventView4 = eventView.sortOnField(field, meta, 'desc');
- expect(eventView4).toMatchObject({
- ...modifiedState,
- sorts: [{field: 'title', kind: 'desc'}],
- });
- });
- it('sorts on a field using function format', function () {
- const modifiedState: ConstructorParameters<typeof EventView>[0] = {
- ...state,
- fields: [...state.fields, {field: 'count()'}],
- };
- const eventView = new EventView(modifiedState);
- expect(eventView).toMatchObject(modifiedState);
- const field = modifiedState.fields[2];
- let sortedEventView = eventView.sortOnField(field, meta, undefined, true);
- expect(sortedEventView.sorts).toEqual([{field: 'count()', kind: 'asc'}]);
- sortedEventView = sortedEventView.sortOnField(field, meta, undefined, true);
- expect(sortedEventView.sorts).toEqual([{field: 'count()', kind: 'desc'}]);
- });
- });
- describe('EventView.withSorts()', function () {
- it('returns a clone', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'event.type'}],
- });
- const updated = eventView.withSorts([{kind: 'desc', field: 'event.type'}]);
- expect(updated.sorts).not.toEqual(eventView.sorts);
- });
- it('only accepts sorting on fields in the view', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'event.type'}],
- });
- const updated = eventView.withSorts([
- {kind: 'desc', field: 'event.type'},
- {kind: 'asc', field: 'unknown'},
- ]);
- expect(updated.sorts).toEqual([{kind: 'desc', field: 'event.type'}]);
- });
- it('accepts aggregate field sorts', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'p50()'}],
- });
- const updated = eventView.withSorts([
- {kind: 'desc', field: 'p50'},
- {kind: 'asc', field: 'unknown'},
- ]);
- expect(updated.sorts).toEqual([{kind: 'desc', field: 'p50'}]);
- });
- });
- describe('EventView.isEqualTo()', function () {
- it('should be true when equal', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'fam',
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- const eventView = new EventView(state);
- const eventView2 = new EventView(state);
- expect(eventView2 !== eventView).toBeTruthy();
- expect(eventView).toMatchObject(state);
- expect(eventView2).toMatchObject(state);
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- // commutativity property holds
- expect(eventView2.isEqualTo(eventView)).toBe(true);
- });
- it('should be true when datetime are equal but differ in format', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-20T21:02:51+0000',
- end: '2019-10-23T19:27:04+0000',
- environment: ['staging'],
- };
- const eventView = new EventView(state);
- const eventView2 = new EventView({
- ...state,
- start: '2019-10-20T21:02:51Z',
- end: '2019-10-23T19:27:04Z',
- });
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- });
- it('should be false when not equal', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'fam',
- display: 'releases',
- dataset: DiscoverDatasets.DISCOVER,
- };
- const differences = {
- id: '12',
- name: 'new query',
- fields: [{field: 'project.id'}, {field: 'count()'}],
- sorts: [{field: AggregationKey.COUNT, kind: 'asc'}],
- query: 'event.type:transaction',
- project: [24],
- start: '2019-09-01T00:00:00',
- end: '2020-09-01T00:00:00',
- statsPeriod: '24d',
- environment: [],
- yAxis: 'ok boomer',
- display: 'previous',
- dataset: DiscoverDatasets.ISSUE_PLATFORM,
- };
- const eventView = new EventView(state);
- for (const key in differences) {
- const eventView2 = new EventView({...state, [key]: differences[key]});
- expect(eventView.isEqualTo(eventView2)).toBe(false);
- }
- });
- it('undefined display type equals default display type', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- yAxis: 'fam',
- };
- const eventView = new EventView(state);
- const eventView2 = new EventView({...state, display: 'default'});
- expect(eventView.isEqualTo(eventView2)).toBe(true);
- });
- });
- describe('EventView.getResultsViewUrlTarget()', function () {
- beforeEach(function () {
- window.__initialData = {
- ...window.__initialData,
- customerDomain: {
- subdomain: 'albertos-apples',
- organizationUrl: 'https://albertos-apples.sentry.io',
- sentryUrl: 'https://sentry.io',
- },
- };
- });
- afterEach(function () {
- window.__initialData = {
- ...window.__initialData,
- customerDomain: null,
- };
- });
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- };
- const organization = Organization();
- it('generates a URL with non-customer domain context', function () {
- window.__initialData.customerDomain = null;
- const view = new EventView(state);
- const result = view.getResultsViewUrlTarget(organization.slug);
- expect(result.pathname).toEqual('/organizations/org-slug/discover/results/');
- expect(result.query.query).toEqual(state.query);
- expect(result.query.project).toEqual(state.project);
- expect(result.query.display).toEqual(state.display);
- });
- it('generates a URL with customer domain context', function () {
- const view = new EventView(state);
- const result = view.getResultsViewUrlTarget(organization.slug);
- expect(result.pathname).toEqual('/discover/results/');
- expect(result.query.query).toEqual(state.query);
- expect(result.query.project).toEqual(state.project);
- expect(result.query.display).toEqual(state.display);
- });
- });
- describe('EventView.getResultsViewShortUrlTarget()', function () {
- beforeEach(function () {
- window.__initialData = {
- ...window.__initialData,
- customerDomain: {
- subdomain: 'albertos-apples',
- organizationUrl: 'https://albertos-apples.sentry.io',
- sentryUrl: 'https://sentry.io',
- },
- };
- });
- afterEach(function () {
- window.__initialData = {
- ...window.__initialData,
- customerDomain: null,
- };
- });
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- };
- const organization = Organization();
- it('generates a URL with non-customer domain context', function () {
- window.__initialData.customerDomain = null;
- const view = new EventView(state);
- const result = view.getResultsViewShortUrlTarget(organization.slug);
- expect(result.pathname).toEqual('/organizations/org-slug/discover/results/');
- expect(result.query).not.toHaveProperty('name');
- expect(result.query).not.toHaveProperty('fields');
- expect(result.query).not.toHaveProperty('query');
- expect(result.query.id).toEqual(state.id);
- expect(result.query.statsPeriod).toEqual(state.statsPeriod);
- expect(result.query.project).toEqual(state.project);
- expect(result.query.environment).toEqual(state.environment);
- });
- it('generates a URL with customer domain context', function () {
- const view = new EventView(state);
- const result = view.getResultsViewShortUrlTarget(organization.slug);
- expect(result.pathname).toEqual('/discover/results/');
- expect(result.query).not.toHaveProperty('name');
- expect(result.query).not.toHaveProperty('fields');
- expect(result.query).not.toHaveProperty('query');
- expect(result.query.id).toEqual(state.id);
- expect(result.query.statsPeriod).toEqual(state.statsPeriod);
- expect(result.query.project).toEqual(state.project);
- expect(result.query.environment).toEqual(state.environment);
- });
- });
- describe('EventView.getPerformanceTransactionEventsViewUrlTarget()', function () {
- beforeEach(function () {
- window.__initialData = {
- ...window.__initialData,
- customerDomain: {
- subdomain: 'albertos-apples',
- organizationUrl: 'https://albertos-apples.sentry.io',
- sentryUrl: 'https://sentry.io',
- },
- };
- });
- afterEach(function () {
- window.__initialData = {
- ...window.__initialData,
- customerDomain: null,
- };
- });
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- display: 'previous',
- dataset: DiscoverDatasets.DISCOVER,
- };
- const organization = Organization();
- const showTransactions = EventsDisplayFilterName.P99;
- const breakdown = SpanOperationBreakdownFilter.HTTP;
- const webVital = WebVital.LCP;
- it('generates a URL with non-customer domain context', function () {
- window.__initialData.customerDomain = null;
- const view = new EventView(state);
- const result = view.getPerformanceTransactionEventsViewUrlTarget(organization.slug, {
- showTransactions,
- breakdown,
- webVital,
- });
- expect(result.pathname).toEqual(
- '/organizations/org-slug/performance/summary/events/'
- );
- expect(result.query.query).toEqual(state.query);
- expect(result.query.project).toEqual(state.project);
- expect(result.query.sort).toEqual(['-count']);
- expect(result.query.transaction).toEqual(state.name);
- expect(result.query.showTransactions).toEqual(showTransactions);
- expect(result.query.breakdown).toEqual(breakdown);
- expect(result.query.webVital).toEqual(webVital);
- });
- it('generates a URL with customer domain context', function () {
- const view = new EventView(state);
- const result = view.getPerformanceTransactionEventsViewUrlTarget(organization.slug, {
- showTransactions,
- breakdown,
- webVital,
- });
- expect(result.pathname).toEqual('/performance/summary/events/');
- expect(result.query.query).toEqual(state.query);
- expect(result.query.project).toEqual(state.project);
- expect(result.query.sort).toEqual(['-count']);
- expect(result.query.transaction).toEqual(state.name);
- expect(result.query.showTransactions).toEqual(showTransactions);
- expect(result.query.breakdown).toEqual(breakdown);
- expect(result.query.webVital).toEqual(webVital);
- });
- });
- describe('EventView.getPageFilters()', function () {
- it('return default global selection', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- });
- expect(eventView.getPageFilters()).toMatchObject({
- projects: [],
- environments: [],
- datetime: {
- start: null,
- end: null,
- period: null,
- // event views currently do not support the utc option,
- // see comment in EventView.getPageFilters
- utc: true,
- },
- });
- });
- it('returns global selection query', function () {
- const state2 = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- project: [42],
- start: 'start',
- end: 'end',
- statsPeriod: '42d',
- environment: ['prod'],
- };
- const eventView = new EventView(state2);
- expect(eventView.getPageFilters()).toMatchObject({
- projects: state2.project,
- environments: state2.environment,
- datetime: {
- start: state2.start,
- end: state2.end,
- period: state2.statsPeriod,
- // event views currently do not support the utc option,
- // see comment in EventView.getPageFilters
- utc: true,
- },
- });
- });
- });
- describe('EventView.getPageFiltersQuery()', function () {
- it('return default global selection query', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- });
- expect(eventView.getPageFiltersQuery()).toMatchObject({
- project: [],
- start: undefined,
- end: undefined,
- statsPeriod: undefined,
- environment: [],
- // event views currently do not support the utc option,
- // see comment in EventView.getPageFilters
- utc: 'true',
- });
- });
- it('returns global selection query', function () {
- const state2 = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- project: [42],
- start: 'start',
- end: 'end',
- statsPeriod: '42d',
- environment: ['prod'],
- };
- const eventView = new EventView(state2);
- expect(eventView.getPageFiltersQuery()).toEqual({
- end: 'end',
- start: 'start',
- statsPeriod: '42d',
- environment: ['prod'],
- project: ['42'],
- utc: 'true',
- });
- });
- });
- describe('EventView.generateBlankQueryStringObject()', function () {
- it('should return blank values', function () {
- const eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- });
- expect(eventView.generateBlankQueryStringObject()).toEqual({
- id: undefined,
- name: undefined,
- fields: undefined,
- sorts: undefined,
- query: undefined,
- project: undefined,
- start: undefined,
- end: undefined,
- statsPeriod: undefined,
- environment: undefined,
- yAxis: undefined,
- cursor: undefined,
- });
- });
- });
- describe('EventView.getYAxisOptions()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- query: '',
- project: [],
- statsPeriod: '42d',
- environment: [],
- };
- function generateYaxis(value) {
- return {
- value,
- label: value,
- };
- }
- it('should return default options', function () {
- const thisEventView = new EventView(state);
- expect(thisEventView.getYAxisOptions()).toEqual(CHART_AXIS_OPTIONS);
- });
- it('should add aggregate fields as options', function () {
- let thisEventView = new EventView({
- ...state,
- fields: generateFields(['ignored-field', 'count_unique(issue)']),
- });
- expect(thisEventView.getYAxisOptions()).toEqual([
- generateYaxis('count_unique(issue)'),
- ...CHART_AXIS_OPTIONS,
- ]);
- // should de-duplicate entries
- thisEventView = new EventView({
- ...state,
- fields: generateFields(['ignored-field', 'count()']),
- });
- expect(thisEventView.getYAxisOptions()).toEqual([...CHART_AXIS_OPTIONS]);
- });
- it('should exclude yAxis options that are not useful', function () {
- const thisEventView = new EventView({
- ...state,
- fields: generateFields([
- 'ignored-field',
- 'count_unique(issue)',
- 'last_seen()',
- 'max(timestamp)',
- ]),
- });
- expect(thisEventView.getYAxisOptions()).toEqual([
- generateYaxis('count_unique(issue)'),
- ...CHART_AXIS_OPTIONS,
- ]);
- });
- });
- describe('EventView.getYAxis()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- query: '',
- project: [],
- statsPeriod: '42d',
- environment: [],
- };
- it('should return first default yAxis', function () {
- const thisEventView = new EventView(state);
- expect(thisEventView.getYAxis()).toEqual('count()');
- });
- it('should return valid yAxis', function () {
- const thisEventView = new EventView({
- ...state,
- fields: generateFields(['ignored-field', 'count_unique(user)', 'last_seen']),
- yAxis: 'count_unique(user)',
- });
- expect(thisEventView.getYAxis()).toEqual('count_unique(user)');
- });
- it('should ignore invalid yAxis', function () {
- const invalid = [
- 'last_seen',
- 'latest_event',
- 'count_unique(issue)', // this is not one of the selected fields
- ];
- for (const option of invalid) {
- const thisEventView = new EventView({
- ...state,
- fields: generateFields(['ignored-field', 'last_seen', 'latest_event']),
- yAxis: option,
- });
- // yAxis defaults to the first entry of the default yAxis options
- expect(thisEventView.getYAxis()).toEqual('count()');
- }
- });
- });
- describe('EventView.getDisplayOptions()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- query: '',
- project: [],
- statsPeriod: '42d',
- environment: [],
- };
- it('should return default options', function () {
- const eventView = new EventView({
- ...state,
- // there needs to exist an aggregate or TOP 5 modes will be disabled
- fields: [{field: 'count()'}],
- });
- expect(eventView.getDisplayOptions()).toEqual(DISPLAY_MODE_OPTIONS);
- });
- it('should disable previous when start/end are used.', function () {
- const eventView = new EventView({
- ...state,
- end: '2020-04-13T12:13:14',
- start: '2020-04-01T12:13:14',
- });
- const options = eventView.getDisplayOptions();
- expect(options[1].value).toEqual('previous');
- expect(options[1].disabled).toBeTruthy();
- });
- it('should disable top 5 period/daily if no aggregates present', function () {
- const eventView = new EventView({
- ...state,
- });
- const options = eventView.getDisplayOptions();
- expect(options[2].value).toEqual('top5');
- expect(options[2].disabled).toBeTruthy();
- expect(options[4].value).toEqual('dailytop5');
- expect(options[4].disabled).toBeTruthy();
- });
- });
- describe('EventView.getDisplayMode()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [],
- sorts: [],
- query: '',
- project: [],
- statsPeriod: '42d',
- environment: [],
- };
- it('should have default', function () {
- const eventView = new EventView({
- ...state,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DEFAULT);
- });
- it('should return current mode when not disabled', function () {
- const eventView = new EventView({
- ...state,
- display: DisplayModes.DAILY,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DAILY);
- });
- it('should return default mode when disabled', function () {
- const eventView = new EventView({
- ...state,
- // the existence of start and end will disable the PREVIOUS mode
- end: '2020-04-13T12:13:14',
- start: '2020-04-01T12:13:14',
- display: DisplayModes.PREVIOUS,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DEFAULT);
- });
- it('top 5 should fallback to default when disabled', function () {
- const eventView = new EventView({
- ...state,
- // the lack of an aggregate will disable the TOP5 mode
- display: DisplayModes.TOP5,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DEFAULT);
- });
- it('top 5 daily should fallback to daily when disabled', function () {
- const eventView = new EventView({
- ...state,
- // the lack of an aggregate will disable the DAILYTOP5 mode
- display: DisplayModes.DAILYTOP5,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DAILY);
- });
- it('daily mode should fall back to default when disabled', function () {
- const eventView = new EventView({
- ...state,
- // the period being less than 24h will disable the DAILY mode
- statsPeriod: '1h',
- display: DisplayModes.DAILY,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DEFAULT);
- });
- it('top 5 daily mode should fall back to default when daily is disabled', function () {
- const eventView = new EventView({
- ...state,
- // the period being less than 24h will disable the DAILY mode
- statsPeriod: undefined,
- start: '2020-04-01T12:13:14',
- end: '2020-04-02T12:10:14',
- display: DisplayModes.DAILYTOP5,
- });
- const displayMode = eventView.getDisplayMode();
- expect(displayMode).toEqual(DisplayModes.DEFAULT);
- });
- });
- describe('EventView.getAggregateFields()', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [
- {field: 'title'},
- {field: 'count()'},
- {field: 'count_unique(user)'},
- {field: 'apdex(300)'},
- {field: 'transaction'},
- ],
- sorts: [],
- query: '',
- project: [],
- statsPeriod: '42d',
- environment: [],
- };
- it('getAggregateFields() returns only aggregates', function () {
- const eventView = new EventView(state);
- const expected = [
- {field: 'count()'},
- {field: 'count_unique(user)'},
- {field: 'apdex(300)'},
- ];
- expect(eventView.getAggregateFields()).toEqual(expected);
- });
- });
- describe('EventView.hasAggregateField', function () {
- it('ensures an eventview has an aggregate field', function () {
- let eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'foobar'}],
- sorts: [],
- query: '',
- project: [],
- environment: [],
- });
- expect(eventView.hasAggregateField()).toBe(false);
- eventView = new EventView({
- ...REQUIRED_CONSTRUCTOR_PROPS,
- fields: [{field: 'count(foo.bar.is-Enterprise_42)'}],
- sorts: [],
- query: '',
- project: [],
- environment: [],
- });
- expect(eventView.hasAggregateField()).toBe(true);
- });
- });
- describe('isAPIPayloadSimilar', function () {
- const state: ConstructorParameters<typeof EventView>[0] = {
- ...REQUIRED_CONSTRUCTOR_PROPS,
- id: '1234',
- name: 'best query',
- fields: [{field: 'count()'}, {field: 'project.id'}],
- sorts: generateSorts([AggregationKey.COUNT]),
- query: 'event.type:error',
- project: [42],
- start: '2019-10-01T00:00:00',
- end: '2019-10-02T00:00:00',
- statsPeriod: '14d',
- environment: ['staging'],
- };
- const meta: MetaType = {
- count: 'integer',
- title: 'string',
- };
- describe('getEventsAPIPayload', function () {
- it('is not similar when relevant query string keys are present in the Location object', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({
- query: {
- project: 'project',
- environment: 'environment',
- start: 'start',
- end: 'end',
- utc: 'utc',
- statsPeriod: 'statsPeriod',
- cursor: 'cursor',
- },
- });
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = thisEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- it('is similar when irrelevant query string keys are present in the Location object', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({
- query: {
- bestCountry: 'canada',
- },
- });
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = thisEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- it('is not similar on sort key sorted in opposite directions', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const otherEventView = thisEventView.sortOnField({field: 'count()'}, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- it('is not similar when a new column is added', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const otherEventView = new EventView({
- ...state,
- fields: [...state.fields, {field: 'title', width: COL_WIDTH_UNDEFINED}],
- });
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- it('is similar when a column is updated with no changes', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.COUNT, '', undefined, undefined],
- };
- const otherEventView = thisEventView.withUpdatedColumn(0, newColumn, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- it('is not similar when a column is updated with a replaced field', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const newColumn: Column = {
- kind: 'field',
- field: 'title',
- };
- const otherEventView = thisEventView.withUpdatedColumn(0, newColumn, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- it('is not similar when a column is updated with a replaced aggregation', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.AVG, '', undefined, undefined],
- };
- const otherEventView = thisEventView.withUpdatedColumn(0, newColumn, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- it('is similar when a column is renamed', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.COUNT, '', undefined, undefined],
- };
- const otherEventView = thisEventView.withUpdatedColumn(0, newColumn, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- it('is not similar when a column is deleted', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const otherEventView = thisEventView.withDeletedColumn(0, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- it('is similar if column order changes', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- const otherEventView = new EventView({...state, fields: shuffle(state.fields)});
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- it('is similar if equation order relatively same', function () {
- const equationField = {field: 'equation|failure_count() / count()'};
- const otherEquationField = {field: 'equation|failure_count() / 2'};
- state.fields = [
- {field: 'project.id'},
- {field: 'count()'},
- equationField,
- otherEquationField,
- ];
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- state.fields = [
- equationField,
- {field: 'project.id'},
- {field: 'count()'},
- otherEquationField,
- ];
- const otherEventView = new EventView(state);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- it('is not similar if equation order changes', function () {
- const equationField = {field: 'equation|failure_count() / count()'};
- const otherEquationField = {field: 'equation|failure_count() / 2'};
- state.fields = [
- {field: 'project.id'},
- {field: 'count()'},
- equationField,
- otherEquationField,
- ];
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getEventsAPIPayload(location);
- state.fields = [
- {field: 'project.id'},
- {field: 'count()'},
- otherEquationField,
- equationField,
- ];
- const otherEventView = new EventView(state);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getEventsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(false);
- });
- });
- describe('getFacetsAPIPayload', function () {
- it('only includes relevant parameters', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const results = thisEventView.getFacetsAPIPayload(location);
- const expected = {
- query: state.query,
- project: ['42'],
- statsPeriod: state.statsPeriod,
- environment: state.environment,
- };
- expect(results).toEqual(expected);
- });
- it('is similar on sort key sorted in opposite directions', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getFacetsAPIPayload(location);
- const newColumn: Column = {
- kind: 'function',
- function: [AggregationKey.COUNT, '', undefined, undefined],
- };
- const otherEventView = thisEventView.withUpdatedColumn(0, newColumn, meta);
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getFacetsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- it('is similar when a columns are different', function () {
- const thisEventView = new EventView(state);
- const location = TestStubs.location({});
- const thisAPIPayload = thisEventView.getFacetsAPIPayload(location);
- const otherEventView = new EventView({
- ...state,
- fields: [...state.fields, {field: 'title', width: COL_WIDTH_UNDEFINED}],
- });
- const otherLocation = TestStubs.location({});
- const otherAPIPayload = otherEventView.getFacetsAPIPayload(otherLocation);
- const results = isAPIPayloadSimilar(thisAPIPayload, otherAPIPayload);
- expect(results).toBe(true);
- });
- });
- });
- describe('pickRelevantLocationQueryStrings', function () {
- it('picks relevant query strings', function () {
- const location = TestStubs.location({
- query: {
- project: 'project',
- environment: 'environment',
- start: 'start',
- end: 'end',
- utc: 'utc',
- statsPeriod: 'statsPeriod',
- cursor: 'cursor',
- // irrelevant query strings
- bestCountry: 'canada',
- },
- });
- const actual = pickRelevantLocationQueryStrings(location);
- const expected = {
- start: 'start',
- end: 'end',
- utc: 'utc',
- statsPeriod: 'statsPeriod',
- cursor: 'cursor',
- };
- expect(actual).toEqual(expected);
- });
- });
|