0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-30 22:03:56 -05:00

Adds tests for server islands

This commit is contained in:
Matthew Phillips 2024-07-01 16:19:22 -04:00
parent a86b43d7b1
commit dc376448bb
17 changed files with 342 additions and 0 deletions

View file

@ -0,0 +1,11 @@
import mdx from '@astrojs/mdx';
import react from '@astrojs/react';
import { defineConfig } from 'astro/config';
import nodejs from '@astrojs/node';
// https://astro.build/config
export default defineConfig({
output: 'hybrid',
adapter: nodejs({ mode: 'standalone' }),
integrations: [react(), mdx()],
});

View file

@ -0,0 +1,16 @@
{
"name": "@e2e/server-islands",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "astro dev"
},
"dependencies": {
"@astrojs/react": "workspace:*",
"astro": "workspace:*",
"@astrojs/mdx": "workspace:*",
"@astrojs/node": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
}

View file

@ -0,0 +1,3 @@
---
---
<h2 id="island">I am an island</h2>

View file

@ -0,0 +1,12 @@
---
import Island from '../components/Island.astro';
---
<html>
<head>
<!-- Head Stuff -->
</head>
<body>
<Island server:defer />
</body>
</html>

View file

@ -0,0 +1,3 @@
import Island from '../components/Island.astro';
<Island server:defer />

View file

@ -0,0 +1,59 @@
import { expect } from '@playwright/test';
import { testFactory } from './test-utils.js';
const test = testFactory({ root: './fixtures/server-islands/' });
test.describe('Server islands', () => {
test.describe('Development', () => {
let devServer;
test.beforeAll(async ({ astro }) => {
devServer = await astro.startDevServer();
});
test.afterAll(async () => {
await devServer.stop();
});
test('Load content from the server', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
let el = page.locator('#island');
await expect(el, 'element rendered').toBeVisible();
await expect(el, 'should have content').toHaveText('I am an island');
});
test('Can be in an MDX file', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/mdx'));
let el = page.locator('#island');
await expect(el, 'element rendered').toBeVisible();
await expect(el, 'should have content').toHaveText('I am an island');
});
});
test.describe('Production', () => {
let previewServer;
test.beforeAll(async ({ astro }) => {
// Playwright's Node version doesn't have these functions, so stub them.
process.stdout.clearLine = () => {};
process.stdout.cursorTo = () => {};
await astro.build();
previewServer = await astro.preview();
});
test.afterAll(async () => {
await previewServer.stop();
});
test('Only one component in prod', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
let el = page.locator('#island');
await expect(el, 'element rendered').toBeVisible();
await expect(el, 'should have content').toHaveText('I am an island');
});
});
});

View file

@ -69,6 +69,7 @@ export function createEndpoint(manifest: SSRManifest) {
const instance: ComponentInstance = {
default: page,
partial: true,
};
return instance;

View file

@ -0,0 +1,10 @@
import svelte from '@astrojs/svelte';
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'hybrid',
integrations: [
svelte()
]
});

View file

@ -0,0 +1,10 @@
{
"name": "@test/server-islands-hybrid",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/svelte": "workspace:*",
"astro": "workspace:*",
"svelte": "^4.2.18"
}
}

View file

@ -0,0 +1,4 @@
---
---
<h2 id="island">I'm an island</h2>

View file

@ -0,0 +1,12 @@
---
import Island from '../components/Island.astro';
---
<html>
<head>
<title>Testing</title>
</head>
<body>
<h1>Testing</h1>
<Island server:defer />
</body>
</html>

View file

@ -0,0 +1,10 @@
import svelte from '@astrojs/svelte';
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'server',
integrations: [
svelte()
]
});

View file

@ -0,0 +1,10 @@
{
"name": "@test/server-islands-ssr",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/svelte": "workspace:*",
"astro": "workspace:*",
"svelte": "^4.2.18"
}
}

View file

@ -0,0 +1,4 @@
---
---
<h2 id="island">I'm an island</h2>

View file

@ -0,0 +1,12 @@
---
import Island from '../components/Island.astro';
---
<html>
<head>
<title>Testing</title>
</head>
<body>
<h1>Testing</h1>
<Island server:defer />
</body>
</html>

