1import React from 'react'; 2import { LogDetails, Props } from './LogDetails'; 3import { LogRowModel, LogLevel, MutableDataFrame, Field, GrafanaTheme2 } from '@grafana/data'; 4import { mount } from 'enzyme'; 5import { LogDetailsRow } from './LogDetailsRow'; 6 7const setup = (propOverrides?: Partial<Props>, rowOverrides?: Partial<LogRowModel>) => { 8 const props: Props = { 9 theme: {} as GrafanaTheme2, 10 showDuplicates: false, 11 wrapLogMessage: false, 12 row: { 13 dataFrame: new MutableDataFrame(), 14 entryFieldIndex: 0, 15 rowIndex: 0, 16 logLevel: 'error' as LogLevel, 17 timeFromNow: '', 18 timeEpochMs: 1546297200000, 19 timeEpochNs: '1546297200000000000', 20 timeLocal: '', 21 timeUtc: '', 22 hasAnsi: false, 23 hasUnescapedContent: false, 24 entry: '', 25 raw: '', 26 uid: '0', 27 labels: {}, 28 ...(rowOverrides || {}), 29 }, 30 getRows: () => [], 31 onClickFilterLabel: () => {}, 32 onClickFilterOutLabel: () => {}, 33 ...(propOverrides || {}), 34 }; 35 36 return mount(<LogDetails {...props} />); 37}; 38 39describe('LogDetails', () => { 40 describe('when labels are present', () => { 41 it('should render heading', () => { 42 const wrapper = setup(undefined, { labels: { key1: 'label1', key2: 'label2' } }); 43 expect(wrapper.find({ 'aria-label': 'Log labels' }).hostNodes()).toHaveLength(1); 44 }); 45 it('should render labels', () => { 46 const wrapper = setup(undefined, { labels: { key1: 'label1', key2: 'label2' } }); 47 expect(wrapper.text().includes('key1label1key2label2')).toBe(true); 48 }); 49 }); 50 describe('when log row has error', () => { 51 it('should not render log level border', () => { 52 const wrapper = setup({ hasError: true }, undefined); 53 expect(wrapper.find({ 'aria-label': 'Log level' }).html()).not.toContain('logs-row__level'); 54 }); 55 }); 56 describe('when row entry has parsable fields', () => { 57 it('should render heading ', () => { 58 const wrapper = setup(undefined, { entry: 'test=successful' }); 59 expect(wrapper.find({ title: 'Ad-hoc statistics' }).hostNodes()).toHaveLength(1); 60 }); 61 it('should render detected fields', () => { 62 const wrapper = setup(undefined, { entry: 'test=successful' }); 63 expect(wrapper.text().includes('testsuccessful')).toBe(true); 64 }); 65 }); 66 describe('when row entry have parsable fields and labels are present', () => { 67 it('should render all headings', () => { 68 const wrapper = setup(undefined, { entry: 'test=successful', labels: { key: 'label' } }); 69 expect(wrapper.find({ 'aria-label': 'Log labels' })).toHaveLength(1); 70 expect(wrapper.find({ 'aria-label': 'Detected fields' })).toHaveLength(1); 71 }); 72 it('should render all labels and detected fields', () => { 73 const wrapper = setup(undefined, { 74 entry: 'test=successful', 75 labels: { key: 'label' }, 76 }); 77 expect(wrapper.text().includes('keylabel')).toBe(true); 78 expect(wrapper.text().includes('testsuccessful')).toBe(true); 79 }); 80 }); 81 describe('when row entry and labels are not present', () => { 82 it('should render no details available message', () => { 83 const wrapper = setup(undefined, { entry: '' }); 84 expect(wrapper.text().includes('No details available')).toBe(true); 85 }); 86 it('should not render headings', () => { 87 const wrapper = setup(undefined, { entry: '' }); 88 expect(wrapper.find({ 'aria-label': 'Log labels' })).toHaveLength(0); 89 expect(wrapper.find({ 'aria-label': 'Detected fields' })).toHaveLength(0); 90 }); 91 }); 92 93 it('should render fields from dataframe with links', () => { 94 const entry = 'traceId=1234 msg="some message"'; 95 const dataFrame = new MutableDataFrame({ 96 fields: [ 97 { name: 'entry', values: [entry] }, 98 // As we have traceId in message already this will shadow it. 99 { 100 name: 'traceId', 101 values: ['1234'], 102 config: { links: [{ title: 'link', url: 'localhost:3210/${__value.text}' }] }, 103 }, 104 { name: 'userId', values: ['5678'] }, 105 ], 106 }); 107 const wrapper = setup( 108 { 109 getFieldLinks: (field: Field, rowIndex: number) => { 110 if (field.config && field.config.links) { 111 return field.config.links.map((link) => { 112 return { 113 href: link.url.replace('${__value.text}', field.values.get(rowIndex)), 114 title: link.title, 115 target: '_blank', 116 origin: field, 117 }; 118 }); 119 } 120 return []; 121 }, 122 }, 123 { entry, dataFrame, entryFieldIndex: 0, rowIndex: 0 } 124 ); 125 expect(wrapper.find(LogDetailsRow).length).toBe(3); 126 const traceIdRow = wrapper.find(LogDetailsRow).filter({ parsedKey: 'traceId' }); 127 expect(traceIdRow.length).toBe(1); 128 expect(traceIdRow.find('a').hostNodes().length).toBe(1); 129 expect((traceIdRow.find('a').getDOMNode() as HTMLAnchorElement).href).toBe('localhost:3210/1234'); 130 }); 131}); 132