diff --git a/.betterer.results b/.betterer.results index 65d99476a08..865f680adee 100644 --- a/.betterer.results +++ b/.betterer.results @@ -215,9 +215,6 @@ exports[`no enzyme tests`] = { "public/app/features/dimensions/editors/ThresholdsEditor/ThresholdsEditor.test.tsx:4164297658": [ [0, 17, 13, "RegExp match", "2409514259"] ], - "public/app/features/explore/LiveLogs.test.tsx:156663779": [ - [0, 17, 13, "RegExp match", "2409514259"] - ], "public/app/features/explore/RichHistory/RichHistoryStarredTab.test.tsx:3933225580": [ [0, 17, 13, "RegExp match", "2409514259"] ], diff --git a/public/app/features/explore/LiveLogs.test.tsx b/public/app/features/explore/LiveLogs.test.tsx index 901a0f0a9c7..ceebb895113 100644 --- a/public/app/features/explore/LiveLogs.test.tsx +++ b/public/app/features/explore/LiveLogs.test.tsx @@ -1,88 +1,21 @@ -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; import React from 'react'; import { LogLevel, LogRowModel, MutableDataFrame } from '@grafana/data'; import { LiveLogsWithTheme } from './LiveLogs'; -describe('LiveLogs', () => { - it('renders logs', () => { - const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })]; - const wrapper = mount( - {}} - onPause={() => {}} - onResume={() => {}} - isPaused={true} - /> - ); - - expect(wrapper.contains('log message 1')).toBeTruthy(); - expect(wrapper.contains('log message 2')).toBeTruthy(); - expect(wrapper.contains('log message 3')).toBeTruthy(); - }); - - it('renders new logs only when not paused', () => { - const rows: LogRowModel[] = [makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })]; - const wrapper = mount( - {}} - onPause={() => {}} - onResume={() => {}} - isPaused={true} - /> - ); - - wrapper.setProps({ - ...wrapper.props(), - logRows: [makeLog({ uid: '4' }), makeLog({ uid: '5' }), makeLog({ uid: '6' })], - }); - - expect(wrapper.contains('log message 1')).toBeTruthy(); - expect(wrapper.contains('log message 2')).toBeTruthy(); - expect(wrapper.contains('log message 3')).toBeTruthy(); - - (wrapper.find('LiveLogs').instance() as any).scrollContainerRef.current.scrollTo = () => {}; - - wrapper.setProps({ - ...wrapper.props(), - isPaused: false, - }); - - expect(wrapper.contains('log message 4')).toBeTruthy(); - expect(wrapper.contains('log message 5')).toBeTruthy(); - expect(wrapper.contains('log message 6')).toBeTruthy(); - }); - - it('renders ansi logs', () => { - const rows: LogRowModel[] = [ - makeLog({ uid: '1' }), - makeLog({ hasAnsi: true, raw: 'log message \u001B[31m2\u001B[0m', uid: '2' }), - makeLog({ hasAnsi: true, raw: 'log message \u001B[31m3\u001B[0m', uid: '3' }), - ]; - const wrapper = mount( - {}} - onPause={() => {}} - onResume={() => {}} - isPaused={true} - /> - ); - - expect(wrapper.contains('log message 1')).toBeTruthy(); - expect(wrapper.contains('log message 2')).not.toBeTruthy(); - expect(wrapper.contains('log message 3')).not.toBeTruthy(); - expect(wrapper.find('LogMessageAnsi')).toHaveLength(2); - expect(wrapper.find('LogMessageAnsi').first().prop('value')).toBe('log message \u001B[31m2\u001B[0m'); - expect(wrapper.find('LogMessageAnsi').last().prop('value')).toBe('log message \u001B[31m3\u001B[0m'); - }); -}); +const setup = (rows: LogRowModel[]) => + render( + {}} + onPause={() => {}} + onResume={() => {}} + isPaused={true} + /> + ); const makeLog = (overrides: Partial): LogRowModel => { const uid = overrides.uid || '1'; @@ -106,3 +39,67 @@ const makeLog = (overrides: Partial): LogRowModel => { ...overrides, }; }; + +describe('LiveLogs', () => { + it('renders logs', () => { + setup([makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })]); + + expect(screen.getByRole('cell', { name: 'log message 1' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 2' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 3' })).toBeInTheDocument(); + }); + + it('renders new logs only when not paused', () => { + const { rerender } = setup([makeLog({ uid: '1' }), makeLog({ uid: '2' }), makeLog({ uid: '3' })]); + + rerender( + {}} + onPause={() => {}} + onResume={() => {}} + isPaused={true} + /> + ); + + expect(screen.getByRole('cell', { name: 'log message 1' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 2' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 3' })).toBeInTheDocument(); + expect(screen.queryByRole('cell', { name: 'log message 4' })).not.toBeInTheDocument(); + expect(screen.queryByRole('cell', { name: 'log message 5' })).not.toBeInTheDocument(); + expect(screen.queryByRole('cell', { name: 'log message 6' })).not.toBeInTheDocument(); + + rerender( + {}} + onPause={() => {}} + onResume={() => {}} + isPaused={false} + /> + ); + + expect(screen.getByRole('cell', { name: 'log message 4' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 5' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 6' })).toBeInTheDocument(); + }); + + it('renders ansi logs', () => { + setup([ + makeLog({ uid: '1' }), + makeLog({ hasAnsi: true, raw: 'log message \u001B[31m2\u001B[0m', uid: '2' }), + makeLog({ hasAnsi: true, raw: 'log message \u001B[33m3\u001B[0m', uid: '3' }), + ]); + + expect(screen.getByRole('cell', { name: 'log message 1' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 2' })).toBeInTheDocument(); + expect(screen.getByRole('cell', { name: 'log message 3' })).toBeInTheDocument(); + + const logList = screen.getAllByTestId('ansiLogLine'); + expect(logList).toHaveLength(2); + expect(logList[0]).toHaveAttribute('style', 'color: rgb(204, 0, 0);'); + expect(logList[1]).toHaveAttribute('style', 'color: rgb(204, 102, 0);'); + }); +}); diff --git a/public/app/features/explore/LiveLogs.tsx b/public/app/features/explore/LiveLogs.tsx index bf07dd72aeb..0dbef3c0829 100644 --- a/public/app/features/explore/LiveLogs.tsx +++ b/public/app/features/explore/LiveLogs.tsx @@ -135,7 +135,8 @@ class LiveLogs extends PureComponent { this.liveEndDiv = element; // This is triggered on every update so on every new row. It keeps the view scrolled at the bottom by // default. - if (this.liveEndDiv && !isPaused) { + // As scrollTo is not implemented in JSDOM it needs to be part of the condition + if (this.liveEndDiv && this.scrollContainerRef.current?.scrollTo && !isPaused) { this.scrollContainerRef.current?.scrollTo(0, this.scrollContainerRef.current.scrollHeight); } }}