mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 22:23:42 +01:00
Use Hunspell for client-side spellchecking (#20286)
GitOrigin-RevId: c4d0d9e06fe0cc9d7cb7a058fd0768eb024e44f5
This commit is contained in:
+100
@@ -0,0 +1,100 @@
|
||||
import DictionaryModal from '@/features/dictionary/components/dictionary-modal'
|
||||
import { EditorProviders } from '../../../helpers/editor-providers'
|
||||
|
||||
describe('<DictionaryModalContent />', function () {
|
||||
beforeEach(function () {
|
||||
cy.interceptCompile()
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
cy.window().then(win => {
|
||||
win.dispatchEvent(new CustomEvent('learnedWords:doreset'))
|
||||
})
|
||||
})
|
||||
|
||||
it('list words', function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-learnedWords', ['foo', 'bar'])
|
||||
win.dispatchEvent(new CustomEvent('learnedWords:doreset'))
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<DictionaryModal show handleHide={cy.stub()} />
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.findByText('foo')
|
||||
cy.findByText('bar')
|
||||
})
|
||||
|
||||
it('shows message when empty', function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-learnedWords', [])
|
||||
win.dispatchEvent(new CustomEvent('learnedWords:doreset'))
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<DictionaryModal show handleHide={cy.stub()} />
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.contains('Your custom dictionary is empty.')
|
||||
})
|
||||
|
||||
it('removes words', function () {
|
||||
cy.intercept('/spelling/unlearn', { statusCode: 200 })
|
||||
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-learnedWords', ['Foo', 'bar'])
|
||||
win.dispatchEvent(new CustomEvent('learnedWords:doreset'))
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<DictionaryModal show handleHide={cy.stub()} />
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.findByText('Foo')
|
||||
cy.findByText('bar')
|
||||
|
||||
cy.findAllByRole('button', {
|
||||
name: 'Remove from dictionary',
|
||||
})
|
||||
.eq(0)
|
||||
.click()
|
||||
|
||||
cy.findByText('bar').should('not.exist')
|
||||
cy.findByText('Foo')
|
||||
})
|
||||
|
||||
it('handles errors', function () {
|
||||
cy.intercept('/spelling/unlearn', { statusCode: 500 }).as('unlearn')
|
||||
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-learnedWords', ['foo'])
|
||||
win.dispatchEvent(new CustomEvent('learnedWords:doreset'))
|
||||
})
|
||||
|
||||
cy.mount(
|
||||
<EditorProviders>
|
||||
<DictionaryModal show handleHide={cy.stub()} />
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
cy.findByText('foo')
|
||||
|
||||
cy.findAllByRole('button', {
|
||||
name: 'Remove from dictionary',
|
||||
})
|
||||
.eq(0)
|
||||
.click()
|
||||
|
||||
cy.wait('@unlearn')
|
||||
|
||||
cy.findByText('Sorry, something went wrong')
|
||||
cy.findByText('foo')
|
||||
})
|
||||
})
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
import {
|
||||
screen,
|
||||
fireEvent,
|
||||
waitForElementToBeRemoved,
|
||||
} from '@testing-library/react'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import DictionaryModal from '../../../../../frontend/js/features/dictionary/components/dictionary-modal'
|
||||
import { renderWithEditorContext } from '../../../helpers/render-with-context'
|
||||
|
||||
function setLearnedWords(words) {
|
||||
window.metaAttributesCache.set('ol-learnedWords', words)
|
||||
window.dispatchEvent(new CustomEvent('learnedWords:doreset'))
|
||||
}
|
||||
describe('<DictionaryModalContent />', function () {
|
||||
afterEach(function () {
|
||||
fetchMock.reset()
|
||||
setLearnedWords([])
|
||||
})
|
||||
|
||||
it('list words', async function () {
|
||||
setLearnedWords(['foo', 'bar'])
|
||||
renderWithEditorContext(<DictionaryModal show handleHide={() => {}} />)
|
||||
screen.getByText('foo')
|
||||
screen.getByText('bar')
|
||||
})
|
||||
|
||||
it('shows message when empty', async function () {
|
||||
setLearnedWords([])
|
||||
renderWithEditorContext(<DictionaryModal show handleHide={() => {}} />)
|
||||
screen.getByText('Your custom dictionary is empty.')
|
||||
})
|
||||
|
||||
it('removes words', async function () {
|
||||
fetchMock.post('/spelling/unlearn', 200)
|
||||
setLearnedWords(['Foo', 'bar'])
|
||||
renderWithEditorContext(<DictionaryModal show handleHide={() => {}} />)
|
||||
screen.getByText('Foo')
|
||||
screen.getByText('bar')
|
||||
const [firstButton] = screen.getAllByRole('button', {
|
||||
name: 'Remove from dictionary',
|
||||
})
|
||||
fireEvent.click(firstButton)
|
||||
await waitForElementToBeRemoved(() => screen.getByText('bar'))
|
||||
screen.getByText('Foo')
|
||||
})
|
||||
|
||||
it('handles errors', async function () {
|
||||
fetchMock.post('/spelling/unlearn', 500)
|
||||
setLearnedWords(['foo'])
|
||||
renderWithEditorContext(<DictionaryModal show handleHide={() => {}} />)
|
||||
screen.getByText('foo')
|
||||
const [firstButton] = screen.getAllByRole('button', {
|
||||
name: 'Remove from dictionary',
|
||||
})
|
||||
fireEvent.click(firstButton)
|
||||
await fetchMock.flush()
|
||||
screen.getByText('Sorry, something went wrong')
|
||||
screen.getByText('foo')
|
||||
})
|
||||
})
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
import '../../../helpers/bootstrap-3'
|
||||
import { mockScope } from '../helpers/mock-scope'
|
||||
import { EditorProviders } from '../../../helpers/editor-providers'
|
||||
import CodeMirrorEditor from '../../../../../frontend/js/features/source-editor/components/codemirror-editor'
|
||||
import { TestContainer } from '../helpers/test-container'
|
||||
import forEach from 'mocha-each'
|
||||
import PackageVersions from '../../../../../app/src/infrastructure/PackageVersions'
|
||||
|
||||
const languages = [
|
||||
{ code: 'en_GB', dic: 'en_GB', name: 'English (British)' },
|
||||
{ code: 'fr', dic: 'fr', name: 'French' },
|
||||
{ code: 'sv', dic: 'sv_SE', name: 'Swedish' },
|
||||
]
|
||||
|
||||
const suggestions = {
|
||||
en_GB: ['medecine', 'medicine'],
|
||||
fr: ['medecin', 'médecin'],
|
||||
sv: ['medecin', 'medicin'],
|
||||
}
|
||||
|
||||
forEach(Object.keys(suggestions)).describe(
|
||||
'Spell check in client (%s)',
|
||||
(spellCheckLanguage: keyof typeof suggestions) => {
|
||||
const content = `
|
||||
\\documentclass{}
|
||||
|
||||
\\title{}
|
||||
\\author{}
|
||||
|
||||
\\begin{document}
|
||||
\\maketitle
|
||||
|
||||
\\begin{abstract}
|
||||
\\end{abstract}
|
||||
|
||||
\\section{}
|
||||
|
||||
\\end{document}`
|
||||
|
||||
beforeEach(function () {
|
||||
cy.window().then(win => {
|
||||
win.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||
win.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'spell-check-client': 'enabled',
|
||||
})
|
||||
win.metaAttributesCache.set('ol-splitTestInfo', {})
|
||||
win.metaAttributesCache.set('ol-learnedWords', ['baz'])
|
||||
win.metaAttributesCache.set(
|
||||
'ol-dictionariesRoot',
|
||||
`js/dictionaries/${PackageVersions.version.dictionaries}/`
|
||||
)
|
||||
win.metaAttributesCache.set('ol-baseAssetPath', '/__cypress/src/')
|
||||
win.metaAttributesCache.set('ol-languages', languages)
|
||||
})
|
||||
|
||||
cy.interceptEvents()
|
||||
|
||||
const scope = mockScope(content)
|
||||
scope.project.spellCheckLanguage = spellCheckLanguage
|
||||
|
||||
cy.mount(
|
||||
<TestContainer>
|
||||
<EditorProviders scope={scope}>
|
||||
<CodeMirrorEditor />
|
||||
</EditorProviders>
|
||||
</TestContainer>
|
||||
)
|
||||
|
||||
cy.get('.cm-line').eq(13).as('line')
|
||||
cy.get('@line').click()
|
||||
})
|
||||
|
||||
it('shows suggestions for misspelled word', function () {
|
||||
const [from, to] = suggestions[spellCheckLanguage]
|
||||
|
||||
cy.get('@line').type(from)
|
||||
cy.get('@line').get('.ol-cm-spelling-error').contains(from)
|
||||
|
||||
cy.get('@line').get('.ol-cm-spelling-error').rightclick()
|
||||
cy.findByText(to).click()
|
||||
cy.get('@line').contains(to)
|
||||
cy.get('@line').find('.ol-cm-spelling-error').should('not.exist')
|
||||
})
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user