Skip to content

Add end-to-end integration tests for news article generation pipeline#707

Merged
pethers merged 20 commits intomainfrom
copilot/add-integration-tests-news-pipeline
Mar 1, 2026
Merged

Add end-to-end integration tests for news article generation pipeline#707
pethers merged 20 commits intomainfrom
copilot/add-integration-tests-news-pipeline

Conversation

Copy link
Contributor

Copilot AI commented Mar 1, 2026

  • Create tests/pipeline/news-generation-e2e.test.ts (42 tests)
  • Fix Norwegian hreflang BCP-47 (no → nb) in template.ts
  • Centralize hreflangCode() helper in helpers.ts
  • Tighten Norwegian switcher hreflang assertion (order-insensitive lookahead regexes)
  • Strengthen validateArticleBatch test (length guard + per-item assertions)
  • Fix calendar event mock fixtures (datedatum, titlerubrik, add tid)
  • Add expect(results).toHaveLength(articles.length) guard (line 318)
  • Assert all 8 generators succeed before building batch (line 752)
  • Fix CI failure: tests/fix-article-navigation.test.ts — map no → nb in hreflang assertion and update buildCompleteArticle fixture to hreflang="nb" for Norwegian
  • Address review comment: rename "HTML entities" test to not imply body escaping; remove <key> from subtitle; assert &amp; in meta/JSON-LD context
  • All 42 pipeline e2e tests pass; all 16 fix-article-navigation tests pass; CodeQL: 0 alerts
Original prompt

This section details on the original issue you should resolve

<issue_title>Add end-to-end integration tests for news article generation pipeline</issue_title>
<issue_description>## 📋 Issue Type
Architecture / Quality

🎯 Objective

Add end-to-end tests for the news article generation pipeline, validating the full flow from template rendering through article quality enhancement to final HTML output.

📊 Current State

  • 53 test files with 2169 tests pass
  • Tests cover individual modules (template, quality enhancer, MCP client, etc.)
  • No integration test validates the full article generation pipeline end-to-end
  • News generation is only validated after deployment via validate-news-generation.sh
  • Critical path from data → template → HTML → validation is tested in isolation, not as a pipeline

🚀 Desired State

  • Integration tests for the full news generation pipeline
  • Tests cover: data fetching mock → content generation → template rendering → HTML validation → quality checks
  • Tests verify all 14 language variants produce valid output
  • Tests verify Schema.org structured data is correct
  • Tests verify hreflang tags are consistent
  • Tests run as part of CI (not just post-deployment)

🔧 Implementation Approach

  1. Create tests/pipeline/news-generation-e2e.test.ts
  2. Mock MCP client responses with realistic data
  3. Run full pipeline: generateArticleHTML() → validate with HTMLHint → check quality metrics
  4. Verify output for each article type:
    • week-ahead, month-ahead, weekly-review, monthly-review
    • committee-reports, propositions, motions
    • evening-analysis
  5. Test edge cases:
    • Empty data (no parliamentary activity)
    • Missing translations
    • RTL language output (Arabic, Hebrew)
    • Very long article content
  6. Verify Schema.org JSON-LD validity

🤖 Recommended Agent

test-specialist — Integration test development

✅ Acceptance Criteria

  • Pipeline integration tests for all 8 article types
  • Tests cover all 14 language variants
  • HTMLHint validation built into tests
  • Schema.org JSON-LD validated
  • hreflang consistency verified
  • Tests run in CI via npm test
  • Edge cases covered (empty data, RTL, long content)

📚 References

  • Pipeline tests: tests/pipeline/ (existing directory)
  • Article template: scripts/article-template/template.ts
  • Quality enhancer: scripts/article-quality-enhancer.ts
  • News types: scripts/news-types/ (8 article type modules)
  • Test config: vitest.config.js

🏷️ Labels

type:testing, priority:medium, component:news-generation</issue_description>

