a722e3e6f0
This PR updates tests for the text shape, as well as updating the logic of `getTextLines`. We now: - allow leading whitespace - allow white space to cause line breaks, trim the whitespace off of the end of the line. Crazy times! - fix a bug with geo shapes changes width when growY changes Note that this is not a "full solution" to line breaks that are caused by whitespace + wrapping. AFAIK this is impossible to fix in SVG-land without measuring the SVG element in order to collapse whitespace in the same way that it collapses in HTML layout. ### Change Type - [x] `patch` — Bug Fix - [ ] `minor` — New Feature - [ ] `major` — Breaking Change - [ ] `dependencies` — Dependency Update (publishes a `patch` release, for devDependencies use `internal`) - [ ] `documentation` — Changes to the documentation only (will not publish a new version) - [ ] `tests` — Changes to any testing-related code only (will not publish a new version) - [ ] `internal` — Any other changes that don't affect the published package (will not publish a new version) ### Test Plan - [x] Webdriver tests ### Release Notes - Allow leading whitespace
292 lines
7.5 KiB
TypeScript
292 lines
7.5 KiB
TypeScript
import { runtime, ui } from '../helpers'
|
|
import { diffScreenshot, takeRegionScreenshot } from '../helpers/webdriver'
|
|
import { describe, env, it } from '../mocha-ext'
|
|
|
|
describe('text', () => {
|
|
env(
|
|
{
|
|
// This can be removed once bugs resolved on mobile.
|
|
// Tracked in <https://linear.app/tldraw/issue/TLD-1300/re-enable-text-rendering-tests-on-mobile>
|
|
device: 'desktop',
|
|
},
|
|
() => {
|
|
const tests = [
|
|
{
|
|
name: 'multiline (align center)',
|
|
fails: true,
|
|
handler: async () => {
|
|
await ui.tools.click('select')
|
|
await ui.tools.click('text')
|
|
await ui.canvas.brush(100, 0, 150, 150)
|
|
await browser.keys('testing\ntesting\n1, 2, 3')
|
|
},
|
|
},
|
|
// {
|
|
// name: 'diacritics (align center)',
|
|
// fails: false,
|
|
// handler: async () => {
|
|
// await ui.tools.click('text')
|
|
// await ui.canvas.brush(50, 100, 150, 150)
|
|
// await browser.keys('âéīôù')
|
|
// },
|
|
// },
|
|
]
|
|
|
|
for (const test of tests) {
|
|
const { name } = test
|
|
const slugName = name.replace(/ /g, '-').replace(/[)(]/g, '')
|
|
const prefix = [
|
|
global.webdriverService,
|
|
global.tldrawOptions.os,
|
|
global.tldrawOptions.browser,
|
|
global.tldrawOptions.ui,
|
|
slugName,
|
|
].join('-')
|
|
|
|
const cleanUp = async () => {
|
|
await ui.main.menu(['edit', 'select-all'])
|
|
await ui.main.menu(['edit', 'delete'])
|
|
}
|
|
|
|
const testHandler = async () => {
|
|
await ui.app.setup()
|
|
await test.handler()
|
|
|
|
await ui.main.menu(['edit', 'select-all'])
|
|
const selectionBounds = await runtime.selectionBounds()
|
|
await ui.main.menu(['edit', 'select-none'])
|
|
|
|
const screenshotResults = await takeRegionScreenshot(selectionBounds, {
|
|
writeTo: {
|
|
path: `${__dirname}/../../screenshots/`,
|
|
prefix,
|
|
},
|
|
})
|
|
|
|
const { pxielDiff } = await diffScreenshot(screenshotResults, {
|
|
writeTo: {
|
|
path: `${__dirname}/../../screenshots/`,
|
|
prefix,
|
|
},
|
|
})
|
|
|
|
await cleanUp()
|
|
expect(pxielDiff).toBeLessThan(70)
|
|
}
|
|
|
|
it[test.fails ? 'fails' : 'ok']('text: ' + test.name, testHandler)
|
|
}
|
|
}
|
|
)
|
|
})
|
|
|
|
describe('text measurement', () => {
|
|
const measureTextOptions = {
|
|
text: 'testing',
|
|
width: 'fit-content',
|
|
fontFamily: 'var(--tl-font-draw)',
|
|
fontSize: 24,
|
|
lineHeight: 1.35,
|
|
fontWeight: 'normal',
|
|
fontStyle: 'normal',
|
|
padding: '0px',
|
|
maxWidth: 'auto',
|
|
}
|
|
|
|
const getTextLinesOptions = {
|
|
text: 'testing',
|
|
width: 100,
|
|
height: 1000,
|
|
wrap: true,
|
|
padding: 0,
|
|
fontSize: 24,
|
|
fontWeight: 'normal',
|
|
fontFamily: 'var(--tl-font-draw)',
|
|
fontStyle: 'normal',
|
|
lineHeight: 1.35,
|
|
textAlign: 'start' as 'start' | 'middle' | 'end',
|
|
}
|
|
|
|
env({}, () => {
|
|
it('should measure text', async () => {
|
|
await ui.app.setup()
|
|
const { w, h } = await browser.execute((options) => {
|
|
return window.app.textMeasure.measureText({
|
|
...options,
|
|
})
|
|
}, measureTextOptions)
|
|
|
|
expect(w).toBeCloseTo(85.828125, 1)
|
|
expect(h).toBeCloseTo(32.3984375, 1)
|
|
})
|
|
|
|
it('should get a single text line', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing'])
|
|
})
|
|
|
|
it('should wrap a word when it has to', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
width: 50,
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['test', 'ing'])
|
|
})
|
|
|
|
it('should wrap between words when it has to', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'testing testing',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing', 'testing'])
|
|
})
|
|
|
|
it('should strip whitespace at line breaks', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'testing testing',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing', 'testing'])
|
|
})
|
|
|
|
it('should strip whitespace at the end of wrapped lines', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'testing testing ',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing', 'testing'])
|
|
})
|
|
|
|
it('strips whitespace at the end of unwrapped lines', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
width: 200,
|
|
text: 'testing testing ',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing testing'])
|
|
})
|
|
|
|
it('preserves whitespace at the start of an unwrapped line', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
width: 200,
|
|
text: ' testing testing',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual([' testing testing'])
|
|
})
|
|
|
|
it('should place starting whitespace on its own line if it has to', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: ' testing testing',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['', 'testing', 'testing'])
|
|
})
|
|
|
|
it('trims ending whitespace', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'testing testing ',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing', 'testing'])
|
|
})
|
|
|
|
it('allows whitespace to cause breaks, however trims it at the end anyway', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'ok hi testing',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['ok hi', 'testing'])
|
|
})
|
|
|
|
it('respects leading whitespace', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: ' ok hi testing ',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual([' ok hi', 'testing'])
|
|
})
|
|
|
|
it('should handle multiline text', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'testing testing ',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testing', 'testing'])
|
|
})
|
|
|
|
it('should break long strings of text', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: 'testingtestingtestingtestingtestingtesting',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual(['testingt', 'estingte', 'stingtes', 'tingtest', 'ingtesti', 'ng'])
|
|
})
|
|
|
|
it('should return an empty array if the text is empty', async () => {
|
|
await ui.app.setup()
|
|
const lines = await browser.execute((options) => {
|
|
return window.app.textMeasure.getTextLines({
|
|
...options,
|
|
text: '',
|
|
})
|
|
}, getTextLinesOptions)
|
|
|
|
expect(lines).toEqual([])
|
|
})
|
|
})
|
|
})
|