1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-22 15:02:51 +02:00

Reintroduce manual Android tests (#5884)

* Re-add manual Android tests

* Remove trailing slash

* Disable autofocus
This commit is contained in:
Joe Anderson
2025-05-27 22:44:02 +01:00
committed by GitHub
parent de260565c7
commit 8f8b957ba6
6 changed files with 519 additions and 19 deletions

View File

@@ -101,6 +101,10 @@ To run integrations with [Playwright](https://playwright.dev/), first run `yarn
[Here's a helpful page](https://github.com/Microsoft/vscode/wiki/IME-Test) detailing how to test various input scenarios on Windows, Mac and Linux. [Here's a helpful page](https://github.com/Microsoft/vscode/wiki/IME-Test) detailing how to test various input scenarios on Windows, Mac and Linux.
## Android tests
When making changes that might affect Android compatibility, you can perform the manual Android tests at [/examples/android-tests](https://slatejs.org/examples/android-tests).
## Publishing Releases ## Publishing Releases
**Important**: When creating releases using Lerna with the instructions below, you will be given choices around how to increase version numbers. You should always use a `major`, `minor` or `patch` release and must never use a `prerelease`. If a prerelease is used, the root package will not link to the packages in the `packages` directory creating hard to diagnose issues. **Important**: When creating releases using Lerna with the instructions below, you will be given choices around how to increase version numbers. You should always use a `major`, `minor` or `patch` release and must never use a `prerelease`. If a prerelease is used, the root package will not link to the packages in the `packages` directory creating hard to diagnose issues.

View File

@@ -10,7 +10,7 @@
"build:rollup": "rollup --config ./config/rollup/rollup.config.js --bundleConfigAsCjs", "build:rollup": "rollup --config ./config/rollup/rollup.config.js --bundleConfigAsCjs",
"changesetversion": "yarn changeset version && yarn install && git add .", "changesetversion": "yarn changeset version && yarn install && git add .",
"clean": "rimraf './packages/*/{dist,lib,node_modules}' './site/{.next,out}' --glob", "clean": "rimraf './packages/*/{dist,lib,node_modules}' './site/{.next,out}' --glob",
"fix": "yarn fix:prettier && yarn fix:eslint", "fix": "yarn tsc:examples && yarn fix:prettier && yarn fix:eslint",
"fix:eslint": "yarn lint:eslint --fix", "fix:eslint": "yarn lint:eslint --fix",
"fix:prettier": "yarn lint:prettier --write", "fix:prettier": "yarn lint:prettier --write",
"lint": "yarn lint:typescript && yarn lint:eslint && yarn lint:prettier", "lint": "yarn lint:typescript && yarn lint:eslint && yarn lint:prettier",

View File

@@ -0,0 +1,234 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { createEditor } from 'slate'
import { withHistory } from 'slate-history'
import { Editable, Slate, withReact } from 'slate-react'
import { css } from '@emotion/css'
const TEST_CASES = [
{
id: 'split-join',
name: 'Split/Join',
instructions:
'Hit enter twice then backspace twice in the following places:\n- Before "before"\n- Between the two "d"s in "middle"\n- After "after"',
value: [
{
type: 'paragraph',
children: [
{ text: 'One ' },
{ text: 'before', bold: true },
{ text: ' two ' },
{ text: 'middle', bold: true },
{ text: ' three ' },
{ text: 'after', bold: true },
{ text: ' four' },
],
},
],
},
{
id: 'insert',
name: 'Insertion',
instructions:
'Enter text below each line of instruction, including mis-spelling "wasnt"',
value: [
{
type: 'paragraph',
children: [
{ text: 'Type by tapping keys: ', bold: true },
{ text: 'It wasnt me. No.' },
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{ text: 'Type using glide typing: ', bold: true },
{ text: 'Yes Sam, I am.' },
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{ text: 'Type using voice input: ', bold: true },
{ text: 'The quick brown fox jumps over the lazy dog' },
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [{ text: 'Write any two words using an IME', bold: true }],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
],
},
{
id: 'special',
name: 'Special',
instructions: 'Follow the instructions on each line',
value: [
{
type: 'paragraph',
children: [
{
text: 'Type "it is", move cursor to "i|t" and hit enter.',
bold: true,
},
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{
text: 'Move cursor to "mid|dle" and press space, backspace, space, backspace.',
bold: true,
},
],
},
{
type: 'paragraph',
children: [{ text: 'The middle word.' }],
},
{
type: 'paragraph',
children: [
{
text: 'Place cursor in line below. Wait for caps on keyboard to show up. If not try again. Type "It me. No." and check it doesn\'t mangle on the last period.',
bold: true,
},
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
],
},
{
id: 'empty',
name: 'Empty',
instructions:
'Type "hello world", press enter, "hi", press enter, "bye", and then backspace over everything',
value: [
{
type: 'paragraph',
children: [{ text: '' }],
},
],
},
{
id: 'remove',
name: 'Remove',
instructions:
'Select from ANCHOR to FOCUS and press backspace. Move cursor to end. Backspace over all remaining content.',
value: [
{
type: 'paragraph',
children: [
{ text: 'Go and ' },
{ text: 'select', bold: true },
{ text: ' from this ANCHOR and then' },
],
},
{
type: 'paragraph',
children: [{ text: 'go and select' }],
},
{
type: 'paragraph',
children: [
{ text: 'to this FOCUS then press ' },
{ text: 'backspace.', bold: true },
],
},
{
type: 'paragraph',
children: [
{ text: 'After you have done that move selection to very end.' },
],
},
{
type: 'paragraph',
children: [
{ text: 'Then try ' },
{ text: 'backspacing', bold: true },
{ text: ' over all remaining text.' },
],
},
],
},
]
const AndroidTestsExample = () => {
const [testId, setTestId] = useState(
() => window.location.hash.replace('#', '') || TEST_CASES[0].id
)
useEffect(() => {
window.history.replaceState({}, '', `#${testId}`)
}, [testId])
const testCase = TEST_CASES.find(({ id }) => id === testId)
if (!testCase) {
throw new Error(`Could not find test case '${testId}'`)
}
return (
<>
<label>
Test case:{' '}
<select value={testId} onChange={e => setTestId(e.target.value)}>
{TEST_CASES.map(({ name, id }) => (
<option key={id} value={id}>
{name}
</option>
))}
</select>
</label>
<p
className={css`
font-weight: 600;
margin: 0.5rem 0;
white-space: pre-line;
`}
>
{testCase.instructions}
</p>
<TestCase key={testId} {...testCase} />
</>
)
}
const TestCase = ({ value }) => {
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
return (
<Slate editor={editor} initialValue={value}>
<Editable
renderLeaf={renderLeaf}
placeholder="Enter some text…"
spellCheck
/>
</Slate>
)
}
const Leaf = ({ attributes, children, leaf }) => {
if (leaf.bold) {
children = <strong>{children}</strong>
}
return <span {...attributes}>{children}</span>
}
export default AndroidTestsExample

View File

@@ -1,22 +1,22 @@
import React, { useMemo, useCallback } from 'react' import { css } from '@emotion/css'
import { import React, { useCallback, useMemo } from 'react'
Slate,
Editable,
withReact,
useSlateStatic,
useReadOnly,
ReactEditor,
} from 'slate-react'
import { import {
Editor, Editor,
Transforms,
Range,
Point, Point,
createEditor, Range,
Element as SlateElement, Element as SlateElement,
Transforms,
createEditor,
} from 'slate' } from 'slate'
import { css } from '@emotion/css'
import { withHistory } from 'slate-history' import { withHistory } from 'slate-history'
import {
Editable,
ReactEditor,
Slate,
useReadOnly,
useSlateStatic,
withReact,
} from 'slate-react'
const initialValue = [ const initialValue = [
{ {

View File

@@ -0,0 +1,254 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { Descendant, createEditor } from 'slate'
import { withHistory } from 'slate-history'
import { Editable, RenderLeafProps, Slate, withReact } from 'slate-react'
import { css } from '@emotion/css'
interface AndroidTestCase {
id: string
name: string
instructions: string
value: Descendant[]
}
const TEST_CASES: AndroidTestCase[] = [
{
id: 'split-join',
name: 'Split/Join',
instructions:
'Hit enter twice then backspace twice in the following places:\n- Before "before"\n- Between the two "d"s in "middle"\n- After "after"',
value: [
{
type: 'paragraph',
children: [
{ text: 'One ' },
{ text: 'before', bold: true },
{ text: ' two ' },
{ text: 'middle', bold: true },
{ text: ' three ' },
{ text: 'after', bold: true },
{ text: ' four' },
],
},
],
},
{
id: 'insert',
name: 'Insertion',
instructions:
'Enter text below each line of instruction, including mis-spelling "wasnt"',
value: [
{
type: 'paragraph',
children: [
{ text: 'Type by tapping keys: ', bold: true },
{ text: 'It wasnt me. No.' },
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{ text: 'Type using glide typing: ', bold: true },
{ text: 'Yes Sam, I am.' },
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{ text: 'Type using voice input: ', bold: true },
{ text: 'The quick brown fox jumps over the lazy dog' },
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [{ text: 'Write any two words using an IME', bold: true }],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
],
},
{
id: 'special',
name: 'Special',
instructions: 'Follow the instructions on each line',
value: [
{
type: 'paragraph',
children: [
{
text: 'Type "it is", move cursor to "i|t" and hit enter.',
bold: true,
},
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{
text: 'Move cursor to "mid|dle" and press space, backspace, space, backspace.',
bold: true,
},
],
},
{
type: 'paragraph',
children: [{ text: 'The middle word.' }],
},
{
type: 'paragraph',
children: [
{
text: 'Place cursor in line below. Wait for caps on keyboard to show up. If not try again. Type "It me. No." and check it doesn\'t mangle on the last period.',
bold: true,
},
],
},
{
type: 'paragraph',
children: [{ text: '' }],
},
],
},
{
id: 'empty',
name: 'Empty',
instructions:
'Type "hello world", press enter, "hi", press enter, "bye", and then backspace over everything',
value: [
{
type: 'paragraph',
children: [{ text: '' }],
},
],
},
{
id: 'remove',
name: 'Remove',
instructions:
'Select from ANCHOR to FOCUS and press backspace. Move cursor to end. Backspace over all remaining content.',
value: [
{
type: 'paragraph',
children: [
{ text: 'Go and ' },
{ text: 'select', bold: true },
{ text: ' from this ANCHOR and then' },
],
},
{
type: 'paragraph',
children: [{ text: 'go and select' }],
},
{
type: 'paragraph',
children: [
{ text: 'to this FOCUS then press ' },
{ text: 'backspace.', bold: true },
],
},
{
type: 'paragraph',
children: [
{ text: 'After you have done that move selection to very end.' },
],
},
{
type: 'paragraph',
children: [
{ text: 'Then try ' },
{ text: 'backspacing', bold: true },
{ text: ' over all remaining text.' },
],
},
],
},
]
const AndroidTestsExample = () => {
const [testId, setTestId] = useState(
() => window.location.hash.replace('#', '') || TEST_CASES[0].id
)
useEffect(() => {
window.history.replaceState({}, '', `#${testId}`)
}, [testId])
const testCase = TEST_CASES.find(({ id }) => id === testId)
if (!testCase) {
throw new Error(`Could not find test case '${testId}'`)
}
return (
<>
<label>
Test case:{' '}
<select value={testId} onChange={e => setTestId(e.target.value)}>
{TEST_CASES.map(({ name, id }) => (
<option key={id} value={id}>
{name}
</option>
))}
</select>
</label>
<p
className={css`
font-weight: 600;
margin: 0.5rem 0;
white-space: pre-line;
`}
>
{testCase.instructions}
</p>
<TestCase key={testId} {...testCase} />
</>
)
}
const TestCase = ({ value }: AndroidTestCase) => {
const renderLeaf = useCallback(
(props: RenderLeafProps) => <Leaf {...props} />,
[]
)
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
return (
<Slate editor={editor} initialValue={value}>
<Editable
renderLeaf={renderLeaf}
placeholder="Enter some text…"
spellCheck
/>
</Slate>
)
}
const Leaf = ({ attributes, children, leaf }: RenderLeafProps) => {
if (leaf.bold) {
children = <strong>{children}</strong>
}
return <span {...attributes}>{children}</span>
}
export default AndroidTestsExample

View File

@@ -7,6 +7,7 @@ import { ErrorBoundary } from 'react-error-boundary'
import { Icon } from '../../examples/ts/components/index' import { Icon } from '../../examples/ts/components/index'
import AndroidTests from '../../examples/ts/android-tests'
import CheckLists from '../../examples/ts/check-lists' import CheckLists from '../../examples/ts/check-lists'
import CodeHighlighting from '../../examples/ts/code-highlighting' import CodeHighlighting from '../../examples/ts/code-highlighting'
import EditableVoids from '../../examples/ts/editable-voids' import EditableVoids from '../../examples/ts/editable-voids'
@@ -33,13 +34,15 @@ import CustomPlaceholder from '../../examples/ts/custom-placeholder'
// node // node
import { getAllExamples } from '../api' import { getAllExamples } from '../api'
type ExampleTuple = [string, React.ComponentType, string] type ExampleTuple = [name: string, component: React.ComponentType, path: string]
const EXAMPLES: ExampleTuple[] = [ const EXAMPLES: ExampleTuple[] = [
['Android Tests', AndroidTests, 'android-tests'],
['Checklists', CheckLists, 'check-lists'], ['Checklists', CheckLists, 'check-lists'],
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
['Custom Placeholder', CustomPlaceholder, 'custom-placeholder'],
['Editable Voids', EditableVoids, 'editable-voids'], ['Editable Voids', EditableVoids, 'editable-voids'],
['Embeds', Embeds, 'embeds'], ['Embeds', Embeds, 'embeds'],
['Code Highlighting', CodeHighlighting, 'code-highlighting'],
['Forced Layout', ForcedLayout, 'forced-layout'], ['Forced Layout', ForcedLayout, 'forced-layout'],
['Hovering Toolbar', HoveringToolbar, 'hovering-toolbar'], ['Hovering Toolbar', HoveringToolbar, 'hovering-toolbar'],
['Huge Document', HugeDocument, 'huge-document'], ['Huge Document', HugeDocument, 'huge-document'],
@@ -51,15 +54,20 @@ const EXAMPLES: ExampleTuple[] = [
['Paste HTML', PasteHtml, 'paste-html'], ['Paste HTML', PasteHtml, 'paste-html'],
['Plain Text', PlainText, 'plaintext'], ['Plain Text', PlainText, 'plaintext'],
['Read-only', ReadOnly, 'read-only'], ['Read-only', ReadOnly, 'read-only'],
['Rendering in iframes', IFrames, 'iframe'],
['Rich Text', RichText, 'richtext'], ['Rich Text', RichText, 'richtext'],
['Search Highlighting', SearchHighlighting, 'search-highlighting'], ['Search Highlighting', SearchHighlighting, 'search-highlighting'],
['Shadow DOM', ShadowDOM, 'shadow-dom'], ['Shadow DOM', ShadowDOM, 'shadow-dom'],
['Styling', Styling, 'styling'], ['Styling', Styling, 'styling'],
['Tables', Tables, 'tables'], ['Tables', Tables, 'tables'],
['Rendering in iframes', IFrames, 'iframe'],
['Custom placeholder', CustomPlaceholder, 'custom-placeholder'],
] ]
const HIDDEN_EXAMPLES = ['android-tests']
const NON_HIDDEN_EXAMPLES = EXAMPLES.filter(
([, , path]) => !HIDDEN_EXAMPLES.includes(path)
)
const Header = (props: React.HTMLAttributes<HTMLDivElement>) => ( const Header = (props: React.HTMLAttributes<HTMLDivElement>) => (
<div <div
{...props} {...props}
@@ -351,7 +359,7 @@ const ExamplePage = ({ example }: { example: string }) => {
</ExampleTitle> </ExampleTitle>
</ExampleHeader> </ExampleHeader>
<TabList isVisible={showTabs}> <TabList isVisible={showTabs}>
{EXAMPLES.map(([n, , p]) => ( {NON_HIDDEN_EXAMPLES.map(([n, , p]) => (
<Link <Link
key={p as string} key={p as string}
href="/examples/[example]" href="/examples/[example]"