<agent_instructions>Add end-to-end tests for the news generation pipeline in tests/pipeline/news-generation-e2e.test.ts. Mock MCP client, run full pipeline through generateArticleHTML(), validate with HTMLHint patterns, check Schema.org JSON-LD. Cover all 8 article types and edge cases.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copilot AI changed the title [WIP] Add end-to-end integration tests for news article generation pipeline Add end-to-end integration tests for news article generation pipeline Mar 1, 2026
@github-actions github-actions bot added testing Test coverage size-l Large change (250-1000 lines) labels Mar 1, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an end-to-end Vitest integration test suite that exercises the news article generation pipeline as a single flow (mock MCP data → generator → HTML template output → pipeline HTML validation), improving confidence beyond the existing unit-level coverage.

Changes:

  • Adds tests/pipeline/news-generation-e2e.test.ts with 41 tests covering all 8 news-type generators and validating generated HTML via pipeline/validation.
  • Verifies all 14 language variants for correct <html lang="…">, RTL dir="rtl" behavior, and structural validity.
  • Adds assertions for Schema.org JSON-LD parseability/shape and hreflang alternate-link consistency.

it('contains hreflang tags for all 14 language codes', () => {
const html = articleTemplate.generateArticleHTML(makeArticleData('en'));
ALL_14_LANGS.forEach(lang => {
expect(html, `hreflang="${lang}" missing`).toContain(`hreflang="${lang}"`);
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hreflang assertions treat Norwegian as hreflang="no", but elsewhere in the repo hreflang is explicitly mapped to BCP-47 nb for Norwegian (no filename suffix → nb hreflang). These tests should follow that convention (expect hreflang="nb" while keeping the href ending in -no.html) so the E2E suite doesn’t codify an SEO inconsistency.

Suggested change
expect(html, `hreflang="${lang}" missing`).toContain(`hreflang="${lang}"`);
const expectedHreflang = lang === 'no' ? 'nb' : lang;
expect(html, `hreflang="${expectedHreflang}" missing`).toContain(`hreflang="${expectedHreflang}"`);

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 9e976b9. The template (scripts/article-template/template.ts line 112) now maps no → nb in the hreflang attribute (URL path stays -no.html), consistent with generate-sitemap.ts, generate-rss.ts, and generate-sitemap-html.ts. The test now checks hreflang="nb" for Norwegian.

Comment on lines 607 to 629
// Generator should still succeed (degraded article or error, but not throw)
expect(typeof result.success).toBe('boolean');
});

it('committee-reports handles empty reports gracefully', async () => {
mockClientInstance.fetchCommitteeReports.mockResolvedValue([]);

const result = await committeeReportsMod.generateCommitteeReports({ languages: ['en'] });
expect(typeof result.success).toBe('boolean');
});

it('propositions handles empty data gracefully', async () => {
mockClientInstance.fetchPropositions.mockResolvedValue([]);

const result = await propositionsMod.generatePropositions({ languages: ['en'] });
expect(typeof result.success).toBe('boolean');
});

it('motions handles empty data gracefully', async () => {
mockClientInstance.fetchMotions.mockResolvedValue([]);

const result = await motionsMod.generateMotions({ languages: ['en'] });
expect(typeof result.success).toBe('boolean');
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “empty MCP data” edge-case tests only assert that result.success is a boolean, which will still pass even if a generator regresses into always failing (or returning success without generating any HTML). To meaningfully validate graceful degradation, assert the expected outcome per generator (e.g., success: true with files: 0 for “skip” generators, or success: true + articles[0].html passing validateArticleHTML for generators that still emit a degraded article).

Suggested change
// Generator should still succeed (degraded article or error, but not throw)
expect(typeof result.success).toBe('boolean');
});
it('committee-reports handles empty reports gracefully', async () => {
mockClientInstance.fetchCommitteeReports.mockResolvedValue([]);
const result = await committeeReportsMod.generateCommitteeReports({ languages: ['en'] });
expect(typeof result.success).toBe('boolean');
});
it('propositions handles empty data gracefully', async () => {
mockClientInstance.fetchPropositions.mockResolvedValue([]);
const result = await propositionsMod.generatePropositions({ languages: ['en'] });
expect(typeof result.success).toBe('boolean');
});
it('motions handles empty data gracefully', async () => {
mockClientInstance.fetchMotions.mockResolvedValue([]);
const result = await motionsMod.generateMotions({ languages: ['en'] });
expect(typeof result.success).toBe('boolean');
// Generator should still succeed and emit a degraded but valid article
expect(result.success).toBe(true);
const articles = result.articles as GeneratedArticle[];
expect(Array.isArray(articles)).toBe(true);
expect(articles.length).toBeGreaterThan(0);
const validation = pipelineValidation.validateArticleHTML(articles[0]!.html);
expect(validation.passed, validation.errors.join(', ')).toBe(true);
});
it('committee-reports handles empty reports gracefully', async () => {
mockClientInstance.fetchCommitteeReports.mockResolvedValue([]);
const result = await committeeReportsMod.generateCommitteeReports({ languages: ['en'] });
expect(result.success).toBe(true);
const articles = result.articles as GeneratedArticle[];
expect(Array.isArray(articles)).toBe(true);
expect(articles.length).toBeGreaterThan(0);
const validation = pipelineValidation.validateArticleHTML(articles[0]!.html);
expect(validation.passed, validation.errors.join(', ')).toBe(true);
});
it('propositions handles empty data gracefully', async () => {
mockClientInstance.fetchPropositions.mockResolvedValue([]);
const result = await propositionsMod.generatePropositions({ languages: ['en'] });
expect(result.success).toBe(true);
const articles = result.articles as GeneratedArticle[];
expect(Array.isArray(articles)).toBe(true);
expect(articles.length).toBeGreaterThan(0);
const validation = pipelineValidation.validateArticleHTML(articles[0]!.html);
expect(validation.passed, validation.errors.join(', ')).toBe(true);
});
it('motions handles empty data gracefully', async () => {
mockClientInstance.fetchMotions.mockResolvedValue([]);
const result = await motionsMod.generateMotions({ languages: ['en'] });
expect(result.success).toBe(true);
const articles = result.articles as GeneratedArticle[];
expect(Array.isArray(articles)).toBe(true);
expect(articles.length).toBeGreaterThan(0);
const validation = pipelineValidation.validateArticleHTML(articles[0]!.html);
expect(validation.passed, validation.errors.join(', ')).toBe(true);

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strengthened in commit 9e976b9. Each generator now has specific assertions:

  • week-ahead (empty events): success: true + articles.length > 0 + HTML passes validateArticleHTML (with requireSections: false since no events → no <h2> sections is expected)
  • committee-reports, propositions, motions (empty data): success: true + files: 0 (they skip article generation when no source data is available)

@pethers
Copy link
Member

pethers commented Mar 1, 2026

@copilot apply changes based on the comments in this thread

@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

…case assertions

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
@github-actions github-actions bot added the refactor Code refactoring label Mar 1, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comment on lines 111 to 113
<!-- Hreflang for language alternatives -->
${ALL_LANG_CODES.map(l => ` <link rel="alternate" hreflang="${l}" href="https://riksdagsmonitor.com/news/${baseSlug}-${l}.html">`).join('\n')}
${ALL_LANG_CODES.map(l => ` <link rel="alternate" hreflang="${l === 'no' ? 'nb' : l}" href="https://riksdagsmonitor.com/news/${baseSlug}-${l}.html">`).join('\n')}
<link rel="alternate" hreflang="x-default" href="https://riksdagsmonitor.com/news/${baseSlug}-en.html">
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The <link rel="alternate"> hreflang mapping now emits nb for Norwegian, but the page still renders the language switcher links with hreflang="no" via generateArticleLanguageSwitcher() (helpers.ts). This creates inconsistent hreflang values for the same Norwegian variant within one document. Consider centralizing a hreflangCode() mapping (no→nb) in the article-template layer and using it for both the <link rel="alternate"> tags and the language-switcher <a hreflang> attributes (or removing hreflang from the switcher entirely if it’s not needed).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 10d1947. Added a hreflangCode() helper to helpers.ts that centralizes the no → nb BCP-47 mapping. Both generateArticleLanguageSwitcher() (the in-page switcher) and the <link rel="alternate"> tags in template.ts now use this shared helper, ensuring consistent hreflang="nb" for Norwegian across the entire document.

Comment on lines +569 to +575
it('contains hreflang tags for all 14 language codes', () => {
const html = articleTemplate.generateArticleHTML(makeArticleData('en'));
ALL_14_LANGS.forEach(lang => {
const expectedHreflang = lang === 'no' ? 'nb' : lang;
expect(html, `hreflang="${expectedHreflang}" missing`).toContain(`hreflang="${expectedHreflang}"`);
});
});
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hreflang assertions only validate the <link rel="alternate"> tags. Since the template also emits hreflang attributes in the in-page language switcher, this suite won’t catch the current mismatch where Norwegian renders as hreflang="no" in the switcher but hreflang="nb" in the head alternates. Add an assertion that the language-switcher link for the -no.html variant uses hreflang="nb" (or whatever the intended mapping is) to prevent regressions.

Copilot generated this review using guidance from repository custom instructions.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in commit 10d1947. A new test 'language switcher Norwegian link uses hreflang="nb" (BCP-47), not "no"' asserts that no anchor with -no.html href uses hreflang="no", and that hreflang="nb" is present in the switcher markup.

@pethers
Copy link
Member

pethers commented Mar 1, 2026

@copilot apply changes based on the comments in this thread

@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

tests/pipeline/news-generation-e2e.test.ts:345

  • ltrLangs is a subset of LTR languages, but the test name says it covers “LTR languages”. As written, a regression that incorrectly adds dir="rtl" to e.g. da, no, fi, es, or nl would not be caught. Consider deriving this list from ALL_14_LANGS (exclude only ar/he) so the assertion matches the intent.
  it('does not set dir="rtl" for LTR languages', () => {
    const ltrLangs: Language[] = ['en', 'sv', 'de', 'fr', 'ja', 'ko', 'zh'];
    ltrLangs.forEach(lang => {
      const html = articleTemplate.generateArticleHTML(makeArticleData(lang));
      expect(html, `${lang} should not have rtl`).not.toContain('dir="rtl"');
    });
  });

Comment on lines 318 to 323
const results = pipelineValidation.validateArticleBatch(articles);

results.forEach(r => {
expect(r.passed, `Language ${r.filename} failed: ${r.errors.join(', ')}`).toBe(true);
});
});
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this test, validateArticleBatch(articles) is only iterated via results.forEach(...). If validateArticleBatch regresses to return an empty array, the loop won’t run and the test will still pass. Add an assertion that results.length === articles.length (or toHaveLength(articles.length)) before iterating so the batch validator itself is actually validated.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2250320. Added expect(results).toHaveLength(articles.length) before the forEach so a regressed validateArticleBatch returning an empty array will now fail fast.

Comment on lines 752 to 755
const successful = results.filter(r => r.success && r.articles?.length);
expect(successful.length).toBeGreaterThan(0);

const batch = successful.map(r => {
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is titled “across all 8 article types”, but it filters to successful and only asserts successful.length > 0. That means the test can still pass even if several generators start failing (or stop producing articles), which defeats the purpose of covering all 8 types. Consider asserting each results[i].success is true and that you have 8 generated articles in the batch before calling validateArticleBatch.

Suggested change
const successful = results.filter(r => r.success && r.articles?.length);
expect(successful.length).toBeGreaterThan(0);
const batch = successful.map(r => {
// Ensure all 8 generators succeeded and produced at least one article each
expect(results).toHaveLength(8);
results.forEach((r, index) => {
expect(r.success, `Generator index ${index} failed`).toBe(true);
expect(
r.articles && r.articles.length > 0,
`Generator index ${index} produced no articles`,
).toBe(true);
});
const batch = results.map(r => {

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 2250320. Replaced the filter + successful.length > 0 pattern with explicit assertions: expect(results).toHaveLength(8), per-generator expect(r.success).toBe(true), and expect(r.articles && r.articles.length > 0).toBe(true) before building the batch.

@pethers
Copy link
Member

pethers commented Mar 1, 2026

@copilot apply changes based on the comments in this thread and TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)
TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)Failing after 1m

@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

… all 8 generators succeed

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 1, 2026

@copilot apply changes based on the comments in this thread

Applied in commit 2250320. Both batch-validation weaknesses are now fixed: the "all 14 language variants" test guards against an empty-array regression with a length check, and the "all 8 article types" test explicitly asserts all 8 generators succeed and produce articles before building the batch.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

tests/pipeline/news-generation-e2e.test.ts:305

  • This test file hardcodes the full 14-language list in ALL_14_LANGS even though the template layer already exposes a single source of truth (ALL_LANG_CODES). To avoid the E2E suite drifting if languages are added/removed/reordered, consider importing and using ALL_LANG_CODES directly instead of duplicating the list here.
// All 14 supported language codes (mirrors ALL_LANG_CODES from constants)
// ---------------------------------------------------------------------------

const ALL_14_LANGS: readonly Language[] = [
  'en', 'sv', 'da', 'no', 'fi', 'de', 'fr', 'es', 'nl', 'ar', 'he', 'ja', 'ko', 'zh',
];

Comment on lines +726 to +727
);
expect(html).toContain('<!DOCTYPE html>');
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test name says it validates handling of HTML entities/special characters, but it doesn’t assert that potentially unsafe characters (like </>) are escaped in the rendered HTML. With the current inputs (subtitle contains <key>), the test will still pass even if the template outputs raw HTML, so it won’t catch XSS/markup-injection regressions. Consider asserting that <key> is rendered as &lt;key&gt; (or, if raw HTML is intended, rename the test and avoid implying escaping).

Suggested change
);
expect(html).toContain('<!DOCTYPE html>');
);
// Basic HTML structure check
expect(html).toContain('<!DOCTYPE html>');
// Ensure potentially unsafe characters are HTML-escaped in the rendered output.
// The raw `<key>` sequence should not appear, but its escaped form should.
expect(html).not.toContain('Analysis of <key> policy areas & legislative priorities');
expect(html).toContain('Analysis of &lt;key&gt; policy areas &amp; legislative priorities');
// JSON-LD blocks should still be valid

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 921a709. Renamed the test to "generates valid HTML when title and subtitle contain special characters" (removes the misleading "HTML entities" implication). Removed <key> from the subtitle (the template renders the lede raw by design — escaping is applied to meta tags and JSON-LD, as covered by article-template.test.ts:511-522). Added expect(html).toContain('Budget &amp; Defence') to assert that & IS escaped in the meta/JSON-LD context.

@pethers
Copy link
Member

pethers commented Mar 1, 2026

@copilot apply changes based on the comments in this thread and TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)
TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request)Failing after 1m

…pecial-chars e2e test

Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 1, 2026

@copilot apply changes based on the comments in this thread and [TypeScript & JavaScript Testing / Unit Tests (Vitest...

Fixed in commit 921a709. Two issues addressed:

  1. CI failure (tests/fix-article-navigation.test.ts): updated buildCompleteArticle fixture to hreflang="nb" for Norwegian and added the no → nb mapping to the "generates all 14 language links" assertion — matches the hreflangCode() BCP-47 mapping now used by generateArticleLanguageSwitcher.
  2. Review comment (special-chars test): renamed test to not imply body-level escaping; removed <key> from subtitle; added &amp; assertion for meta/JSON-LD context.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

🔍 Lighthouse Performance Audit

Category Score Status
Performance 85/100 🟡
Accessibility 95/100 🟢
Best Practices 90/100 🟢
SEO 95/100 🟢

📥 Download full Lighthouse report

Budget Compliance: Performance budgets enforced via budget.json

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@pethers pethers marked this pull request as ready for review March 1, 2026 14:44
@pethers pethers merged commit b0c473a into main Mar 1, 2026
19 checks passed
@pethers pethers deleted the copilot/add-integration-tests-news-pipeline branch March 1, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

refactor Code refactoring size-l Large change (250-1000 lines) testing Test coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add end-to-end integration tests for news article generation pipeline

3 participants