import { afterEach, beforeAll, describe, expect, it } from 'vitest' import { labelsFor } from '../../assets/src/elements/labels' import { HostFailure, mountWidget, settle } from './host' // E9 golem15-seo-graph (UI-SPEC C18): the checking line with aria-busy // while the request runs, the noRules line per type without Google rules, // at most one queued request, and the danger line that keeps the last // graph. The first render and the 800 ms re-check are in schema.test.ts. beforeAll(async () => { await import('../../assets/src/elements/index') }) afterEach(() => { document.body.replaceChildren() }) const en = labelsFor('en') const answer = { locale: 'en', url: 'https://example.test/x', graph: { '@context': 'https://schema.org', '@graph': [] }, nodes: [ { id: 'https://example.test/x#webpage', type: 'WebPage', rules: false, findings: [] }, { id: 'https://example.test/x#service', type: 'Service', rules: false, findings: [] }, { id: 'https://example.test/x#website', type: 'WebSite', rules: true, findings: [{ level: 'required', property: 'name' }] }, ], } describe('E9 golem15-seo-graph states', () => { it('shows the checking line and aria-busy while the request runs, neither after it', async () => { const host = mountWidget('golem15-seo-graph', { attrs: { 'ui-locale': 'en' }, answer: () => answer }) await Promise.resolve() expect(host.node.getAttribute('aria-busy')).toBe('true') expect(host.node.querySelector('.seo-graph__checking')!.textContent).toBe(en.graphChecking) await settle() expect(host.node.getAttribute('aria-busy')).toBe('false') expect(host.node.querySelector('.seo-graph__checking')).toBeNull() }) it('writes one noRules line per node type without Google rules and the finding of the others', async () => { const host = mountWidget('golem15-seo-graph', { attrs: { 'ui-locale': 'en' }, answer: () => answer }) await settle() const text = host.node.textContent ?? '' expect(text).toContain(en.noRules.replace(':type', 'WebPage')) expect(text).toContain(en.noRules.replace(':type', 'Service')) expect(text).not.toContain(en.noRules.replace(':type', 'WebSite')) expect(text).toContain('Missing required property “name” (WebSite)') expect(text).not.toContain(en.allGood) }) it('queues at most one request while one runs', async () => { const host = mountWidget('golem15-seo-graph', { attrs: { 'ui-locale': 'en' }, answer: () => answer }) await Promise.resolve() const node = host.node as HTMLElement & { check(): void } node.check() node.check() node.check() await settle() expect(host.posted).toHaveLength(2) expect(host.node.getAttribute('aria-busy')).toBe('false') }) it('shows the danger line on the first failure and clears it on the next success', async () => { let fail = true const host = mountWidget('golem15-seo-graph', { attrs: { 'ui-locale': 'en' }, answer: () => { if (fail) { throw new HostFailure('down') } return answer }, }) await settle() expect(host.node.querySelector('.seo-graph__error')!.textContent).toBe(en.graphFailed) expect(host.node.getAttribute('aria-busy')).toBe('false') fail = false host.node.querySelector('.seo-graph__button')!.click() await settle() expect(host.node.querySelector('.seo-graph__error')).toBeNull() expect(host.node.textContent).toContain('WebSite') }) it('renders the Polish labels with ui-locale pl', async () => { const host = mountWidget('golem15-seo-graph', { attrs: { 'ui-locale': 'pl' }, answer: () => ({ ...answer, nodes: [answer.nodes[0]] }) }) await settle() expect(host.node.textContent).toContain(labelsFor('pl').noRules.replace(':type', 'WebPage')) }) })