fix: SEO SPA editor last fixes (3/4)
This commit is contained in:
1 parent
470584400f
commit
cb737b7ae3
19 files changed
+316
-147
No files matched your search
@@ -214,9 +214,9 @@ describe('A late answer never overwrites a newer one', () => {
|
||||
gates[0]!.resolve(checkAnswer([], 'hidden'))
|
||||
await flushPromises()
|
||||
|
||||
expect(textOf(sectionBody())).toContain('This article has no cover image.')
|
||||
expect(textOf(sectionBody())).toContain("No cover image. The site's social image is used.")
|
||||
expect(textOf(sectionBody())).not.toContain('Hidden from search engines')
|
||||
expect(textOf(panelRoot()!)).toContain('This article has no cover image.')
|
||||
expect(textOf(panelRoot()!)).toContain("No cover image. The site's social image is used.")
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -222,13 +222,13 @@ describe('Formatted', () => {
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ key: 'title', source: 'title', chip: 'Using article title' },
|
||||
{ key: 'description', source: 'body', chip: 'Using first sentence of the body' },
|
||||
{ key: 'description', source: 'excerpt', chip: 'Using the excerpt' },
|
||||
{ key: 'description', source: 'site', chip: 'Using the site default description' },
|
||||
{ key: 'image', source: 'cover', chip: 'Using cover image' },
|
||||
{ key: 'image', source: 'site', chip: 'Using site social image' },
|
||||
{ key: 'canonical', source: 'site', chip: 'Using site address and slug' },
|
||||
{ key: 'title', source: 'title', chip: 'article title + template' },
|
||||
{ key: 'description', source: 'body', chip: 'first sentence of the body' },
|
||||
{ key: 'description', source: 'excerpt', chip: 'excerpt' },
|
||||
{ key: 'description', source: 'site', chip: 'site default description' },
|
||||
{ key: 'image', source: 'cover', chip: 'cover image' },
|
||||
{ key: 'image', source: 'site', chip: 'site social image' },
|
||||
{ key: 'canonical', source: 'site', chip: 'site address + slug' },
|
||||
{ key: 'image', source: 'none', chip: 'No image' },
|
||||
])('shows "$chip" when fallbacks.$key is $source', async ({ key, source, chip }) => {
|
||||
await mountWithDialog({
|
||||
|
||||
@@ -427,6 +427,8 @@ describe('Advanced, canonical URL', () => {
|
||||
it.each([
|
||||
{ value: 'renew.example/costs', error: true },
|
||||
{ value: 'http://renew.example/a', error: true },
|
||||
{ value: ' https://renew.example/a', error: true },
|
||||
{ value: 'https://renew.example/a ', error: true },
|
||||
{ value: 'https://renew.example/a', error: false },
|
||||
{ value: '', error: false },
|
||||
])('for "$value" the error is shown: $error', async ({ value, error }) => {
|
||||
|
||||
@@ -149,6 +149,8 @@ describe('Saving state', () => {
|
||||
expect(fieldByLabel(panel, 'Meta description')!.disabled).toBe(true)
|
||||
expect(fieldByLabel(panel, 'Excerpt')!.disabled).toBe(true)
|
||||
expect(textOf(panel)).toContain('Saving…')
|
||||
expect(fieldByLabel(panel, 'Meta title')!.className).toContain('disabled:opacity-100')
|
||||
expect(fieldByLabel(panel, 'Meta title')!.className).not.toContain('opacity-40')
|
||||
expect(
|
||||
textOf(document.body.querySelector('[data-testid="save-button"]')!.parentElement),
|
||||
).toContain('Save')
|
||||
@@ -286,6 +288,22 @@ describe('The editor Save button treats SEO edits like any other edit', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Publish with a clean draft', () => {
|
||||
it('only sends the publish request', async () => {
|
||||
const backend = await mountSeo(seoBackend())
|
||||
backend.responders['PATCH /v1/article/12/publish'] = () => ({
|
||||
...backend.article,
|
||||
is_online: true,
|
||||
})
|
||||
const before = backend.calls.length
|
||||
|
||||
await click('Publish')
|
||||
|
||||
const patches = backend.calls.slice(before).filter((call) => call.method === 'PATCH')
|
||||
expect(patches.map((call) => call.path)).toEqual(['/v1/article/12/publish'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('Leaving with unsaved SEO edits', () => {
|
||||
it('asks Leave without saving? when the draft holds an unsaved SEO value', async () => {
|
||||
const { panel } = await failedPanelSave()
|
||||
|
||||
@@ -111,7 +111,7 @@ describe('The open section: address, suggestions and actions', () => {
|
||||
expect(panel).not.toBeNull()
|
||||
const suggestions = panel.querySelector('[data-testid="seo-panel-suggestions"]')!
|
||||
expect(document.activeElement).toBe(suggestions)
|
||||
expect(textOf(suggestions)).toContain('The body is 40 characters.')
|
||||
expect(textOf(suggestions)).toContain('The article is under 300 words.')
|
||||
})
|
||||
|
||||
it('shows no "+N more" action with three suggestions or fewer', async () => {
|
||||
@@ -263,28 +263,33 @@ describe('The messages follow the params of the response', () => {
|
||||
{},
|
||||
'The body has no headings. H2 headings help readers scan the article.',
|
||||
],
|
||||
['title_empty', 'seo_title', {}, 'The meta title is empty.'],
|
||||
['title_empty', 'seo_title', {}, 'No meta title yet. The article title is used instead.'],
|
||||
[
|
||||
'desc_long',
|
||||
'seo_description',
|
||||
{ length: 170, max: 160 },
|
||||
'The description is 170 characters. About 70 to 160 reads best in results.',
|
||||
'The description is 170 characters. Search engines may cut it off after about 160.',
|
||||
],
|
||||
['cover_none', 'cover_image_id', {}, 'This article has no cover image.'],
|
||||
['cover_none', 'cover_image_id', {}, "No cover image. The site's social image is used."],
|
||||
[
|
||||
'slug_long',
|
||||
'slug',
|
||||
{ length: 80, max: 75 },
|
||||
'The URL slug is 80 characters. Shorter addresses are easier to share.',
|
||||
'The slug is 80 characters. Shorter addresses are easier to share.',
|
||||
],
|
||||
[
|
||||
'no_au',
|
||||
'author_ids',
|
||||
{},
|
||||
'This article has no authors, so the structured data has no author.',
|
||||
],
|
||||
['no_au', 'author_ids', {}, 'This article has no author.'],
|
||||
['body_alt', 'body', { count: 2 }, '2 images in the body have no alt text.'],
|
||||
['body_alt', 'body', { count: 1 }, '1 image in the body has no alt text.'],
|
||||
[
|
||||
'short',
|
||||
'body',
|
||||
{ length: 40, min: 300 },
|
||||
'The body is 40 characters. Longer articles tend to do better in search.',
|
||||
'The article is under 300 words. That is fine for a short note.',
|
||||
],
|
||||
] as const)('renders %s with %j', async (code, field, params, message) => {
|
||||
const backend = seoBackend()
|
||||
|
||||
Reference in new issue
Block a user