diff --git a/.changeset/config.json b/.changeset/config.json
index 8292fbe07..41ec3ec86 100644
--- a/.changeset/config.json
+++ b/.changeset/config.json
@@ -6,5 +6,5 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
- "ignore": ["@example/*", "@test/*"]
+ "ignore": ["@example/*", "@test/*", "@e2e/*"]
}
diff --git a/package.json b/package.json
index 14e9e6193..b3e2bf6d3 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"test:smoke": "node scripts/smoke/index.js",
"test:vite-ci": "turbo run test --no-deps --scope=astro --concurrency=1",
"test:e2e": "cd packages/astro && pnpm playwright install && pnpm run test:e2e",
+ "test:e2e:match": "cd packages/astro && pnpm playwright install && pnpm run test:e2e:match",
"benchmark": "turbo run benchmark --scope=astro",
"lint": "eslint \"packages/**/*.ts\"",
"format": "prettier -w .",
diff --git a/packages/astro/e2e/astro-component.test.js b/packages/astro/e2e/astro-component.test.js
new file mode 100644
index 000000000..65499499f
--- /dev/null
+++ b/packages/astro/e2e/astro-component.test.js
@@ -0,0 +1,42 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/astro-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('Astro components', () => {
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const hero = page.locator('section');
+ await expect(hero, 'hero has background: white').toHaveCSS(
+ 'background-color',
+ 'rgb(255, 255, 255)'
+ );
+ await expect(hero, 'hero has color: black').toHaveCSS('color', 'rgb(0, 0, 0)');
+
+ // Edit the Hero component with a new background color
+ await astro.editFile('./src/components/Hero.astro', (content) =>
+ content.replace('background: white', 'background: rgb(230, 230, 230)')
+ );
+
+ await expect(hero, 'background color updated').toHaveCSS(
+ 'background-color',
+ 'rgb(230, 230, 230)'
+ );
+ });
+});
diff --git a/packages/astro/e2e/fixtures/astro-component/astro.config.mjs b/packages/astro/e2e/fixtures/astro-component/astro.config.mjs
new file mode 100644
index 000000000..882e6515a
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/astro.config.mjs
@@ -0,0 +1,4 @@
+import { defineConfig } from 'astro/config';
+
+// https://astro.build/config
+export default defineConfig({});
diff --git a/packages/astro/e2e/fixtures/astro-component/package.json b/packages/astro/e2e/fixtures/astro-component/package.json
new file mode 100644
index 000000000..33a377834
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "@e2e/astro-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/astro-component/src/components/Counter.css b/packages/astro/e2e/fixtures/astro-component/src/components/Counter.css
new file mode 100644
index 000000000..fb21044d7
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/src/components/Counter.css
@@ -0,0 +1,11 @@
+.counter {
+ display: grid;
+ font-size: 2em;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ margin-top: 2em;
+ place-items: center;
+}
+
+.counter-message {
+ text-align: center;
+}
diff --git a/packages/astro/e2e/fixtures/astro-component/src/components/Counter.jsx b/packages/astro/e2e/fixtures/astro-component/src/components/Counter.jsx
new file mode 100644
index 000000000..526f26963
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/src/components/Counter.jsx
@@ -0,0 +1,20 @@
+import { h, Fragment } from 'preact';
+import { useState } from 'preact/hooks';
+import './Counter.css';
+
+export default function Counter({ children, count: initialCount, id }) {
+ const [count, setCount] = useState(initialCount);
+ const add = () => setCount((i) => i + 1);
+ const subtract = () => setCount((i) => i - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/astro-component/src/components/Hero.astro b/packages/astro/e2e/fixtures/astro-component/src/components/Hero.astro
new file mode 100644
index 000000000..680a5f639
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/src/components/Hero.astro
@@ -0,0 +1,25 @@
+---
+export interface Props {
+ title: string;
+}
+
+const { title } = Astro.props as Props;
+---
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/astro-component/src/components/JSXComponent.jsx b/packages/astro/e2e/fixtures/astro-component/src/components/JSXComponent.jsx
new file mode 100644
index 000000000..6cc7b7858
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/src/components/JSXComponent.jsx
@@ -0,0 +1,5 @@
+import { h } from 'preact';
+
+export default function({ id }) {
+ return Preact client:only component
+}
diff --git a/packages/astro/e2e/fixtures/astro-component/src/pages/index.astro b/packages/astro/e2e/fixtures/astro-component/src/pages/index.astro
new file mode 100644
index 000000000..a52ee713f
--- /dev/null
+++ b/packages/astro/e2e/fixtures/astro-component/src/pages/index.astro
@@ -0,0 +1,16 @@
+---
+import Hero from '../components/Hero.astro';
+---
+
+
+
+
+
+
+
+
+ Lorem ipsum, dolor sit amet consectetur adipisicing elit.
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/lit-component/astro.config.mjs b/packages/astro/e2e/fixtures/lit-component/astro.config.mjs
new file mode 100644
index 000000000..1eab8f9ab
--- /dev/null
+++ b/packages/astro/e2e/fixtures/lit-component/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import lit from '@astrojs/lit';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [lit()],
+});
diff --git a/packages/astro/e2e/fixtures/lit-component/package.json b/packages/astro/e2e/fixtures/lit-component/package.json
new file mode 100644
index 000000000..ea73f5982
--- /dev/null
+++ b/packages/astro/e2e/fixtures/lit-component/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "@e2e/lit-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/lit": "workspace:*",
+ "astro": "workspace:*",
+ "@webcomponents/template-shadowroot": "^0.1.0",
+ "lit": "^2.2.3"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/lit-component/src/components/Counter.js b/packages/astro/e2e/fixtures/lit-component/src/components/Counter.js
new file mode 100644
index 000000000..3316a7342
--- /dev/null
+++ b/packages/astro/e2e/fixtures/lit-component/src/components/Counter.js
@@ -0,0 +1,36 @@
+import { LitElement, html } from 'lit';
+
+export const tagName = 'my-counter';
+
+class Counter extends LitElement {
+ static get properties() {
+ return {
+ count: {
+ type: Number,
+ },
+ };
+ }
+
+ constructor() {
+ super();
+ this.count = 0;
+ }
+
+ increment() {
+ this.count++;
+ }
+
+ render() {
+ return html`
+
+
Count: ${this.count}
+
+
+
+
+
+ `;
+ }
+}
+
+customElements.define(tagName, Counter);
diff --git a/packages/astro/e2e/fixtures/lit-component/src/pages/index.astro b/packages/astro/e2e/fixtures/lit-component/src/pages/index.astro
new file mode 100644
index 000000000..48eb7d2f9
--- /dev/null
+++ b/packages/astro/e2e/fixtures/lit-component/src/pages/index.astro
@@ -0,0 +1,26 @@
+---
+import '../components/Counter.js';
+
+const someProps = {
+ count: 0,
+};
+---
+
+
+
+
+
+
+
+ Hello, client:idle!
+
+
+
+ Hello, client:load!
+
+
+
+ Hello, client:visible!
+
+
+
diff --git a/packages/astro/e2e/fixtures/lit-component/src/pages/media.astro b/packages/astro/e2e/fixtures/lit-component/src/pages/media.astro
new file mode 100644
index 000000000..e54cec071
--- /dev/null
+++ b/packages/astro/e2e/fixtures/lit-component/src/pages/media.astro
@@ -0,0 +1,18 @@
+---
+import '../components/Counter.js';
+
+const someProps = {
+ count: 0,
+};
+---
+
+
+
+
+
+
+
+ Hello, client:media!
+
+
+
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs b/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs
new file mode 100644
index 000000000..4b50887cd
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/astro.config.mjs
@@ -0,0 +1,12 @@
+import { defineConfig } from 'astro/config';
+import preact from '@astrojs/preact';
+import react from '@astrojs/react';
+import svelte from '@astrojs/svelte';
+import vue from '@astrojs/vue';
+import solid from '@astrojs/solid-js';
+
+// https://astro.build/config
+export default defineConfig({
+ // Enable many frameworks to support all different kinds of components.
+ integrations: [preact(), react(), svelte(), vue(), solid()],
+});
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/package.json b/packages/astro/e2e/fixtures/multiple-frameworks/package.json
new file mode 100644
index 000000000..ab0dd06bc
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@e2e/multiple-frameworks",
+ "version": "0.0.0",
+ "private": true,
+ "devDependencies": {
+ "@astrojs/lit": "^0.1.3",
+ "@astrojs/preact": "^0.1.2",
+ "@astrojs/react": "^0.1.2",
+ "@astrojs/solid-js": "^0.1.2",
+ "@astrojs/svelte": "^0.1.3",
+ "@astrojs/vue": "^0.1.4",
+ "astro": "^1.0.0-beta.31"
+ },
+ "dependencies": {
+ "@webcomponents/template-shadowroot": "^0.1.0",
+ "lit": "^2.2.4",
+ "preact": "^10.7.2",
+ "react": "^18.1.0",
+ "react-dom": "^18.1.0",
+ "solid-js": "^1.4.2",
+ "svelte": "^3.48.0",
+ "vue": "^3.2.34"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/A.astro b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/A.astro
new file mode 100644
index 000000000..b2c223a29
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/A.astro
@@ -0,0 +1,7 @@
+---
+const { id } = Astro.props
+---
+
+
+
Hello Astro (A)
+
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/B.astro b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/B.astro
new file mode 100644
index 000000000..339f63735
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/B.astro
@@ -0,0 +1,7 @@
+---
+const { id } = Astro.props
+---
+
+
+
Hello Astro (B)
+
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/LitCounter.js b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/LitCounter.js
new file mode 100644
index 000000000..883a7581d
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/LitCounter.js
@@ -0,0 +1,33 @@
+import { LitElement, html } from 'lit';
+
+export const tagName = 'my-counter';
+
+class Counter extends LitElement {
+ static get properties() {
+ return {
+ count: {
+ type: Number,
+ },
+ };
+ }
+
+ constructor() {
+ super();
+ this.count = 0;
+ }
+
+ increment() {
+ this.count++;
+ }
+
+ render() {
+ return html`
+
+
Count: ${this.count}
+
+
+ `;
+ }
+}
+
+customElements.define(tagName, Counter);
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/PreactCounter.tsx b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/PreactCounter.tsx
new file mode 100644
index 000000000..af2258fdf
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/PreactCounter.tsx
@@ -0,0 +1,19 @@
+import { useState } from 'preact/hooks';
+
+/** a counter written in Preact */
+export function PreactCounter({ children, id }) {
+ const [count, setCount] = useState(0);
+ const add = () => setCount((i) => i + 1);
+ const subtract = () => setCount((i) => i - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/ReactCounter.jsx b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/ReactCounter.jsx
new file mode 100644
index 000000000..02eb19539
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/ReactCounter.jsx
@@ -0,0 +1,19 @@
+import { useState } from 'react';
+
+/** a counter written in React */
+export function Counter({ children, id }) {
+ const [count, setCount] = useState(0);
+ const add = () => setCount((i) => i + 1);
+ const subtract = () => setCount((i) => i - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SolidCounter.tsx b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SolidCounter.tsx
new file mode 100644
index 000000000..689c5222c
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SolidCounter.tsx
@@ -0,0 +1,19 @@
+import { createSignal } from 'solid-js';
+
+/** a counter written with Solid */
+export default function SolidCounter({ children, id }) {
+ const [count, setCount] = createSignal(0);
+ const add = () => setCount(count() + 1);
+ const subtract = () => setCount(count() - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SvelteCounter.svelte b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SvelteCounter.svelte
new file mode 100644
index 000000000..ab13b9c71
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/SvelteCounter.svelte
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/VueCounter.vue b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/VueCounter.vue
new file mode 100644
index 000000000..4861511c8
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/VueCounter.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/components/index.ts b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/index.ts
new file mode 100644
index 000000000..4077dcacd
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/components/index.ts
@@ -0,0 +1,2 @@
+export { default as A } from './A.astro';
+export { default as B } from './B.astro';
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro b/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro
new file mode 100644
index 000000000..a30688bca
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/pages/index.astro
@@ -0,0 +1,50 @@
+---
+// Style Imports
+import '../styles/global.css';
+// Component Imports
+import { A, B as Renamed } from '../components';
+import * as react from '../components/ReactCounter.jsx';
+import { PreactCounter } from '../components/PreactCounter.tsx';
+import SolidCounter from '../components/SolidCounter.tsx';
+import VueCounter from '../components/VueCounter.vue';
+import SvelteCounter from '../components/SvelteCounter.svelte';
+
+// Full Astro Component Syntax:
+// https://docs.astro.build/core-concepts/astro-components/
+---
+
+
+
+
+
+
+
+
+
+
+ Hello React!
+ What's up?
+
+
+
+ Hello Preact!
+
+
+
+ Hello Solid!
+
+
+
+ Hello Vue!
+
+
+
+ Hello Svelte!
+
+
+
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/multiple-frameworks/src/styles/global.css b/packages/astro/e2e/fixtures/multiple-frameworks/src/styles/global.css
new file mode 100644
index 000000000..4912b4c39
--- /dev/null
+++ b/packages/astro/e2e/fixtures/multiple-frameworks/src/styles/global.css
@@ -0,0 +1,21 @@
+html,
+body {
+ font-family: system-ui;
+ margin: 0;
+}
+
+body {
+ padding: 2rem;
+}
+
+.counter {
+ display: grid;
+ font-size: 2em;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ margin-top: 2em;
+ place-items: center;
+}
+
+.counter-message {
+ text-align: center;
+}
diff --git a/packages/astro/e2e/fixtures/preact-component/astro.config.mjs b/packages/astro/e2e/fixtures/preact-component/astro.config.mjs
new file mode 100644
index 000000000..08916b1fe
--- /dev/null
+++ b/packages/astro/e2e/fixtures/preact-component/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import preact from '@astrojs/preact';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [preact()],
+});
diff --git a/packages/astro/e2e/fixtures/preact-component/package.json b/packages/astro/e2e/fixtures/preact-component/package.json
new file mode 100644
index 000000000..8ee5c3a0a
--- /dev/null
+++ b/packages/astro/e2e/fixtures/preact-component/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@e2e/preact-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/preact": "workspace:*",
+ "astro": "workspace:*",
+ "preact": "^10.7.2"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/preact-component/src/components/Counter.css b/packages/astro/e2e/fixtures/preact-component/src/components/Counter.css
new file mode 100644
index 000000000..fb21044d7
--- /dev/null
+++ b/packages/astro/e2e/fixtures/preact-component/src/components/Counter.css
@@ -0,0 +1,11 @@
+.counter {
+ display: grid;
+ font-size: 2em;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ margin-top: 2em;
+ place-items: center;
+}
+
+.counter-message {
+ text-align: center;
+}
diff --git a/packages/astro/e2e/fixtures/preact-component/src/components/Counter.jsx b/packages/astro/e2e/fixtures/preact-component/src/components/Counter.jsx
new file mode 100644
index 000000000..526f26963
--- /dev/null
+++ b/packages/astro/e2e/fixtures/preact-component/src/components/Counter.jsx
@@ -0,0 +1,20 @@
+import { h, Fragment } from 'preact';
+import { useState } from 'preact/hooks';
+import './Counter.css';
+
+export default function Counter({ children, count: initialCount, id }) {
+ const [count, setCount] = useState(initialCount);
+ const add = () => setCount((i) => i + 1);
+ const subtract = () => setCount((i) => i - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx b/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx
new file mode 100644
index 000000000..6cc7b7858
--- /dev/null
+++ b/packages/astro/e2e/fixtures/preact-component/src/components/JSXComponent.jsx
@@ -0,0 +1,5 @@
+import { h } from 'preact';
+
+export default function({ id }) {
+ return Preact client:only component
+}
diff --git a/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro b/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro
new file mode 100644
index 000000000..946b90be0
--- /dev/null
+++ b/packages/astro/e2e/fixtures/preact-component/src/pages/index.astro
@@ -0,0 +1,37 @@
+---
+import Counter from '../components/Counter.jsx';
+import PreactComponent from '../components/JSXComponent.jsx';
+
+const someProps = {
+ count: 0,
+};
+---
+
+
+
+
+
+
+
+ Hello, server!
+
+
+
+ Hello, client:idle!
+
+
+
+ Hello, client:load!
+
+
+
+ Hello, client:visible!
+
+
+
+ Hello, client:media!
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/react-component/astro.config.mjs b/packages/astro/e2e/fixtures/react-component/astro.config.mjs
new file mode 100644
index 000000000..8a6f1951c
--- /dev/null
+++ b/packages/astro/e2e/fixtures/react-component/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import react from '@astrojs/react';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [react()],
+});
diff --git a/packages/astro/e2e/fixtures/react-component/package.json b/packages/astro/e2e/fixtures/react-component/package.json
new file mode 100644
index 000000000..9236558f0
--- /dev/null
+++ b/packages/astro/e2e/fixtures/react-component/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "@e2e/react-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/react": "workspace:*",
+ "astro": "workspace:*",
+ "react": "^18.1.0",
+ "react-dom": "^18.1.0"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/react-component/src/components/Counter.css b/packages/astro/e2e/fixtures/react-component/src/components/Counter.css
new file mode 100644
index 000000000..fb21044d7
--- /dev/null
+++ b/packages/astro/e2e/fixtures/react-component/src/components/Counter.css
@@ -0,0 +1,11 @@
+.counter {
+ display: grid;
+ font-size: 2em;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ margin-top: 2em;
+ place-items: center;
+}
+
+.counter-message {
+ text-align: center;
+}
diff --git a/packages/astro/e2e/fixtures/react-component/src/components/Counter.jsx b/packages/astro/e2e/fixtures/react-component/src/components/Counter.jsx
new file mode 100644
index 000000000..769e0cccf
--- /dev/null
+++ b/packages/astro/e2e/fixtures/react-component/src/components/Counter.jsx
@@ -0,0 +1,19 @@
+import React, { useState } from 'react';
+import './Counter.css';
+
+export default function Counter({ children, count: initialCount, id }) {
+ const [count, setCount] = useState(initialCount);
+ const add = () => setCount((i) => i + 1);
+ const subtract = () => setCount((i) => i - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx b/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx
new file mode 100644
index 000000000..90a4d7c42
--- /dev/null
+++ b/packages/astro/e2e/fixtures/react-component/src/components/JSXComponent.jsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+export default function({ id }) {
+ return React client:only component
+}
diff --git a/packages/astro/e2e/fixtures/react-component/src/pages/index.astro b/packages/astro/e2e/fixtures/react-component/src/pages/index.astro
new file mode 100644
index 000000000..388fc1d98
--- /dev/null
+++ b/packages/astro/e2e/fixtures/react-component/src/pages/index.astro
@@ -0,0 +1,37 @@
+---
+import Counter from '../components/Counter.jsx';
+import ReactComponent from '../components/JSXComponent.jsx';
+
+const someProps = {
+ count: 0,
+};
+---
+
+
+
+
+
+
+
+ Hello, server!
+
+
+
+ Hello, client:idle!
+
+
+
+ Hello, client:load!
+
+
+
+ Hello, client:visible!
+
+
+
+ Hello, client:media!
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/solid-component/astro.config.mjs b/packages/astro/e2e/fixtures/solid-component/astro.config.mjs
new file mode 100644
index 000000000..a6c39b853
--- /dev/null
+++ b/packages/astro/e2e/fixtures/solid-component/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import solid from '@astrojs/solid-js';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [solid()],
+});
diff --git a/packages/astro/e2e/fixtures/solid-component/package.json b/packages/astro/e2e/fixtures/solid-component/package.json
new file mode 100644
index 000000000..5973f12fa
--- /dev/null
+++ b/packages/astro/e2e/fixtures/solid-component/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@e2e/solid-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/solid-js": "workspace:*",
+ "astro": "workspace:*"
+ },
+ "devDependencies": {
+ "solid-js": "^1.4.1"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/solid-component/src/components/Counter.css b/packages/astro/e2e/fixtures/solid-component/src/components/Counter.css
new file mode 100644
index 000000000..cffdbda7b
--- /dev/null
+++ b/packages/astro/e2e/fixtures/solid-component/src/components/Counter.css
@@ -0,0 +1,11 @@
+.counter {
+ display: grid;
+ font-size: 2em;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ margin-top: 3em;
+ place-items: center;
+}
+
+.counter-message {
+ text-align: center;
+}
diff --git a/packages/astro/e2e/fixtures/solid-component/src/components/Counter.jsx b/packages/astro/e2e/fixtures/solid-component/src/components/Counter.jsx
new file mode 100644
index 000000000..e315033d3
--- /dev/null
+++ b/packages/astro/e2e/fixtures/solid-component/src/components/Counter.jsx
@@ -0,0 +1,19 @@
+import { createSignal } from 'solid-js';
+import './Counter.css';
+
+export default function Counter({ children, id, count: initialCount = 0 }) {
+ const [count, setCount] = createSignal(initialCount);
+ const add = () => setCount(count() + 1);
+ const subtract = () => setCount(count() - 1);
+
+ return (
+ <>
+
+ {children}
+ >
+ );
+}
diff --git a/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro b/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro
new file mode 100644
index 000000000..91013ad0e
--- /dev/null
+++ b/packages/astro/e2e/fixtures/solid-component/src/pages/index.astro
@@ -0,0 +1,34 @@
+---
+import Counter from '../components/Counter.jsx';
+
+const someProps = {
+ count: 0,
+};
+---
+
+
+
+
+
+
+
+ Hello, server!
+
+
+
+ Hello, client:idle!
+
+
+
+ Hello, client:load!
+
+
+
+ Hello, client:visible!
+
+
+
+ Hello, client:media!
+
+
+
diff --git a/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs b/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs
new file mode 100644
index 000000000..77fdcd1b9
--- /dev/null
+++ b/packages/astro/e2e/fixtures/svelte-component/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import svelte from '@astrojs/svelte';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [svelte()],
+});
diff --git a/packages/astro/e2e/fixtures/svelte-component/package.json b/packages/astro/e2e/fixtures/svelte-component/package.json
new file mode 100644
index 000000000..2777c8ecd
--- /dev/null
+++ b/packages/astro/e2e/fixtures/svelte-component/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "@e2e/svelte-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/svelte": "workspace:*",
+ "astro": "workspace:*",
+ "svelte": "^3.48.0"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte b/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte
new file mode 100644
index 000000000..264ec9dde
--- /dev/null
+++ b/packages/astro/e2e/fixtures/svelte-component/src/components/Counter.svelte
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro b/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro
new file mode 100644
index 000000000..3c8117124
--- /dev/null
+++ b/packages/astro/e2e/fixtures/svelte-component/src/pages/index.astro
@@ -0,0 +1,34 @@
+---
+import Counter from '../components/Counter.svelte';
+
+const someProps = {
+ count: 0,
+};
+---
+
+
+
+
+
+
+
+ Hello, server!
+
+
+
+ Hello, client:idle!
+
+
+
+ Hello, client:load!
+
+
+
+ Hello, client:visible!
+
+
+
+ Hello, client:media!
+
+
+
diff --git a/packages/astro/e2e/fixtures/tailwindcss/package.json b/packages/astro/e2e/fixtures/tailwindcss/package.json
index 4bcc56872..f06e3ea91 100644
--- a/packages/astro/e2e/fixtures/tailwindcss/package.json
+++ b/packages/astro/e2e/fixtures/tailwindcss/package.json
@@ -1,5 +1,5 @@
{
- "name": "@test/e2e-tailwindcss",
+ "name": "@e2e/e2e-tailwindcss",
"version": "0.0.0",
"private": true,
"dependencies": {
diff --git a/packages/astro/e2e/fixtures/vue-component/astro.config.mjs b/packages/astro/e2e/fixtures/vue-component/astro.config.mjs
new file mode 100644
index 000000000..94bdad87f
--- /dev/null
+++ b/packages/astro/e2e/fixtures/vue-component/astro.config.mjs
@@ -0,0 +1,13 @@
+import { defineConfig } from 'astro/config';
+import vue from '@astrojs/vue';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [vue({
+ template: {
+ compilerOptions: {
+ isCustomElement: tag => tag.includes('my-button')
+ }
+ }
+ })],
+});
diff --git a/packages/astro/e2e/fixtures/vue-component/package.json b/packages/astro/e2e/fixtures/vue-component/package.json
new file mode 100644
index 000000000..2322b5d2d
--- /dev/null
+++ b/packages/astro/e2e/fixtures/vue-component/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@test/vue-component",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/vue": "workspace:*",
+ "astro": "workspace:*"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue b/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue
new file mode 100644
index 000000000..6516d1ee5
--- /dev/null
+++ b/packages/astro/e2e/fixtures/vue-component/src/components/Counter.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/astro/e2e/fixtures/vue-component/src/components/Result.vue b/packages/astro/e2e/fixtures/vue-component/src/components/Result.vue
new file mode 100644
index 000000000..90bf218b2
--- /dev/null
+++ b/packages/astro/e2e/fixtures/vue-component/src/components/Result.vue
@@ -0,0 +1,16 @@
+
+ {{ value }}
+ Click Me
+
+
+
diff --git a/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro b/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro
new file mode 100644
index 000000000..40619841f
--- /dev/null
+++ b/packages/astro/e2e/fixtures/vue-component/src/pages/index.astro
@@ -0,0 +1,33 @@
+---
+import Counter from '../components/Counter.vue'
+---
+
+
+
+
+ Vue component
+
+
+
+
+ No Client
+ Hello, client:load!
+
+ Hello, client:load!
+
+ Hello, client:load!
+ Hello, client:idle!
+
+ Hello, client:visible!
+ Hello, client:media!
+
+
+
diff --git a/packages/astro/e2e/lit-component.test.js b/packages/astro/e2e/lit-component.test.js
new file mode 100644
index 000000000..b3f48a3af
--- /dev/null
+++ b/packages/astro/e2e/lit-component.test.js
@@ -0,0 +1,103 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/lit-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+// TODO: configure playwright to handle web component APIs
+// https://github.com/microsoft/playwright/issues/14241
+test.describe.skip('Lit components', () => {
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('p');
+ await expect(count, 'initial count is 0').toHaveText('Count: 0');
+
+ const inc = counter.locator('button');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('Count: 1');
+ });
+
+ test('client:load', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-load');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('p');
+ await expect(count, 'initial count is 0').toHaveText('Count: 0');
+
+ const inc = counter.locator('button');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('Count: 1');
+ });
+
+ test('client:visible', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Make sure the component is on screen to trigger hydration
+ const counter = page.locator('#client-visible');
+ await counter.scrollIntoViewIfNeeded();
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('p');
+ await expect(count, 'initial count is 0').toHaveText('Count: 0');
+
+ const inc = counter.locator('button');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('Count: 1');
+ });
+
+ test('client:media', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/media'));
+
+ const counter = page.locator('#client-media');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('p');
+ await expect(count, 'initial count is 0').toHaveText('Count: 0');
+
+ const inc = counter.locator('button');
+ await inc.click();
+
+ await expect(count, 'component not hydrated yet').toHaveText('Count: 0');
+
+ // Reset the viewport to hydrate the component (max-width: 50rem)
+ await page.setViewportSize({ width: 414, height: 1124 });
+
+ await inc.click();
+ await expect(count, 'count incremented by 1').toHaveText('Count: 1');
+ });
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const label = page.locator('#client-idle h1');
+
+ await astro.editFile('./src/pages/index.astro', (original) =>
+ original.replace('Hello, client:idle!', 'Hello, updated client:idle!')
+ );
+
+ await expect(label, 'slot text updated').toHaveText('Hello, updated client:idle!');
+ });
+});
diff --git a/packages/astro/e2e/multiple-frameworks.test.js b/packages/astro/e2e/multiple-frameworks.test.js
new file mode 100644
index 000000000..6f3906400
--- /dev/null
+++ b/packages/astro/e2e/multiple-frameworks.test.js
@@ -0,0 +1,141 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/multiple-frameworks/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('Multiple frameworks', () => {
+ test('React counter', async ({ astro, page }) => {
+ await page.goto('/');
+
+ const counter = await page.locator('#react-counter');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = await counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const increment = await counter.locator('.increment');
+ await increment.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('Preact counter', async ({ astro, page }) => {
+ await page.goto('/');
+
+ const counter = await page.locator('#preact-counter');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = await counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const increment = await counter.locator('.increment');
+ await increment.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('Solid counter', async ({ astro, page }) => {
+ await page.goto('/');
+
+ const counter = await page.locator('#solid-counter');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = await counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const increment = await counter.locator('.increment');
+ await increment.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('Vue counter', async ({ astro, page }) => {
+ await page.goto('/');
+
+ const counter = await page.locator('#vue-counter');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = await counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const increment = await counter.locator('.increment');
+ await increment.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('Svelte counter', async ({ astro, page }) => {
+ await page.goto('/');
+
+ const counter = await page.locator('#svelte-counter');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = await counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const increment = await counter.locator('.increment');
+ await increment.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('Astro components', async ({ astro, page }) => {
+ await page.goto('/');
+
+ const aComponent = await page.locator('#astro-a');
+ await expect(aComponent, 'component is visible').toBeVisible();
+ await expect(aComponent, 'component text is visible').toHaveText('Hello Astro (A)');
+
+
+ const bComponent = await page.locator('#astro-b');
+ await expect(bComponent, 'component is visible').toBeVisible();
+ await expect(bComponent, 'component text is visible').toHaveText('Hello Astro (B)');
+ });
+
+ test('HMR', async ({ astro, page }) => {
+ await page.goto('/');
+
+ // 1: updating the page template
+ const preactSlot = page.locator('#preact-counter + .counter-message');
+ await expect(preactSlot, 'initial slot content').toHaveText('Hello Preact!');
+
+ await astro.editFile('./src/pages/index.astro', (content) =>
+ content.replace('Hello Preact!', 'Hello Preact, updated!')
+ );
+
+ await expect(preactSlot, 'slot content updated').toHaveText('Hello Preact, updated!');
+
+ // Edit the react component
+ await astro.editFile('./src/components/ReactCounter.jsx', (content) =>
+ content.replace('useState(0)', 'useState(5)')
+ );
+
+ const reactCount = await page.locator('#react-counter pre');
+ await expect(reactCount, 'initial count updated to 5').toHaveText('5');
+
+ // Edit the svelte component's style
+ const svelteCounter = page.locator('#svelte-counter');
+ await expect(svelteCounter, 'initial background is white').toHaveCSS('background-color', 'rgb(255, 255, 255)');
+
+ await astro.editFile('./src/components/SvelteCounter.svelte', (content) =>
+ content.replace('background: white', 'background: rgb(230, 230, 230)')
+ );
+
+ await expect(svelteCounter, 'background color updated').toHaveCSS('background-color', 'rgb(230, 230, 230)');
+ });
+});
diff --git a/packages/astro/e2e/nested-styles.test.js b/packages/astro/e2e/nested-styles.test.js
index 7c233d4cb..ff7dbac30 100644
--- a/packages/astro/e2e/nested-styles.test.js
+++ b/packages/astro/e2e/nested-styles.test.js
@@ -10,18 +10,18 @@ const test = base.extend({
let devServer;
-test.beforeAll(async ({ astro }) => {
+test.beforeEach(async ({ astro }) => {
devServer = await astro.startDevServer();
});
-test.afterAll(async ({ astro }) => {
+test.afterEach(async () => {
await devServer.stop();
});
-test('Loading styles that are nested', async ({ page, astro }) => {
- await page.goto(astro.resolveUrl('/'));
+test.describe('Loading styles that are nested', () => {
+ test('header', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
- await test.step('header', async () => {
const header = page.locator('header');
await expect(header, 'should have background color').toHaveCSS(
diff --git a/packages/astro/e2e/preact-component.test.js b/packages/astro/e2e/preact-component.test.js
new file mode 100644
index 000000000..7eca69044
--- /dev/null
+++ b/packages/astro/e2e/preact-component.test.js
@@ -0,0 +1,143 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/preact-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('Preact components', () => {
+ test('server only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#server-only');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('0');
+ });
+
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:load', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-load');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:visible', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Make sure the component is on screen to trigger hydration
+ const counter = page.locator('#client-visible');
+ await counter.scrollIntoViewIfNeeded();
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:media', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-media');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+ await expect(count, 'component not hydrated yet').toHaveText('0');
+
+ // Reset the viewport to hydrate the component (max-width: 50rem)
+ await page.setViewportSize({ width: 414, height: 1124 });
+ await inc.click();
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const label = page.locator('#client-only');
+ await expect(label, 'component is visible').toBeVisible();
+
+ await expect(label, 'slot text is visible').toHaveText('Preact client:only component');
+ });
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const count = page.locator('#client-idle pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ // Edit the component's initial count prop
+ await astro.editFile('./src/pages/index.astro', (original) =>
+ original.replace('id="client-idle" {...someProps}', 'id="client-idle" count={5}')
+ );
+
+ await expect(count, 'count prop updated').toHaveText('5');
+
+ // Edit the component's slot text
+ await astro.editFile('./src/components/JSXComponent.jsx', (original) =>
+ original.replace('Preact client:only component', 'Updated preact client:only component')
+ );
+
+ const label = page.locator('#client-only');
+ await expect(label, 'client:only component is visible').toBeVisible();
+ await expect(label, 'client:only slot text is visible').toHaveText(
+ 'Updated preact client:only component'
+ );
+
+ // Edit the imported CSS file
+ await astro.editFile('./src/components/Counter.css', (original) =>
+ original.replace('font-size: 2em;', 'font-size: 24px;')
+ );
+
+ await expect(count, 'imported styles updated').toHaveCSS('font-size', '24px');
+ });
+});
diff --git a/packages/astro/e2e/react-component.test.js b/packages/astro/e2e/react-component.test.js
new file mode 100644
index 000000000..2dded1e6d
--- /dev/null
+++ b/packages/astro/e2e/react-component.test.js
@@ -0,0 +1,143 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/react-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('React components', () => {
+ test('server only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#server-only');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'component not hydrated').toHaveText('0');
+ });
+
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:load', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-load');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:visible', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Make sure the component is on screen to trigger hydration
+ const counter = page.locator('#client-visible');
+ await counter.scrollIntoViewIfNeeded();
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:media', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-media');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+ await expect(count, 'component not hydrated yet').toHaveText('0');
+
+ // Reset the viewport to hydrate the component (max-width: 50rem)
+ await page.setViewportSize({ width: 414, height: 1124 });
+ await inc.click();
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const label = page.locator('#client-only');
+ await expect(label, 'component is visible').toBeVisible();
+
+ await expect(label, 'slot text is visible').toHaveText('React client:only component');
+ });
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const count = page.locator('#client-idle pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ // Edit the component's initial count prop
+ await astro.editFile('./src/pages/index.astro', (original) =>
+ original.replace('id="client-idle" {...someProps}', 'id="client-idle" count={5}')
+ );
+
+ await expect(count, 'count prop updated').toHaveText('5');
+
+ // Edit the component's slot text
+ await astro.editFile('./src/components/JSXComponent.jsx', (original) =>
+ original.replace('React client:only component', 'Updated react client:only component')
+ );
+
+ const label = page.locator('#client-only');
+ await expect(label, 'client:only component is visible').toBeVisible();
+ await expect(label, 'client:only slot text is visible').toHaveText(
+ 'Updated react client:only component'
+ );
+
+ // Edit the imported CSS file
+ await astro.editFile('./src/components/Counter.css', (original) =>
+ original.replace('font-size: 2em;', 'font-size: 24px;')
+ );
+
+ await expect(count, 'imported CSS updated').toHaveCSS('font-size', '24px');
+ });
+});
diff --git a/packages/astro/e2e/solid-component.test.js b/packages/astro/e2e/solid-component.test.js
new file mode 100644
index 000000000..f02b76f65
--- /dev/null
+++ b/packages/astro/e2e/solid-component.test.js
@@ -0,0 +1,123 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/solid-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('Solid components', () => {
+ test('server only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#server-only');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'component not hydrated').toHaveText('0');
+ });
+
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:load', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-load');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:visible', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Make sure the component is on screen to trigger hydration
+ const counter = page.locator('#client-visible');
+ await counter.scrollIntoViewIfNeeded();
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:media', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-media');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+ await expect(count, 'component not hydrated yet').toHaveText('0');
+
+ // Reset the viewport to hydrate the component (max-width: 50rem)
+ await page.setViewportSize({ width: 414, height: 1124 });
+ await inc.click();
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const count = page.locator('#client-idle pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ // Edit the component's initial count prop
+ await astro.editFile('./src/pages/index.astro', (original) =>
+ original.replace('id="client-idle" {...someProps}', 'id="client-idle" count={5}')
+ );
+
+ await expect(count, 'count prop updated').toHaveText('5');
+
+ // Edit the imported CSS
+ await astro.editFile('./src/components/Counter.css', (original) =>
+ original.replace('font-size: 2em;', 'font-size: 24px;')
+ );
+
+ await expect(count, 'imported CSS updated').toHaveCSS('font-size', '24px');
+ });
+});
diff --git a/packages/astro/e2e/svelte-component.test.js b/packages/astro/e2e/svelte-component.test.js
new file mode 100644
index 000000000..65d9ea68e
--- /dev/null
+++ b/packages/astro/e2e/svelte-component.test.js
@@ -0,0 +1,114 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/svelte-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('Svelte components', () => {
+ test('server only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#server-only');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'component not hydrated').toHaveText('0');
+ });
+
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:load', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-load');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:visible', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Make sure the component is on screen to trigger hydration
+ const counter = page.locator('#client-visible');
+ await counter.scrollIntoViewIfNeeded();
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:media', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-media');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+ await expect(count, 'component not hydrated yet').toHaveText('0');
+
+ // Reset the viewport to hydrate the component (max-width: 50rem)
+ await page.setViewportSize({ width: 414, height: 1124 });
+ await inc.click();
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Edit the component's slot text
+ await astro.editFile('./src/pages/index.astro', (original) =>
+ original.replace('Hello, client:idle!', 'Hello, updated client:idle!')
+ );
+
+ const label = page.locator('#client-idle-message');
+ await expect(label, 'slot text updated').toHaveText('Hello, updated client:idle!');
+ });
+});
diff --git a/packages/astro/e2e/tailwindcss.test.js b/packages/astro/e2e/tailwindcss.test.js
index e156a7be7..acfa9b724 100644
--- a/packages/astro/e2e/tailwindcss.test.js
+++ b/packages/astro/e2e/tailwindcss.test.js
@@ -10,18 +10,19 @@ const test = base.extend({
let devServer;
-test.beforeAll(async ({ astro }) => {
+test.beforeEach(async ({ astro }) => {
devServer = await astro.startDevServer();
});
-test.afterAll(async ({ astro }) => {
+test.afterEach(async ({ astro }) => {
await devServer.stop();
+ astro.resetAllFiles();
});
-test('Tailwind CSS', async ({ page, astro }) => {
- await page.goto(astro.resolveUrl('/'));
+test.describe('Tailwind CSS', () => {
+ test('body', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
- await test.step('body', async () => {
const body = page.locator('body');
await expect(body, 'should have classes').toHaveClass('bg-dawn text-midnight');
@@ -32,7 +33,9 @@ test('Tailwind CSS', async ({ page, astro }) => {
await expect(body, 'should have color').toHaveCSS('color', 'rgb(49, 39, 74)');
});
- await test.step('button', async () => {
+ test('button', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
const button = page.locator('button');
await expect(button, 'should have bg-purple-600').toHaveClass(/bg-purple-600/);
@@ -48,4 +51,20 @@ test('Tailwind CSS', async ({ page, astro }) => {
await expect(button, 'should have font-[900]').toHaveClass(/font-\[900\]/);
await expect(button, 'should have font weight').toHaveCSS('font-weight', '900');
});
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ await astro.editFile('./src/components/Button.astro', (original) =>
+ original.replace('bg-purple-600', 'bg-purple-400')
+ );
+
+ const button = page.locator('button');
+
+ await expect(button, 'should have bg-purple-400').toHaveClass(/bg-purple-400/);
+ await expect(button, 'should have background color').toHaveCSS(
+ 'background-color',
+ 'rgb(192, 132, 252)'
+ );
+ });
});
diff --git a/packages/astro/e2e/vue-component.test.js b/packages/astro/e2e/vue-component.test.js
new file mode 100644
index 000000000..28b5e3fd0
--- /dev/null
+++ b/packages/astro/e2e/vue-component.test.js
@@ -0,0 +1,144 @@
+import { test as base, expect } from '@playwright/test';
+import { loadFixture } from './test-utils.js';
+
+const test = base.extend({
+ astro: async ({}, use) => {
+ const fixture = await loadFixture({ root: './fixtures/vue-component/' });
+ await use(fixture);
+ },
+});
+
+let devServer;
+
+test.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+});
+
+test.afterEach(async () => {
+ await devServer.stop();
+});
+
+test.describe('Vue components', () => {
+ test('server only', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#server-only');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'component not hydrated').toHaveText('0');
+ });
+
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:load', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Multiple counters on the page to verify islands aren't sharing state
+ const counter = page.locator('#client-load');
+ const counterDup = page.locator('#client-load-dup');
+ const counterStep = page.locator('#client-load-step');
+
+ await expect(counter).toBeVisible();
+ await expect(counterDup).toBeVisible();
+ await expect(counterStep).toBeVisible();
+
+ const count = counter.locator('pre');
+ const countDup = counterDup.locator('pre');
+ const countStep = counterStep.locator('pre');
+
+ const countInc = counter.locator('.increment');
+ const countDupInc = counterDup.locator('.increment');
+ const countStepInc = counterStep.locator('.increment');
+
+ // Should only increment the first counter
+ await countInc.click();
+
+ await expect(count, 'intial count is 1').toHaveText('1');
+ await expect(countDup, 'initial count is 0').toHaveText('0');
+ await expect(countStep, 'initial count is 0').toHaveText('0');
+
+ // Should only increment the second counter
+ await countDupInc.click();
+
+ await expect(count, "count didn't change").toHaveText('1');
+ await expect(countDup, 'count incremented by 1').toHaveText('1');
+ await expect(countStep, "count didn't change").toHaveText('0');
+
+ // Should only increment the third counter
+ // Expecting an increase of 4 becasuse the component's
+ // step is set to 2
+ await countStepInc.click();
+ await countStepInc.click();
+
+ await expect(count, "count didn't change").toHaveText('1');
+ await expect(countDup, "count didn't change").toHaveText('1');
+ await expect(countStep, 'count incremented by 4').toHaveText('4');
+ });
+
+ test('client:visible', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Make sure the component is on screen to trigger hydration
+ const counter = page.locator('#client-visible');
+ await counter.scrollIntoViewIfNeeded();
+ await expect(counter).toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('client:media', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-media');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+ await expect(count, 'component not hydrated yet').toHaveText('0');
+
+ // Reset the viewport to hydrate the component (max-width: 50rem)
+ await page.setViewportSize({ width: 414, height: 1124 });
+ await inc.click();
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+
+ test('HMR', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ // Edit the component's slot text
+ await astro.editFile('./src/pages/index.astro', (original) =>
+ original.replace('Hello, client:visible!', 'Hello, updated client:visible!')
+ );
+
+ const label = page.locator('#client-visible h1');
+ await expect(label, 'slotted text updated').toHaveText('Hello, updated client:visible!');
+ });
+});
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 9a2b06ec3..709d6f21f 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -73,7 +73,8 @@
"benchmark": "node test/benchmark/dev.bench.js && node test/benchmark/build.bench.js",
"test": "mocha --exit --timeout 20000 --ignore **/lit-element.test.js --ignore **/errors.test.js && mocha --timeout 20000 **/lit-element.test.js && mocha --timeout 20000 **/errors.test.js",
"test:match": "mocha --timeout 20000 -g",
- "test:e2e": "playwright test e2e"
+ "test:e2e": "playwright test",
+ "test:e2e:match": "playwright test -g"
},
"dependencies": {
"@astrojs/compiler": "^0.14.3",
diff --git a/packages/astro/playwright.config.js b/packages/astro/playwright.config.js
new file mode 100644
index 000000000..8c13d8ef9
--- /dev/null
+++ b/packages/astro/playwright.config.js
@@ -0,0 +1,42 @@
+import { devices } from '@playwright/test';
+
+const config = {
+ testMatch: 'e2e/*.test.js',
+ /* Maximum time one test can run for. */
+ timeout: 30 * 1000,
+ expect: {
+ /**
+ * Maximum time expect() should wait for the condition to be met.
+ * For example in `await expect(locator).toHaveText();`
+ */
+ timeout: 5000
+ },
+ /* Fail the build on CI if you accidentally left test in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
+ actionTimeout: 0,
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL || 'http://localhost:3000',
+
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry',
+ },
+ projects: [
+ {
+ name: 'Chrome Stable',
+ use: {
+ browserName: 'chromium',
+ channel: 'chrome',
+ },
+ },
+ ],
+
+};
+
+export default config;
diff --git a/packages/astro/src/runtime/client/hmr.ts b/packages/astro/src/runtime/client/hmr.ts
index 7cd773256..8a0512f26 100644
--- a/packages/astro/src/runtime/client/hmr.ts
+++ b/packages/astro/src/runtime/client/hmr.ts
@@ -31,7 +31,7 @@ if (import.meta.hot) {
}
}
if (hasAstroUpdate) {
- return updatePage();
+ return await updatePage();
}
}
import.meta.hot.on('vite:beforeUpdate', async (event) => {
diff --git a/packages/astro/test/errors.test.js b/packages/astro/test/errors.test.js
index 7391d363e..2c5dbdbf3 100644
--- a/packages/astro/test/errors.test.js
+++ b/packages/astro/test/errors.test.js
@@ -52,9 +52,7 @@ describe('Error display', () => {
expect($('.statusMessage').text()).to.equal('Internal Error');
// 2. Edit the file, fixing the error
- let changeOccured = fixture.onNextChange();
await fixture.editFile('./src/components/SvelteSyntaxError.svelte', `No mismatch
`);
- await changeOccured;
// 3. Verify that the file is fixed.
html = await fixture.fetch('/svelte-syntax-error').then((res) => res.text());
diff --git a/packages/astro/test/test-utils.js b/packages/astro/test/test-utils.js
index bbdd86b57..8fd5393c0 100644
--- a/packages/astro/test/test-utils.js
+++ b/packages/astro/test/test-utils.js
@@ -28,6 +28,7 @@ polyfill(globalThis, {
* @property {(url: string) => string} resolveUrl
* @property {(url: string, opts: any) => Promise} fetch
* @property {(path: string) => Promise} readFile
+ * @property {(path: string, updater: (content: string) => string) => Promise} writeFile
* @property {(path: string) => Promise} readdir
* @property {() => Promise} startDevServer
* @property {() => Promise} preview
@@ -97,7 +98,7 @@ export async function loadFixture(inlineConfig) {
const resolveUrl = (url) =>
`http://${'127.0.0.1'}:${config.server.port}${url.replace(/^\/?/, '/')}`;
-
+
// A map of files that have been editted.
let fileEdits = new Map();
@@ -108,6 +109,11 @@ export async function loadFixture(inlineConfig) {
fileEdits.clear();
};
+ const onNextChange = () =>
+ devServer
+ ? new Promise((resolve) => devServer.watcher.once('change', resolve))
+ : Promise.reject(new Error('No dev server running'))
+
// After each test, reset each of the edits to their original contents.
if (typeof afterEach === 'function') {
afterEach(resetAllFiles);
@@ -134,7 +140,9 @@ export async function loadFixture(inlineConfig) {
readFile: (filePath) =>
fs.promises.readFile(new URL(filePath.replace(/^\//, ''), config.outDir), 'utf8'),
readdir: (fp) => fs.promises.readdir(new URL(fp.replace(/^\//, ''), config.outDir)),
- clean: () => fs.promises.rm(config.outDir, { maxRetries: 10, recursive: true, force: true }),
+ clean: async () => {
+ await fs.promises.rm(config.outDir, { maxRetries: 10, recursive: true, force: true });
+ },
loadTestAdapterApp: async () => {
const url = new URL('./server/entry.mjs', config.outDir);
const { createApp, manifest } = await import(url);
@@ -142,22 +150,26 @@ export async function loadFixture(inlineConfig) {
app.manifest = manifest;
return app;
},
- editFile: async (filePath, newContents) => {
+ editFile: async (filePath, newContentsOrCallback) => {
const fileUrl = new URL(filePath.replace(/^\//, ''), config.root);
const contents = await fs.promises.readFile(fileUrl, 'utf-8');
- const reset = () => fs.writeFileSync(fileUrl, contents);
+ const reset = () => {
+ fs.writeFileSync(fileUrl, contents);
+ }
// Only save this reset if not already in the map, in case multiple edits happen
// to the same file.
if (!fileEdits.has(fileUrl.toString())) {
fileEdits.set(fileUrl.toString(), reset);
}
+ const newContents = typeof newContentsOrCallback === 'function'
+ ? newContentsOrCallback(contents)
+ : newContentsOrCallback;
+ const nextChange = onNextChange();
await fs.promises.writeFile(fileUrl, newContents);
+ await nextChange;
return reset;
},
- onNextChange: () =>
- devServer
- ? new Promise((resolve) => devServer.watcher.once('change', resolve))
- : Promise.reject(new Error('No dev server running')),
+ resetAllFiles
};
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index efaf70f05..3ef4e7001 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -661,12 +661,108 @@ importers:
chai-as-promised: 7.1.1_chai@4.3.6
mocha: 9.2.2
+ packages/astro/e2e/fixtures/astro-component:
+ specifiers:
+ astro: workspace:*
+ dependencies:
+ astro: link:../../..
+
+ packages/astro/e2e/fixtures/lit-component:
+ specifiers:
+ '@astrojs/lit': workspace:*
+ '@webcomponents/template-shadowroot': ^0.1.0
+ astro: workspace:*
+ lit: ^2.2.3
+ dependencies:
+ '@astrojs/lit': link:../../../../integrations/lit
+ '@webcomponents/template-shadowroot': 0.1.0
+ astro: link:../../..
+ lit: 2.2.4
+
+ packages/astro/e2e/fixtures/multiple-frameworks:
+ specifiers:
+ '@astrojs/lit': ^0.1.3
+ '@astrojs/preact': ^0.1.2
+ '@astrojs/react': ^0.1.2
+ '@astrojs/solid-js': ^0.1.2
+ '@astrojs/svelte': ^0.1.3
+ '@astrojs/vue': ^0.1.4
+ '@webcomponents/template-shadowroot': ^0.1.0
+ astro: ^1.0.0-beta.31
+ lit: ^2.2.4
+ preact: ^10.7.2
+ react: ^18.1.0
+ react-dom: ^18.1.0
+ solid-js: ^1.4.2
+ svelte: ^3.48.0
+ vue: ^3.2.34
+ dependencies:
+ '@webcomponents/template-shadowroot': 0.1.0
+ lit: 2.2.4
+ preact: 10.7.2
+ react: 18.1.0
+ react-dom: 18.1.0_react@18.1.0
+ solid-js: 1.4.2
+ svelte: 3.48.0
+ vue: 3.2.34
+ devDependencies:
+ '@astrojs/lit': link:../../../../integrations/lit
+ '@astrojs/preact': link:../../../../integrations/preact
+ '@astrojs/react': link:../../../../integrations/react
+ '@astrojs/solid-js': link:../../../../integrations/solid
+ '@astrojs/svelte': link:../../../../integrations/svelte
+ '@astrojs/vue': link:../../../../integrations/vue
+ astro: link:../../..
+
packages/astro/e2e/fixtures/nested-styles:
specifiers:
astro: workspace:*
dependencies:
astro: link:../../..
+ packages/astro/e2e/fixtures/preact-component:
+ specifiers:
+ '@astrojs/preact': workspace:*
+ astro: workspace:*
+ preact: ^10.7.2
+ dependencies:
+ '@astrojs/preact': link:../../../../integrations/preact
+ astro: link:../../..
+ preact: 10.7.2
+
+ packages/astro/e2e/fixtures/react-component:
+ specifiers:
+ '@astrojs/react': workspace:*
+ astro: workspace:*
+ react: ^18.1.0
+ react-dom: ^18.1.0
+ dependencies:
+ '@astrojs/react': link:../../../../integrations/react
+ astro: link:../../..
+ react: 18.1.0
+ react-dom: 18.1.0_react@18.1.0
+
+ packages/astro/e2e/fixtures/solid-component:
+ specifiers:
+ '@astrojs/solid-js': workspace:*
+ astro: workspace:*
+ solid-js: ^1.4.1
+ dependencies:
+ '@astrojs/solid-js': link:../../../../integrations/solid
+ astro: link:../../..
+ devDependencies:
+ solid-js: 1.4.2
+
+ packages/astro/e2e/fixtures/svelte-component:
+ specifiers:
+ '@astrojs/svelte': workspace:*
+ astro: workspace:*
+ svelte: ^3.48.0
+ dependencies:
+ '@astrojs/svelte': link:../../../../integrations/svelte
+ astro: link:../../..
+ svelte: 3.48.0
+
packages/astro/e2e/fixtures/tailwindcss:
specifiers:
'@astrojs/tailwind': workspace:*
@@ -675,6 +771,14 @@ importers:
'@astrojs/tailwind': link:../../../../integrations/tailwind
astro: link:../../..
+ packages/astro/e2e/fixtures/vue-component:
+ specifiers:
+ '@astrojs/vue': workspace:*
+ astro: workspace:*
+ dependencies:
+ '@astrojs/vue': link:../../../../integrations/vue
+ astro: link:../../..
+
packages/astro/test/fixtures/0-css:
specifiers:
'@astrojs/react': workspace:*
@@ -1972,7 +2076,7 @@ packages:
resolution: {integrity: sha512-rgi3g078uAxdb8jg1A5U8sNWMUQq7UXwHT7qmPiGOeB+h5p+tzUFy/Awq2suv99Tq8efpn3HrAGTuDvxyvbwfg==}
dependencies:
svelte: 3.48.0
- svelte2tsx: 0.5.10_wwvk7nlptlrqo2czohjtk6eiqm
+ svelte2tsx: 0.5.9_wwvk7nlptlrqo2czohjtk6eiqm
transitivePeerDependencies:
- typescript
dev: false
@@ -3725,7 +3829,7 @@ packages:
dependencies:
'@lit-labs/ssr-client': 1.0.1
'@lit/reactive-element': 1.3.2
- '@types/node': 16.11.36
+ '@types/node': 16.11.34
lit: 2.2.4
lit-element: 3.2.0
lit-html: 2.2.4
@@ -3748,7 +3852,7 @@ packages:
resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==}
dependencies:
'@babel/runtime': 7.18.0
- '@types/node': 12.20.52
+ '@types/node': 12.20.51
find-up: 4.1.0
fs-extra: 8.1.0
dev: true
@@ -6032,7 +6136,7 @@ packages:
slash: 3.0.0
dev: true
- /@rollup/plugin-babel/5.3.1_ykg7cmcqpmn5fbkb5gxs7i3du4:
+ /@rollup/plugin-babel/5.3.1_3gvlzenj6qraw2ojvkgevxalie:
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
engines: {node: '>= 10.0.0'}
peerDependencies:
@@ -6047,8 +6151,8 @@ packages:
dependencies:
'@babel/core': 7.18.0
'@babel/helper-module-imports': 7.16.7
- '@rollup/pluginutils': 3.1.0_rollup@2.74.1
- rollup: 2.74.1
+ '@rollup/pluginutils': 3.1.0_rollup@2.72.1
+ rollup: 2.72.1
dev: true
/@rollup/plugin-inject/4.0.4_rollup@2.74.1:
@@ -6062,19 +6166,19 @@ packages:
rollup: 2.74.1
dev: true
- /@rollup/plugin-node-resolve/11.2.1_rollup@2.74.1:
+ /@rollup/plugin-node-resolve/11.2.1_rollup@2.72.1:
resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==}
engines: {node: '>= 10.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0
dependencies:
- '@rollup/pluginutils': 3.1.0_rollup@2.74.1
+ '@rollup/pluginutils': 3.1.0_rollup@2.72.1
'@types/resolve': 1.17.1
builtin-modules: 3.3.0
deepmerge: 4.2.2
is-module: 1.0.0
resolve: 1.22.0
- rollup: 2.74.1
+ rollup: 2.72.1
dev: true
/@rollup/plugin-node-resolve/13.3.0_rollup@2.74.1:
@@ -6092,14 +6196,14 @@ packages:
rollup: 2.74.1
dev: true
- /@rollup/plugin-replace/2.4.2_rollup@2.74.1:
+ /@rollup/plugin-replace/2.4.2_rollup@2.72.1:
resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==}
peerDependencies:
rollup: ^1.20.0 || ^2.0.0
dependencies:
- '@rollup/pluginutils': 3.1.0_rollup@2.74.1
+ '@rollup/pluginutils': 3.1.0_rollup@2.72.1
magic-string: 0.25.9
- rollup: 2.74.1
+ rollup: 2.72.1
dev: true
/@rollup/plugin-typescript/8.3.2_ewnwotriipvq7wps276zlnnxuy:
@@ -6117,6 +6221,18 @@ packages:
typescript: 4.6.4
dev: true
+ /@rollup/pluginutils/3.1.0_rollup@2.72.1:
+ resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
+ engines: {node: '>= 8.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0
+ dependencies:
+ '@types/estree': 0.0.39
+ estree-walker: 1.0.1
+ picomatch: 2.3.1
+ rollup: 2.72.1
+ dev: true
+
/@rollup/pluginutils/3.1.0_rollup@2.74.1:
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
engines: {node: '>= 8.0.0'}
@@ -6255,7 +6371,7 @@ packages:
/@types/connect/3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies:
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: true
/@types/debug/4.1.7:
@@ -6296,7 +6412,7 @@ packages:
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
dependencies:
'@types/minimatch': 3.0.5
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: true
/@types/hast/2.3.4:
@@ -6360,20 +6476,20 @@ packages:
'@types/unist': 2.0.6
dev: false
- /@types/node/12.20.52:
- resolution: {integrity: sha512-cfkwWw72849SNYp3Zx0IcIs25vABmFh73xicxhCkTcvtZQeIez15PpwQN8fY3RD7gv1Wrxlc9MEtfMORZDEsGw==}
+ /@types/node/12.20.51:
+ resolution: {integrity: sha512-anVDMfReTatfH8GVmHmaTZOL0jeTLNZ9wK9SSrQS3tMmn4vUc+9fVWlUzAieuQefWDyWUz4Z3aqXxDgO1VsYjg==}
dev: true
/@types/node/14.18.18:
resolution: {integrity: sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==}
dev: true
- /@types/node/16.11.36:
- resolution: {integrity: sha512-FR5QJe+TaoZ2GsMHkjuwoNabr+UrJNRr2HNOo+r/7vhcuntM6Ee/pRPOnRhhL2XE9OOvX9VLEq+BcXl3VjNoWA==}
+ /@types/node/16.11.34:
+ resolution: {integrity: sha512-UrWGDyLAlQ2Z8bNOGWTsqbP9ZcBeTYBVuTRNxXTztBy5KhWUFI3BaeDWoCP/CzV/EVGgO1NTYzv9ZytBI9GAEw==}
dev: false
- /@types/node/17.0.35:
- resolution: {integrity: sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==}
+ /@types/node/17.0.32:
+ resolution: {integrity: sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==}
/@types/normalize-package-data/2.4.1:
resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
@@ -6397,7 +6513,7 @@ packages:
/@types/prompts/2.0.14:
resolution: {integrity: sha512-HZBd99fKxRWpYCErtm2/yxUZv6/PBI9J7N4TNFffl5JbrYMHBwF25DjQGTW3b3jmXq+9P6/8fCIb2ee57BFfYA==}
dependencies:
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: false
/@types/prop-types/15.7.5:
@@ -6437,7 +6553,7 @@ packages:
/@types/resolve/1.17.1:
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
dependencies:
- '@types/node': 14.18.18
+ '@types/node': 17.0.32
dev: true
/@types/resolve/1.20.2:
@@ -6447,19 +6563,19 @@ packages:
resolution: {integrity: sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==}
dependencies:
'@types/glob': 7.2.0
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: true
/@types/sass/1.43.1:
resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==}
dependencies:
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: false
/@types/sax/1.2.4:
resolution: {integrity: sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==}
dependencies:
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: false
/@types/scheduler/0.16.2:
@@ -6473,7 +6589,7 @@ packages:
resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==}
dependencies:
'@types/mime': 1.3.2
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
dev: true
/@types/tailwindcss/3.0.10:
@@ -6726,7 +6842,7 @@ packages:
acorn: 8.7.1
bindings: 1.5.0
estree-walker: 2.0.2
- glob: 7.2.3
+ glob: 7.2.0
graceful-fs: 4.2.10
micromatch: 4.0.5
node-gyp-build: 4.4.0
@@ -6974,13 +7090,8 @@ packages:
engines: {node: '>=6'}
dev: true
- /ansi-colors/4.1.3:
- resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
- engines: {node: '>=6'}
- dev: true
-
/ansi-regex/2.1.1:
- resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==}
+ resolution: {integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=}
engines: {node: '>=0.10.0'}
/ansi-regex/5.0.1:
@@ -7064,7 +7175,7 @@ packages:
dev: false
/arrify/1.0.1:
- resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==}
+ resolution: {integrity: sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=}
engines: {node: '>=0.10.0'}
dev: true
@@ -7112,7 +7223,7 @@ packages:
postcss: ^8.1.0
dependencies:
browserslist: 4.20.3
- caniuse-lite: 1.0.30001341
+ caniuse-lite: 1.0.30001340
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
@@ -7244,7 +7355,7 @@ packages:
dev: false
/boolbase/1.0.0:
- resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
+ resolution: {integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24=}
/boxen/6.2.1:
resolution: {integrity: sha512-H4PEsJXfFI/Pt8sjDWbHlQPx4zL/bvSQjcilJmaulGt5mLDorHOHpmdXAJcBcmru7PhYSp/cDMWRko4ZUMFkSw==}
@@ -7293,14 +7404,14 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
dependencies:
- caniuse-lite: 1.0.30001341
+ caniuse-lite: 1.0.30001340
electron-to-chromium: 1.4.137
escalade: 3.1.1
node-releases: 2.0.4
picocolors: 1.0.0
/buffer-crc32/0.2.13:
- resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
+ resolution: {integrity: sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=}
dev: false
/buffer-from/1.1.2:
@@ -7369,8 +7480,8 @@ packages:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
engines: {node: '>=10'}
- /caniuse-lite/1.0.30001341:
- resolution: {integrity: sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==}
+ /caniuse-lite/1.0.30001340:
+ resolution: {integrity: sha512-jUNz+a9blQTQVu4uFcn17uAD8IDizPzQkIKh3LCJfg9BkyIqExYYdyc/ZSlWUSKb8iYiXxKsxbv4zYSvkqjrxw==}
/canvas-confetti/1.5.1:
resolution: {integrity: sha512-Ncz+oZJP6OvY7ti4E1slxVlyAV/3g7H7oQtcCDXgwGgARxPnwYY9PW5Oe+I8uvspYNtuHviAdgA0LfcKFWJfpg==}
@@ -7451,7 +7562,7 @@ packages:
dev: true
/check-error/1.0.2:
- resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==}
+ resolution: {integrity: sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=}
dev: true
/cheerio-select/1.6.0:
@@ -8037,7 +8148,7 @@ packages:
resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
engines: {node: '>=8.6'}
dependencies:
- ansi-colors: 4.1.3
+ ansi-colors: 4.1.1
dev: true
/entities/2.2.0:
@@ -8682,10 +8793,8 @@ packages:
resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==}
dev: true
- /for-each/0.3.3:
- resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
- dependencies:
- is-callable: 1.2.4
+ /foreach/2.0.6:
+ resolution: {integrity: sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==}
dev: false
/formdata-polyfill/4.0.10:
@@ -8883,17 +8992,6 @@ packages:
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
- dev: true
-
- /glob/7.2.3:
- resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
/globals/11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
@@ -9563,14 +9661,14 @@ packages:
dependencies:
has-symbols: 1.0.3
- /is-typed-array/1.1.9:
- resolution: {integrity: sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==}
+ /is-typed-array/1.1.8:
+ resolution: {integrity: sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==}
engines: {node: '>= 0.4'}
dependencies:
available-typed-arrays: 1.0.5
call-bind: 1.0.2
es-abstract: 1.20.1
- for-each: 0.3.3
+ foreach: 2.0.6
has-tostringtag: 1.0.0
dev: false
@@ -9625,7 +9723,7 @@ packages:
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
engines: {node: '>= 10.13.0'}
dependencies:
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
merge-stream: 2.0.0
supports-color: 7.2.0
dev: true
@@ -11711,13 +11809,25 @@ packages:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
hasBin: true
dependencies:
- glob: 7.2.3
+ glob: 7.2.0
/rimraf/3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
- glob: 7.2.3
+ glob: 7.2.0
+
+ /rollup-plugin-terser/7.0.2_rollup@2.72.1:
+ resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
+ peerDependencies:
+ rollup: ^2.0.0
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ jest-worker: 26.6.2
+ rollup: 2.72.1
+ serialize-javascript: 4.0.0
+ terser: 5.13.1
+ dev: true
/rollup-plugin-terser/7.0.2_rollup@2.74.1:
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
@@ -11737,6 +11847,14 @@ packages:
estree-walker: 0.6.1
dev: false
+ /rollup/2.72.1:
+ resolution: {integrity: sha512-NTc5UGy/NWFGpSqF1lFY8z9Adri6uhyMLI6LvPAXdBKoPRFhIIiBUpt+Qg2awixqO3xvzSijjhnb4+QEZwJmxA==}
+ engines: {node: '>=10.0.0'}
+ hasBin: true
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
/rollup/2.74.1:
resolution: {integrity: sha512-K2zW7kV8Voua5eGkbnBtWYfMIhYhT9Pel2uhBk2WO5eMee161nPze/XRfvEQPFYz7KgrCCnmh2Wy0AMFLGGmMA==}
engines: {node: '>=10.0.0'}
@@ -11955,7 +12073,7 @@ packages:
engines: {node: '>=12.0.0', npm: '>=5.6.0'}
hasBin: true
dependencies:
- '@types/node': 17.0.35
+ '@types/node': 17.0.32
'@types/sax': 1.2.4
arg: 5.0.1
sax: 1.2.4
@@ -12012,6 +12130,10 @@ packages:
smart-buffer: 4.2.0
dev: true
+ /solid-js/1.3.17:
+ resolution: {integrity: sha512-BFCosxa4hRm+LF7S+kBL5bNr4RtuZif6AaR5FdQkBpV1E6QNLAOFm4HWgEN8vL2aCWEKl384cT8Etw8ziW8aag==}
+ dev: false
+
/solid-js/1.4.2:
resolution: {integrity: sha512-IU5yKuT8P/n5F5g8j1rTXqxUdPYmoZDk/074TG94AEYf/nyXAeG82BSge4/lLIbCfUcnGUJ6DRdebIjujOAYyg==}
@@ -12019,7 +12141,7 @@ packages:
resolution: {integrity: sha512-iwbgdBzQSxBKoxkzaZgC9MGGUsHWJ74at9i7FF0naoqtwGuKdLYOgOJ9QRlA353DHDS/ttH2e0SRS6s3gz8NLQ==}
dependencies:
nanostores: 0.5.12
- solid-js: 1.4.2
+ solid-js: 1.3.17
dev: false
/sorcery/0.10.0:
@@ -12364,8 +12486,8 @@ packages:
resolution: {integrity: sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ==}
engines: {node: '>= 8'}
- /svelte2tsx/0.5.10_wwvk7nlptlrqo2czohjtk6eiqm:
- resolution: {integrity: sha512-nokQ0HTTWMcNX6tLrDLiOmJCuqjKZU9nCZ6/mVuCL3nusXdbp+9nv69VG2pCy7uQC66kV4Ls+j0WfvvJuGVnkg==}
+ /svelte2tsx/0.5.9_wwvk7nlptlrqo2czohjtk6eiqm:
+ resolution: {integrity: sha512-xTDASjlh+rKo4QRhTRYSH87sS7fRoyX67xhGIMPKa3FYqftRHRmMes6nVgEskiuhBovslNHYYpMMg5YM5n/STg==}
peerDependencies:
svelte: ^3.24
typescript: ^4.1.2
@@ -12989,9 +13111,9 @@ packages:
inherits: 2.0.4
is-arguments: 1.1.1
is-generator-function: 1.0.10
- is-typed-array: 1.1.9
+ is-typed-array: 1.1.8
safe-buffer: 5.2.1
- which-typed-array: 1.1.8
+ which-typed-array: 1.1.7
dev: false
/uvu/0.5.3:
@@ -13056,7 +13178,7 @@ packages:
debug: 4.3.4
fast-glob: 3.2.11
pretty-bytes: 5.6.0
- rollup: 2.74.1
+ rollup: 2.72.1
workbox-build: 6.5.3
workbox-window: 6.5.3
transitivePeerDependencies:
@@ -13266,16 +13388,16 @@ packages:
load-yaml-file: 0.2.0
path-exists: 4.0.0
- /which-typed-array/1.1.8:
- resolution: {integrity: sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==}
+ /which-typed-array/1.1.7:
+ resolution: {integrity: sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==}
engines: {node: '>= 0.4'}
dependencies:
available-typed-arrays: 1.0.5
call-bind: 1.0.2
es-abstract: 1.20.1
- for-each: 0.3.3
+ foreach: 2.0.6
has-tostringtag: 1.0.0
- is-typed-array: 1.1.9
+ is-typed-array: 1.1.8
dev: false
/which/1.3.1:
@@ -13330,19 +13452,19 @@ packages:
'@babel/core': 7.18.0
'@babel/preset-env': 7.18.0_@babel+core@7.18.0
'@babel/runtime': 7.18.0
- '@rollup/plugin-babel': 5.3.1_ykg7cmcqpmn5fbkb5gxs7i3du4
- '@rollup/plugin-node-resolve': 11.2.1_rollup@2.74.1
- '@rollup/plugin-replace': 2.4.2_rollup@2.74.1
+ '@rollup/plugin-babel': 5.3.1_3gvlzenj6qraw2ojvkgevxalie
+ '@rollup/plugin-node-resolve': 11.2.1_rollup@2.72.1
+ '@rollup/plugin-replace': 2.4.2_rollup@2.72.1
'@surma/rollup-plugin-off-main-thread': 2.2.3
ajv: 8.11.0
common-tags: 1.8.2
fast-json-stable-stringify: 2.1.0
fs-extra: 9.1.0
- glob: 7.2.3
+ glob: 7.2.0
lodash: 4.17.21
pretty-bytes: 5.6.0
- rollup: 2.74.1
- rollup-plugin-terser: 7.0.2_rollup@2.74.1
+ rollup: 2.72.1
+ rollup-plugin-terser: 7.0.2_rollup@2.72.1
source-map: 0.8.0-beta.0
stringify-object: 3.3.0
strip-comments: 2.0.1