View file

@ -0,0 +1,120 @@
import assert from 'node:assert/strict';
import { after, before, describe, it } from 'node:test';
import * as cheerio from 'cheerio';
import testAdapter from './test-adapter.js';
import { loadFixture } from './test-utils.js';
describe('Server islands', () => {
describe('SSR', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/server-islands/ssr',
adapter: testAdapter(),
});
});
describe('dev', () => {
let devServer;
before(async () => {
devServer = await fixture.startDevServer();
});
after(async () => {
await devServer.stop();
});
it('omits the islands HTML', async () => {
const res = await fixture.fetch('/');
assert.equal(res.status, 200);
const html = await res.text();
const $ = cheerio.load(html);
const serverIslandEl = $('h2#island');
assert.equal(serverIslandEl.length, 0);
});
});
describe('prod', () => {
before(async () => {
await fixture.build();
});
it('omits the islands HTML', async () => {
const app = await fixture.loadTestAdapterApp();
const request = new Request('http://example.com/');
const response = await app.render(request);
const html = await response.text();
const $ = cheerio.load(html);
const serverIslandEl = $('h2#island');
assert.equal(serverIslandEl.length, 0);
const serverIslandScript = $('script[data-island-id]');
assert.equal(serverIslandScript.length, 1, 'has the island script');
});
});
});
describe('Hybrid mode', () => {
/** @type {import('./test-utils').Fixture} */
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/server-islands/hybrid',
adapter: testAdapter(),
});
});
describe('build', () => {
before(async () => {
await fixture.build();
});
it('Omits the island HTML from the static HTML', async () => {
let html = await fixture.readFile('/client/index.html');
const $ = cheerio.load(html);
const serverIslandEl = $('h2#island');
assert.equal(serverIslandEl.length, 0);
const serverIslandScript = $('script[data-island-id]');
assert.equal(serverIslandScript.length, 1, 'has the island script');
});
describe('prod', () => {
async function fetchIsland() {
const app = await fixture.loadTestAdapterApp();
const request = new Request('http://example.com/_server-islands/Island', {
method: 'POST',
body: JSON.stringify({
componentExport: 'default',
props: {},
slots: {},
})
});
return app.render(request);
}
it('Island returns its HTML', async () => {
const response = await fetchIsland();
const html = await response.text();
const $ = cheerio.load(html);
const serverIslandEl = $('h2#island');
assert.equal(serverIslandEl.length, 1);
});
it('Island does not include the doctype', async () => {
const response = await fetchIsland();
const html = await response.text();
console.log(html);
assert.ok(!/doctype/i.test(html), 'html does not include doctype');
});
});
});
});
});

View file

@ -1596,6 +1596,27 @@ importers:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
packages/astro/e2e/fixtures/server-islands:
dependencies:
'@astrojs/mdx':
specifier: workspace:*
version: link:../../../../integrations/mdx
'@astrojs/node':
specifier: workspace:*
version: link:../../../../integrations/node
'@astrojs/react':
specifier: workspace:*
version: link:../../../../integrations/react
astro:
specifier: workspace:*
version: link:../../..
react:
specifier: ^18.3.1
version: 18.3.1
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
packages/astro/e2e/fixtures/solid-circular:
dependencies:
'@astrojs/solid-js':
@ -3616,6 +3637,30 @@ importers:
specifier: workspace:*
version: link:../../..
packages/astro/test/fixtures/server-islands/hybrid:
dependencies:
'@astrojs/svelte':
specifier: workspace:*
version: link:../../../../../integrations/svelte
astro:
specifier: workspace:*
version: link:../../../..
svelte:
specifier: ^4.2.18
version: 4.2.18
packages/astro/test/fixtures/server-islands/ssr:
dependencies:
'@astrojs/svelte':
specifier: workspace:*
version: link:../../../../../integrations/svelte
astro:
specifier: workspace:*
version: link:../../../..
svelte:
specifier: ^4.2.18
version: 4.2.18
packages/astro/test/fixtures/set-html:
dependencies:
astro: