mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-30 06:05:30 -05:00
4e74fb2694
* Ordering of log entries in the new errors UI * Don't show the expand-collapse widget when not needed; smaller font size in the raw log output * Expose log actions in the log pane. * Use "This project" instead of "Your project" in the new errors UI * Better handling of long log messages; left-ellipsize the file/line number button * Make log location more button-like; add tooltip when needed. * Add a PDF expand button to the toolbar. * Add a stop compilation button to the new compile UI * Use aria-label for button accessible text; improve handling of long filenames in the log location button * Set max-height correctly for the logs pane dropdown * Avoid changing raw logs sizing when expanded and collapsed * Add comment on the solution for right-to-left text and ellipsis * Improve logs pane actions GitOrigin-RevId: 4098d77a9ee6d333644906876b9ff27035b79319
305 lines
8.9 KiB
JavaScript
305 lines
8.9 KiB
JavaScript
import React from 'react'
|
|
import { screen, render, fireEvent } from '@testing-library/react'
|
|
import PreviewPane from '../../../../../frontend/js/features/preview/components/preview-pane'
|
|
const { expect } = require('chai')
|
|
|
|
describe('<PreviewPane />', 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."
|
|
}
|
|
|
|
describe('first error pop-up', function() {
|
|
it('renders a first error pop-up with the first error', function() {
|
|
const propsAfterCompileWithErrors = getProps(false, {
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
})
|
|
render(<PreviewPane {...propsAfterCompileWithErrors} />)
|
|
screen.getByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
screen.getByText(sampleError1.message)
|
|
})
|
|
|
|
it('does not render a first error pop-up when there are only warnings', function() {
|
|
const propsAfterCompileWithWarningsOnly = getProps(false, {
|
|
errors: [],
|
|
warnings: [sampleWarning]
|
|
})
|
|
render(<PreviewPane {...propsAfterCompileWithWarningsOnly} />)
|
|
expect(
|
|
screen.queryByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
).to.not.exist
|
|
})
|
|
|
|
it('does not render a first error pop-up when a compile is ongoing', function() {
|
|
const propsWhileCompiling = getProps(true, {
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
})
|
|
render(<PreviewPane {...propsWhileCompiling} />)
|
|
expect(
|
|
screen.queryByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
).to.not.exist
|
|
})
|
|
|
|
it('does not render a first error pop-up when viewing logs', function() {
|
|
const propsWithErrorsViewingLogs = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
Date.now(),
|
|
true
|
|
)
|
|
render(<PreviewPane {...propsWithErrorsViewingLogs} />)
|
|
expect(
|
|
screen.queryByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
).to.not.exist
|
|
})
|
|
|
|
it('does not render a first error pop-up when going back to the PDF view after viewing logs', function() {
|
|
const nowTimestamp = Date.now()
|
|
const propsWithErrorsViewingLogs = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
nowTimestamp,
|
|
true
|
|
)
|
|
const propsWithErrorsAfterViewingLogs = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
nowTimestamp,
|
|
false
|
|
)
|
|
const { rerender } = render(
|
|
<PreviewPane {...propsWithErrorsViewingLogs} />
|
|
)
|
|
rerender(<PreviewPane {...propsWithErrorsAfterViewingLogs} />)
|
|
expect(
|
|
screen.queryByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
).to.not.exist
|
|
})
|
|
|
|
it('renders a first error pop-up with updated errors after recompiling', function() {
|
|
const nowTimestamp = Date.now()
|
|
const laterTimestamp = Date.now() + 1000
|
|
const propsWithErrorsAfterFirstCompile = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
nowTimestamp,
|
|
true
|
|
)
|
|
const propsWithErrorsAfterSecondCompile = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
laterTimestamp,
|
|
false
|
|
)
|
|
const { rerender } = render(
|
|
<PreviewPane {...propsWithErrorsAfterFirstCompile} />
|
|
)
|
|
rerender(<PreviewPane {...propsWithErrorsAfterSecondCompile} />)
|
|
screen.getByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
screen.getByText(sampleError2.message)
|
|
})
|
|
|
|
it('allows dismissing the first error pop-up', function() {
|
|
const propsWithErrors = getProps(false, {
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
})
|
|
render(<PreviewPane {...propsWithErrors} />)
|
|
const dismissPopUpButton = screen.getByRole('button', {
|
|
name: 'Dismiss first error alert'
|
|
})
|
|
|
|
fireEvent.click(dismissPopUpButton)
|
|
expect(
|
|
screen.queryByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
).to.not.exist
|
|
})
|
|
|
|
it('does not render the first error pop-up with new recompiles after it being dismissed once', function() {
|
|
const nowTimestamp = Date.now()
|
|
const laterTimestamp = Date.now() + 1000
|
|
const propsWithErrorsForFirstCompile = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError1, sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
nowTimestamp
|
|
)
|
|
const propsWithErrorsForSecondCompile = getProps(
|
|
false,
|
|
{
|
|
errors: [sampleError2],
|
|
warnings: [sampleWarning]
|
|
},
|
|
laterTimestamp
|
|
)
|
|
const { rerender } = render(
|
|
<PreviewPane {...propsWithErrorsForFirstCompile} />
|
|
)
|
|
const dismissPopUpButton = screen.getByRole('button', {
|
|
name: 'Dismiss first error alert'
|
|
})
|
|
fireEvent.click(dismissPopUpButton)
|
|
rerender(<PreviewPane {...propsWithErrorsForSecondCompile} />)
|
|
expect(
|
|
screen.queryByRole('alertdialog', {
|
|
name: 'This project has errors. This is the first one.'
|
|
})
|
|
).to.not.exist
|
|
})
|
|
})
|
|
|
|
describe('accessible description of the compile result', function() {
|
|
it('renders an accessible description with the errors and warnings count', function() {
|
|
const errors = [sampleError1, sampleError2]
|
|
const warnings = [sampleWarning]
|
|
const propsWithErrorsAndWarnings = getProps(false, {
|
|
errors,
|
|
warnings
|
|
})
|
|
render(<PreviewPane {...propsWithErrorsAndWarnings} />)
|
|
|
|
screen.getByText(`${errors.length} error${errors.length > 1 ? 's' : ''}`)
|
|
screen.getByText(
|
|
`${warnings.length} warning${warnings.length > 1 ? 's' : ''}`
|
|
)
|
|
})
|
|
it('renders an accessible description for failed compiles with CLSI errors', function() {
|
|
const sampleCLSIError = {
|
|
clsiMaintenance: true
|
|
}
|
|
|
|
const propsWithCLSIError = getProps(
|
|
false,
|
|
{},
|
|
Date.now(),
|
|
false,
|
|
true,
|
|
{},
|
|
sampleCLSIError
|
|
)
|
|
render(<PreviewPane {...propsWithCLSIError} />)
|
|
|
|
screen.getByText('This project did not compile because of an error')
|
|
})
|
|
|
|
it('renders an accessible description for failed compiles with validation issues', function() {
|
|
const sampleValidationIssue = {
|
|
clsiMaintenance: true
|
|
}
|
|
|
|
const propsWithValidationIssue = getProps(
|
|
false,
|
|
{},
|
|
Date.now(),
|
|
false,
|
|
true,
|
|
sampleValidationIssue,
|
|
{}
|
|
)
|
|
render(<PreviewPane {...propsWithValidationIssue} />)
|
|
|
|
screen.getByText(
|
|
'This project did not compile because of a validation issue'
|
|
)
|
|
})
|
|
})
|
|
|
|
function getProps(
|
|
isCompiling = false,
|
|
logEntries = {},
|
|
lastCompileTimestamp = Date.now(),
|
|
isShowingLogs = false,
|
|
compileFailed = false,
|
|
validationIssues = {},
|
|
errors = {}
|
|
) {
|
|
const logEntriesWithDefaults = {
|
|
errors: [],
|
|
warnings: [],
|
|
typesetting: [],
|
|
...logEntries
|
|
}
|
|
logEntriesWithDefaults.all = [
|
|
...logEntriesWithDefaults.errors,
|
|
...logEntriesWithDefaults.warnings,
|
|
...logEntriesWithDefaults.typesetting
|
|
]
|
|
return {
|
|
compilerState: {
|
|
isAutoCompileOn: false,
|
|
isCompiling: isCompiling,
|
|
isClearingCache: false,
|
|
isDraftModeOn: false,
|
|
isSyntaxCheckOn: false,
|
|
lastCompileTimestamp,
|
|
logEntries: logEntriesWithDefaults,
|
|
compileFailed,
|
|
validationIssues,
|
|
errors
|
|
},
|
|
onClearCache: () => {},
|
|
onLogEntryLocationClick: () => {},
|
|
onRecompile: () => {},
|
|
onRecompileFromScratch: () => {},
|
|
onRunSyntaxCheckNow: () => {},
|
|
onSetAutoCompile: () => {},
|
|
onSetDraftMode: () => {},
|
|
onSetSyntaxCheck: () => {},
|
|
onToggleLogs: () => {},
|
|
onSetSplitLayout: () => {},
|
|
onSetFullLayout: () => {},
|
|
onStopCompilation: () => {},
|
|
showLogs: isShowingLogs,
|
|
splitLayout: true
|
|
}
|
|
}
|
|
})
|