mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Remove spell check split tests (#21382)
GitOrigin-RevId: 819fc94f55dc1d73e4f58e36dd594a5019c68439
This commit is contained in:
parent
bb465adba1
commit
ea5b521882
31 changed files with 46 additions and 274 deletions
|
@ -14,7 +14,6 @@ const DocstoreManager = require('../Docstore/DocstoreManager')
|
||||||
const logger = require('@overleaf/logger')
|
const logger = require('@overleaf/logger')
|
||||||
const { expressify } = require('@overleaf/promise-utils')
|
const { expressify } = require('@overleaf/promise-utils')
|
||||||
const Settings = require('@overleaf/settings')
|
const Settings = require('@overleaf/settings')
|
||||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
joinProject: expressify(joinProject),
|
joinProject: expressify(joinProject),
|
||||||
|
@ -57,33 +56,9 @@ async function joinProject(req, res, next) {
|
||||||
await ProjectDeleter.promises.unmarkAsDeletedByExternalSource(projectId)
|
await ProjectDeleter.promises.unmarkAsDeletedByExternalSource(projectId)
|
||||||
}
|
}
|
||||||
|
|
||||||
let spellCheckClient
|
|
||||||
try {
|
|
||||||
const assignment = await SplitTestHandler.promises.getAssignmentForUser(
|
|
||||||
userId,
|
|
||||||
'spell-check-client'
|
|
||||||
)
|
|
||||||
spellCheckClient = assignment?.variant === 'enabled'
|
|
||||||
} catch {
|
|
||||||
spellCheckClient = false
|
|
||||||
}
|
|
||||||
|
|
||||||
let spellCheckNoServer
|
|
||||||
try {
|
|
||||||
const assignment = await SplitTestHandler.promises.getAssignmentForUser(
|
|
||||||
userId,
|
|
||||||
'spell-check-no-server'
|
|
||||||
)
|
|
||||||
spellCheckNoServer = assignment?.variant === 'enabled'
|
|
||||||
} catch {
|
|
||||||
spellCheckNoServer = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (project.spellCheckLanguage) {
|
if (project.spellCheckLanguage) {
|
||||||
project.spellCheckLanguage = await chooseSpellCheckLanguage(
|
project.spellCheckLanguage = await chooseSpellCheckLanguage(
|
||||||
project.spellCheckLanguage,
|
project.spellCheckLanguage
|
||||||
spellCheckClient,
|
|
||||||
spellCheckNoServer
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,43 +264,20 @@ async function deleteEntity(req, res, next) {
|
||||||
res.sendStatus(204)
|
res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chooseSpellCheckLanguage(
|
const supportedSpellCheckLanguages = new Set(
|
||||||
spellCheckLanguage,
|
Settings.languages
|
||||||
spellCheckClient = false,
|
// only include spell-check languages that are available in the client
|
||||||
spellCheckNoServer = false
|
.filter(language => language.dic !== undefined)
|
||||||
) {
|
.map(language => language.code)
|
||||||
const supportedSpellCheckLanguages = new Set(
|
)
|
||||||
Settings.languages
|
|
||||||
// optionally only include languages which support client-side spell checking
|
|
||||||
.filter(language => {
|
|
||||||
if (!spellCheckClient) {
|
|
||||||
// only include spell-check languages that are available on the server
|
|
||||||
return language.server !== false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spellCheckNoServer) {
|
|
||||||
// only include spell-check languages that are available in the client
|
|
||||||
return language.dic !== undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
.map(language => language.code)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
async function chooseSpellCheckLanguage(spellCheckLanguage) {
|
||||||
if (supportedSpellCheckLanguages.has(spellCheckLanguage)) {
|
if (supportedSpellCheckLanguages.has(spellCheckLanguage)) {
|
||||||
return spellCheckLanguage
|
return spellCheckLanguage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable spell checking for currently unsupported spell check languages.
|
|
||||||
// Preserve the value in the database so they can use it again once we add back support.
|
// Preserve the value in the database so they can use it again once we add back support.
|
||||||
|
// Map some server-only languages to a specific variant, or disable spell checking for currently unsupported spell check languages.
|
||||||
// existing behaviour: map all unsupported languages to "off"
|
|
||||||
if (!spellCheckNoServer) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// new behaviour: map some server-only languages to a specific variant
|
|
||||||
switch (spellCheckLanguage) {
|
switch (spellCheckLanguage) {
|
||||||
case 'en':
|
case 'en':
|
||||||
// map "English" to "English (American)"
|
// map "English" to "English (American)"
|
||||||
|
|
|
@ -348,8 +348,6 @@ const _ProjectController = {
|
||||||
'write-and-cite-ars',
|
'write-and-cite-ars',
|
||||||
'default-visual-for-beginners',
|
'default-visual-for-beginners',
|
||||||
'hotjar',
|
'hotjar',
|
||||||
'spell-check-client',
|
|
||||||
'spell-check-no-server',
|
|
||||||
].filter(Boolean)
|
].filter(Boolean)
|
||||||
|
|
||||||
const getUserValues = async userId =>
|
const getUserValues = async userId =>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
interceptDeferredCompile,
|
interceptDeferredCompile,
|
||||||
} from './compile'
|
} from './compile'
|
||||||
import { interceptEvents } from './events'
|
import { interceptEvents } from './events'
|
||||||
import { interceptSpelling } from './spelling'
|
|
||||||
import { interceptAsync } from './intercept-async'
|
import { interceptAsync } from './intercept-async'
|
||||||
import { interceptFileUpload } from './upload'
|
import { interceptFileUpload } from './upload'
|
||||||
import { interceptProjectListing } from './project-list'
|
import { interceptProjectListing } from './project-list'
|
||||||
|
@ -24,7 +23,6 @@ declare global {
|
||||||
interceptCompile: typeof interceptCompile
|
interceptCompile: typeof interceptCompile
|
||||||
interceptEvents: typeof interceptEvents
|
interceptEvents: typeof interceptEvents
|
||||||
interceptMetadata: typeof interceptMetadata
|
interceptMetadata: typeof interceptMetadata
|
||||||
interceptSpelling: typeof interceptSpelling
|
|
||||||
waitForCompile: typeof waitForCompile
|
waitForCompile: typeof waitForCompile
|
||||||
interceptDeferredCompile: typeof interceptDeferredCompile
|
interceptDeferredCompile: typeof interceptDeferredCompile
|
||||||
interceptFileUpload: typeof interceptFileUpload
|
interceptFileUpload: typeof interceptFileUpload
|
||||||
|
@ -40,7 +38,6 @@ Cypress.Commands.add('interceptAsync', interceptAsync)
|
||||||
Cypress.Commands.add('interceptCompile', interceptCompile)
|
Cypress.Commands.add('interceptCompile', interceptCompile)
|
||||||
Cypress.Commands.add('interceptEvents', interceptEvents)
|
Cypress.Commands.add('interceptEvents', interceptEvents)
|
||||||
Cypress.Commands.add('interceptMetadata', interceptMetadata)
|
Cypress.Commands.add('interceptMetadata', interceptMetadata)
|
||||||
Cypress.Commands.add('interceptSpelling', interceptSpelling)
|
|
||||||
Cypress.Commands.add('waitForCompile', waitForCompile)
|
Cypress.Commands.add('waitForCompile', waitForCompile)
|
||||||
Cypress.Commands.add('interceptDeferredCompile', interceptDeferredCompile)
|
Cypress.Commands.add('interceptDeferredCompile', interceptDeferredCompile)
|
||||||
Cypress.Commands.add('interceptFileUpload', interceptFileUpload)
|
Cypress.Commands.add('interceptFileUpload', interceptFileUpload)
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export const interceptSpelling = () => {
|
|
||||||
cy.intercept('POST', '/spelling/check', [])
|
|
||||||
}
|
|
|
@ -4,34 +4,19 @@ import getMeta from '../../../../utils/meta'
|
||||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||||
import SettingsMenuSelect from './settings-menu-select'
|
import SettingsMenuSelect from './settings-menu-select'
|
||||||
import type { Optgroup } from './settings-menu-select'
|
import type { Optgroup } from './settings-menu-select'
|
||||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
|
||||||
import { useEditorContext } from '@/shared/context/editor-context'
|
import { useEditorContext } from '@/shared/context/editor-context'
|
||||||
|
|
||||||
export default function SettingsSpellCheckLanguage() {
|
export default function SettingsSpellCheckLanguage() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const languages = getMeta('ol-languages')
|
|
||||||
|
|
||||||
const spellCheckClientEnabled = useFeatureFlag('spell-check-client')
|
|
||||||
const spellCheckNoServer = useFeatureFlag('spell-check-no-server')
|
|
||||||
|
|
||||||
const { spellCheckLanguage, setSpellCheckLanguage } =
|
const { spellCheckLanguage, setSpellCheckLanguage } =
|
||||||
useProjectSettingsContext()
|
useProjectSettingsContext()
|
||||||
const { permissionsLevel } = useEditorContext()
|
const { permissionsLevel } = useEditorContext()
|
||||||
|
|
||||||
const optgroup: Optgroup = useMemo(() => {
|
const optgroup: Optgroup = useMemo(() => {
|
||||||
const options = (languages ?? []).filter(language => {
|
const options = (getMeta('ol-languages') ?? [])
|
||||||
if (!spellCheckClientEnabled) {
|
// only include spell-check languages that are available in the client
|
||||||
// only include spell-check languages that are available on the server
|
.filter(language => language.dic !== undefined)
|
||||||
return language.server !== false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spellCheckNoServer) {
|
|
||||||
// only include spell-check languages that are available in the client
|
|
||||||
return language.dic !== undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: 'Language',
|
label: 'Language',
|
||||||
|
@ -40,7 +25,7 @@ export default function SettingsSpellCheckLanguage() {
|
||||||
label: language.name,
|
label: language.name,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}, [languages, spellCheckClientEnabled, spellCheckNoServer])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsMenuSelect
|
<SettingsMenuSelect
|
||||||
|
|
|
@ -1,35 +1,13 @@
|
||||||
import { postJSON } from '../../../../infrastructure/fetch-json'
|
import { postJSON } from '@/infrastructure/fetch-json'
|
||||||
import { Word } from './spellchecker'
|
import { Word } from './spellchecker'
|
||||||
|
|
||||||
const apiUrl = (path: string) => {
|
|
||||||
return `/spelling${path}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function learnWordRequest(word?: Word) {
|
export async function learnWordRequest(word?: Word) {
|
||||||
if (!word || !word.text) {
|
if (!word || !word.text) {
|
||||||
throw new Error(`Invalid word supplied: ${word}`)
|
throw new Error(`Invalid word supplied: ${word}`)
|
||||||
}
|
}
|
||||||
return await postJSON(apiUrl('/learn'), {
|
return await postJSON('/spelling/learn', {
|
||||||
body: {
|
body: {
|
||||||
word: word.text,
|
word: word.text,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spellCheckRequest(
|
|
||||||
language: string,
|
|
||||||
words: Word[],
|
|
||||||
controller: AbortController
|
|
||||||
) {
|
|
||||||
const signal = controller.signal
|
|
||||||
const textWords = words.map(w => w.text)
|
|
||||||
return postJSON<{
|
|
||||||
misspellings: { index: number; suggestions: string[] }[]
|
|
||||||
}>(apiUrl('/check'), {
|
|
||||||
body: {
|
|
||||||
language,
|
|
||||||
words: textWords,
|
|
||||||
},
|
|
||||||
signal,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { ignoredWordsField, resetSpellChecker } from './ignored-words'
|
||||||
import { cacheField, addWordToCache, WordCacheValue } from './cache'
|
import { cacheField, addWordToCache, WordCacheValue } from './cache'
|
||||||
import { WORD_REGEX } from './helpers'
|
import { WORD_REGEX } from './helpers'
|
||||||
import OError from '@overleaf/o-error'
|
import OError from '@overleaf/o-error'
|
||||||
import { spellCheckRequest } from './backend'
|
|
||||||
import { EditorView, ViewUpdate } from '@codemirror/view'
|
import { EditorView, ViewUpdate } from '@codemirror/view'
|
||||||
import { ChangeSet, Line, Range, RangeValue } from '@codemirror/state'
|
import { ChangeSet, Line, Range, RangeValue } from '@codemirror/state'
|
||||||
import { IgnoredWords } from '../../../dictionary/ignored-words'
|
import { IgnoredWords } from '../../../dictionary/ignored-words'
|
||||||
|
@ -158,16 +157,6 @@ export class SpellChecker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
spellCheckRequest(this.language, unknownWords, this.abortController)
|
|
||||||
.then(result => {
|
|
||||||
this.abortController = null
|
|
||||||
return processResult(result.misspellings)
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.abortController = null
|
|
||||||
debugConsole.error(error)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { FC, memo } from 'react'
|
import { FC, memo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useSplitTest } from '@/shared/context/split-test-context'
|
|
||||||
import { chooseBadgeClass } from '@/shared/components/beta-badge'
|
|
||||||
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
|
||||||
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
import BootstrapVersionSwitcher from '@/features/ui/components/bootstrap-5/bootstrap-version-switcher'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
|
@ -9,46 +7,36 @@ import MaterialIcon from '@/shared/components/material-icon'
|
||||||
|
|
||||||
const SpellingSuggestionsFeedback: FC = () => {
|
const SpellingSuggestionsFeedback: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { info } = useSplitTest('spell-check-client')
|
|
||||||
|
|
||||||
if (!info) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const { tooltipText, url } = info.badgeInfo ?? {}
|
|
||||||
const badgeClass = chooseBadgeClass(info.phase)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OLTooltip
|
<OLTooltip
|
||||||
id="spell-check-client-tooltip"
|
id="spell-check-client-tooltip"
|
||||||
description={
|
description={
|
||||||
tooltipText || (
|
<>
|
||||||
<>
|
The spell-checker has been updated.
|
||||||
We are testing an updated spellchecker.
|
<br />
|
||||||
<br />
|
Click to give feedback
|
||||||
Click to give feedback
|
</>
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
tooltipProps={{ className: 'split-test-badge-tooltip' }}
|
tooltipProps={{ className: 'split-test-badge-tooltip' }}
|
||||||
overlayProps={{ placement: 'bottom', delay: 100 }}
|
overlayProps={{ placement: 'bottom', delay: 100 }}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href={url || '/beta/participate'}
|
href="https://docs.google.com/forms/d/e/1FAIpQLSdD1wa5SiCZ7x_UF6e8vywTN82kSm6ou2rTKz-XBiEjNilOXQ/viewform"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
<BootstrapVersionSwitcher
|
<BootstrapVersionSwitcher
|
||||||
bs3={
|
bs3={
|
||||||
<span
|
<span
|
||||||
className={classnames('badge', badgeClass)}
|
className={classnames('badge', 'info-badge')}
|
||||||
style={{ width: 14, height: 14 }}
|
style={{ width: 14, height: 14 }}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
bs5={
|
bs5={
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
type="info"
|
type="info"
|
||||||
className={classnames('align-middle', badgeClass)}
|
className={classnames('align-middle', 'info-badge')}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { SpellChecker, Word } from './spellchecker'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import getMeta from '@/utils/meta'
|
import getMeta from '@/utils/meta'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
|
||||||
import { sendMB } from '@/infrastructure/event-tracking'
|
import { sendMB } from '@/infrastructure/event-tracking'
|
||||||
import SpellingSuggestionsFeedback from './spelling-suggestions-feedback'
|
import SpellingSuggestionsFeedback from './spelling-suggestions-feedback'
|
||||||
import { SpellingSuggestionsLanguage } from './spelling-suggestions-language'
|
import { SpellingSuggestionsLanguage } from './spelling-suggestions-language'
|
||||||
|
@ -76,14 +75,12 @@ export const SpellingSuggestions: FC<{
|
||||||
|
|
||||||
const language = useMemo(() => {
|
const language = useMemo(() => {
|
||||||
if (spellCheckLanguage) {
|
if (spellCheckLanguage) {
|
||||||
return getMeta('ol-languages').find(
|
return (getMeta('ol-languages') ?? []).find(
|
||||||
item => item.code === spellCheckLanguage
|
item => item.code === spellCheckLanguage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, [spellCheckLanguage])
|
}, [spellCheckLanguage])
|
||||||
|
|
||||||
const spellCheckClientEnabled = useFeatureFlag('spell-check-client')
|
|
||||||
|
|
||||||
if (!language) {
|
if (!language) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
@ -146,7 +143,7 @@ export const SpellingSuggestions: FC<{
|
||||||
/>
|
/>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{spellCheckClientEnabled && language.dic && (
|
{getMeta('ol-isSaas') && (
|
||||||
<>
|
<>
|
||||||
<li className="divider" />
|
<li className="divider" />
|
||||||
<li role="menuitem">
|
<li role="menuitem">
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import getMeta from '@/utils/meta'
|
import getMeta from '@/utils/meta'
|
||||||
import { globalLearnedWords } from '@/features/dictionary/ignored-words'
|
import { globalLearnedWords } from '@/features/dictionary/ignored-words'
|
||||||
|
@ -9,24 +8,23 @@ export const useHunspell = (spellCheckLanguage: string | null) => {
|
||||||
const [hunspellManager, setHunspellManager] = useState<HunspellManager>()
|
const [hunspellManager, setHunspellManager] = useState<HunspellManager>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isSplitTestEnabled('spell-check-client')) {
|
if (spellCheckLanguage) {
|
||||||
if (spellCheckLanguage) {
|
const lang = (getMeta('ol-languages') ?? []).find(
|
||||||
const languages = getMeta('ol-languages')
|
item => item.code === spellCheckLanguage
|
||||||
const lang = languages.find(item => item.code === spellCheckLanguage)
|
)
|
||||||
if (lang?.dic) {
|
if (lang?.dic) {
|
||||||
const hunspellManager = new HunspellManager(lang.dic, [
|
const hunspellManager = new HunspellManager(lang.dic, [
|
||||||
...globalLearnedWords,
|
...globalLearnedWords,
|
||||||
...getMeta('ol-learnedWords'),
|
...getMeta('ol-learnedWords'),
|
||||||
])
|
])
|
||||||
setHunspellManager(hunspellManager)
|
setHunspellManager(hunspellManager)
|
||||||
debugConsole.log(spellCheckLanguage, hunspellManager)
|
debugConsole.log(spellCheckLanguage, hunspellManager)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
hunspellManager.destroy()
|
hunspellManager.destroy()
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setHunspellManager(undefined)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setHunspellManager(undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [spellCheckLanguage])
|
}, [spellCheckLanguage])
|
||||||
|
|
|
@ -441,10 +441,12 @@ describe('<EditorLeftMenu />', function () {
|
||||||
{
|
{
|
||||||
name: 'Lang 1',
|
name: 'Lang 1',
|
||||||
code: 'lang-1',
|
code: 'lang-1',
|
||||||
|
dic: 'lang_1',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Lang 2',
|
name: 'Lang 2',
|
||||||
code: 'lang-2',
|
code: 'lang-2',
|
||||||
|
dic: 'lang_2',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,12 @@ describe('<SettingsSpellCheckLanguage />', function () {
|
||||||
{
|
{
|
||||||
name: 'Lang 1',
|
name: 'Lang 1',
|
||||||
code: 'lang-1',
|
code: 'lang-1',
|
||||||
|
dic: 'lang_1',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Lang 2',
|
name: 'Lang 2',
|
||||||
code: 'lang-2',
|
code: 'lang-2',
|
||||||
|
dic: 'lang_2',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ describe('<ReviewPanel />', function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
|
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const scope = mockScope('')
|
const scope = mockScope('')
|
||||||
scope.editor.showVisual = true
|
scope.editor.showVisual = true
|
||||||
|
|
|
@ -16,7 +16,6 @@ describe('autocomplete', { scrollBehavior: false }, function () {
|
||||||
window.metaAttributesCache.set('ol-showSymbolPalette', true)
|
window.metaAttributesCache.set('ol-showSymbolPalette', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('opens autocomplete on matched text', function () {
|
it('opens autocomplete on matched text', function () {
|
||||||
|
|
|
@ -8,7 +8,6 @@ describe('close brackets', { scrollBehavior: false }, function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const scope = mockScope()
|
const scope = mockScope()
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ ${'long line '.repeat(200)}`
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const scope = mockScope(content)
|
const scope = mockScope(content)
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ describe('<FigureModal />', function () {
|
||||||
cy.interceptMathJax()
|
cy.interceptMathJax()
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
mount()
|
mount()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ test
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const scope = mockScope(content)
|
const scope = mockScope(content)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ describe('keyboard shortcuts', { scrollBehavior: false }, function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const scope = mockScope()
|
const scope = mockScope()
|
||||||
|
|
||||||
|
@ -127,7 +126,6 @@ describe('emacs keybindings', { scrollBehavior: false }, function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const shortDoc = `
|
const shortDoc = `
|
||||||
\\documentclass{article}
|
\\documentclass{article}
|
||||||
|
@ -229,7 +227,6 @@ describe('vim keybindings', { scrollBehavior: false }, function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
// Make a short doc that will fit entirely into the dom tree, so that
|
// Make a short doc that will fit entirely into the dom tree, so that
|
||||||
// index() corresponds to line number - 1
|
// index() corresponds to line number - 1
|
||||||
|
|
|
@ -114,14 +114,6 @@ forEach(Object.keys(suggestions)).describe(
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
cy.window().then(win => {
|
cy.window().then(win => {
|
||||||
win.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
win.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
win.metaAttributesCache.set('ol-splitTestVariants', {
|
|
||||||
'spell-check-client': 'enabled',
|
|
||||||
'spell-check-no-server': 'enabled',
|
|
||||||
})
|
|
||||||
win.metaAttributesCache.set('ol-splitTestInfo', {
|
|
||||||
'spell-check-client': { phase: 'release' },
|
|
||||||
'spell-check-no-server': { phase: 'release' },
|
|
||||||
})
|
|
||||||
win.metaAttributesCache.set('ol-learnedWords', ['baz'])
|
win.metaAttributesCache.set('ol-learnedWords', ['baz'])
|
||||||
win.metaAttributesCache.set(
|
win.metaAttributesCache.set(
|
||||||
'ol-dictionariesRoot',
|
'ol-dictionariesRoot',
|
||||||
|
|
|
@ -1,86 +0,0 @@
|
||||||
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'
|
|
||||||
|
|
||||||
describe('Spellchecker', function () {
|
|
||||||
const content = `
|
|
||||||
\\documentclass{}
|
|
||||||
|
|
||||||
\\title{}
|
|
||||||
\\author{}
|
|
||||||
|
|
||||||
\\begin{document}
|
|
||||||
\\maketitle
|
|
||||||
|
|
||||||
\\begin{abstract}
|
|
||||||
\\end{abstract}
|
|
||||||
|
|
||||||
\\section{}
|
|
||||||
|
|
||||||
\\end{document}`
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
|
||||||
cy.interceptEvents()
|
|
||||||
|
|
||||||
const scope = mockScope(content)
|
|
||||||
|
|
||||||
cy.mount(
|
|
||||||
<TestContainer>
|
|
||||||
<EditorProviders scope={scope}>
|
|
||||||
<CodeMirrorEditor />
|
|
||||||
</EditorProviders>
|
|
||||||
</TestContainer>
|
|
||||||
)
|
|
||||||
|
|
||||||
cy.get('.cm-line').eq(13).as('line')
|
|
||||||
cy.get('@line').click()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('makes initial spellcheck request', function () {
|
|
||||||
cy.intercept('POST', '/spelling/check').as('spellCheckRequest')
|
|
||||||
cy.get('@line').type('wombat')
|
|
||||||
cy.wait('@spellCheckRequest')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('makes only one spellcheck request for multiple typed characters', function () {
|
|
||||||
let spellCheckRequestCount = 0
|
|
||||||
cy.intercept('POST', '/spelling/check', req => {
|
|
||||||
++spellCheckRequestCount
|
|
||||||
if (spellCheckRequestCount > 1) {
|
|
||||||
throw new Error('No more than one request was expected')
|
|
||||||
}
|
|
||||||
req.reply({
|
|
||||||
misspellings: [],
|
|
||||||
})
|
|
||||||
}).as('spellCheckRequest')
|
|
||||||
|
|
||||||
cy.get('@line').type('wombat')
|
|
||||||
cy.wait('@spellCheckRequest')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('shows red underline for misspelled word', function () {
|
|
||||||
cy.intercept('POST', '/spelling/check', {
|
|
||||||
misspellings: [
|
|
||||||
{
|
|
||||||
index: 0,
|
|
||||||
suggestions: [
|
|
||||||
'noncombat',
|
|
||||||
'wombat',
|
|
||||||
'nutmeat',
|
|
||||||
'nitwit',
|
|
||||||
'steamboat',
|
|
||||||
'entombed',
|
|
||||||
'tombed',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).as('spellCheckRequest')
|
|
||||||
|
|
||||||
cy.get('@line').type('notawombat')
|
|
||||||
cy.wait('@spellCheckRequest')
|
|
||||||
cy.get('@line').get('.ol-cm-spelling-error').contains('notawombat')
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -107,7 +107,7 @@ function checkBordersWithNoMultiColumn(
|
||||||
describe('<CodeMirrorEditor/> Table editor', function () {
|
describe('<CodeMirrorEditor/> Table editor', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
cy.interceptMathJax()
|
cy.interceptMathJax()
|
||||||
cy.interceptCompile('compile', Number.MAX_SAFE_INTEGER)
|
cy.interceptCompile('compile', Number.MAX_SAFE_INTEGER)
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
|
|
|
@ -25,7 +25,6 @@ describe('<CodeMirrorEditor/> command tooltip in Visual mode', function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows a tooltip for \\href', function () {
|
it('shows a tooltip for \\href', function () {
|
||||||
|
|
|
@ -24,7 +24,6 @@ describe('<CodeMirrorEditor/> floats', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('decorates a caption', function () {
|
it('decorates a caption', function () {
|
||||||
|
|
|
@ -26,7 +26,6 @@ describe('<CodeMirrorEditor/> lists in Rich Text mode', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('creates a nested list inside an unindented list', function () {
|
it('creates a nested list inside an unindented list', function () {
|
||||||
|
|
|
@ -25,7 +25,6 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('handles paste', function () {
|
it('handles paste', function () {
|
||||||
|
|
|
@ -62,7 +62,6 @@ describe('<CodeMirrorEditor/> in Visual mode with read-only permission', functio
|
||||||
cy.interceptMathJax()
|
cy.interceptMathJax()
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('decorates footnote content', function () {
|
it('decorates footnote content', function () {
|
||||||
|
|
|
@ -39,7 +39,6 @@ describe('<CodeMirrorEditor/> toolbar in Rich Text mode', function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should handle Undo and Redo', function () {
|
it('should handle Undo and Redo', function () {
|
||||||
|
|
|
@ -10,7 +10,6 @@ describe('<CodeMirrorEditor/> tooltips in Visual mode', function () {
|
||||||
cy.interceptMathJax()
|
cy.interceptMathJax()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
|
|
||||||
const scope = mockScope('\n\n\n')
|
const scope = mockScope('\n\n\n')
|
||||||
scope.editor.showVisual = true
|
scope.editor.showVisual = true
|
||||||
|
|
|
@ -14,7 +14,6 @@ describe('<CodeMirrorEditor/> in Visual mode', function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptMetadata()
|
cy.interceptMetadata()
|
||||||
cy.interceptSpelling()
|
|
||||||
cy.interceptMathJax()
|
cy.interceptMathJax()
|
||||||
|
|
||||||
// 3 blank lines
|
// 3 blank lines
|
||||||
|
|
|
@ -12,7 +12,6 @@ describe('<CodeMirrorEditor/>', { scrollBehavior: false }, function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('deletes selected text on Backspace', function () {
|
it('deletes selected text on Backspace', function () {
|
||||||
|
|
Loading…
Reference in a new issue