/* eslint-env jest */ import type { ISeoBulkFields, ISeoBulkRow, } from '../../../service/seo/seo.interface'; import { DRAFT_CREDITS, changeOf, draftCost, draftRequest, mergeDraft, ranToday, renderRow, rowState, } from '../bulk-editor'; const LIST = { separator: '|', variables: { '%sitename%': 'Kettle Shop', '%page%': '' }, }; const content = '

A cast iron kettle keeps tea warm for hours and lasts for decades when it is dried after use.

How do you care for a cast iron kettle?

Dry it after every use.

'; const row = (overrides: Partial = {}): ISeoBulkRow => ({ id: 12, type: 'post', status: 'publish', title: 'Kettles', post_title: 'Kettles', excerpt: '', link: 'https://shop.example/kettles/', edit_link: 'https://shop.example/wp-admin/post.php?post=12&action=edit', editable: true, fields: { title: '', description: '', keywords: 'cast iron kettle' }, templates: { title: '%title% %sep% %sitename%', description: '%excerpt%' }, variables: { '%title%': 'Kettles', '%excerpt%': 'A cast iron kettle keeps tea warm.', }, score: 40, stale: false, ran_today: [], input: { title: 'Kettles | Kettle Shop', description: 'A cast iron kettle keeps tea warm.', slug: 'kettles', content, keyword: 'cast iron kettle', keywords: ['cast iron kettle'], hasFeaturedImage: false, imageAlts: [], postType: 'post', language: 'en', siteLanguage: 'en_US', keywordUsedElsewhere: null, }, ...overrides, }); const fields = (overrides: Partial = {}): ISeoBulkFields => ({ ...row().fields, ...overrides, }); describe('the bulk editor rows', () => { it('prices the drafts as the agent bills the snippet', () => { expect(DRAFT_CREDITS).toBe(10); expect(draftCost(7)).toBe(70); }); it('prints what the server printed until a field changes', () => { expect(renderRow(row(), fields(), LIST)).toEqual({ title: 'Kettles | Kettle Shop', description: 'A cast iron kettle keeps tea warm.', }); expect( renderRow( row(), fields({ title: '%focuskw%: how to choose one %sep% %sitename%' }), LIST ).title ).toBe('cast iron kettle: how to choose one | Kettle Shop'); // An empty field prints its template. expect( renderRow(row(), fields({ description: '', keywords: 'kettle' }), LIST) .description ).toBe('A cast iron kettle keeps tea warm.'); expect(renderRow(row(), fields({ keywords: 'kettle' }), LIST).title).toBe( 'Kettles | Kettle Shop' ); }); it('scores with the editor analysis, and keeps no score without a keyword', () => { const state = rowState(row(), fields(), LIST, 'shop.example'); expect(state.score).toBe(state.analysis.score); expect(state.tests.fixIds).toContain('keywordInTitle'); const better = rowState( row(), fields({ title: 'Cast iron kettle: how to choose and care for one' }), LIST, 'shop.example' ); expect(better.tests.fixIds).not.toContain('keywordInTitle'); expect(better.score).toBeGreaterThan(state.score ?? 0); expect( rowState(row(), fields({ keywords: '' }), LIST, 'shop.example').score ).toBeNull(); }); it('saves only what changed, with the score it makes', () => { expect(changeOf(row(), fields(), 40)).toBeNull(); expect(changeOf(row(), fields({ title: 'New title' }), 55)).toEqual({ id: 12, title: 'New title', score: 55, }); expect(changeOf(row(), fields({ keywords: '' }), null)).toEqual({ id: 12, keywords: '', }); }); it('puts a draft in the way Fix with AI applies it in the editor', () => { expect( mergeDraft(fields({ keywords: 'kettle, teapot, cast iron' }), { title: 'Cast iron kettle: how to choose one', description: 'How to choose a cast iron kettle by size and enamel.', keyword: 'cast iron kettle', }) ).toEqual({ title: 'Cast iron kettle: how to choose one', description: 'How to choose a cast iron kettle by size and enamel.', keywords: 'cast iron kettle, teapot, cast iron', }); // What the draft left empty stays. expect( mergeDraft(fields({ title: 'Mine' }), { title: ' ', description: '', keyword: '', }) ).toEqual(fields({ title: 'Mine' })); }); it('asks Fix with AI for the snippet alone, with the tests as edited', () => { const state = rowState(row(), fields(), LIST, 'shop.example'); const request = draftRequest( row(), fields({ keywords: 'kettle care, kettle' }), state.tests ); expect(request).toMatchObject({ post_id: 12, title: 'Kettles', keyword: 'kettle care', slug: 'kettles', snippet: true, rewrite: false, keyword_used_elsewhere: false, }); expect(request.content).toBe(content); expect(request.test_ids).toEqual(state.tests.fixIds); expect(request.tests).toHaveLength(state.tests.fixIds.length); }); it('tells a row Fix with AI already ran on today', () => { expect(ranToday(row())).toBe(false); expect(ranToday(row({ ran_today: ['fix'] }))).toBe(true); expect(ranToday(row({ ran_today: ['faq'] }))).toBe(false); }); });