Просмотр исходного кода

Remove editor split tests (#14985)

* Remove source-editor-toolbar split test
* Remove editor-left-menu split test
* Remove paste-html split test
* Remove figure-modal split test
* Remove rich-text split test
* Remove table-generator split test

GitOrigin-RevId: e3fe415b81ff0135d8764cd3f3c91b1dd4a77cf0
Alf Eaton 2 лет назад
Родитель
Сommit
6dbb2df5b8
18 измененных файлов с 165 добавлено и 214 удалено
  1. 1 73
      services/web/app/src/Features/Project/ProjectController.js
  2. 1 4
      services/web/app/views/project/editor/main.pug
  3. 0 5
      services/web/frontend/js/features/source-editor/components/editor-switch-legacy.tsx
  4. 14 2
      services/web/frontend/js/features/source-editor/components/editor-switch.tsx
  5. 5 4
      services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal.tsx
  6. 8 8
      services/web/frontend/js/features/source-editor/components/paste-html/pasted-content-menu.tsx
  7. 13 4
      services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar.tsx
  8. 2 14
      services/web/frontend/js/features/source-editor/components/toolbar/toolbar-items.tsx
  9. 0 6
      services/web/frontend/js/features/source-editor/extensions/figure-modal.ts
  10. 1 2
      services/web/frontend/js/features/source-editor/extensions/index.ts
  11. 3 22
      services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts
  12. 2 5
      services/web/frontend/js/features/source-editor/extensions/visual/visual.ts
  13. 25 0
      services/web/frontend/js/shared/components/feedback-badge.tsx
  14. 35 0
      services/web/frontend/stories/feedback-badge.stories.tsx
  15. 0 5
      services/web/frontend/stories/source-editor/source-editor.stories.tsx
  16. 3 6
      services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx
  17. 52 51
      services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx
  18. 0 3
      services/web/test/frontend/features/source-editor/components/figure-modal.spec.tsx

+ 1 - 73
services/web/app/src/Features/Project/ProjectController.js

@@ -636,49 +636,6 @@ const ProjectController = {
             }
           )
         },
-        editorLeftMenuAssignment(cb) {
-          SplitTestHandler.getAssignment(
-            req,
-            res,
-            'editor-left-menu',
-            (error, assignment) => {
-              // do not fail editor load if assignment fails
-              if (error) {
-                cb(null, { variant: 'default' })
-              } else {
-                cb(null, assignment)
-              }
-            }
-          )
-        },
-        // this is only needed until the survey link is removed from the toolbar
-        richTextAssignment(cb) {
-          SplitTestHandler.getAssignment(
-            req,
-            res,
-            'rich-text',
-            (error, assignment) => {
-              // do not fail editor load if assignment fails
-              if (error) {
-                cb(null, { variant: 'default' })
-              } else {
-                cb(null, assignment)
-              }
-            }
-          )
-        },
-        figureModalAssignment(cb) {
-          SplitTestHandler.getAssignment(req, res, 'figure-modal', () => {
-            // We'll pick up the assignment from the res.locals assignment.
-            cb()
-          })
-        },
-        tableGeneratorAssignment(cb) {
-          SplitTestHandler.getAssignment(req, res, 'table-generator', () => {
-            // We'll pick up the assignment from the res.locals assignment.
-            cb()
-          })
-        },
         tableGeneratorPromotionAssignment(cb) {
           SplitTestHandler.getAssignment(
             req,
@@ -690,27 +647,6 @@ const ProjectController = {
             }
           )
         },
