feat(site-builder): pre-publish checklist and canonical link
Publish now runs client-side checks (image alt, meta description, title length, H1, empty links, contrast, noindex landing, empty page) over the current state and shows a grouped checklist with Fix links and "Publish anyway". Adds ExportOptions.canonicalUrl -> <link rel="canonical"> after the favicon line in both Preview and export. Refs #54
This commit is contained in:
1 parent
5430f13877
commit
c0fd183c11
12 files changed
+913
-13
No files matched your search
@@ -204,7 +204,7 @@ describe('conflict modal', () => {
|
||||
loadedThen('r1', [conflict409]);
|
||||
mount();
|
||||
await flush();
|
||||
await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); });
|
||||
await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await confirmChecklist();
|
||||
await flush();
|
||||
expect(q('[data-testid="conflict-modal"]')).not.toBeNull();
|
||||
expect(fetchMock.mock.calls.filter(([u]) => String(u).includes('action=publish'))).toHaveLength(0);
|
||||
@@ -264,3 +264,10 @@ describe('revision and overwrite edge cases', () => {
|
||||
expect(saveBody(2).base_rev).toBe('r1');
|
||||
});
|
||||
});
|
||||
|
||||
/** #54: the pre-publish checklist opens for these fixtures (an empty Home with no
|
||||
* meta description); these tests are about the publish path, so confirm it. */
|
||||
async function confirmChecklist() {
|
||||
const b = q('[data-testid="publish-checklist-confirm"]') as HTMLElement | null;
|
||||
if (b) await act(async () => { b.click(); });
|
||||
}
|
||||
@@ -138,7 +138,7 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
const edit = () => act(() => { guard.markDirty(); });
|
||||
const clickPublish = async () => { await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await flush(); };
|
||||
const clickPublish = async () => { await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await confirmChecklist(); await flush(); };
|
||||
|
||||
describe('saves are serialised', () => {
|
||||
test('a save requested during an in-flight publish waits, then saves with the rev the first save returned', async () => {
|
||||
@@ -235,3 +235,10 @@ describe('autosave timer', () => {
|
||||
expect(calls('save').length).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
/** #54: the pre-publish checklist opens for these fixtures (an empty Home with no
|
||||
* meta description); these tests are about the publish path, so confirm it. */
|
||||
async function confirmChecklist() {
|
||||
const b = q('[data-testid="publish-checklist-confirm"]') as HTMLElement | null;
|
||||
if (b) await act(async () => { b.click(); });
|
||||
}
|
||||
@@ -69,7 +69,7 @@ const flush = () => act(async () => { for (let i = 0; i < 10; i++) await Promise
|
||||
const calls = (action: string) => fetchMock.mock.calls.filter(([u]) => String(u).includes(`action=${action}`));
|
||||
const edit = () => act(() => { guard.markDirty(); });
|
||||
const clickSave = async () => { await act(async () => { q('button[aria-label="Save Draft"]')!.click(); }); await flush(); };
|
||||
const clickPublish = async () => { await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await flush(); };
|
||||
const clickPublish = async () => { await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await confirmChecklist(); await flush(); };
|
||||
|
||||
function respondWith(handlers: { save?: unknown[]; publish?: unknown[] }) {
|
||||
const save = [...(handlers.save ?? [])];
|
||||
@@ -368,7 +368,7 @@ describe('publish racing an edit', () => {
|
||||
});
|
||||
await mount();
|
||||
edit();
|
||||
await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); });
|
||||
await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await confirmChecklist();
|
||||
await flush();
|
||||
expect(calls('publish')).toHaveLength(1);
|
||||
|
||||
@@ -392,7 +392,7 @@ describe('publish racing an edit', () => {
|
||||
});
|
||||
await mount();
|
||||
edit();
|
||||
await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); });
|
||||
await act(async () => { q('button[aria-label="Publish to live site"]')!.click(); }); await confirmChecklist();
|
||||
await flush();
|
||||
const savesBefore = calls('save').length; // the publish's own save
|
||||
await act(async () => { vi.advanceTimersByTime(30_000); });
|
||||
@@ -433,3 +433,10 @@ describe('populated project load', () => {
|
||||
expect(pill()).toBe('unsaved');
|
||||
});
|
||||
});
|
||||
|
||||
/** #54: the pre-publish checklist opens for these fixtures (an empty Home with no
|
||||
* meta description); these tests are about the publish path, so confirm it. */
|
||||
async function confirmChecklist() {
|
||||
const b = q('[data-testid="publish-checklist-confirm"]') as HTMLElement | null;
|
||||
if (b) await act(async () => { b.click(); });
|
||||
}
|
||||
Reference in new issue
Block a user