import { screen, fireEvent } from '@testing-library/react' import PreviewLogsPane from '../../../../../frontend/js/features/preview/components/preview-logs-pane' import sinon from 'sinon' import { renderWithEditorContext } from '../../../helpers/render-with-context' const { expect } = require('chai') describe('', function () { const sampleError1 = { content: 'error 1 content', file: 'main.tex', level: 'error', line: 17, message: 'Misplaced alignment tab character &.', } const sampleError2 = { content: 'error 1 content', file: 'main.tex', level: 'error', line: 22, message: 'Extra alignment tab has been changed to cr.', } const sampleWarning = { file: 'main.tex', level: 'warning', line: 30, message: "Reference `idontexist' on page 1 undefined on input line 30.", } const sampleTypesettingIssue = { file: 'main.tex', level: 'typesetting', line: 12, message: "Reference `idontexist' on page 1 undefined on input line 30.", } const sampleRawLog = ` This is pdfTeX, Version 3.14159265-2.6-1.40.21 (TeX Live 2020) (preloaded format=pdflatex 2020.9.10) 6 NOV 2020 15:23 entering extended mode \\write18 enabled. %&-line parsing enabled. **main.tex (/compile/main.tex LaTeX2e <2020-02-02> patch level 5 L3 programming layer <2020-07-17> (/usr/local/texlive/2020/texmf-dist/tex/latex /base/article.cls Document Class: article 2019/12/20 v1.4l Standard LaTeX document class (/usr/local/texlive/2020/texmf-dist/tex/latex/base/size10.clo File: size10.clo 2019/12/20 v1.4l Standard LaTeX file (size option) )` const errors = [sampleError1, sampleError2] const warnings = [sampleWarning] const typesetting = [sampleTypesettingIssue] const logEntries = { all: [...errors, ...warnings, ...typesetting], errors, warnings, typesetting, } const noOp = () => {} const onLogEntryLocationClick = sinon.stub() describe('with logs', function () { beforeEach(function () { renderWithEditorContext( ) }) it('renders all log entries with appropriate labels', function () { const errorEntries = screen.getAllByLabelText( `Log entry with level: error` ) const warningEntries = screen.getAllByLabelText( `Log entry with level: warning` ) const typesettingEntries = screen.getAllByLabelText( `Log entry with level: typesetting` ) expect(errorEntries).to.have.lengthOf(errors.length) expect(warningEntries).to.have.lengthOf(warnings.length) expect(typesettingEntries).to.have.lengthOf(typesetting.length) }) it('renders the raw log', function () { screen.getByLabelText('Raw logs from the LaTeX compiler') }) it('renders a link to location button for every error and warning log entry', function () { logEntries.all.forEach((entry, index) => { const linkToSourceButton = screen.getByRole('button', { name: `Navigate to log position in source code: ${entry.file}, ${entry.line}`, }) fireEvent.click(linkToSourceButton) expect(onLogEntryLocationClick).to.have.callCount(index + 1) const call = onLogEntryLocationClick.getCall(index) expect( call.calledWith({ file: entry.file, line: entry.line, column: entry.column, }) ).to.be.true }) }) it(' does not render a link to location button for the raw log entry', function () { const rawLogEntry = screen.getByLabelText( 'Raw logs from the LaTeX compiler' ) expect(rawLogEntry.querySelector('.log-entry-header-link')).to.not.exist }) }) describe('with over 100 log entries', function () { it('renders only 100 with a warning message', function () { const errors = Array(200).fill(sampleError1) const logEntries = { all: [...errors, ...warnings, ...typesetting], errors, warnings, typesetting, } renderWithEditorContext( ) const displayedLogEntries = screen.getAllByLabelText( `Log entry with level`, { exact: false } ) screen.getByLabelText(`Maximum log entries limit hit`) // should only show the first 100 errors and stop expect(displayedLogEntries).to.have.lengthOf(100) }) }) describe('with validation issues', function () { const sampleValidationIssues = { sizeCheck: { resources: [ { path: 'foo/bar', kbSize: 76221 }, { path: 'bar/baz', kbSize: 2342 }, ], }, mainFile: true, } it('renders a validation entry for known issues', function () { renderWithEditorContext( ) const validationEntries = screen.getAllByLabelText( 'A validation issue which prevented this project from compiling' ) expect(validationEntries).to.have.lengthOf( Object.keys(sampleValidationIssues).length ) }) it('ignores unknown issues', function () { renderWithEditorContext( ) const validationEntries = screen.queryAllByLabelText( 'A validation issue prevented this project from compiling' ) expect(validationEntries).to.have.lengthOf(0) }) }) describe('with compilation errors', function () { const sampleErrors = { clsiMaintenance: true, tooRecentlyCompiled: true, compileTerminated: true, } it('renders an error entry for known errors', function () { renderWithEditorContext( ) const errorEntries = screen.getAllByLabelText( 'An error which prevented this project from compiling' ) expect(errorEntries).to.have.lengthOf(Object.keys(sampleErrors).length) }) it('ignores unknown errors', function () { renderWithEditorContext( ) const errorEntries = screen.queryAllByLabelText( 'There was an error compiling this project' ) expect(errorEntries).to.have.lengthOf(0) }) }) describe('with failing code check', function () { beforeEach(function () { renderWithEditorContext( ) }) it('renders a code check failed entry', function () { screen.getByText( 'Your code has errors that need to be fixed before the auto-compile can run' ) }) }) })