overleaf/services/web/test/frontend/features/preview/components/preview-pane.test.js

306 lines
9 KiB
JavaScript
Raw Normal View History

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: {
autoCompileHasChanges: false,
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,
}
}
})