voorhoede / head-start

Base setup on top of headless services to help you quickly start a new website
ISC License
3 stars 0 forks source link

Test Setup #103

Open jbmoelker opened 9 months ago

jbmoelker commented 9 months ago

User story

As a developer, I want a test setup and test coverage, so I can author code without worrying about regression.

Checklist

jbmoelker commented 8 months ago

We've experienced some issues with routing in recent Astro releases. So maybe it's good to have some of our tests covering this.

And probably good practice to start adding tests to our /api/ routes.

Individual blocks, components and partials may be easier to test once Astro container API is available.

jbmoelker commented 3 months ago

The Astro container API is now generally available.

jbmoelker commented 1 month ago

Possible setup to test components. Focus on how to, not what we should and shouldn't test.

src/blocks/Image.test.ts:

import { expect, test } from 'vitest';
import { renderToFragment, renderToString } from '@lib/renderer';
import Image from './Image.astro';

// test using rendered component as a string:
test('Image ...', async () => {
  const result = await renderToString(Image, {
    props: {
      image: {
        url: 'https://example.com/image.jpg',
        alt: 'An image',
        // title: 'A title',
      }
    },
  });

  expect(result).toContain(' alt="An image"');
  expect(result).toContain(' loading="lazy"');
  expect(result).not.toContain('<figcaption ');
  expect(result).not.toContain('</figcaption>');
});

// test using rendered component as a document fragment with DOM methods:
test('Image fragment', async () => {
  const fragment = await renderToFragment(Image, {
    props: {
      image: {
        url: 'https://example.com/image.jpg',
        alt: 'An image',
        // title: 'A title',
      }
    },
  });

  expect(fragment.querySelector('img')?.getAttribute('alt')).toEqual('An image');
  expect(fragment.querySelector('figcaption')).toBeNull();
});

src/lib/renderer.ts (helper)

import type { ContainerRenderOptions } from 'astro/container';
import type { AstroComponentFactory } from 'astro/runtime/server/index.d.ts';
import { experimental_AstroContainer as AstroContainer } from 'astro/container';
import { JSDOM } from 'jsdom';

export async function renderToString(
  component: AstroComponentFactory,
  options?: ContainerRenderOptions
): Promise<string> {
  const container = await AstroContainer.create();
  return container.renderToString(component, options);
}

export async function renderToFragment(
  component: AstroComponentFactory,
  options?: ContainerRenderOptions
): Promise<DocumentFragment> {
  const container = await AstroContainer.create();
  const result = await container.renderToString(component, options);
  return JSDOM.fragment(result);
}