-        pasteHtmlAssignment(cb) {
-          SplitTestHandler.getAssignment(req, res, 'paste-html', () => {
-            // We'll pick up the assignment from the res.locals assignment.
-            cb()
-          })
-        },
-        sourceEditorToolbarAssigment(cb) {
-          SplitTestHandler.getAssignment(
-            req,
-            res,
-            'source-editor-toolbar',
-            (error, assignment) => {
-              // do not fail editor load if assignment fails
-              if (error) {
-                cb(null, { variant: 'default' })
-              } else {
-                cb(null, assignment)
-              }
-            }
-          )
-        },
         historyViewAssignment(cb) {
           SplitTestHandler.getAssignment(
             req,
@@ -761,8 +697,6 @@ const ProjectController = {
           isInvitedMember,
           brandVariation,
           pdfjsAssignment,
-          editorLeftMenuAssignment,
-          sourceEditorToolbarAssigment,
           historyViewAssignment,
           reviewPanelAssignment,
           projectTags,
@@ -853,9 +787,6 @@ const ProjectController = {
               // Allow override via legacy_source_editor=true in query string
               shouldDisplayFeature('legacy_source_editor')
 
-            const editorLeftMenuReact =
-              editorLeftMenuAssignment?.variant === 'react'
-
             const showSymbolPalette =
               !Features.hasFeature('saas') ||
               (user.features && user.features.symbolPalette)
@@ -889,7 +820,6 @@ const ProjectController = {
               bodyClasses: ['editor'],
               project_id: project._id,
               projectName: project.name,
-              editorLeftMenuReact,
               user: {
                 id: userId,
                 email: user.email,
@@ -943,9 +873,7 @@ const ProjectController = {
               pdfjsVariant: pdfjsAssignment.variant,
               debugPdfDetach,
               showLegacySourceEditor,
-              showSourceToolbar:
-                !showLegacySourceEditor &&
-                sourceEditorToolbarAssigment.variant === 'enabled',
+              showSourceToolbar: !showLegacySourceEditor,
               showSymbolPalette,
               symbolPaletteAvailable: Features.hasFeature('symbol-palette'),
               detachRole,

+ 1 - 4
services/web/app/views/project/editor/main.pug

@@ -1,7 +1,4 @@
-if editorLeftMenuReact
-	include ./left-menu-react
-else
-	include ./left-menu
+include ./left-menu-react
 
 #chat-wrapper.full-size(
 	layout="chat",

+ 0 - 5
services/web/frontend/js/features/source-editor/components/editor-switch-legacy.tsx

@@ -5,7 +5,6 @@ import { sendMB } from '../../../infrastructure/event-tracking'
 import getMeta from '../../../utils/meta'
 import isValidTeXFile from '../../../main/is-valid-tex-file'
 import { useTranslation } from 'react-i18next'
-import SplitTestBadge from '../../../shared/components/split-test-badge'
 
 function Badge() {
   const content = (
@@ -125,10 +124,6 @@ function EditorSwitch() {
           handleChange={handleChange}
         />
       </fieldset>
-
-      {!!richTextOrVisual && (
-        <SplitTestBadge splitTestName="rich-text" displayOnVariants={['cm6']} />
-      )}
     </div>
   )
 }

+ 14 - 2
services/web/frontend/js/features/source-editor/components/editor-switch.tsx

@@ -4,8 +4,8 @@ import Tooltip from '../../../shared/components/tooltip'
 import { sendMB } from '../../../infrastructure/event-tracking'
 import isValidTeXFile from '../../../main/is-valid-tex-file'
 import { useTranslation } from 'react-i18next'
-import SplitTestBadge from '../../../shared/components/split-test-badge'
 import { PromotionOverlay } from './table-generator/promotion/popover'
+import { FeedbackBadge } from '@/shared/components/feedback-badge'
 
 function EditorSwitch() {
   const { t } = useTranslation()
@@ -71,12 +71,24 @@ function EditorSwitch() {
       </fieldset>
 
       {!!richTextOrVisual && (
-        <SplitTestBadge splitTestName="rich-text" displayOnVariants={['cm6']} />
+        <FeedbackBadge
+          id="visual-editor-feedback"
+          url="https://forms.gle/AUqHmKNiEH3DRniPA"
+          text={<VisualEditorFeedbackContent />}
+        />
       )}
     </div>
   )
 }
 
+const VisualEditorFeedbackContent = () => (
+  <>
+    We have a new Visual Editor!
+    <br />
+    Click to give feedback
+  </>
+)
+
 const RichTextToggle: FC<{
   checked: boolean
   disabled: boolean

+ 5 - 4
services/web/frontend/js/features/source-editor/components/figure-modal/figure-modal.tsx

@@ -11,7 +11,6 @@ import { FigureModalFooter } from './figure-modal-footer'
 import { memo, useCallback, useEffect } from 'react'
 import { useCodeMirrorViewContext } from '../codemirror-editor'
 import { ChangeSpec } from '@codemirror/state'
-import SplitTestBadge from '../../../../shared/components/split-test-badge'
 import {
   FigureData,
   PastedImageData,
@@ -22,6 +21,7 @@ import { ensureEmptyLine } from '../../extensions/toolbar/commands'
 import { useTranslation } from 'react-i18next'
 import useEventListener from '../../../../shared/hooks/use-event-listener'
 import { prepareLines } from '../../utils/prepare-lines'
+import { FeedbackBadge } from '@/shared/components/feedback-badge'
 
 export const FigureModal = memo(function FigureModal() {
   return (
@@ -268,9 +268,10 @@ const FigureModalContent = () => {
             : sourcePickerShown
             ? t('replace_figure')
             : getTitle(source)}{' '}
-          <SplitTestBadge
-            splitTestName="figure-modal"
-            displayOnVariants={['enabled']}
+          <FeedbackBadge
+            id="figure-modal-feedback"
+            url="https://forms.gle/PfEtwceYBNQ32DF4A"
+            text="Please click to give feedback about editing figures."
           />
         </Modal.Title>
       </Modal.Header>

+ 8 - 8
services/web/frontend/js/features/source-editor/components/paste-html/pasted-content-menu.tsx

@@ -12,8 +12,7 @@ import { useTranslation } from 'react-i18next'
 import { EditorView } from '@codemirror/view'
 import { PastedContent } from '../../extensions/visual/pasted-content'
 import useEventListener from '../../../../shared/hooks/use-event-listener'
-import SplitTestBadge from '../../../../shared/components/split-test-badge'
-import { useSplitTestContext } from '../../../../shared/context/split-test-context'
+import { FeedbackBadge } from '@/shared/components/feedback-badge'
 
 const isMac = /Mac/.test(window.navigator?.platform)
 
@@ -30,8 +29,6 @@ export const PastedContentMenu: FC<{
   const [menuOpen, setMenuOpen] = useState(false)
   const toggleButtonRef = useRef<HTMLButtonElement | null>(null)
   const { t } = useTranslation()
-  const { splitTestInfo } = useSplitTestContext()
-  const feedbackURL = splitTestInfo['paste-html']?.badgeInfo?.url
 
   // record whether the Shift key is currently down, for use in the `paste` event handler
   const shiftRef = useRef(false)
@@ -138,13 +135,16 @@ export const PastedContentMenu: FC<{
               <MenuItem
                 style={{ borderTop: '1px solid #eee' }}
                 onClick={() => {
-                  window.open(feedbackURL, '_blank')
+                  window.open(
+                    'https://docs.google.com/forms/d/e/1FAIpQLSc7WcHrwz9fnCkUP5hXyvkG3LkSYZiR3lVJWZ0o6uqNQYrV7Q/viewform',
+                    '_blank'
+                  )
                   setMenuOpen(false)
                 }}
               >
-                <SplitTestBadge
-                  splitTestName="paste-html"
-                  displayOnVariants={['enabled']}
+                <FeedbackBadge
+                  id="paste-html-feedback"
+                  url="https://docs.google.com/forms/d/e/1FAIpQLSc7WcHrwz9fnCkUP5hXyvkG3LkSYZiR3lVJWZ0o6uqNQYrV7Q/viewform"
                 />
                 <span className="ol-cm-pasted-content-menu-item-label">
                   {t('give_feedback')}

+ 13 - 4
services/web/frontend/js/features/source-editor/components/table-generator/toolbar/toolbar.tsx

@@ -20,8 +20,8 @@ import {
 import { useCodeMirrorViewContext } from '../../codemirror-editor'
 import { useTableContext } from '../contexts/table-context'
 import { useTabularContext } from '../contexts/tabular-context'
-import SplitTestBadge from '../../../../../shared/components/split-test-badge'
 import { useTranslation } from 'react-i18next'
+import { FeedbackBadge } from '@/shared/components/feedback-badge'
 
 export const Toolbar = memo(function Toolbar() {
   const { selection, setSelection } = useSelectionContext()
@@ -359,12 +359,21 @@ export const Toolbar = memo(function Toolbar() {
           command={showHelp}
         />
         <div className="toolbar-beta-badge">
-          <SplitTestBadge
-            displayOnVariants={['enabled']}
-            splitTestName="table-generator"
+          <FeedbackBadge
+            id="table-generator-feedback"
+            url="https://forms.gle/ri3fzV1oQDAjmfmD7"
+            text={<FeedbackBadgeContent />}
           />
         </div>
       </div>
     </div>
   )
 })
+
+const FeedbackBadgeContent = () => (
+  <>
+    We have a new way to insert and edit tables.
+    <br />
+    Click to give feedback
+  </>
+)

+ 2 - 14
services/web/frontend/js/features/source-editor/components/toolbar/toolbar-items.tsx

@@ -36,7 +36,6 @@ export const ToolbarItems: FC<{
   const isActive = withinFormattingCommand(state)
   const addCommentEmitter = useScopeEventEmitter('comment:start_adding')
   const { setReviewPanelOpen } = useLayoutContext()
-  const splitTestVariants = getMeta('ol-splitTestVariants', {})
   const addComment = useCallback(
     (view: EditorView) => {
       const range = view.state.selection.main
@@ -52,8 +51,6 @@ export const ToolbarItems: FC<{
     [addCommentEmitter, setReviewPanelOpen]
   )
 
-  const showFigureModal = splitTestVariants['figure-modal'] === 'enabled'
-  const showTableGenerator = splitTestVariants['table-generator'] === 'enabled'
   const symbolPaletteAvailable = getMeta('ol-symbolPaletteAvailable')
   const showGroup = (group: string) => !overflowed || overflowed.has(group)
 
@@ -157,17 +154,8 @@ export const ToolbarItems: FC<{
                 icon="comment"
                 hidden // enable this if an alternative to the floating "Add Comment" button is needed
               />
-              {showFigureModal ? (
-                <InsertFigureDropdown />
-              ) : (
-                <ToolbarButton
-                  id="toolbar-figure"
-                  label={t('toolbar_insert_figure')}
-                  command={commands.insertFigure}
-                  icon="picture-o"
-                />
-              )}
-              {showTableGenerator && <TableInserterDropdown />}
+              <InsertFigureDropdown />
+              <TableInserterDropdown />
             </div>
           )}
           {showGroup('group-list') && (

+ 0 - 6
services/web/frontend/js/features/source-editor/extensions/figure-modal.ts

@@ -7,7 +7,6 @@ import {
 import { EditorView } from '@codemirror/view'
 import { addEffectListener, removeEffectListener } from './effect-listeners'
 import { setMetadataEffect } from './language'
-import getMeta from '../../../utils/meta'
 import { debugConsole } from '@/utils/debugging'
 
 type NestedReadonly<T> = {
@@ -174,11 +173,6 @@ export type PastedImageData = {
 }
 
 export const figureModalPasteHandler = (): Extension => {
-  const splitTestVariants = getMeta('ol-splitTestVariants', {})
-  const figureModalEnabled = splitTestVariants['figure-modal'] === 'enabled'
-  if (!figureModalEnabled) {
-    return []
-  }
   return EditorView.domEventHandlers({
     drop: evt => {
       if (!evt.dataTransfer || evt.dataTransfer.files.length === 0) {

+ 1 - 2
services/web/frontend/js/features/source-editor/extensions/index.ts

@@ -47,7 +47,6 @@ import { effectListeners } from './effect-listeners'
 import { highlightSpecialChars } from './highlight-special-chars'
 import { toolbarPanel } from './toolbar/toolbar-panel'
 import { geometryChangeEvent } from './geometry-change-event'
-import { isSplitTestEnabled } from '../../../utils/splitTestUtils'
 import { completionLogger } from './completion-logger'
 import { shortcutLogger } from './shortcut-logger'
 
@@ -125,7 +124,7 @@ export const createExtensions = (options: Record<string, any>): Extension[] => [
   emptyLineFiller(),
   trackChanges(options.currentDoc, options.changeManager),
   visual(options.currentDoc, options.visual),
-  isSplitTestEnabled('source-editor-toolbar') ? toolbarPanel() : [],
+  toolbarPanel(),
   verticalOverflow(),
   highlightActiveLine(options.visual.visual),
   // The built-in extension that highlights the active line in the gutter.

+ 3 - 22
services/web/frontend/js/features/source-editor/extensions/visual/atomic-decorations.ts

@@ -29,7 +29,6 @@ import {
   parseFigureData,
 } from '../../utils/tree-operations/environments'
 import { MathWidget } from './visual-widgets/math'
-import { GraphicsWidget } from './visual-widgets/graphics'
 import { IconBraceWidget } from './visual-widgets/icon-brace'
 import { TeXWidget } from './visual-widgets/tex'
 import {
@@ -47,8 +46,6 @@ import {
   ancestorOfNodeWithType,
   isDirectChildOfEnvironment,
 } from '../../utils/tree-operations/ancestors'
-import { InlineGraphicsWidget } from './visual-widgets/inline-graphics'
-import getMeta from '../../../../utils/meta'
 import { EditableGraphicsWidget } from './visual-widgets/editable-graphics'
 import { EditableInlineGraphicsWidget } from './visual-widgets/editable-inline-graphics'
 import {
@@ -136,11 +133,6 @@ const hasClosingBrace = (node: SyntaxNode) =>
  * Decorations that span multiple lines must be contained in a StateField, not a ViewPlugin.
  */
 export const atomicDecorations = (options: Options) => {
-  const splitTestVariants = getMeta('ol-splitTestVariants', {})
-  const figureModalEnabled = splitTestVariants['figure-modal'] === 'enabled'
-  const tableGeneratorEnabled =
-    splitTestVariants['table-generator'] === 'enabled'
-
   const getPreviewByPath = (path: string) =>
     options.fileTreeManager.getPreviewByPath(path)
 
@@ -324,10 +316,7 @@ export const atomicDecorations = (options: Options) => {
                 )
               }
             }
-          } else if (
-            tableGeneratorEnabled &&
-            nodeRef.type.is('TabularEnvironment')
-          ) {
+          } else if (nodeRef.type.is('TabularEnvironment')) {
             if (shouldDecorate(state, nodeRef)) {
               const tabularNode = nodeRef.node
               const tableNode = ancestorOfNodeWithType(
@@ -896,18 +885,10 @@ export const atomicDecorations = (options: Options) => {
                 const lineContainsOnlyNode =
                   line.text.trim().length === nodeRef.to - nodeRef.from
 
-                const BlockGraphicsWidgetClass = figureModalEnabled
-                  ? EditableGraphicsWidget
-                  : GraphicsWidget
-
-                const InlineGraphicsWidgetClass = figureModalEnabled
-                  ? EditableInlineGraphicsWidget
-                  : InlineGraphicsWidget
-
                 if (lineContainsOnlyNode) {
                   decorations.push(
                     Decoration.replace({
-                      widget: new BlockGraphicsWidgetClass(
+                      widget: new EditableGraphicsWidget(
                         filePath,
                         getPreviewByPath,
                         centered,
@@ -919,7 +900,7 @@ export const atomicDecorations = (options: Options) => {
                 } else {
                   decorations.push(
                     Decoration.replace({
-                      widget: new InlineGraphicsWidgetClass(
+                      widget: new EditableInlineGraphicsWidget(
                         filePath,
                         getPreviewByPath,
                         centered,

+ 2 - 5
services/web/frontend/js/features/source-editor/extensions/visual/visual.ts

@@ -19,8 +19,6 @@ import { restoreScrollPosition } from '../scroll-position'
 import { CurrentDoc } from '../../../../../../types/current-doc'
 import isValidTeXFile from '../../../../main/is-valid-tex-file'
 import { listItemMarker } from './list-item-marker'
-import { isSplitTestEnabled } from '../../../../utils/splitTestUtils'
-import { toolbarPanel } from '../toolbar/toolbar-panel'
 import { selectDecoratedArgument } from './select-decorated-argument'
 import { pasteHtml } from './paste-html'
 import { commandTooltip } from '../command-tooltip'
@@ -200,9 +198,8 @@ const extension = (options: Options) => [
   visualKeymap,
   commandTooltip,
   scrollJumpAdjuster,
-  isSplitTestEnabled('source-editor-toolbar') ? [] : toolbarPanel(),
   selectDecoratedArgument,
   showContentWhenParsed,
-  isSplitTestEnabled('paste-html') ? pasteHtml : [],
-  isSplitTestEnabled('table-generator') ? tableGeneratorTheme : [],
+  pasteHtml,
+  tableGeneratorTheme,
 ]

+ 25 - 0
services/web/frontend/js/shared/components/feedback-badge.tsx

@@ -0,0 +1,25 @@
+import BetaBadge from './beta-badge'
+import { FC, ReactNode, useMemo } from 'react'
+
+export const FeedbackBadge: FC<{
+  url: string
+  id: string
+  text?: ReactNode
+}> = ({ url, id, text }) => {
+  const tooltip = useMemo(() => {
+    return {
+      id: `${id}-tooltip`,
+      text: text || <DefaultContent />,
+    }
+  }, [id, text])
+
+  return <BetaBadge tooltip={tooltip} phase="release" url={url} />
+}
+
+const DefaultContent = () => (
+  <>
+    We are testing this new feature.
+    <br />
+    Click to give feedback
+  </>
+)

+ 35 - 0
services/web/frontend/stories/feedback-badge.stories.tsx

@@ -0,0 +1,35 @@
+import { ScopeDecorator } from './decorators/scope'
+import { FeedbackBadge } from '@/shared/components/feedback-badge'
+
+export const WithDefaultText = () => {
+  return (
+    <FeedbackBadge
+      url="https://example.com"
+      id="storybook-feedback-with-text"
+    />
+  )
+}
+
+export const WithCustomText = () => {
+  const FeedbackContent = () => (
+    <>
+      This is an example.
+      <br />
+      Click to find out more
+    </>
+  )
+
+  return (
+    <FeedbackBadge
+      url="https://example.com"
+      id="storybook-feedback-with-text"
+      text={<FeedbackContent />}
+    />
+  )
+}
+
+export default {
+  title: 'Shared / Components / Feedback Badge',
+  component: FeedbackBadge,
+  decorators: [ScopeDecorator],
+}

+ 0 - 5
services/web/frontend/stories/source-editor/source-editor.stories.tsx

@@ -128,11 +128,6 @@ export const Visual = (args: any, { globals: { theme } }: any) => {
   useMeta({
     'ol-showSymbolPalette': true,
     'ol-mathJax3Path': 'https://unpkg.com/mathjax@3.2.2/es5/tex-svg-full.js',
-    'ol-splitTestVariants': {
-      'figure-modal': 'enabled',
-      'paste-html': 'enabled',
-      'table-generator': 'enabled',
-    },
     'ol-completedTutorials': {
       'table-generator-promotion': '2023-09-01T00:00:00.000Z',
     },

+ 3 - 6
services/web/test/frontend/features/source-editor/components/codemirror-editor-table-generator.spec.tsx

@@ -111,9 +111,6 @@ describe('<CodeMirrorEditor/> Table editor', function () {
     cy.interceptMathJax()
     cy.interceptCompile('compile', Number.MAX_SAFE_INTEGER)
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
-    window.metaAttributesCache.set('ol-splitTestVariants', {
-      'table-generator': 'enabled',
-    })
     window.metaAttributesCache.set('ol-completedTutorials', {
       'table-generator-promotion': '2023-09-01T00:00:00.000Z',
     })
@@ -151,7 +148,7 @@ describe('<CodeMirrorEditor/> Table editor', function () {
     it('Renders borders', function () {
       mountEditor(`
 \\begin{tabular}{c|c}
-cell 1 & cell 2 \\\\ 
+cell 1 & cell 2 \\\\
 \\hline
 cell 3 & cell 4 \\\\
 \\end{tabular}`)
@@ -181,12 +178,12 @@ cell 3 & cell 4 \\\\
     cell 1 & cell 2 \\\\
     cell 3 & cell 4 \\\\
 \\end{tabular}
-      `)
+`)
       checkBordersWithNoMultiColumn([false, false, false], [false, true, false])
       cy.get('.table-generator-floating-toolbar').should('not.exist')
       cy.get('.table-generator-cell').first().click()
       cy.get('.table-generator-floating-toolbar').as('toolbar').should('exist')
-      cy.get('@toolbar').findByText('Custom borders').click()
+      cy.get('@toolbar').findByText('Custom borders').click({ force: true })
       cy.get('.table-generator').findByText('All borders').click()
       // The element is partially covered, but we can still click it
       cy.get('.cm-line').first().click({ force: true })

+ 52 - 51
services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx

@@ -27,10 +27,6 @@ const mountEditor = (content = '') => {
 describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
   beforeEach(function () {
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
-    window.metaAttributesCache.set('ol-splitTestVariants', {
-      'paste-html': 'enabled',
-      'figure-modal': 'enabled',
-    })
     cy.interceptEvents()
     cy.interceptSpelling()
   })
@@ -100,10 +96,8 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{l l}foo & bar ↩\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'foobar')
+    cy.get('.table-generator-cell').should('have.length', 2)
   })
 
   it('handles a pasted table with cell borders', function () {
@@ -116,10 +110,12 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{| l | l |}\\hlinefoo & bar ↩\\hline\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'foobar')
+    cy.get('.table-generator-cell').should('have.length', 2)
+    cy.get('.table-generator-cell-border-left').should('have.length', 1)
+    cy.get('.table-generator-cell-border-right').should('have.length', 2)
+    cy.get('.table-generator-row-border-top').should('have.length', 2)
+    cy.get('.table-generator-row-border-bottom').should('have.length', 2)
   })
 
   it('handles a pasted table with row borders', function () {
@@ -132,10 +128,12 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{l l}\\hlinefoo & bar ↩\\hline\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'foobar')
+    cy.get('.table-generator-cell').should('have.length', 2)
+    cy.get('.table-generator-cell-border-left').should('have.length', 0)
+    cy.get('.table-generator-cell-border-right').should('have.length', 0)
+    cy.get('.table-generator-row-border-top').should('have.length', 2)
+    cy.get('.table-generator-row-border-bottom').should('have.length', 2)
   })
 
   it('handles a pasted table with adjacent borders', function () {
@@ -153,10 +151,12 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{| l | l |}\\hlinefoo & bar ↩\\hlinefoo & bar ↩\\hlinefoo & bar ↩\\hline\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'foobarfoobarfoobar')
+    cy.get('.table-generator-cell').should('have.length', 6)
+    cy.get('.table-generator-cell-border-left').should('have.length', 3)
+    cy.get('.table-generator-cell-border-right').should('have.length', 6)
+    cy.get('.table-generator-row-border-top').should('have.length', 6)
+    cy.get('.table-generator-row-border-bottom').should('have.length', 2)
   })
 
   it('handles a pasted table with alignment', function () {
@@ -169,10 +169,11 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{l l c r l}foo & foo & foo & foo & foo ↩\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'foofoofoofoofoo')
+    cy.get('.table-generator-cell').should('have.length', 5)
+    cy.get('.table-generator-cell.alignment-left').should('have.length', 3)
+    cy.get('.table-generator-cell.alignment-center').should('have.length', 1)
+    cy.get('.table-generator-cell.alignment-right').should('have.length', 1)
   })
 
   it('handles a pasted table with merged columns', function () {
@@ -190,10 +191,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{l l l}test & test & test ↩\\multicolumn{2}{l}{test} & test ↩test & \\multicolumn{2}{r}{test} ↩\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'testtesttesttesttesttesttest')
+    cy.get('.table-generator-cell').should('have.length', 7)
+    cy.get('.table-generator-cell[colspan="2"]').should('have.length', 2)
   })
 
   it('handles a pasted table with merged rows', function () {
@@ -213,8 +213,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
 
     cy.get('@content').should(
       'have.text',
-      '\\begin{tabular}{l l l}test & test & test\\multirow{2}{*}{test} & test & test ↩ & test & test ↩\\end{tabular}'
+      'testtesttest\\multirow{2}{*}{test}testtesttesttest'
     )
+    cy.get('.table-generator-cell').should('have.length', 9)
   })
 
   it('handles a pasted table with merged rows and columns', function () {
@@ -234,8 +235,10 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
 
     cy.get('@content').should(
       'have.text',
-      '\\begin{tabular}{l l l}\\multicolumn{2}{l}{\\multirow{2}{*}{test}} & test ↩ &  & testtest & test & test ↩\\end{tabular}'
+      '\\multirow{2}{*}{test}testtesttesttesttest'
     )
+    cy.get('.table-generator-cell').should('have.length', 8)
+    cy.get('.table-generator-cell[colspan="2"]').should('have.length', 1)
   })
 
   it('ignores rowspan="1" and colspan="1"', function () {
@@ -243,7 +246,7 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
 
     const data = [
       `<table><tbody>`,
-      `<tr><td colspan="1" rowspan="1">test</td><td>test</td></tr>`,
+      `<tr><td colspan="1" rowspan="1">test</td><td>test</td><td>test</td></tr>`,
       `<tr><td>test</td><td>test</td><td>test</td></tr>`,
       `</tbody></table>`,
     ].join('')
@@ -252,10 +255,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{l l l}test & test ↩test & test & test ↩\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'testtesttesttesttesttest')
+    cy.get('.table-generator-cell').should('have.length', 6)
+    cy.get('.table-generator-cell[colspan]').should('have.length', 0)
   })
 
   it('handles a pasted table with adjacent borders and merged cells', function () {
@@ -273,18 +275,16 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      '\\begin{tabular}{| l | l |}\\hline\\multicolumn{2}{l}{foo} ↩\\hlinefoo & bar ↩\\hlinefoo & bar ↩\\hline\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'foofoobarfoobar')
+    cy.get('.table-generator-cell').should('have.length', 5)
+    cy.get('.table-generator-cell[colspan="2"]').should('have.length', 1)
+    cy.get('.table-generator-cell-border-left').should('have.length', 2)
+    cy.get('.table-generator-cell-border-right').should('have.length', 4)
+    cy.get('.table-generator-row-border-top').should('have.length', 5)
+    cy.get('.table-generator-row-border-bottom').should('have.length', 2)
   })
 
   it('handles a pasted table with cell styles', function () {
-    window.metaAttributesCache.set('ol-splitTestVariants', {
-      'paste-html': 'enabled',
-      'table-generator': 'enabled',
-    })
-
     mountEditor()
 
     const data =
@@ -310,10 +310,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     clipboardData.setData('text/html', data)
     cy.get('@content').trigger('paste', { clipboardData })
 
-    cy.get('@content').should(
-      'have.text',
-      'A table\\begin{tabular}{l l}foo & bar ↩\\end{tabular}'
-    )
+    cy.get('@content').should('have.text', 'A tablefoobar')
+    cy.get('.table-generator-cell').should('have.length', 2)
+    cy.get('.ol-cm-command-caption').should('have.length', 1)
   })
 
   it('handles a pasted link', function () {
@@ -409,9 +408,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
 
     cy.get('@content').should(
       'have.text',
-      'testfoobarbaz foo foo foo foo\\begin{tabular}{l}foo ↩\\end{tabular}test'
+      'testfoobarbaz foo foo foo foofootest'
     )
-    cy.get('.cm-line').should('have.length', 19)
+    cy.get('.cm-line').should('have.length', 15)
   })
 
   it('handles pasted inline code', function () {
@@ -643,7 +642,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     cy.get('.ol-cm-command-verb').should('have.length', 1)
   })
 
-  it('tidies whitespace in pasted tables', function () {
+  // FIXME: need to assert on source code
+  // eslint-disable-next-line mocha/no-skipped-tests
+  it.skip('tidies whitespace in pasted tables', function () {
     mountEditor()
 
     const data = `<table>

+ 0 - 3
services/web/test/frontend/features/source-editor/components/figure-modal.spec.tsx

@@ -41,9 +41,6 @@ describe('<FigureModal />', function () {
   // TODO: Write tests for width toggle, when we can match on source code
   beforeEach(function () {
     window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
-    window.metaAttributesCache.set('ol-splitTestVariants', {
-      'figure-modal': 'enabled',
-    })
     window.metaAttributesCache.set(
       'ol-mathJax3Path',
       'https://unpkg.com/mathjax@3.2.2/es5/tex-svg-full.js'